D3D: Use new readback methods for EFB2RAM
This commit is contained in:
parent
9da9f26b90
commit
752dd4761d
|
@ -4,17 +4,21 @@
|
||||||
|
|
||||||
#include "VideoBackends/D3D/PSTextureEncoder.h"
|
#include "VideoBackends/D3D/PSTextureEncoder.h"
|
||||||
|
|
||||||
|
#include "Common/Assert.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Core/HW/Memmap.h"
|
#include "Core/HW/Memmap.h"
|
||||||
#include "VideoBackends/D3D/D3DBase.h"
|
#include "VideoBackends/D3D/D3DBase.h"
|
||||||
#include "VideoBackends/D3D/D3DShader.h"
|
#include "VideoBackends/D3D/D3DShader.h"
|
||||||
#include "VideoBackends/D3D/D3DState.h"
|
#include "VideoBackends/D3D/D3DState.h"
|
||||||
#include "VideoBackends/D3D/D3DUtil.h"
|
#include "VideoBackends/D3D/D3DUtil.h"
|
||||||
|
#include "VideoBackends/D3D/DXTexture.h"
|
||||||
#include "VideoBackends/D3D/FramebufferManager.h"
|
#include "VideoBackends/D3D/FramebufferManager.h"
|
||||||
#include "VideoBackends/D3D/Render.h"
|
#include "VideoBackends/D3D/Render.h"
|
||||||
#include "VideoBackends/D3D/TextureCache.h"
|
#include "VideoBackends/D3D/TextureCache.h"
|
||||||
#include "VideoBackends/D3D/VertexShaderCache.h"
|
#include "VideoBackends/D3D/VertexShaderCache.h"
|
||||||
|
|
||||||
|
#include "VideoCommon/AbstractStagingTexture.h"
|
||||||
|
#include "VideoCommon/AbstractTexture.h"
|
||||||
#include "VideoCommon/TextureConversionShader.h"
|
#include "VideoCommon/TextureConversionShader.h"
|
||||||
#include "VideoCommon/VideoCommon.h"
|
#include "VideoCommon/VideoCommon.h"
|
||||||
|
|
||||||
|
@ -31,76 +35,41 @@ struct EFBEncodeParams
|
||||||
};
|
};
|
||||||
|
|
||||||
PSTextureEncoder::PSTextureEncoder()
|
PSTextureEncoder::PSTextureEncoder()
|
||||||
: m_ready(false), m_out(nullptr), m_outRTV(nullptr), m_outStage(nullptr),
|
|
||||||
m_encodeParams(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PSTextureEncoder::~PSTextureEncoder() = default;
|
||||||
|
|
||||||
void PSTextureEncoder::Init()
|
void PSTextureEncoder::Init()
|
||||||
{
|
{
|
||||||
m_ready = false;
|
// TODO: Move this to a constant somewhere in common.
|
||||||
|
TextureConfig encoding_texture_config(EFB_WIDTH * 4, 1024, 1, 1, AbstractTextureFormat::BGRA8,
|
||||||
HRESULT hr;
|
true);
|
||||||
|
m_encoding_render_texture = g_renderer->CreateTexture(encoding_texture_config);
|
||||||
// Create output texture RGBA format
|
m_encoding_readback_texture =
|
||||||
// TODO: This Texture is overly large and parts of it are unused
|
g_renderer->CreateStagingTexture(StagingTextureType::Readback, encoding_texture_config);
|
||||||
// EFB2RAM copies use max (EFB_WIDTH * 4) by (EFB_HEIGHT / 4)
|
_assert_(m_encoding_render_texture && m_encoding_readback_texture);
|
||||||
// XFB2RAM copies use max (EFB_WIDTH / 2) by (EFB_HEIGHT)
|
|
||||||
D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_B8G8R8A8_UNORM, EFB_WIDTH * 4, 1024,
|
|
||||||
1, 1, D3D11_BIND_RENDER_TARGET);
|
|
||||||
hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_out);
|
|
||||||
CHECK(SUCCEEDED(hr), "create efb encode output texture");
|
|
||||||
D3D::SetDebugObjectName(m_out, "efb encoder output texture");
|
|
||||||
|
|
||||||
// Create output render target view
|
|
||||||
D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC(
|
|
||||||
m_out, D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_B8G8R8A8_UNORM);
|
|
||||||
hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV);
|
|
||||||
CHECK(SUCCEEDED(hr), "create efb encode output render target view");
|
|
||||||
D3D::SetDebugObjectName(m_outRTV, "efb encoder output rtv");
|
|
||||||
|
|
||||||
// Create output staging buffer
|
|
||||||
t2dd.Usage = D3D11_USAGE_STAGING;
|
|
||||||
t2dd.BindFlags = 0;
|
|
||||||
t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
|
||||||
hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_outStage);
|
|
||||||
CHECK(SUCCEEDED(hr), "create efb encode output staging buffer");
|
|
||||||
D3D::SetDebugObjectName(m_outStage, "efb encoder output staging buffer");
|
|
||||||
|
|
||||||
// Create constant buffer for uploading data to shaders
|
// Create constant buffer for uploading data to shaders
|
||||||
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(EFBEncodeParams), D3D11_BIND_CONSTANT_BUFFER);
|
D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(EFBEncodeParams), D3D11_BIND_CONSTANT_BUFFER);
|
||||||
hr = D3D::device->CreateBuffer(&bd, nullptr, &m_encodeParams);
|
HRESULT hr = D3D::device->CreateBuffer(&bd, nullptr, &m_encode_params);
|
||||||
CHECK(SUCCEEDED(hr), "create efb encode params buffer");
|
CHECK(SUCCEEDED(hr), "create efb encode params buffer");
|
||||||
D3D::SetDebugObjectName(m_encodeParams, "efb encoder params buffer");
|
D3D::SetDebugObjectName(m_encode_params, "efb encoder params buffer");
|
||||||
|
|
||||||
m_ready = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PSTextureEncoder::Shutdown()
|
void PSTextureEncoder::Shutdown()
|
||||||
{
|
{
|
||||||
m_ready = false;
|
|
||||||
|
|
||||||
for (auto& it : m_encoding_shaders)
|
for (auto& it : m_encoding_shaders)
|
||||||
{
|
|
||||||
SAFE_RELEASE(it.second);
|
SAFE_RELEASE(it.second);
|
||||||
}
|
|
||||||
m_encoding_shaders.clear();
|
m_encoding_shaders.clear();
|
||||||
|
|
||||||
SAFE_RELEASE(m_encodeParams);
|
SAFE_RELEASE(m_encode_params);
|
||||||
SAFE_RELEASE(m_outStage);
|
|
||||||
SAFE_RELEASE(m_outRTV);
|
|
||||||
SAFE_RELEASE(m_out);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PSTextureEncoder::Encode(u8* dst, const EFBCopyParams& params, u32 native_width,
|
void PSTextureEncoder::Encode(u8* dst, const EFBCopyParams& params, u32 native_width,
|
||||||
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
|
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
|
||||||
const EFBRectangle& src_rect, bool scale_by_half)
|
const EFBRectangle& src_rect, bool scale_by_half)
|
||||||
{
|
{
|
||||||
if (!m_ready) // Make sure we initialized OK
|
|
||||||
return;
|
|
||||||
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
// Resolve MSAA targets before copying.
|
// Resolve MSAA targets before copying.
|
||||||
// FIXME: Instead of resolving EFB, it would be better to pick out a
|
// FIXME: Instead of resolving EFB, it would be better to pick out a
|
||||||
// single sample from each pixel. The game may break if it isn't
|
// single sample from each pixel. The game may break if it isn't
|
||||||
|
@ -122,7 +91,10 @@ void PSTextureEncoder::Encode(u8* dst, const EFBCopyParams& params, u32 native_w
|
||||||
constexpr EFBRectangle fullSrcRect(0, 0, EFB_WIDTH, EFB_HEIGHT);
|
constexpr EFBRectangle fullSrcRect(0, 0, EFB_WIDTH, EFB_HEIGHT);
|
||||||
TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(fullSrcRect);
|
TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(fullSrcRect);
|
||||||
|
|
||||||
D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr);
|
D3D::context->OMSetRenderTargets(
|
||||||
|
1,
|
||||||
|
&static_cast<DXTexture*>(m_encoding_render_texture.get())->GetRawTexIdentifier()->GetRTV(),
|
||||||
|
nullptr);
|
||||||
|
|
||||||
EFBEncodeParams encode_params;
|
EFBEncodeParams encode_params;
|
||||||
encode_params.SrcLeft = src_rect.left;
|
encode_params.SrcLeft = src_rect.left;
|
||||||
|
@ -130,8 +102,8 @@ void PSTextureEncoder::Encode(u8* dst, const EFBCopyParams& params, u32 native_w
|
||||||
encode_params.DestWidth = native_width;
|
encode_params.DestWidth = native_width;
|
||||||
encode_params.ScaleFactor = scale_by_half ? 2 : 1;
|
encode_params.ScaleFactor = scale_by_half ? 2 : 1;
|
||||||
encode_params.y_scale = params.y_scale;
|
encode_params.y_scale = params.y_scale;
|
||||||
D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, &encode_params, 0, 0);
|
D3D::context->UpdateSubresource(m_encode_params, 0, nullptr, &encode_params, 0, 0);
|
||||||
D3D::stateman->SetPixelConstants(m_encodeParams);
|
D3D::stateman->SetPixelConstants(m_encode_params);
|
||||||
|
|
||||||
// We also linear filtering for both box filtering and downsampling higher resolutions to 1x
|
// We also linear filtering for both box filtering and downsampling higher resolutions to 1x
|
||||||
// TODO: This only produces perfect downsampling for 2x IR, other resolutions will need more
|
// TODO: This only produces perfect downsampling for 2x IR, other resolutions will need more
|
||||||
|
@ -148,24 +120,15 @@ void PSTextureEncoder::Encode(u8* dst, const EFBCopyParams& params, u32 native_w
|
||||||
VertexShaderCache::GetSimpleInputLayout());
|
VertexShaderCache::GetSimpleInputLayout());
|
||||||
|
|
||||||
// Copy to staging buffer
|
// Copy to staging buffer
|
||||||
D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, words_per_row, num_blocks_y, 1);
|
MathUtil::Rectangle<int> copy_rect(0, 0, words_per_row, num_blocks_y);
|
||||||
D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox);
|
m_encoding_readback_texture->CopyFromTexture(m_encoding_render_texture.get(), copy_rect, 0, 0,
|
||||||
|
copy_rect);
|
||||||
// Transfer staging buffer to GameCube/Wii RAM
|
m_encoding_readback_texture->Flush();
|
||||||
D3D11_MAPPED_SUBRESOURCE map = {0};
|
if (m_encoding_readback_texture->Map())
|
||||||
hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map);
|
|
||||||
CHECK(SUCCEEDED(hr), "map staging buffer (0x%x)", hr);
|
|
||||||
|
|
||||||
u8* src = (u8*)map.pData;
|
|
||||||
u32 readStride = std::min(bytes_per_row, map.RowPitch);
|
|
||||||
for (unsigned int y = 0; y < num_blocks_y; ++y)
|
|
||||||
{
|
{
|
||||||
memcpy(dst, src, readStride);
|
m_encoding_readback_texture->ReadTexels(copy_rect, dst, memory_stride);
|
||||||
dst += memory_stride;
|
m_encoding_readback_texture->Unmap();
|
||||||
src += map.RowPitch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D::context->Unmap(m_outStage, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore API
|
// Restore API
|
||||||
|
|
|
@ -5,11 +5,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "VideoCommon/TextureConversionShader.h"
|
#include "VideoCommon/TextureConversionShader.h"
|
||||||
#include "VideoCommon/VideoCommon.h"
|
#include "VideoCommon/VideoCommon.h"
|
||||||
|
|
||||||
|
class AbstractTexture;
|
||||||
|
class AbstractStagingTexture;
|
||||||
|
|
||||||
struct ID3D11Texture2D;
|
struct ID3D11Texture2D;
|
||||||
struct ID3D11RenderTargetView;
|
struct ID3D11RenderTargetView;
|
||||||
struct ID3D11Buffer;
|
struct ID3D11Buffer;
|
||||||
|
@ -29,6 +33,7 @@ class PSTextureEncoder final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PSTextureEncoder();
|
PSTextureEncoder();
|
||||||
|
~PSTextureEncoder();
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
@ -39,12 +44,9 @@ public:
|
||||||
private:
|
private:
|
||||||
ID3D11PixelShader* GetEncodingPixelShader(const EFBCopyParams& params);
|
ID3D11PixelShader* GetEncodingPixelShader(const EFBCopyParams& params);
|
||||||
|
|
||||||
bool m_ready;
|
ID3D11Buffer* m_encode_params = nullptr;
|
||||||
|
std::unique_ptr<AbstractTexture> m_encoding_render_texture;
|
||||||
ID3D11Texture2D* m_out;
|
std::unique_ptr<AbstractStagingTexture> m_encoding_readback_texture;
|
||||||
ID3D11RenderTargetView* m_outRTV;
|
|
||||||
ID3D11Texture2D* m_outStage;
|
|
||||||
ID3D11Buffer* m_encodeParams;
|
|
||||||
std::map<EFBCopyParams, ID3D11PixelShader*> m_encoding_shaders;
|
std::map<EFBCopyParams, ID3D11PixelShader*> m_encoding_shaders;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue