Use OpenGL to allocate the canvas buffer to avoid a costly memcpy

This commit is contained in:
Magnus Norddahl 2016-10-18 01:16:36 +02:00
parent cd21d017fb
commit df3f5ae882
2 changed files with 77 additions and 37 deletions

View file

@ -1093,7 +1093,24 @@ bool OpenGLSWFrameBuffer::Lock(bool buffered)
} }
assert(!In2D); assert(!In2D);
Accel2D = vid_hw2d; Accel2D = vid_hw2d;
Buffer = MemBuffer; if (UseMappedMemBuffer)
{
if (!MappedMemBuffer)
{
BindFBBuffer();
MappedMemBuffer = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);
Pitch = Width;
if (MappedMemBuffer == nullptr)
return true;
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
Buffer = (uint8_t*)MappedMemBuffer;
}
else
{
Buffer = MemBuffer;
}
return false; return false;
} }
@ -1269,54 +1286,73 @@ bool OpenGLSWFrameBuffer::PaintToWindow()
// //
//========================================================================== //==========================================================================
void OpenGLSWFrameBuffer::BindFBBuffer()
{
int usage = UseMappedMemBuffer ? GL_DYNAMIC_DRAW : GL_STREAM_DRAW;
int pixelsize = IsBgra() ? 4 : 1;
int size = Width * Height * pixelsize;
if (FBTexture->Buffers[0] == 0)
{
glGenBuffers(2, (GLuint*)FBTexture->Buffers);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, FBTexture->Buffers[1]);
glBufferData(GL_PIXEL_UNPACK_BUFFER, size, nullptr, usage);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, FBTexture->Buffers[0]);
glBufferData(GL_PIXEL_UNPACK_BUFFER, size, nullptr, usage);
}
else
{
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, FBTexture->Buffers[FBTexture->CurrentBuffer]);
}
}
void OpenGLSWFrameBuffer::Draw3DPart(bool copy3d) void OpenGLSWFrameBuffer::Draw3DPart(bool copy3d)
{ {
if (copy3d) if (copy3d)
{ {
int pixelsize = IsBgra() ? 4 : 1; BindFBBuffer();
int size = Width * Height * pixelsize; FBTexture->CurrentBuffer = (FBTexture->CurrentBuffer + 1) & 1;
if (FBTexture->Buffers[0] == 0) if (!UseMappedMemBuffer)
{ {
glGenBuffers(2, (GLuint*)FBTexture->Buffers); int pixelsize = IsBgra() ? 4 : 1;
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, FBTexture->Buffers[0]); int size = Width * Height * pixelsize;
glBufferData(GL_PIXEL_UNPACK_BUFFER, size, nullptr, GL_STREAM_DRAW);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, FBTexture->Buffers[1]);
glBufferData(GL_PIXEL_UNPACK_BUFFER, size, nullptr, GL_STREAM_DRAW);
}
else
{
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, FBTexture->Buffers[FBTexture->CurrentBuffer]);
FBTexture->CurrentBuffer = (FBTexture->CurrentBuffer + 1) & 1;
}
uint8_t *dest = (uint8_t*)MapBuffer(GL_PIXEL_UNPACK_BUFFER, size); uint8_t *dest = (uint8_t*)MapBuffer(GL_PIXEL_UNPACK_BUFFER, size);
if (dest) if (dest)
{
if (Pitch == Width)
{ {
memcpy(dest, MemBuffer, Width * Height * pixelsize); if (Pitch == Width)
}
else
{
uint8_t *src = MemBuffer;
for (int y = 0; y < Height; y++)
{ {
memcpy(dest, src, Width * pixelsize); memcpy(dest, MemBuffer, Width * Height * pixelsize);
dest += Width * pixelsize;
src += Pitch * pixelsize;
} }
else
{
uint8_t *src = MemBuffer;
for (int y = 0; y < Height; y++)
{
memcpy(dest, src, Width * pixelsize);
dest += Width * pixelsize;
src += Pitch * pixelsize;
}
}
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
} }
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
GLint oldBinding = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding);
glBindTexture(GL_TEXTURE_2D, FBTexture->Texture);
if (IsBgra())
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Width, Height, GL_BGRA, GL_UNSIGNED_BYTE, 0);
else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Width, Height, GL_RED, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, oldBinding);
} }
else if (MappedMemBuffer)
{
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
MappedMemBuffer = nullptr;
}
GLint oldBinding = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding);
glBindTexture(GL_TEXTURE_2D, FBTexture->Texture);
if (IsBgra())
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Width, Height, GL_BGRA, GL_UNSIGNED_BYTE, 0);
else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Width, Height, GL_RED, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, oldBinding);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
} }

View file

@ -194,6 +194,10 @@ private:
void DrawTriangleList(int minIndex, int numVertices, int startIndex, int primitiveCount); void DrawTriangleList(int minIndex, int numVertices, int startIndex, int primitiveCount);
void Present(); void Present();
void BindFBBuffer();
void *MappedMemBuffer = nullptr;
bool UseMappedMemBuffer = true;
static uint32_t ColorARGB(uint32_t a, uint32_t r, uint32_t g, uint32_t b) { return ((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | ((b) & 0xff); } static uint32_t ColorARGB(uint32_t a, uint32_t r, uint32_t g, uint32_t b) { return ((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | ((b) & 0xff); }
static uint32_t ColorRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) { return ColorARGB(a, r, g, b); } static uint32_t ColorRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) { return ColorARGB(a, r, g, b); }
static uint32_t ColorXRGB(uint32_t r, uint32_t g, uint32_t b) { return ColorARGB(0xff, r, g, b); } static uint32_t ColorXRGB(uint32_t r, uint32_t g, uint32_t b) { return ColorARGB(0xff, r, g, b); }