diff --git a/Common/GPU/OpenGL/GLQueueRunner.cpp b/Common/GPU/OpenGL/GLQueueRunner.cpp index 34836c08a0f6..d81688189a29 100644 --- a/Common/GPU/OpenGL/GLQueueRunner.cpp +++ b/Common/GPU/OpenGL/GLQueueRunner.cpp @@ -438,11 +438,6 @@ void GLQueueRunner::InitCreateFramebuffer(const GLRInitStep &step) { tex.wrapT = GL_CLAMP_TO_EDGE; tex.magFilter = linear ? GL_LINEAR : GL_NEAREST; tex.minFilter = linear ? GL_LINEAR : GL_NEAREST; - if (gl_extensions.OES_texture_npot) { - tex.canWrap = true; - } else { - tex.canWrap = isPowerOf2(fbo->width) && isPowerOf2(fbo->height); - } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, tex.wrapS); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tex.wrapT); diff --git a/Common/GPU/OpenGL/GLRenderManager.cpp b/Common/GPU/OpenGL/GLRenderManager.cpp index 7764adfde8ba..97f5bcb0a67f 100644 --- a/Common/GPU/OpenGL/GLRenderManager.cpp +++ b/Common/GPU/OpenGL/GLRenderManager.cpp @@ -5,6 +5,7 @@ #include "Common/Log.h" #include "Common/MemoryUtil.h" +#include "Common/Math/math_util.h" #if 0 // def _DEBUG #define VLOG(...) INFO_LOG(G3D, __VA_ARGS__) @@ -19,6 +20,23 @@ static bool OnRenderThread() { } #endif +GLRTexture::GLRTexture(int width, int height, int numMips) { + if (gl_extensions.OES_texture_npot) { + canWrap = true; + } else { + canWrap = isPowerOf2(width) && isPowerOf2(height); + } + w = width; + h = height; + this->numMips = numMips; +} + +GLRTexture::~GLRTexture() { + if (texture) { + glDeleteTextures(1, &texture); + } +} + void GLDeleter::Take(GLDeleter &other) { _assert_msg_(IsEmpty(), "Deleter already has stuff"); shaders = std::move(other.shaders); diff --git a/Common/GPU/OpenGL/GLRenderManager.h b/Common/GPU/OpenGL/GLRenderManager.h index eca7204de2bf..fc774aa1c98e 100644 --- a/Common/GPU/OpenGL/GLRenderManager.h +++ b/Common/GPU/OpenGL/GLRenderManager.h @@ -23,13 +23,12 @@ class DrawContext; class GLRTexture { public: - ~GLRTexture() { - if (texture) { - glDeleteTextures(1, &texture); - } - } + GLRTexture(int width, int height, int numMips); + ~GLRTexture(); GLuint texture = 0; + uint16_t w; + uint16_t h; // We don't trust OpenGL defaults - setting wildly off values ensures that we'll end up overwriting these parameters. GLenum target = 0xFFFF; @@ -37,6 +36,7 @@ class GLRTexture { GLenum wrapT = 0xFFFF; GLenum magFilter = 0xFFFF; GLenum minFilter = 0xFFFF; + uint8_t numMips = 0; bool canWrap = true; float anisotropy = -100000.0f; float minLod = -1000.0f; @@ -47,7 +47,8 @@ class GLRTexture { class GLRFramebuffer { public: GLRFramebuffer(int _width, int _height, bool z_stencil) - : width(_width), height(_height), z_stencil_(z_stencil) { + : width(_width), height(_height), z_stencil_(z_stencil), + color_texture(_width, _height, 1), z_stencil_texture(_width, _height, 1) { } ~GLRFramebuffer(); @@ -378,9 +379,11 @@ class GLRenderManager { void WaitUntilQueueIdle(); // Creation commands. These were not needed in Vulkan since there we can do that on the main thread. - GLRTexture *CreateTexture(GLenum target) { + // We pass in width/height here even though it's not strictly needed until we support glTextureStorage + // and then we'll also need formats and stuff. + GLRTexture *CreateTexture(GLenum target, int width, int height, int numMips) { GLRInitStep step{ GLRInitStepType::CREATE_TEXTURE }; - step.create_texture.texture = new GLRTexture(); + step.create_texture.texture = new GLRTexture(width, height, numMips); step.create_texture.texture->target = target; initSteps_.push_back(step); return step.create_texture.texture; diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 4e7067164fc8..6695ae7728c6 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -386,7 +386,7 @@ class OpenGLContext : public DrawContext { void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override; void BindSamplerStates(int start, int count, SamplerState **states) override { - if (start + count >= MAX_TEXTURE_SLOTS) { + if (start + count > MAX_TEXTURE_SLOTS) { return; } for (int i = 0; i < count; i++) { @@ -497,7 +497,9 @@ class OpenGLContext : public DrawContext { // Bound state OpenGLSamplerState *boundSamplers_[MAX_TEXTURE_SLOTS]{}; - OpenGLTexture *boundTextures_[MAX_TEXTURE_SLOTS]{}; + // Point to GLRTexture directly because they can point to the textures + // in framebuffers too (which also can be bound). + const GLRTexture *boundTextures_[MAX_TEXTURE_SLOTS]{}; OpenGLPipeline *curPipeline_ = nullptr; OpenGLBuffer *curVBuffers_[4]{}; @@ -739,9 +741,7 @@ class OpenGLTexture : public Texture { bool HasMips() const { return mipLevels_ > 1 || generatedMips_; } - bool CanWrap() const { - return canWrap_; - } + TextureType GetType() const { return type_; } void Bind(int stage) { render_->BindTexture(stage, tex_); @@ -749,6 +749,9 @@ class OpenGLTexture : public Texture { int NumMipmaps() const { return mipLevels_; } + const GLRTexture *GetTex() const { + return tex_; + } private: void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data, TextureCallback callback); @@ -760,7 +763,6 @@ class OpenGLTexture : public Texture { TextureType type_; int mipLevels_; bool generatedMips_; - bool canWrap_; }; OpenGLTexture::OpenGLTexture(GLRenderManager *render, const TextureDesc &desc) : render_(render) { @@ -771,9 +773,8 @@ OpenGLTexture::OpenGLTexture(GLRenderManager *render, const TextureDesc &desc) : format_ = desc.format; type_ = desc.type; GLenum target = TypeToTarget(desc.type); - tex_ = render->CreateTexture(target); + tex_ = render->CreateTexture(target, desc.width, desc.height, desc.mipLevels); - canWrap_ = isPowerOf2(width_) && isPowerOf2(height_); mipLevels_ = desc.mipLevels; if (desc.initData.empty()) return; @@ -1091,7 +1092,7 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc) { } void OpenGLContext::BindTextures(int start, int count, Texture **textures) { - if (start + count >= MAX_TEXTURE_SLOTS) { + if (start + count > MAX_TEXTURE_SLOTS) { return; } for (int i = start; i < start + count; i++) { @@ -1102,14 +1103,14 @@ void OpenGLContext::BindTextures(int start, int count, Texture **textures) { continue; } glTex->Bind(i); - boundTextures_[i] = glTex; + boundTextures_[i] = glTex->GetTex(); } } void OpenGLContext::ApplySamplers() { for (int i = 0; i < MAX_TEXTURE_SLOTS; i++) { const OpenGLSamplerState *samp = boundSamplers_[i]; - const OpenGLTexture *tex = boundTextures_[i]; + const GLRTexture *tex = boundTextures_[i]; if (tex) { _assert_(samp); } else { @@ -1117,7 +1118,7 @@ void OpenGLContext::ApplySamplers() { } GLenum wrapS; GLenum wrapT; - if (tex->CanWrap()) { + if (tex->canWrap) { wrapS = samp->wrapU; wrapT = samp->wrapV; } else { @@ -1125,9 +1126,9 @@ void OpenGLContext::ApplySamplers() { wrapT = GL_CLAMP_TO_EDGE; } GLenum magFilt = samp->magFilt; - GLenum minFilt = tex->HasMips() ? samp->mipMinFilt : samp->minFilt; + GLenum minFilt = tex->numMips > 1 ? samp->mipMinFilt : samp->minFilt; renderManager_.SetTextureSampler(i, wrapS, wrapT, magFilt, minFilt, 0.0f); - renderManager_.SetTextureLod(i, 0.0, (float)(tex->NumMipmaps() - 1), 0.0); + renderManager_.SetTextureLod(i, 0.0, (float)(tex->numMips - 1), 0.0); } } @@ -1376,12 +1377,18 @@ void OpenGLContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBCh OpenGLFramebuffer *fb = (OpenGLFramebuffer *)fbo; GLuint aspect = 0; - if (channelBit & FB_COLOR_BIT) + if (channelBit & FB_COLOR_BIT) { aspect |= GL_COLOR_BUFFER_BIT; - if (channelBit & FB_DEPTH_BIT) + boundTextures_[binding] = &fb->framebuffer_->color_texture; + } + if (channelBit & FB_DEPTH_BIT) { aspect |= GL_DEPTH_BUFFER_BIT; - if (channelBit & FB_STENCIL_BIT) + boundTextures_[binding] = &fb->framebuffer_->z_stencil_texture; + } + if (channelBit & FB_STENCIL_BIT) { aspect |= GL_STENCIL_BUFFER_BIT; + boundTextures_[binding] = &fb->framebuffer_->z_stencil_texture; + } renderManager_.BindFramebufferAsTexture(fb->framebuffer_, binding, aspect, color); } diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index b96f96b42e91..45cee9199c50 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -605,6 +605,7 @@ void FramebufferManagerCommon::ReinterpretFramebufferFrom(VirtualFramebuffer *vf // Copy to a temp framebuffer. Draw::Framebuffer *temp = GetTempFBO(TempFBO::REINTERPRET, vfb->renderWidth, vfb->renderHeight); + draw_->InvalidateCachedState(); draw_->CopyFramebufferImage(vfb->fbo, 0, 0, 0, 0, temp, 0, 0, 0, 0, vfb->renderWidth, vfb->renderHeight, 1, Draw::FBChannel::FB_COLOR_BIT, "reinterpret_prep"); draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "reinterpret"); draw_->BindPipeline(pipeline); diff --git a/GPU/GLES/DepalettizeShaderGLES.cpp b/GPU/GLES/DepalettizeShaderGLES.cpp index 8e58de7c55c1..47ddfa19074a 100644 --- a/GPU/GLES/DepalettizeShaderGLES.cpp +++ b/GPU/GLES/DepalettizeShaderGLES.cpp @@ -98,7 +98,7 @@ GLRTexture *DepalShaderCacheGLES::GetClutTexture(GEPaletteFormat clutFormat, con int texturePixels = clutFormat == GE_CMODE_32BIT_ABGR8888 ? 256 : 512; DepalTexture *tex = new DepalTexture(); - tex->texture = render_->CreateTexture(GL_TEXTURE_2D); + tex->texture = render_->CreateTexture(GL_TEXTURE_2D, texturePixels, 1, 1); uint8_t *clutCopy = new uint8_t[1024]; memcpy(clutCopy, rawClut, 1024); diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index deb288bd85b0..18731568060c 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -696,7 +696,7 @@ void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *p prevSizeU = size_u; prevSizeV = size_v; if (!data_tex[0]) - data_tex[0] = renderManager_->CreateTexture(GL_TEXTURE_2D); + data_tex[0] = renderManager_->CreateTexture(GL_TEXTURE_2D, size_u * 3, size_v, 1); renderManager_->TextureImage(data_tex[0], 0, size_u * 3, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, nullptr, GLRAllocType::NONE, false); renderManager_->FinalizeTexture(data_tex[0], 0, false); } @@ -714,7 +714,7 @@ void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *p if (prevSizeWU < weights.size_u) { prevSizeWU = weights.size_u; if (!data_tex[1]) - data_tex[1] = renderManager_->CreateTexture(GL_TEXTURE_2D); + data_tex[1] = renderManager_->CreateTexture(GL_TEXTURE_2D, weights.size_u * 2, 1, 1); renderManager_->TextureImage(data_tex[1], 0, weights.size_u * 2, 1, Draw::DataFormat::R32G32B32A32_FLOAT, nullptr, GLRAllocType::NONE, false); renderManager_->FinalizeTexture(data_tex[1], 0, false); } @@ -725,7 +725,7 @@ void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *p if (prevSizeWV < weights.size_v) { prevSizeWV = weights.size_v; if (!data_tex[2]) - data_tex[2] = renderManager_->CreateTexture(GL_TEXTURE_2D); + data_tex[2] = renderManager_->CreateTexture(GL_TEXTURE_2D, weights.size_v * 2, 1, 1); renderManager_->TextureImage(data_tex[2], 0, weights.size_v * 2, 1, Draw::DataFormat::R32G32B32A32_FLOAT, nullptr, GLRAllocType::NONE, false); renderManager_->FinalizeTexture(data_tex[2], 0, false); } diff --git a/GPU/GLES/FragmentTestCacheGLES.cpp b/GPU/GLES/FragmentTestCacheGLES.cpp index 47a23efc4da7..bd977cf103c8 100644 --- a/GPU/GLES/FragmentTestCacheGLES.cpp +++ b/GPU/GLES/FragmentTestCacheGLES.cpp @@ -144,7 +144,7 @@ GLRTexture *FragmentTestCacheGLES::CreateTestTexture(const GEComparison funcs[4] } } - GLRTexture *tex = render_->CreateTexture(GL_TEXTURE_2D); + GLRTexture *tex = render_->CreateTexture(GL_TEXTURE_2D, 256, 1, 1); render_->TextureImage(tex, 0, 256, 1, Draw::DataFormat::R8G8B8A8_UNORM, data); return tex; } diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index dfe2f19648ce..93a26232816d 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -445,11 +445,6 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) { // For the estimate, we assume cluts always point to 8888 for simplicity. cacheSizeEstimate_ += EstimateTexMemoryUsage(entry); - // Always generate a texture name unless it's a framebuffer, we might need it if the texture is replaced later. - if (!entry->textureName) { - entry->textureName = render_->CreateTexture(GL_TEXTURE_2D); - } - if ((entry->bufw == 0 || (gstate.texbufwidth[0] & 0xf800) != 0) && entry->addr >= PSP_GetKernelMemoryEnd()) { ERROR_LOG_REPORT(G3D, "Texture with unexpected bufw (full=%d)", gstate.texbufwidth[0] & 0xffff); // Proceeding here can cause a crash. @@ -535,7 +530,7 @@ void TextureCacheGLES::BuildTexture(TexCacheEntry *const entry) { texelsScaledThisFrame_ += w * h; } } - + // GLES2 doesn't have support for a "Max lod" which is critical as PSP games often // don't specify mips all the way down. As a result, we either need to manually generate // the bottom few levels or rely on OpenGL's autogen mipmaps instead, which might not @@ -645,6 +640,14 @@ void TextureCacheGLES::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &r gpuStats.numTexturesDecoded++; + if (!entry.textureName) { + // TODO: Actually pass in correct size here. The size here is not yet used for anything else + // than determining if we can wrap this texture size, that is, it's pow2 or not on very old hardware, else true. + // This will be easy after .. well, yet another refactoring, where I hoist the size calculation out of LoadTextureLevel + // and unify BuildTexture. + entry.textureName = render_->CreateTexture(GL_TEXTURE_2D, 16, 16, 1); + } + if (replaced.GetSize(level, w, h)) { PROFILE_THIS_SCOPE("replacetex");