Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GPU: Rotate screenshot framebuffer per display #14185

Merged
merged 1 commit into from
Feb 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions Core/Screenshot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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");
Expand All @@ -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);
}
Expand Down
41 changes: 37 additions & 4 deletions GPU/Common/GPUDebugInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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];
}

Expand All @@ -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:
Expand Down Expand Up @@ -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];

Expand All @@ -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;
}
}
5 changes: 3 additions & 2 deletions GPU/Common/GPUDebugInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand All @@ -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;
Expand Down