summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp')
-rw-r--r--Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp106
1 files changed, 105 insertions, 1 deletions
diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
index 80c30e1f92..034f94a3b0 100644
--- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
+++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
@@ -9,6 +9,7 @@
#include <string>
#include "Common/Align.h"
+#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Common/GL/GLInterfaceBase.h"
@@ -20,6 +21,7 @@
#include "Core/ConfigManager.h"
#include "Core/Host.h"
+#include "VideoBackends/OGL/OGLShader.h"
#include "VideoBackends/OGL/Render.h"
#include "VideoBackends/OGL/StreamBuffer.h"
#include "VideoBackends/OGL/VertexManager.h"
@@ -57,6 +59,7 @@ 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;
ProgramShaderCache::PCacheEntry* ProgramShaderCache::last_entry;
ProgramShaderCache::PCacheEntry* ProgramShaderCache::last_uber_entry;
SHADERUID ProgramShaderCache::last_uid;
@@ -188,6 +191,47 @@ void SHADER::DestroyShaders()
}
}
+bool PipelineProgramKey::operator!=(const PipelineProgramKey& rhs) const
+{
+ return !operator==(rhs);
+}
+
+bool PipelineProgramKey::operator==(const PipelineProgramKey& rhs) const
+{
+ return std::tie(vertex_shader, geometry_shader, pixel_shader) ==
+ std::tie(rhs.vertex_shader, rhs.geometry_shader, rhs.pixel_shader);
+}
+
+bool PipelineProgramKey::operator<(const PipelineProgramKey& rhs) const
+{
+ return std::tie(vertex_shader, geometry_shader, pixel_shader) <
+ std::tie(rhs.vertex_shader, rhs.geometry_shader, rhs.pixel_shader);
+}
+
+std::size_t PipelineProgramKeyHash::operator()(const PipelineProgramKey& key) const
+{
+ // We would really want std::hash_combine for this..
+ std::hash<const void*> hasher;
+ return hasher(key.vertex_shader) + hasher(key.geometry_shader) + hasher(key.pixel_shader);
+}
+
+StreamBuffer* ProgramShaderCache::GetUniformBuffer()
+{
+ return s_buffer.get();
+}
+
+u32 ProgramShaderCache::GetUniformBufferAlignment()
+{
+ return s_ubo_align;
+}
+
+void ProgramShaderCache::InvalidateConstants()
+{
+ VertexShaderManager::dirty = true;
+ GeometryShaderManager::dirty = true;
+ PixelShaderManager::dirty = true;
+}
+
void ProgramShaderCache::UploadConstants()
{
if (PixelShaderManager::dirty || VertexShaderManager::dirty || GeometryShaderManager::dirty)
@@ -697,6 +741,10 @@ void ProgramShaderCache::Shutdown()
s_attributeless_VBO = 0;
s_attributeless_VAO = 0;
s_last_VAO = 0;
+
+ // All pipeline programs should have been released.
+ _dbg_assert_(VIDEO, pipelineprograms.empty());
+ pipelineprograms.clear();
}
void ProgramShaderCache::CreateAttributelessVAO()
@@ -732,6 +780,11 @@ void ProgramShaderCache::InvalidateVertexFormat()
s_last_VAO = 0;
}
+void ProgramShaderCache::InvalidateLastProgram()
+{
+ CurrentProgram = 0;
+}
+
GLuint ProgramShaderCache::CreateProgramFromBinary(const u8* value, u32 value_size)
{
const u8* binary = value + sizeof(GLenum);
@@ -860,6 +913,58 @@ void ProgramShaderCache::DestroyShaders()
ubershaders.clear();
}
+const PipelineProgram* ProgramShaderCache::GetPipelineProgram(const OGLShader* vertex_shader,
+ const OGLShader* geometry_shader,
+ const OGLShader* pixel_shader)
+{
+ PipelineProgramKey key = {vertex_shader, geometry_shader, pixel_shader};
+ auto iter = pipelineprograms.find(key);
+ if (iter != pipelineprograms.end())
+ {
+ iter->second->reference_count++;
+ return iter->second.get();
+ }
+
+ std::unique_ptr<PipelineProgram> prog = std::make_unique<PipelineProgram>();
+ prog->key = key;
+
+ // Attach shaders.
+ _assert_(vertex_shader && vertex_shader->GetStage() == ShaderStage::Vertex);
+ _assert_(pixel_shader && pixel_shader->GetStage() == ShaderStage::Pixel);
+ prog->shader.glprogid = glCreateProgram();
+ glAttachShader(prog->shader.glprogid, vertex_shader->GetGLShaderID());
+ glAttachShader(prog->shader.glprogid, pixel_shader->GetGLShaderID());
+ if (geometry_shader)
+ {
+ _assert_(geometry_shader->GetStage() == ShaderStage::Geometry);
+ glAttachShader(prog->shader.glprogid, geometry_shader->GetGLShaderID());
+ }
+
+ // Link program.
+ prog->shader.SetProgramBindings(false);
+ glLinkProgram(prog->shader.glprogid);
+ if (!ProgramShaderCache::CheckProgramLinkResult(prog->shader.glprogid, {}, {}, {}))
+ {
+ prog->shader.Destroy();
+ return nullptr;
+ }
+
+ auto ip = pipelineprograms.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());
+
+ if (--iter->second->reference_count == 0)
+ {
+ iter->second->shader.Destroy();
+ pipelineprograms.erase(iter);
+ }
+}
+
void ProgramShaderCache::CreateHeader()
{
GlslVersion v = g_ogl_config.eSupportedGLSLVersion;
@@ -1368,5 +1473,4 @@ void ProgramShaderCache::DrawPrerenderArray(const SHADER& shader, PrimitiveType
glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
glDeleteSync(sync);
}
-
} // namespace OGL