diff --git a/CMakeLists.txt b/CMakeLists.txt index a00879fe..d2f23696 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,8 +73,8 @@ add_definitions(-DEMULATOR_VERSION_PATCH=${EMULATOR_VERSION_PATCH}) set_property(GLOBAL PROPERTY USE_FOLDERS ON) # enable link time optimization for release builds -set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON) -set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON) +#set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)# +#set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON)# if (MSVC) set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT CemuBin) diff --git a/src/Cafe/HW/Latte/Core/LatteShader.cpp b/src/Cafe/HW/Latte/Core/LatteShader.cpp index 91de6310..54c5acc1 100644 --- a/src/Cafe/HW/Latte/Core/LatteShader.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShader.cpp @@ -14,6 +14,7 @@ #include "util/helpers/StringParser.h" #include "config/ActiveSettings.h" #include "Cafe/GameProfile/GameProfile.h" +#include "HW/Latte/Renderer/OpenGL/RendererShaderGL.h" #include "util/containers/flat_hash_map.hpp" #if ENABLE_METAL #include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h" @@ -360,23 +361,15 @@ void LatteShader_CreateRendererShader(LatteDecompilerShader* shader, bool compil } // create shader - shader->shader = g_renderer->shader_create(shaderType, shader->baseHash, shader->auxHash, shaderSrc, true, shader->isCustomShader); + shader->shader = g_renderer->shader_create(shaderType, shader->baseHash, shader->auxHash, std::move(shaderSrc), true, shader->isCustomShader); if (shader->shader == nullptr) shader->hasError = true; - // after renderer shader creation we can throw away any intermediate info - LatteShader_CleanupAfterCompile(shader); -} - -void LatteShader_FinishCompilation(LatteDecompilerShader* shader) -{ - if (shader->hasError) + if (g_renderer->GetType() == RendererAPI::OpenGL) { - cemuLog_logDebug(LogType::Force, "LatteShader_finishCompilation(): Skipped because of error in shader {:x}", shader->baseHash); - return; + RendererShaderGL* shaderGL = static_cast(shader->shader); + shaderGL->SetDecompilerShader(shader); } - shader->shader->WaitForCompiled(); - - LatteShader_prepareSeparableUniforms(shader); + // after renderer shader creation we can throw away any intermediate info LatteShader_CleanupAfterCompile(shader); } @@ -845,13 +838,6 @@ LatteDecompilerShader* LatteShader_CompileSeparableVertexShader(uint64 baseHash, LatteShader_CreateRendererShader(vertexShader, false); performanceMonitor.numCompiledVS++; - if (g_renderer->GetType() == RendererAPI::OpenGL) - { - if (vertexShader->shader) - vertexShader->shader->PreponeCompilation(true); - LatteShader_FinishCompilation(vertexShader); - } - LatteSHRC_RegisterShader(vertexShader, vertexShader->baseHash, vertexShader->auxHash); return vertexShader; } @@ -874,13 +860,6 @@ LatteDecompilerShader* LatteShader_CompileSeparableGeometryShader(uint64 baseHas LatteShader_CreateRendererShader(geometryShader, false); performanceMonitor.numCompiledGS++; - if (g_renderer->GetType() == RendererAPI::OpenGL) - { - if (geometryShader->shader) - geometryShader->shader->PreponeCompilation(true); - LatteShader_FinishCompilation(geometryShader); - } - LatteSHRC_RegisterShader(geometryShader, geometryShader->baseHash, geometryShader->auxHash); return geometryShader; } @@ -903,13 +882,6 @@ LatteDecompilerShader* LatteShader_CompileSeparablePixelShader(uint64 baseHash, LatteShaderCache_writeSeparablePixelShader(_shaderBaseHash_ps, psAuxHash, pixelShaderPtr, pixelShaderSize, LatteGPUState.contextRegister, usesGeometryShader); } - if (g_renderer->GetType() == RendererAPI::OpenGL) - { - if (pixelShader->shader) - pixelShader->shader->PreponeCompilation(true); - LatteShader_FinishCompilation(pixelShader); - } - LatteSHRC_RegisterShader(pixelShader, _shaderBaseHash_ps, psAuxHash); return pixelShader; } diff --git a/src/Cafe/HW/Latte/Core/LatteShader.h b/src/Cafe/HW/Latte/Core/LatteShader.h index 85d53b01..253de4e1 100644 --- a/src/Cafe/HW/Latte/Core/LatteShader.h +++ b/src/Cafe/HW/Latte/Core/LatteShader.h @@ -100,7 +100,6 @@ void LatteShader_GetDecompilerOptions(struct LatteDecompilerOptions& options, La LatteDecompilerShader* LatteShader_CreateShaderFromDecompilerOutput(LatteDecompilerOutput_t& decompilerOutput, uint64 baseHash, bool calculateAuxHash, uint64 optionalAuxHash, uint32* contextRegister); void LatteShader_CreateRendererShader(LatteDecompilerShader* shader, bool compileAsync); -void LatteShader_FinishCompilation(LatteDecompilerShader* shader); void LatteShader_prepareSeparableUniforms(LatteDecompilerShader* shader); diff --git a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp index 14a1f9b0..305e3011 100644 --- a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp @@ -106,13 +106,24 @@ void LatteShaderCache_removeFromCompileQueue(sint32 index) */ void LatteShaderCache_updateCompileQueue(sint32 maxRemainingEntries) { + // remove any shaders that are already done + for (size_t i = 0; i < shaderCompileQueue.count; i++) + { + auto shaderEntry = shaderCompileQueue.entry[i].shader; + if (!shaderEntry) + continue; + if (shaderEntry->shader->IsCompiled()) + { + LatteShaderCache_removeFromCompileQueue(i); + } + } while (true) { if (shaderCompileQueue.count <= maxRemainingEntries) break; auto shader = shaderCompileQueue.entry[0].shader; if (shader) - LatteShader_FinishCompilation(shader); + shader->shader->PreponeCompilation(); LatteShaderCache_removeFromCompileQueue(0); } } diff --git a/src/Cafe/HW/Latte/Core/LatteShaderGL.cpp b/src/Cafe/HW/Latte/Core/LatteShaderGL.cpp index 09c484e6..7a22539a 100644 --- a/src/Cafe/HW/Latte/Core/LatteShaderGL.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShaderGL.cpp @@ -26,7 +26,7 @@ bool gxShader_checkIfSuccessfullyLinked(GLuint glProgram) void LatteShader_prepareSeparableUniforms(LatteDecompilerShader* shader) { - if (g_renderer->GetType() != RendererAPI::OpenGL) + if(shader->hasError) return; auto shaderGL = (RendererShaderGL*)shader->shader; diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.cpp index 6193ab10..737554ed 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.cpp @@ -176,8 +176,8 @@ static RendererShaderMtl* rectsEmulationGS_generate(MetalRenderer* metalRenderer gsSrc.append("}\r\n"); - auto mtlShader = new RendererShaderMtl(metalRenderer, RendererShader::ShaderType::kGeometry, 0, 0, false, false, gsSrc); - mtlShader->PreponeCompilation(true); + auto mtlShader = new RendererShaderMtl(metalRenderer, RendererShader::ShaderType::kGeometry, 0, 0, false, false, std::move(gsSrc)); + mtlShader->PreponeCompilation(); return mtlShader; } @@ -321,11 +321,11 @@ bool MetalPipelineCompiler::Compile(bool forceCompile, bool isRenderThread, bool { // if some shader stages are not compiled yet, compile them now if (m_vertexShaderMtl && !m_vertexShaderMtl->IsCompiled()) - m_vertexShaderMtl->PreponeCompilation(isRenderThread); + m_vertexShaderMtl->PreponeCompilation(); if (m_geometryShaderMtl && !m_geometryShaderMtl->IsCompiled()) - m_geometryShaderMtl->PreponeCompilation(isRenderThread); + m_geometryShaderMtl->PreponeCompilation(); if (m_pixelShaderMtl && !m_pixelShaderMtl->IsCompiled()) - m_pixelShaderMtl->PreponeCompilation(isRenderThread); + m_pixelShaderMtl->PreponeCompilation(); } else { diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index 7ceaf74d..ceb12742 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -996,9 +996,9 @@ void MetalRenderer::buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, m_state.m_uniformBufferOffsets[GetMtlGeneralShaderType(shaderType)][bufferIndex] = offset; } -RendererShader* MetalRenderer::shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool isGameShader, bool isGfxPackShader) +RendererShader* MetalRenderer::shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, std::string&& source, bool isGameShader, bool isGfxPackShader) { - return new RendererShaderMtl(this, type, baseHash, auxHash, isGameShader, isGfxPackShader, source); + return new RendererShaderMtl(this, type, baseHash, auxHash, isGameShader, isGfxPackShader, std::move(source)); } void MetalRenderer::streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h index e905b834..7d4d9d80 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h @@ -241,7 +241,7 @@ public: void buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) override; // shader - RendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool compileAsync, bool isGfxPackSource) override; + RendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, std::string&& source, bool compileAsync, bool isGfxPackSource) override; // streamout void streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) override; diff --git a/src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.cpp b/src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.cpp index f00af85a..bf94bddc 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.cpp @@ -213,8 +213,8 @@ void RendererShaderMtl::Shutdown() shaderMtlThreadPool.StopThreads(); } -RendererShaderMtl::RendererShaderMtl(MetalRenderer* mtlRenderer, ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& mslCode) - : RendererShader(type, baseHash, auxHash, isGameShader, isGfxPackShader), m_mtlr{mtlRenderer}, m_mslCode{mslCode} +RendererShaderMtl::RendererShaderMtl(MetalRenderer* mtlRenderer, ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, std::string&& mslCode) + : RendererShader(type, baseHash, auxHash, isGameShader, isGfxPackShader), m_mtlr{mtlRenderer}, m_mslCode{std::move(mslCode)} { // start async compilation shaderMtlThreadPool.s_compilationQueueMutex.lock(); @@ -231,7 +231,7 @@ RendererShaderMtl::~RendererShaderMtl() m_function->release(); } -void RendererShaderMtl::PreponeCompilation(bool isRenderThread) +void RendererShaderMtl::PreponeCompilation() { shaderMtlThreadPool.s_compilationQueueMutex.lock(); bool isStillQueued = m_compilationState.hasState(COMPILATION_STATE::QUEUED); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.h b/src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.h index 1a0c33a9..0246223a 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.h @@ -28,7 +28,7 @@ public: static void Initialize(); static void Shutdown(); - RendererShaderMtl(class MetalRenderer* mtlRenderer, ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& mslCode); + RendererShaderMtl(class MetalRenderer* mtlRenderer, ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, std::string&& mslCode); virtual ~RendererShaderMtl(); MTL::Function* GetFunction() const @@ -36,7 +36,7 @@ public: return m_function; } - void PreponeCompilation(bool isRenderThread) override; + void PreponeCompilation() override; bool IsCompiled() override; bool WaitForCompiled() override; diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp index a4d1966d..c9308fe4 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp @@ -1306,9 +1306,9 @@ void OpenGLRenderer::attributeStream_unbindVertexBuffer() glBindBuffer(GL_ARRAY_BUFFER, 0); } -RendererShader* OpenGLRenderer::shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool isGameShader, bool isGfxPackShader) +RendererShader* OpenGLRenderer::shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, std::string&& source, bool isGameShader, bool isGfxPackShader) { - return new RendererShaderGL(type, baseHash, auxHash, isGameShader, isGfxPackShader, source); + return new RendererShaderGL(type, baseHash, auxHash, isGameShader, isGfxPackShader, std::move(source)); } void OpenGLRenderer::shader_bind(RendererShader* shader) diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h index 5b9ccd41..159657ab 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h @@ -145,7 +145,7 @@ public: void uniformData_update(); // shader - RendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool isGameShader, bool isGfxPackShader) override; + RendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, std::string&& source, bool isGameShader, bool isGfxPackShader) override; void shader_bind(RendererShader* shader); void shader_unbind(RendererShader::ShaderType shaderType); diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp index 571961f4..821252d3 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp @@ -867,8 +867,8 @@ RendererShaderGL* rectsEmulationGS_generateShaderGL(LatteDecompilerShader* verte gsSrc.append("}\r\n"); - auto glShader = new RendererShaderGL(RendererShader::ShaderType::kGeometry, 0, 0, false, false, gsSrc); - glShader->PreponeCompilation(true); + auto glShader = new RendererShaderGL(RendererShader::ShaderType::kGeometry, 0, 0, false, false, std::move(gsSrc)); + glShader->PreponeCompilation(); return glShader; } @@ -912,9 +912,20 @@ void OpenGLRenderer::draw_genericDrawHandler(uint32 baseVertex, uint32 baseInsta { beginPerfMonProfiling(performanceMonitor.gpuTime_dcStageShaderAndUniformMgr); LatteSHRC_UpdateActiveShaders(); - LatteDecompilerShader* vs = (LatteDecompilerShader*)LatteSHRC_GetActiveVertexShader(); - LatteDecompilerShader* gs = (LatteDecompilerShader*)LatteSHRC_GetActiveGeometryShader(); - LatteDecompilerShader* ps = (LatteDecompilerShader*)LatteSHRC_GetActivePixelShader(); + LatteDecompilerShader* vs = LatteSHRC_GetActiveVertexShader(); + LatteDecompilerShader* gs = LatteSHRC_GetActiveGeometryShader(); + LatteDecompilerShader* ps = LatteSHRC_GetActivePixelShader(); + + for (auto& i : {vs, gs, ps}) + { + if (!i) + continue; + if (!i->shader->IsCompiled()) + { + i->shader->WaitForCompiled(); + } + } + if (vs) shader_bind(vs->shader); else diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp index 4d7fe2b9..31034222 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp @@ -2,6 +2,7 @@ #include "Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h" #include "Cemu/FileCache/FileCache.h" +#include "HW/Latte/Core/LatteShader.h" #include "config/ActiveSettings.h" #include "config/LaunchSettings.h" @@ -42,7 +43,7 @@ bool RendererShaderGL::loadBinary() m_program = 0; return false; } - m_isCompiled = true; + m_binaryLoaded = true; return true; } @@ -73,8 +74,8 @@ void RendererShaderGL::storeBinary() } } -RendererShaderGL::RendererShaderGL(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& glslSource) - : RendererShader(type, baseHash, auxHash, isGameShader, isGfxPackShader), m_glslSource(glslSource) +RendererShaderGL::RendererShaderGL(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, std::string&& glslSource) + : RendererShader(type, baseHash, auxHash, isGameShader, isGfxPackShader), m_glslSource(std::move(glslSource)) { GLenum glShaderType; switch (type) @@ -109,19 +110,8 @@ RendererShaderGL::RendererShaderGL(ShaderType type, uint64 baseHash, uint64 auxH glShaderSource(m_shader_object, 1, &c_str, &size); glCompileShader(m_shader_object); - GLint log_length; - glGetShaderiv(m_shader_object, GL_INFO_LOG_LENGTH, &log_length); - if (log_length > 0) - { - char log[2048]{}; - GLsizei log_size; - glGetShaderInfoLog(m_shader_object, std::min(log_length, sizeof(log) - 1), &log_size, log); - cemuLog_log(LogType::Force, "Error/Warning in shader:"); - cemuLog_log(LogType::Force, log); - } - // set debug name - if (LaunchSettings::NSightModeEnabled()) + if (LaunchSettings::NSightModeEnabled()) { auto objNameStr = fmt::format("shader_{:016x}_{:016x}", m_baseHash, m_auxHash); glObjectLabel(GL_SHADER, m_shader_object, objNameStr.size(), objNameStr.c_str()); @@ -134,12 +124,6 @@ RendererShaderGL::RendererShaderGL(ShaderType type, uint64 baseHash, uint64 auxH m_shader_attached = true; glLinkProgram(m_program); - storeBinary(); - - // count shader compilation - if (!s_isLoadingShaders) - ++g_compiled_shaders_total; - // we can throw away the GLSL code to conserve RAM m_glslSource.clear(); m_glslSource.shrink_to_fit(); @@ -157,7 +141,7 @@ RendererShaderGL::~RendererShaderGL() glDeleteProgram(m_program); } -void RendererShaderGL::PreponeCompilation(bool isRenderThread) +void RendererShaderGL::PreponeCompilation() { // the logic for initiating compilation is currently in the constructor // here we only guarantee that it is finished before we return @@ -168,47 +152,74 @@ void RendererShaderGL::PreponeCompilation(bool isRenderThread) bool RendererShaderGL::IsCompiled() { - cemu_assert_debug(false); - return true; + if(m_isCompiled) + return true; + + if(!glMaxShaderCompilerThreadsARB || m_binaryLoaded) + { + WaitForCompiled(); + return true; + } + + GLint isShaderComplete = 0, isProgramComplete = 0; + glGetShaderiv(m_shader_object, GL_COMPLETION_STATUS_ARB, &isShaderComplete); + if(!isShaderComplete) + return false; + glGetProgramiv(m_program, GL_COMPLETION_STATUS_ARB, &isProgramComplete); + if (isProgramComplete) + WaitForCompiled(); // since COMPLETION_STATUS == true, this should be very fast + return m_isCompiled; } bool RendererShaderGL::WaitForCompiled() { - char infoLog[8 * 1024]; if (m_isCompiled) return true; + if (m_binaryLoaded) + { + LatteShader_prepareSeparableUniforms(m_decompilerShader); + m_isCompiled = true; + return true; + } + + char infoLog[8 * 1024]; + GLint log_length; + + // count shader compilation + if (!s_isLoadingShaders) + ++g_compiled_shaders_total; + // check if compilation was successful GLint compileStatus = GL_FALSE; glGetShaderiv(m_shader_object, GL_COMPILE_STATUS, &compileStatus); - if (compileStatus == 0) + if (compileStatus == GL_FALSE) { - uint32 infoLogLength, tempLength; - glGetShaderiv(m_shader_object, GL_INFO_LOG_LENGTH, (GLint *)&infoLogLength); - if (infoLogLength != 0) + glGetShaderiv(m_shader_object, GL_INFO_LOG_LENGTH, &log_length); + if (log_length > 0) { - tempLength = sizeof(infoLog) - 1; - glGetShaderInfoLog(m_shader_object, std::min(infoLogLength, tempLength), (GLsizei*)&tempLength, (GLcharARB*)infoLog); - infoLog[tempLength] = '\0'; - cemuLog_log(LogType::Force, "Compile error in shader. Log:"); + glGetShaderInfoLog(m_shader_object, sizeof(infoLog), &log_length, infoLog); + cemuLog_log(LogType::Force, "Error/Warning in shader:"); cemuLog_log(LogType::Force, infoLog); } + if (m_shader_object != 0) glDeleteShader(m_shader_object); + if (m_program != 0) + glDeleteProgram(m_program); + m_program = m_shader_object = 0; m_isCompiled = true; return false; } + // get shader binary GLint linkStatus = GL_FALSE; glGetProgramiv(m_program, GL_LINK_STATUS, &linkStatus); - if (linkStatus == 0) + if (linkStatus == GL_FALSE) { - uint32 infoLogLength, tempLength; - glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, (GLint *)&infoLogLength); - if (infoLogLength != 0) + glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, (GLint *)&log_length); + if (log_length != 0) { - tempLength = sizeof(infoLog) - 1; - glGetProgramInfoLog(m_program, std::min(infoLogLength, tempLength), (GLsizei*)&tempLength, (GLcharARB*)infoLog); - infoLog[tempLength] = '\0'; + glGetProgramInfoLog(m_program, sizeof(infoLog), &log_length, (GLcharARB*)infoLog); cemuLog_log(LogType::Force, "Link error in shader. Log:"); cemuLog_log(LogType::Force, infoLog); } @@ -216,9 +227,19 @@ bool RendererShaderGL::WaitForCompiled() return false; } - /*glDetachShader(m_program, m_shader_object); - m_shader_attached = false;*/ + glDetachShader(m_program, m_shader_object); + m_shader_attached = false; + glDeleteShader(m_shader_object); + m_shader_object = 0; + + storeBinary(); + m_isCompiled = true; + if (m_decompilerShader) + { + LatteShader_prepareSeparableUniforms(m_decompilerShader); + } + return true; } @@ -246,6 +267,10 @@ void RendererShaderGL::SetUniform4iv(sint32 location, void* data, sint32 count) { glProgramUniform4iv(m_program, location, count, (const GLint*)data); } +void RendererShaderGL::SetDecompilerShader(LatteDecompilerShader* decompilerShader) +{ + m_decompilerShader = decompilerShader; +} void RendererShaderGL::ShaderCacheLoading_begin(uint64 cacheTitleId) { @@ -276,8 +301,8 @@ void RendererShaderGL::ShaderCacheLoading_begin(uint64 cacheTitleId) { const uint32 cacheMagic = GeneratePrecompiledCacheId(); const std::string cacheFilename = fmt::format("{:016x}_gl.bin", cacheTitleId); - s_programBinaryCache = FileCache::Open(ActiveSettings::GetCachePath("shaderCache/precompiled/{}", cacheFilename), true, cacheMagic); - if (s_programBinaryCache == nullptr) + s_programBinaryCache.reset(FileCache::Open(ActiveSettings::GetCachePath("shaderCache/precompiled/{}", cacheFilename), true, cacheMagic)); + if (!s_programBinaryCache) cemuLog_log(LogType::Force, "Unable to open OpenGL precompiled cache {}", cacheFilename); } s_isLoadingShaders = true; @@ -290,13 +315,10 @@ void RendererShaderGL::ShaderCacheLoading_end() void RendererShaderGL::ShaderCacheLoading_Close() { - if(s_programBinaryCache) - { - delete s_programBinaryCache; - s_programBinaryCache = nullptr; - } + s_programBinaryCache.reset(); g_compiled_shaders_total = 0; g_compiled_shaders_async = 0; } -FileCache* RendererShaderGL::s_programBinaryCache{}; + +std::unique_ptr RendererShaderGL::s_programBinaryCache{}; diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h b/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h index 1e8784ff..2d4f986b 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h @@ -6,11 +6,11 @@ class RendererShaderGL : public RendererShader { public: - RendererShaderGL(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& glslSource); + RendererShaderGL(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, std::string&& glslSource); virtual ~RendererShaderGL(); - void PreponeCompilation(bool isRenderThread) override; + void PreponeCompilation() override; bool IsCompiled() override; bool WaitForCompiled() override; @@ -24,6 +24,8 @@ public: void SetUniform2fv(sint32 location, void* data, sint32 count); void SetUniform4iv(sint32 location, void* data, sint32 count); + void SetDecompilerShader(class LatteDecompilerShader* decompilerShader); + static void ShaderCacheLoading_begin(uint64 cacheTitleId); static void ShaderCacheLoading_end(); static void ShaderCacheLoading_Close(); @@ -31,6 +33,7 @@ public: private: GLuint m_program; GLuint m_shader_object; + LatteDecompilerShader* m_decompilerShader = nullptr; bool loadBinary(); void storeBinary(); @@ -39,7 +42,8 @@ private: bool m_shader_attached{ false }; bool m_isCompiled{ false }; + bool m_binaryLoaded { false }; - static class FileCache* s_programBinaryCache; + static std::unique_ptr s_programBinaryCache; }; diff --git a/src/Cafe/HW/Latte/Renderer/Renderer.h b/src/Cafe/HW/Latte/Renderer/Renderer.h index 01a6d3b2..e2060f4d 100644 --- a/src/Cafe/HW/Latte/Renderer/Renderer.h +++ b/src/Cafe/HW/Latte/Renderer/Renderer.h @@ -131,7 +131,7 @@ public: virtual void buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) = 0; // shader - virtual RendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool compileAsync, bool isGfxPackSource) = 0; + virtual RendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, std::string&& source, bool compileAsync, bool isGfxPackSource) = 0; // streamout virtual void streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) = 0; diff --git a/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp b/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp index a4f538a8..293d3174 100644 --- a/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp +++ b/src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp @@ -251,11 +251,11 @@ RendererOutputShader::RendererOutputShader(const std::string& vertex_source, con else finalFragmentSrc = PrependFragmentPreamble(fragment_source); - m_vertex_shader.reset(g_renderer->shader_create(RendererShader::ShaderType::kVertex, 0, 0, vertex_source, false, false)); - m_fragment_shader.reset(g_renderer->shader_create(RendererShader::ShaderType::kFragment, 0, 0, finalFragmentSrc, false, false)); + m_vertex_shader.reset(g_renderer->shader_create(RendererShader::ShaderType::kVertex, 0, 0, std::string(vertex_source), false, false)); + m_fragment_shader.reset(g_renderer->shader_create(RendererShader::ShaderType::kFragment, 0, 0, std::string(finalFragmentSrc), false, false)); - m_vertex_shader->PreponeCompilation(true); - m_fragment_shader->PreponeCompilation(true); + m_vertex_shader->PreponeCompilation(); + m_fragment_shader->PreponeCompilation(); if (!m_vertex_shader->WaitForCompiled()) throw std::exception(); diff --git a/src/Cafe/HW/Latte/Renderer/RendererShader.h b/src/Cafe/HW/Latte/Renderer/RendererShader.h index 2bc66769..7dd80291 100644 --- a/src/Cafe/HW/Latte/Renderer/RendererShader.h +++ b/src/Cafe/HW/Latte/Renderer/RendererShader.h @@ -14,7 +14,7 @@ public: ShaderType GetType() const { return m_type; } - virtual void PreponeCompilation(bool isRenderThread) = 0; // if shader not yet compiled, compile it synchronously (if possible) or alternatively wait for compilation. After this function IsCompiled() is guaranteed to be true + virtual void PreponeCompilation() = 0; // if shader not yet compiled, compile it synchronously (if possible) or alternatively wait for compilation. After this function IsCompiled() is guaranteed to be true virtual bool IsCompiled() = 0; virtual bool WaitForCompiled() = 0; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp index 15fd66e0..73cf86b3 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp @@ -174,7 +174,7 @@ public: job->m_compilationState.setValue(RendererShaderVk::COMPILATION_STATE::COMPILING); s_compilationQueueMutex.unlock(); // compile - job->CompileInternal(false); + job->CompileInternal(); ++g_compiled_shaders_async; // mark as compiled cemu_assert_debug(job->m_compilationState.getValue() == RendererShaderVk::COMPILATION_STATE::COMPILING); @@ -195,8 +195,8 @@ private: std::atomic m_threadsActive; }ShaderVkThreadPool; -RendererShaderVk::RendererShaderVk(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& glslCode) - : RendererShader(type, baseHash, auxHash, isGameShader, isGfxPackShader), m_glslCode(glslCode) +RendererShaderVk::RendererShaderVk(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, std::string&& glslCode) + : RendererShader(type, baseHash, auxHash, isGameShader, isGfxPackShader), m_glslCode(std::move(glslCode)) { // start async compilation ShaderVkThreadPool.s_compilationQueueMutex.lock(); @@ -264,7 +264,7 @@ void RendererShaderVk::FinishCompilation() m_glslCode.shrink_to_fit(); } -void RendererShaderVk::CompileInternal(bool isRenderThread) +void RendererShaderVk::CompileInternal() { const bool compileWithDebugInfo = ((VulkanRenderer*)g_renderer.get())->IsTracingToolEnabled(); @@ -393,7 +393,7 @@ void RendererShaderVk::CompileInternal(bool isRenderThread) FinishCompilation(); } -void RendererShaderVk::PreponeCompilation(bool isRenderThread) +void RendererShaderVk::PreponeCompilation() { ShaderVkThreadPool.s_compilationQueueMutex.lock(); bool isStillQueued = m_compilationState.hasState(COMPILATION_STATE::QUEUED); @@ -413,7 +413,7 @@ void RendererShaderVk::PreponeCompilation(bool isRenderThread) else { // compile synchronously - CompileInternal(isRenderThread); + CompileInternal(); m_compilationState.setValue(COMPILATION_STATE::DONE); } } diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h index e2e1169a..4bd9c8f1 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h @@ -25,7 +25,7 @@ public: static void ShaderCacheLoading_end(); static void ShaderCacheLoading_Close(); - RendererShaderVk(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& glslCode); + RendererShaderVk(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, std::string&& glslCode); virtual ~RendererShaderVk(); static void Init(); @@ -49,12 +49,12 @@ public: s_dependencyLock.unlock(); } - void PreponeCompilation(bool isRenderThread) override; + void PreponeCompilation() override; bool IsCompiled() override; bool WaitForCompiled() override; private: - void CompileInternal(bool isRenderThread); + void CompileInternal(); void FinishCompilation(); diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp index 55b2330e..73812383 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp @@ -157,8 +157,8 @@ RendererShaderVk* rectsEmulationGS_generate(LatteDecompilerShader* vertexShader, gsSrc.append("}\r\n"); - auto vkShader = new RendererShaderVk(RendererShader::ShaderType::kGeometry, 0, 0, false, false, gsSrc); - vkShader->PreponeCompilation(true); + auto vkShader = new RendererShaderVk(RendererShader::ShaderType::kGeometry, 0, 0, false, false, std::move(gsSrc)); + vkShader->PreponeCompilation(); return vkShader; } @@ -964,11 +964,11 @@ bool PipelineCompiler::Compile(bool forceCompile, bool isRenderThread, bool show { // if some shader stages are not compiled yet, compile them now if (m_vkVertexShader && m_vkVertexShader->IsCompiled() == false) - m_vkVertexShader->PreponeCompilation(isRenderThread); + m_vkVertexShader->PreponeCompilation(); if (m_vkPixelShader && m_vkPixelShader->IsCompiled() == false) - m_vkPixelShader->PreponeCompilation(isRenderThread); + m_vkPixelShader->PreponeCompilation(); if (m_vkGeometryShader && m_vkGeometryShader->IsCompiled() == false) - m_vkGeometryShader->PreponeCompilation(isRenderThread); + m_vkGeometryShader->PreponeCompilation(); } if (shaderStages.empty()) diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index d70cb065..0203e97e 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -1293,9 +1293,9 @@ VkDeviceCreateInfo VulkanRenderer::CreateDeviceCreateInfo(const std::vector buffer_genStrideWorkaroundVertexBuffer(MPTR buffer, uint32 size, uint32 oldStride); void buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) override; - RendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool isGameShader, bool isGfxPackShader) override; + RendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, std::string&& source, bool isGameShader, bool isGfxPackShader) override; IndexAllocation indexData_reserveIndexMemory(uint32 size) override; void indexData_releaseIndexMemory(IndexAllocation& allocation) override; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanSurfaceCopy.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanSurfaceCopy.cpp index e3e42012..f286f19f 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanSurfaceCopy.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanSurfaceCopy.cpp @@ -180,8 +180,8 @@ RendererShaderVk* _vkGenSurfaceCopyShader_vs() "}\r\n"; std::string shaderStr(vsShaderSrc); - auto vkShader = new RendererShaderVk(RendererShader::ShaderType::kVertex, 0, 0, false, false, shaderStr); - vkShader->PreponeCompilation(true); + auto vkShader = new RendererShaderVk(RendererShader::ShaderType::kVertex, 0, 0, false, false, std::move(shaderStr)); + vkShader->PreponeCompilation(); return vkShader; } @@ -198,8 +198,8 @@ RendererShaderVk* _vkGenSurfaceCopyShader_ps_colorToDepth() "}\r\n"; std::string shaderStr(psShaderSrc); - auto vkShader = new RendererShaderVk(RendererShader::ShaderType::kFragment, 0, 0, false, false, shaderStr); - vkShader->PreponeCompilation(true); + auto vkShader = new RendererShaderVk(RendererShader::ShaderType::kFragment, 0, 0, false, false, std::move(shaderStr)); + vkShader->PreponeCompilation(); return vkShader; } @@ -217,8 +217,8 @@ RendererShaderVk* _vkGenSurfaceCopyShader_ps_depthToColor() "}\r\n"; std::string shaderStr(psShaderSrc); - auto vkShader = new RendererShaderVk(RendererShader::ShaderType::kFragment, 0, 0, false, false, shaderStr); - vkShader->PreponeCompilation(true); + auto vkShader = new RendererShaderVk(RendererShader::ShaderType::kFragment, 0, 0, false, false, std::move(shaderStr)); + vkShader->PreponeCompilation(); return vkShader; }