summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
diff options
context:
space:
mode:
authorStenzek <stenzek@gmail.com>2018-02-25 17:56:09 +1000
committerStenzek <stenzek@gmail.com>2018-03-10 15:56:34 +1000
commitf9c829c7f711efadea1db7aabb51c703380fa03a (patch)
treecc645756b893e4c994360ec362977aaa9e5ad51f /Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
parentdec0c3bce85ceda89ea05f00b94aad00e675598d (diff)
OGL: Re-implement async shader compiling
Diffstat (limited to 'Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp')
-rw-r--r--Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp100
1 files changed, 85 insertions, 15 deletions
diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
index d953996396..60b7da82b9 100644
--- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
+++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
@@ -51,9 +51,10 @@ static std::unique_ptr<StreamBuffer> s_buffer;
static int num_failures = 0;
static GLuint CurrentProgram = 0;
-ProgramShaderCache::PipelineProgramMap ProgramShaderCache::pipelineprograms;
-std::mutex ProgramShaderCache::pipelineprogramlock;
+ProgramShaderCache::PipelineProgramMap ProgramShaderCache::s_pipeline_programs;
+std::mutex ProgramShaderCache::s_pipeline_program_lock;
static std::string s_glsl_header = "";
+static thread_local bool s_is_shared_context = false;
static std::string GetGLSLVersionString()
{
@@ -506,8 +507,8 @@ void ProgramShaderCache::Shutdown()
s_last_VAO = 0;
// All pipeline programs should have been released.
- _dbg_assert_(VIDEO, pipelineprograms.empty());
- pipelineprograms.clear();
+ _dbg_assert_(VIDEO, s_pipeline_programs.empty());
+ s_pipeline_programs.clear();
}
void ProgramShaderCache::CreateAttributelessVAO()
@@ -548,21 +549,28 @@ void ProgramShaderCache::InvalidateLastProgram()
CurrentProgram = 0;
}
-const PipelineProgram* ProgramShaderCache::GetPipelineProgram(const OGLShader* vertex_shader,
+const PipelineProgram* ProgramShaderCache::GetPipelineProgram(const GLVertexFormat* vertex_format,
+ const OGLShader* vertex_shader,
const OGLShader* geometry_shader,
const OGLShader* pixel_shader)
{
PipelineProgramKey key = {vertex_shader, geometry_shader, pixel_shader};
{
- std::lock_guard<std::mutex> guard(pipelineprogramlock);
- auto iter = pipelineprograms.find(key);
- if (iter != pipelineprograms.end())
+ std::lock_guard<std::mutex> guard(s_pipeline_program_lock);
+ auto iter = s_pipeline_programs.find(key);
+ if (iter != s_pipeline_programs.end())
{
iter->second->reference_count++;
return iter->second.get();
}
}
+ // We temporarily change the vertex array to the pipeline's vertex format.
+ // This can prevent the NVIDIA OpenGL driver from recompiling on first use.
+ GLuint vao = vertex_format ? vertex_format->VAO : s_attributeless_VAO;
+ if (s_is_shared_context || vao != s_last_VAO)
+ glBindVertexArray(vao);
+
std::unique_ptr<PipelineProgram> prog = std::make_unique<PipelineProgram>();
prog->key = key;
@@ -581,6 +589,11 @@ const PipelineProgram* ProgramShaderCache::GetPipelineProgram(const OGLShader* v
// Link program.
prog->shader.SetProgramBindings(false);
glLinkProgram(prog->shader.glprogid);
+
+ // Restore VAO binding after linking.
+ if (!s_is_shared_context && vao != s_last_VAO)
+ glBindVertexArray(s_last_VAO);
+
if (!ProgramShaderCache::CheckProgramLinkResult(prog->shader.glprogid, {}, {}, {}))
{
prog->shader.Destroy();
@@ -588,9 +601,9 @@ const PipelineProgram* ProgramShaderCache::GetPipelineProgram(const OGLShader* v
}
// Lock to insert. A duplicate program may have been created in the meantime.
- std::lock_guard<std::mutex> guard(pipelineprogramlock);
- auto iter = pipelineprograms.find(key);
- if (iter != pipelineprograms.end())
+ std::lock_guard<std::mutex> guard(s_pipeline_program_lock);
+ auto iter = s_pipeline_programs.find(key);
+ if (iter != s_pipeline_programs.end())
{
// Destroy this program, and use the one which was created first.
prog->shader.Destroy();
@@ -601,19 +614,25 @@ const PipelineProgram* ProgramShaderCache::GetPipelineProgram(const OGLShader* v
// Set program variables on the shader which will be returned.
// This is only needed for drivers which don't support binding layout.
prog->shader.SetProgramVariables();
- auto ip = pipelineprograms.emplace(key, std::move(prog));
+
+ // If this is a shared context, ensure we sync before we return the program to
+ // the main thread. If we don't do this, some driver can lock up (e.g. AMD).
+ if (s_is_shared_context)
+ glFinish();
+
+ auto ip = s_pipeline_programs.emplace(key, std::move(prog));
return ip.first->second.get();
}
void ProgramShaderCache::ReleasePipelineProgram(const PipelineProgram* prog)
{
- auto iter = pipelineprograms.find(prog->key);
- _assert_(iter != pipelineprograms.end() && prog == iter->second.get());
+ auto iter = s_pipeline_programs.find(prog->key);
+ _assert_(iter != s_pipeline_programs.end() && prog == iter->second.get());
if (--iter->second->reference_count == 0)
{
iter->second->shader.Destroy();
- pipelineprograms.erase(iter);
+ s_pipeline_programs.erase(iter);
}
}
@@ -783,4 +802,55 @@ void ProgramShaderCache::CreateHeader()
v > GlslEs300 ? "precision highp sampler2DMS;" : "",
v >= GlslEs310 ? "precision highp image2DArray;" : "");
}
+
+bool SharedContextAsyncShaderCompiler::WorkerThreadInitMainThread(void** param)
+{
+ std::unique_ptr<cInterfaceBase> context = GLInterface->CreateSharedContext();
+ if (!context)
+ {
+ PanicAlert("Failed to create shared context for shader compiling.");
+ return false;
+ }
+
+ *param = context.release();
+ return true;
+}
+
+bool SharedContextAsyncShaderCompiler::WorkerThreadInitWorkerThread(void* param)
+{
+ cInterfaceBase* context = static_cast<cInterfaceBase*>(param);
+ if (!context->MakeCurrent())
+ return false;
+
+ s_is_shared_context = true;
+ if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart)
+ {
+ if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3)
+ {
+ glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
+ }
+ else
+ {
+ if (GLExtensions::Version() >= 310)
+ {
+ glEnable(GL_PRIMITIVE_RESTART);
+ glPrimitiveRestartIndex(65535);
+ }
+ else
+ {
+ glEnableClientState(GL_PRIMITIVE_RESTART_NV);
+ glPrimitiveRestartIndexNV(65535);
+ }
+ }
+ }
+
+ return true;
+}
+
+void SharedContextAsyncShaderCompiler::WorkerThreadExit(void* param)
+{
+ cInterfaceBase* context = static_cast<cInterfaceBase*>(param);
+ context->ClearCurrent();
+ delete context;
+}
} // namespace OGL