summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
diff options
context:
space:
mode:
authorStenzek <stenzek@gmail.com>2018-02-25 01:15:35 +1000
committerStenzek <stenzek@gmail.com>2018-03-10 15:56:30 +1000
commitdec0c3bce85ceda89ea05f00b94aad00e675598d (patch)
tree8c967a47d8a531ae3f0245e419d7ec652535ee3a /Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
parent24df896eb8d1520706b086039743ef2dca7ce6df (diff)
Move shader caches to VideoCommon
Diffstat (limited to 'Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp')
-rw-r--r--Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp703
1 files changed, 0 insertions, 703 deletions
diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
index a4cb6620dc..d953996396 100644
--- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
+++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
@@ -33,8 +33,6 @@
#include "VideoCommon/ImageWrite.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/Statistics.h"
-#include "VideoCommon/UberShaderPixel.h"
-#include "VideoCommon/UberShaderVertex.h"
#include "VideoCommon/VertexLoaderManager.h"
#include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoCommon.h"
@@ -43,8 +41,6 @@ namespace OGL
{
static constexpr u32 UBO_LENGTH = 32 * 1024 * 1024;
-std::unique_ptr<ProgramShaderCache::SharedContextAsyncShaderCompiler>
- ProgramShaderCache::s_async_compiler;
u32 ProgramShaderCache::s_ubo_buffer_size;
s32 ProgramShaderCache::s_ubo_align;
GLuint ProgramShaderCache::s_attributeless_VBO = 0;
@@ -54,17 +50,9 @@ GLuint ProgramShaderCache::s_last_VAO = 0;
static std::unique_ptr<StreamBuffer> s_buffer;
static int num_failures = 0;
-static LinearDiskCache<SHADERUID, u8> s_program_disk_cache;
-static LinearDiskCache<UBERSHADERUID, u8> s_uber_program_disk_cache;
static GLuint CurrentProgram = 0;
-ProgramShaderCache::PCache ProgramShaderCache::pshaders;
-ProgramShaderCache::UberPCache ProgramShaderCache::ubershaders;
ProgramShaderCache::PipelineProgramMap ProgramShaderCache::pipelineprograms;
std::mutex ProgramShaderCache::pipelineprogramlock;
-ProgramShaderCache::PCacheEntry* ProgramShaderCache::last_entry;
-ProgramShaderCache::PCacheEntry* ProgramShaderCache::last_uber_entry;
-SHADERUID ProgramShaderCache::last_uid;
-UBERSHADERUID ProgramShaderCache::last_uber_uid;
static std::string s_glsl_header = "";
static std::string GetGLSLVersionString()
@@ -270,143 +258,6 @@ void ProgramShaderCache::UploadConstants()
}
}
-SHADER* ProgramShaderCache::SetShader(PrimitiveType primitive_type,
- const GLVertexFormat* vertex_format)
-{
- if (g_ActiveConfig.bDisableSpecializedShaders)
- return SetUberShader(primitive_type, vertex_format);
-
- SHADERUID uid;
- std::memset(&uid, 0, sizeof(uid));
- uid.puid = GetPixelShaderUid();
- uid.vuid = GetVertexShaderUid();
- uid.guid = GetGeometryShaderUid(primitive_type);
- ClearUnusedPixelShaderUidBits(APIType::OpenGL, &uid.puid);
-
- // Check if the shader is already set
- if (last_entry && uid == last_uid)
- {
- last_entry->shader.Bind();
- BindVertexFormat(vertex_format);
- return &last_entry->shader;
- }
-
- // Check if shader is already in cache
- auto iter = pshaders.find(uid);
- if (iter != pshaders.end())
- {
- PCacheEntry* entry = &iter->second;
- if (entry->pending)
- return SetUberShader(primitive_type, vertex_format);
-
- last_uid = uid;
- last_entry = entry;
- BindVertexFormat(vertex_format);
- last_entry->shader.Bind();
- return &last_entry->shader;
- }
-
- // Compile the new shader program.
- PCacheEntry& newentry = pshaders[uid];
- newentry.in_cache = false;
- newentry.pending = false;
-
- // Can we background compile this shader? Requires background shader compiling to be enabled,
- // and all ubershaders to have been successfully compiled.
- if (g_ActiveConfig.CanBackgroundCompileShaders() && !ubershaders.empty() && s_async_compiler)
- {
- newentry.pending = true;
- s_async_compiler->QueueWorkItem(s_async_compiler->CreateWorkItem<ShaderCompileWorkItem>(uid));
- return SetUberShader(primitive_type, vertex_format);
- }
-
- // Synchronous shader compiling.
- ShaderHostConfig host_config = ShaderHostConfig::GetCurrent();
- ShaderCode vcode = GenerateVertexShaderCode(APIType::OpenGL, host_config, uid.vuid.GetUidData());
- ShaderCode pcode = GeneratePixelShaderCode(APIType::OpenGL, host_config, uid.puid.GetUidData());
- ShaderCode gcode;
- if (g_ActiveConfig.backend_info.bSupportsGeometryShaders &&
- !uid.guid.GetUidData()->IsPassthrough())
- gcode = GenerateGeometryShaderCode(APIType::OpenGL, host_config, uid.guid.GetUidData());
-
- if (!CompileShader(newentry.shader, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer()))
- return nullptr;
-
- INCSTAT(stats.numPixelShadersCreated);
- SETSTAT(stats.numPixelShadersAlive, pshaders.size());
-
- last_uid = uid;
- last_entry = &newentry;
- BindVertexFormat(vertex_format);
- last_entry->shader.Bind();
- return &last_entry->shader;
-}
-
-SHADER* ProgramShaderCache::SetUberShader(PrimitiveType primitive_type,
- const GLVertexFormat* vertex_format)
-{
- UBERSHADERUID uid;
- std::memset(&uid, 0, sizeof(uid));
- uid.puid = UberShader::GetPixelShaderUid();
- uid.vuid = UberShader::GetVertexShaderUid();
- uid.guid = GetGeometryShaderUid(primitive_type);
- UberShader::ClearUnusedPixelShaderUidBits(APIType::OpenGL, &uid.puid);
-
- // We need to use the ubershader vertex format with all attributes enabled.
- // Otherwise, the NV driver can generate variants for the vertex shaders.
- const GLVertexFormat* uber_vertex_format = static_cast<const GLVertexFormat*>(
- VertexLoaderManager::GetUberVertexFormat(vertex_format->GetVertexDeclaration()));
-
- // Check if the shader is already set
- if (last_uber_entry && last_uber_uid == uid)
- {
- BindVertexFormat(uber_vertex_format);
- last_uber_entry->shader.Bind();
- return &last_uber_entry->shader;
- }
-
- // Check if shader is already in cache
- auto iter = ubershaders.find(uid);
- if (iter != ubershaders.end())
- {
- PCacheEntry* entry = &iter->second;
- last_uber_uid = uid;
- last_uber_entry = entry;
- BindVertexFormat(uber_vertex_format);
- last_uber_entry->shader.Bind();
- return &last_uber_entry->shader;
- }
-
- // Make an entry in the table
- PCacheEntry& newentry = ubershaders[uid];
- newentry.in_cache = false;
- newentry.pending = false;
-
- ShaderHostConfig host_config = ShaderHostConfig::GetCurrent();
- ShaderCode vcode =
- UberShader::GenVertexShader(APIType::OpenGL, host_config, uid.vuid.GetUidData());
- ShaderCode pcode =
- UberShader::GenPixelShader(APIType::OpenGL, host_config, uid.puid.GetUidData());
- ShaderCode gcode;
- if (g_ActiveConfig.backend_info.bSupportsGeometryShaders &&
- !uid.guid.GetUidData()->IsPassthrough())
- {
- gcode = GenerateGeometryShaderCode(APIType::OpenGL, host_config, uid.guid.GetUidData());
- }
-
- if (!CompileShader(newentry.shader, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer()))
- {
- GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true);
- return nullptr;
- }
-
- last_uber_uid = uid;
- last_uber_entry = &newentry;
- BindVertexFormat(uber_vertex_format);
- last_uber_entry->shader.Bind();
- return &last_uber_entry->shader;
-}
-
bool ProgramShaderCache::CompileShader(SHADER& shader, const std::string& vcode,
const std::string& pcode, const std::string& gcode)
{
@@ -620,11 +471,6 @@ bool ProgramShaderCache::CheckProgramLinkResult(GLuint id, const std::string& vc
return true;
}
-ProgramShaderCache::PCacheEntry ProgramShaderCache::GetShaderProgram()
-{
- return *last_entry;
-}
-
void ProgramShaderCache::Init()
{
// We have to get the UBO alignment here because
@@ -642,93 +488,14 @@ void ProgramShaderCache::Init()
// Then once more to get bytes
s_buffer = StreamBuffer::Create(GL_UNIFORM_BUFFER, UBO_LENGTH);
- // The GPU shader code appears to be context-specific on Mesa/i965.
- // This means that if we compiled the ubershaders asynchronously, they will be recompiled
- // on the main thread the first time they are used, causing stutter. Nouveau has been
- // reported to crash if draw calls are invoked on the shared context threads. For now,
- // disable asynchronous compilation on Mesa.
- if (!DriverDetails::HasBug(DriverDetails::BUG_SHARED_CONTEXT_SHADER_COMPILATION))
- s_async_compiler = std::make_unique<SharedContextAsyncShaderCompiler>();
-
- // Read our shader cache, only if supported and enabled
- if (g_ogl_config.bSupportsGLSLCache && g_ActiveConfig.bShaderCache)
- LoadProgramBinaries();
-
CreateHeader();
CreateAttributelessVAO();
CurrentProgram = 0;
- last_entry = nullptr;
- last_uber_entry = nullptr;
-
- if (g_ActiveConfig.CanPrecompileUberShaders())
- {
- if (s_async_compiler)
- s_async_compiler->ResizeWorkerThreads(g_ActiveConfig.GetShaderPrecompilerThreads());
- PrecompileUberShaders();
- }
-
- if (s_async_compiler)
- {
- // No point using the async compiler without workers.
- s_async_compiler->ResizeWorkerThreads(g_ActiveConfig.GetShaderCompilerThreads());
- if (!s_async_compiler->HasWorkerThreads())
- s_async_compiler.reset();
- }
-}
-
-void ProgramShaderCache::RetrieveAsyncShaders()
-{
- if (s_async_compiler)
- s_async_compiler->RetrieveWorkItems();
-}
-
-void ProgramShaderCache::Reload()
-{
- if (s_async_compiler)
- {
- s_async_compiler->WaitUntilCompletion();
- s_async_compiler->RetrieveWorkItems();
- }
-
- const bool use_cache = g_ogl_config.bSupportsGLSLCache && g_ActiveConfig.bShaderCache;
- if (use_cache)
- SaveProgramBinaries();
-
- s_program_disk_cache.Close();
- s_uber_program_disk_cache.Close();
- DestroyShaders();
-
- if (use_cache)
- LoadProgramBinaries();
-
- if (g_ActiveConfig.CanPrecompileUberShaders())
- PrecompileUberShaders();
-
- CurrentProgram = 0;
- last_entry = nullptr;
- last_uber_entry = nullptr;
- last_uid = {};
- last_uber_uid = {};
}
void ProgramShaderCache::Shutdown()
{
- if (s_async_compiler)
- {
- s_async_compiler->WaitUntilCompletion();
- s_async_compiler->StopWorkerThreads();
- s_async_compiler->RetrieveWorkItems();
- s_async_compiler.reset();
- }
-
- // store all shaders in cache on disk
- if (g_ogl_config.bSupportsGLSLCache && g_ActiveConfig.bShaderCache)
- SaveProgramBinaries();
- s_program_disk_cache.Close();
- s_uber_program_disk_cache.Close();
-
- DestroyShaders();
s_buffer.reset();
glBindVertexArray(0);
@@ -781,134 +548,6 @@ void ProgramShaderCache::InvalidateLastProgram()
CurrentProgram = 0;
}
-GLuint ProgramShaderCache::CreateProgramFromBinary(const u8* value, u32 value_size)
-{
- const u8* binary = value + sizeof(GLenum);
- GLint binary_size = value_size - sizeof(GLenum);
- GLenum prog_format;
- std::memcpy(&prog_format, value, sizeof(GLenum));
-
- GLuint progid = glCreateProgram();
- glProgramBinary(progid, prog_format, binary, binary_size);
-
- GLint success;
- glGetProgramiv(progid, GL_LINK_STATUS, &success);
- if (!success)
- {
- glDeleteProgram(progid);
- return 0;
- }
-
- return progid;
-}
-
-bool ProgramShaderCache::CreateCacheEntryFromBinary(PCacheEntry* entry, const u8* value,
- u32 value_size)
-{
- entry->in_cache = true;
- entry->pending = false;
- entry->shader.glprogid = CreateProgramFromBinary(value, value_size);
- if (entry->shader.glprogid == 0)
- return false;
-
- entry->shader.SetProgramVariables();
- return true;
-}
-
-void ProgramShaderCache::LoadProgramBinaries()
-{
- GLint Supported;
- glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &Supported);
- if (!Supported)
- {
- ERROR_LOG(VIDEO, "GL_ARB_get_program_binary is supported, but no binary format is known. So "
- "disable shader cache.");
- g_ogl_config.bSupportsGLSLCache = false;
- }
- else
- {
- // Load game-specific shaders.
- std::string cache_filename =
- GetDiskShaderCacheFileName(APIType::OpenGL, "ProgramBinaries", true, true);
- ProgramShaderCacheInserter<SHADERUID> inserter(pshaders);
- s_program_disk_cache.OpenAndRead(cache_filename, inserter);
-
- // Load global ubershaders.
- cache_filename =
- GetDiskShaderCacheFileName(APIType::OpenGL, "UberProgramBinaries", false, true);
- ProgramShaderCacheInserter<UBERSHADERUID> uber_inserter(ubershaders);
- s_uber_program_disk_cache.OpenAndRead(cache_filename, uber_inserter);
- }
- SETSTAT(stats.numPixelShadersAlive, pshaders.size());
-}
-
-static bool GetProgramBinary(const ProgramShaderCache::PCacheEntry& entry, std::vector<u8>& data)
-{
- // Clear any prior error code
- glGetError();
-
- GLint link_status = GL_FALSE, delete_status = GL_TRUE, binary_size = 0;
- glGetProgramiv(entry.shader.glprogid, GL_LINK_STATUS, &link_status);
- glGetProgramiv(entry.shader.glprogid, GL_DELETE_STATUS, &delete_status);
- glGetProgramiv(entry.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size);
- if (glGetError() != GL_NO_ERROR || link_status == GL_FALSE || delete_status == GL_TRUE ||
- binary_size == 0)
- {
- return false;
- }
-
- data.resize(binary_size + sizeof(GLenum));
-
- GLsizei length = binary_size;
- GLenum prog_format;
- glGetProgramBinary(entry.shader.glprogid, binary_size, &length, &prog_format,
- &data[sizeof(GLenum)]);
- if (glGetError() != GL_NO_ERROR)
- return false;
-
- std::memcpy(&data[0], &prog_format, sizeof(prog_format));
- return true;
-}
-
-template <typename CacheMapType, typename DiskCacheType>
-static void SaveProgramBinaryMap(CacheMapType& program_map, DiskCacheType& disk_cache)
-{
- std::vector<u8> binary_data;
- for (auto& entry : program_map)
- {
- if (entry.second.in_cache || entry.second.pending)
- continue;
-
- // Entry is now in cache (even if it fails, we don't want to try to save it again).
- entry.second.in_cache = true;
- if (!GetProgramBinary(entry.second, binary_data))
- continue;
-
- disk_cache.Append(entry.first, &binary_data[0], static_cast<u32>(binary_data.size()));
- }
-
- disk_cache.Sync();
-}
-
-void ProgramShaderCache::SaveProgramBinaries()
-{
- SaveProgramBinaryMap(pshaders, s_program_disk_cache);
- SaveProgramBinaryMap(ubershaders, s_uber_program_disk_cache);
-}
-
-void ProgramShaderCache::DestroyShaders()
-{
- glUseProgram(0);
-
- for (auto& entry : pshaders)
- entry.second.Destroy();
- pshaders.clear();
-
- for (auto& entry : ubershaders)
- entry.second.Destroy();
- ubershaders.clear();
-}
-
const PipelineProgram* ProgramShaderCache::GetPipelineProgram(const OGLShader* vertex_shader,
const OGLShader* geometry_shader,
const OGLShader* pixel_shader)
@@ -1144,346 +783,4 @@ void ProgramShaderCache::CreateHeader()
v > GlslEs300 ? "precision highp sampler2DMS;" : "",
v >= GlslEs310 ? "precision highp image2DArray;" : "");
}
-
-void ProgramShaderCache::PrecompileUberShaders()
-{
- bool success = true;
-
- UberShader::EnumerateVertexShaderUids([&](const UberShader::VertexShaderUid& vuid) {
- UberShader::EnumeratePixelShaderUids([&](const UberShader::PixelShaderUid& puid) {
- // UIDs must have compatible texgens, a mismatching combination will never be queried.
- if (vuid.GetUidData()->num_texgens != puid.GetUidData()->num_texgens)
- return;
-
- EnumerateGeometryShaderUids([&](const GeometryShaderUid& guid) {
- if (guid.GetUidData()->numTexGens != vuid.GetUidData()->num_texgens)
- return;
-
- UBERSHADERUID uid;
- std::memcpy(&uid.vuid, &vuid, sizeof(uid.vuid));
- std::memcpy(&uid.puid, &puid, sizeof(uid.puid));
- std::memcpy(&uid.guid, &guid, sizeof(uid.guid));
-
- // The ubershader may already exist if shader caching is enabled.
- if (!success || ubershaders.find(uid) != ubershaders.end())
- return;
-
- PCacheEntry& entry = ubershaders[uid];
- entry.in_cache = false;
- entry.pending = false;
-
- // Multi-context path?
- if (s_async_compiler)
- {
- entry.pending = true;
- s_async_compiler->QueueWorkItem(
- s_async_compiler->CreateWorkItem<UberShaderCompileWorkItem>(uid));
- return;
- }
-
- ShaderHostConfig host_config = ShaderHostConfig::GetCurrent();
- ShaderCode vcode =
- UberShader::GenVertexShader(APIType::OpenGL, host_config, uid.vuid.GetUidData());
- ShaderCode pcode =
- UberShader::GenPixelShader(APIType::OpenGL, host_config, uid.puid.GetUidData());
- ShaderCode gcode;
- if (g_ActiveConfig.backend_info.bSupportsGeometryShaders &&
- !uid.guid.GetUidData()->IsPassthrough())
- {
- GenerateGeometryShaderCode(APIType::OpenGL, host_config, uid.guid.GetUidData());
- }
-
- // Always background compile, even when it's not supported.
- // This way hopefully the driver can still compile the shaders in parallel.
- if (!CompileShader(entry.shader, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer()))
- {
- // Stop compiling shaders if any of them fail, no point continuing.
- success = false;
- return;
- }
- });
- });
- });
-
- if (s_async_compiler)
- {
- s_async_compiler->WaitUntilCompletion([](size_t completed, size_t total) {
- Host_UpdateProgressDialog(GetStringT("Compiling shaders...").c_str(),
- static_cast<int>(completed), static_cast<int>(total));
- });
- s_async_compiler->RetrieveWorkItems();
- Host_UpdateProgressDialog("", -1, -1);
- }
-
- if (!success)
- {
- PanicAlert("One or more ubershaders failed to compile. Disabling ubershaders.");
- for (auto& it : ubershaders)
- it.second.Destroy();
- ubershaders.clear();
- }
-}
-
-bool ProgramShaderCache::SharedContextAsyncShaderCompiler::WorkerThreadInitMainThread(void** param)
-{
- SharedContextData* ctx_data = new SharedContextData();
- ctx_data->context = GLInterface->CreateSharedContext();
- if (!ctx_data->context)
- {
- PanicAlert("Failed to create shared context for shader compiling.");
- delete ctx_data;
- return false;
- }
-
- *param = ctx_data;
- return true;
-}
-
-bool ProgramShaderCache::SharedContextAsyncShaderCompiler::WorkerThreadInitWorkerThread(void* param)
-{
- SharedContextData* ctx_data = reinterpret_cast<SharedContextData*>(param);
- if (!ctx_data->context->MakeCurrent())
- {
- PanicAlert("Failed to make shared context current.");
- ctx_data->context->Shutdown();
- delete ctx_data;
- return false;
- }
-
- CreatePrerenderArrays(ctx_data);
- return true;
-}
-
-void ProgramShaderCache::SharedContextAsyncShaderCompiler::WorkerThreadExit(void* param)
-{
- SharedContextData* ctx_data = reinterpret_cast<SharedContextData*>(param);
- DestroyPrerenderArrays(ctx_data);
- ctx_data->context->Shutdown();
- delete ctx_data;
-}
-
-ProgramShaderCache::ShaderCompileWorkItem::ShaderCompileWorkItem(const SHADERUID& uid)
-{
- std::memcpy(&m_uid, &uid, sizeof(m_uid));
-}
-
-bool ProgramShaderCache::ShaderCompileWorkItem::Compile()
-{
- ShaderHostConfig host_config = ShaderHostConfig::GetCurrent();
- ShaderCode vcode =
- GenerateVertexShaderCode(APIType::OpenGL, host_config, m_uid.vuid.GetUidData());
- ShaderCode pcode = GeneratePixelShaderCode(APIType::OpenGL, host_config, m_uid.puid.GetUidData());
- ShaderCode gcode;
- if (g_ActiveConfig.backend_info.bSupportsGeometryShaders &&
- !m_uid.guid.GetUidData()->IsPassthrough())
- gcode = GenerateGeometryShaderCode(APIType::OpenGL, host_config, m_uid.guid.GetUidData());
-
- CompileShader(m_program, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer());
- DrawPrerenderArray(m_program,
- static_cast<PrimitiveType>(m_uid.guid.GetUidData()->primitive_type));
- return true;
-}
-
-void ProgramShaderCache::ShaderCompileWorkItem::Retrieve()
-{
- auto iter = pshaders.find(m_uid);
- if (iter != pshaders.end() && !iter->second.pending)
- {
- // Main thread already compiled this shader.
- m_program.Destroy();
- return;
- }
-
- PCacheEntry& entry = pshaders[m_uid];
- entry.shader = m_program;
- entry.in_cache = false;
- entry.pending = false;
-}
-
-ProgramShaderCache::UberShaderCompileWorkItem::UberShaderCompileWorkItem(const UBERSHADERUID& uid)
-{
- std::memcpy(&m_uid, &uid, sizeof(m_uid));
-}
-
-bool ProgramShaderCache::UberShaderCompileWorkItem::Compile()
-{
- ShaderHostConfig host_config = ShaderHostConfig::GetCurrent();
- ShaderCode vcode =
- UberShader::GenVertexShader(APIType::OpenGL, host_config, m_uid.vuid.GetUidData());
- ShaderCode pcode =
- UberShader::GenPixelShader(APIType::OpenGL, host_config, m_uid.puid.GetUidData());
- ShaderCode gcode;
- if (g_ActiveConfig.backend_info.bSupportsGeometryShaders &&
- !m_uid.guid.GetUidData()->IsPassthrough())
- gcode = GenerateGeometryShaderCode(APIType::OpenGL, host_config, m_uid.guid.GetUidData());
-
- CompileShader(m_program, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer());
- DrawPrerenderArray(m_program,
- static_cast<PrimitiveType>(m_uid.guid.GetUidData()->primitive_type));
- return true;
-}
-
-void ProgramShaderCache::UberShaderCompileWorkItem::Retrieve()
-{
- auto iter = ubershaders.find(m_uid);
- if (iter != ubershaders.end() && !iter->second.pending)
- {
- // Main thread already compiled this shader.
- m_program.Destroy();
- return;
- }
-
- PCacheEntry& entry = ubershaders[m_uid];
- entry.shader = m_program;
- entry.in_cache = false;
- entry.pending = false;
-}
-
-void ProgramShaderCache::CreatePrerenderArrays(SharedContextData* data)
-{
- // Create a framebuffer object to render into.
- // This is because in EGL, and potentially GLX, we have a surfaceless context.
- glGenTextures(1, &data->prerender_FBO_tex);
- glBindTexture(GL_TEXTURE_2D_ARRAY, data->prerender_FBO_tex);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 1);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- glGenTextures(1, &data->prerender_FBO_depth);
- glBindTexture(GL_TEXTURE_2D_ARRAY, data->prerender_FBO_depth);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 1);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, 1, 1, 1, 0, GL_DEPTH_COMPONENT,
- GL_FLOAT, nullptr);
- glGenFramebuffers(1, &data->prerender_FBO);
- glBindFramebuffer(GL_FRAMEBUFFER, data->prerender_FBO);
- glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, data->prerender_FBO_tex, 0, 0);
- glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, data->prerender_FBO_depth, 0, 0);
-
- // Create VAO for the prerender vertices.
- // We don't use the normal VAO map, since we need to change the VBO pointer.
- glGenVertexArrays(1, &data->prerender_VAO);
- glBindVertexArray(data->prerender_VAO);
-
- // Create and populate the prerender VBO. We need enough space to draw 3 triangles.
- static constexpr float vbo_data[] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
- constexpr u32 vbo_stride = sizeof(float) * 3;
- glGenBuffers(1, &data->prerender_VBO);
- glBindBuffer(GL_ARRAY_BUFFER, data->prerender_VBO);
- glBufferData(GL_ARRAY_BUFFER, sizeof(vbo_data), vbo_data, GL_STATIC_DRAW);
-
- // We only need a position in our prerender vertex.
- glEnableVertexAttribArray(SHADER_POSITION_ATTRIB);
- glVertexAttribPointer(SHADER_POSITION_ATTRIB, 3, GL_FLOAT, GL_FALSE, vbo_stride, nullptr);
-
- // The other attributes have to be active to avoid variant generation.
- glEnableVertexAttribArray(SHADER_POSMTX_ATTRIB);
- glVertexAttribIPointer(SHADER_POSMTX_ATTRIB, 1, GL_UNSIGNED_BYTE, vbo_stride, nullptr);
- for (u32 i = 0; i < 3; i++)
- {
- glEnableVertexAttribArray(SHADER_NORM0_ATTRIB + i);
- glVertexAttribPointer(SHADER_NORM0_ATTRIB + i, 3, GL_FLOAT, GL_FALSE, vbo_stride, nullptr);
- }
- for (u32 i = 0; i < 2; i++)
- {
- glEnableVertexAttribArray(SHADER_COLOR0_ATTRIB + i);
- glVertexAttribPointer(SHADER_COLOR0_ATTRIB + i, 4, GL_UNSIGNED_BYTE, GL_TRUE, vbo_stride,
- nullptr);
- }
- for (u32 i = 0; i < 8; i++)
- {
- glEnableVertexAttribArray(SHADER_TEXTURE0_ATTRIB + i);
- glVertexAttribPointer(SHADER_TEXTURE0_ATTRIB + i, 3, GL_FLOAT, GL_FALSE, vbo_stride, nullptr);
- }
-
- // We need an index buffer to set up the same drawing state on Mesa.
- static constexpr u16 ibo_data[] = {0, 1, 2};
- glGenBuffers(1, &data->prerender_IBO);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data->prerender_IBO);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ibo_data), ibo_data, GL_STATIC_DRAW);
-
- // Mesa also requires the primitive restart state matches?
- 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);
- }
- }
- }
-}
-
-void ProgramShaderCache::DestroyPrerenderArrays(SharedContextData* data)
-{
- if (data->prerender_VAO)
- {
- glDeleteVertexArrays(1, &data->prerender_VAO);
- data->prerender_VAO = 0;
- }
- if (data->prerender_VBO)
- {
- glDeleteBuffers(1, &data->prerender_VBO);
- data->prerender_VBO = 0;
- }
- if (data->prerender_IBO)
- {
- glDeleteBuffers(1, &data->prerender_IBO);
- data->prerender_IBO = 0;
- }
- if (data->prerender_FBO)
- {
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- glDeleteFramebuffers(1, &data->prerender_FBO);
- data->prerender_FBO = 0;
- }
- if (data->prerender_FBO_tex)
- {
- glDeleteTextures(1, &data->prerender_FBO_tex);
- data->prerender_FBO_tex = 0;
- }
- if (data->prerender_FBO_depth)
- {
- glDeleteTextures(1, &data->prerender_FBO_depth);
- data->prerender_FBO_depth = 0;
- }
-}
-
-void ProgramShaderCache::DrawPrerenderArray(const SHADER& shader, PrimitiveType primitive_type)
-{
- // This is called on a worker thread, so we don't want to use the normal binding process.
- glUseProgram(shader.glprogid);
-
- // The number of primitives drawn depends on the type.
- switch (primitive_type)
- {
- case PrimitiveType::Points:
- glDrawElements(GL_POINTS, 1, GL_UNSIGNED_SHORT, nullptr);
- break;
- case PrimitiveType::Lines:
- glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, nullptr);
- break;
- case PrimitiveType::Triangles:
- glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, nullptr);
- break;
- case PrimitiveType::TriangleStrip:
- glDrawElements(GL_TRIANGLE_STRIP, 3, GL_UNSIGNED_SHORT, nullptr);
- break;
- }
-
- // Has to be finished by the time the main thread picks it up.
- GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
- glDeleteSync(sync);
-}
} // namespace OGL