diff --git a/scgl/GLSupport.cpp b/scgl/GLSupport.cpp index 960d246..9a7e852 100644 --- a/scgl/GLSupport.cpp +++ b/scgl/GLSupport.cpp @@ -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; @@ -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); diff --git a/scgl/GLSupport.h b/scgl/GLSupport.h index c7c279e..7c4a72d 100644 --- a/scgl/GLSupport.h +++ b/scgl/GLSupport.h @@ -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); @@ -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 @@ -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; diff --git a/scgl/cGDriver.cpp b/scgl/cGDriver.cpp index 18bfa6d..814873c 100644 --- a/scgl/cGDriver.cpp +++ b/scgl/cGDriver.cpp @@ -31,7 +31,9 @@ namespace nSCGL viewportWidth(0), viewportHeight(0), bufferRegionFlags(0), - bufferRegionHandles(), + framebufferHandles(), + renderbufferHandles(), + framebufferMasks(), supportedExtensions(), windowHandle(nullptr), deviceContext(nullptr), diff --git a/scgl/cGDriver.h b/scgl/cGDriver.h index bfe3b44..0345c71 100644 --- a/scgl/cGDriver.h +++ b/scgl/cGDriver.h @@ -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 { diff --git a/scgl/cGDriver_Viewport.cpp b/scgl/cGDriver_Viewport.cpp index e54bfab..eda254d 100644 --- a/scgl/cGDriver_Viewport.cpp +++ b/scgl/cGDriver_Viewport.cpp @@ -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; @@ -210,7 +210,7 @@ namespace nSCGL wglMakeCurrent(hdc, static_cast(glContext)); if (supportedExtensions.swapControl) { - wglSwapIntervalEXT(-1); + wglSwapIntervalEXT(0); } // Window should now be ready to go, show it and wrap up initialization diff --git a/scgl/ext/cGDriver_BufferRegions.cpp b/scgl/ext/cGDriver_BufferRegions.cpp index 30e65af..43db3af 100644 --- a/scgl/ext/cGDriver_BufferRegions.cpp +++ b/scgl/ext/cGDriver_BufferRegions.cpp @@ -26,45 +26,84 @@ 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(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) { @@ -72,9 +111,7 @@ namespace nSCGL } 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) {