Minor cleanup in GL backend, fixes #13647

Was a stray old texture in boundTextures_ in thin3d. Now makes sure to
invalidate them, and also make it possible to look up bound framebuffer
textures when checking for valid tex parameters.
This commit is contained in:
Henrik Rydgård 2020-11-10 00:12:15 +01:00
parent 9f33a82b49
commit 5eea7435d0
9 changed files with 68 additions and 41 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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 @@ public:
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 @@ public:
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 @@ public:
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;

View File

@ -386,7 +386,7 @@ public:
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 @@ private:
// 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 @@ public:
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 @@ public:
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 @@ private:
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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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");