[client] opengl: indirectly access non-OpenGL 1.3 functions

This commit adds check for the extensions that we need and then calls
the functions indirectly through gl_dynprocs.

This should improve compatibility with older versions of OpenGL, as we
now fallback to the ARB extensions if possible, and in the case of
glGenerateMipmap, we can handle the function not existing at all.
This commit is contained in:
Quantum 2021-09-30 06:36:24 -04:00 committed by Geoffrey McRae
parent ad4b40fad6
commit 6370350006

View file

@ -35,6 +35,7 @@
#include "common/option.h" #include "common/option.h"
#include "common/framebuffer.h" #include "common/framebuffer.h"
#include "common/locking.h" #include "common/locking.h"
#include "gl_dynprocs.h"
#include "ll.h" #include "ll.h"
#include "util.h" #include "util.h"
@ -413,6 +414,31 @@ bool opengl_renderStartup(LG_Renderer * renderer, bool useDMA)
DEBUG_INFO("GL_AMD_pinned_memory is available but not in use"); DEBUG_INFO("GL_AMD_pinned_memory is available but not in use");
} }
GLint maj, min;
glGetIntegerv(GL_MAJOR_VERSION, &maj);
glGetIntegerv(GL_MINOR_VERSION, &min);
if ((maj < 3 || (maj == 3 && min < 2)) && !util_hasGLExt(exts, "GL_ARB_sync"))
{
DEBUG_ERROR("Need OpenGL 3.2+ or GL_ARB_sync for sync objects");
return false;
}
if (maj < 2 && !util_hasGLExt(exts, "GL_ARB_pixel_buffer_object"))
{
DEBUG_ERROR("Need OpenGL 2.0+ or GL_ARB_pixel_buffer_object");
return false;
}
if (this->opt.mipmap && maj < 3 &&
!util_hasGLExt(exts, "GL_ARB_framebuffer_object") &&
!util_hasGLExt(exts, "GL_EXT_framebuffer_object"))
{
DEBUG_WARN("Need OpenGL 3.0+ or GL_ARB_framebuffer_object or "
"GL_EXT_framebuffer_object for glGenerateMipmap, disabling mipmaps");
this->opt.mipmap = false;
}
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glEnable(GL_COLOR_MATERIAL); glEnable(GL_COLOR_MATERIAL);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@ -705,7 +731,7 @@ static enum ConfigStatus configure(struct Inst * this)
this->texSize = this->format.height * this->format.pitch; this->texSize = this->format.height * this->format.pitch;
this->texPos = 0; this->texPos = 0;
glGenBuffers(BUFFER_COUNT, this->vboID); g_gl_dynProcs.glGenBuffers(BUFFER_COUNT, this->vboID);
if (check_gl_error("glGenBuffers")) if (check_gl_error("glGenBuffers"))
{ {
LG_UNLOCK(this->formatLock); LG_UNLOCK(this->formatLock);
@ -728,14 +754,14 @@ static enum ConfigStatus configure(struct Inst * this)
memset(this->texPixels[i], 0, this->texSize); memset(this->texPixels[i], 0, this->texSize);
glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, this->vboID[i]); g_gl_dynProcs.glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, this->vboID[i]);
if (check_gl_error("glBindBuffer")) if (check_gl_error("glBindBuffer"))
{ {
LG_UNLOCK(this->formatLock); LG_UNLOCK(this->formatLock);
return CONFIG_STATUS_ERROR; return CONFIG_STATUS_ERROR;
} }
glBufferData( g_gl_dynProcs.glBufferData(
GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD,
this->texSize, this->texSize,
this->texPixels[i], this->texPixels[i],
@ -748,20 +774,20 @@ static enum ConfigStatus configure(struct Inst * this)
return CONFIG_STATUS_ERROR; return CONFIG_STATUS_ERROR;
} }
} }
glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0); g_gl_dynProcs.glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0);
} }
else else
{ {
for(int i = 0; i < BUFFER_COUNT; ++i) for(int i = 0; i < BUFFER_COUNT; ++i)
{ {
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[i]); g_gl_dynProcs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[i]);
if (check_gl_error("glBindBuffer")) if (check_gl_error("glBindBuffer"))
{ {
LG_UNLOCK(this->formatLock); LG_UNLOCK(this->formatLock);
return CONFIG_STATUS_ERROR; return CONFIG_STATUS_ERROR;
} }
glBufferData( g_gl_dynProcs.glBufferData(
GL_PIXEL_UNPACK_BUFFER, GL_PIXEL_UNPACK_BUFFER,
this->texSize, this->texSize,
NULL, NULL,
@ -773,7 +799,7 @@ static enum ConfigStatus configure(struct Inst * this)
return CONFIG_STATUS_ERROR; return CONFIG_STATUS_ERROR;
} }
} }
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); g_gl_dynProcs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
} }
// create the frame textures // create the frame textures
@ -833,7 +859,7 @@ static enum ConfigStatus configure(struct Inst * this)
} }
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); g_gl_dynProcs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
this->drawStart = nanotime(); this->drawStart = nanotime();
this->configured = true; this->configured = true;
@ -853,7 +879,7 @@ static void deconfigure(struct Inst * this)
if (this->hasBuffers) if (this->hasBuffers)
{ {
glDeleteBuffers(BUFFER_COUNT, this->vboID); g_gl_dynProcs.glDeleteBuffers(BUFFER_COUNT, this->vboID);
this->hasBuffers = false; this->hasBuffers = false;
} }
@ -863,7 +889,7 @@ static void deconfigure(struct Inst * this)
{ {
if (this->fences[i]) if (this->fences[i])
{ {
glDeleteSync(this->fences[i]); g_gl_dynProcs.glDeleteSync(this->fences[i]);
this->fences[i] = NULL; this->fences[i] = NULL;
} }
@ -1028,7 +1054,7 @@ static bool opengl_bufferFn(void * opaque, const void * data, size_t size)
struct Inst * this = (struct Inst *)opaque; struct Inst * this = (struct Inst *)opaque;
// update the buffer, this performs a DMA transfer if possible // update the buffer, this performs a DMA transfer if possible
glBufferSubData( g_gl_dynProcs.glBufferSubData(
GL_PIXEL_UNPACK_BUFFER, GL_PIXEL_UNPACK_BUFFER,
this->texPos, this->texPos,
size, size,
@ -1042,9 +1068,9 @@ static bool opengl_bufferFn(void * opaque, const void * data, size_t size)
static bool drawFrame(struct Inst * this) static bool drawFrame(struct Inst * this)
{ {
if (glIsSync(this->fences[this->texWIndex])) if (g_gl_dynProcs.glIsSync(this->fences[this->texWIndex]))
{ {
switch(glClientWaitSync(this->fences[this->texWIndex], 0, GL_TIMEOUT_IGNORED)) switch(g_gl_dynProcs.glClientWaitSync(this->fences[this->texWIndex], 0, GL_TIMEOUT_IGNORED))
{ {
case GL_ALREADY_SIGNALED: case GL_ALREADY_SIGNALED:
break; break;
@ -1062,7 +1088,7 @@ static bool drawFrame(struct Inst * this)
break; break;
} }
glDeleteSync(this->fences[this->texWIndex]); g_gl_dynProcs.glDeleteSync(this->fences[this->texWIndex]);
this->fences[this->texWIndex] = NULL; this->fences[this->texWIndex] = NULL;
this->texRIndex = this->texWIndex; this->texRIndex = this->texWIndex;
@ -1079,7 +1105,7 @@ static bool drawFrame(struct Inst * this)
LG_LOCK(this->formatLock); LG_LOCK(this->formatLock);
glBindTexture(GL_TEXTURE_2D, this->frames[this->texWIndex]); glBindTexture(GL_TEXTURE_2D, this->frames[this->texWIndex]);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[this->texWIndex]); g_gl_dynProcs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[this->texWIndex]);
const int bpp = this->format.bpp / 8; const int bpp = this->format.bpp / 8;
glPixelStorei(GL_UNPACK_ALIGNMENT , bpp); glPixelStorei(GL_UNPACK_ALIGNMENT , bpp);
@ -1119,7 +1145,7 @@ static bool drawFrame(struct Inst * this)
} }
// unbind the buffer // unbind the buffer
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); g_gl_dynProcs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
const bool mipmap = this->opt.mipmap && ( const bool mipmap = this->opt.mipmap && (
(this->format.width > this->destRect.w) || (this->format.width > this->destRect.w) ||
@ -1127,7 +1153,7 @@ static bool drawFrame(struct Inst * this)
if (mipmap) if (mipmap)
{ {
glGenerateMipmap(GL_TEXTURE_2D); g_gl_dynProcs.glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
} }
@ -1140,7 +1166,7 @@ static bool drawFrame(struct Inst * this)
// set a fence so we don't overwrite a buffer in use // set a fence so we don't overwrite a buffer in use
this->fences[this->texWIndex] = this->fences[this->texWIndex] =
glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); g_gl_dynProcs.glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glFlush(); glFlush();
LG_UNLOCK(this->formatLock); LG_UNLOCK(this->formatLock);