Skip to content

Commit

Permalink
Replace buffer region implementation with GL3 renderbuffers
Browse files Browse the repository at this point in the history
This lets us enable partial region writes in the buffer region
interface, which is a huge performance boost for the dirty rectangle
system and gets us most of the way to DirectX-like framerates.
  • Loading branch information
nsgomez committed Oct 17, 2023
1 parent 308fffb commit 034ec75
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 21 deletions.
22 changes: 22 additions & 0 deletions scgl/GLSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ PFNGLCLIENTACTIVETEXTUREPROC glClientActiveTexture = nullptr;
PFNGLGETSTRINGIPROC glGetStringi = nullptr;
PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback = nullptr;

PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = nullptr;
PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = nullptr;
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = nullptr;
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = nullptr;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = nullptr;
PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = nullptr;
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = nullptr;
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = nullptr;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = nullptr;
PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer = nullptr;

PFNWGLCREATEBUFFERREGIONARBPROC wglCreateBufferRegionARB = nullptr;
PFNWGLDELETEBUFFERREGIONARBPROC wglDeleteBufferRegionARB = nullptr;
PFNWGLSAVEBUFFERREGIONARBPROC wglSaveBufferRegionARB = nullptr;
Expand All @@ -32,6 +43,17 @@ void InitGLSupport(void) {
TRY_LOAD(PFNGLGETSTRINGIPROC, glGetStringi);
TRY_LOAD(PFNGLDEBUGMESSAGECALLBACKPROC, glDebugMessageCallback);

TRY_LOAD(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer);
TRY_LOAD(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers);
TRY_LOAD(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers);
TRY_LOAD(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage);
TRY_LOAD(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer);
TRY_LOAD(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers);
TRY_LOAD(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers);
TRY_LOAD(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus);
TRY_LOAD(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer);
TRY_LOAD(PFNGLBLITFRAMEBUFFERPROC, glBlitFramebuffer);

TRY_LOAD(PFNWGLCREATEBUFFERREGIONARBPROC, wglCreateBufferRegionARB);
TRY_LOAD(PFNWGLDELETEBUFFERREGIONARBPROC, wglDeleteBufferRegionARB);
TRY_LOAD(PFNWGLSAVEBUFFERREGIONARBPROC, wglSaveBufferRegionARB);
Expand Down
37 changes: 37 additions & 0 deletions scgl/GLSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint
typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture);

typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer);
typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint* renderbuffers);
typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint* renderbuffers);
typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer);
typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint* framebuffers);
typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint* framebuffers);
typedef GLenum(APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target);
typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);

typedef const GLubyte* (APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index);

typedef void (APIENTRY* GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam);
Expand Down Expand Up @@ -78,6 +89,21 @@ typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, co
#define GL_OPERAND3_RGB_NV 0x8593
#define GL_OPERAND3_ALPHA_NV 0x859B

#define GL_RGB5_A1 0x8057
#define GL_RGBA8 0x8058
#define GL_DEPTH_COMPONENT16 0x81A5
#define GL_DEPTH_COMPONENT24 0x81A6
#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6
#define GL_READ_FRAMEBUFFER 0x8CA8
#define GL_DRAW_FRAMEBUFFER 0x8CA9
#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA
#define GL_COLOR_ATTACHMENT0 0x8CE0
#define GL_DEPTH_ATTACHMENT 0x8D00
#define GL_FRAMEBUFFER 0x8D40
#define GL_RENDERBUFFER 0x8D41
#define GL_FRAMEBUFFER_DEFAULT 0x8218
#define GL_FRAMEBUFFER_COMPLETE 0x8CD5

#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
#define GL_DEBUG_CALLBACK_FUNCTION 0x8244
Expand Down Expand Up @@ -209,6 +235,17 @@ extern PFNGLCLIENTACTIVETEXTUREPROC glClientActiveTexture;
extern PFNGLGETSTRINGIPROC glGetStringi;
extern PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback;

extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;

extern PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
extern PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;

Expand Down
4 changes: 3 additions & 1 deletion scgl/cGDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ namespace nSCGL
viewportWidth(0),
viewportHeight(0),
bufferRegionFlags(0),
bufferRegionHandles(),
framebufferHandles(),
renderbufferHandles(),
framebufferMasks(),
supportedExtensions(),
windowHandle(nullptr),
deviceContext(nullptr),
Expand Down
4 changes: 3 additions & 1 deletion scgl/cGDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ namespace nSCGL
// We're not expecting to use a lot of buffer regions simultaneously, so we'll use an
// 8-bit mask to indicate which regions are allocated and free.
uint8_t bufferRegionFlags;
void* bufferRegionHandles[MAX_BUFFER_REGIONS];
uint32_t framebufferHandles[MAX_BUFFER_REGIONS];
uint32_t renderbufferHandles[MAX_BUFFER_REGIONS];
uint32_t framebufferMasks[MAX_BUFFER_REGIONS];

private:
struct {
Expand Down
4 changes: 2 additions & 2 deletions scgl/cGDriver_Viewport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ namespace nSCGL
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cAlphaBits = (newMode.depth == 32) ? 8 : 1;
pfd.cColorBits = (newMode.depth == 32) ? 24 : 16;
pfd.cColorBits = (newMode.depth == 32) ? 24 : 15;
pfd.cDepthBits = (newMode.depth == 32) ? 24 : 16;
pfd.cStencilBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
Expand Down Expand Up @@ -210,7 +210,7 @@ namespace nSCGL
wglMakeCurrent(hdc, static_cast<HGLRC>(glContext));

if (supportedExtensions.swapControl) {
wglSwapIntervalEXT(-1);
wglSwapIntervalEXT(0);
}

// Window should now be ready to go, show it and wrap up initialization
Expand Down
71 changes: 54 additions & 17 deletions scgl/ext/cGDriver_BufferRegions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,55 +26,92 @@ namespace nSCGL
}

