Skip to content

Commit

Permalink
Rip out async readbacks from FramebufferManagerGLES. They should be i…
Browse files Browse the repository at this point in the history
…mplemented in GLQueueRunner, differently.
  • Loading branch information
hrydgard committed Jan 27, 2018
1 parent 42f2312 commit 63b9140
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 191 deletions.
2 changes: 1 addition & 1 deletion GPU/Common/FramebufferCommon.h
Expand Up @@ -224,7 +224,7 @@ class FramebufferManagerCommon {

virtual void ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h);

virtual void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes);
void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes);
void DrawFramebufferToOutput(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, bool applyPostShader);

void DrawPixels(VirtualFramebuffer *vfb, int dstX, int dstY, const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height);
Expand Down
161 changes: 2 additions & 159 deletions GPU/GLES/FramebufferManagerGLES.cpp
Expand Up @@ -238,18 +238,7 @@ void FramebufferManagerGLES::BindPostShader(const PostShaderUniforms &uniforms)

FramebufferManagerGLES::FramebufferManagerGLES(Draw::DrawContext *draw, GLRenderManager *render) :
FramebufferManagerCommon(draw),
render_(render),
drawPixelsTex_(0),
drawPixelsTexFormat_(GE_FORMAT_INVALID),
convBuf_(nullptr),
videoLoc_(-1),
timeLoc_(-1),
pixelDeltaLoc_(-1),
deltaLoc_(-1),
textureCacheGL_(nullptr),
shaderManagerGL_(nullptr),
pixelBufObj_(nullptr),
currentPBO_(0)
render_(render)
{
needBackBufferYSwap_ = true;
needGLESRebinds_ = true;
Expand Down Expand Up @@ -315,14 +304,6 @@ void FramebufferManagerGLES::DestroyDeviceObjects() {
FramebufferManagerGLES::~FramebufferManagerGLES() {
DestroyDeviceObjects();

if (pixelBufObj_) {
for (int i = 0; i < MAX_PBO; i++) {
if (pixelBufObj_[i].buffer) {
render_->DeleteBuffer(pixelBufObj_[i].buffer);
}
}
delete[] pixelBufObj_;
}
delete [] convBuf_;
}

Expand Down Expand Up @@ -540,46 +521,19 @@ void FramebufferManagerGLES::BindFramebufferAsColorTexture(int stage, VirtualFra

void FramebufferManagerGLES::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) {
PROFILE_THIS_SCOPE("gpu-readback");
if (sync) {
// flush async just in case when we go for synchronous update
// Doesn't actually pack when sent a null argument.
PackFramebufferAsync_(nullptr);
}

if (vfb) {
// We'll pseudo-blit framebuffers here to get a resized version of vfb.
VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb);
OptimizeDownloadRange(vfb, x, y, w, h);
BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);

// PackFramebufferSync_() - Synchronous pixel data transfer using glReadPixels
// PackFramebufferAsync_() - Asynchronous pixel data transfer using glReadPixels with PBOs

if (gl_extensions.IsGLES) {
PackFramebufferSync_(nvfb, x, y, w, h);
} else {
// TODO: Can we fall back to sync without these?
if (gl_extensions.ARB_pixel_buffer_object && gstate_c.Supports(GPU_SUPPORTS_OES_TEXTURE_NPOT)) {
if (!sync) {
PackFramebufferAsync_(nvfb);
} else {
PackFramebufferSync_(nvfb, x, y, w, h);
}
}
}
PackFramebufferSync_(nvfb, x, y, w, h);

textureCacheGL_->ForgetLastTexture();
RebindFramebuffer();
}
}

void FramebufferManagerGLES::DownloadFramebufferForClut(u32 fb_address, u32 loadBytes) {
PROFILE_THIS_SCOPE("gpu-readback");
// Flush async just in case.
PackFramebufferAsync_(nullptr);
FramebufferManagerCommon::DownloadFramebufferForClut(fb_address, loadBytes);
}

bool FramebufferManagerGLES::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
// When updating VRAM, it need to be exact format.
if (!gstate_c.Supports(GPU_PREFER_CPU_DOWNLOAD)) {
Expand Down Expand Up @@ -758,117 +712,6 @@ void ConvertFromRGBA8888(u8 *dst, const u8 *src, u32 dstStride, u32 srcStride, u
}
}

