diff --git a/Core/Screenshot.cpp b/Core/Screenshot.cpp index bb8d109c10..8a06d54ab7 100644 --- a/Core/Screenshot.cpp +++ b/Core/Screenshot.cpp @@ -24,6 +24,7 @@ #include "Common/ColorConv.h" #include "Common/File/FileUtil.h" #include "Common/Log.h" +#include "Common/System/Display.h" #include "Core/Config.h" #include "Core/Screenshot.h" #include "Core/Core.h" @@ -295,6 +296,36 @@ const u8 *ConvertBufferToScreenshot(const GPUDebugBuffer &buf, bool alpha, u8 *& return temp ? temp : buffer; } +static GPUDebugBuffer ApplyRotation(const GPUDebugBuffer &buf, DisplayRotation rotation) { + GPUDebugBuffer rotated; + + // This is a simple but not terribly efficient rotation. + if (rotation == DisplayRotation::ROTATE_90) { + rotated.Allocate(buf.GetHeight(), buf.GetStride(), buf.GetFormat(), false); + for (u32 y = 0; y < buf.GetStride(); ++y) { + for (u32 x = 0; x < buf.GetHeight(); ++x) { + rotated.SetRawPixel(x, y, buf.GetRawPixel(buf.GetStride() - y - 1, x)); + } + } + } else if (rotation == DisplayRotation::ROTATE_180) { + rotated.Allocate(buf.GetStride(), buf.GetHeight(), buf.GetFormat(), false); + for (u32 y = 0; y < buf.GetHeight(); ++y) { + for (u32 x = 0; x < buf.GetStride(); ++x) { + rotated.SetRawPixel(x, y, buf.GetRawPixel(buf.GetStride() - x - 1, buf.GetHeight() - y - 1)); + } + } + } else { + rotated.Allocate(buf.GetHeight(), buf.GetStride(), buf.GetFormat(), false); + for (u32 y = 0; y < buf.GetStride(); ++y) { + for (u32 x = 0; x < buf.GetHeight(); ++x) { + rotated.SetRawPixel(x, y, buf.GetRawPixel(y, buf.GetHeight() - x - 1)); + } + } + } + + return rotated; +} + bool TakeGameScreenshot(const char *filename, ScreenshotFormat fmt, ScreenshotType type, int *width, int *height, int maxRes) { if (!gpuDebug) { ERROR_LOG(SYSTEM, "Can't take screenshots when GPU not running"); @@ -311,6 +342,12 @@ bool TakeGameScreenshot(const char *filename, ScreenshotFormat fmt, ScreenshotTy // Only crop to the top left when using a render screenshot. w = maxRes > 0 ? 480 * maxRes : PSP_CoreParameter().renderWidth; h = maxRes > 0 ? 272 * maxRes : PSP_CoreParameter().renderHeight; + } else if (g_display_rotation != DisplayRotation::ROTATE_0) { + GPUDebugBuffer temp; + success = gpuDebug->GetOutputFramebuffer(temp); + if (success) { + buf = ApplyRotation(temp, g_display_rotation); + } } else { success = gpuDebug->GetOutputFramebuffer(buf); } diff --git a/GPU/Common/GPUDebugInterface.cpp b/GPU/Common/GPUDebugInterface.cpp index 9fb5d2916c..e4ce10ea44 100644 --- a/GPU/Common/GPUDebugInterface.cpp +++ b/GPU/Common/GPUDebugInterface.cpp @@ -39,7 +39,7 @@ void GPUDebugBuffer::Allocate(u32 stride, u32 height, GPUDebugBufferFormat fmt, fmt_ = fmt; flipped_ = flipped; - u32 pixelSize = PixelSize(fmt); + u32 pixelSize = PixelSize(); data_ = new u8[pixelSize * stride * height]; } @@ -50,8 +50,8 @@ void GPUDebugBuffer::Free() { data_ = NULL; } -u32 GPUDebugBuffer::PixelSize(GPUDebugBufferFormat fmt) const { - switch (fmt) { +u32 GPUDebugBuffer::PixelSize() const { + switch (fmt_) { case GPU_DBG_FORMAT_8888: case GPU_DBG_FORMAT_8888_BGRA: case GPU_DBG_FORMAT_FLOAT: @@ -81,7 +81,7 @@ u32 GPUDebugBuffer::GetRawPixel(int x, int y) const { y = height_ - y - 1; } - u32 pixelSize = PixelSize(fmt_); + u32 pixelSize = PixelSize(); u32 byteOffset = pixelSize * (stride_ * y + x); const u8 *ptr = &data_[byteOffset]; @@ -98,3 +98,36 @@ u32 GPUDebugBuffer::GetRawPixel(int x, int y) const { return 0; } } + +void GPUDebugBuffer::SetRawPixel(int x, int y, u32 c) { + if (data_ == nullptr) { + return; + } + + if (flipped_) { + y = height_ - y - 1; + } + + u32 pixelSize = PixelSize(); + u32 byteOffset = pixelSize * (stride_ * y + x); + u8 *ptr = &data_[byteOffset]; + + switch (pixelSize) { + case 4: + *(u32 *)ptr = c; + break; + case 3: + ptr[0] = (c >> 0) & 0xFF; + ptr[1] = (c >> 8) & 0xFF; + ptr[2] = (c >> 16) & 0xFF; + break; + case 2: + *(u16 *)ptr = (u16)c; + break; + case 1: + *ptr = (u8)c; + break; + default: + break; + } +} diff --git a/GPU/Common/GPUDebugInterface.h b/GPU/Common/GPUDebugInterface.h index 93c100e4fc..f72d57939d 100644 --- a/GPU/Common/GPUDebugInterface.h +++ b/GPU/Common/GPUDebugInterface.h @@ -140,6 +140,7 @@ struct GPUDebugBuffer { } u32 GetRawPixel(int x, int y) const; + void SetRawPixel(int x, int y, u32 c); const u8 *GetData() const { return data_; @@ -161,9 +162,9 @@ struct GPUDebugBuffer { return fmt_; } -private: - u32 PixelSize(GPUDebugBufferFormat fmt) const; + u32 PixelSize() const; +private: bool alloc_ = false; u8 *data_ = nullptr; u32 stride_ = 0;