mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #20137 from hrydgard/screenshot-speedup
Screenshot performance improvement
This commit is contained in:
commit
a68e4292f9
21 changed files with 159 additions and 123 deletions
|
@ -2411,8 +2411,6 @@ add_library(${CoreLibName} ${CoreLinkType}
|
|||
Core/Screenshot.h
|
||||
Core/System.cpp
|
||||
Core/System.h
|
||||
Core/ThreadPools.cpp
|
||||
Core/ThreadPools.h
|
||||
Core/Util/AtracTrack.cpp
|
||||
Core/Util/AtracTrack.h
|
||||
Core/Util/AudioFormat.cpp
|
||||
|
|
|
@ -7,6 +7,22 @@
|
|||
#include "Common/Thread/Channel.h"
|
||||
#include "Common/Thread/ThreadManager.h"
|
||||
|
||||
// Nobody needs to wait for this (except threadpool shutdown).
|
||||
template<class T>
|
||||
class IndependentTask : public Task {
|
||||
public:
|
||||
IndependentTask(TaskType type, TaskPriority prio, T func) : func_(std::move(func)), type_(type), prio_(prio) {}
|
||||
TaskType Type() const override { return type_; }
|
||||
TaskPriority Priority() const override { return prio_; }
|
||||
void Run() override {
|
||||
func_();
|
||||
}
|
||||
private:
|
||||
T func_;
|
||||
TaskType type_;
|
||||
TaskPriority prio_;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class PromiseTask : public Task {
|
||||
public:
|
||||
|
|
|
@ -24,6 +24,8 @@ const int MAX_CORES_TO_USE = 16;
|
|||
const int MIN_IO_BLOCKING_THREADS = 4;
|
||||
static constexpr size_t TASK_PRIORITY_COUNT = (size_t)TaskPriority::COUNT;
|
||||
|
||||
ThreadManager g_threadManager;
|
||||
|
||||
struct GlobalThreadContext {
|
||||
std::mutex mutex;
|
||||
std::deque<Task *> compute_queue[TASK_PRIORITY_COUNT];
|
||||
|
|
|
@ -1084,7 +1084,6 @@
|
|||
<ClCompile Include="MIPS\MIPSStackWalk.cpp" />
|
||||
<ClCompile Include="Screenshot.cpp" />
|
||||
<ClCompile Include="System.cpp" />
|
||||
<ClCompile Include="ThreadPools.cpp" />
|
||||
<ClCompile Include="TiltEventProcessor.cpp" />
|
||||
<ClCompile Include="Util\AtracTrack.cpp" />
|
||||
<ClCompile Include="Util\AudioFormat.cpp" />
|
||||
|
@ -1470,7 +1469,6 @@
|
|||
<ClInclude Include="Screenshot.h" />
|
||||
<ClInclude Include="System.h" />
|
||||
<ClInclude Include="ThreadEventQueue.h" />
|
||||
<ClInclude Include="ThreadPools.h" />
|
||||
<ClInclude Include="TiltEventProcessor.h" />
|
||||
<ClInclude Include="Util\AtracTrack.h" />
|
||||
<ClInclude Include="Util\AudioFormat.h" />
|
||||
|
|
|
@ -952,9 +952,6 @@
|
|||
<ClCompile Include="KeyMap.cpp">
|
||||
<Filter>Core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ThreadPools.cpp">
|
||||
<Filter>Core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\WebSocket\InputSubscriber.cpp">
|
||||
<Filter>Debugger\WebSocket</Filter>
|
||||
</ClCompile>
|
||||
|
@ -2034,9 +2031,6 @@
|
|||
<ClInclude Include="KeyMap.h">
|
||||
<Filter>Core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ThreadPools.h">
|
||||
<Filter>Core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\WebSocket\InputSubscriber.h">
|
||||
<Filter>Debugger\WebSocket</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <sstream>
|
||||
|
||||
#include "Common/Thread/ParallelLoop.h"
|
||||
#include "Common/Thread/ThreadManager.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/Debugger/MemBlockInfo.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
|
@ -30,7 +31,6 @@
|
|||
#include "Core/MemMapHelpers.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/ThreadPools.h"
|
||||
#include "Common/Serialize/Serializer.h"
|
||||
#include "Common/Serialize/SerializeFuncs.h"
|
||||
#include "Common/Serialize/SerializeMap.h"
|
||||
|
|
|
@ -483,7 +483,7 @@ void PSPModule::GetLongInfo(char *ptr, int bufSize) const {
|
|||
StringWriter w(ptr, bufSize);
|
||||
w.F("%s: Version %d.%d. %d segments", nm.name, nm.version[1], nm.version[0], nm.nsegment).endl();
|
||||
w.F("Memory block: %08x (%08x/%d bytes)", memoryBlockAddr, memoryBlockSize, memoryBlockSize).endl();
|
||||
for (int i = 0; i < nm.nsegment; i++) {
|
||||
for (int i = 0; i < (int)nm.nsegment; i++) {
|
||||
w.F(" %08x (%08x bytes)\n", nm.segmentaddr[i], nm.segmentsize[i]);
|
||||
}
|
||||
w.F("Text: %08x (%08x bytes)\n", nm.text_addr, nm.text_size);
|
||||
|
|
|
@ -466,13 +466,12 @@ double g_lastSaveTime = -1.0;
|
|||
Enqueue(Operation(SAVESTATE_REWIND, Path(), -1, callback, cbUserData));
|
||||
}
|
||||
|
||||
void SaveScreenshot(const Path &filename, Callback callback, void *cbUserData) {
|
||||
static void SaveScreenshot(const Path &filename) {
|
||||
screenshotFailures = 0;
|
||||
Enqueue(Operation(SAVESTATE_SAVE_SCREENSHOT, filename, -1, callback, cbUserData));
|
||||
Enqueue(Operation(SAVESTATE_SAVE_SCREENSHOT, filename, -1, nullptr, nullptr));
|
||||
}
|
||||
|
||||
bool CanRewind()
|
||||
{
|
||||
bool CanRewind() {
|
||||
return !rewindStates.Empty();
|
||||
}
|
||||
|
||||
|
@ -690,7 +689,7 @@ double g_lastSaveTime = -1.0;
|
|||
DeleteIfExists(shotUndo);
|
||||
RenameIfExists(shot, shotUndo);
|
||||
}
|
||||
SaveScreenshot(shot, Callback(), 0);
|
||||
SaveScreenshot(shot);
|
||||
Save(fn.WithExtraExtension(".tmp"), slot, renameCallback, cbUserData);
|
||||
} else {
|
||||
if (callback) {
|
||||
|
@ -966,11 +965,9 @@ double g_lastSaveTime = -1.0;
|
|||
|
||||
bool readbackImage = false;
|
||||
|
||||
for (size_t i = 0, n = operations.size(); i < n; ++i) {
|
||||
Operation &op = operations[i];
|
||||
for (const auto &op : operations) {
|
||||
CChunkFileReader::Error result;
|
||||
Status callbackResult;
|
||||
bool tempResult;
|
||||
std::string callbackMessage;
|
||||
std::string title;
|
||||
|
||||
|
@ -1056,7 +1053,8 @@ double g_lastSaveTime = -1.0;
|
|||
break;
|
||||
|
||||
case SAVESTATE_VERIFY:
|
||||
tempResult = CChunkFileReader::Verify(state) == CChunkFileReader::ERROR_NONE;
|
||||
{
|
||||
int tempResult = CChunkFileReader::Verify(state) == CChunkFileReader::ERROR_NONE;
|
||||
callbackResult = tempResult ? Status::SUCCESS : Status::FAILURE;
|
||||
if (tempResult) {
|
||||
INFO_LOG(Log::SaveState, "Verified save state system");
|
||||
|
@ -1064,6 +1062,7 @@ double g_lastSaveTime = -1.0;
|
|||
ERROR_LOG(Log::SaveState, "Save state system verification failed");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SAVESTATE_REWIND:
|
||||
INFO_LOG(Log::SaveState, "Rewinding to recent savestate snapshot");
|
||||
|
@ -1093,18 +1092,32 @@ double g_lastSaveTime = -1.0;
|
|||
|
||||
case SAVESTATE_SAVE_SCREENSHOT:
|
||||
{
|
||||
_dbg_assert_(!op.callback);
|
||||
|
||||
int maxResMultiplier = 2;
|
||||
tempResult = TakeGameScreenshot(nullptr, op.filename, ScreenshotFormat::JPG, SCREENSHOT_DISPLAY, nullptr, nullptr, maxResMultiplier);
|
||||
callbackResult = tempResult ? Status::SUCCESS : Status::FAILURE;
|
||||
if (!tempResult) {
|
||||
ScreenshotResult tempResult = TakeGameScreenshot(nullptr, op.filename, ScreenshotFormat::JPG, SCREENSHOT_DISPLAY, maxResMultiplier, [](bool success) {
|
||||
if (success) {
|
||||
screenshotFailures = 0;
|
||||
}
|
||||
});
|
||||
|
||||
switch (tempResult) {
|
||||
case ScreenshotResult::ScreenshotNotPossible:
|
||||
// Try again soon, for a short while.
|
||||
callbackResult = Status::FAILURE;
|
||||
WARN_LOG(Log::SaveState, "Failed to take a screenshot for the savestate! (%s) The savestate will lack an icon.", op.filename.c_str());
|
||||
if (coreState != CORE_STEPPING_CPU && screenshotFailures++ < SCREENSHOT_FAILURE_RETRIES) {
|
||||
// Requeue for next frame (if we were stepping, no point, will just spam errors quickly).
|
||||
SaveScreenshot(op.filename, op.callback, op.cbUserData);
|
||||
SaveScreenshot(op.filename);
|
||||
}
|
||||
} else {
|
||||
screenshotFailures = 0;
|
||||
break;
|
||||
case ScreenshotResult::DelayedResult:
|
||||
case ScreenshotResult::Success:
|
||||
// We might not know if the file write succeeded yet though.
|
||||
callbackResult = Status::SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
readbackImage = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,10 @@
|
|||
#include "Common/File/FileUtil.h"
|
||||
#include "Common/File/Path.h"
|
||||
#include "Common/Log.h"
|
||||
#include "Common/System/System.h"
|
||||
#include "Common/System/Display.h"
|
||||
#include "Common/System/NativeApp.h"
|
||||
#include "Common/Thread/Promise.h"
|
||||
#include "Core/Screenshot.h"
|
||||
#include "Core/System.h"
|
||||
#include "GPU/Common/GPUDebugInterface.h"
|
||||
|
@ -328,56 +331,54 @@ static GPUDebugBuffer ApplyRotation(const GPUDebugBuffer &buf, DisplayRotation r
|
|||
return rotated;
|
||||
}
|
||||
|
||||
bool TakeGameScreenshot(Draw::DrawContext *draw, const Path &filename, ScreenshotFormat fmt, ScreenshotType type, int *width, int *height, int maxRes) {
|
||||
ScreenshotResult TakeGameScreenshot(Draw::DrawContext *draw, const Path &filename, ScreenshotFormat fmt, ScreenshotType type, int maxRes, std::function<void(bool success)> callback) {
|
||||
GPUDebugBuffer buf;
|
||||
bool success = false;
|
||||
u32 w = (u32)-1;
|
||||
u32 h = (u32)-1;
|
||||
|
||||
if (type == SCREENSHOT_DISPLAY || type == SCREENSHOT_RENDER) {
|
||||
if (!gpuDebug) {
|
||||
ERROR_LOG(Log::System, "Can't take screenshots when GPU not running");
|
||||
return false;
|
||||
return ScreenshotResult::ScreenshotNotPossible;
|
||||
}
|
||||
if (!gpuDebug->GetCurrentFramebuffer(buf, type == SCREENSHOT_RENDER ? GPU_DBG_FRAMEBUF_RENDER : GPU_DBG_FRAMEBUF_DISPLAY, maxRes)) {
|
||||
return ScreenshotResult::ScreenshotNotPossible;
|
||||
}
|
||||
success = gpuDebug->GetCurrentFramebuffer(buf, type == SCREENSHOT_RENDER ? GPU_DBG_FRAMEBUF_RENDER : GPU_DBG_FRAMEBUF_DISPLAY, maxRes);
|
||||
w = maxRes > 0 ? 480 * maxRes : PSP_CoreParameter().renderWidth;
|
||||
h = maxRes > 0 ? 272 * maxRes : PSP_CoreParameter().renderHeight;
|
||||
} else if (g_display.rotation != DisplayRotation::ROTATE_0) {
|
||||
_dbg_assert_(draw);
|
||||
GPUDebugBuffer temp;
|
||||
success = ::GetOutputFramebuffer(draw, temp);
|
||||
if (success) {
|
||||
buf = ApplyRotation(temp, g_display.rotation);
|
||||
if (!::GetOutputFramebuffer(draw, temp)) {
|
||||
return ScreenshotResult::ScreenshotNotPossible;
|
||||
}
|
||||
buf = ApplyRotation(temp, g_display.rotation);
|
||||
} else {
|
||||
_dbg_assert_(draw);
|
||||
success = ::GetOutputFramebuffer(draw, buf);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
u8 *flipbuffer = nullptr;
|
||||
const u8 *buffer = ConvertBufferToScreenshot(buf, false, flipbuffer, w, h);
|
||||
success = buffer != nullptr;
|
||||
if (success) {
|
||||
if (width)
|
||||
*width = w;
|
||||
if (height)
|
||||
*height = h;
|
||||
|
||||
success = Save888RGBScreenshot(filename, fmt, buffer, w, h);
|
||||
if (!GetOutputFramebuffer(draw, buf)) {
|
||||
return ScreenshotResult::ScreenshotNotPossible;
|
||||
}
|
||||
delete[] flipbuffer;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
ERROR_LOG(Log::IO, "Failed to write screenshot.");
|
||||
if (callback) {
|
||||
g_threadManager.EnqueueTask(new IndependentTask(TaskType::CPU_COMPUTE, TaskPriority::LOW,
|
||||
[buf = std::move(buf), callback = std::move(callback), filename, fmt, w, h]() {
|
||||
u8 *flipbuffer = nullptr;
|
||||
u32 width = w, height = h;
|
||||
const u8 *buffer = ConvertBufferToScreenshot(buf, false, flipbuffer, width, height);
|
||||
bool success = Save888RGBScreenshot(filename, fmt, buffer, width, height);
|
||||
delete[] flipbuffer;
|
||||
System_RunOnMainThread([success, callback = std::move(callback)]() {
|
||||
callback(success);
|
||||
});
|
||||
}));
|
||||
return ScreenshotResult::DelayedResult;
|
||||
}
|
||||
|
||||
return success;
|
||||
u8 *flipbuffer = nullptr;
|
||||
const u8 *buffer = ConvertBufferToScreenshot(buf, false, flipbuffer, w, h);
|
||||
bool success = Save888RGBScreenshot(filename, fmt, buffer, w, h);
|
||||
delete[] flipbuffer;
|
||||
return success ? ScreenshotResult::Success : ScreenshotResult::FailedToWriteFile;
|
||||
}
|
||||
|
||||
bool Save888RGBScreenshot(const Path &filename, ScreenshotFormat fmt, const u8 *bufferRGB888, int w, int h) {
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include "Common/File/Path.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
struct GPUDebugBuffer;
|
||||
namespace Draw {
|
||||
class DrawContext;
|
||||
|
@ -29,6 +31,8 @@ enum class ScreenshotFormat {
|
|||
JPG,
|
||||
};
|
||||
|
||||
// NOTE: The first two may need rotation, depending on the backend and screen orientation.
|
||||
// This is handled internally in TakeGameScreenshot().
|
||||
enum ScreenshotType {
|
||||
// What's being show on screen (e.g. including FPS, etc.)
|
||||
SCREENSHOT_OUTPUT,
|
||||
|
@ -38,10 +42,19 @@ enum ScreenshotType {
|
|||
SCREENSHOT_RENDER,
|
||||
};
|
||||
|
||||
enum class ScreenshotResult {
|
||||
ScreenshotNotPossible,
|
||||
DelayedResult, // This specifies that the actual result is one of the two below and will arrive in the callback.
|
||||
// These result can be delayed and arrive in the callback, if one is specified.
|
||||
FailedToWriteFile,
|
||||
Success,
|
||||
};
|
||||
|
||||
const u8 *ConvertBufferToScreenshot(const GPUDebugBuffer &buf, bool alpha, u8 *&temp, u32 &w, u32 &h);
|
||||
|
||||
// Can only be used while in game.
|
||||
bool TakeGameScreenshot(Draw::DrawContext *draw, const Path &filename, ScreenshotFormat fmt, ScreenshotType type, int *width = nullptr, int *height = nullptr, int maxRes = -1);
|
||||
// If the callback is passed in, the saving action happens on a background thread.
|
||||
ScreenshotResult TakeGameScreenshot(Draw::DrawContext *draw, const Path &filename, ScreenshotFormat fmt, ScreenshotType type, int maxRes = -1, std::function<void(bool success)> callback = nullptr);
|
||||
|
||||
bool Save888RGBScreenshot(const Path &filename, ScreenshotFormat fmt, const u8 *bufferRGB888, int w, int h);
|
||||
bool Save8888RGBAScreenshot(const Path &filename, const u8 *bufferRGBA8888, int w, int h);
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
#include "ThreadPools.h"
|
||||
|
||||
ThreadManager g_threadManager;
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "Common/Thread/ThreadManager.h"
|
||||
|
||||
extern ThreadManager g_threadManager;
|
|
@ -153,13 +153,13 @@ struct GPUDebugBuffer {
|
|||
|
||||
void ZeroBytes();
|
||||
|
||||
u32 GetRawPixel(int x, int y) const;
|
||||
void SetRawPixel(int x, int y, u32 c);
|
||||
|
||||
u8 *GetData() {
|
||||
return data_;
|
||||
}
|
||||
|
||||
u32 GetRawPixel(int x, int y) const;
|
||||
void SetRawPixel(int x, int y, u32 c);
|
||||
|
||||
const u8 *GetData() const {
|
||||
return data_;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/File/FileUtil.h"
|
||||
#include "Common/Thread/ThreadManager.h"
|
||||
#include "Common/Thread/ParallelLoop.h"
|
||||
#include "Common/Log.h"
|
||||
#include "Common/StringUtils.h"
|
||||
|
@ -36,7 +37,6 @@
|
|||
#include "Core/HLE/sceDisplay.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/ThreadPools.h"
|
||||
#include "GPU/Common/GPUDebugInterface.h"
|
||||
#include "GPU/GPUCommon.h"
|
||||
#include "GPU/GPUState.h"
|
||||
|
|
|
@ -1445,8 +1445,7 @@ bool SoftGPU::GetCurrentTexture(GPUDebugBuffer &buffer, int level, bool *isFrame
|
|||
return Rasterizer::GetCurrentTexture(buffer, level);
|
||||
}
|
||||
|
||||
bool SoftGPU::GetCurrentClut(GPUDebugBuffer &buffer)
|
||||
{
|
||||
bool SoftGPU::GetCurrentClut(GPUDebugBuffer &buffer) {
|
||||
const u32 bpp = gstate.getClutPaletteFormat() == GE_CMODE_32BIT_ABGR8888 ? 4 : 2;
|
||||
const u32 pixels = 1024 / bpp;
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
#include "Common/OSVersion.h"
|
||||
#include "Common/GPU/ShaderTranslation.h"
|
||||
#include "Common/VR/PPSSPPVR.h"
|
||||
#include "Common/Thread/ThreadManager.h"
|
||||
|
||||
#include "Core/ControlMapper.h"
|
||||
#include "Core/Config.h"
|
||||
|
@ -109,7 +110,6 @@
|
|||
#include "Core/Util/AudioFormat.h"
|
||||
#include "Core/WebServer.h"
|
||||
#include "Core/TiltEventProcessor.h"
|
||||
#include "Core/ThreadPools.h"
|
||||
|
||||
#include "GPU/GPUCommon.h"
|
||||
#include "GPU/Common/PresentationCommon.h"
|
||||
|
@ -949,45 +949,60 @@ static void TakeScreenshot(Draw::DrawContext *draw) {
|
|||
}
|
||||
|
||||
// First, find a free filename.
|
||||
int i = 0;
|
||||
//
|
||||
// NOTE: On Android, the old approach of checking filenames one by one doesn't scale.
|
||||
// So let's just grab the full file listing, and then find a name that's not in it.
|
||||
//
|
||||
// TODO: Also, we could do this on a thread too. Not sure if worth it.
|
||||
|
||||
std::string gameId = g_paramSFO.GetDiscID();
|
||||
const std::string gameId = g_paramSFO.GetDiscID();
|
||||
|
||||
// TODO: Make something like IterateFileInDir instead.
|
||||
std::vector<File::FileInfo> files;
|
||||
const std::string prefix = gameId + "_";
|
||||
File::GetFilesInDir(path, &files, nullptr, 0, prefix);
|
||||
std::set<std::string> existingNames;
|
||||
for (auto &file : files) {
|
||||
existingNames.insert(file.name);
|
||||
}
|
||||
|
||||
Path filename;
|
||||
while (i < 10000){
|
||||
if (g_Config.bScreenshotsAsPNG)
|
||||
filename = path / StringFromFormat("%s_%05d.png", gameId.c_str(), i);
|
||||
else
|
||||
filename = path / StringFromFormat("%s_%05d.jpg", gameId.c_str(), i);
|
||||
File::FileInfo info;
|
||||
if (!File::Exists(filename))
|
||||
int i = 0;
|
||||
for (int i = 0; i < 20000; i++) {
|
||||
const std::string pngName = prefix + StringFromFormat("%05d.png", i);
|
||||
const std::string jpgName = prefix + StringFromFormat("%05d.jpg", i);
|
||||
if (existingNames.find(pngName) == existingNames.end() && existingNames.find(jpgName) == existingNames.end()) {
|
||||
filename = path / (g_Config.bScreenshotsAsPNG ? pngName : jpgName);
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
ScreenshotType type = SCREENSHOT_OUTPUT;
|
||||
if (g_Config.iScreenshotMode == (int)ScreenshotMode::GameImage) {
|
||||
type = SCREENSHOT_DISPLAY;
|
||||
}
|
||||
|
||||
bool success = TakeGameScreenshot(draw, filename, g_Config.bScreenshotsAsPNG ? ScreenshotFormat::PNG : ScreenshotFormat::JPG, type);
|
||||
if (success) {
|
||||
g_OSD.Show(OSDType::MESSAGE_FILE_LINK, filename.ToVisualString(), 0.0f, "screenshot_link");
|
||||
if (System_GetPropertyBool(SYSPROP_CAN_SHOW_FILE)) {
|
||||
g_OSD.SetClickCallback("screenshot_link", [](bool clicked, void *data) -> void {
|
||||
Path *path = reinterpret_cast<Path *>(data);
|
||||
if (clicked) {
|
||||
System_ShowFileInFolder(*path);
|
||||
} else {
|
||||
delete path;
|
||||
}
|
||||
}, new Path(filename));
|
||||
}
|
||||
} else {
|
||||
auto err = GetI18NCategory(I18NCat::ERRORS);
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, err->T("Could not save screenshot file"));
|
||||
WARN_LOG(Log::System, "Failed to take screenshot.");
|
||||
}
|
||||
|
||||
if (filename.empty()) {
|
||||
// Overwrite this one over and over.
|
||||
filename = path / (prefix + (g_Config.bScreenshotsAsPNG ? "20000.png" : "20000.jpg"));
|
||||
}
|
||||
|
||||
const ScreenshotType type = g_Config.iScreenshotMode == (int)ScreenshotMode::GameImage ? SCREENSHOT_DISPLAY : SCREENSHOT_OUTPUT;
|
||||
|
||||
const ScreenshotResult result = TakeGameScreenshot(draw, filename, g_Config.bScreenshotsAsPNG ? ScreenshotFormat::PNG : ScreenshotFormat::JPG, type, -1, [filename](bool success) {
|
||||
if (success) {
|
||||
g_OSD.Show(OSDType::MESSAGE_FILE_LINK, filename.ToVisualString(), 0.0f, "screenshot_link");
|
||||
if (System_GetPropertyBool(SYSPROP_CAN_SHOW_FILE)) {
|
||||
g_OSD.SetClickCallback("screenshot_link", [](bool clicked, void *data) -> void {
|
||||
Path *path = reinterpret_cast<Path *>(data);
|
||||
if (clicked) {
|
||||
System_ShowFileInFolder(*path);
|
||||
} else {
|
||||
delete path;
|
||||
}
|
||||
}, new Path(filename));
|
||||
}
|
||||
} else {
|
||||
auto err = GetI18NCategory(I18NCat::ERRORS);
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, err->T("Could not save screenshot file"));
|
||||
WARN_LOG(Log::System, "Failed to take screenshot.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CallbackPostRender(UIContext *dc, void *userdata) {
|
||||
|
|
|
@ -182,21 +182,22 @@ ScreenRenderFlags ReportScreen::render(ScreenRenderMode mode) {
|
|||
File::CreateDir(path);
|
||||
}
|
||||
screenshotFilename_ = path / ".reporting.jpg";
|
||||
if (TakeGameScreenshot(screenManager()->getDrawContext(), screenshotFilename_, ScreenshotFormat::JPG, SCREENSHOT_DISPLAY, nullptr, nullptr, 4)) {
|
||||
// Redo the views already, now with a screenshot included.
|
||||
RecreateViews();
|
||||
} else {
|
||||
// Good news (?), the views are good as-is without a screenshot.
|
||||
screenshotFilename_.clear();
|
||||
}
|
||||
ScreenshotResult ignored = TakeGameScreenshot(screenManager()->getDrawContext(), screenshotFilename_, ScreenshotFormat::JPG, SCREENSHOT_RENDER, 4, [this](bool success) {
|
||||
if (success) {
|
||||
// Redo the views already, now with a screenshot included.
|
||||
RecreateViews();
|
||||
} else {
|
||||
// Good news (?), the views are good as-is without a screenshot.
|
||||
screenshotFilename_.clear();
|
||||
}
|
||||
});
|
||||
tookScreenshot_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
// We take the screenshot first, then we start rendering.
|
||||
// We are the only screen visible so this avoid starting and then trying to resume a backbuffer render pass.
|
||||
ScreenRenderFlags flags = UIScreen::render(mode);
|
||||
|
||||
const ScreenRenderFlags flags = UIScreen::render(mode);
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
|
|
@ -331,7 +331,6 @@
|
|||
<ClInclude Include="..\..\Core\Screenshot.h" />
|
||||
<ClInclude Include="..\..\Core\System.h" />
|
||||
<ClInclude Include="..\..\Core\ThreadEventQueue.h" />
|
||||
<ClInclude Include="..\..\Core\ThreadPools.h" />
|
||||
<ClInclude Include="..\..\Core\TiltEventProcessor.h" />
|
||||
<ClInclude Include="..\..\Core\Util\AtracTrack.h" />
|
||||
<ClInclude Include="..\..\Core\Util\GameDB.h" />
|
||||
|
@ -631,7 +630,6 @@
|
|||
<ClCompile Include="..\..\Core\SaveState.cpp" />
|
||||
<ClCompile Include="..\..\Core\Screenshot.cpp" />
|
||||
<ClCompile Include="..\..\Core\System.cpp" />
|
||||
<ClCompile Include="..\..\Core\ThreadPools.cpp" />
|
||||
<ClCompile Include="..\..\Core\TiltEventProcessor.cpp" />
|
||||
<ClCompile Include="..\..\Core\Util\AtracTrack.cpp" />
|
||||
<ClCompile Include="..\..\Core\Util\GameDB.cpp" />
|
||||
|
@ -1042,4 +1040,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -1191,7 +1191,6 @@
|
|||
<Filter>Ext\libzip</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Core\KeyMap.cpp" />
|
||||
<ClCompile Include="..\..\Core\ThreadPools.cpp" />
|
||||
<ClCompile Include="..\..\Core\ControlMapper.cpp" />
|
||||
<ClCompile Include="..\..\Core\KeyMapDefaults.cpp" />
|
||||
<ClCompile Include="..\..\Core\HLE\sceNp2.cpp">
|
||||
|
@ -1912,7 +1911,6 @@
|
|||
<Filter>Ext\jpge</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Core\KeyMap.h" />
|
||||
<ClInclude Include="..\..\Core\ThreadPools.h" />
|
||||
<ClInclude Include="..\..\Core\ControlMapper.h" />
|
||||
<ClInclude Include="..\..\Core\KeyMapDefaults.h" />
|
||||
<ClInclude Include="..\..\Core\HLE\sceNp2.h">
|
||||
|
@ -1966,4 +1964,4 @@
|
|||
<Filter>Ext\gason</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -619,7 +619,6 @@ EXEC_AND_LIB_FILES := \
|
|||
$(SRC)/Core/Screenshot.cpp \
|
||||
$(SRC)/Core/System.cpp \
|
||||
$(SRC)/Core/TiltEventProcessor.cpp \
|
||||
$(SRC)/Core/ThreadPools.cpp \
|
||||
$(SRC)/Core/WebServer.cpp \
|
||||
$(SRC)/Core/Debugger/Breakpoints.cpp \
|
||||
$(SRC)/Core/Debugger/DisassemblyManager.cpp \
|
||||
|
|
|
@ -825,7 +825,6 @@ SOURCES_CXX += \
|
|||
$(COREDIR)/SaveState.cpp \
|
||||
$(COREDIR)/Screenshot.cpp \
|
||||
$(COREDIR)/System.cpp \
|
||||
$(COREDIR)/ThreadPools.cpp \
|
||||
$(COREDIR)/Util/AtracTrack.cpp \
|
||||
$(COREDIR)/Util/BlockAllocator.cpp \
|
||||
$(COREDIR)/Util/MemStick.cpp \
|
||||
|
|
Loading…
Add table
Reference in a new issue