From e1e83c11cc17131a178d293a807cf57923c2ad4d Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sun, 9 Jan 2022 21:50:13 +1000 Subject: [PATCH] GS: Compute mipmap levels in base device Also fixes the incorrect number of levels. --- pcsx2/GS/GSExtra.h | 4 +++ pcsx2/GS/Renderers/Common/GSDevice.cpp | 30 +++++++++++++--------- pcsx2/GS/Renderers/Common/GSDevice.h | 4 +-- pcsx2/GS/Renderers/DX11/GSDevice11.cpp | 12 ++++----- pcsx2/GS/Renderers/DX11/GSDevice11.h | 2 +- pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp | 8 ++---- pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h | 2 +- pcsx2/GS/Renderers/OpenGL/GSTextureOGL.cpp | 8 +++--- pcsx2/GS/Renderers/OpenGL/GSTextureOGL.h | 2 +- pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp | 9 +++---- pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h | 2 +- 11 files changed, 44 insertions(+), 39 deletions(-) diff --git a/pcsx2/GS/GSExtra.h b/pcsx2/GS/GSExtra.h index 742b4ee555..58d66677c3 100644 --- a/pcsx2/GS/GSExtra.h +++ b/pcsx2/GS/GSExtra.h @@ -113,6 +113,10 @@ static const GSVector2i default_rt_size(1280, 1024); // Maximum texture size to skip preload/hash path. static constexpr int MAXIMUM_PRELOAD_TEXTURE_SIZE = 512; +// Maximum number of mipmap levels for a texture. +// PS2 has a max of 7 levels (1 base + 6 mips). +static constexpr int MAXIMUM_TEXTURE_MIPMAP_LEVELS = 7; + // Helper path to dump texture extern const std::string root_sw; extern const std::string root_hw; diff --git a/pcsx2/GS/Renderers/Common/GSDevice.cpp b/pcsx2/GS/Renderers/Common/GSDevice.cpp index cf23296996..640872df74 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.cpp +++ b/pcsx2/GS/Renderers/Common/GSDevice.cpp @@ -48,6 +48,11 @@ const char* shaderName(ShaderConvert value) } } +static const int MipmapLevelsForSize(int width, int height) +{ + return std::min(static_cast(std::log2(std::max(width, height))) + 1, MAXIMUM_TEXTURE_MIPMAP_LEVELS); +} + std::unique_ptr g_gs_device; GSDevice::GSDevice() @@ -104,9 +109,9 @@ void GSDevice::RestoreAPIState() { } -GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int w, int h, bool mipmap, GSTexture::Format format, bool clear, bool prefer_reuse) +GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_reuse) { - const GSVector2i size(w, h); + const GSVector2i size(width, height); const bool prefer_new_texture = (m_features.prefer_new_textures && type == GSTexture::Type::Texture && !prefer_reuse); GSTexture* t = nullptr; @@ -118,7 +123,7 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int w, int h, bool mipma assert(t); - if (t->GetType() == type && t->GetFormat() == format && t->GetSize() == size && t->IsMipmap() == mipmap) + if (t->GetType() == type && t->GetFormat() == format && t->GetSize() == size && t->GetMipmapLevels() == levels) { if (!prefer_new_texture) { @@ -143,7 +148,7 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int w, int h, bool mipma } else { - t = CreateSurface(type, w, h, mipmap, format); + t = CreateSurface(type, width, height, levels, format); if (!t) throw std::bad_alloc(); } @@ -247,32 +252,33 @@ void GSDevice::ClearSamplerCache() GSTexture* GSDevice::CreateSparseRenderTarget(int w, int h, GSTexture::Format format, bool clear) { - return FetchSurface(HasColorSparse() ? GSTexture::Type::SparseRenderTarget : GSTexture::Type::RenderTarget, w, h, false, format, clear, true); + return FetchSurface(HasColorSparse() ? GSTexture::Type::SparseRenderTarget : GSTexture::Type::RenderTarget, w, h, 1, format, clear, true); } GSTexture* GSDevice::CreateSparseDepthStencil(int w, int h, GSTexture::Format format, bool clear) { - return FetchSurface(HasDepthSparse() ? GSTexture::Type::SparseDepthStencil : GSTexture::Type::DepthStencil, w, h, false, format, clear, true); + return FetchSurface(HasDepthSparse() ? GSTexture::Type::SparseDepthStencil : GSTexture::Type::DepthStencil, w, h, 1, format, clear, true); } GSTexture* GSDevice::CreateRenderTarget(int w, int h, GSTexture::Format format, bool clear) { - return FetchSurface(GSTexture::Type::RenderTarget, w, h, false, format, clear, true); + return FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, format, clear, true); } GSTexture* GSDevice::CreateDepthStencil(int w, int h, GSTexture::Format format, bool clear) { - return FetchSurface(GSTexture::Type::DepthStencil, w, h, false, format, clear, true); + return FetchSurface(GSTexture::Type::DepthStencil, w, h, 1, format, clear, true); } GSTexture* GSDevice::CreateTexture(int w, int h, bool mipmap, GSTexture::Format format, bool prefer_reuse /* = false */) { - return FetchSurface(GSTexture::Type::Texture, w, h, mipmap, format, false, prefer_reuse); + const int levels = mipmap ? MipmapLevelsForSize(w, h) : 1; + return FetchSurface(GSTexture::Type::Texture, w, h, levels, format, false, prefer_reuse); } GSTexture* GSDevice::CreateOffscreen(int w, int h, GSTexture::Format format) { - return FetchSurface(GSTexture::Type::Offscreen, w, h, false, format, false, true); + return FetchSurface(GSTexture::Type::Offscreen, w, h, 1, format, false, true); } GSTexture::Format GSDevice::GetDefaultTextureFormat(GSTexture::Type type) @@ -433,10 +439,10 @@ bool GSDevice::ResizeTexture(GSTexture** t, GSTexture::Type type, int w, int h, if (t2 == NULL || t2->GetWidth() != w || t2->GetHeight() != h) { const GSTexture::Format fmt = t2 ? t2->GetFormat() : GetDefaultTextureFormat(type); - const bool mipmap = t2 ? t2->IsMipmap() : false; + const int levels = t2 ? (t2->IsMipmap() ? MipmapLevelsForSize(w, h) : 1) : 1; delete t2; - t2 = FetchSurface(type, w, h, mipmap, fmt, clear, prefer_reuse); + t2 = FetchSurface(type, w, h, levels, fmt, clear, prefer_reuse); *t = t2; } diff --git a/pcsx2/GS/Renderers/Common/GSDevice.h b/pcsx2/GS/Renderers/Common/GSDevice.h index 92bc9a8623..b43457fd32 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.h +++ b/pcsx2/GS/Renderers/Common/GSDevice.h @@ -593,8 +593,8 @@ protected: bool m_rbswapped; FeatureSupport m_features; - virtual GSTexture* CreateSurface(GSTexture::Type type, int w, int h, bool mipmap, GSTexture::Format format) = 0; - GSTexture* FetchSurface(GSTexture::Type type, int w, int h, bool mipmap, GSTexture::Format format, bool clear, bool prefer_reuse); + virtual GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) = 0; + GSTexture* FetchSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_reuse); virtual void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c) = 0; virtual void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset) = 0; diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index 6cbffc587f..6b89b919a6 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -481,7 +481,7 @@ void GSDevice11::ClearStencil(GSTexture* t, u8 c) m_ctx->ClearDepthStencilView(*(GSTexture11*)t, D3D11_CLEAR_STENCIL, 0, c); } -GSTexture* GSDevice11::CreateSurface(GSTexture::Type type, int w, int h, bool mipmap, GSTexture::Format format) +GSTexture* GSDevice11::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) { D3D11_TEXTURE2D_DESC desc; @@ -503,10 +503,10 @@ GSTexture* GSDevice11::CreateSurface(GSTexture::Type type, int w, int h, bool mi } // Texture limit for D3D10/11 min 1, max 8192 D3D10, max 16384 D3D11. - desc.Width = std::max(1, std::min(w, m_d3d_texsize)); - desc.Height = std::max(1, std::min(h, m_d3d_texsize)); + desc.Width = std::clamp(width, 1, m_d3d_texsize); + desc.Height = std::clamp(height, 1, m_d3d_texsize); desc.Format = dxformat; - desc.MipLevels = mipmap ? (int)log2(std::max(desc.Width, desc.Height)) : 1; + desc.MipLevels = levels; desc.ArraySize = 1; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; @@ -521,8 +521,8 @@ GSTexture* GSDevice11::CreateSurface(GSTexture::Type type, int w, int h, bool mi desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; break; case GSTexture::Type::Texture: - desc.BindFlags = mipmap ? (D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE) : D3D11_BIND_SHADER_RESOURCE; - desc.MiscFlags = mipmap ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0; + desc.BindFlags = (levels > 1) ? (D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE) : D3D11_BIND_SHADER_RESOURCE; + desc.MiscFlags = (levels > 1) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0; break; case GSTexture::Type::Offscreen: desc.Usage = D3D11_USAGE_STAGING; diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.h b/pcsx2/GS/Renderers/DX11/GSDevice11.h index 8a9287cfe8..c95dc7b530 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.h +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.h @@ -111,7 +111,7 @@ private: int m_upscale_multiplier; int m_d3d_texsize; - GSTexture* CreateSurface(GSTexture::Type type, int w, int h, bool mipmap, GSTexture::Format format) final; + GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) final; void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c) final; void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) final; diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp index cd24718eff..01c29f00b6 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp @@ -198,14 +198,10 @@ void GSDeviceOGL::GenerateProfilerData() } } -GSTexture* GSDeviceOGL::CreateSurface(GSTexture::Type type, int w, int h, bool mipmap, GSTexture::Format fmt) +GSTexture* GSDeviceOGL::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) { GL_PUSH("Create surface"); - - // A wrapper to call GSTextureOGL, with the different kind of parameters. - GSTextureOGL* t = new GSTextureOGL(type, w, h, fmt, m_fbo_read, mipmap); - - return t; + return new GSTextureOGL(type, width, height, levels, format, m_fbo_read); } bool GSDeviceOGL::Create(HostDisplay* display) diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h index cf06c04151..402369195a 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h @@ -300,7 +300,7 @@ private: AlignedBuffer m_download_buffer; - GSTexture* CreateSurface(GSTexture::Type type, int w, int h, bool mipmap, GSTexture::Format format) final; + GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) final; void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c) final; void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) final; diff --git a/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.cpp index 877e4915ba..34a91a3a70 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.cpp @@ -171,12 +171,12 @@ namespace PboPool } } // namespace PboPool -GSTextureOGL::GSTextureOGL(Type type, int w, int h, Format format, GLuint fbo_read, bool mipmap) +GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format format, GLuint fbo_read) : m_clean(false), m_r_x(0), m_r_y(0), m_r_w(0), m_r_h(0), m_layer(0) { // OpenGL didn't like dimensions of size 0 - m_size.x = std::max(1, w); - m_size.y = std::max(1, h); + m_size.x = std::max(1, width); + m_size.y = std::max(1, height); m_format = format; m_type = type; m_fbo_read = fbo_read; @@ -251,7 +251,7 @@ GSTextureOGL::GSTextureOGL(Type type, int w, int h, Format format, GLuint fbo_re { case Type::Texture: // Only 32 bits input texture will be supported for mipmap - m_mipmap_levels = mipmap && m_format == Format::Color ? (int)log2(std::max(w, h)) : 1; + m_mipmap_levels = levels; break; case Type::SparseRenderTarget: case Type::SparseDepthStencil: diff --git a/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.h b/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.h index 3419b004f6..181e939d5e 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.h +++ b/pcsx2/GS/Renderers/OpenGL/GSTextureOGL.h @@ -58,7 +58,7 @@ private: u32 m_mem_usage; public: - explicit GSTextureOGL(Type type, int w, int h, Format format, GLuint fbo_read, bool mipmap); + explicit GSTextureOGL(Type type, int width, int height, int levels, Format format, GLuint fbo_read); virtual ~GSTextureOGL(); void* GetNativeHandle() const override; diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index 64cdd6b371..af3d938c62 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -338,16 +338,15 @@ void GSDeviceVK::ClearStencil(GSTexture* t, u8 c) static_cast(t)->TransitionToLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); } -GSTexture* GSDeviceVK::CreateSurface(GSTexture::Type type, int w, int h, bool mipmap, GSTexture::Format format) +GSTexture* GSDeviceVK::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) { pxAssert(type != GSTexture::Type::Offscreen && type != GSTexture::Type::SparseRenderTarget && type != GSTexture::Type::SparseDepthStencil); - const u32 width = std::max(1, std::min(w, g_vulkan_context->GetMaxImageDimension2D())); - const u32 height = std::max(1, std::min(h, g_vulkan_context->GetMaxImageDimension2D())); - const u32 layers = mipmap ? static_cast(log2(std::max(w, h))) : 1u; + const u32 clamped_width = static_cast(std::clamp(1, width, g_vulkan_context->GetMaxImageDimension2D())); + const u32 clamped_height = static_cast(std::clamp(1, height, g_vulkan_context->GetMaxImageDimension2D())); - return GSTextureVK::Create(type, width, height, layers, format).release(); + return GSTextureVK::Create(type, clamped_width, clamped_height, levels, format).release(); } bool GSDeviceVK::DownloadTexture(GSTexture* src, const GSVector4i& rect, GSTexture::GSMap& out_map) diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h index 24026007d4..1830e1338c 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h @@ -158,7 +158,7 @@ private: std::string m_tfx_source; - GSTexture* CreateSurface(GSTexture::Type type, int w, int h, bool mipmap, GSTexture::Format format) override; + GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override; void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c) final;