OpenGLDevice: Lazily compile shaders

This commit is contained in:
Stenzek 2023-08-30 22:20:39 +10:00
parent 5421900bb2
commit a11c9faba9
3 changed files with 85 additions and 33 deletions

View file

@ -373,8 +373,8 @@ public:
DepthState depth; DepthState depth;
BlendState blend; BlendState blend;
const GPUShader* vertex_shader; GPUShader* vertex_shader;
const GPUShader* fragment_shader; GPUShader* fragment_shader;
GPUTexture::Format color_format; GPUTexture::Format color_format;
GPUTexture::Format depth_format; GPUTexture::Format depth_format;

View file

@ -68,48 +68,54 @@ static void FillFooter(PipelineDiskCacheFooter* footer, u32 version)
std::size(footer->driver_version)); std::size(footer->driver_version));
} }
OpenGLShader::OpenGLShader(GPUShaderStage stage, GLuint id, const GPUShaderCache::CacheIndexKey& key) OpenGLShader::OpenGLShader(GPUShaderStage stage, const GPUShaderCache::CacheIndexKey& key, std::string source)
: GPUShader(stage), m_id(id), m_key(key) : GPUShader(stage), m_key(key), m_source(std::move(source))
{ {
} }
OpenGLShader::~OpenGLShader() = default; OpenGLShader::~OpenGLShader()
{
if (m_id.has_value())
glDeleteShader(m_id.value());
}
void OpenGLShader::SetDebugName(const std::string_view& name) void OpenGLShader::SetDebugName(const std::string_view& name)
{ {
#ifdef _DEBUG #ifdef _DEBUG
if (glObjectLabel) if (glObjectLabel)
glObjectLabel(GL_SHADER, m_id, static_cast<GLsizei>(name.length()), static_cast<const GLchar*>(name.data())); {
if (m_id.has_value())
{
m_debug_name = {};
glObjectLabel(GL_SHADER, m_id.value(), static_cast<GLsizei>(name.length()),
static_cast<const GLchar*>(name.data()));
}
else
{
m_debug_name = name;
}
}
#endif #endif
} }
std::unique_ptr<GPUShader> OpenGLDevice::CreateShaderFromBinary(GPUShaderStage stage, gsl::span<const u8> data) bool OpenGLShader::Compile()
{ {
// Not supported.. except spir-v maybe? but no point really... if (m_compile_tried)
return {}; return m_id.has_value();
}
std::unique_ptr<GPUShader> OpenGLDevice::CreateShaderFromSource(GPUShaderStage stage, const std::string_view& source, m_compile_tried = true;
const char* entry_point,
DynamicHeapArray<u8>* out_binary)
{
if (std::strcmp(entry_point, "main") != 0)
{
Log_ErrorPrintf("Entry point must be 'main', but got '%s' instead.", entry_point);
return {};
}
glGetError(); glGetError();
GLuint shader = glCreateShader(GetGLShaderType(stage)); GLuint shader = glCreateShader(GetGLShaderType(m_stage));
if (GLenum err = glGetError(); err != GL_NO_ERROR) if (GLenum err = glGetError(); err != GL_NO_ERROR)
{ {
Log_ErrorPrintf("glCreateShader() failed: %u", err); Log_ErrorPrintf("glCreateShader() failed: %u", err);
return {}; return false;
} }
const GLchar* string = source.data(); const GLchar* string = m_source.data();
const GLint length = static_cast<GLint>(source.length()); const GLint length = static_cast<GLint>(m_source.length());
glShaderSource(shader, 1, &string, &length); glShaderSource(shader, 1, &string, &length);
glCompileShader(shader); glCompileShader(shader);
@ -134,21 +140,51 @@ std::unique_ptr<GPUShader> OpenGLDevice::CreateShaderFromSource(GPUShaderStage s
Log_ErrorPrintf("Shader failed to compile:\n%s", info_log.c_str()); Log_ErrorPrintf("Shader failed to compile:\n%s", info_log.c_str());
auto fp = FileSystem::OpenManagedCFile( auto fp = FileSystem::OpenManagedCFile(
GetShaderDumpPath(fmt::format("bad_shader_{}.txt", s_next_bad_shader_id++)).c_str(), "wb"); GPUDevice::GetShaderDumpPath(fmt::format("bad_shader_{}.txt", s_next_bad_shader_id++)).c_str(), "wb");
if (fp) if (fp)
{ {
std::fwrite(source.data(), source.size(), 1, fp.get()); std::fwrite(m_source.data(), m_source.size(), 1, fp.get());
std::fprintf(fp.get(), "\n\nCompile %s shader failed\n", GPUShader::GetStageName(stage)); std::fprintf(fp.get(), "\n\nCompile %s shader failed\n", GPUShader::GetStageName(m_stage));
std::fwrite(info_log.c_str(), info_log_length, 1, fp.get()); std::fwrite(info_log.c_str(), info_log_length, 1, fp.get());
} }
glDeleteShader(shader); glDeleteShader(shader);
return {}; return false;
} }
} }
m_id = shader;
#ifdef _DEBUG
if (glObjectLabel && !m_debug_name.empty())
{
glObjectLabel(GL_SHADER, shader, static_cast<GLsizei>(m_debug_name.length()),
static_cast<const GLchar*>(m_debug_name.data()));
m_debug_name = {};
}
#endif
return true;
}
std::unique_ptr<GPUShader> OpenGLDevice::CreateShaderFromBinary(GPUShaderStage stage, gsl::span<const u8> data)
{
// Not supported.. except spir-v maybe? but no point really...
return {};
}
std::unique_ptr<GPUShader> OpenGLDevice::CreateShaderFromSource(GPUShaderStage stage, const std::string_view& source,
const char* entry_point,
DynamicHeapArray<u8>* out_binary)
{
if (std::strcmp(entry_point, "main") != 0)
{
Log_ErrorPrintf("Entry point must be 'main', but got '%s' instead.", entry_point);
return {};
}
return std::unique_ptr<GPUShader>( return std::unique_ptr<GPUShader>(
new OpenGLShader(stage, shader, GPUShaderCache::GetCacheKey(stage, source, "main"))); new OpenGLShader(stage, GPUShaderCache::GetCacheKey(stage, source, entry_point), std::string(source)));
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -262,6 +298,14 @@ GLuint OpenGLDevice::LookupProgramCache(const OpenGLPipeline::ProgramCacheKey& k
GLuint OpenGLDevice::CompileProgram(const GPUPipeline::GraphicsConfig& plconfig) GLuint OpenGLDevice::CompileProgram(const GPUPipeline::GraphicsConfig& plconfig)
{ {
OpenGLShader* vertex_shader = static_cast<OpenGLShader*>(plconfig.vertex_shader);
OpenGLShader* fragment_shader = static_cast<OpenGLShader*>(plconfig.fragment_shader);
if (!vertex_shader || !fragment_shader || !vertex_shader->Compile() || !fragment_shader->Compile())
{
Log_ErrorPrintf("Failed to compile shaders.");
return 0;
}
glGetError(); glGetError();
const GLuint program_id = glCreateProgram(); const GLuint program_id = glCreateProgram();
if (glGetError() != GL_NO_ERROR) if (glGetError() != GL_NO_ERROR)
@ -274,8 +318,8 @@ GLuint OpenGLDevice::CompileProgram(const GPUPipeline::GraphicsConfig& plconfig)
glProgramParameteri(program_id, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); glProgramParameteri(program_id, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
Assert(plconfig.vertex_shader && plconfig.fragment_shader); Assert(plconfig.vertex_shader && plconfig.fragment_shader);
glAttachShader(program_id, static_cast<const OpenGLShader*>(plconfig.vertex_shader)->GetGLId()); glAttachShader(program_id, vertex_shader->GetGLId());
glAttachShader(program_id, static_cast<const OpenGLShader*>(plconfig.fragment_shader)->GetGLId()); glAttachShader(program_id, fragment_shader->GetGLId());
if (!ShaderGen::UseGLSLBindingLayout()) if (!ShaderGen::UseGLSLBindingLayout())
{ {

View file

@ -18,14 +18,22 @@ public:
void SetDebugName(const std::string_view& name) override; void SetDebugName(const std::string_view& name) override;
ALWAYS_INLINE GLuint GetGLId() const { return m_id; } bool Compile();
ALWAYS_INLINE GLuint GetGLId() const { return m_id.value(); }
ALWAYS_INLINE const GPUShaderCache::CacheIndexKey& GetKey() const { return m_key; } ALWAYS_INLINE const GPUShaderCache::CacheIndexKey& GetKey() const { return m_key; }
private: private:
OpenGLShader(GPUShaderStage stage, GLuint id, const GPUShaderCache::CacheIndexKey& key); OpenGLShader(GPUShaderStage stage, const GPUShaderCache::CacheIndexKey& key, std::string source);
GLuint m_id;
GPUShaderCache::CacheIndexKey m_key; GPUShaderCache::CacheIndexKey m_key;
std::string m_source;
std::optional<GLuint> m_id;
bool m_compile_tried = false;
#ifdef _DEBUG
std::string m_debug_name;
#endif
}; };
class OpenGLPipeline final : public GPUPipeline class OpenGLPipeline final : public GPUPipeline