[opengl] Add support for AMD_pinned_memory if it is available

This commit is contained in:
Geoffrey McRae 2018-05-15 13:23:44 +10:00
parent ae1344d1a0
commit 332d53e016

View File

@ -21,6 +21,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <unistd.h> #include <unistd.h>
#include <malloc.h>
#include <SDL2/SDL_ttf.h> #include <SDL2/SDL_ttf.h>
@ -62,6 +63,7 @@ struct Inst
LG_RendererParams params; LG_RendererParams params;
struct Options opt; struct Options opt;
bool amdPinnedMemSupport;
bool configured; bool configured;
bool reconfigure; bool reconfigure;
SDL_GLContext glContext; SDL_GLContext glContext;
@ -92,6 +94,7 @@ struct Inst
bool hasTextures, hasFrames; bool hasTextures, hasFrames;
GLuint frames[BUFFER_COUNT]; GLuint frames[BUFFER_COUNT];
GLsync fences[BUFFER_COUNT];
void * decoderFrames[BUFFER_COUNT]; void * decoderFrames[BUFFER_COUNT];
GLuint textures[TEXTURE_COUNT]; GLuint textures[TEXTURE_COUNT];
@ -542,6 +545,20 @@ static bool configure(struct Inst * this, SDL_Window *window)
DEBUG_INFO("Vendor : %s", glGetString(GL_VENDOR )); DEBUG_INFO("Vendor : %s", glGetString(GL_VENDOR ));
DEBUG_INFO("Renderer: %s", glGetString(GL_RENDERER)); DEBUG_INFO("Renderer: %s", glGetString(GL_RENDERER));
DEBUG_INFO("Version : %s", glGetString(GL_VERSION )); DEBUG_INFO("Version : %s", glGetString(GL_VERSION ));
GLint n;
glGetIntegerv(GL_NUM_EXTENSIONS, &n);
for(GLint i = 0; i < n; ++i)
{
const GLubyte *ext = glGetStringi(GL_EXTENSIONS, i);
this->amdPinnedMemSupport = (strcmp((const char *)ext, "GL_AMD_pinned_memory") == 0);
if (this->amdPinnedMemSupport)
{
DEBUG_INFO("Using GL_AMD_pinned_memory");
break;
}
}
this->doneInfo = true; this->doneInfo = true;
} }
@ -629,42 +646,73 @@ static bool configure(struct Inst * this, SDL_Window *window)
} }
this->hasBuffers = true; this->hasBuffers = true;
for(int i = 0; i < BUFFER_COUNT; ++i) if (this->amdPinnedMemSupport)
{ {
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[i]); const int pagesize = getpagesize();
if (check_gl_error("glBindBuffer")) for(int i = 0; i < BUFFER_COUNT; ++i)
{ {
LG_UNLOCK(this->formatLock); glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, this->vboID[i]);
return false; if (check_gl_error("glBindBuffer"))
} {
LG_UNLOCK(this->formatLock);
return false;
}
glBufferStorage( this->texPixels[i] = memalign(pagesize, this->texSize);
GL_PIXEL_UNPACK_BUFFER, glBufferData(
this->texSize, GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD,
NULL, this->texSize,
GL_MAP_WRITE_BIT | this->texPixels[i],
GL_MAP_PERSISTENT_BIT GL_STREAM_DRAW);
);
if (check_gl_error("glBufferStorage")) if (check_gl_error("glBufferData"))
{
LG_UNLOCK(this->formatLock);
return false;
}
}
glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0);
}
else
{
for(int i = 0; i < BUFFER_COUNT; ++i)
{ {
LG_UNLOCK(this->formatLock); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[i]);
return false; if (check_gl_error("glBindBuffer"))
} {
LG_UNLOCK(this->formatLock);
return false;
}
this->texPixels[i] = glMapBufferRange( glBufferStorage(
GL_PIXEL_UNPACK_BUFFER, GL_PIXEL_UNPACK_BUFFER,
0, this->texSize,
this->texSize, NULL,
GL_MAP_WRITE_BIT | GL_MAP_WRITE_BIT |
GL_MAP_PERSISTENT_BIT | GL_MAP_PERSISTENT_BIT
GL_MAP_FLUSH_EXPLICIT_BIT );
); if (check_gl_error("glBufferStorage"))
{
LG_UNLOCK(this->formatLock);
return false;
}
if (check_gl_error("glMapBufferRange")) this->texPixels[i] = glMapBufferRange(
{ GL_PIXEL_UNPACK_BUFFER,
LG_UNLOCK(this->formatLock); 0,
return false; this->texSize,
GL_MAP_WRITE_BIT |
GL_MAP_PERSISTENT_BIT |
GL_MAP_FLUSH_EXPLICIT_BIT
);
if (check_gl_error("glMapBufferRange"))
{
LG_UNLOCK(this->formatLock);
return false;
}
} }
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
} }
} }
@ -802,6 +850,22 @@ static void deconfigure(struct Inst * this)
this->hasBuffers = false; this->hasBuffers = false;
} }
if (this->amdPinnedMemSupport)
for(int i = 0; i < BUFFER_COUNT; ++i)
{
if (this->fences[i])
{
glDeleteSync(this->fences[i]);
this->fences[i] = NULL;
}
if (this->texPixels[i])
{
free(this->texPixels[i]);
this->texPixels[i] = NULL;
}
}
if (this->glContext) if (this->glContext)
{ {
SDL_GL_DeleteContext(this->glContext); SDL_GL_DeleteContext(this->glContext);
@ -982,13 +1046,29 @@ static bool draw_frame(struct Inst * this)
} }
else else
{ {
glBindTexture(GL_TEXTURE_2D, this->frames[this->texIndex]); if (this->amdPinnedMemSupport && glIsSync(this->fences[this->texIndex]))
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[this->texIndex]); {
switch(glClientWaitSync(this->fences[this->texIndex], 0, GL_TIMEOUT_IGNORED))
{
case GL_ALREADY_SIGNALED:
break;
glPixelStorei(GL_UNPACK_ALIGNMENT , 4); case GL_CONDITION_SATISFIED:
glPixelStorei(GL_UNPACK_ROW_LENGTH , DEBUG_WARN("Had to wait for the sync");
this->decoder->get_frame_stride(this->decoderData) break;
);
case GL_TIMEOUT_EXPIRED:
DEBUG_WARN("Timeout expired, DMA transfers are too slow!");
break;
case GL_WAIT_FAILED:
DEBUG_ERROR("Wait failed %s", gluErrorString(glGetError()));
break;
}
glDeleteSync(this->fences[this->texIndex]);
this->fences[this->texIndex] = NULL;
}
if (!this->decoder->get_buffer( if (!this->decoder->get_buffer(
this->decoderData, this->decoderData,
@ -1001,7 +1081,19 @@ static bool draw_frame(struct Inst * this)
return false; return false;
} }
glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, this->texSize); if (this->amdPinnedMemSupport)
this->fences[this->texIndex] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glBindTexture(GL_TEXTURE_2D, this->frames[this->texIndex]);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, this->vboID[this->texIndex]);
glPixelStorei(GL_UNPACK_ALIGNMENT , 4);
glPixelStorei(GL_UNPACK_ROW_LENGTH ,
this->decoder->get_frame_stride(this->decoderData)
);
if (!this->amdPinnedMemSupport)
glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, this->texSize);
// update the texture // update the texture
glTexSubImage2D( glTexSubImage2D(
@ -1023,7 +1115,7 @@ static bool draw_frame(struct Inst * this)
} }
// unbind the buffer // unbind the buffer
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
} }
const bool mipmap = this->opt.mipmap && ( const bool mipmap = this->opt.mipmap && (