From f2f0355d940bf261dc5c31bc0020e4931da98e45 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 24 Mar 2014 10:55:07 +0100 Subject: [PATCH] Split up ApplyShader into ApplyVertexShader and ApplyFragmentShader. Will allow the alphatest avoiding optimization later. --- GPU/GLES/ShaderManager.cpp | 29 ++++++++++++++++++----------- GPU/GLES/ShaderManager.h | 12 +++++++++++- GPU/GLES/TransformPipeline.cpp | 7 +++++-- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/GPU/GLES/ShaderManager.cpp b/GPU/GLES/ShaderManager.cpp index b3924e2b8f..d6010ca4fc 100644 --- a/GPU/GLES/ShaderManager.cpp +++ b/GPU/GLES/ShaderManager.cpp @@ -82,7 +82,7 @@ Shader::~Shader() { LinkedShader::LinkedShader(Shader *vs, Shader *fs, u32 vertType, bool useHWTransform, LinkedShader *previous) : useHWTransform_(useHWTransform), program(0), dirtyUniforms(0) { program = glCreateProgram(); - + vs_ = vs; glAttachShader(program, vs->shader); glAttachShader(program, fs->shader); @@ -605,8 +605,7 @@ void ShaderManager::DirtyLastShader() { // disables vertex arrays lastShader_ = 0; } - -LinkedShader *ShaderManager::ApplyShader(int prim, u32 vertType) { +Shader *ShaderManager::ApplyVertexShader(int prim, u32 vertType) { // This doesn't work - we miss some events that really do need to dirty the prescale. // like changing the texmapmode. // if (g_Config.bPrescaleUV) @@ -622,18 +621,20 @@ LinkedShader *ShaderManager::ApplyShader(int prim, u32 vertType) { bool useHWTransform = CanUseHardwareTransform(prim); VertexShaderID VSID; - FragmentShaderID FSID; ComputeVertexShaderID(&VSID, vertType, prim, useHWTransform); - ComputeFragmentShaderID(&FSID); + ComputeFragmentShaderID(&FSID_); // Just update uniforms if this is the same shader as last time. - if (lastShader_ != 0 && VSID == lastVSID_ && FSID == lastFSID_) { + if (lastShader_ != 0 && VSID == lastVSID_ && FSID_ == lastFSID_) { lastShader_->UpdateUniforms(vertType); - return lastShader_; // Already all set. + lastShaderSame_ = true; + return lastShader_->vs_; // Already all set. + } else { + lastShaderSame_ = false; } lastVSID_ = VSID; - lastFSID_ = FSID; + lastFSID_ = FSID_; VSCache::iterator vsIter = vsCache_.find(VSID); Shader *vs; @@ -660,14 +661,20 @@ LinkedShader *ShaderManager::ApplyShader(int prim, u32 vertType) { } else { vs = vsIter->second; } + return vs; +} - FSCache::iterator fsIter = fsCache_.find(FSID); +LinkedShader *ShaderManager::ApplyFragmentShader(Shader *vs, int prim, u32 vertType) { + if (lastShaderSame_) + return lastShader_; + + FSCache::iterator fsIter = fsCache_.find(FSID_); Shader *fs; if (fsIter == fsCache_.end()) { // Fragment shader not in cache. Let's compile it. GenerateFragmentShader(codeBuffer_); - fs = new Shader(codeBuffer_, GL_FRAGMENT_SHADER, useHWTransform); - fsCache_[FSID] = fs; + fs = new Shader(codeBuffer_, GL_FRAGMENT_SHADER, vs->UseHWTransform()); + fsCache_[FSID_] = fs; } else { fs = fsIter->second; } diff --git a/GPU/GLES/ShaderManager.h b/GPU/GLES/ShaderManager.h index 9c18a12516..2a7bba13c3 100644 --- a/GPU/GLES/ShaderManager.h +++ b/GPU/GLES/ShaderManager.h @@ -47,6 +47,7 @@ public: void stop(); void UpdateUniforms(u32 vertType); + Shader *vs_; // Set to false if the VS failed, happens on Mali-400 a lot for complex shaders. bool useHWTransform_; @@ -167,7 +168,12 @@ public: ~ShaderManager(); void ClearCache(bool deleteThem); // TODO: deleteThem currently not respected - LinkedShader *ApplyShader(int prim, u32 vertType); + + // This is the old ApplyShader split into two parts, because of annoying information dependencies. + // If you call ApplyVertexShader, you MUST call ApplyFragmentShader soon afterwards. + Shader *ApplyVertexShader(int prim, u32 vertType); + LinkedShader *ApplyFragmentShader(Shader *vs, int prim, u32 vertType); + void DirtyShader(); void DirtyUniform(u32 what) { globalDirty_ |= what; @@ -192,6 +198,10 @@ private: typedef std::vector LinkedShaderCache; LinkedShaderCache linkedShaderCache_; + + FragmentShaderID FSID_; + bool lastShaderSame_; + FragmentShaderID lastFSID_; VertexShaderID lastVSID_; diff --git a/GPU/GLES/TransformPipeline.cpp b/GPU/GLES/TransformPipeline.cpp index ab2174aefd..0b01d00a3a 100644 --- a/GPU/GLES/TransformPipeline.cpp +++ b/GPU/GLES/TransformPipeline.cpp @@ -526,12 +526,12 @@ void TransformDrawEngine::DoFlush() { GEPrimitiveType prim = prevPrim_; ApplyDrawState(prim); - LinkedShader *program = shaderManager_->ApplyShader(prim, lastVType_); + Shader *vshader = shaderManager_->ApplyVertexShader(prim, lastVType_); // Compiler warns about this because it's only used in the #ifdeffed out RangeElements path. int maxIndex = 0; - if (program->useHWTransform_) { + if (vshader->UseHWTransform()) { GLuint vbo = 0, ebo = 0; int vertexCount = 0; bool useElements = true; @@ -699,7 +699,9 @@ rotateVBO: VERBOSE_LOG(G3D, "Flush prim %i! %i verts in one go", prim, vertexCount); + LinkedShader *program = shaderManager_->ApplyFragmentShader(vshader, prim, lastVType_); SetupDecFmtForDraw(program, dec_->GetDecVtxFmt(), vbo ? 0 : decoded); + if (useElements) { #if 1 // USING_GLES2 glDrawElements(glprim[prim], vertexCount, GL_UNSIGNED_SHORT, ebo ? 0 : (GLvoid*)decIndex); @@ -715,6 +717,7 @@ rotateVBO: glBindBuffer(GL_ARRAY_BUFFER, 0); } else { DecodeVerts(); + LinkedShader *program = shaderManager_->ApplyFragmentShader(vshader, prim, lastVType_); gpuStats.numUncachedVertsDrawn += indexGen.VertexCount(); prim = indexGen.Prim(); // Undo the strip optimization, not supported by the SW code yet.