void FramebufferManagerGLES::PackFramebufferAsync_(VirtualFramebuffer *vfb) {
GLubyte *packed = 0;
bool unbind = false;
const u8 nextPBO = (currentPBO_ + 1) % MAX_PBO;
const bool useCPU = gstate_c.Supports(GPU_PREFER_CPU_DOWNLOAD);

// We'll prepare two PBOs to switch between readying and reading
if (!pixelBufObj_) {
if (!vfb) {
// This call is just to flush the buffers. We don't have any yet,
// so there's nothing to do.
return;
}

pixelBufObj_ = new AsyncPBO[MAX_PBO]{};
}

// Receive previously requested data from a PBO
AsyncPBO &pbo = pixelBufObj_[nextPBO];
if (pbo.reading) {
render_->BindPixelPackBuffer(pbo.buffer);
#ifdef USING_GLES2
// Not on desktop GL 2.x...
packed = (GLubyte *)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, pbo.size, GL_MAP_READ_BIT);
#else
packed = (GLubyte *)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
#endif

if (packed) {
DEBUG_LOG(FRAMEBUF, "Reading PBO to memory , bufSize = %u, packed = %p, fb_address = %08x, stride = %u, pbo = %u",
pbo.size, packed, pbo.fb_address, pbo.stride, nextPBO);

if (useCPU) {
u8 *dst = Memory::GetPointer(pbo.fb_address);
ConvertFromRGBA8888(dst, packed, pbo.stride, pbo.stride, pbo.stride, pbo.height, pbo.format);
} else {
// We don't need to convert, GPU already did (or should have)
Memory::MemcpyUnchecked(pbo.fb_address, packed, pbo.size);
}

pbo.reading = false;
}

glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
unbind = true;
}

// Order packing/readback of the framebuffer
if (vfb) {
bool reverseOrder = gstate_c.Supports(GPU_PREFER_REVERSE_COLOR_ORDER);
Draw::DataFormat dataFmt = Draw::DataFormat::UNDEFINED;
switch (vfb->format) {
case GE_FORMAT_4444:
dataFmt = (reverseOrder ? Draw::DataFormat::A4R4G4B4_UNORM_PACK16 : Draw::DataFormat::B4G4R4A4_UNORM_PACK16);
break;
case GE_FORMAT_5551:
dataFmt = (reverseOrder ? Draw::DataFormat::A1R5G5B5_UNORM_PACK16 : Draw::DataFormat::B5G5R5A1_UNORM_PACK16);
break;
case GE_FORMAT_565:
dataFmt = (reverseOrder ? Draw::DataFormat::R5G6B5_UNORM_PACK16 : Draw::DataFormat::B5G6R5_UNORM_PACK16);
break;
case GE_FORMAT_8888:
dataFmt = Draw::DataFormat::R8G8B8A8_UNORM;
break;
};

if (useCPU) {
dataFmt = Draw::DataFormat::R8G8B8A8_UNORM;
}

int pixelSize = (int)DataFormatSizeInBytes(dataFmt);
int align = pixelSize;

// If using the CPU, we need 4 bytes per pixel always.
u32 bufSize = vfb->fb_stride * vfb->height * pixelSize;
u32 fb_address = (0x04000000) | vfb->fb_address;

if (!vfb->fbo) {
ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackFramebufferAsync_: vfb->fbo == 0");
return;
}

if (pixelBufObj_[currentPBO_].maxSize < bufSize) {
if (pixelBufObj_[currentPBO_].buffer) {
render_->DeleteBuffer(pixelBufObj_[currentPBO_].buffer);
}
pixelBufObj_[currentPBO_].buffer = render_->CreateBuffer(GL_PIXEL_PACK_BUFFER, bufSize, GL_DYNAMIC_READ);
pixelBufObj_[currentPBO_].maxSize = bufSize;
}

render_->BindPixelPackBuffer(pixelBufObj_[currentPBO_].buffer);
// TODO: This is a hack since PBOs have not been implemented in Thin3D yet (and maybe shouldn't? maybe should do this internally?)
draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_COLOR_BIT, 0, 0, vfb->fb_stride, vfb->height, dataFmt, nullptr, vfb->fb_stride);

