mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Merge pull request #7999 from stenzek/pipeline-cache-data
Implement pipeline data cache for OpenGL and D3D12
This commit is contained in:
@@ -127,7 +127,9 @@ std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage sta
|
||||
return DXShader::CreateFromBytecode(stage, DXShader::CreateByteCode(data, length));
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config)
|
||||
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config,
|
||||
const void* cache_data,
|
||||
size_t cache_data_length)
|
||||
{
|
||||
return DXPipeline::Create(config);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,9 @@ public:
|
||||
size_t length) override;
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
|
||||
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config) override;
|
||||
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config,
|
||||
const void* cache_data = nullptr,
|
||||
size_t cache_data_length = 0) override;
|
||||
std::unique_ptr<AbstractFramebuffer>
|
||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) override;
|
||||
|
||||
|
||||
@@ -82,6 +82,8 @@ void VideoBackend::FillBackendInfo()
|
||||
g_Config.backend_info.bSupportsFragmentStoresAndAtomics = true;
|
||||
g_Config.backend_info.bSupportsGSInstancing = true;
|
||||
g_Config.backend_info.bSupportsSSAA = true;
|
||||
g_Config.backend_info.bSupportsShaderBinaries = true;
|
||||
g_Config.backend_info.bSupportsPipelineCacheData = false;
|
||||
|
||||
g_Config.backend_info.Adapters = D3DCommon::GetAdapterNames();
|
||||
g_Config.backend_info.AAModes = D3D::GetAAModes(g_Config.iAdapter);
|
||||
|
||||
@@ -156,7 +156,8 @@ static void GetD3DBlendDesc(D3D12_BLEND_DESC* desc, const BlendingState& state)
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& config)
|
||||
std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& config,
|
||||
const void* cache_data, size_t cache_data_size)
|
||||
{
|
||||
DEBUG_ASSERT(config.vertex_shader && config.pixel_shader);
|
||||
|
||||
@@ -202,16 +203,36 @@ std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& con
|
||||
D3DCommon::GetDSVFormatForAbstractFormat(config.framebuffer_state.depth_texture_format);
|
||||
desc.SampleDesc.Count = config.framebuffer_state.samples;
|
||||
desc.NodeMask = 1;
|
||||
desc.CachedPSO.pCachedBlob = cache_data;
|
||||
desc.CachedPSO.CachedBlobSizeInBytes = cache_data_size;
|
||||
|
||||
ID3D12PipelineState* pso;
|
||||
HRESULT hr = g_dx_context->GetDevice()->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(&pso));
|
||||
CHECK(SUCCEEDED(hr), "Create PSO");
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WARN_LOG(VIDEO, "CreateGraphicsPipelineState() %sfailed with HRESULT %08X",
|
||||
cache_data ? "with cache data " : "", hr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bool use_integer_rtv =
|
||||
!config.blending_state.blendenable && config.blending_state.logicopenable;
|
||||
return std::make_unique<DXPipeline>(pso, desc.pRootSignature, config.usage,
|
||||
GetD3DTopology(config.rasterization_state), use_integer_rtv);
|
||||
}
|
||||
|
||||
AbstractPipeline::CacheData DXPipeline::GetCacheData() const
|
||||
{
|
||||
ComPtr<ID3DBlob> blob;
|
||||
HRESULT hr = m_pipeline->GetCachedBlob(&blob);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WARN_LOG(VIDEO, "ID3D12Pipeline::GetCachedBlob() failed with HRESULT %08X", hr);
|
||||
return {};
|
||||
}
|
||||
|
||||
CacheData data(blob->GetBufferSize());
|
||||
std::memcpy(data.data(), blob->GetBufferPointer(), blob->GetBufferSize());
|
||||
return data;
|
||||
}
|
||||
} // namespace DX12
|
||||
|
||||
@@ -19,7 +19,8 @@ public:
|
||||
bool use_integer_rtv);
|
||||
~DXPipeline() override;
|
||||
|
||||
static std::unique_ptr<DXPipeline> Create(const AbstractPipelineConfig& config);
|
||||
static std::unique_ptr<DXPipeline> Create(const AbstractPipelineConfig& config,
|
||||
const void* cache_data, size_t cache_data_size);
|
||||
|
||||
ID3D12PipelineState* GetPipeline() const { return m_pipeline; }
|
||||
ID3D12RootSignature* GetRootSignature() const { return m_root_signature; }
|
||||
@@ -27,6 +28,8 @@ public:
|
||||
D3D12_PRIMITIVE_TOPOLOGY GetPrimitiveTopology() const { return m_primitive_topology; }
|
||||
bool UseIntegerRTV() const { return m_use_integer_rtv; }
|
||||
|
||||
CacheData GetCacheData() const override;
|
||||
|
||||
private:
|
||||
ID3D12PipelineState* m_pipeline;
|
||||
ID3D12RootSignature* m_root_signature;
|
||||
|
||||
@@ -99,9 +99,11 @@ Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
||||
return std::make_unique<DXVertexFormat>(vtx_decl);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config)
|
||||
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config,
|
||||
const void* cache_data,
|
||||
size_t cache_data_length)
|
||||
{
|
||||
return DXPipeline::Create(config);
|
||||
return DXPipeline::Create(config, cache_data, cache_data_length);
|
||||
}
|
||||
|
||||
u16 Renderer::BBoxRead(int index)
|
||||
|
||||
@@ -41,7 +41,9 @@ public:
|
||||
size_t length) override;
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
|
||||
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config) override;
|
||||
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config,
|
||||
const void* cache_data = nullptr,
|
||||
size_t cache_data_length = 0) override;
|
||||
|
||||
u16 BBoxRead(int index) override;
|
||||
void BBoxWrite(int index, u16 value) override;
|
||||
|
||||
@@ -80,6 +80,8 @@ void VideoBackend::FillBackendInfo()
|
||||
g_Config.backend_info.bSupportsPartialDepthCopies = false;
|
||||
g_Config.backend_info.Adapters = D3DCommon::GetAdapterNames();
|
||||
g_Config.backend_info.AAModes = DXContext::GetAAModes(g_Config.iAdapter);
|
||||
g_Config.backend_info.bSupportsShaderBinaries = true;
|
||||
g_Config.backend_info.bSupportsPipelineCacheData = true;
|
||||
|
||||
// We can only check texture support once we have a device.
|
||||
if (g_dx_context)
|
||||
|
||||
@@ -23,11 +23,6 @@ Shader::Shader(ShaderStage stage, BinaryData bytecode)
|
||||
|
||||
Shader::~Shader() = default;
|
||||
|
||||
bool Shader::HasBinary() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractShader::BinaryData Shader::GetBinary() const
|
||||
{
|
||||
return m_bytecode;
|
||||
|
||||
@@ -16,7 +16,6 @@ public:
|
||||
|
||||
const BinaryData& GetByteCode() const { return m_bytecode; }
|
||||
|
||||
bool HasBinary() const override;
|
||||
BinaryData GetBinary() const override;
|
||||
|
||||
static bool CompileShader(D3D_FEATURE_LEVEL feature_level, BinaryData* out_bytecode,
|
||||
|
||||
@@ -52,6 +52,8 @@ void VideoBackend::InitBackendInfo()
|
||||
g_Config.backend_info.bSupportsLogicOp = false;
|
||||
g_Config.backend_info.bSupportsLargePoints = false;
|
||||
g_Config.backend_info.bSupportsPartialDepthCopies = false;
|
||||
g_Config.backend_info.bSupportsShaderBinaries = false;
|
||||
g_Config.backend_info.bSupportsPipelineCacheData = false;
|
||||
|
||||
// aamodes: We only support 1 sample, so no MSAA
|
||||
g_Config.backend_info.Adapters.clear();
|
||||
|
||||
@@ -46,9 +46,6 @@ class NullShader final : public AbstractShader
|
||||
public:
|
||||
explicit NullShader(ShaderStage stage) : AbstractShader(stage) {}
|
||||
~NullShader() = default;
|
||||
|
||||
bool HasBinary() const override { return false; }
|
||||
BinaryData GetBinary() const override { return {}; }
|
||||
};
|
||||
|
||||
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
||||
@@ -70,7 +67,9 @@ public:
|
||||
~NullPipeline() override = default;
|
||||
};
|
||||
|
||||
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config)
|
||||
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config,
|
||||
const void* cache_data,
|
||||
size_t cache_data_length)
|
||||
{
|
||||
return std::make_unique<NullPipeline>();
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@ public:
|
||||
size_t length) override;
|
||||
std::unique_ptr<NativeVertexFormat>
|
||||
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override;
|
||||
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config) override;
|
||||
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config,
|
||||
const void* cache_data = nullptr,
|
||||
size_t cache_data_length = 0) override;
|
||||
|
||||
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override { return 0; }
|
||||
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||
#include "VideoBackends/OGL/Render.h"
|
||||
#include "VideoBackends/OGL/VertexManager.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
@@ -31,7 +32,7 @@ static GLenum MapToGLPrimitive(PrimitiveType primitive_type)
|
||||
OGLPipeline::OGLPipeline(const GLVertexFormat* vertex_format,
|
||||
const RasterizationState& rasterization_state,
|
||||
const DepthState& depth_state, const BlendingState& blending_state,
|
||||
const PipelineProgram* program, GLuint gl_primitive)
|
||||
PipelineProgram* program, GLuint gl_primitive)
|
||||
: m_vertex_format(vertex_format), m_rasterization_state(rasterization_state),
|
||||
m_depth_state(depth_state), m_blending_state(blending_state), m_program(program),
|
||||
m_gl_primitive(gl_primitive)
|
||||
@@ -44,13 +45,47 @@ OGLPipeline::~OGLPipeline()
|
||||
ProgramShaderCache::ReleasePipelineProgram(m_program);
|
||||
}
|
||||
|
||||
std::unique_ptr<OGLPipeline> OGLPipeline::Create(const AbstractPipelineConfig& config)
|
||||
AbstractPipeline::CacheData OGLPipeline::GetCacheData() const
|
||||
{
|
||||
const PipelineProgram* program = ProgramShaderCache::GetPipelineProgram(
|
||||
// More than one pipeline can share the same shaders. To avoid bloating the cache with multiple
|
||||
// copies of the same program combination, we set a flag on the program object so that it can't
|
||||
// be retrieved again. When booting, the pipeline cache is loaded in-order, so the additional
|
||||
// pipelines which use the program combination will re-use the already-created object.
|
||||
if (!g_ActiveConfig.backend_info.bSupportsPipelineCacheData || m_program->binary_retrieved)
|
||||
return {};
|
||||
|
||||
GLint program_size = 0;
|
||||
glGetProgramiv(m_program->shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &program_size);
|
||||
if (program_size == 0)
|
||||
return {};
|
||||
|
||||
// Clear any existing error.
|
||||
glGetError();
|
||||
|
||||
// We pack the format at the start of the buffer.
|
||||
CacheData data(program_size + sizeof(u32));
|
||||
GLsizei data_size = 0;
|
||||
GLenum program_format = 0;
|
||||
glGetProgramBinary(m_program->shader.glprogid, program_size, &data_size, &program_format,
|
||||
&data[sizeof(u32)]);
|
||||
if (glGetError() != GL_NO_ERROR || data_size == 0)
|
||||
return {};
|
||||
|
||||
u32 program_format_u32 = static_cast<u32>(program_format);
|
||||
std::memcpy(&data[0], &program_format_u32, sizeof(u32));
|
||||
data.resize(data_size + sizeof(u32));
|
||||
m_program->binary_retrieved = true;
|
||||
return data;
|
||||
}
|
||||
|
||||
std::unique_ptr<OGLPipeline> OGLPipeline::Create(const AbstractPipelineConfig& config,
|
||||
const void* cache_data, size_t cache_data_size)
|
||||
{
|
||||
PipelineProgram* program = ProgramShaderCache::GetPipelineProgram(
|
||||
static_cast<const GLVertexFormat*>(config.vertex_format),
|
||||
static_cast<const OGLShader*>(config.vertex_shader),
|
||||
static_cast<const OGLShader*>(config.geometry_shader),
|
||||
static_cast<const OGLShader*>(config.pixel_shader));
|
||||
static_cast<const OGLShader*>(config.pixel_shader), cache_data, cache_data_size);
|
||||
if (!program)
|
||||
return nullptr;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ class OGLPipeline final : public AbstractPipeline
|
||||
public:
|
||||
explicit OGLPipeline(const GLVertexFormat* vertex_format,
|
||||
const RasterizationState& rasterization_state, const DepthState& depth_state,
|
||||
const BlendingState& blending_state, const PipelineProgram* program,
|
||||
const BlendingState& blending_state, PipelineProgram* program,
|
||||
GLenum gl_primitive);
|
||||
~OGLPipeline() override;
|
||||
|
||||
@@ -29,14 +29,16 @@ public:
|
||||
const PipelineProgram* GetProgram() const { return m_program; }
|
||||
bool HasVertexInput() const { return m_vertex_format != nullptr; }
|
||||
GLenum GetGLPrimitive() const { return m_gl_primitive; }
|
||||
static std::unique_ptr<OGLPipeline> Create(const AbstractPipelineConfig& config);
|
||||
CacheData GetCacheData() const override;
|
||||
static std::unique_ptr<OGLPipeline> Create(const AbstractPipelineConfig& config,
|
||||
const void* cache_data, size_t cache_data_size);
|
||||
|
||||
private:
|
||||
const GLVertexFormat* m_vertex_format;
|
||||
RasterizationState m_rasterization_state;
|
||||
DepthState m_depth_state;
|
||||
BlendingState m_blending_state;
|
||||
const PipelineProgram* m_program;
|
||||
PipelineProgram* m_program;
|
||||
GLenum m_gl_primitive;
|
||||
};
|
||||
|
||||
|
||||
@@ -44,17 +44,6 @@ OGLShader::~OGLShader()
|
||||
glDeleteProgram(m_gl_compute_program_id);
|
||||
}
|
||||
|
||||
bool OGLShader::HasBinary() const
|
||||
{
|
||||
// NOTE: GL shaders do not have binaries, programs do.
|
||||
return false;
|
||||
}
|
||||
|
||||
AbstractShader::BinaryData OGLShader::GetBinary() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<OGLShader> OGLShader::CreateFromSource(ShaderStage stage, const char* source,
|
||||
size_t length)
|
||||
{
|
||||
|
||||
@@ -24,8 +24,6 @@ public:
|
||||
GLenum GetGLShaderType() const { return m_type; }
|
||||
GLuint GetGLShaderID() const { return m_gl_id; }
|
||||
GLuint GetGLComputeProgramID() const { return m_gl_compute_program_id; }
|
||||
bool HasBinary() const override;
|
||||
BinaryData GetBinary() const override;
|
||||
|
||||
static std::unique_ptr<OGLShader> CreateFromSource(ShaderStage stage, const char* source,
|
||||
size_t length);
|
||||
|
||||
@@ -312,7 +312,7 @@ bool ProgramShaderCache::CompileShader(SHADER& shader, const std::string& vcode,
|
||||
if (shader.gsid)
|
||||
glAttachShader(shader.glprogid, shader.gsid);
|
||||
|
||||
if (g_ogl_config.bSupportsGLSLCache)
|
||||
if (g_ActiveConfig.backend_info.bSupportsPipelineCacheData)
|
||||
glProgramParameteri(shader.glprogid, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
|
||||
|
||||
shader.SetProgramBindings(false);
|
||||
@@ -562,10 +562,12 @@ void ProgramShaderCache::InvalidateLastProgram()
|
||||
CurrentProgram = 0;
|
||||
}
|
||||
|
||||
const PipelineProgram* ProgramShaderCache::GetPipelineProgram(const GLVertexFormat* vertex_format,
|
||||
const OGLShader* vertex_shader,
|
||||
const OGLShader* geometry_shader,
|
||||
const OGLShader* pixel_shader)
|
||||
PipelineProgram* ProgramShaderCache::GetPipelineProgram(const GLVertexFormat* vertex_format,
|
||||
const OGLShader* vertex_shader,
|
||||
const OGLShader* geometry_shader,
|
||||
const OGLShader* pixel_shader,
|
||||
const void* cache_data,
|
||||
size_t cache_data_size)
|
||||
{
|
||||
PipelineProgramKey key = {vertex_shader ? vertex_shader->GetID() : 0,
|
||||
geometry_shader ? geometry_shader->GetID() : 0,
|
||||
@@ -580,39 +582,69 @@ const PipelineProgram* ProgramShaderCache::GetPipelineProgram(const GLVertexForm
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// 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)
|
||||
|
||||
// Use the cache data, if present. If this fails, we want to return an error, so the shader cache
|
||||
// doesn't attempt to use the same binary data in the future.
|
||||
if (cache_data_size >= sizeof(u32))
|
||||
{
|
||||
ASSERT(geometry_shader->GetStage() == ShaderStage::Geometry);
|
||||
glAttachShader(prog->shader.glprogid, geometry_shader->GetGLShaderID());
|
||||
u32 program_binary_type;
|
||||
std::memcpy(&program_binary_type, cache_data, sizeof(u32));
|
||||
glProgramBinary(prog->shader.glprogid, static_cast<GLenum>(program_binary_type),
|
||||
static_cast<const u8*>(cache_data) + sizeof(u32),
|
||||
static_cast<GLsizei>(cache_data_size - sizeof(u32)));
|
||||
|
||||
// Check the link status. If this fails, it means the binary was invalid.
|
||||
GLint link_status;
|
||||
glGetProgramiv(prog->shader.glprogid, GL_LINK_STATUS, &link_status);
|
||||
if (link_status != GL_TRUE)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Failed to create GL program from program binary.");
|
||||
prog->shader.Destroy();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We don't want to retrieve this binary and duplicate entries in the cache again.
|
||||
// See the explanation in OGLPipeline.cpp.
|
||||
prog->binary_retrieved = true;
|
||||
}
|
||||
|
||||
// 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, {}, {}, {}))
|
||||
else
|
||||
{
|
||||
prog->shader.Destroy();
|
||||
return nullptr;
|
||||
// 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);
|
||||
|
||||
// Attach shaders.
|
||||
ASSERT(vertex_shader && vertex_shader->GetStage() == ShaderStage::Vertex);
|
||||
ASSERT(pixel_shader && pixel_shader->GetStage() == ShaderStage::Pixel);
|
||||
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());
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsPipelineCacheData)
|
||||
glProgramParameteri(prog->shader.glprogid, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
|
||||
|
||||
// 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();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Lock to insert. A duplicate program may have been created in the meantime.
|
||||
@@ -639,16 +671,17 @@ const PipelineProgram* ProgramShaderCache::GetPipelineProgram(const GLVertexForm
|
||||
return ip.first->second.get();
|
||||
}
|
||||
|
||||
void ProgramShaderCache::ReleasePipelineProgram(const PipelineProgram* prog)
|
||||
void ProgramShaderCache::ReleasePipelineProgram(PipelineProgram* prog)
|
||||
{
|
||||
if (--prog->reference_count > 0)
|
||||
return;
|
||||
|
||||
prog->shader.Destroy();
|
||||
|
||||
std::lock_guard<std::mutex> guard(s_pipeline_program_lock);
|
||||
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();
|
||||
s_pipeline_programs.erase(iter);
|
||||
}
|
||||
s_pipeline_programs.erase(iter);
|
||||
}
|
||||
|
||||
void ProgramShaderCache::CreateHeader()
|
||||
|
||||
@@ -63,6 +63,7 @@ struct PipelineProgram
|
||||
PipelineProgramKey key;
|
||||
SHADER shader;
|
||||
std::atomic_size_t reference_count{1};
|
||||
bool binary_retrieved = false;
|
||||
};
|
||||
|
||||
class ProgramShaderCache
|
||||
@@ -97,11 +98,12 @@ public:
|
||||
// pipeline do not match the pipeline configuration.
|
||||
static u64 GenerateShaderID();
|
||||
|
||||
static const PipelineProgram* GetPipelineProgram(const GLVertexFormat* vertex_format,
|
||||
const OGLShader* vertex_shader,
|
||||
const OGLShader* geometry_shader,
|
||||
const OGLShader* pixel_shader);
|
||||
static void ReleasePipelineProgram(const PipelineProgram* prog);
|
||||
static PipelineProgram* GetPipelineProgram(const GLVertexFormat* vertex_format,
|
||||
const OGLShader* vertex_shader,
|
||||
const OGLShader* geometry_shader,
|
||||
const OGLShader* pixel_shader, const void* cache_data,
|
||||
size_t cache_data_size);
|
||||
static void ReleasePipelineProgram(PipelineProgram* prog);
|
||||
|
||||
private:
|
||||
typedef std::unordered_map<PipelineProgramKey, std::unique_ptr<PipelineProgram>,
|
||||
|
||||
@@ -350,6 +350,7 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
|
||||
}
|
||||
|
||||
bool bSuccess = true;
|
||||
bool supports_glsl_cache = false;
|
||||
|
||||
g_ogl_config.gl_vendor = (const char*)glGetString(GL_VENDOR);
|
||||
g_ogl_config.gl_renderer = (const char*)glGetString(GL_RENDERER);
|
||||
@@ -466,7 +467,7 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
|
||||
GLExtensions::Supports("GL_ARB_gpu_shader5");
|
||||
|
||||
g_ogl_config.bIsES = m_main_gl_context->IsGLES();
|
||||
g_ogl_config.bSupportsGLSLCache = GLExtensions::Supports("GL_ARB_get_program_binary");
|
||||
supports_glsl_cache = GLExtensions::Supports("GL_ARB_get_program_binary");
|
||||
g_ogl_config.bSupportsGLPinnedMemory = GLExtensions::Supports("GL_AMD_pinned_memory");
|
||||
g_ogl_config.bSupportsGLSync = GLExtensions::Supports("GL_ARB_sync");
|
||||
g_ogl_config.bSupportsGLBaseVertex = GLExtensions::Supports("GL_ARB_draw_elements_base_vertex") ||
|
||||
@@ -507,7 +508,7 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
|
||||
EsTexbufType::TexbufExt :
|
||||
EsTexbufType::TexbufNone;
|
||||
|
||||
g_ogl_config.bSupportsGLSLCache = true;
|
||||
supports_glsl_cache = true;
|
||||
g_ogl_config.bSupportsGLSync = true;
|
||||
|
||||
// TODO: Implement support for GL_EXT_clip_cull_distance when there is an extension for
|
||||
@@ -675,6 +676,16 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
|
||||
g_Config.backend_info.bSupportsBackgroundCompiling =
|
||||
!DriverDetails::HasBug(DriverDetails::BUG_SHARED_CONTEXT_SHADER_COMPILATION);
|
||||
|
||||
// Program binaries are supported on GL4.1+, ARB_get_program_binary, or ES3.
|
||||
if (supports_glsl_cache)
|
||||
{
|
||||
// We need to check the number of formats supported. If zero, don't bother getting the binaries.
|
||||
GLint num_formats = 0;
|
||||
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &num_formats);
|
||||
supports_glsl_cache = num_formats > 0;
|
||||
}
|
||||
g_Config.backend_info.bSupportsPipelineCacheData = supports_glsl_cache;
|
||||
|
||||
if (g_ogl_config.bSupportsDebug)
|
||||
{
|
||||
if (GLExtensions::Supports("GL_KHR_debug"))
|
||||
@@ -739,7 +750,7 @@ Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context, float backbuffer_
|
||||
g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" : "PrimitiveRestart ",
|
||||
g_ActiveConfig.backend_info.bSupportsEarlyZ ? "" : "EarlyZ ",
|
||||
g_ogl_config.bSupportsGLPinnedMemory ? "" : "PinnedMemory ",
|
||||
g_ogl_config.bSupportsGLSLCache ? "" : "ShaderCache ",
|
||||
supports_glsl_cache ? "" : "ShaderCache ",
|
||||
g_ogl_config.bSupportsGLBaseVertex ? "" : "BaseVertex ",
|
||||
g_ogl_config.bSupportsGLBufferStorage ? "" : "BufferStorage ",
|
||||
g_ogl_config.bSupportsGLSync ? "" : "Sync ", g_ogl_config.bSupportsMSAA ? "" : "MSAA ",
|
||||
@@ -828,9 +839,11 @@ std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage sta
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config)
|
||||
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config,
|
||||
const void* cache_data,
|
||||
size_t cache_data_length)
|
||||
{
|
||||
return OGLPipeline::Create(config);
|
||||
return OGLPipeline::Create(config, cache_data, cache_data_length);
|
||||
}
|
||||
|
||||
void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user