From 0b02880b7699b8049be0ae64ff1461a792a9bf9b Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sun, 10 Nov 2013 00:10:20 +0100 Subject: [PATCH] Revert "Be less dumb." Revert "Actually, filename really does need to be a parameter because of some random debug thing." Revert "fix non-HAVE_WX case" Revert "Handle screenshot saving in RenderBase. Removes dependency on D3DX11 for screenshots (texture dumping is still broken)." This reverts commits 00fe5057f13bca3416b9d25a1fe9df27c514b29c, 74b5fb3ab4b066681336d1be44c7eecfcf6a4dc6, cd46138d299088631bbcbf37543584946c4b174a and 5f72542e0637799092ad1006d16ebad1961020e0 because taking screenshots in D3D still crashed for me so there was no point in the code changes (which I found ugly anyway). --- Source/Core/VideoBackends/D3D/Src/Render.cpp | 36 +++-- Source/Core/VideoBackends/D3D/Src/Render.h | 3 +- Source/Core/VideoBackends/OGL/Src/Render.cpp | 130 ++++++++++++++++-- Source/Core/VideoBackends/OGL/Src/Render.h | 4 +- .../VideoBackends/OGL/Src/VertexManager.cpp | 2 +- Source/Core/VideoCommon/Src/RenderBase.cpp | 77 +---------- Source/Core/VideoCommon/Src/RenderBase.h | 7 +- 7 files changed, 148 insertions(+), 111 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/Src/Render.cpp b/Source/Core/VideoBackends/D3D/Src/Render.cpp index 9790f2b52e..380ab7fa83 100644 --- a/Source/Core/VideoBackends/D3D/Src/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Src/Render.cpp @@ -680,7 +680,7 @@ void Renderer::SetBlendMode(bool forceUpdate) } } -void Renderer::TakeScreenshot(const TargetRectangle &rc, std::string filename) +bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle& rc) { if (!s_screenshot_texture) CreateScreenshotTexture(rc); @@ -689,26 +689,34 @@ void Renderer::TakeScreenshot(const TargetRectangle &rc, std::string filename) D3D11_BOX box = CD3D11_BOX(rc.left, rc.top, 0, rc.right, rc.bottom, 1); D3D::context->CopySubresourceRegion(s_screenshot_texture, 0, 0, 0, 0, (ID3D11Resource*)D3D::GetBackBuffer()->GetTex(), 0, &box); - u8* __restrict dest = (u8*) malloc(rc.GetWidth() * rc.GetHeight() * 3); - + // D3DX11SaveTextureToFileA doesn't allow us to ignore the alpha channel, so we need to strip it out ourselves D3D11_MAPPED_SUBRESOURCE map; D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ_WRITE, 0, &map); - u8* src = (u8*) map.pData; - for (int y = 0; y < rc.GetHeight(); ++y) + for (unsigned int y = 0; y < rc.GetHeight(); ++y) { - u8* __restrict row = src; - for (int x = 0; x < rc.GetWidth(); ++x) + u8* ptr = (u8*)map.pData + y * map.RowPitch + 3; + for (unsigned int x = 0; x < rc.GetWidth(); ++x) { - *dest++ = *row++; - *dest++ = *row++; - *dest++ = *row++; - row++; + *ptr = 0xFF; + ptr += 4; } - src += map.RowPitch; } D3D::context->Unmap(s_screenshot_texture, 0); - SaveScreenshot(dest, rc.GetWidth(), rc.GetHeight(), filename); + // ready to be saved + //HRESULT hr = PD3DX11SaveTextureToFileA(D3D::context, s_screenshot_texture, D3DX11_IFF_PNG, filename.c_str()); + HRESULT hr = 0; + if (SUCCEEDED(hr)) + { + OSD::AddMessage(StringFromFormat("Saved %i x %i %s", rc.GetWidth(), + rc.GetHeight(), filename.c_str())); + } + else + { + OSD::AddMessage(StringFromFormat("Error saving %s", filename.c_str())); + } + + return SUCCEEDED(hr); } void formatBufferDump(const u8* in, u8* out, int w, int h, int p) @@ -846,7 +854,7 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbHeight,const EFBRectangle& r // done with drawing the game stuff, good moment to save a screenshot if (s_bScreenshot) { - TakeScreenshot(GetTargetRectangle(), s_sScreenshotName); + SaveScreenshot(s_sScreenshotName, GetTargetRectangle()); s_bScreenshot = false; } diff --git a/Source/Core/VideoBackends/D3D/Src/Render.h b/Source/Core/VideoBackends/D3D/Src/Render.h index e899484111..12e5b595d3 100644 --- a/Source/Core/VideoBackends/D3D/Src/Render.h +++ b/Source/Core/VideoBackends/D3D/Src/Render.h @@ -48,10 +48,9 @@ public: void UpdateViewport(); - static void TakeScreenshot(const TargetRectangle &rc, std::string filename); + bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc); static bool CheckForResize(); - }; } diff --git a/Source/Core/VideoBackends/OGL/Src/Render.cpp b/Source/Core/VideoBackends/OGL/Src/Render.cpp index 4583c6772c..d03d3cedd3 100644 --- a/Source/Core/VideoBackends/OGL/Src/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Src/Render.cpp @@ -11,6 +11,9 @@ #include #include "GLUtil.h" +#if defined(HAVE_WX) && HAVE_WX +#include "WxUtils.h" +#endif #include "FileUtil.h" @@ -22,6 +25,7 @@ #include "DriverDetails.h" #include "VideoConfig.h" #include "Statistics.h" +#include "ImageWrite.h" #include "PixelEngine.h" #include "Render.h" #include "BPStructs.h" @@ -58,6 +62,10 @@ #include "AVIDump.h" #endif +#if defined(HAVE_WX) && HAVE_WX +#include +#endif + // glew1.8 doesn't define KHR_debug #ifndef GL_DEBUG_OUTPUT #define GL_DEBUG_OUTPUT 0x92E0 @@ -70,6 +78,17 @@ void VideoConfig::UpdateProjectionHack() } +#if defined(HAVE_WX) && HAVE_WX +// Screenshot thread struct +typedef struct +{ + int W, H; + std::string filename; + wxImage *img; +} ScrStrct; +#endif + + int OSDInternalW, OSDInternalH; namespace OGL @@ -108,6 +127,10 @@ static u32 s_blendMode; static bool s_vsync; +#if defined(HAVE_WX) && HAVE_WX +static std::thread scrshotThread; +#endif + // EFB cache related static const u32 EFB_CACHE_RECT_SIZE = 64; // Cache 64x64 blocks. static const u32 EFB_CACHE_WIDTH = (EFB_WIDTH + EFB_CACHE_RECT_SIZE - 1) / EFB_CACHE_RECT_SIZE; // round up @@ -616,6 +639,11 @@ Renderer::Renderer() Renderer::~Renderer() { + +#if defined(HAVE_WX) && HAVE_WX + if (scrshotThread.joinable()) + scrshotThread.join(); +#endif } void Renderer::Shutdown() @@ -1391,9 +1419,11 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbHeight,const EFBRectangle& r // Save screenshot if (s_bScreenshot) { - TakeScreenshot(flipped_trc, s_sScreenshotName); - s_bScreenshot = false; + std::lock_guard lk(s_criticalScreenshot); + SaveScreenshot(s_sScreenshotName, flipped_trc); // Reset settings + s_sScreenshotName.clear(); + s_bScreenshot = false; } // Frame dumps are handled a little differently in Windows @@ -1771,22 +1801,71 @@ void Renderer::SetInterlacingMode() void Renderer::FlipImageData(u8 *data, int w, int h) { - // XXX make this faster - u8* __restrict top = data; - u8* bot = data + w * h * 3; + // Flip image upside down. Damn OpenGL. for (int y = 0; y < h / 2; y++) { - size_t stride = w * 3; - bot -= stride; - u8* __restrict brow = bot; - for(size_t x = 0; x < stride; x++) + for(int x = 0; x < w; x++) { - std::swap(*top++, *brow++); + std::swap(data[(y * w + x) * 3], data[((h - 1 - y) * w + x) * 3]); + std::swap(data[(y * w + x) * 3 + 1], data[((h - 1 - y) * w + x) * 3 + 1]); + std::swap(data[(y * w + x) * 3 + 2], data[((h - 1 - y) * w + x) * 3 + 2]); } } } -void Renderer::TakeScreenshot(const TargetRectangle &back_rc, std::string filename) +} + +// TODO: remove +extern bool g_aspect_wide; + +#if defined(HAVE_WX) && HAVE_WX +void TakeScreenshot(ScrStrct* threadStruct) +{ + // These will contain the final image size + float FloatW = (float)threadStruct->W; + float FloatH = (float)threadStruct->H; + + // Handle aspect ratio for the final ScrStrct to look exactly like what's on screen. + if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH) + { + bool use16_9 = g_aspect_wide; + + // Check for force-settings and override. + if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_16_9) + use16_9 = true; + else if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_4_3) + use16_9 = false; + + float Ratio = (FloatW / FloatH) / (!use16_9 ? (4.0f / 3.0f) : (16.0f / 9.0f)); + + // If ratio > 1 the picture is too wide and we have to limit the width. + if (Ratio > 1) + FloatW /= Ratio; + // ratio == 1 or the image is too high, we have to limit the height. + else + FloatH *= Ratio; + + // This is a bit expensive on high resolutions + threadStruct->img->Rescale((int)FloatW, (int)FloatH, wxIMAGE_QUALITY_HIGH); + } + + // Save the screenshot and finally kill the wxImage object + // This is really expensive when saving to PNG, but not at all when using BMP + threadStruct->img->SaveFile(StrToWxStr(threadStruct->filename), + wxBITMAP_TYPE_PNG); + threadStruct->img->Destroy(); + + // Show success messages + OSD::AddMessage(StringFromFormat("Saved %i x %i %s", (int)FloatW, (int)FloatH, + threadStruct->filename.c_str()), 2000); + delete threadStruct; +} +#endif + +namespace OGL +{ + +bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle &back_rc) { u32 W = back_rc.GetWidth(); u32 H = back_rc.GetHeight(); @@ -1800,13 +1879,38 @@ void Renderer::TakeScreenshot(const TargetRectangle &back_rc, std::string filena { free(data); OSD::AddMessage("Error capturing or saving screenshot.", 2000); - return; + return false; } // Turn image upside down FlipImageData(data, W, H); - SaveScreenshot(data, W, H, filename); +#if defined(HAVE_WX) && HAVE_WX + // Create wxImage + wxImage *a = new wxImage(W, H, data); + + if (scrshotThread.joinable()) + scrshotThread.join(); + + ScrStrct *threadStruct = new ScrStrct; + threadStruct->filename = filename; + threadStruct->img = a; + threadStruct->H = H; threadStruct->W = W; + + scrshotThread = std::thread(TakeScreenshot, threadStruct); +#ifdef _WIN32 + SetThreadPriority(scrshotThread.native_handle(), THREAD_PRIORITY_BELOW_NORMAL); +#endif + bool result = true; + + OSD::AddMessage("Saving Screenshot... ", 2000); + +#else + bool result = SaveTGA(filename.c_str(), W, H, data); + free(data); +#endif + + return result; } } diff --git a/Source/Core/VideoBackends/OGL/Src/Render.h b/Source/Core/VideoBackends/OGL/Src/Render.h index f38c9b4c58..9b4838ee25 100644 --- a/Source/Core/VideoBackends/OGL/Src/Render.h +++ b/Source/Core/VideoBackends/OGL/Src/Render.h @@ -63,7 +63,7 @@ public: void RenderText(const char* pstr, int left, int top, u32 color) override; void DrawDebugInfo(); - static void FlipImageData(u8 *data, int w, int h); + void FlipImageData(u8 *data, int w, int h); u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; @@ -80,7 +80,7 @@ public: void UpdateViewport() override; - static void TakeScreenshot(const TargetRectangle &rc, std::string filename); + bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc); private: void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc, const TargetRectangle& targetPixelRc, const u32* data); diff --git a/Source/Core/VideoBackends/OGL/Src/VertexManager.cpp b/Source/Core/VideoBackends/OGL/Src/VertexManager.cpp index 4fb355d897..44d8ddeaa4 100644 --- a/Source/Core/VideoBackends/OGL/Src/VertexManager.cpp +++ b/Source/Core/VideoBackends/OGL/Src/VertexManager.cpp @@ -341,7 +341,7 @@ void VertexManager::vFlush() tr.right = Renderer::GetTargetWidth(); tr.top = 0; tr.bottom = Renderer::GetTargetHeight(); - Renderer::TakeScreenshot(tr, str); + g_renderer->SaveScreenshot(str, tr); } #endif g_Config.iSaveTargetId++; diff --git a/Source/Core/VideoCommon/Src/RenderBase.cpp b/Source/Core/VideoCommon/Src/RenderBase.cpp index bb3dad8a73..e509ccb980 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.cpp +++ b/Source/Core/VideoCommon/Src/RenderBase.cpp @@ -30,12 +30,6 @@ #include "XFMemory.h" #include "FifoPlayer/FifoRecorder.h" #include "AVIDump.h" -#include "OnScreenDisplay.h" -#if defined(HAVE_WX) && HAVE_WX -#include "WxUtils.h" -#include -#endif -#include "ImageWrite.h" #include #include @@ -73,8 +67,6 @@ unsigned int Renderer::efb_scale_numeratorY = 1; unsigned int Renderer::efb_scale_denominatorX = 1; unsigned int Renderer::efb_scale_denominatorY = 1; -// TODO: remove -extern bool g_aspect_wide; Renderer::Renderer() : frame_data() @@ -250,72 +242,6 @@ void Renderer::SetScreenshot(const char *filename) s_bScreenshot = true; } -#if defined(HAVE_WX) && HAVE_WX -void Renderer::SaveScreenshotOnThread(u8* data, size_t width, size_t height, std::string filename) -{ - wxImage *img = new wxImage(width, height, data); - - // These will contain the final image size - float FloatW = (float)width; - float FloatH = (float)height; - - // Handle aspect ratio for the final ScrStrct to look exactly like what's on screen. - if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH) - { - bool use16_9 = g_aspect_wide; - - // Check for force-settings and override. - if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_16_9) - use16_9 = true; - else if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_4_3) - use16_9 = false; - - float Ratio = (FloatW / FloatH) / (!use16_9 ? (4.0f / 3.0f) : (16.0f / 9.0f)); - - // If ratio > 1 the picture is too wide and we have to limit the width. - if (Ratio > 1) - FloatW /= Ratio; - // ratio == 1 or the image is too high, we have to limit the height. - else - FloatH *= Ratio; - - // This is a bit expensive on high resolutions - img->Rescale((int)FloatW, (int)FloatH, wxIMAGE_QUALITY_HIGH); - } - - // Save the screenshot and finally kill the wxImage object - // This is really expensive when saving to PNG, but not at all when using BMP - img->SaveFile(StrToWxStr(filename), wxBITMAP_TYPE_PNG); - img->Destroy(); - - // Show success messages - OSD::AddMessage(StringFromFormat("Saved %i x %i %s", (int)FloatW, (int)FloatH, - filename.c_str()), 2000); -} -#endif - -void Renderer::SaveScreenshot(u8* ptr, size_t width, size_t height, std::string filename) -{ - std::lock_guard lk(s_criticalScreenshot); -#if defined(HAVE_WX) && HAVE_WX - // Create wxImage - - std::thread thread(SaveScreenshotOnThread, ptr, width, height, filename); -#ifdef _WIN32 - SetThreadPriority(thread.native_handle(), THREAD_PRIORITY_BELOW_NORMAL); -#endif - thread.detach(); - - OSD::AddMessage("Saving Screenshot... ", 2000); - -#else - SaveTGA(filename.c_str(), width, height, ptr); - free(ptr); -#endif - - s_bScreenshot = false; -} - // Create On-Screen-Messages void Renderer::DrawDebugText() { @@ -421,6 +347,9 @@ void Renderer::DrawDebugText() g_renderer->RenderText(final_yellow.c_str(), 20, 20, 0xFFFFFF00); } +// TODO: remove +extern bool g_aspect_wide; + void Renderer::UpdateDrawRectangle(int backbuffer_width, int backbuffer_height) { float FloatGLWidth = (float)backbuffer_width; diff --git a/Source/Core/VideoCommon/Src/RenderBase.h b/Source/Core/VideoCommon/Src/RenderBase.h index 7a153fb5cc..22d31cde23 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.h +++ b/Source/Core/VideoCommon/Src/RenderBase.h @@ -110,6 +110,8 @@ public: virtual void UpdateViewport() = 0; + virtual bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc) = 0; + static unsigned int GetPrevPixelFormat() { return prev_efb_format; } static void StorePixelFormat(unsigned int new_format) { prev_efb_format = new_format; } @@ -121,11 +123,6 @@ protected: static void CheckFifoRecording(); static void RecordVideoMemory(); - #if defined(HAVE_WX) && HAVE_WX - static void SaveScreenshotOnThread(u8* data, size_t width, size_t height, std::string filename); - #endif - static void SaveScreenshot(u8* ptr, size_t width, size_t height, std::string filename); - static volatile bool s_bScreenshot; static std::mutex s_criticalScreenshot; static std::string s_sScreenshotName;