D3D: Use new readback methods for EFB2RAM

This commit is contained in:
Stenzek 2017-10-30 23:11:46 +10:00
parent 9da9f26b90
commit 752dd4761d
2 changed files with 37 additions and 72 deletions

View File

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

View File

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