diff options
| author | degasus <wickmarkus@web.de> | 2013-02-13 13:12:19 +0100 |
|---|---|---|
| committer | degasus <wickmarkus@web.de> | 2013-02-13 13:12:19 +0100 |
| commit | bbc292c21000ee3532c1fb4e955dc03951a6e2f6 (patch) | |
| tree | cca6d4faae744494b38962eaabbf0879eb154928 /Source/Plugins/Plugin_VideoOGL/Src/ProgramShaderCache.cpp | |
| parent | 818a376bd4f13a8913c4d8726e2e5a6701beeee8 (diff) | |
merge Vertex and PixelShaderCache into ProgramShaderCache
this is the first step, uniform handling is still missing
Diffstat (limited to 'Source/Plugins/Plugin_VideoOGL/Src/ProgramShaderCache.cpp')
| -rw-r--r-- | Source/Plugins/Plugin_VideoOGL/Src/ProgramShaderCache.cpp | 334 |
1 files changed, 234 insertions, 100 deletions
diff --git a/Source/Plugins/Plugin_VideoOGL/Src/ProgramShaderCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/ProgramShaderCache.cpp index 5481f26541..fcffa175c6 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/ProgramShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/ProgramShaderCache.cpp @@ -18,37 +18,30 @@ #include "ProgramShaderCache.h" #include "MathUtil.h" #include "StreamBuffer.h" +#include "Debugger.h" +#include "Statistics.h" namespace OGL { static const u32 UBO_LENGTH = 4*1024*1024; -GLuint ProgramShaderCache::CurrentProgram = 0; +static GLuint CurrentProgram = 0; ProgramShaderCache::PCache ProgramShaderCache::pshaders; GLintptr ProgramShaderCache::s_vs_data_offset; u8 *ProgramShaderCache::s_ubo_buffer; u32 ProgramShaderCache::s_ubo_buffer_size; bool ProgramShaderCache::s_ubo_dirty; -LinearDiskCache<u64, u8> g_program_disk_cache; +LinearDiskCache<SHADERUID, u8> g_program_disk_cache; GLenum ProgramFormat; GLuint ProgramShaderCache::PCacheEntry::prog_format = 0; -u64 ProgramShaderCache::CurrentShaderProgram; - static StreamBuffer *s_buffer; -u64 Create_Pair(u32 key1, u32 key2) -{ - return (((u64)key1) << 32) | key2; -} -void Get_Pair(u64 key, u32 *key1, u32 *key2) -{ - *key1 = (key & 0xFFFFFFFF00000000) >> 32; - *key2 = key & 0xFFFFFFFF; -} +ProgramShaderCache::PCacheEntry* ProgramShaderCache::last_entry; +SHADERUID ProgramShaderCache::last_uid; const char *UniformNames[NUM_UNIFORMS] = { @@ -75,18 +68,21 @@ const char *UniformNames[NUM_UNIFORMS] = I_DEPTHPARAMS, }; -void ProgramShaderCache::SetProgramVariables(PCacheEntry &entry) +void SHADER::SetProgramVariables() { + // glsl shader must be bind to set samplers + Bind(); + // Bind UBO if (g_ActiveConfig.backend_info.bSupportsGLSLUBO) { - GLint PSBlock_id = glGetUniformBlockIndex(entry.prog_id, "PSBlock"); - GLint VSBlock_id = glGetUniformBlockIndex(entry.prog_id, "VSBlock"); + GLint PSBlock_id = glGetUniformBlockIndex(glprogid, "PSBlock"); + GLint VSBlock_id = glGetUniformBlockIndex(glprogid, "VSBlock"); if(PSBlock_id != -1) - glUniformBlockBinding(entry.prog_id, PSBlock_id, 1); + glUniformBlockBinding(glprogid, PSBlock_id, 1); if(VSBlock_id != -1) - glUniformBlockBinding(entry.prog_id, VSBlock_id, 2); + glUniformBlockBinding(glprogid, VSBlock_id, 2); } // We cache our uniform locations for now @@ -94,12 +90,12 @@ void ProgramShaderCache::SetProgramVariables(PCacheEntry &entry) // We can remove this // (Sonicadvance): For some reason this fails on my hardware - //glGetUniformIndices(entry.prog_id, NUM_UNIFORMS, UniformNames, entry.UniformLocations); + //glGetUniformIndices(glprogid, NUM_UNIFORMS, UniformNames, UniformLocations); // Got to do it this crappy way. - entry.UniformLocations[0] = glGetUniformLocation(entry.prog_id, UniformNames[0]); + UniformLocations[0] = glGetUniformLocation(glprogid, UniformNames[0]); if (!g_ActiveConfig.backend_info.bSupportsGLSLUBO) for (int a = 1; a < NUM_UNIFORMS; ++a) - entry.UniformLocations[a] = glGetUniformLocation(entry.prog_id, UniformNames[a]); + UniformLocations[a] = glGetUniformLocation(glprogid, UniformNames[a]); // Bind Texture Sampler for (int a = 0; a <= 9; ++a) @@ -108,165 +104,284 @@ void ProgramShaderCache::SetProgramVariables(PCacheEntry &entry) snprintf(name, 8, "samp%d", a); // Still need to get sampler locations since we aren't binding them statically in the shaders - int loc = glGetUniformLocation(entry.prog_id, name); + int loc = glGetUniformLocation(glprogid, name); if (loc != -1) glUniform1i(loc, a); } } -void ProgramShaderCache::SetProgramBindings ( ProgramShaderCache::PCacheEntry& entry ) +void SHADER::SetProgramBindings() { if (g_ActiveConfig.backend_info.bSupportsDualSourceBlend) { // So we do support extended blending // So we need to set a few more things here. // Bind our out locations - glBindFragDataLocationIndexed(entry.prog_id, 0, 0, "ocol0"); - glBindFragDataLocationIndexed(entry.prog_id, 0, 1, "ocol1"); + glBindFragDataLocationIndexed(glprogid, 0, 0, "ocol0"); + glBindFragDataLocationIndexed(glprogid, 0, 1, "ocol1"); } else - glBindFragDataLocation(entry.prog_id, 0, "ocol0"); + glBindFragDataLocation(glprogid, 0, "ocol0"); // Need to set some attribute locations - glBindAttribLocation(entry.prog_id, SHADER_POSITION_ATTRIB, "rawpos"); + glBindAttribLocation(glprogid, SHADER_POSITION_ATTRIB, "rawpos"); - glBindAttribLocation(entry.prog_id, SHADER_POSMTX_ATTRIB, "fposmtx"); + glBindAttribLocation(glprogid, SHADER_POSMTX_ATTRIB, "fposmtx"); - glBindAttribLocation(entry.prog_id, SHADER_COLOR0_ATTRIB, "color0"); - glBindAttribLocation(entry.prog_id, SHADER_COLOR1_ATTRIB, "color1"); + glBindAttribLocation(glprogid, SHADER_COLOR0_ATTRIB, "color0"); + glBindAttribLocation(glprogid, SHADER_COLOR1_ATTRIB, "color1"); - glBindAttribLocation(entry.prog_id, SHADER_NORM0_ATTRIB, "rawnorm0"); - glBindAttribLocation(entry.prog_id, SHADER_NORM1_ATTRIB, "rawnorm1"); - glBindAttribLocation(entry.prog_id, SHADER_NORM2_ATTRIB, "rawnorm2"); + glBindAttribLocation(glprogid, SHADER_NORM0_ATTRIB, "rawnorm0"); + glBindAttribLocation(glprogid, SHADER_NORM1_ATTRIB, "rawnorm1"); + glBindAttribLocation(glprogid, SHADER_NORM2_ATTRIB, "rawnorm2"); for(int i=0; i<8; i++) { char attrib_name[8]; snprintf(attrib_name, 8, "tex%d", i); - glBindAttribLocation(entry.prog_id, SHADER_TEXTURE0_ATTRIB+i, attrib_name); + glBindAttribLocation(glprogid, SHADER_TEXTURE0_ATTRIB+i, attrib_name); } } +void SHADER::Bind() +{ + if(CurrentProgram != glprogid) + { + glUseProgram(glprogid); + CurrentProgram = glprogid; + } +} + + +void ProgramShaderCache::SetMultiPSConstant4fv(unsigned int offset, const float *f, unsigned int count) +{ + s_ubo_dirty = true; + memcpy(s_ubo_buffer+(offset*4*sizeof(float)), f, count*4*sizeof(float)); +} + +void ProgramShaderCache::SetMultiVSConstant4fv(unsigned int offset, const float *f, unsigned int count) +{ + s_ubo_dirty = true; + memcpy(s_ubo_buffer+(offset*4*sizeof(float))+s_vs_data_offset, f, count*4*sizeof(float)); +} -void ProgramShaderCache::SetBothShaders(GLuint PS, GLuint VS) +void ProgramShaderCache::UploadConstants() { - if(!PS || !VS) { - ERROR_LOG(VIDEO, "tried to bind a zero shader"); - return; + if(s_ubo_dirty) { + s_buffer->Alloc(s_ubo_buffer_size); + size_t offset = s_buffer->Upload(s_ubo_buffer, s_ubo_buffer_size); + glBindBufferRange(GL_UNIFORM_BUFFER, 1, s_buffer->getBuffer(), offset, s_vs_data_offset); + glBindBufferRange(GL_UNIFORM_BUFFER, 2, s_buffer->getBuffer(), offset + s_vs_data_offset, s_ubo_buffer_size - s_vs_data_offset); + s_ubo_dirty = false; } +} + +GLuint ProgramShaderCache::GetCurrentProgram(void) +{ + return CurrentProgram; +} + +SHADER* ProgramShaderCache::SetShader ( DSTALPHA_MODE dstAlphaMode, u32 components ) +{ + SHADERUID uid; + GetShaderId(&uid, dstAlphaMode, components); - u64 ShaderPair = Create_Pair(PS, VS); + // Check if the shader is already set + if (last_entry) + { + if (uid == last_uid) + { + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + ValidateShaderIDs(last_entry, dstAlphaMode, components); + last_entry->shader.Bind(); + return &last_entry->shader; + } + } - // program is already bound - if(ShaderPair == CurrentShaderProgram) return; + last_uid = uid; - PCache::iterator iter = pshaders.find(ShaderPair); + // Check if shader is already in cache + PCache::iterator iter = pshaders.find(uid); if (iter != pshaders.end()) { - PCacheEntry &entry = iter->second; - glUseProgram(entry.prog_id); - CurrentProgram = entry.prog_id; - CurrentShaderProgram = ShaderPair; - return; + PCacheEntry *entry = &iter->second; + last_entry = entry; + + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + ValidateShaderIDs(entry, dstAlphaMode, components); + last_entry->shader.Bind(); + return &last_entry->shader; + } + + // Make an entry in the table + PCacheEntry& newentry = pshaders[uid]; + last_entry = &newentry; + + const char *vcode = GenerateVertexShaderCode(components, API_OPENGL); + const char *pcode = GeneratePixelShaderCode(dstAlphaMode, API_OPENGL, components); + + if (g_ActiveConfig.bEnableShaderDebugging) + { + GetSafePixelShaderId(&newentry.safe_uid, dstAlphaMode, components); + newentry.shader.strvprog = vcode; + newentry.shader.strpprog = pcode; } - PCacheEntry entry; - entry.Create(PS, VS); +#if defined(_DEBUG) || defined(DEBUGFAST) + if (g_ActiveConfig.iLog & CONF_SAVESHADERS) { + static int counter = 0; + char szTemp[MAX_PATH]; + sprintf(szTemp, "%svs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); + SaveData(szTemp, vcode); + sprintf(szTemp, "%sps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); + SaveData(szTemp, pcode); + } +#endif - // Right, the program is created now - // Let's attach everything - glAttachShader(entry.prog_id, entry.vsid); - glAttachShader(entry.prog_id, entry.psid); + if (!CompileShader(newentry.shader, vcode, pcode)) { + GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); + return NULL; + } + + INCSTAT(stats.numPixelShadersCreated); + SETSTAT(stats.numPixelShadersAlive, pshaders.size()); + GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); + + last_entry->shader.Bind(); + return &last_entry->shader; +} + +bool ProgramShaderCache::CompileShader ( SHADER& shader, const char* vcode, const char* pcode ) +{ + GLuint vsid = CompileSingleShader(GL_VERTEX_SHADER, vcode); + GLuint psid = CompileSingleShader(GL_FRAGMENT_SHADER, pcode); + + if(!vsid || !psid) + { + glDeleteShader(vsid); + glDeleteShader(psid); + return false; + } + + GLuint pid = shader.glprogid = glCreateProgram();; + + glAttachShader(pid, vsid); + glAttachShader(pid, psid); if (g_ActiveConfig.backend_info.bSupportsGLSLCache) - glProgramParameteri(entry.prog_id, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); + glProgramParameteri(pid, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); - SetProgramBindings(entry); + shader.SetProgramBindings(); - glLinkProgram(entry.prog_id); + glLinkProgram(pid); + + // original shaders aren't needed any more + glDeleteShader(vsid); + glDeleteShader(psid); #if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL) GLsizei length = 0; - glGetProgramiv(entry.prog_id, GL_INFO_LOG_LENGTH, &length); + glGetProgramiv(pid, GL_INFO_LOG_LENGTH, &length); if (length > 1) { GLsizei charsWritten; GLchar* infoLog = new GLchar[length]; - glGetProgramInfoLog(entry.prog_id, length, &charsWritten, infoLog); + glGetProgramInfoLog(pid, length, &charsWritten, infoLog); ERROR_LOG(VIDEO, "Program info log:\n%s", infoLog); char szTemp[MAX_PATH]; - sprintf(szTemp, "p_%d.txt", entry.prog_id); + sprintf(szTemp, "p_%d.txt", pid); FILE *fp = fopen(szTemp, "wb"); fwrite(infoLog, length, 1, fp); delete[] infoLog; - - glGetShaderiv(VS, GL_SHADER_SOURCE_LENGTH, &length); - GLchar* src = new GLchar[length]; - glGetShaderSource(VS, length, &charsWritten, src); - fwrite(src, strlen(src), 1, fp); - delete [] src; - - glGetShaderiv(PS, GL_SHADER_SOURCE_LENGTH, &length); - src = new GLchar[length]; - glGetShaderSource(PS, length, &charsWritten, src); - fwrite(src, strlen(src), 1, fp); - delete [] src; + fwrite(vcode, strlen(vcode), 1, fp); + fwrite(pcode, strlen(pcode), 1, fp); fclose(fp); } GLint linkStatus; - glGetProgramiv(entry.prog_id, GL_LINK_STATUS, &linkStatus); + glGetProgramiv(pid, GL_LINK_STATUS, &linkStatus); if (linkStatus != GL_TRUE) { // Compile failed ERROR_LOG(VIDEO, "Program linking failed; see info log"); // Don't try to use this shader - glDeleteProgram(entry.prog_id); - return; + glDeleteProgram(pid); + return false; } #endif - glUseProgram(entry.prog_id); - - SetProgramVariables(entry); - - pshaders[ShaderPair] = entry; - CurrentShaderProgram = ShaderPair; - CurrentProgram = entry.prog_id; + shader.SetProgramVariables(); + + return true; } -void ProgramShaderCache::SetMultiPSConstant4fv(unsigned int offset, const float *f, unsigned int count) +GLuint ProgramShaderCache::CompileSingleShader (GLuint type, const char* code ) { - s_ubo_dirty = true; - memcpy(s_ubo_buffer+(offset*4*sizeof(float)), f, count*4*sizeof(float)); + GLuint result = glCreateShader(type); + + const char *src[] = {code}; + + glShaderSource(result, 1, src, NULL); + glCompileShader(result); +#if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL) + GLsizei length = 0; + glGetShaderiv(result, GL_INFO_LOG_LENGTH, &length); + if (length > 1) + { + GLsizei charsWritten; + GLchar* infoLog = new GLchar[length]; + glGetShaderInfoLog(result, length, &charsWritten, infoLog); + ERROR_LOG(VIDEO, "PS Shader info log:\n%s", infoLog); + char szTemp[MAX_PATH]; + sprintf(szTemp, "ps_%d.txt", result); + FILE *fp = fopen(szTemp, "wb"); + fwrite(infoLog, strlen(infoLog), 1, fp); + fwrite(code, strlen(code), 1, fp); + fclose(fp); + delete[] infoLog; + } + + GLint compileStatus; + glGetShaderiv(result, GL_COMPILE_STATUS, &compileStatus); + if (compileStatus != GL_TRUE) + { + // Compile failed + ERROR_LOG(VIDEO, "Shader compilation failed; see info log"); + + // Don't try to use this shader + glDeleteShader(result); + return 0; + } +#endif + (void)GL_REPORT_ERROR(); + return result; } -void ProgramShaderCache::SetMultiVSConstant4fv(unsigned int offset, const float *f, unsigned int count) + + +void ProgramShaderCache::GetShaderId ( SHADERUID* uid, DSTALPHA_MODE dstAlphaMode, u32 components ) { - s_ubo_dirty = true; - memcpy(s_ubo_buffer+(offset*4*sizeof(float))+s_vs_data_offset, f, count*4*sizeof(float)); + GetPixelShaderId(&uid->puid, dstAlphaMode, components); + GetVertexShaderId(&uid->vuid, components); } -void ProgramShaderCache::UploadConstants() +void ProgramShaderCache::GetSafeShaderId ( SHADERUIDSAFE* uid, DSTALPHA_MODE dstAlphaMode, u32 components ) { - if(s_ubo_dirty) { - s_buffer->Alloc(s_ubo_buffer_size); - size_t offset = s_buffer->Upload(s_ubo_buffer, s_ubo_buffer_size); - glBindBufferRange(GL_UNIFORM_BUFFER, 1, s_buffer->getBuffer(), offset, s_vs_data_offset); - glBindBufferRange(GL_UNIFORM_BUFFER, 2, s_buffer->getBuffer(), offset + s_vs_data_offset, s_ubo_buffer_size - s_vs_data_offset); - s_ubo_dirty = false; - } + GetSafePixelShaderId(&uid->puid, dstAlphaMode, components); + GetSafeVertexShaderId(&uid->vuid, components); } -GLuint ProgramShaderCache::GetCurrentProgram(void) +void ProgramShaderCache::ValidateShaderIDs ( PCacheEntry *entry, DSTALPHA_MODE dstAlphaMode, u32 components ) { - return CurrentProgram; + //ValidatePixelShaderIDs(API_OPENGL, entry->safe_uid, entry->shader.strprog, dstAlphaMode, components); } + + ProgramShaderCache::PCacheEntry ProgramShaderCache::GetShaderProgram(void) { - return pshaders[CurrentShaderProgram]; + return *last_entry; } void ProgramShaderCache::Init(void) @@ -308,7 +423,7 @@ void ProgramShaderCache::Init(void) } CurrentProgram = 0; - CurrentShaderProgram = 0; + last_entry = NULL; } void ProgramShaderCache::Shutdown(void) @@ -318,7 +433,7 @@ void ProgramShaderCache::Shutdown(void) PCache::iterator iter = pshaders.begin(); for (; iter != pshaders.end(); ++iter) { - g_program_disk_cache.Append(iter->second.uid, iter->second.GetProgram(), iter->second.Size()); + g_program_disk_cache.Append(iter->first, iter->second.GetProgram(), iter->second.Size()); iter->second.FreeProgram(); } @@ -342,4 +457,23 @@ void ProgramShaderCache::Shutdown(void) } } +void ProgramShaderCache::ProgramShaderCacheInserter::Read ( const SHADERUID& key, const u8* value, u32 value_size ) +{ + // The two shaders might not even exist anymore + // But it is fine, no need to worry about that + PCacheEntry entry; + entry.shader.glprogid = glCreateProgram(); + glProgramBinary(entry.shader.glprogid, entry.prog_format, value, value_size); + + GLint success; + glGetProgramiv(entry.shader.glprogid, GL_LINK_STATUS, &success); + + if (success) + { + pshaders[key] = entry; + entry.shader.SetProgramVariables(); + } +} + + } // namespace OGL |