unbind = true;

pixelBufObj_[currentPBO_].fb_address = fb_address;
pixelBufObj_[currentPBO_].size = bufSize;
pixelBufObj_[currentPBO_].stride = vfb->fb_stride;
pixelBufObj_[currentPBO_].height = vfb->height;
pixelBufObj_[currentPBO_].format = vfb->format;
pixelBufObj_[currentPBO_].reading = true;
}

currentPBO_ = nextPBO;

if (unbind) {
render_->BindPixelPackBuffer(0);
}
}

void FramebufferManagerGLES::PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h) {
if (!vfb->fbo) {
ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackFramebufferSync_: vfb->fbo == 0");
Expand Down
41 changes: 10 additions & 31 deletions GPU/GLES/FramebufferManagerGLES.h
Expand Up @@ -36,19 +36,6 @@ class TextureCacheGLES;
class DrawEngineGLES;
class ShaderManagerGLES;

// Simple struct for asynchronous PBO readbacks
struct AsyncPBO {
GLRBuffer *buffer;
u32 maxSize;

u32 fb_address;
u32 stride;
u32 height;
u32 size;
GEBufferFormat format;
bool reading;
};

class FramebufferManagerGLES : public FramebufferManagerCommon {
public:
FramebufferManagerGLES(Draw::DrawContext *draw, GLRenderManager *render);
Expand All @@ -67,7 +54,6 @@ class FramebufferManagerGLES : public FramebufferManagerCommon {
void EndFrame();
void Resized() override;
void DeviceLost();
void SetLineWidth();
void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override;

void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) override;
Expand All @@ -77,7 +63,6 @@ class FramebufferManagerGLES : public FramebufferManagerCommon {

// Reads a rectangular subregion of a framebuffer to the right position in its backing memory.
void ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) override;
void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes) override;

bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override;

Expand Down Expand Up @@ -105,24 +90,22 @@ class FramebufferManagerGLES : public FramebufferManagerCommon {
void CompileDraw2DProgram();
void CompilePostShader();

void PackFramebufferAsync_(VirtualFramebuffer *vfb); // Not used under ES currently
void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h) override;
void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h);

GLRenderManager *render_;

// Used by DrawPixels
GLRTexture *drawPixelsTex_;
GEBufferFormat drawPixelsTexFormat_;
int drawPixelsTexW_;
int drawPixelsTexH_;
GLRTexture *drawPixelsTex_ = nullptr;
GEBufferFormat drawPixelsTexFormat_ = GE_FORMAT_INVALID;
int drawPixelsTexW_ = 0;
int drawPixelsTexH_ = 0;

u8 *convBuf_;
u32 convBufSize_;
u8 *convBuf_ = nullptr;
u32 convBufSize_ = 0;
GLRProgram *draw2dprogram_ = nullptr;
GLRProgram *postShaderProgram_ = nullptr;


GLRProgram *stencilUploadProgram_ = nullptr;
int u_stencilUploadTex = -1;
int u_stencilValue = -1;
Expand All @@ -137,17 +120,13 @@ class FramebufferManagerGLES : public FramebufferManagerCommon {
int pixelDeltaLoc_ = -1;
int deltaLoc_ = -1;

TextureCacheGLES *textureCacheGL_;
ShaderManagerGLES *shaderManagerGL_;
DrawEngineGLES *drawEngineGL_;
TextureCacheGLES *textureCacheGL_ = nullptr;
ShaderManagerGLES *shaderManagerGL_ = nullptr;
DrawEngineGLES *drawEngineGL_ = nullptr;

struct Simple2DVertex {
float pos[3];
float uv[2];
};
GLRInputLayout *simple2DInputLayout_;

// Not used under ES currently.
AsyncPBO *pixelBufObj_; //this isn't that large
u8 currentPBO_;
GLRInputLayout *simple2DInputLayout_ = nullptr;
};

0 comments on commit 63b9140

Please sign in to comment.