From df3f5ae882c888c12ed73323292f5237538d108c Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 18 Oct 2016 01:16:36 +0200 Subject: [PATCH] Use OpenGL to allocate the canvas buffer to avoid a costly memcpy --- src/gl/system/gl_swframebuffer.cpp | 110 +++++++++++++++++++---------- src/gl/system/gl_swframebuffer.h | 4 ++ 2 files changed, 77 insertions(+), 37 deletions(-) diff --git a/src/gl/system/gl_swframebuffer.cpp b/src/gl/system/gl_swframebuffer.cpp index a239f9d57..b6d163044 100644 --- a/src/gl/system/gl_swframebuffer.cpp +++ b/src/gl/system/gl_swframebuffer.cpp @@ -1093,7 +1093,24 @@ bool OpenGLSWFrameBuffer::Lock(bool buffered) } assert(!In2D); 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; } @@ -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) { if (copy3d) { - int pixelsize = IsBgra() ? 4 : 1; - int size = Width * Height * pixelsize; + BindFBBuffer(); + FBTexture->CurrentBuffer = (FBTexture->CurrentBuffer + 1) & 1; - if (FBTexture->Buffers[0] == 0) + if (!UseMappedMemBuffer) { - glGenBuffers(2, (GLuint*)FBTexture->Buffers); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, FBTexture->Buffers[0]); - 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; - } + int pixelsize = IsBgra() ? 4 : 1; + int size = Width * Height * pixelsize; - uint8_t *dest = (uint8_t*)MapBuffer(GL_PIXEL_UNPACK_BUFFER, size); - if (dest) - { - if (Pitch == Width) + uint8_t *dest = (uint8_t*)MapBuffer(GL_PIXEL_UNPACK_BUFFER, size); + if (dest) { - memcpy(dest, MemBuffer, Width * Height * pixelsize); - } - else - { - uint8_t *src = MemBuffer; - for (int y = 0; y < Height; y++) + if (Pitch == Width) { - memcpy(dest, src, Width * pixelsize); - dest += Width * pixelsize; - src += Pitch * pixelsize; + memcpy(dest, MemBuffer, Width * Height * 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); } diff --git a/src/gl/system/gl_swframebuffer.h b/src/gl/system/gl_swframebuffer.h index 315101fde..226d8cca7 100644 --- a/src/gl/system/gl_swframebuffer.h +++ b/src/gl/system/gl_swframebuffer.h @@ -194,6 +194,10 @@ private: void DrawTriangleList(int minIndex, int numVertices, int startIndex, int primitiveCount); 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 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); }