OpenGL: readback efb2ram with different strides at once

This is done with a pixel buffer object. We still have to stall the GPU, but
we only do it once per efb2ram call.
As the cpu can't access the vram, it has to queue a memcpy for the gpu and
wait for the gpu to finish this copy. We did this for every cache line which
is just stupid. Now we copy the complete texture into a pbo and readback this
at once. So we don't have to wait for lots of round-trip-times.
This commit is contained in:
degasus 2013-11-26 20:05:49 +01:00
parent db9c586356
commit 95aeedec19

View File

@ -44,6 +44,8 @@ static GLuint s_encode_VBO = 0;
static GLuint s_encode_VAO = 0; static GLuint s_encode_VAO = 0;
static TargetRectangle s_cached_sourceRc; static TargetRectangle s_cached_sourceRc;
static GLuint s_PBO = 0; // for readback with different strides
static const char *VProgram = static const char *VProgram =
"ATTRIN vec2 rawpos;\n" "ATTRIN vec2 rawpos;\n"
"ATTRIN vec2 tex0;\n" "ATTRIN vec2 tex0;\n"
@ -186,6 +188,8 @@ void Init()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, renderBufferWidth, renderBufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, renderBufferWidth, renderBufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glGenBuffers(1, &s_PBO);
CreatePrograms(); CreatePrograms();
} }
@ -196,6 +200,7 @@ void Shutdown()
glDeleteFramebuffers(1, &s_texConvFrameBuffer); glDeleteFramebuffers(1, &s_texConvFrameBuffer);
glDeleteBuffers(1, &s_encode_VBO ); glDeleteBuffers(1, &s_encode_VBO );
glDeleteVertexArrays(1, &s_encode_VAO ); glDeleteVertexArrays(1, &s_encode_VAO );
glDeleteBuffers(1, &s_PBO);
s_rgbToYuyvProgram.Destroy(); s_rgbToYuyvProgram.Destroy();
s_yuyvToRgbProgram.Destroy(); s_yuyvToRgbProgram.Destroy();
@ -206,6 +211,7 @@ void Shutdown()
s_srcTexture = 0; s_srcTexture = 0;
s_dstTexture = 0; s_dstTexture = 0;
s_texConvFrameBuffer = 0; s_texConvFrameBuffer = 0;
s_PBO = 0;
} }
void EncodeToRamUsingShader(GLuint srcTexture, const TargetRectangle& sourceRc, void EncodeToRamUsingShader(GLuint srcTexture, const TargetRectangle& sourceRc,
@ -267,25 +273,37 @@ void EncodeToRamUsingShader(GLuint srcTexture, const TargetRectangle& sourceRc,
// TODO: make this less slow. // TODO: make this less slow.
int writeStride = bpmem.copyMipMapStrideChannels * 32; int writeStride = bpmem.copyMipMapStrideChannels * 32;
int dstSize = dstWidth*dstHeight*4;
int readHeight = readStride / dstWidth / 4; // 4 bytes per pixel
int readLoops = dstHeight / readHeight;
if (writeStride != readStride && toTexture) if (writeStride != readStride && readLoops > 1 && toTexture)
{ {
// writing to a texture of a different size // writing to a texture of a different size
// also copy more then one block line, so the different strides matters
// copy into one pbo first, map this buffer, and then memcpy into gc memory
// in this way, we only have one vram->ram transfer, but maybe a bigger
// cpu overhead because of the pbo
glBindBuffer(GL_PIXEL_PACK_BUFFER, s_PBO);
glBufferData(GL_PIXEL_PACK_BUFFER, dstSize, NULL, GL_STREAM_READ);
glReadPixels(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0);
u8* pbo = (u8*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, dstSize, GL_MAP_READ_BIT);
int readHeight = readStride / dstWidth; //int readStart = 0;
readHeight /= 4; // 4 bytes per pixel
int readStart = 0;
int readLoops = dstHeight / readHeight;
for (int i = 0; i < readLoops; i++) for (int i = 0; i < readLoops; i++)
{ {
glReadPixels(0, readStart, (GLsizei)dstWidth, (GLsizei)readHeight, GL_BGRA, GL_UNSIGNED_BYTE, destAddr); memcpy(destAddr, pbo, readStride);
readStart += readHeight; pbo += readStride;
destAddr += writeStride; destAddr += writeStride;
} }
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
} }
else else
{
glReadPixels(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, destAddr); glReadPixels(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, destAddr);
}
GL_REPORT_ERRORD(); GL_REPORT_ERRORD();