uint32_t cGDriver::NewBufferRegion(int32_t gdBufferRegionType) {
static GLenum regionTypeMap[] = { WGL_BACK_COLOR_BUFFER_BIT_ARB, WGL_DEPTH_BUFFER_BIT_ARB, WGL_STENCIL_BUFFER_BIT_ARB };
static GLenum regionTypeMap[] = { WGL_BACK_COLOR_BUFFER_BIT_ARB, WGL_DEPTH_BUFFER_BIT_ARB };
SIZE_CHECK_RETVAL(gdBufferRegionType, regionTypeMap, 0);

if (!supportedExtensions.bufferRegion || wglCreateBufferRegionARB == nullptr) {
return 0;
}

uint32_t bufferRegionIndex = FindFreeBufferRegionIndex();
if (bufferRegionIndex == -1) {
return 0;
}

HANDLE result = wglCreateBufferRegionARB(reinterpret_cast<HDC>(deviceContext), 0, regionTypeMap[gdBufferRegionType]);
if (result == nullptr) {
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);

GLuint renderbuffer;
glGenRenderbuffers(1, &renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);

GLuint renderbufferStorageType, attachmentType;
GLuint framebufferMask;

if (regionTypeMap[gdBufferRegionType] == WGL_BACK_COLOR_BUFFER_BIT_ARB) {
renderbufferStorageType = (videoModes[currentVideoMode].depth == 32) ? GL_RGBA8 : GL_RGB5_A1;
attachmentType = GL_COLOR_ATTACHMENT0;
framebufferMask = GL_COLOR_BUFFER_BIT;
}
else {
renderbufferStorageType = (videoModes[currentVideoMode].depth == 32) ? GL_DEPTH_COMPONENT24 : GL_DEPTH_COMPONENT16;
attachmentType = GL_DEPTH_ATTACHMENT;
framebufferMask = GL_DEPTH_BUFFER_BIT;
}

glRenderbufferStorage(GL_RENDERBUFFER, renderbufferStorageType, windowWidth, windowHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachmentType, GL_RENDERBUFFER, renderbuffer);

if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
return 0;
}

bufferRegionFlags |= 1 << bufferRegionIndex;
bufferRegionHandles[bufferRegionIndex] = result;
framebufferHandles[bufferRegionIndex] = framebuffer;
renderbufferHandles[bufferRegionIndex] = renderbuffer;
framebufferMasks[bufferRegionIndex] = framebufferMask;

glBindFramebuffer(GL_FRAMEBUFFER, 0);
return bufferRegionIndex + 1;
}

bool cGDriver::DeleteBufferRegion(int32_t region) {
uint32_t bufferRegionIndex = region - 1;
if ((bufferRegionFlags & (1 << bufferRegionIndex)) == 0) {
return true;
}

wglDeleteBufferRegionARB(bufferRegionHandles[bufferRegionIndex]);
bufferRegionHandles[bufferRegionIndex] = nullptr;
bufferRegionFlags &= ~(1 << bufferRegionIndex);
glDeleteRenderbuffers(1, &renderbufferHandles[bufferRegionIndex]);
glDeleteFramebuffers(1, &framebufferHandles[bufferRegionIndex]);

bufferRegionFlags &= ~(1 << bufferRegionIndex);
return true;
}

bool cGDriver::ReadBufferRegion(uint32_t region, GLint x, GLint y, GLsizei width, GLsizei height, int32_t unused0, int32_t unused1) {
return wglSaveBufferRegionARB(bufferRegionHandles[region - 1], x, y, width, height);
bool cGDriver::ReadBufferRegion(uint32_t region, GLint x0, GLint y0, GLsizei width, GLsizei height, int32_t unused0, int32_t unused1) {
uint32_t bufferRegionIndex = region - 1;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebufferHandles[bufferRegionIndex]);

GLint x1 = x0 + width;
GLint y1 = y0 + height;

glBlitFramebuffer(x0, y0, x1, y1, x0, y0, x1, y1, framebufferMasks[bufferRegionIndex], GL_NEAREST);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
return true;
}

bool cGDriver::DrawBufferRegion(uint32_t region, GLint x, GLint y, GLsizei width, GLsizei height, GLint xDest, GLint yDest) {
return wglRestoreBufferRegionARB(bufferRegionHandles[region - 1], xDest, y, width, height, x, yDest);
uint32_t bufferRegionIndex = region - 1;
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferHandles[bufferRegionIndex]);

glBlitFramebuffer(x, yDest, x + width, yDest + height, xDest, y, xDest + width, y + height, framebufferMasks[bufferRegionIndex], GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
return true;
}

bool cGDriver::IsBufferRegion(uint32_t region) {
return (bufferRegionFlags & (1 << (region - 1))) != 0;
}

bool cGDriver::CanDoPartialRegionWrites(void) {
// TODO: we might be able to implement partial writes if we use OpenGL 3.0 and glBlitFramebuffer
// instead of the older WGL_ARB_buffer_region extension.
return false;
return true;
}

bool cGDriver::CanDoOffsetReads(void) {
Expand Down

0 comments on commit 034ec75

Please sign in to comment.