From 17675ca418d94ffd9a245889a00b6eece47a2ce8 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 29 Nov 2015 09:49:12 -0800 Subject: [PATCH] Refactor to reuse more code. --- GPU/GLES/DepalettizeShader.cpp | 108 ++++------- GPU/GLES/DepalettizeShader.h | 21 +-- GPU/GLES/TextureCache.cpp | 329 ++++++++++++++------------------- 3 files changed, 180 insertions(+), 278 deletions(-) diff --git a/GPU/GLES/DepalettizeShader.cpp b/GPU/GLES/DepalettizeShader.cpp index c5db58a1a6cc..62df501226fd 100644 --- a/GPU/GLES/DepalettizeShader.cpp +++ b/GPU/GLES/DepalettizeShader.cpp @@ -193,25 +193,7 @@ void DepalShaderCache::Decimate() { } } -DepalShader *DepalShaderCache::GetDepalettizeShader(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat) { - u32 id = GenerateShaderID(clutFormat, pixelFormat); - - auto shader = cache_.find(id); - if (shader != cache_.end()) { - return shader->second; - } - - if (vertexShader_ == 0) { - if (!CreateVertexShader()) { - // The vertex shader failed, no need to bother trying the fragment. - return nullptr; - } - } - - char *buffer = new char[2048]; - - GenerateDepalShader(buffer, pixelFormat, useGL3_ ? GLSL_300 : GLSL_140); - +void DepalShaderCache::CreateFragShader(DepalShader *depal, char *buffer) { GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER); const char *buf = buffer; @@ -232,14 +214,14 @@ DepalShader *DepalShaderCache::GetDepalettizeShader(GEPaletteFormat clutFormat, GLint u_tex = glGetUniformLocation(program, "tex"); GLint u_pal = glGetUniformLocation(program, "pal"); + GLint u_offset = glGetUniformLocation(program, "u_offset"); glUniform1i(u_tex, 0); glUniform1i(u_pal, 3); - DepalShader *depal = new DepalShader(); depal->program = program; depal->fragShader = fragShader; - cache_[id] = depal; + depal->u_offset = u_offset; GLint linkStatus = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); @@ -267,15 +249,37 @@ DepalShader *DepalShaderCache::GetDepalettizeShader(GEPaletteFormat clutFormat, depal->a_position = glGetAttribLocation(program, "a_position"); depal->a_texcoord0 = glGetAttribLocation(program, "a_texcoord0"); } +} + +DepalShader *DepalShaderCache::GetDepalettizeShader(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat) { + u32 id = GenerateShaderID(clutFormat, pixelFormat); + + auto shader = cache_.find(id); + if (shader != cache_.end()) { + return shader->second; + } + + if (vertexShader_ == 0) { + if (!CreateVertexShader()) { + // The vertex shader failed, no need to bother trying the fragment. + return nullptr; + } + } + + char *buffer = new char[2048]; + GenerateDepalShader(buffer, pixelFormat, useGL3_ ? GLSL_300 : GLSL_140); + + DepalShader *depal = new DepalShader(); + CreateFragShader(depal, buffer); delete[] buffer; return depal->program ? depal : nullptr; } -IndexedShader *DepalShaderCache::GetIndexedShader() { +DepalShader *DepalShaderCache::GetIndexedShader() { if (indexedShader_.program != 0) { if (indexedShader_.program == -1) { - // Previously failed. + // Previously failed. Don't try again. return nullptr; } return &indexedShader_; @@ -291,62 +295,12 @@ IndexedShader *DepalShaderCache::GetIndexedShader() { char *buffer = new char[2048]; GenerateIndexedShader(buffer, useGL3_ ? GLSL_300 : GLSL_140); - GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER); - - const char *buf = buffer; - glShaderSource(fragShader, 1, &buf, 0); - glCompileShader(fragShader); - - CheckShaderCompileSuccess(fragShader, buffer); - - GLuint program = glCreateProgram(); - glAttachShader(program, vertexShader_); - glAttachShader(program, fragShader); - - glBindAttribLocation(program, 0, "a_position"); - glBindAttribLocation(program, 1, "a_texcoord0"); - - glLinkProgram(program); - glUseProgram(program); - - GLint u_tex = glGetUniformLocation(program, "tex"); - GLint u_pal = glGetUniformLocation(program, "pal"); - GLint u_offset = glGetUniformLocation(program, "u_offset"); - - glUniform1i(u_tex, 0); - glUniform1i(u_pal, 3); - - indexedShader_.program = program; - indexedShader_.fragShader = fragShader; - indexedShader_.u_offset = u_offset; - - GLint linkStatus = GL_FALSE; - glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); - if (linkStatus != GL_TRUE) { - GLint bufLength = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); - if (bufLength) { - char* errorbuf = new char[bufLength]; - glGetProgramInfoLog(program, bufLength, NULL, errorbuf); -#ifdef SHADERLOG - OutputDebugStringUTF8(buffer); - OutputDebugStringUTF8(errorbuf); -#endif - ERROR_LOG(G3D, "Could not link program:\n %s \n\n %s", errorbuf, buf); - delete[] errorbuf; // we're dead! - } - - // Since it failed, let's mark it in the cache so we don't keep retrying. - // That will only make it slower. + CreateFragShader(&indexedShader_, buffer); + if (indexedShader_.program == 0) { + // So that we know not to try again next time. indexedShader_.program = -1; - - // We will delete the shader later in Clear(). - glDeleteProgram(program); - } else { - indexedShader_.a_position = glGetAttribLocation(program, "a_position"); - indexedShader_.a_texcoord0 = glGetAttribLocation(program, "a_texcoord0"); } delete[] buffer; - return indexedShader_.program ? &indexedShader_ : nullptr; + return indexedShader_.program != 0 && indexedShader_.program != -1 ? &indexedShader_ : nullptr; } diff --git a/GPU/GLES/DepalettizeShader.h b/GPU/GLES/DepalettizeShader.h index 20e9f7ca8fd0..bd7c9d826b2a 100644 --- a/GPU/GLES/DepalettizeShader.h +++ b/GPU/GLES/DepalettizeShader.h @@ -23,10 +23,14 @@ class DepalShader { public: + DepalShader() : program(0), fragShader(0) { + } + GLuint program; GLuint fragShader; GLint a_position; GLint a_texcoord0; + GLint u_offset; }; class DepalTexture { @@ -35,18 +39,6 @@ class DepalTexture { int lastFrame; }; -class IndexedShader { -public: - IndexedShader() : program(0), fragShader(0) { - } - - GLuint program; - GLuint fragShader; - GLint a_position; - GLint a_texcoord0; - GLint u_offset; -}; - // Caches both shaders and palette textures. class DepalShaderCache { public: @@ -56,19 +48,20 @@ class DepalShaderCache { // This also uploads the palette and binds the correct texture. DepalShader *GetDepalettizeShader(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat); GLuint GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, u32 *rawClut); - IndexedShader *GetIndexedShader(); + DepalShader *GetIndexedShader(); void Clear(); void Decimate(); private: u32 GenerateShaderID(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat); bool CreateVertexShader(); + void CreateFragShader(DepalShader *depal, char *buffer); bool useGL3_; bool vertexShaderFailed_; GLuint vertexShader_; std::map cache_; std::map texCache_; - IndexedShader indexedShader_; + DepalShader indexedShader_; }; diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index f0a182dd969f..405f6de1b371 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -874,6 +874,125 @@ void TextureCache::ApplyTexture() { nextTexture_ = nullptr; } +class TextureShaderApplier { +public: + struct Pos { + Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) { + } + Pos() { + } + + float x; + float y; + float z; + }; + struct UV { + UV(float u_, float v_) : u(u_), v(v_) { + } + UV() { + } + + float u; + float v; + }; + + TextureShaderApplier(DepalShader *shader, float bufferW, float bufferH, int renderW, int renderH) + : shader_(shader), bufferW_(bufferW), bufferH_(bufferH), renderW_(renderW), renderH_(renderH) { + static const Pos pos[4] = { + {-1, -1, -1}, + { 1, -1, -1}, + { 1, 1, -1}, + {-1, 1, -1}, + }; + memcpy(pos_, pos, sizeof(pos_)); + + static const UV uv[4] = { + {0, 0}, + {1, 0}, + {1, 1}, + {0, 1}, + }; + memcpy(uv_, uv, sizeof(uv_)); + } + + void ApplyBounds(const KnownVertexBounds &bounds, u32 uoff, u32 voff) { + // If min is not < max, then we don't have values (wasn't set during decode.) + if (bounds.minV < bounds.maxV) { + const float invWidth = 1.0f / bufferW_; + const float invHeight = 1.0f / bufferH_; + // Inverse of half = double. + const float invHalfWidth = invWidth * 2.0f; + const float invHalfHeight = invHeight * 2.0f; + + const int u1 = bounds.minU + uoff; + const int v1 = bounds.minV + voff; + const int u2 = bounds.maxU + uoff; + const int v2 = bounds.maxV + voff; + + const float left = u1 * invHalfWidth - 1.0f; + const float right = u2 * invHalfWidth - 1.0f; + const float top = v1 * invHalfHeight - 1.0f; + const float bottom = v2 * invHalfHeight - 1.0f; + // Points are: BL, BR, TR, TL. + pos_[0] = Pos(left, bottom, -1.0f); + pos_[1] = Pos(right, bottom, -1.0f); + pos_[2] = Pos(right, top, -1.0f); + pos_[3] = Pos(left, top, -1.0f); + + // And also the UVs, same order. + const float uvleft = u1 * invWidth; + const float uvright = u2 * invWidth; + const float uvtop = v1 * invHeight; + const float uvbottom = v2 * invHeight; + uv_[0] = UV(uvleft, uvbottom); + uv_[1] = UV(uvright, uvbottom); + uv_[2] = UV(uvright, uvtop); + uv_[3] = UV(uvleft, uvtop); + } + } + + void Use() { + glUseProgram(shader_->program); + + // Restore will rebind all of the state below. + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glEnableVertexAttribArray(shader_->a_position); + glEnableVertexAttribArray(shader_->a_texcoord0); + } + + void Shade() { + static const GLubyte indices[4] = { 0, 1, 3, 2 }; + + glstate.blend.force(false); + glstate.colorMask.force(true, true, true, true); + glstate.scissorTest.force(false); + glstate.cullFace.force(false); + glstate.depthTest.force(false); + glstate.stencilTest.force(false); +#if !defined(USING_GLES2) + glstate.colorLogicOp.force(false); +#endif + glViewport(0, 0, renderW_, renderH_); + + glVertexAttribPointer(shader_->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos_); + glVertexAttribPointer(shader_->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, uv_); + glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices); + glDisableVertexAttribArray(shader_->a_position); + glDisableVertexAttribArray(shader_->a_texcoord0); + + glstate.Restore(); + } + +protected: + DepalShader *shader_; + Pos pos_[4]; + UV uv_[4]; + float bufferW_; + float bufferH_; + int renderW_; + int renderH_; +}; void TextureCache::ApplyIndexedTexture(TexCacheEntry *entry) { VirtualFramebuffer *clutVfb = nullptr; @@ -889,103 +1008,38 @@ void TextureCache::ApplyIndexedTexture(TexCacheEntry *entry) { return; } - IndexedShader *shader = depalShaderCache_->GetIndexedShader(); + DepalShader *shader = depalShaderCache_->GetIndexedShader(); if (!shader) { return; } - // TODO: Mipmaps. + // TODO: Mipmaps are theoretically possible, but not implemented. int w = 1 << ((entry->dim >> 0) & 0xf); int h = 1 << ((entry->dim >> 8) & 0xf); - FBO *depalFBO = framebufferManager_->GetTempFBO(w, h, FBO_8888); + FBO *depalFBO = framebufferManager_->GetTempFBO(w, h, FBO_8888); fbo_bind_as_render_target(depalFBO); - - struct Pos { - Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) { - } - float x; - float y; - float z; - }; - struct UV { - UV(float u_, float v_) : u(u_), v(v_) { - } - float u; - float v; - }; - - Pos pos[4] = { - {-1, -1, -1}, - { 1, -1, -1}, - { 1, 1, -1}, - {-1, 1, -1}, - }; - UV uv[4] = { - {0, 0}, - {1, 0}, - {1, 1}, - {0, 1}, - }; - static const GLubyte indices[4] = { 0, 1, 3, 2 }; - - // If min is not < max, then we don't have values (wasn't set during decode.) - if (gstate_c.vertBounds.minV < gstate_c.vertBounds.maxV) { - const float invWidth = 1.0f / (float)w; - const float invHeight = 1.0f / (float)h; - // Inverse of half = double. - const float invHalfWidth = invWidth * 2.0f; - const float invHalfHeight = invHeight * 2.0f; - - const int u1 = gstate_c.vertBounds.minU + gstate_c.curTextureXOffset; - const int v1 = gstate_c.vertBounds.minV + gstate_c.curTextureYOffset; - const int u2 = gstate_c.vertBounds.maxU + gstate_c.curTextureXOffset; - const int v2 = gstate_c.vertBounds.maxV + gstate_c.curTextureYOffset; - - const float left = u1 * invHalfWidth - 1.0f; - const float right = u2 * invHalfWidth - 1.0f; - const float top = v1 * invHalfHeight - 1.0f; - const float bottom = v2 * invHalfHeight - 1.0f; - // Points are: BL, BR, TR, TL. - pos[0] = Pos(left, bottom, -1.0f); - pos[1] = Pos(right, bottom, -1.0f); - pos[2] = Pos(right, top, -1.0f); - pos[3] = Pos(left, top, -1.0f); - - // And also the UVs, same order. - const float uvleft = u1 * invWidth; - const float uvright = u2 * invWidth; - const float uvtop = v1 * invHeight; - const float uvbottom = v2 * invHeight; - uv[0] = UV(uvleft, uvbottom); - uv[1] = UV(uvright, uvbottom); - uv[2] = UV(uvright, uvtop); - uv[3] = UV(uvleft, uvtop); - } - shaderManager_->DirtyLastShader(); - glUseProgram(shader->program); + TextureShaderApplier shaderApply(shader, w, h, w, h); + shaderApply.ApplyBounds(gstate_c.vertBounds, gstate_c.curTextureXOffset, gstate_c.curTextureYOffset); + shaderApply.Use(); - // Restore will rebind all of the state below. - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glEnableVertexAttribArray(shader->a_position); - glEnableVertexAttribArray(shader->a_texcoord0); - - float texel_offset = 0.5f / (float)clutVfb->bufferWidth; - if (gstate.getClutPaletteFormat() != GE_CMODE_32BIT_ABGR8888 && (gstate.getClutIndexStartPos() & 0x100) != 0) { - // In this case, we truncated the index entries. Apply the offset here. - if (clutVfb->renderWidth > 256) { - texel_offset += 256.0f / (float)clutVfb->renderWidth; + if (shader->u_offset != -1) { + float texel_offset = 0.5f / (float)clutVfb->bufferWidth; + if (gstate.getClutPaletteFormat() != GE_CMODE_32BIT_ABGR8888 && (gstate.getClutIndexStartPos() & 0x100) != 0) { + // In this case, we truncated the index entries. Apply the offset here. + if (clutVfb->renderWidth > 256) { + texel_offset += 256.0f / (float)clutVfb->renderWidth; + } } - } - // We scale by the width of the CLUT - to map 0.0 -> 0, 1.0 -> 255. - // If the width is 256, 255 is right (see offset above.) We aim for the texel centers. - float texel_mult = 255.0f / (float)clutVfb->bufferWidth; + // We scale by the width of the CLUT - to map 0.0 -> 0, 1.0 -> 255. + // If the width is 256, 255 is right (see offset above.) We aim for the texel centers. + float texel_mult = 255.0f / (float)clutVfb->bufferWidth; - glUniform2f(shader->u_offset, texel_mult, texel_offset); + glUniform2f(shader->u_offset, texel_mult, texel_offset); + } glActiveTexture(GL_TEXTURE3); fbo_bind_color_as_texture(clutVfb->fbo, 0); @@ -997,25 +1051,9 @@ void TextureCache::ApplyIndexedTexture(TexCacheEntry *entry) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glstate.blend.force(false); - glstate.colorMask.force(true, true, true, true); - glstate.scissorTest.force(false); - glstate.cullFace.force(false); - glstate.depthTest.force(false); - glstate.stencilTest.force(false); -#if !defined(USING_GLES2) - glstate.colorLogicOp.force(false); -#endif - glViewport(0, 0, w, h); - - glVertexAttribPointer(shader->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos); - glVertexAttribPointer(shader->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, uv); - glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices); - glDisableVertexAttribArray(shader->a_position); - glDisableVertexAttribArray(shader->a_texcoord0); + shaderApply.Shade(); fbo_bind_color_as_texture(depalFBO, 0); - glstate.Restore(); framebufferManager_->RebindFramebuffer(); SetFramebufferSamplingParams(w, h); @@ -1033,78 +1071,11 @@ void TextureCache::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuf GLuint clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_); FBO *depalFBO = framebufferManager_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, FBO_8888); fbo_bind_as_render_target(depalFBO); - - struct Pos { - Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) { - } - float x; - float y; - float z; - }; - struct UV { - UV(float u_, float v_) : u(u_), v(v_) { - } - float u; - float v; - }; - - Pos pos[4] = { - {-1, -1, -1}, - { 1, -1, -1}, - { 1, 1, -1}, - {-1, 1, -1}, - }; - UV uv[4] = { - {0, 0}, - {1, 0}, - {1, 1}, - {0, 1}, - }; - static const GLubyte indices[4] = { 0, 1, 3, 2 }; - - // If min is not < max, then we don't have values (wasn't set during decode.) - if (gstate_c.vertBounds.minV < gstate_c.vertBounds.maxV) { - const float invWidth = 1.0f / (float)framebuffer->bufferWidth; - const float invHeight = 1.0f / (float)framebuffer->bufferHeight; - // Inverse of half = double. - const float invHalfWidth = invWidth * 2.0f; - const float invHalfHeight = invHeight * 2.0f; - - const int u1 = gstate_c.vertBounds.minU + gstate_c.curTextureXOffset; - const int v1 = gstate_c.vertBounds.minV + gstate_c.curTextureYOffset; - const int u2 = gstate_c.vertBounds.maxU + gstate_c.curTextureXOffset; - const int v2 = gstate_c.vertBounds.maxV + gstate_c.curTextureYOffset; - - const float left = u1 * invHalfWidth - 1.0f; - const float right = u2 * invHalfWidth - 1.0f; - const float top = v1 * invHalfHeight - 1.0f; - const float bottom = v2 * invHalfHeight - 1.0f; - // Points are: BL, BR, TR, TL. - pos[0] = Pos(left, bottom, -1.0f); - pos[1] = Pos(right, bottom, -1.0f); - pos[2] = Pos(right, top, -1.0f); - pos[3] = Pos(left, top, -1.0f); - - // And also the UVs, same order. - const float uvleft = u1 * invWidth; - const float uvright = u2 * invWidth; - const float uvtop = v1 * invHeight; - const float uvbottom = v2 * invHeight; - uv[0] = UV(uvleft, uvbottom); - uv[1] = UV(uvright, uvbottom); - uv[2] = UV(uvright, uvtop); - uv[3] = UV(uvleft, uvtop); - } - shaderManager_->DirtyLastShader(); - glUseProgram(depal->program); - - // Restore will rebind all of the state below. - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glEnableVertexAttribArray(depal->a_position); - glEnableVertexAttribArray(depal->a_texcoord0); + TextureShaderApplier shaderApply(depal, framebuffer->bufferWidth, framebuffer->bufferHeight, framebuffer->renderWidth, framebuffer->renderHeight); + shaderApply.ApplyBounds(gstate_c.vertBounds, gstate_c.curTextureXOffset, gstate_c.curTextureYOffset); + shaderApply.Use(); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, clutTexture); @@ -1114,25 +1085,9 @@ void TextureCache::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuf glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glstate.blend.force(false); - glstate.colorMask.force(true, true, true, true); - glstate.scissorTest.force(false); - glstate.cullFace.force(false); - glstate.depthTest.force(false); - glstate.stencilTest.force(false); -#if !defined(USING_GLES2) - glstate.colorLogicOp.force(false); -#endif - glViewport(0, 0, framebuffer->renderWidth, framebuffer->renderHeight); - - glVertexAttribPointer(depal->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos); - glVertexAttribPointer(depal->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, uv); - glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices); - glDisableVertexAttribArray(depal->a_position); - glDisableVertexAttribArray(depal->a_texcoord0); + shaderApply.Shade(); fbo_bind_color_as_texture(depalFBO, 0); - glstate.Restore(); } else { framebufferManager_->BindFramebufferColor(GL_TEXTURE0, gstate.getFrameBufRawAddress(), framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); }