mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Allow taking screenshots with a clamped size.
Sometimes 10x is a little on the big side.
This commit is contained in:
1 parent
16897bd19d
commit
6151f8ef9f
13 files changed
+81
-31
No files matched your search
+9
-4
@@ -215,7 +215,7 @@ static const u8 *ConvertBufferTo888RGB(const GPUDebugBuffer &buf, u8 *&temp, u32
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TakeGameScreenshot(const char *filename, ScreenshotFormat fmt, ScreenshotType type) {
|
bool TakeGameScreenshot(const char *filename, ScreenshotFormat fmt, ScreenshotType type, int *width, int *height, int maxRes) {
|
||||||
GPUDebugBuffer buf;
|
GPUDebugBuffer buf;
|
||||||
bool success = false;
|
bool success = false;
|
||||||
u32 w = (u32)-1;
|
u32 w = (u32)-1;
|
||||||
@@ -223,12 +223,12 @@ bool TakeGameScreenshot(const char *filename, ScreenshotFormat fmt, ScreenshotTy
|
|||||||
|
|
||||||
if (type == SCREENSHOT_RENDER) {
|
if (type == SCREENSHOT_RENDER) {
|
||||||
if (gpuDebug) {
|
if (gpuDebug) {
|
||||||
success = gpuDebug->GetCurrentFramebuffer(buf);
|
success = gpuDebug->GetCurrentFramebuffer(buf, maxRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only crop to the top left when using a render screenshot.
|
// Only crop to the top left when using a render screenshot.
|
||||||
w = PSP_CoreParameter().renderWidth;
|
w = maxRes > 0 ? 480 * maxRes : PSP_CoreParameter().renderWidth;
|
||||||
h = PSP_CoreParameter().renderHeight;
|
h = maxRes > 0 ? 272 * maxRes : PSP_CoreParameter().renderHeight;
|
||||||
} else {
|
} else {
|
||||||
if (GetGPUBackend() == GPUBackend::OPENGL) {
|
if (GetGPUBackend() == GPUBackend::OPENGL) {
|
||||||
success = GPU_GLES::GetDisplayFramebuffer(buf);
|
success = GPU_GLES::GetDisplayFramebuffer(buf);
|
||||||
@@ -261,6 +261,11 @@ bool TakeGameScreenshot(const char *filename, ScreenshotFormat fmt, ScreenshotTy
|
|||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (width)
|
||||||
|
*width = w;
|
||||||
|
if (height)
|
||||||
|
*height = h;
|
||||||
|
|
||||||
if (success && fmt == SCREENSHOT_PNG) {
|
if (success && fmt == SCREENSHOT_PNG) {
|
||||||
png_image png;
|
png_image png;
|
||||||
memset(&png, 0, sizeof(png));
|
memset(&png, 0, sizeof(png));
|
||||||
|
|||||||
+1
-1
@@ -30,4 +30,4 @@ enum ScreenshotType {
|
|||||||
SCREENSHOT_RENDER,
|
SCREENSHOT_RENDER,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool TakeGameScreenshot(const char *filename, ScreenshotFormat fmt, ScreenshotType type);
|
bool TakeGameScreenshot(const char *filename, ScreenshotFormat fmt, ScreenshotType type, int *width = nullptr, int *height = nullptr, int maxRes = -1);
|
||||||
@@ -206,7 +206,7 @@ public:
|
|||||||
|
|
||||||
// Needs to be called from the GPU thread, so on the same thread as a notification is fine.
|
// Needs to be called from the GPU thread, so on the same thread as a notification is fine.
|
||||||
// Calling from a separate thread (e.g. UI) may fail.
|
// Calling from a separate thread (e.g. UI) may fail.
|
||||||
virtual bool GetCurrentFramebuffer(GPUDebugBuffer &buffer) {
|
virtual bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, int maxRes = -1) {
|
||||||
// False means unsupported.
|
// False means unsupported.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -630,7 +630,11 @@ namespace DX9 {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 key = ((u64)desc.Format << 32) | (desc.Width << 16) | desc.Height;
|
return GetOffscreenSurface(desc.Format, desc.Width, desc.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
LPDIRECT3DSURFACE9 FramebufferManagerDX9::GetOffscreenSurface(D3DFORMAT fmt, u32 w, u32 h) {
|
||||||
|
u64 key = ((u64)fmt << 32) | (w << 16) | h;
|
||||||
auto it = offscreenSurfaces_.find(key);
|
auto it = offscreenSurfaces_.find(key);
|
||||||
if (it != offscreenSurfaces_.end()) {
|
if (it != offscreenSurfaces_.end()) {
|
||||||
it->second.last_frame_used = gpuStats.numFlips;
|
it->second.last_frame_used = gpuStats.numFlips;
|
||||||
@@ -639,9 +643,9 @@ namespace DX9 {
|
|||||||
|
|
||||||
textureCache_->ForgetLastTexture();
|
textureCache_->ForgetLastTexture();
|
||||||
LPDIRECT3DSURFACE9 offscreen = nullptr;
|
LPDIRECT3DSURFACE9 offscreen = nullptr;
|
||||||
hr = pD3Ddevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &offscreen, NULL);
|
HRESULT hr = pD3Ddevice->CreateOffscreenPlainSurface(w, h, fmt, D3DPOOL_SYSTEMMEM, &offscreen, NULL);
|
||||||
if (FAILED(hr) || !offscreen) {
|
if (FAILED(hr) || !offscreen) {
|
||||||
ERROR_LOG_REPORT(G3D, "Unable to create offscreen surface %dx%d @%d", desc.Width, desc.Height, desc.Format);
|
ERROR_LOG_REPORT(G3D, "Unable to create offscreen surface %dx%d @%d", w, h, fmt);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
const OffscreenSurface info = {offscreen, gpuStats.numFlips};
|
const OffscreenSurface info = {offscreen, gpuStats.numFlips};
|
||||||
@@ -1307,7 +1311,7 @@ namespace DX9 {
|
|||||||
resized_ = true;
|
resized_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FramebufferManagerDX9::GetCurrentFramebuffer(GPUDebugBuffer &buffer) {
|
bool FramebufferManagerDX9::GetCurrentFramebuffer(GPUDebugBuffer &buffer, int maxRes) {
|
||||||
u32 fb_address = gstate.getFrameBufRawAddress();
|
u32 fb_address = gstate.getFrameBufRawAddress();
|
||||||
int fb_stride = gstate.FrameBufStride();
|
int fb_stride = gstate.FrameBufStride();
|
||||||
|
|
||||||
@@ -1322,12 +1326,31 @@ namespace DX9 {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LPDIRECT3DSURFACE9 renderTarget = vfb->fbo ? fbo_get_color_for_read(vfb->fbo_dx9) : nullptr;
|
LPDIRECT3DSURFACE9 renderTarget = vfb->fbo_dx9 ? fbo_get_color_for_read(vfb->fbo_dx9) : nullptr;
|
||||||
bool success = false;
|
bool success = false;
|
||||||
if (renderTarget) {
|
if (renderTarget) {
|
||||||
|
FBO_DX9 *tempFBO = nullptr;
|
||||||
|
int w = vfb->renderWidth, h = vfb->renderHeight;
|
||||||
|
|
||||||
|
if (maxRes > 0 && vfb->renderWidth > vfb->width * maxRes) {
|
||||||
|
// Let's resize. We must stretch to a render target first.
|
||||||
|
w = vfb->width * maxRes;
|
||||||
|
h = vfb->height * maxRes;
|
||||||
|
|
||||||
|
tempFBO = fbo_create(w, h, 1, false);
|
||||||
|
RECT srcRect = {0, 0, vfb->renderWidth, vfb->renderHeight};
|
||||||
|
D3DTEXTUREFILTERTYPE filt = g_Config.iBufFilter == SCALE_LINEAR ? D3DTEXF_LINEAR : D3DTEXF_POINT;
|
||||||
|
if (SUCCEEDED(fbo_blit_color(vfb->fbo_dx9, &srcRect, tempFBO, nullptr, filt))) {
|
||||||
|
renderTarget = fbo_get_color_for_read(tempFBO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LPDIRECT3DSURFACE9 offscreen = GetOffscreenSurface(renderTarget, vfb);
|
LPDIRECT3DSURFACE9 offscreen = GetOffscreenSurface(renderTarget, vfb);
|
||||||
if (offscreen) {
|
if (offscreen) {
|
||||||
success = GetRenderTargetFramebuffer(renderTarget, offscreen, vfb->renderWidth, vfb->renderHeight, buffer);
|
success = GetRenderTargetFramebuffer(renderTarget, offscreen, w, h, buffer);
|
||||||
|
}
|
||||||
|
if (tempFBO) {
|
||||||
|
fbo_destroy(tempFBO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public:
|
|||||||
void DestroyFramebuf(VirtualFramebuffer *vfb);
|
void DestroyFramebuf(VirtualFramebuffer *vfb);
|
||||||
void ResizeFramebufFBO(VirtualFramebuffer *vfb, u16 w, u16 h, bool force = false);
|
void ResizeFramebufFBO(VirtualFramebuffer *vfb, u16 w, u16 h, bool force = false);
|
||||||
|
|
||||||
bool GetCurrentFramebuffer(GPUDebugBuffer &buffer);
|
bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, int maxRes);
|
||||||
bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer);
|
bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer);
|
||||||
bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer);
|
bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer);
|
||||||
static bool GetDisplayFramebuffer(GPUDebugBuffer &buffer);
|
static bool GetDisplayFramebuffer(GPUDebugBuffer &buffer);
|
||||||
@@ -91,6 +91,7 @@ public:
|
|||||||
|
|
||||||
FBO_DX9 *GetTempFBO(u16 w, u16 h, FBOColorDepth depth = FBO_8888);
|
FBO_DX9 *GetTempFBO(u16 w, u16 h, FBOColorDepth depth = FBO_8888);
|
||||||
LPDIRECT3DSURFACE9 GetOffscreenSurface(LPDIRECT3DSURFACE9 similarSurface, VirtualFramebuffer *vfb);
|
LPDIRECT3DSURFACE9 GetOffscreenSurface(LPDIRECT3DSURFACE9 similarSurface, VirtualFramebuffer *vfb);
|
||||||
|
LPDIRECT3DSURFACE9 GetOffscreenSurface(D3DFORMAT fmt, u32 w, u32 h);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void DisableState() override;
|
void DisableState() override;
|
||||||
|
|||||||
@@ -2142,8 +2142,8 @@ void GPU_DX9::DoState(PointerWrap &p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPU_DX9::GetCurrentFramebuffer(GPUDebugBuffer &buffer) {
|
bool GPU_DX9::GetCurrentFramebuffer(GPUDebugBuffer &buffer, int maxRes) {
|
||||||
return framebufferManager_.GetCurrentFramebuffer(buffer);
|
return framebufferManager_.GetCurrentFramebuffer(buffer, maxRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPU_DX9::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) {
|
bool GPU_DX9::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) {
|
||||||
|
|||||||
@@ -75,13 +75,13 @@ public:
|
|||||||
}
|
}
|
||||||
std::vector<FramebufferInfo> GetFramebufferList() override;
|
std::vector<FramebufferInfo> GetFramebufferList() override;
|
||||||
|
|
||||||
bool GetCurrentFramebuffer(GPUDebugBuffer &buffer);
|
bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, int maxRes = -1) override;
|
||||||
bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer);
|
bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override;
|
||||||
bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer);
|
bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override;
|
||||||
bool GetCurrentTexture(GPUDebugBuffer &buffer, int level);
|
bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override;
|
||||||
bool GetCurrentClut(GPUDebugBuffer &buffer) override;
|
bool GetCurrentClut(GPUDebugBuffer &buffer) override;
|
||||||
static bool GetDisplayFramebuffer(GPUDebugBuffer &buffer);
|
static bool GetDisplayFramebuffer(GPUDebugBuffer &buffer);
|
||||||
bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices);
|
bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) override;
|
||||||
|
|
||||||
typedef void (GPU_DX9::*CmdFunc)(u32 op, u32 diff);
|
typedef void (GPU_DX9::*CmdFunc)(u32 op, u32 diff);
|
||||||
struct CommandInfo {
|
struct CommandInfo {
|
||||||
|
|||||||
@@ -1970,7 +1970,7 @@ void FramebufferManager::Resized() {
|
|||||||
resized_ = true;
|
resized_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FramebufferManager::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer) {
|
bool FramebufferManager::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) {
|
||||||
VirtualFramebuffer *vfb = currentRenderVfb_;
|
VirtualFramebuffer *vfb = currentRenderVfb_;
|
||||||
if (!vfb) {
|
if (!vfb) {
|
||||||
vfb = GetVFBAt(fb_address);
|
vfb = GetVFBAt(fb_address);
|
||||||
@@ -1982,14 +1982,35 @@ bool FramebufferManager::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferF
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GE_FORMAT_8888, !useBufferedRendering_, true);
|
int w = vfb->renderWidth, h = vfb->renderHeight;
|
||||||
if (vfb->fbo)
|
if (vfb->fbo) {
|
||||||
fbo_bind_for_read(vfb->fbo);
|
if (maxRes > 0 && vfb->renderWidth > vfb->width * maxRes) {
|
||||||
|
w = vfb->width * maxRes;
|
||||||
|
h = vfb->height * maxRes;
|
||||||
|
|
||||||
|
FBO *tempFBO = GetTempFBO(w, h);
|
||||||
|
VirtualFramebuffer tempVfb = *vfb;
|
||||||
|
tempVfb.fbo = tempFBO;
|
||||||
|
tempVfb.bufferWidth = vfb->width;
|
||||||
|
tempVfb.bufferHeight = vfb->height;
|
||||||
|
tempVfb.renderWidth = w;
|
||||||
|
tempVfb.renderHeight = h;
|
||||||
|
BlitFramebuffer(&tempVfb, 0, 0, vfb, 0, 0, vfb->width, vfb->height, 0);
|
||||||
|
|
||||||
|
fbo_bind_for_read(tempFBO);
|
||||||
|
} else {
|
||||||
|
fbo_bind_for_read(vfb->fbo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.Allocate(w, h, GE_FORMAT_8888, !useBufferedRendering_, true);
|
||||||
if (gl_extensions.GLES3 || !gl_extensions.IsGLES)
|
if (gl_extensions.GLES3 || !gl_extensions.IsGLES)
|
||||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||||
|
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
glPixelStorei(GL_PACK_ALIGNMENT, 4);
|
||||||
SafeGLReadPixels(0, 0, vfb->renderWidth, vfb->renderHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.GetData());
|
SafeGLReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer.GetData());
|
||||||
|
|
||||||
|
fbo_unbind();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ public:
|
|||||||
void DestroyFramebuf(VirtualFramebuffer *vfb) override;
|
void DestroyFramebuf(VirtualFramebuffer *vfb) override;
|
||||||
void ResizeFramebufFBO(VirtualFramebuffer *vfb, u16 w, u16 h, bool force = false) override;
|
void ResizeFramebufFBO(VirtualFramebuffer *vfb, u16 w, u16 h, bool force = false) override;
|
||||||
|
|
||||||
bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer);
|
bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes);
|
||||||
bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer);
|
bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer);
|
||||||
bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer);
|
bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer);
|
||||||
static bool GetDisplayFramebuffer(GPUDebugBuffer &buffer);
|
static bool GetDisplayFramebuffer(GPUDebugBuffer &buffer);
|
||||||
|
|||||||
@@ -2413,11 +2413,11 @@ void GPU_GLES::DoState(PointerWrap &p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPU_GLES::GetCurrentFramebuffer(GPUDebugBuffer &buffer) {
|
bool GPU_GLES::GetCurrentFramebuffer(GPUDebugBuffer &buffer, int maxRes) {
|
||||||
u32 fb_address = gstate.getFrameBufRawAddress();
|
u32 fb_address = gstate.getFrameBufRawAddress();
|
||||||
int fb_stride = gstate.FrameBufStride();
|
int fb_stride = gstate.FrameBufStride();
|
||||||
GEBufferFormat format = gstate.FrameBufFormat();
|
GEBufferFormat format = gstate.FrameBufFormat();
|
||||||
return framebufferManager_.GetFramebuffer(fb_address, fb_stride, format, buffer);
|
return framebufferManager_.GetFramebuffer(fb_address, fb_stride, format, buffer, maxRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPU_GLES::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) {
|
bool GPU_GLES::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) {
|
||||||
|
|||||||
+1
-1
@@ -80,7 +80,7 @@ public:
|
|||||||
}
|
}
|
||||||
std::vector<FramebufferInfo> GetFramebufferList() override;
|
std::vector<FramebufferInfo> GetFramebufferList() override;
|
||||||
|
|
||||||
bool GetCurrentFramebuffer(GPUDebugBuffer &buffer) override;
|
bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, int maxRes) override;
|
||||||
bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override;
|
bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override;
|
||||||
bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override;
|
bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override;
|
||||||
bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override;
|
bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override;
|
||||||
|
|||||||
@@ -821,7 +821,7 @@ bool SoftGPU::FramebufferDirty() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SoftGPU::GetCurrentFramebuffer(GPUDebugBuffer &buffer)
|
bool SoftGPU::GetCurrentFramebuffer(GPUDebugBuffer &buffer, int maxRes)
|
||||||
{
|
{
|
||||||
const int w = gstate.getRegionX2() - gstate.getRegionX1() + 1;
|
const int w = gstate.getRegionX2() - gstate.getRegionX1() + 1;
|
||||||
const int h = gstate.getRegionY2() - gstate.getRegionY1() + 1;
|
const int h = gstate.getRegionY2() - gstate.getRegionY1() + 1;
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public:
|
|||||||
return !(gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME);
|
return !(gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetCurrentFramebuffer(GPUDebugBuffer &buffer) override;
|
bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, int maxRes = -1) override;
|
||||||
bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override;
|
bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override;
|
||||||
bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override;
|
bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override;
|
||||||
bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override;
|
bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override;
|
||||||
|
|||||||
Reference in new issue
Block a user