mirror of https://github.com/PCSX2/pcsx2.git
GS: Compute mipmap levels in base device
Also fixes the incorrect number of levels.
This commit is contained in:
parent
0f5b17de0f
commit
e1e83c11cc
|
@ -113,6 +113,10 @@ static const GSVector2i default_rt_size(1280, 1024);
|
||||||
// Maximum texture size to skip preload/hash path.
|
// Maximum texture size to skip preload/hash path.
|
||||||
static constexpr int MAXIMUM_PRELOAD_TEXTURE_SIZE = 512;
|
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
|
// Helper path to dump texture
|
||||||
extern const std::string root_sw;
|
extern const std::string root_sw;
|
||||||
extern const std::string root_hw;
|
extern const std::string root_hw;
|
||||||
|
|
|
@ -48,6 +48,11 @@ const char* shaderName(ShaderConvert value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const int MipmapLevelsForSize(int width, int height)
|
||||||
|
{
|
||||||
|
return std::min(static_cast<int>(std::log2(std::max(width, height))) + 1, MAXIMUM_TEXTURE_MIPMAP_LEVELS);
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<GSDevice> g_gs_device;
|
std::unique_ptr<GSDevice> g_gs_device;
|
||||||
|
|
||||||
GSDevice::GSDevice()
|
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);
|
const bool prefer_new_texture = (m_features.prefer_new_textures && type == GSTexture::Type::Texture && !prefer_reuse);
|
||||||
|
|
||||||
GSTexture* t = nullptr;
|
GSTexture* t = nullptr;
|
||||||
|
@ -118,7 +123,7 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int w, int h, bool mipma
|
||||||
|
|
||||||
assert(t);
|
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)
|
if (!prefer_new_texture)
|
||||||
{
|
{
|
||||||
|
@ -143,7 +148,7 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int w, int h, bool mipma
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
t = CreateSurface(type, w, h, mipmap, format);
|
t = CreateSurface(type, width, height, levels, format);
|
||||||
if (!t)
|
if (!t)
|
||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
}
|
}
|
||||||
|
@ -247,32 +252,33 @@ void GSDevice::ClearSamplerCache()
|
||||||
|
|
||||||
GSTexture* GSDevice::CreateSparseRenderTarget(int w, int h, GSTexture::Format format, bool clear)
|
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)
|
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)
|
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)
|
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 */)
|
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)
|
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)
|
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)
|
if (t2 == NULL || t2->GetWidth() != w || t2->GetHeight() != h)
|
||||||
{
|
{
|
||||||
const GSTexture::Format fmt = t2 ? t2->GetFormat() : GetDefaultTextureFormat(type);
|
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;
|
delete t2;
|
||||||
|
|
||||||
t2 = FetchSurface(type, w, h, mipmap, fmt, clear, prefer_reuse);
|
t2 = FetchSurface(type, w, h, levels, fmt, clear, prefer_reuse);
|
||||||
|
|
||||||
*t = t2;
|
*t = t2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -593,8 +593,8 @@ protected:
|
||||||
bool m_rbswapped;
|
bool m_rbswapped;
|
||||||
FeatureSupport m_features;
|
FeatureSupport m_features;
|
||||||
|
|
||||||
virtual GSTexture* CreateSurface(GSTexture::Type type, int w, int h, bool mipmap, GSTexture::Format format) = 0;
|
virtual GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) = 0;
|
||||||
GSTexture* FetchSurface(GSTexture::Type type, int w, int h, bool mipmap, GSTexture::Format format, bool clear, bool prefer_reuse);
|
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 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;
|
virtual void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset) = 0;
|
||||||
|
|
|
@ -481,7 +481,7 @@ void GSDevice11::ClearStencil(GSTexture* t, u8 c)
|
||||||
m_ctx->ClearDepthStencilView(*(GSTexture11*)t, D3D11_CLEAR_STENCIL, 0, 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;
|
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.
|
// 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.Width = std::clamp(width, 1, m_d3d_texsize);
|
||||||
desc.Height = std::max(1, std::min(h, m_d3d_texsize));
|
desc.Height = std::clamp(height, 1, m_d3d_texsize);
|
||||||
desc.Format = dxformat;
|
desc.Format = dxformat;
|
||||||
desc.MipLevels = mipmap ? (int)log2(std::max(desc.Width, desc.Height)) : 1;
|
desc.MipLevels = levels;
|
||||||
desc.ArraySize = 1;
|
desc.ArraySize = 1;
|
||||||
desc.SampleDesc.Count = 1;
|
desc.SampleDesc.Count = 1;
|
||||||
desc.SampleDesc.Quality = 0;
|
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;
|
desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
|
||||||
break;
|
break;
|
||||||
case GSTexture::Type::Texture:
|
case GSTexture::Type::Texture:
|
||||||
desc.BindFlags = mipmap ? (D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE) : D3D11_BIND_SHADER_RESOURCE;
|
desc.BindFlags = (levels > 1) ? (D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE) : D3D11_BIND_SHADER_RESOURCE;
|
||||||
desc.MiscFlags = mipmap ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;
|
desc.MiscFlags = (levels > 1) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;
|
||||||
break;
|
break;
|
||||||
case GSTexture::Type::Offscreen:
|
case GSTexture::Type::Offscreen:
|
||||||
desc.Usage = D3D11_USAGE_STAGING;
|
desc.Usage = D3D11_USAGE_STAGING;
|
||||||
|
|
|
@ -111,7 +111,7 @@ private:
|
||||||
int m_upscale_multiplier;
|
int m_upscale_multiplier;
|
||||||
int m_d3d_texsize;
|
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 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;
|
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) final;
|
||||||
|
|
|
@ -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");
|
GL_PUSH("Create surface");
|
||||||
|
return new GSTextureOGL(type, width, height, levels, format, m_fbo_read);
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GSDeviceOGL::Create(HostDisplay* display)
|
bool GSDeviceOGL::Create(HostDisplay* display)
|
||||||
|
|
|
@ -300,7 +300,7 @@ private:
|
||||||
|
|
||||||
AlignedBuffer<u8, 32> m_download_buffer;
|
AlignedBuffer<u8, 32> 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 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;
|
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) final;
|
||||||
|
|
|
@ -171,12 +171,12 @@ namespace PboPool
|
||||||
}
|
}
|
||||||
} // 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)
|
: 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
|
// OpenGL didn't like dimensions of size 0
|
||||||
m_size.x = std::max(1, w);
|
m_size.x = std::max(1, width);
|
||||||
m_size.y = std::max(1, h);
|
m_size.y = std::max(1, height);
|
||||||
m_format = format;
|
m_format = format;
|
||||||
m_type = type;
|
m_type = type;
|
||||||
m_fbo_read = fbo_read;
|
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:
|
case Type::Texture:
|
||||||
// Only 32 bits input texture will be supported for mipmap
|
// 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;
|
break;
|
||||||
case Type::SparseRenderTarget:
|
case Type::SparseRenderTarget:
|
||||||
case Type::SparseDepthStencil:
|
case Type::SparseDepthStencil:
|
||||||
|
|
|
@ -58,7 +58,7 @@ private:
|
||||||
u32 m_mem_usage;
|
u32 m_mem_usage;
|
||||||
|
|
||||||
public:
|
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();
|
virtual ~GSTextureOGL();
|
||||||
|
|
||||||
void* GetNativeHandle() const override;
|
void* GetNativeHandle() const override;
|
||||||
|
|
|
@ -338,16 +338,15 @@ void GSDeviceVK::ClearStencil(GSTexture* t, u8 c)
|
||||||
static_cast<GSTextureVK*>(t)->TransitionToLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
static_cast<GSTextureVK*>(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 &&
|
pxAssert(type != GSTexture::Type::Offscreen && type != GSTexture::Type::SparseRenderTarget &&
|
||||||
type != GSTexture::Type::SparseDepthStencil);
|
type != GSTexture::Type::SparseDepthStencil);
|
||||||
|
|
||||||
const u32 width = std::max<u32>(1, std::min<u32>(w, g_vulkan_context->GetMaxImageDimension2D()));
|
const u32 clamped_width = static_cast<u32>(std::clamp<int>(1, width, g_vulkan_context->GetMaxImageDimension2D()));
|
||||||
const u32 height = std::max<u32>(1, std::min<u32>(h, g_vulkan_context->GetMaxImageDimension2D()));
|
const u32 clamped_height = static_cast<u32>(std::clamp<int>(1, height, g_vulkan_context->GetMaxImageDimension2D()));
|
||||||
const u32 layers = mipmap ? static_cast<u32>(log2(std::max(w, h))) : 1u;
|
|
||||||
|
|
||||||
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)
|
bool GSDeviceVK::DownloadTexture(GSTexture* src, const GSVector4i& rect, GSTexture::GSMap& out_map)
|
||||||
|
|
|
@ -158,7 +158,7 @@ private:
|
||||||
|
|
||||||
std::string m_tfx_source;
|
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,
|
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE,
|
||||||
const GSRegEXTBUF& EXTBUF, const GSVector4& c) final;
|
const GSRegEXTBUF& EXTBUF, const GSVector4& c) final;
|
||||||
|
|
Loading…
Reference in New Issue