mirror of https://github.com/PCSX2/pcsx2.git
GS: Fix depth texture dumping for HW
This commit is contained in:
parent
e3a1125e84
commit
728ca8aa9d
|
@ -26,6 +26,23 @@ GSTexture::GSTexture() = default;
|
||||||
|
|
||||||
bool GSTexture::Save(const std::string& fn)
|
bool GSTexture::Save(const std::string& fn)
|
||||||
{
|
{
|
||||||
|
// Depth textures need special treatment - we have a stencil component.
|
||||||
|
// Just re-use the existing conversion shader instead.
|
||||||
|
if (m_format == Format::DepthStencil)
|
||||||
|
{
|
||||||
|
GSTexture* temp = g_gs_device->CreateRenderTarget(GetWidth(), GetHeight(), Format::Color, false);
|
||||||
|
if (!temp)
|
||||||
|
{
|
||||||
|
Console.Error("Failed to allocate %dx%d texture for depth conversion", GetWidth(), GetHeight());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_gs_device->StretchRect(this, GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f), temp, GSVector4(GetRect()), ShaderConvert::FLOAT32_TO_RGBA8, false);
|
||||||
|
const bool res = temp->Save(fn);
|
||||||
|
g_gs_device->Recycle(temp);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef PCSX2_DEVBUILD
|
#ifdef PCSX2_DEVBUILD
|
||||||
GSPng::Format format = GSPng::RGB_A_PNG;
|
GSPng::Format format = GSPng::RGB_A_PNG;
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -92,103 +92,6 @@ void GSTexture11::Unmap()
|
||||||
pxFailRel("Should not be called.");
|
pxFailRel("Should not be called.");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GSTexture11::Save(const std::string& fn)
|
|
||||||
{
|
|
||||||
GSDevice11::GetInstance()->CommitClear(this);
|
|
||||||
|
|
||||||
D3D11_TEXTURE2D_DESC desc = m_desc;
|
|
||||||
desc.Usage = D3D11_USAGE_STAGING;
|
|
||||||
desc.BindFlags = 0;
|
|
||||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
|
||||||
|
|
||||||
wil::com_ptr_nothrow<ID3D11Texture2D> res;
|
|
||||||
HRESULT hr = GSDevice11::GetInstance()->GetD3DDevice()->CreateTexture2D(&desc, nullptr, res.put());
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GSDevice11::GetInstance()->GetD3DContext()->CopyResource(res.get(), m_texture.get());
|
|
||||||
|
|
||||||
if (m_desc.BindFlags & D3D11_BIND_DEPTH_STENCIL)
|
|
||||||
{
|
|
||||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
desc.CPUAccessFlags |= D3D11_CPU_ACCESS_WRITE;
|
|
||||||
|
|
||||||
wil::com_ptr_nothrow<ID3D11Texture2D> dst;
|
|
||||||
hr = GSDevice11::GetInstance()->GetD3DDevice()->CreateTexture2D(&desc, nullptr, dst.put());
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D11_MAPPED_SUBRESOURCE sm, dm;
|
|
||||||
|
|
||||||
hr = GSDevice11::GetInstance()->GetD3DContext()->Map(res.get(), 0, D3D11_MAP_READ, 0, &sm);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto unmap_res = wil::scope_exit([res]{ // Capture by value to preserve the original pointer
|
|
||||||
GSDevice11::GetInstance()->GetD3DContext()->Unmap(res.get(), 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
hr = GSDevice11::GetInstance()->GetD3DContext()->Map(dst.get(), 0, D3D11_MAP_WRITE, 0, &dm);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto unmap_dst = wil::scope_exit([dst]{ // Capture by value to preserve the original pointer
|
|
||||||
GSDevice11::GetInstance()->GetD3DContext()->Unmap(dst.get(), 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
const u8* s = static_cast<const u8*>(sm.pData);
|
|
||||||
u8* d = static_cast<u8*>(dm.pData);
|
|
||||||
|
|
||||||
for (u32 y = 0; y < desc.Height; y++, s += sm.RowPitch, d += dm.RowPitch)
|
|
||||||
{
|
|
||||||
for (u32 x = 0; x < desc.Width; x++)
|
|
||||||
{
|
|
||||||
reinterpret_cast<u32*>(d)[x] = static_cast<u32>(ldexpf(reinterpret_cast<const float*>(s)[x * 2], 32));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res = std::move(dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
res->GetDesc(&desc);
|
|
||||||
|
|
||||||
#ifdef PCSX2_DEVBUILD
|
|
||||||
GSPng::Format format = GSPng::RGB_A_PNG;
|
|
||||||
#else
|
|
||||||
GSPng::Format format = GSPng::RGB_PNG;
|
|
||||||
#endif
|
|
||||||
switch (desc.Format)
|
|
||||||
{
|
|
||||||
case DXGI_FORMAT_A8_UNORM:
|
|
||||||
format = GSPng::R8I_PNG;
|
|
||||||
break;
|
|
||||||
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "DXGI_FORMAT %d not saved to image\n", desc.Format);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D11_MAPPED_SUBRESOURCE sm;
|
|
||||||
hr = GSDevice11::GetInstance()->GetD3DContext()->Map(res.get(), 0, D3D11_MAP_READ, 0, &sm);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool success = GSPng::Save(format, fn, static_cast<u8*>(sm.pData), desc.Width, desc.Height, sm.RowPitch, GSConfig.PNGCompressionLevel);
|
|
||||||
|
|
||||||
GSDevice11::GetInstance()->GetD3DContext()->Unmap(res.get(), 0);
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GSTexture11::GenerateMipmap()
|
void GSTexture11::GenerateMipmap()
|
||||||
{
|
{
|
||||||
GSDevice11::GetInstance()->GetD3DContext()->GenerateMips(operator ID3D11ShaderResourceView*());
|
GSDevice11::GetInstance()->GetD3DContext()->GenerateMips(operator ID3D11ShaderResourceView*());
|
||||||
|
|
|
@ -43,7 +43,6 @@ public:
|
||||||
bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override;
|
bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override;
|
||||||
bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) override;
|
bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) override;
|
||||||
void Unmap() override;
|
void Unmap() override;
|
||||||
bool Save(const std::string& fn) override;
|
|
||||||
void GenerateMipmap() override;
|
void GenerateMipmap() override;
|
||||||
void Swap(GSTexture* tex) override;
|
void Swap(GSTexture* tex) override;
|
||||||
bool Equal(GSTexture11* tex);
|
bool Equal(GSTexture11* tex);
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include "GS/Renderers/OpenGL/GLState.h"
|
#include "GS/Renderers/OpenGL/GLState.h"
|
||||||
#include "GS/GSExtra.h"
|
#include "GS/GSExtra.h"
|
||||||
#include "GS/GSPerfMon.h"
|
#include "GS/GSPerfMon.h"
|
||||||
#include "GS/GSPng.h"
|
|
||||||
#include "GS/GSGL.h"
|
#include "GS/GSGL.h"
|
||||||
#include "common/BitUtils.h"
|
#include "common/BitUtils.h"
|
||||||
#include "common/AlignedMalloc.h"
|
#include "common/AlignedMalloc.h"
|
||||||
|
@ -329,65 +328,6 @@ void GSTextureOGL::GenerateMipmap()
|
||||||
glGenerateTextureMipmap(m_texture_id);
|
glGenerateTextureMipmap(m_texture_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GSTextureOGL::Save(const std::string& fn)
|
|
||||||
{
|
|
||||||
GSDeviceOGL::GetInstance()->CommitClear(this, true);
|
|
||||||
|
|
||||||
// Collect the texture data
|
|
||||||
u32 pitch = 4 * m_size.x;
|
|
||||||
u32 buf_size = pitch * m_size.y * 2; // Note *2 for security (depth/stencil)
|
|
||||||
std::unique_ptr<u8[]> image(new u8[buf_size]);
|
|
||||||
#ifdef PCSX2_DEVBUILD
|
|
||||||
GSPng::Format fmt = GSPng::RGB_A_PNG;
|
|
||||||
#else
|
|
||||||
GSPng::Format fmt = GSPng::RGB_PNG;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (IsDepthStencil())
|
|
||||||
{
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, GSDeviceOGL::GetInstance()->GetFBORead());
|
|
||||||
|
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_texture_id, 0);
|
|
||||||
glReadPixels(0, 0, m_size.x, m_size.y, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image.get());
|
|
||||||
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
|
||||||
|
|
||||||
fmt = GSPng::RGB_A_PNG;
|
|
||||||
}
|
|
||||||
else if (m_format == Format::PrimID)
|
|
||||||
{
|
|
||||||
// Note: 4.5 function used for accurate DATE
|
|
||||||
glGetTextureImage(m_texture_id, 0, GL_RED_INTEGER, GL_INT, buf_size, image.get());
|
|
||||||
|
|
||||||
fmt = GSPng::R32I_PNG;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, GSDeviceOGL::GetInstance()->GetFBORead());
|
|
||||||
|
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture_id, 0);
|
|
||||||
|
|
||||||
if (m_format == Format::Color)
|
|
||||||
{
|
|
||||||
glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, image.get());
|
|
||||||
}
|
|
||||||
else if (m_format == Format::UInt16)
|
|
||||||
{
|
|
||||||
glReadPixels(0, 0, m_size.x, m_size.y, GL_RED_INTEGER, GL_UNSIGNED_SHORT, image.get());
|
|
||||||
fmt = GSPng::R16I_PNG;
|
|
||||||
}
|
|
||||||
else if (m_format == Format::UNorm8)
|
|
||||||
{
|
|
||||||
fmt = GSPng::R8I_PNG;
|
|
||||||
glReadPixels(0, 0, m_size.x, m_size.y, GL_RED, GL_UNSIGNED_BYTE, image.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return GSPng::Save(fmt, fn, image.get(), m_size.x, m_size.y, pitch, GSConfig.PNGCompressionLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GSTextureOGL::Swap(GSTexture* tex)
|
void GSTextureOGL::Swap(GSTexture* tex)
|
||||||
{
|
{
|
||||||
GSTexture::Swap(tex);
|
GSTexture::Swap(tex);
|
||||||
|
|
|
@ -52,7 +52,6 @@ public:
|
||||||
bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) final;
|
bool Map(GSMap& m, const GSVector4i* r = NULL, int layer = 0) final;
|
||||||
void Unmap() final;
|
void Unmap() final;
|
||||||
void GenerateMipmap() final;
|
void GenerateMipmap() final;
|
||||||
bool Save(const std::string& fn) final;
|
|
||||||
void Swap(GSTexture* tex) final;
|
void Swap(GSTexture* tex) final;
|
||||||
|
|
||||||
bool IsIntegerFormat() const
|
bool IsIntegerFormat() const
|
||||||
|
|
Loading…
Reference in New Issue