Add an interface to return the current framebuffer.

This commit is contained in:
Unknown W. Brackets 2013-09-22 19:03:31 -07:00
parent 2ad5167f75
commit 6af44910c1
7 changed files with 140 additions and 1 deletions

View File

@ -30,6 +30,93 @@ struct GPUDebugOp {
std::string desc;
};
struct GPUDebugBuffer {
GPUDebugBuffer() : alloc_(false), data_(NULL) {
}
GPUDebugBuffer(void *data, u32 stride, u32 height, GEBufferFormat fmt)
: alloc_(false), data_((u8 *)data), stride_(stride), height_(height), fmt_(fmt) {
}
GPUDebugBuffer(GPUDebugBuffer &&other) {
alloc_ = other.alloc_;
data_ = other.data_;
height_ = other.height_;
stride_ = other.stride_;
fmt_ = other.fmt_;
other.alloc_ = false;
other.data_ = NULL;
}
~GPUDebugBuffer() {
Free();
}
GPUDebugBuffer &operator = (GPUDebugBuffer &&other) {
if (this != &other) {
Free();
alloc_ = other.alloc_;
data_ = other.data_;
height_ = other.height_;
stride_ = other.stride_;
fmt_ = other.fmt_;
other.alloc_ = false;
other.data_ = NULL;
}
return *this;
}
void Allocate(u32 stride, u32 height, GEBufferFormat fmt) {
if (alloc_ && stride_ == stride && height_ == height && fmt_ == fmt) {
// Already allocated the right size.
return;
}
Free();
alloc_ = true;
height_ = height;
stride_ = stride;
fmt_ = fmt;
u32 pixelSize = 2;
if (fmt == GE_FORMAT_8888) {
pixelSize = 4;
};
data_ = new u8[pixelSize * stride * height];
}
void Free() {
if (alloc_ && data_ != NULL) {
delete [] data_;
}
data_ = NULL;
}
u8 *GetData() const {
return data_;
}
u32 GetHeight() const {
return height_;
}
u32 GetStride() const {
return stride_;
}
GEBufferFormat GetFormat() const {
return fmt_;
}
bool alloc_;
u8 *data_;
u32 height_;
u32 stride_;
GEBufferFormat fmt_;
};
class GPUDebugInterface {
public:
virtual bool GetCurrentDisplayList(DisplayList &list) = 0;
@ -49,6 +136,13 @@ public:
virtual u32 GetIndexAddress() = 0;
virtual GPUgstate GetGState() = 0;
// 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.
virtual bool GetCurrentFramebuffer(GPUDebugBuffer &buffer) {
// False means unsupported.
return false;
}
// TODO:
// cached framebuffers / textures / vertices?
// get content of framebuffer / texture

View File

@ -1310,3 +1310,28 @@ void FramebufferManager::UpdateFromMemory(u32 addr, int size) {
void FramebufferManager::Resized() {
resized_ = true;
}
bool FramebufferManager::GetCurrentFramebuffer(GPUDebugBuffer &buffer)
{
u32 fb_address = (gstate.fbptr & 0xFFFFFF) | ((gstate.fbwidth & 0xFF0000) << 8);
int fb_stride = gstate.fbwidth & 0x3C0;
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
vfb = GetVFBAt(fb_address);
}
if (!vfb) {
// If there's no vfb and we're drawing there, must be memory?
buffer = GPUDebugBuffer(Memory::GetPointer(fb_address), fb_stride, 512, gstate.FrameBufFormat());
return true;
}
buffer.Allocate(vfb->fb_stride, vfb->height, GE_FORMAT_8888);
fbo_bind_for_read(vfb->fbo);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glReadPixels(0, 0, vfb->fb_stride, vfb->height, GL_RGBA, GL_UNSIGNED_BYTE, buffer.GetData());
return true;
}

View File

@ -170,6 +170,8 @@ public:
void DestroyFramebuf(VirtualFramebuffer *vfb);
bool GetCurrentFramebuffer(GPUDebugBuffer &buffer);
private:
void CompileDraw2DProgram();

View File

@ -1504,3 +1504,8 @@ void GLES_GPU::DoState(PointerWrap &p) {
gstate_c.textureChanged = true;
framebufferManager_.DestroyAllFBOs();
}
bool GLES_GPU::GetCurrentFramebuffer(GPUDebugBuffer &buffer)
{
return framebufferManager_.GetCurrentFramebuffer(buffer);
}

View File

@ -66,6 +66,8 @@ public:
}
std::vector<FramebufferInfo> GetFramebufferList();
bool GetCurrentFramebuffer(GPUDebugBuffer &buffer);
protected:
virtual void FastRunLoop(DisplayList &list);
virtual void ProcessEvent(GPUEvent ev);

View File

@ -743,3 +743,11 @@ void SoftGPU::UpdateMemory(u32 dest, u32 src, int size)
// Nothing to update.
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);
}
bool SoftGPU::GetCurrentFramebuffer(GPUDebugBuffer &buffer)
{
// We don't know the height, so just use 512, which should be the max (hopefully?)
// TODO: Could check clipping and such, though...?
buffer = GPUDebugBuffer(fb.data, gstate.FrameBufStride(), 512, gstate.FrameBufFormat());
return true;
}

View File

@ -17,7 +17,8 @@
#pragma once
#include "../GPUCommon.h"
#include "GPU/GPUCommon.h"
#include "GPU/Common/GPUDebugInterface.h"
typedef struct {
union {
@ -72,6 +73,8 @@ public:
fullInfo = "Software";
}
virtual bool GetCurrentFramebuffer(GPUDebugBuffer &buffer);
protected:
virtual void FastRunLoop(DisplayList &list);
virtual void ProcessEvent(GPUEvent ev);