This commit is contained in:
Stenzek 2023-08-02 21:40:53 +10:00
parent 2834635f59
commit a43b6ee9db
24 changed files with 528 additions and 629 deletions

View File

@ -38,6 +38,12 @@ static void SetD3DDebugObjectName(ID3D11DeviceChild* obj, const std::string_view
{
// WKPDID_D3DDebugObjectName
static constexpr GUID guid = {0x429b8c22, 0x9188, 0x4b0c, 0x87, 0x42, 0xac, 0xb0, 0xbf, 0x85, 0xc2, 0x00};
UINT existing_data_size;
HRESULT hr = obj->GetPrivateData(guid, &existing_data_size, nullptr);
if (SUCCEEDED(hr) && existing_data_size > 0)
return;
const std::wstring wname = StringUtil::UTF8StringToWideString(name);
obj->SetPrivateData(guid, static_cast<UINT>(wname.length()) * 2u, wname.c_str());
}
@ -163,21 +169,6 @@ RenderAPI D3D11Device::GetRenderAPI() const
return RenderAPI::D3D11;
}
void* D3D11Device::GetDevice() const
{
return m_device.Get();
}
void* D3D11Device::GetContext() const
{
return m_context.Get();
}
bool D3D11Device::HasDevice() const
{
return static_cast<bool>(m_device);
}
bool D3D11Device::HasSurface() const
{
return static_cast<bool>(m_swap_chain);
@ -396,11 +387,12 @@ bool D3D11Device::CreateDevice(const WindowInfo& wi, bool vsync)
static constexpr std::array<D3D_FEATURE_LEVEL, 3> requested_feature_levels = {
{D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0}};
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> context;
hr =
D3D11CreateDevice(dxgi_adapter.Get(), dxgi_adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, nullptr,
create_flags, requested_feature_levels.data(), static_cast<UINT>(requested_feature_levels.size()),
D3D11_SDK_VERSION, m_device.GetAddressOf(), nullptr, m_context.GetAddressOf());
D3D11_SDK_VERSION, device.GetAddressOf(), nullptr, context.GetAddressOf());
// we re-grab these later, see below
dxgi_adapter.Reset();
temp_dxgi_factory.Reset();
@ -410,6 +402,11 @@ bool D3D11Device::CreateDevice(const WindowInfo& wi, bool vsync)
Log_ErrorPrintf("Failed to create D3D device: 0x%08X", hr);
return false;
}
else if (FAILED(hr = device.As(&m_device)) || FAILED(hr = context.As(&m_context)))
{
Log_ErrorPrintf("Failed to get D3D11.1 device: 0x%08X", hr);
return false;
}
if (g_settings.gpu_use_debug_device && IsDebuggerPresent())
{
@ -603,20 +600,22 @@ bool D3D11Device::CreateSwapChainRTV()
return false;
}
D3D11_TEXTURE2D_DESC backbuffer_desc;
backbuffer->GetDesc(&backbuffer_desc);
CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(D3D11_RTV_DIMENSION_TEXTURE2D, backbuffer_desc.Format, 0, 0,
backbuffer_desc.ArraySize);
hr = m_device->CreateRenderTargetView(backbuffer.Get(), &rtv_desc, m_swap_chain_rtv.GetAddressOf());
if (FAILED(hr))
m_swap_chain_texture = std::make_unique<D3D11Texture>();
if (!m_swap_chain_texture->Adopt(m_device.Get(), std::move(backbuffer)))
{
Log_ErrorPrintf("CreateRenderTargetView for swap chain failed: 0x%08X", hr);
m_swap_chain_texture.reset();
return false;
}
m_window_info.surface_width = backbuffer_desc.Width;
m_window_info.surface_height = backbuffer_desc.Height;
if (!(m_swap_chain_framebuffer = std::unique_ptr<D3D11Framebuffer>(
static_cast<D3D11Framebuffer*>(CreateFramebuffer(m_swap_chain_texture.get()).release()))))
{
m_swap_chain_texture.reset();
return false;
}
m_window_info.surface_width = m_swap_chain_texture->GetWidth();
m_window_info.surface_height = m_swap_chain_texture->GetHeight();
Log_InfoPrintf("Swap chain buffer size: %ux%u", m_window_info.surface_width, m_window_info.surface_height);
if (m_window_info.type == WindowInfo::Type::Win32)
@ -652,7 +651,8 @@ void D3D11Device::DestroySurface()
if (IsFullscreen())
SetFullscreen(false, 0, 0, 0.0f);
m_swap_chain_rtv.Reset();
m_swap_chain_framebuffer.reset();
m_swap_chain_texture.reset();
m_swap_chain.Reset();
}
@ -676,7 +676,8 @@ void D3D11Device::ResizeWindow(s32 new_window_width, s32 new_window_height)
if (!m_swap_chain)
return;
m_swap_chain_rtv.Reset();
m_swap_chain_framebuffer.reset();
m_swap_chain_texture.reset();
HRESULT hr = m_swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN,
m_using_allow_tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0);
@ -745,7 +746,8 @@ bool D3D11Device::SetFullscreen(bool fullscreen, u32 width, u32 height, float re
return true;
}
m_swap_chain_rtv.Reset();
m_swap_chain_framebuffer.reset();
m_swap_chain_texture.reset();
m_swap_chain.Reset();
if (!CreateSwapChain(&closest_mode))
@ -764,7 +766,7 @@ bool D3D11Device::CreateBuffers()
{
if (!m_vertex_buffer.Create(m_device.Get(), D3D11_BIND_VERTEX_BUFFER, VERTEX_BUFFER_SIZE) ||
!m_index_buffer.Create(m_device.Get(), D3D11_BIND_INDEX_BUFFER, INDEX_BUFFER_SIZE) ||
!m_uniform_buffer.Create(m_device.Get(), D3D11_BIND_CONSTANT_BUFFER, MAX_UNIFORM_BUFFER_SIZE))
!m_uniform_buffer.Create(m_device.Get(), D3D11_BIND_CONSTANT_BUFFER, UNIFORM_BUFFER_SIZE))
{
Log_ErrorPrintf("Failed to create vertex/index/uniform buffers.");
return false;
@ -795,11 +797,19 @@ bool D3D11Device::Render(bool skip_present)
if (m_vsync_enabled && m_gpu_timing_enabled)
PopTimestampQuery();
m_context->ClearRenderTargetView(m_swap_chain_rtv.Get(), s_clear_color.data());
m_context->OMSetRenderTargets(1, m_swap_chain_rtv.GetAddressOf(), nullptr);
m_current_framebuffer = nullptr;
ClearRenderTarget(m_swap_chain_texture.get(), 0);
RenderDisplay();
if (HasDisplayTexture())
{
const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight());
GL_SCOPE("RenderDisplay: %dx%d at %d,%d", left, top, width, height);
RenderDisplay(m_swap_chain_framebuffer.get(), left, top, width, height, m_display_texture, m_display_texture_view_x,
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
IsUsingLinearFiltering());
}
SetFramebuffer(m_swap_chain_framebuffer.get());
SetViewportAndScissor(0, 0, m_swap_chain_framebuffer->GetWidth(), m_swap_chain_framebuffer->GetHeight());
RenderImGui();
@ -816,6 +826,8 @@ bool D3D11Device::Render(bool skip_present)
if (m_gpu_timing_enabled)
KickTimestampQuery();
m_current_framebuffer = nullptr;
return true;
}
@ -1032,9 +1044,9 @@ D3D11Framebuffer::~D3D11Framebuffer() = default;
void D3D11Framebuffer::SetDebugName(const std::string_view& name)
{
if (m_rtv)
SetD3DDebugObjectName(m_rtv.Get(), name);
SetD3DDebugObjectName(m_rtv.Get(), fmt::format("{} RTV", name));
if (m_dsv)
SetD3DDebugObjectName(m_dsv.Get(), name);
SetD3DDebugObjectName(m_dsv.Get(), fmt::format("{} DSV", name));
}
void D3D11Framebuffer::CommitClear(ID3D11DeviceContext* context)
@ -1633,7 +1645,7 @@ std::unique_ptr<GPUPipeline> D3D11Device::CreatePipeline(const GPUPipeline::Grap
return std::unique_ptr<GPUPipeline>(
new D3D11Pipeline(std::move(rs), std::move(ds), std::move(bs), std::move(il),
static_cast<const D3D11Shader*>(config.vertex_shader)->GetVertexShader(),
static_cast<const D3D11Shader*>(config.pixel_shader)->GetPixelShader(),
static_cast<const D3D11Shader*>(config.fragment_shader)->GetPixelShader(),
primitives[static_cast<u8>(config.primitive)]));
}
@ -2070,29 +2082,33 @@ void D3D11Device::UnmapIndexBuffer(u32 used_index_count)
void D3D11Device::PushUniformBuffer(const void* data, u32 data_size)
{
Assert(data_size <= MAX_UNIFORM_BUFFER_SIZE);
const auto res = m_uniform_buffer.Map(m_context.Get(), MAX_UNIFORM_BUFFER_SIZE, MAX_UNIFORM_BUFFER_SIZE);
const u32 used_space = Common::AlignUpPow2(data_size, UNIFORM_BUFFER_ALIGNMENT);
const auto res = m_uniform_buffer.Map(m_context.Get(), UNIFORM_BUFFER_ALIGNMENT, used_space);
std::memcpy(res.pointer, data, data_size);
m_uniform_buffer.Unmap(m_context.Get(), data_size);
m_context->VSSetConstantBuffers(0, 1, m_uniform_buffer.GetD3DBufferArray());
m_context->PSSetConstantBuffers(0, 1, m_uniform_buffer.GetD3DBufferArray());
const UINT first_constant = (res.index_aligned * UNIFORM_BUFFER_ALIGNMENT) / 16u;
const UINT num_constants = (used_space * UNIFORM_BUFFER_ALIGNMENT) / 16u;
m_context->VSSetConstantBuffers1(0, 1, m_uniform_buffer.GetD3DBufferArray(), &first_constant, &num_constants);
m_context->PSSetConstantBuffers1(0, 1, m_uniform_buffer.GetD3DBufferArray(), &first_constant, &num_constants);
}
void* D3D11Device::MapUniformBuffer(u32 size)
{
Assert(size <= MAX_UNIFORM_BUFFER_SIZE);
const auto res = m_uniform_buffer.Map(m_context.Get(), MAX_UNIFORM_BUFFER_SIZE, MAX_UNIFORM_BUFFER_SIZE);
const u32 used_space = Common::AlignUpPow2(size, UNIFORM_BUFFER_ALIGNMENT);
const auto res = m_uniform_buffer.Map(m_context.Get(), UNIFORM_BUFFER_ALIGNMENT, used_space);
return res.pointer;
}
void D3D11Device::UnmapUniformBuffer(u32 size)
{
m_uniform_buffer.Unmap(m_context.Get(), size);
m_context->VSSetConstantBuffers(0, 1, m_uniform_buffer.GetD3DBufferArray());
m_context->PSSetConstantBuffers(0, 1, m_uniform_buffer.GetD3DBufferArray());
const u32 used_space = Common::AlignUpPow2(size, UNIFORM_BUFFER_ALIGNMENT);
const UINT first_constant = m_uniform_buffer.GetPosition() / 16u;
const UINT num_constants = used_space / 16u;
m_uniform_buffer.Unmap(m_context.Get(), used_space);
m_context->VSSetConstantBuffers1(0, 1, m_uniform_buffer.GetD3DBufferArray(), &first_constant, &num_constants);
m_context->PSSetConstantBuffers1(0, 1, m_uniform_buffer.GetD3DBufferArray(), &first_constant, &num_constants);
}
void D3D11Device::SetFramebuffer(GPUFramebuffer* fb)
@ -2186,231 +2202,3 @@ void D3D11Device::DrawIndexed(u32 index_count, u32 base_index, u32 base_vertex)
PreDrawCheck();
m_context->DrawIndexed(index_count, base_index, base_vertex);
}
#if 0
struct PostProcessingStage
{
ComPtr<ID3D11VertexShader> vertex_shader;
ComPtr<ID3D11PixelShader> pixel_shader;
D3D11Texture output_texture;
u32 uniforms_size;
};
bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height);
void ApplyPostProcessingChain(ID3D11RenderTargetView* final_target, s32 final_left, s32 final_top, s32 final_width,
s32 final_height, D3D11Texture* texture, s32 texture_view_x, s32 texture_view_y,
s32 texture_view_width, s32 texture_view_height, u32 target_width, u32 target_height);
FrontendCommon::PostProcessingChain m_post_processing_chain;
D3D11Texture m_post_processing_input_texture;
std::vector<PostProcessingStage> m_post_processing_stages;
Common::Timer m_post_processing_timer;
bool D3D11Device::SetPostProcessingChain(const std::string_view& config)
{
if (config.empty())
{
m_post_processing_input_texture.Destroy();
m_post_processing_stages.clear();
m_post_processing_chain.ClearStages();
return true;
}
if (!m_post_processing_chain.CreateFromString(config))
return false;
m_post_processing_stages.clear();
D3D11::ShaderCache shader_cache;
shader_cache.Open(EmuFolders::Cache, m_device->GetFeatureLevel(), SHADER_CACHE_VERSION,
g_settings.gpu_use_debug_device);
FrontendCommon::PostProcessingShaderGen shadergen(RenderAPI::D3D11, true);
u32 max_ubo_size = 0;
for (u32 i = 0; i < m_post_processing_chain.GetStageCount(); i++)
{
const FrontendCommon::PostProcessingShader& shader = m_post_processing_chain.GetShaderStage(i);
const std::string vs = shadergen.GeneratePostProcessingVertexShader(shader);
const std::string ps = shadergen.GeneratePostProcessingFragmentShader(shader);
PostProcessingStage stage;
stage.uniforms_size = shader.GetUniformsSize();
stage.vertex_shader = shader_cache.GetVertexShader(m_device.Get(), vs);
stage.pixel_shader = shader_cache.GetPixelShader(m_device.Get(), ps);
if (!stage.vertex_shader || !stage.pixel_shader)
{
Log_ErrorPrintf("Failed to compile one or more post-processing shaders, disabling.");
m_post_processing_stages.clear();
m_post_processing_chain.ClearStages();
return false;
}
max_ubo_size = std::max(max_ubo_size, stage.uniforms_size);
m_post_processing_stages.push_back(std::move(stage));
}
if (m_push_uniform_buffer.GetSize() < max_ubo_size &&
!m_push_uniform_buffer.Create(m_device.Get(), D3D11_BIND_CONSTANT_BUFFER, max_ubo_size))
{
Log_ErrorPrintf("Failed to allocate %u byte constant buffer for postprocessing", max_ubo_size);
m_post_processing_stages.clear();
m_post_processing_chain.ClearStages();
return false;
}
m_post_processing_timer.Reset();
return true;
}
bool D3D11Device::CheckPostProcessingRenderTargets(u32 target_width, u32 target_height)
{
DebugAssert(!m_post_processing_stages.empty());
const GPUTexture::Type type = GPUTexture::Type::RenderTarget;
const GPUTexture::Format format = GPUTexture::Format::RGBA8;
if (m_post_processing_input_texture.GetWidth() != target_width ||
m_post_processing_input_texture.GetHeight() != target_height)
{
if (!m_post_processing_input_texture.Create(m_device.Get(), target_width, target_height, 1, 1, 1, type, format))
return false;
}
const u32 target_count = (static_cast<u32>(m_post_processing_stages.size()) - 1);
for (u32 i = 0; i < target_count; i++)
{
PostProcessingStage& pps = m_post_processing_stages[i];
if (pps.output_texture.GetWidth() != target_width || pps.output_texture.GetHeight() != target_height)
{
if (!pps.output_texture.Create(m_device.Get(), target_width, target_height, 1, 1, 1, type, format))
return false;
}
}
return true;
}
void D3D11Device::ApplyPostProcessingChain(ID3D11RenderTargetView* final_target, s32 final_left, s32 final_top,
s32 final_width, s32 final_height, D3D11Texture* texture, s32 texture_view_x,
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height,
u32 target_width, u32 target_height)
{
if (!CheckPostProcessingRenderTargets(target_width, target_height))
{
RenderDisplay(final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y,
texture_view_width, texture_view_height, IsUsingLinearFiltering());
return;
}
// downsample/upsample - use same viewport for remainder
m_context->ClearRenderTargetView(m_post_processing_input_texture.GetD3DRTV(), s_clear_color.data());
m_context->OMSetRenderTargets(1, m_post_processing_input_texture.GetD3DRTVArray(), nullptr);
RenderDisplay(final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y,
texture_view_width, texture_view_height, IsUsingLinearFiltering());
const s32 orig_texture_width = texture_view_width;
const s32 orig_texture_height = texture_view_height;
texture = &m_post_processing_input_texture;
texture_view_x = final_left;
texture_view_y = final_top;
texture_view_width = final_width;
texture_view_height = final_height;
const u32 final_stage = static_cast<u32>(m_post_processing_stages.size()) - 1u;
for (u32 i = 0; i < static_cast<u32>(m_post_processing_stages.size()); i++)
{
PostProcessingStage& pps = m_post_processing_stages[i];
ID3D11RenderTargetView* rtv = (i == final_stage) ? final_target : pps.output_texture.GetD3DRTV();
m_context->ClearRenderTargetView(rtv, s_clear_color.data());
m_context->OMSetRenderTargets(1, &rtv, nullptr);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->VSSetShader(pps.vertex_shader.Get(), nullptr, 0);
m_context->PSSetShader(pps.pixel_shader.Get(), nullptr, 0);
m_context->PSSetShaderResources(0, 1, texture->GetD3DSRVArray());
m_context->PSSetSamplers(0, 1, m_border_sampler.GetAddressOf());
const auto map = m_push_uniform_buffer.Map(m_context.Get(), m_push_uniform_buffer.GetSize(), pps.uniforms_size);
m_post_processing_chain.GetShaderStage(i).FillUniformBuffer(
map.pointer, texture->GetWidth(), texture->GetHeight(), texture_view_x, texture_view_y, texture_view_width,
texture_view_height, GetWindowWidth(), GetWindowHeight(), orig_texture_width, orig_texture_height,
static_cast<float>(m_post_processing_timer.GetTimeSeconds()));
m_push_uniform_buffer.Unmap(m_context.Get(), pps.uniforms_size);
m_context->VSSetConstantBuffers(0, 1, m_push_uniform_buffer.GetD3DBufferArray());
m_context->PSSetConstantBuffers(0, 1, m_push_uniform_buffer.GetD3DBufferArray());
m_context->Draw(3, 0);
if (i != final_stage)
texture = &pps.output_texture;
}
ID3D11ShaderResourceView* null_srv = nullptr;
m_context->PSSetShaderResources(0, 1, &null_srv);
}
void D3D11Device::RenderDisplay()
{
const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight());
if (HasDisplayTexture() && !m_post_processing_chain.IsEmpty())
{
ApplyPostProcessingChain(m_swap_chain_rtv.Get(), left, top, width, height,
static_cast<D3D11Texture*>(m_display_texture), m_display_texture_view_x,
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
GetWindowWidth(), GetWindowHeight());
return;
}
m_context->ClearRenderTargetView(m_swap_chain_rtv.Get(), s_clear_color.data());
m_context->OMSetRenderTargets(1, m_swap_chain_rtv.GetAddressOf(), nullptr);
if (!HasDisplayTexture())
return;
RenderDisplay(left, top, width, height, static_cast<D3D11Texture*>(m_display_texture), m_display_texture_view_x,
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
IsUsingLinearFiltering());
}
bool D3D11Device::RenderScreenshot(u32 width, u32 height, const Common::Rectangle<s32>& draw_rect,
std::vector<u32>* out_pixels, u32* out_stride, GPUTexture::Format* out_format)
{
static constexpr GPUTexture::Format hdformat = GPUTexture::Format::RGBA8;
D3D11Texture render_texture;
if (!render_texture.Create(m_device.Get(), width, height, 1, 1, 1, GPUTexture::Type::RenderTarget, hdformat))
return false;
static constexpr std::array<float, 4> clear_color = {};
m_context->ClearRenderTargetView(render_texture.GetD3DRTV(), clear_color.data());
m_context->OMSetRenderTargets(1, render_texture.GetD3DRTVArray(), nullptr);
if (HasDisplayTexture())
{
if (!m_post_processing_chain.IsEmpty())
{
ApplyPostProcessingChain(render_texture.GetD3DRTV(), draw_rect.left, draw_rect.top, draw_rect.GetWidth(),
draw_rect.GetHeight(), static_cast<D3D11Texture*>(m_display_texture),
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
m_display_texture_view_height, width, height);
}
else
{
RenderDisplay(draw_rect.left, draw_rect.top, draw_rect.GetWidth(), draw_rect.GetHeight(),
static_cast<D3D11Texture*>(m_display_texture), m_display_texture_view_x, m_display_texture_view_y,
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
}
}
m_context->OMSetRenderTargets(0, nullptr, nullptr);
const u32 stride = GPUTexture::GetPixelSize(hdformat) * width;
out_pixels->resize(width * height);
if (!DownloadTexture(&render_texture, 0, 0, width, height, out_pixels->data(), stride))
return false;
*out_stride = stride;
*out_format = hdformat;
return true;
}
#endif

View File

@ -264,10 +264,7 @@ public:
~D3D11Device();
RenderAPI GetRenderAPI() const override;
void* GetDevice() const override;
void* GetContext() const override;
bool HasDevice() const override;
bool HasSurface() const override;
bool CreateDevice(const WindowInfo& wi, bool vsync) override;
@ -353,10 +350,10 @@ private:
using InputLayoutMap =
std::unordered_map<GPUPipeline::InputLayout, ComPtr<ID3D11InputLayout>, GPUPipeline::InputLayoutHash>;
// Currently we don't stream uniforms, instead just re-map the buffer every time and let the driver take care of it.
static constexpr u32 MAX_UNIFORM_BUFFER_SIZE = 64;
static constexpr u32 VERTEX_BUFFER_SIZE = 8 * 1024 * 1024;
static constexpr u32 INDEX_BUFFER_SIZE = 4 * 1024 * 1024;
static constexpr u32 UNIFORM_BUFFER_SIZE = 2 * 1024 * 1024;
static constexpr u32 UNIFORM_BUFFER_ALIGNMENT = 256;
static constexpr u8 NUM_TIMESTAMP_QUERIES = 3;
static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory);
@ -384,13 +381,14 @@ private:
void PopTimestampQuery();
void KickTimestampQuery();
ComPtr<ID3D11Device> m_device;
ComPtr<ID3D11DeviceContext> m_context;
ComPtr<ID3D11Device1> m_device;
ComPtr<ID3D11DeviceContext1> m_context;
ComPtr<ID3DUserDefinedAnnotation> m_annotation;
ComPtr<IDXGIFactory> m_dxgi_factory;
ComPtr<IDXGISwapChain> m_swap_chain;
ComPtr<ID3D11RenderTargetView> m_swap_chain_rtv;
std::unique_ptr<D3D11Texture> m_swap_chain_texture;
std::unique_ptr<D3D11Framebuffer> m_swap_chain_framebuffer;
RasterizationStateMap m_rasterization_states;
DepthStateMap m_depth_states;

View File

@ -37,21 +37,6 @@ RenderAPI D3D12GPUDevice::GetRenderAPI() const
return RenderAPI::D3D12;
}
void* D3D12GPUDevice::GetDevice() const
{
return g_d3d12_context->GetDevice();
}
void* D3D12GPUDevice::GetContext() const
{
return g_d3d12_context.get();
}
bool D3D12GPUDevice::HasDevice() const
{
return static_cast<bool>(g_d3d12_context);
}
bool D3D12GPUDevice::HasSurface() const
{
return static_cast<bool>(m_swap_chain);
@ -472,6 +457,7 @@ bool D3D12GPUDevice::CreateResources()
if (!m_display_root_signature)
return false;
#if 0
rsbuilder.SetInputAssemblerFlag();
rsbuilder.Add32BitConstants(0, FrontendCommon::PostProcessingShader::PUSH_CONSTANT_SIZE_THRESHOLD / sizeof(u32),
D3D12_SHADER_VISIBILITY_ALL);
@ -488,6 +474,7 @@ bool D3D12GPUDevice::CreateResources()
m_post_processing_cb_root_signature = rsbuilder.Create();
if (!m_post_processing_cb_root_signature)
return false;
#endif
D3D12::GraphicsPipelineBuilder gpbuilder;
gpbuilder.SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
@ -546,12 +533,14 @@ void D3D12GPUDevice::DestroyResources()
{
GPUDevice::DestroyResources();
#if 0
m_post_processing_cbuffer.Destroy(false);
m_post_processing_chain.ClearStages();
m_post_processing_input_texture.Destroy();
m_post_processing_stages.clear();
m_post_processing_cb_root_signature.Reset();
m_post_processing_root_signature.Reset();
#endif
m_readback_staging_texture.Destroy(false);
g_d3d12_context->GetSamplerHeapManager().Free(&m_border_sampler);
@ -638,6 +627,7 @@ void D3D12GPUDevice::RenderDisplay(ID3D12GraphicsCommandList* cmdlist, D3D12::Te
{
const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight());
#if 0
if (HasDisplayTexture() && !m_post_processing_chain.IsEmpty())
{
ApplyPostProcessingChain(cmdlist, swap_chain_buf, left, top, width, height,
@ -646,6 +636,7 @@ void D3D12GPUDevice::RenderDisplay(ID3D12GraphicsCommandList* cmdlist, D3D12::Te
GetWindowWidth(), GetWindowHeight());
return;
}
#endif
swap_chain_buf->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
cmdlist->ClearRenderTargetView(swap_chain_buf->GetRTVOrDSVDescriptor(), s_clear_color.data(), 0, nullptr);
@ -787,6 +778,7 @@ GPUDevice::AdapterAndModeList D3D12GPUDevice::GetAdapterAndModeList(IDXGIFactory
return adapter_info;
}
#if 0
D3D12GPUDevice::PostProcessingStage::PostProcessingStage(PostProcessingStage&& move)
: pipeline(std::move(move.pipeline)), output_texture(std::move(move.output_texture)),
uniforms_size(move.uniforms_size)
@ -798,9 +790,11 @@ D3D12GPUDevice::PostProcessingStage::~PostProcessingStage()
{
output_texture.Destroy(true);
}
#endif
bool D3D12GPUDevice::SetPostProcessingChain(const std::string_view& config)
{
#if 0
g_d3d12_context->ExecuteCommandList(true);
if (config.empty())
@ -882,8 +876,12 @@ bool D3D12GPUDevice::SetPostProcessingChain(const std::string_view& config)
m_post_processing_timer.Reset();
return true;
#else
return false;
#endif
}
#if 0
bool D3D12GPUDevice::CheckPostProcessingRenderTargets(u32 target_width, u32 target_height)
{
DebugAssert(!m_post_processing_stages.empty());
@ -1011,3 +1009,4 @@ void D3D12GPUDevice::ApplyPostProcessingChain(ID3D12GraphicsCommandList* cmdlist
}
}
}
#endif

View File

@ -29,10 +29,7 @@ public:
~D3D12GPUDevice();
RenderAPI GetRenderAPI() const override;
void* GetDevice() const override;
void* GetContext() const override;
bool HasDevice() const override;
bool HasSurface() const override;
bool CreateDevice(const WindowInfo& wi, bool vsync) override;
@ -70,17 +67,6 @@ public:
static AdapterAndModeList StaticGetAdapterAndModeList();
protected:
struct PostProcessingStage
{
PostProcessingStage() = default;
PostProcessingStage(PostProcessingStage&& move);
~PostProcessingStage();
ComPtr<ID3D12PipelineState> pipeline;
D3D12::Texture output_texture;
u32 uniforms_size = 0;
};
static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory);
virtual bool CreateResources() override;
@ -100,12 +86,6 @@ protected:
void RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height,
GPUTexture* texture_handle);
bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height);
void ApplyPostProcessingChain(ID3D12GraphicsCommandList* cmdlist, D3D12::Texture* final_target, s32 final_left,
s32 final_top, s32 final_width, s32 final_height, D3D12::Texture* texture,
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height,
u32 target_width, u32 target_height);
ComPtr<IDXGIFactory> m_dxgi_factory;
ComPtr<IDXGISwapChain> m_swap_chain;
std::vector<D3D12::Texture> m_swap_chain_buffers;
@ -121,14 +101,6 @@ protected:
D3D12::Texture m_display_pixels_texture;
D3D12::StagingTexture m_readback_staging_texture;
ComPtr<ID3D12RootSignature> m_post_processing_root_signature;
ComPtr<ID3D12RootSignature> m_post_processing_cb_root_signature;
FrontendCommon::PostProcessingChain m_post_processing_chain;
D3D12::StreamBuffer m_post_processing_cbuffer;
D3D12::Texture m_post_processing_input_texture;
std::vector<PostProcessingStage> m_post_processing_stages;
Common::Timer m_post_processing_timer;
bool m_allow_tearing_supported = false;
bool m_using_allow_tearing = false;
};

View File

@ -4,6 +4,8 @@
#include "gpu_device.h"
#include "../settings.h"
#include "../shadergen.h"
#include "postprocessing_chain.h"
#include "common/align.h"
#include "common/assert.h"
#include "common/file_system.h"
@ -12,15 +14,18 @@
#include "common/path.h"
#include "common/string_util.h"
#include "common/timer.h"
#include "imgui.h"
#include "stb_image.h"
#include "stb_image_resize.h"
#include "stb_image_write.h"
#include <cerrno>
#include <cmath>
#include <cstring>
#include <thread>
#include <vector>
Log_SetChannel(GPUDevice);
// FIXME
@ -43,6 +48,28 @@ GPUSampler::GPUSampler() = default;
GPUSampler::~GPUSampler() = default;
GPUSampler::Config GPUSampler::GetNearestConfig()
{
Config config = {};
config.address_u = GPUSampler::AddressMode::ClampToEdge;
config.address_v = GPUSampler::AddressMode::ClampToEdge;
config.address_w = GPUSampler::AddressMode::ClampToEdge;
config.min_filter = GPUSampler::Filter::Nearest;
config.mag_filter = GPUSampler::Filter::Nearest;
return config;
}
GPUSampler::Config GPUSampler::GetLinearConfig()
{
Config config = {};
config.address_u = GPUSampler::AddressMode::ClampToEdge;
config.address_v = GPUSampler::AddressMode::ClampToEdge;
config.address_w = GPUSampler::AddressMode::ClampToEdge;
config.min_filter = GPUSampler::Filter::Linear;
config.mag_filter = GPUSampler::Filter::Linear;
return config;
}
GPUShader::GPUShader(GPUShaderStage stage) : m_stage(stage)
{
}
@ -188,32 +215,16 @@ bool GPUDevice::SetupDevice()
bool GPUDevice::CreateResources()
{
GPUSampler::Config spconfig = {};
spconfig.address_u = GPUSampler::AddressMode::ClampToEdge;
spconfig.address_v = GPUSampler::AddressMode::ClampToEdge;
spconfig.address_w = GPUSampler::AddressMode::ClampToEdge;
spconfig.min_filter = GPUSampler::Filter::Nearest;
spconfig.mag_filter = GPUSampler::Filter::Nearest;
if (!(m_point_sampler = CreateSampler(spconfig)))
if (!(m_nearest_sampler = CreateSampler(GPUSampler::GetNearestConfig())))
return false;
spconfig.min_filter = GPUSampler::Filter::Linear;
spconfig.mag_filter = GPUSampler::Filter::Linear;
if (!(m_linear_sampler = CreateSampler(spconfig)))
if (!(m_linear_sampler = CreateSampler(GPUSampler::GetLinearConfig())))
return false;
spconfig.mag_filter = GPUSampler::Filter::Nearest;
spconfig.mag_filter = GPUSampler::Filter::Nearest;
spconfig.address_u = GPUSampler::AddressMode::ClampToBorder;
spconfig.address_v = GPUSampler::AddressMode::ClampToBorder;
spconfig.border_color = 0xFF000000u;
if (!(m_border_sampler = CreateSampler(spconfig)))
return false;
ShaderGen shadergen(GetRenderAPI(), /*FIXME DSB*/ true);
ShaderGen shadergen(GetRenderAPI(), m_features.dual_source_blend);
GPUPipeline::GraphicsConfig plconfig;
plconfig.layout = GPUPipeline::Layout::SingleTexture;
plconfig.layout = GPUPipeline::Layout::SingleTexturePushConstants;
plconfig.primitive = GPUPipeline::Primitive::Triangles;
plconfig.rasterization = GPUPipeline::RasterizationState::GetNoCullState();
plconfig.depth = GPUPipeline::DepthState::GetNoTestsState();
@ -235,13 +246,13 @@ bool GPUDevice::CreateResources()
GL_OBJECT_NAME(cursor_fs, "Cursor Fragment Shader");
plconfig.vertex_shader = display_vs.get();
plconfig.pixel_shader = display_fs.get();
plconfig.fragment_shader = display_fs.get();
if (!(m_display_pipeline = CreatePipeline(plconfig)))
return false;
GL_OBJECT_NAME(m_display_pipeline, "Display Pipeline");
plconfig.blend = GPUPipeline::BlendState::GetAlphaBlendingState();
plconfig.pixel_shader = cursor_fs.get();
plconfig.fragment_shader = cursor_fs.get();
if (!(m_cursor_pipeline = CreatePipeline(plconfig)))
return false;
GL_OBJECT_NAME(m_cursor_pipeline, "Cursor Pipeline");
@ -262,7 +273,7 @@ bool GPUDevice::CreateResources()
plconfig.input_layout.vertex_attributes = imgui_attributes;
plconfig.input_layout.vertex_stride = sizeof(ImDrawVert);
plconfig.vertex_shader = imgui_vs.get();
plconfig.pixel_shader = imgui_fs.get();
plconfig.fragment_shader = imgui_fs.get();
m_imgui_pipeline = CreatePipeline(plconfig);
if (!m_imgui_pipeline)
@ -287,14 +298,33 @@ void GPUDevice::DestroyResources()
m_imgui_pipeline.reset();
m_linear_sampler.reset();
m_point_sampler.reset();
m_nearest_sampler.reset();
m_shader_cache.Close();
}
bool GPUDevice::SetPostProcessingChain(const std::string_view& config)
{
return false;
static constexpr GPUTexture::Format hdformat = GPUTexture::Format::RGBA8; // TODO FIXME m_window_info.surface_format
m_post_processing_chain.reset();
if (config.empty())
return true;
m_post_processing_chain = std::make_unique<PostProcessingChain>();
if (!m_post_processing_chain->CreateFromString(config) || !m_post_processing_chain->CompilePipelines(hdformat))
{
m_post_processing_chain.reset();
return false;
}
else if (m_post_processing_chain->IsEmpty())
{
m_post_processing_chain.reset();
return true;
}
return true;
}
std::string GPUDevice::GetShaderCacheBaseName(const std::string_view& type, bool debug) const
@ -862,26 +892,10 @@ bool GPUDevice::RenderScreenshot(u32 width, u32 height, const Common::Rectangle<
return false;
ClearRenderTarget(render_texture.get(), 0);
SetFramebuffer(render_fb.get());
if (HasDisplayTexture())
{
#if 0
if (!m_post_processing_chain.IsEmpty())
{
ApplyPostProcessingChain(render_texture.GetD3DRTV(), draw_rect.left, draw_rect.top, draw_rect.GetWidth(),
draw_rect.GetHeight(), static_cast<D3D11Texture*>(m_display_texture),
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
m_display_texture_view_height, width, height);
}
else
#endif
{
RenderDisplay(draw_rect.left, draw_rect.top, draw_rect.GetWidth(), draw_rect.GetHeight(), m_display_texture,
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
m_display_texture_view_height, IsUsingLinearFiltering());
}
}
RenderDisplay(render_fb.get(), draw_rect.left, draw_rect.top, draw_rect.GetWidth(), draw_rect.GetHeight(),
m_display_texture, m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
m_display_texture_view_height, IsUsingLinearFiltering());
SetFramebuffer(nullptr);
@ -895,35 +909,27 @@ bool GPUDevice::RenderScreenshot(u32 width, u32 height, const Common::Rectangle<
return true;
}
void GPUDevice::RenderDisplay()
void GPUDevice::RenderDisplay(GPUFramebuffer* target, s32 left, s32 top, s32 width, s32 height, GPUTexture* texture,
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height,
bool linear_filter)
{
const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight());
GL_SCOPE("RenderDisplay: %dx%d at %d,%d", left, top, width, height);
#if 0
if (HasDisplayTexture() && !m_post_processing_chain.IsEmpty())
static constexpr GPUTexture::Format hdformat = GPUTexture::Format::RGBA8; // TODO FIXME m_window_info.surface_format
const u32 target_width = target ? target->GetWidth() : m_window_info.surface_width;
const u32 target_height = target ? target->GetHeight() : m_window_info.surface_height;
const bool postfx =
(m_post_processing_chain && m_post_processing_chain->CheckTargets(hdformat, target_width, target_height));
if (postfx)
{
ApplyPostProcessingChain(m_swap_chain_rtv.Get(), left, top, width, height,
static_cast<D3D11Texture*>(m_display_texture), m_display_texture_view_x,
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
GetWindowWidth(), GetWindowHeight());
return;
ClearRenderTarget(m_post_processing_chain->GetInputTexture(), 0);
SetFramebuffer(m_post_processing_chain->GetInputFramebuffer());
}
else
{
SetFramebuffer(target);
}
#endif
if (!HasDisplayTexture())
return;
RenderDisplay(left, top, width, height, m_display_texture, m_display_texture_view_x, m_display_texture_view_y,
m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering());
}
void GPUDevice::RenderDisplay(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture, s32 texture_view_x,
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, bool linear_filter)
{
SetPipeline(m_display_pipeline.get());
SetTextureSampler(0, texture, linear_filter ? m_linear_sampler.get() : m_point_sampler.get());
SetTextureSampler(0, texture, linear_filter ? m_linear_sampler.get() : m_nearest_sampler.get());
const bool linear = IsUsingLinearFiltering();
const float position_adjust = linear ? 0.5f : 0.0f;
@ -937,6 +943,12 @@ void GPUDevice::RenderDisplay(s32 left, s32 top, s32 width, s32 height, GPUTextu
SetViewportAndScissor(left, top, width, height);
Draw(3, 0);
if (postfx)
{
m_post_processing_chain->Apply(target, left, top, width, height, texture_view_width, texture_view_height,
target_width, target_height);
}
}
void GPUDevice::RenderSoftwareCursor()

View File

@ -89,6 +89,9 @@ public:
virtual ~GPUSampler();
virtual void SetDebugName(const std::string_view& name) = 0;
static Config GetNearestConfig();
static Config GetLinearConfig();
};
enum class GPUShaderStage : u8
@ -119,11 +122,11 @@ class GPUPipeline
public:
enum class Layout : u8
{
// 128 byte UBO via push constants, 1 texture.
SingleTexture,
// 1 streamed UBO, 1 texture in PS.
HWBatch,
SingleTextureUBO,
// 128 byte UBO via push constants, 1 texture.
SingleTexturePushConstants,
MaxCount
};
@ -254,6 +257,7 @@ public:
MaxCount
};
// TODO: purge this?
union RasterizationState
{
BitField<u8, CullMode, 0, 2> cull_mode;
@ -326,7 +330,7 @@ public:
BlendState blend;
const GPUShader* vertex_shader;
const GPUShader* pixel_shader;
const GPUShader* fragment_shader;
GPUTexture::Format color_format;
GPUTexture::Format depth_format;
@ -369,6 +373,9 @@ protected:
u32 m_current_position;
};
// TODO: remove
class PostProcessingChain;
class GPUDevice
{
public:
@ -412,7 +419,7 @@ public:
ALWAYS_INLINE float GetWindowScale() const { return m_window_info.surface_scale; }
ALWAYS_INLINE GPUSampler* GetLinearSampler() const { return m_linear_sampler.get(); }
ALWAYS_INLINE GPUSampler* GetPointSampler() const { return m_point_sampler.get(); }
ALWAYS_INLINE GPUSampler* GetNearestSampler() const { return m_nearest_sampler.get(); }
// Position is relative to the top-left corner of the window.
ALWAYS_INLINE s32 GetMousePositionX() const { return m_mouse_position_x; }
@ -430,22 +437,21 @@ public:
ALWAYS_INLINE bool IsGPUTimingEnabled() const { return m_gpu_timing_enabled; }
virtual RenderAPI GetRenderAPI() const = 0;
virtual void* GetDevice() const = 0;
virtual void* GetContext() const = 0;
virtual bool HasDevice() const = 0;
virtual bool HasSurface() const = 0;
virtual bool CreateDevice(const WindowInfo& wi, bool vsync) = 0;
virtual bool SetupDevice();
virtual bool MakeCurrent() = 0;
virtual bool DoneCurrent() = 0;
virtual bool HasSurface() const = 0;
virtual void DestroySurface() = 0;
virtual bool ChangeWindow(const WindowInfo& wi) = 0;
virtual bool SupportsFullscreen() const = 0;
virtual bool IsFullscreen() = 0;
virtual bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) = 0;
virtual AdapterAndModeList GetAdapterAndModeList() = 0;
virtual bool CreateResources();
virtual void DestroyResources();
@ -605,11 +611,11 @@ protected:
void RenderImGui();
void RenderDisplay();
void RenderSoftwareCursor();
void RenderDisplay(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture, s32 texture_view_x,
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, bool linear_filter);
void RenderDisplay(GPUFramebuffer* target, s32 left, s32 top, s32 width, s32 height, GPUTexture* texture,
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height,
bool linear_filter);
void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture);
Features m_features = {};
@ -620,9 +626,8 @@ protected:
GPUShaderCache m_shader_cache;
std::unique_ptr<GPUSampler> m_point_sampler;
std::unique_ptr<GPUSampler> m_nearest_sampler;
std::unique_ptr<GPUSampler> m_linear_sampler;
std::unique_ptr<GPUSampler> m_border_sampler;
u64 m_last_frame_displayed_time = 0;
@ -655,6 +660,8 @@ protected:
bool m_display_changed = false;
bool m_gpu_timing_enabled = false;
bool m_vsync_enabled = false;
std::unique_ptr<PostProcessingChain> m_post_processing_chain;
};
/// Returns a pointer to the current host display abstraction. Assumes AcquireHostDisplay() has been called.

View File

@ -37,16 +37,6 @@ RenderAPI OpenGLGPUDevice::GetRenderAPI() const
return m_gl_context->IsGLES() ? RenderAPI::OpenGLES : RenderAPI::OpenGL;
}
void* OpenGLGPUDevice::GetDevice() const
{
return nullptr;
}
void* OpenGLGPUDevice::GetContext() const
{
return m_gl_context.get();
}
std::unique_ptr<GPUTexture> OpenGLGPUDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
GPUTexture::Type type, GPUTexture::Format format,
const void* data, u32 data_stride,
@ -273,11 +263,6 @@ static void APIENTRY GLDebugCallback(GLenum source, GLenum type, GLuint id, GLen
}
}
bool OpenGLGPUDevice::HasDevice() const
{
return static_cast<bool>(m_gl_context);
}
bool OpenGLGPUDevice::HasSurface() const
{
return m_window_info.type != WindowInfo::Type::Surfaceless;
@ -623,10 +608,12 @@ void OpenGLGPUDevice::DestroyResources()
{
GPUDevice::DestroyResources();
#if 0
m_post_processing_chain.ClearStages();
m_post_processing_input_texture.Destroy();
m_post_processing_ubo.reset();
m_post_processing_stages.clear();
#endif
if (m_display_vao != 0)
{
@ -695,6 +682,7 @@ void OpenGLGPUDevice::RenderDisplay()
{
const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight());
#if 0
if (HasDisplayTexture() && !m_post_processing_chain.IsEmpty())
{
ApplyPostProcessingChain(0, left, GetWindowHeight() - top - height, width, height,
@ -703,6 +691,7 @@ void OpenGLGPUDevice::RenderDisplay()
GetWindowWidth(), GetWindowHeight());
return;
}
#endif
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT);
@ -817,6 +806,7 @@ void OpenGLGPUDevice::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32
bool OpenGLGPUDevice::SetPostProcessingChain(const std::string_view& config)
{
#if 0
if (config.empty())
{
m_post_processing_input_texture.Destroy();
@ -882,8 +872,12 @@ bool OpenGLGPUDevice::SetPostProcessingChain(const std::string_view& config)
m_post_processing_timer.Reset();
return true;
#else
return false;
#endif
}
#if 0
bool OpenGLGPUDevice::CheckPostProcessingRenderTargets(u32 target_width, u32 target_height)
{
DebugAssert(!m_post_processing_stages.empty());
@ -973,7 +967,7 @@ void OpenGLGPUDevice::ApplyPostProcessingChain(GLuint final_target, s32 final_le
glBindSampler(0, 0);
m_post_processing_ubo->Unbind();
}
#endif
void OpenGLGPUDevice::CreateTimestampQueries()
{
const bool gles = m_gl_context->IsGLES();

View File

@ -20,10 +20,7 @@ public:
~OpenGLGPUDevice();
RenderAPI GetRenderAPI() const override;
void* GetDevice() const override;
void* GetContext() const override;
bool HasDevice() const override;
bool HasSurface() const override;
bool CreateDevice(const WindowInfo& wi, bool vsync) override;
@ -82,18 +79,6 @@ protected:
s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, bool linear_filter);
void RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32 height, GPUTexture* texture_handle);
struct PostProcessingStage
{
GL::Program program;
GL::Texture output_texture;
u32 uniforms_size;
};
bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height);
void ApplyPostProcessingChain(GLuint final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height,
GL::Texture* texture, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width,
s32 texture_view_height, u32 target_width, u32 target_height);
void CreateTimestampQueries();
void DestroyTimestampQueries();
void PopTimestampQuery();
@ -113,12 +98,6 @@ protected:
std::vector<u8> m_texture_repack_buffer;
u32 m_texture_stream_buffer_offset = 0;
FrontendCommon::PostProcessingChain m_post_processing_chain;
GL::Texture m_post_processing_input_texture;
std::unique_ptr<GL::StreamBuffer> m_post_processing_ubo;
std::vector<PostProcessingStage> m_post_processing_stages;
Common::Timer m_post_processing_timer;
std::array<GLuint, NUM_TIMESTAMP_QUERIES> m_timestamp_queries = {};
float m_accumulated_gpu_time = 0.0f;
u8 m_read_timestamp_query = 0;

View File

@ -1,19 +1,21 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "postprocessing_chain.h"
#include "../host.h"
#include "../settings.h"
#include "gpu_device.h"
#include "common/assert.h"
#include "common/file_system.h"
#include "common/log.h"
#include "common/string.h"
#include "common/path.h"
#include "core/host.h"
#include "core/settings.h"
#include "common/string.h"
#include "fmt/format.h"
#include <sstream>
Log_SetChannel(PostProcessingChain);
namespace FrontendCommon {
Log_SetChannel(PostProcessingChain);
static bool TryLoadingShader(PostProcessingShader* shader, const std::string_view& shader_name)
{
@ -24,7 +26,8 @@ static bool TryLoadingShader(PostProcessingShader* shader, const std::string_vie
return true;
}
std::optional<std::string> resource_str(Host::ReadResourceFileToString(fmt::format("shaders" FS_OSPATH_SEPARATOR_STR "{}.glsl", shader_name).c_str()));
std::optional<std::string> resource_str(
Host::ReadResourceFileToString(fmt::format("shaders" FS_OSPATH_SEPARATOR_STR "{}.glsl", shader_name).c_str()));
if (resource_str.has_value() && shader->LoadFromString(std::string(shader_name), std::move(resource_str.value())))
return true;
@ -115,6 +118,20 @@ bool PostProcessingChain::CreateFromString(const std::string_view& chain_config)
return true;
}
bool PostProcessingChain::CompilePipelines(GPUTexture::Format target_format)
{
for (PostProcessingShader& stage : m_shaders)
{
if (!stage.CompilePipeline(target_format))
{
Log_ErrorPrintf("Failed to compile one or more post-processing shaders, disabling.");
return false;
}
}
return true;
}
std::vector<std::string> PostProcessingChain::GetAvailableShaderNames()
{
std::vector<std::string> names;
@ -182,4 +199,93 @@ void PostProcessingChain::ClearStages()
m_shaders.clear();
}
} // namespace FrontendCommon
bool PostProcessingChain::CheckTargets(GPUTexture::Format format, u32 target_width, u32 target_height)
{
if (!m_input_texture || m_input_texture->GetFormat() != format || m_input_texture->GetWidth() != target_width ||
m_input_texture->GetHeight() != target_height)
{
m_input_framebuffer.reset();
m_input_texture.reset();
if (!(m_input_texture = g_host_display->CreateTexture(target_width, target_height, 1, 1, 1,
GPUTexture::Type::RenderTarget, format)))
{
return false;
}
if (!(m_input_framebuffer = g_host_display->CreateFramebuffer(m_input_texture.get())))
{
m_input_texture.reset();
return false;
}
}
const PostProcessingShader& final_stage = m_shaders.back();
for (PostProcessingShader& shader : m_shaders)
{
if (&shader == &final_stage)
continue;
if (!shader.ResizeOutput(format, target_width, target_height))
return false;
}
if (!m_border_sampler)
{
GPUSampler::Config config = GPUSampler::GetNearestConfig();
config.address_u = GPUSampler::AddressMode::ClampToBorder;
config.address_v = GPUSampler::AddressMode::ClampToBorder;
config.border_color = 0xFF000000u;
if (!(m_border_sampler = g_host_display->CreateSampler(config)))
return false;
}
return true;
}
void PostProcessingChain::Apply(GPUFramebuffer* final_target, s32 final_left, s32 final_top, s32 final_width,
s32 final_height, s32 orig_width, s32 orig_height, u32 target_width, u32 target_height)
{
const u32 window_width = final_target ? final_target->GetWidth() : g_host_display->GetWindowWidth();
const u32 window_height = final_target ? final_target->GetHeight() : g_host_display->GetWindowHeight();
GL_PUSH("PostProcessingChain Apply");
g_host_display->SetViewportAndScissor(final_left, final_top, final_width, final_height);
GPUTexture* input = m_input_texture.get();
input->MakeReadyForSampling();
const PostProcessingShader& final_stage = m_shaders.back();
for (PostProcessingShader& stage : m_shaders)
{
const bool is_final = (&stage == &final_stage);
GL_SCOPE("PostProcessingShader %s", stage.GetName().c_str());
// Assumes final stage has been cleared already.
if (!is_final)
g_host_display->ClearRenderTarget(stage.GetOutputTexture(), 0);
g_host_display->SetFramebuffer(is_final ? final_target : stage.GetOutputFramebuffer());
g_host_display->SetPipeline(stage.GetPipeline());
g_host_display->SetTextureSampler(0, input, m_border_sampler.get());
const u32 uniforms_size = stage.GetUniformsSize();
void* uniforms = g_host_display->MapUniformBuffer(uniforms_size);
stage.FillUniformBuffer(uniforms, input->GetWidth(), input->GetHeight(), final_left, final_top, final_width,
final_height, window_width, window_height, orig_width, orig_height,
static_cast<float>(m_timer.GetTimeSeconds()));
g_host_display->UnmapUniformBuffer(uniforms_size);
g_host_display->Draw(3, 0);
if (!is_final)
{
input = stage.GetOutputTexture();
input->MakeReadyForSampling();
}
}
GL_POP();
}

View File

@ -1,12 +1,19 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
#include "gpu_device.h"
#include "postprocessing_shader.h"
#include "common/timer.h"
#include <memory>
#include <string_view>
#include <vector>
namespace FrontendCommon {
class GPUSampler;
class GPUFramebuffer;
class GPUTexture;
class PostProcessingChain
{
@ -14,10 +21,14 @@ public:
PostProcessingChain();
~PostProcessingChain();
static std::vector<std::string> GetAvailableShaderNames();
ALWAYS_INLINE bool IsEmpty() const { return m_shaders.empty(); }
ALWAYS_INLINE u32 GetStageCount() const { return static_cast<u32>(m_shaders.size()); }
ALWAYS_INLINE const PostProcessingShader& GetShaderStage(u32 i) const { return m_shaders[i]; }
ALWAYS_INLINE PostProcessingShader& GetShaderStage(u32 i) { return m_shaders[i]; }
ALWAYS_INLINE GPUTexture* GetInputTexture() const { return m_input_texture.get(); }
ALWAYS_INLINE GPUFramebuffer* GetInputFramebuffer() const { return m_input_framebuffer.get(); }
void AddShader(PostProcessingShader shader);
bool AddStage(const std::string_view& name);
@ -29,11 +40,19 @@ public:
std::string GetConfigString() const;
bool CreateFromString(const std::string_view& chain_config);
bool CompilePipelines(GPUTexture::Format target_format);
static std::vector<std::string> GetAvailableShaderNames();
bool CheckTargets(GPUTexture::Format target_format, u32 target_width, u32 target_height);
void Apply(GPUFramebuffer* final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height,
s32 orig_width, s32 orig_height, u32 target_width, u32 target_height);
private:
std::vector<PostProcessingShader> m_shaders;
};
} // namespace FrontendCommon
std::unique_ptr<GPUSampler> m_border_sampler;
std::unique_ptr<GPUTexture> m_input_texture;
std::unique_ptr<GPUFramebuffer> m_input_framebuffer;
Common::Timer m_timer;
};

View File

@ -2,18 +2,19 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "postprocessing_shader.h"
#include "postprocessing_shadergen.h"
#include "common/file_system.h"
#include "common/log.h"
#include "common/string_util.h"
#include "core/shadergen.h"
#include <cctype>
#include <cstring>
#include <sstream>
Log_SetChannel(PostProcessingShader);
namespace FrontendCommon {
void ParseKeyValue(const std::string_view& line, std::string_view* key, std::string_view* value)
static void ParseKeyValue(const std::string_view& line, std::string_view* key, std::string_view* value)
{
size_t key_start = 0;
while (key_start < line.size() && std::isspace(line[key_start]))
@ -49,7 +50,7 @@ void ParseKeyValue(const std::string_view& line, std::string_view* key, std::str
}
template<typename T>
u32 ParseVector(const std::string_view& line, PostProcessingShader::Option::ValueVector* values)
static u32 ParseVector(const std::string_view& line, PostProcessingShader::Option::ValueVector* values)
{
u32 index = 0;
size_t start = 0;
@ -141,7 +142,7 @@ const PostProcessingShader::Option* PostProcessingShader::GetOptionByName(const
return nullptr;
}
FrontendCommon::PostProcessingShader::Option* PostProcessingShader::GetOptionByName(const std::string_view& name)
PostProcessingShader::Option* PostProcessingShader::GetOptionByName(const std::string_view& name)
{
for (Option& option : m_options)
{
@ -238,11 +239,6 @@ void PostProcessingShader::SetConfigString(const std::string_view& str)
}
}
bool PostProcessingShader::UsePushConstants() const
{
return GetUniformsSize() <= PUSH_CONSTANT_SIZE_THRESHOLD;
}
u32 PostProcessingShader::GetUniformsSize() const
{
// lazy packing. todo improve.
@ -293,7 +289,66 @@ void PostProcessingShader::FillUniformBuffer(void* buffer, u32 texture_width, s3
}
}
FrontendCommon::PostProcessingShader& PostProcessingShader::operator=(const PostProcessingShader& copy)
bool PostProcessingShader::CompilePipeline(GPUTexture::Format target_format)
{
if (m_pipeline)
m_pipeline.reset();
PostProcessingShaderGen shadergen(g_host_display->GetRenderAPI(), g_host_display->GetFeatures().dual_source_blend);
std::unique_ptr<GPUShader> vs =
g_host_display->CreateShader(GPUShaderStage::Vertex, shadergen.GeneratePostProcessingVertexShader(*this));
std::unique_ptr<GPUShader> fs =
g_host_display->CreateShader(GPUShaderStage::Fragment, shadergen.GeneratePostProcessingFragmentShader(*this));
if (!vs || !fs)
return false;
GPUPipeline::GraphicsConfig plconfig;
plconfig.layout = GPUPipeline::Layout::SingleTextureUBO;
plconfig.primitive = GPUPipeline::Primitive::Triangles;
plconfig.color_format = target_format;
plconfig.depth_format = GPUTexture::Format::Unknown;
plconfig.rasterization = GPUPipeline::RasterizationState::GetNoCullState();
plconfig.depth = GPUPipeline::DepthState::GetNoTestsState();
plconfig.blend = GPUPipeline::BlendState::GetNoBlendingState();
plconfig.samples = 1;
plconfig.per_sample_shading = false;
plconfig.vertex_shader = vs.get();
plconfig.fragment_shader = fs.get();
if (!(m_pipeline = g_host_display->CreatePipeline(plconfig)))
return false;
return true;
}
bool PostProcessingShader::ResizeOutput(GPUTexture::Format format, u32 width, u32 height)
{
if (m_output_texture && m_output_texture->GetFormat() == format && m_output_texture->GetWidth() == width &&
m_output_texture->GetHeight() == height)
{
return true;
}
m_output_framebuffer.reset();
m_output_texture.reset();
if (!(m_output_texture =
g_host_display->CreateTexture(width, height, 1, 1, 1, GPUTexture::Type::RenderTarget, format)))
{
return false;
}
if (!(m_output_framebuffer = g_host_display->CreateFramebuffer(m_output_texture.get())))
{
m_output_texture.reset();
return false;
}
return true;
}
PostProcessingShader& PostProcessingShader::operator=(const PostProcessingShader& copy)
{
m_name = copy.m_name;
m_code = copy.m_code;
@ -301,7 +356,7 @@ FrontendCommon::PostProcessingShader& PostProcessingShader::operator=(const Post
return *this;
}
FrontendCommon::PostProcessingShader& PostProcessingShader::operator=(PostProcessingShader& move)
PostProcessingShader& PostProcessingShader::operator=(PostProcessingShader& move)
{
m_name = std::move(move.m_name);
m_code = std::move(move.m_code);
@ -434,5 +489,3 @@ void PostProcessingShader::LoadOptions()
m_options.push_back(std::move(current_option));
}
}
} // namespace FrontendCommon

View File

@ -1,24 +1,29 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
#include "common/rectangle.h"
#include "core/types.h"
#include "gpu_device.h"
#include <array>
#include <string>
#include <string_view>
#include <vector>
namespace FrontendCommon {
class GPUPipeline;
class GPUTexture;
class PostProcessingChain;
class PostProcessingShaderGen;
class PostProcessingShader
{
public:
enum : u32
{
PUSH_CONSTANT_SIZE_THRESHOLD = 128
};
friend PostProcessingChain;
friend PostProcessingShaderGen;
public:
struct Option
{
enum : u32
@ -82,11 +87,7 @@ public:
bool LoadFromFile(std::string name, const char* filename);
bool LoadFromString(std::string name, std::string code);
bool UsePushConstants() const;
u32 GetUniformsSize() const;
void FillUniformBuffer(void* buffer, u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y,
s32 texture_view_width, s32 texture_view_height, u32 window_width, u32 window_height,
s32 original_width, s32 original_height, float time) const;
bool ResizeOutput(GPUTexture::Format format, u32 width, u32 height);
private:
struct CommonUniforms
@ -105,9 +106,21 @@ private:
void LoadOptions();
ALWAYS_INLINE GPUPipeline* GetPipeline() const { return m_pipeline.get(); }
ALWAYS_INLINE GPUTexture* GetOutputTexture() const { return m_output_texture.get(); }
ALWAYS_INLINE GPUFramebuffer* GetOutputFramebuffer() const { return m_output_framebuffer.get(); }
u32 GetUniformsSize() const;
void FillUniformBuffer(void* buffer, u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y,
s32 texture_view_width, s32 texture_view_height, u32 window_width, u32 window_height,
s32 original_width, s32 original_height, float time) const;
bool CompilePipeline(GPUTexture::Format target_format);
std::string m_name;
std::string m_code;
std::vector<Option> m_options;
};
} // namespace FrontendCommon
std::unique_ptr<GPUPipeline> m_pipeline;
std::unique_ptr<GPUTexture> m_output_texture;
std::unique_ptr<GPUFramebuffer> m_output_framebuffer;
};

View File

@ -3,8 +3,6 @@
#include "postprocessing_shadergen.h"
namespace FrontendCommon {
PostProcessingShaderGen::PostProcessingShaderGen(RenderAPI render_api, bool supports_dual_source_blend)
: ShaderGen(render_api, supports_dual_source_blend)
{
@ -18,7 +16,7 @@ std::string PostProcessingShaderGen::GeneratePostProcessingVertexShader(const Po
WriteHeader(ss);
DeclareTexture(ss, "samp0", 0);
WriteUniformBuffer(ss, shader, shader.UsePushConstants());
WriteUniformBuffer(ss, shader, false);
DeclareVertexEntryPoint(ss, {}, 0, 1, {}, true);
ss << R"(
@ -41,7 +39,7 @@ std::string PostProcessingShaderGen::GeneratePostProcessingFragmentShader(const
WriteHeader(ss);
DeclareTexture(ss, "samp0", 0);
WriteUniformBuffer(ss, shader, shader.UsePushConstants());
WriteUniformBuffer(ss, shader, false);
// Rename main, since we need to set up globals
if (!m_glsl)
@ -200,5 +198,3 @@ void PostProcessingShaderGen::WriteUniformBuffer(std::stringstream& ss, const Po
ss << "};\n\n";
}
} // namespace FrontendCommon

View File

@ -4,9 +4,6 @@
#pragma once
#include "core/shadergen.h"
#include "postprocessing_shader.h"
#include <sstream>
namespace FrontendCommon {
class PostProcessingShaderGen : public ShaderGen
{
@ -20,5 +17,3 @@ public:
private:
void WriteUniformBuffer(std::stringstream& ss, const PostProcessingShader& shader, bool use_push_constants);
};
} // namespace FrontendCommon

View File

@ -46,16 +46,6 @@ RenderAPI VulkanGPUDevice::GetRenderAPI() const
return RenderAPI::Vulkan;
}
void* VulkanGPUDevice::GetDevice() const
{
return nullptr;
}
void* VulkanGPUDevice::GetContext() const
{
return nullptr;
}
bool VulkanGPUDevice::ChangeWindow(const WindowInfo& new_wi)
{
g_vulkan_context->WaitForGPUIdle();
@ -261,11 +251,6 @@ bool VulkanGPUDevice::SetupDevice()
return true;
}
bool VulkanGPUDevice::HasDevice() const
{
return static_cast<bool>(g_vulkan_context);
}
bool VulkanGPUDevice::HasSurface() const
{
return static_cast<bool>(m_swap_chain);
@ -469,12 +454,14 @@ void main()
if (m_post_process_descriptor_set_layout == VK_NULL_HANDLE)
return false;
#if 0
plbuilder.AddDescriptorSet(m_post_process_descriptor_set_layout);
plbuilder.AddPushConstants(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
FrontendCommon::PostProcessingShader::PUSH_CONSTANT_SIZE_THRESHOLD);
m_post_process_pipeline_layout = plbuilder.Create(device);
if (m_post_process_pipeline_layout == VK_NULL_HANDLE)
return false;
#endif
dslbuilder.AddBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
@ -552,11 +539,13 @@ void VulkanGPUDevice::DestroyResources()
Vulkan::Util::SafeDestroyPipelineLayout(m_post_process_ubo_pipeline_layout);
Vulkan::Util::SafeDestroyDescriptorSetLayout(m_post_process_descriptor_set_layout);
Vulkan::Util::SafeDestroyDescriptorSetLayout(m_post_process_ubo_descriptor_set_layout);
#if 0
m_post_processing_input_texture.Destroy(false);
Vulkan::Util::SafeDestroyFramebuffer(m_post_processing_input_framebuffer);
m_post_processing_stages.clear();
m_post_processing_ubo.Destroy(true);
m_post_processing_chain.ClearStages();
#endif
Vulkan::Util::SafeDestroyPipeline(m_display_pipeline);
Vulkan::Util::SafeDestroyPipeline(m_cursor_pipeline);
@ -708,6 +697,7 @@ void VulkanGPUDevice::RenderDisplay()
const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight());
#if 0
if (!m_post_processing_chain.IsEmpty())
{
ApplyPostProcessingChain(m_swap_chain->GetCurrentFramebuffer(), left, top, width, height,
@ -716,6 +706,7 @@ void VulkanGPUDevice::RenderDisplay()
m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
return;
}
#endif
BeginSwapChainRenderPass(m_swap_chain->GetCurrentFramebuffer(), m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
RenderDisplay(left, top, width, height, static_cast<Vulkan::Texture*>(m_display_texture), m_display_texture_view_x,
@ -861,6 +852,7 @@ GPUDevice::AdapterAndModeList VulkanGPUDevice::StaticGetAdapterAndModeList(const
return ret;
}
#if 0
VulkanGPUDevice::PostProcessingStage::PostProcessingStage(PostProcessingStage&& move)
: pipeline(move.pipeline), output_framebuffer(move.output_framebuffer),
output_texture(std::move(move.output_texture)), uniforms_size(move.uniforms_size)
@ -879,9 +871,11 @@ VulkanGPUDevice::PostProcessingStage::~PostProcessingStage()
if (pipeline != VK_NULL_HANDLE)
g_vulkan_context->DeferPipelineDestruction(pipeline);
}
#endif
bool VulkanGPUDevice::SetPostProcessingChain(const std::string_view& config)
{
#if 0
g_vulkan_context->ExecuteCommandBuffer(true);
if (config.empty())
@ -966,8 +960,13 @@ bool VulkanGPUDevice::SetPostProcessingChain(const std::string_view& config)
"Post Processing Uniform Buffer");
m_post_processing_timer.Reset();
return true;
#else
return false;
#endif
}
#if 0
bool VulkanGPUDevice::CheckPostProcessingRenderTargets(u32 target_width, u32 target_height)
{
DebugAssert(!m_post_processing_stages.empty());
@ -1141,3 +1140,4 @@ void VulkanGPUDevice::ApplyPostProcessingChain(VkFramebuffer target_fb, s32 fina
}
}
}
#endif

View File

@ -24,10 +24,7 @@ public:
~VulkanGPUDevice();
RenderAPI GetRenderAPI() const override;
void* GetDevice() const override;
void* GetContext() const override;
bool HasDevice() const override;
bool HasSurface() const override;
bool CreateDevice(const WindowInfo& wi, bool vsync) override;
@ -71,23 +68,6 @@ protected:
float src_rect_height;
};
struct PostProcessingStage
{
PostProcessingStage() = default;
PostProcessingStage(PostProcessingStage&& move);
~PostProcessingStage();
VkPipeline pipeline = VK_NULL_HANDLE;
VkFramebuffer output_framebuffer = VK_NULL_HANDLE;
Vulkan::Texture output_texture;
u32 uniforms_size = 0;
};
bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height);
void ApplyPostProcessingChain(VkFramebuffer target_fb, s32 final_left, s32 final_top, s32 final_width,
s32 final_height, Vulkan::Texture* texture, s32 texture_view_x, s32 texture_view_y,
s32 texture_view_width, s32 texture_view_height, u32 target_width, u32 target_height);
VkRenderPass GetRenderPassForDisplay() const;
bool CheckStagingBufferSize(u32 required_size);
@ -125,11 +105,4 @@ protected:
VkDescriptorSetLayout m_post_process_ubo_descriptor_set_layout = VK_NULL_HANDLE;
VkPipelineLayout m_post_process_pipeline_layout = VK_NULL_HANDLE;
VkPipelineLayout m_post_process_ubo_pipeline_layout = VK_NULL_HANDLE;
FrontendCommon::PostProcessingChain m_post_processing_chain;
Vulkan::Texture m_post_processing_input_texture;
VkFramebuffer m_post_processing_input_framebuffer = VK_NULL_HANDLE;
Vulkan::StreamBuffer m_post_processing_ubo;
std::vector<PostProcessingStage> m_post_processing_stages;
Common::Timer m_post_processing_timer;
};

View File

@ -219,7 +219,7 @@ bool GPU_HW::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_di
void GPU_HW::RestoreGraphicsAPIState()
{
g_host_display->SetTextureSampler(0, m_vram_read_texture.get(), g_host_display->GetPointSampler());
g_host_display->SetTextureSampler(0, m_vram_read_texture.get(), g_host_display->GetNearestSampler());
g_host_display->SetFramebuffer(m_vram_framebuffer.get());
g_host_display->SetViewport(0, 0, m_vram_texture->GetWidth(), m_vram_texture->GetHeight());
SetScissor();
@ -500,15 +500,17 @@ bool GPU_HW::CreateBuffers()
return false;
}
}
else if (m_downsample_mode == GPUDownsampleMode::Box)
else
#endif
if (m_downsample_mode == GPUDownsampleMode::Box)
{
if (!m_downsample_texture.Create(m_device.Get(), VRAM_WIDTH, VRAM_HEIGHT, 1, 1, 1, GPUTexture::Type::RenderTarget,
texture_format))
if (!(m_downsample_texture = g_host_display->CreateTexture(VRAM_WIDTH, VRAM_HEIGHT, 1, 1, 1,
GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)) ||
!(m_downsample_framebuffer = g_host_display->CreateFramebuffer(m_downsample_texture.get())))
{
return false;
}
}
#endif
g_host_display->SetFramebuffer(m_vram_framebuffer.get());
SetFullVRAMDirtyRectangle();
@ -527,6 +529,8 @@ void GPU_HW::ClearFramebuffer()
void GPU_HW::DestroyBuffers()
{
m_vram_upload_buffer.reset();
m_downsample_framebuffer.reset();
m_downsample_texture.reset();
m_display_framebuffer.reset();
m_vram_readback_framebuffer.reset();
m_vram_update_depth_framebuffer.reset();
@ -613,7 +617,7 @@ bool GPU_HW::CompilePipelines()
};
GPUPipeline::GraphicsConfig plconfig = {};
plconfig.layout = GPUPipeline::Layout::HWBatch;
plconfig.layout = GPUPipeline::Layout::SingleTextureUBO;
plconfig.input_layout.vertex_stride = sizeof(BatchVertex);
plconfig.rasterization = GPUPipeline::RasterizationState::GetNoCullState();
plconfig.primitive = GPUPipeline::Primitive::Triangles;
@ -647,7 +651,8 @@ bool GPU_HW::CompilePipelines()
gsl::span<const GPUPipeline::VertexAttribute>(batch_attributes);
plconfig.vertex_shader = batch_vertex_shaders[BoolToUInt8(textured)].get();
plconfig.pixel_shader = batch_fragment_shaders[render_mode][texture_mode][dithering][interlacing].get();
plconfig.fragment_shader =
batch_fragment_shaders[render_mode][texture_mode][dithering][interlacing].get();
// TODO: Depth write always on???
plconfig.depth.depth_test = depth_test_values[depth_test];
@ -721,7 +726,7 @@ bool GPU_HW::CompilePipelines()
progress.Increment();
// common state
plconfig.layout = GPUPipeline::Layout::SingleTexture;
plconfig.layout = GPUPipeline::Layout::SingleTexturePushConstants;
plconfig.per_sample_shading = false;
plconfig.blend = GPUPipeline::BlendState::GetNoBlendingState();
plconfig.vertex_shader = fullscreen_quad_vertex_shader.get();
@ -737,7 +742,7 @@ bool GPU_HW::CompilePipelines()
if (!fs)
return false;
plconfig.pixel_shader = fs.get();
plconfig.fragment_shader = fs.get();
plconfig.depth = GPUPipeline::DepthState::GetAlwaysWriteState();
if (!(m_vram_fill_pipelines[wrapped][interlaced] = g_host_display->CreatePipeline(plconfig)))
@ -754,7 +759,7 @@ bool GPU_HW::CompilePipelines()
if (!fs)
return false;
plconfig.pixel_shader = fs.get();
plconfig.fragment_shader = fs.get();
for (u8 depth_test = 0; depth_test < 2; depth_test++)
{
plconfig.depth.depth_write = true;
@ -778,7 +783,7 @@ bool GPU_HW::CompilePipelines()
if (!fs)
return false;
plconfig.pixel_shader = fs.get();
plconfig.fragment_shader = fs.get();
for (u8 depth_test = 0; depth_test < 2; depth_test++)
{
plconfig.depth.depth_write = true;
@ -801,7 +806,7 @@ bool GPU_HW::CompilePipelines()
if (!fs)
return false;
plconfig.pixel_shader = fs.get();
plconfig.fragment_shader = fs.get();
plconfig.color_format = GPUTexture::Format::Unknown;
plconfig.depth_format = VRAM_DS_FORMAT;
plconfig.depth = GPUPipeline::DepthState::GetAlwaysWriteState();
@ -827,7 +832,7 @@ bool GPU_HW::CompilePipelines()
if (!fs)
return false;
plconfig.pixel_shader = fs.get();
plconfig.fragment_shader = fs.get();
if (!(m_vram_readback_pipeline = g_host_display->CreatePipeline(plconfig)))
return false;
@ -849,7 +854,7 @@ bool GPU_HW::CompilePipelines()
if (!fs)
return false;
plconfig.pixel_shader = fs.get();
plconfig.fragment_shader = fs.get();
if (!(m_display_pipelines[depth_24][interlace_mode] = g_host_display->CreatePipeline(plconfig)))
return false;
@ -865,7 +870,7 @@ bool GPU_HW::CompilePipelines()
if (!fs)
return false;
plconfig.pixel_shader = fs.get();
plconfig.fragment_shader = fs.get();
if (!(m_copy_pipeline = g_host_display->CreatePipeline(plconfig)))
return false;
}
@ -938,32 +943,23 @@ bool GPU_HW::CompilePipelines()
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_downsample_composite_pass_pipeline,
"Downsample Composite Pass Pipeline");
}
else if (m_downsample_mode == GPUDownsampleMode::Box)
{
gpbuilder.Clear();
gpbuilder.SetRenderPass(m_downsample_render_pass, 0);
gpbuilder.SetPipelineLayout(m_single_sampler_pipeline_layout);
gpbuilder.SetVertexShader(fullscreen_quad_vertex_shader);
gpbuilder.SetNoCullRasterizationState();
gpbuilder.SetNoDepthTestState();
gpbuilder.SetNoBlendingState();
gpbuilder.SetDynamicViewportAndScissorState();
std::unique_ptr<GPUShader> fs = g_host_display->CreateShaderFromSource(
GPUShader::Stage::Pixel, shadergen.GenerateBoxSampleDownsampleFragmentShader());
if (fs == VK_NULL_HANDLE)
return false;
gpbuilder.SetFragmentShader(fs);
m_downsample_first_pass_pipeline = gpbuilder.Create(device, pipeline_cache, false);
vkDestroyShaderModule(g_vulkan_context->GetDevice(), fs, nullptr);
if (m_downsample_first_pass_pipeline == VK_NULL_HANDLE)
return false;
Vulkan::Util::SetObjectName(g_vulkan_context->GetDevice(), m_downsample_first_pass_pipeline,
"Downsample First Pass Pipeline");
}
else
#endif
if (m_downsample_mode == GPUDownsampleMode::Box)
{
std::unique_ptr<GPUShader> fs =
g_host_display->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateBoxSampleDownsampleFragmentShader());
if (!fs)
return false;
GL_OBJECT_NAME(fs, "Downsample First Pass Fragment Shader");
plconfig.fragment_shader = fs.get();
if (!(m_downsample_first_pass_pipeline = g_host_display->CreatePipeline(plconfig)))
return false;
GL_OBJECT_NAME(m_downsample_first_pass_pipeline, "Downsample First Pass Pipeline");
}
progress.Increment();
@ -1027,11 +1023,11 @@ void GPU_HW::UpdateDepthBufferFromMaskBit()
g_host_display->SetScissor(0, 0, m_vram_texture->GetWidth(), m_vram_texture->GetHeight());
g_host_display->SetFramebuffer(m_vram_update_depth_framebuffer.get());
g_host_display->SetPipeline(m_vram_update_depth_pipeline.get());
g_host_display->SetTextureSampler(0, m_vram_texture.get(), g_host_display->GetPointSampler());
g_host_display->SetTextureSampler(0, m_vram_texture.get(), g_host_display->GetNearestSampler());
g_host_display->Draw(3, 0);
// Restore.
g_host_display->SetTextureSampler(0, m_vram_read_texture.get(), g_host_display->GetPointSampler());
g_host_display->SetTextureSampler(0, m_vram_read_texture.get(), g_host_display->GetNearestSampler());
g_host_display->SetFramebuffer(m_vram_framebuffer.get());
SetScissor();
}
@ -2087,7 +2083,7 @@ void GPU_HW::ReadVRAM(u32 x, u32 y, u32 width, u32 height)
const u32 uniforms[4] = {copy_rect.left, copy_rect.top, copy_rect.GetWidth(), copy_rect.GetHeight()};
g_host_display->SetPipeline(m_vram_readback_pipeline.get());
g_host_display->SetFramebuffer(m_vram_readback_framebuffer.get());
g_host_display->SetTextureSampler(0, m_vram_texture.get(), g_host_display->GetPointSampler());
g_host_display->SetTextureSampler(0, m_vram_texture.get(), g_host_display->GetNearestSampler());
g_host_display->SetViewportAndScissor(0, 0, encoded_width, encoded_height);
g_host_display->PushUniformBuffer(uniforms, sizeof(uniforms));
g_host_display->Draw(3, 0);
@ -2436,7 +2432,7 @@ void GPU_HW::UpdateDisplay()
}
}
void GPU_HW::DownsampleFramebuffer(const GPUTexture* source, u32 left, u32 top, u32 width, u32 height)
void GPU_HW::DownsampleFramebuffer(GPUTexture* source, u32 left, u32 top, u32 width, u32 height)
{
if (m_downsample_mode == GPUDownsampleMode::Adaptive)
DownsampleFramebufferAdaptive(source, left, top, width, height);
@ -2444,7 +2440,7 @@ void GPU_HW::DownsampleFramebuffer(const GPUTexture* source, u32 left, u32 top,
DownsampleFramebufferBoxFilter(source, left, top, width, height);
}
void GPU_HW::DownsampleFramebufferAdaptive(const GPUTexture* source, u32 left, u32 top, u32 width, u32 height)
void GPU_HW::DownsampleFramebufferAdaptive(GPUTexture* source, u32 left, u32 top, u32 width, u32 height)
{
#if 0
CD3D11_BOX src_box(left, top, 0, left + width, top + height, 1);
@ -2517,31 +2513,25 @@ void GPU_HW::DownsampleFramebufferAdaptive(const GPUTexture* source, u32 left, u
#endif
}
void GPU_HW::DownsampleFramebufferBoxFilter(const GPUTexture* source, u32 left, u32 top, u32 width, u32 height)
void GPU_HW::DownsampleFramebufferBoxFilter(GPUTexture* source, u32 left, u32 top, u32 width, u32 height)
{
#if 0
const u32 ds_left = left / m_resolution_scale;
const u32 ds_top = top / m_resolution_scale;
const u32 ds_width = width / m_resolution_scale;
const u32 ds_height = height / m_resolution_scale;
static constexpr float clear_color[4] = {};
m_context->ClearRenderTargetView(m_downsample_texture.GetD3DRTV(), clear_color);
m_context->OMSetDepthStencilState(m_depth_disabled_state.Get(), 0);
m_context->OMSetRenderTargets(1, m_downsample_texture.GetD3DRTVArray(), nullptr);
m_context->OMSetBlendState(m_blend_disabled_state.Get(), nullptr, 0xFFFFFFFFu);
m_context->VSSetShader(m_screen_quad_vertex_shader.Get(), nullptr, 0);
m_context->PSSetShader(m_downsample_first_pass_pixel_shader.Get(), nullptr, 0);
m_context->PSSetShaderResources(0, 1, source->GetD3DSRVArray());
SetViewportAndScissor(ds_left, ds_top, ds_width, ds_height);
m_context->Draw(3, 0);
source->MakeReadyForSampling();
g_host_display->ClearRenderTarget(m_downsample_texture.get(), 0);
g_host_display->SetFramebuffer(m_downsample_framebuffer.get());
g_host_display->SetPipeline(m_downsample_first_pass_pipeline.get());
g_host_display->SetTextureSampler(0, source, g_host_display->GetNearestSampler());
g_host_display->SetViewportAndScissor(ds_left, ds_top, ds_width, ds_height);
g_host_display->Draw(3, 0);
RestoreGraphicsAPIState();
g_host_display->SetDisplayTexture(&m_downsample_texture, ds_left, ds_top, ds_width, ds_height);
#else
Panic("Not implemented");
#endif
g_host_display->SetDisplayTexture(m_downsample_texture.get(), ds_left, ds_top, ds_width, ds_height);
}
void GPU_HW::DrawRendererStats(bool is_idle_frame)

View File

@ -58,6 +58,7 @@ public:
protected:
enum : u32
{
// TODO: Remove these
VRAM_UPDATE_TEXTURE_BUFFER_SIZE = 4 * 1024 * 1024,
VERTEX_BUFFER_SIZE = 4 * 1024 * 1024,
UNIFORM_BUFFER_SIZE = 2 * 1024 * 1024,
@ -374,9 +375,9 @@ protected:
SmoothingUBOData GetSmoothingUBO(u32 level, u32 left, u32 top, u32 width, u32 height, u32 tex_width,
u32 tex_height) const;
void DownsampleFramebuffer(const GPUTexture* source, u32 left, u32 top, u32 width, u32 height);
void DownsampleFramebufferAdaptive(const GPUTexture* source, u32 left, u32 top, u32 width, u32 height);
void DownsampleFramebufferBoxFilter(const GPUTexture* source, u32 left, u32 top, u32 width, u32 height);
void DownsampleFramebuffer(GPUTexture* source, u32 left, u32 top, u32 width, u32 height);
void DownsampleFramebufferAdaptive(GPUTexture* source, u32 left, u32 top, u32 width, u32 height);
void DownsampleFramebufferBoxFilter(GPUTexture* source, u32 left, u32 top, u32 width, u32 height);
std::unique_ptr<GPUTexture> m_vram_texture;
std::unique_ptr<GPUTexture> m_vram_depth_texture;
@ -458,6 +459,10 @@ protected:
// TODO: get rid of this, and use image blits instead where supported
std::unique_ptr<GPUPipeline> m_copy_pipeline;
std::unique_ptr<GPUTexture> m_downsample_texture;
std::unique_ptr<GPUFramebuffer> m_downsample_framebuffer;
//std::unique_ptr<GPUTexture> m_downsample_weight_texture;
//std::unique_ptr<GPUFramebuffer> m_downsample_weight_framebuffer;
std::unique_ptr<GPUPipeline> m_downsample_first_pass_pipeline;
std::unique_ptr<GPUPipeline> m_downsample_mid_pass_pipeline;
std::unique_ptr<GPUPipeline> m_downsample_blur_pass_pipeline;

View File

@ -71,7 +71,7 @@ void PostProcessingChainConfigWidget::updateList()
for (u32 i = 0; i < m_chain.GetStageCount(); i++)
{
const FrontendCommon::PostProcessingShader& shader = m_chain.GetShaderStage(i);
const PostProcessingShader& shader = m_chain.GetShaderStage(i);
QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(shader.GetName()), m_ui.shaders);
item->setData(Qt::UserRole, QVariant(i));
@ -112,7 +112,7 @@ void PostProcessingChainConfigWidget::onAddButtonClicked()
{
QMenu menu;
const std::vector<std::string> shaders(FrontendCommon::PostProcessingChain::GetAvailableShaderNames());
const std::vector<std::string> shaders(PostProcessingChain::GetAvailableShaderNames());
if (shaders.empty())
{
menu.addAction(tr("No Shaders Available"))->setEnabled(false);

View File

@ -22,7 +22,7 @@ public:
PostProcessingChainConfigWidget(QWidget* parent);
~PostProcessingChainConfigWidget();
ALWAYS_INLINE FrontendCommon::PostProcessingChain& getChain() { return m_chain; }
ALWAYS_INLINE PostProcessingChain& getChain() { return m_chain; }
bool setConfigString(const std::string_view& config_string);
void setOptionsButtonVisible(bool visible);
@ -51,5 +51,5 @@ private:
Ui::PostProcessingChainConfigWidget m_ui;
FrontendCommon::PostProcessingChain m_chain;
PostProcessingChain m_chain;
};

View File

@ -71,7 +71,7 @@ void PostProcessingSettingsWidget::updateShaderConfigPanel(s32 index)
if (index < 0)
return;
FrontendCommon::PostProcessingShader& shader = m_ui.widget->getChain().GetShaderStage(static_cast<u32>(index));
PostProcessingShader& shader = m_ui.widget->getChain().GetShaderStage(static_cast<u32>(index));
if (!shader.HasOptions())
return;

View File

@ -8,10 +8,8 @@
#include <QtWidgets/QLabel>
#include <QtWidgets/QSlider>
using FrontendCommon::PostProcessingShader;
PostProcessingShaderConfigWidget::PostProcessingShaderConfigWidget(QWidget* parent,
FrontendCommon::PostProcessingShader* shader)
PostProcessingShader* shader)
: QWidget(parent), m_shader(shader)
{
createUi();
@ -146,7 +144,7 @@ void PostProcessingShaderConfigWidget::onResetToDefaultsClicked()
}
PostProcessingShaderConfigDialog::PostProcessingShaderConfigDialog(QWidget* parent,
FrontendCommon::PostProcessingShader* shader)
PostProcessingShader* shader)
: QDialog(parent)
{
setWindowTitle(tr("%1 Shader Options").arg(QString::fromStdString(shader->GetName())));

View File

@ -13,7 +13,7 @@ class PostProcessingShaderConfigWidget : public QWidget
Q_OBJECT
public:
PostProcessingShaderConfigWidget(QWidget* parent, FrontendCommon::PostProcessingShader* shader);
PostProcessingShaderConfigWidget(QWidget* parent, PostProcessingShader* shader);
~PostProcessingShaderConfigWidget();
QGridLayout* getLayout() { return m_layout; }
@ -28,7 +28,7 @@ private Q_SLOTS:
protected:
void createUi();
FrontendCommon::PostProcessingShader* m_shader;
PostProcessingShader* m_shader;
QGridLayout* m_layout;
};
@ -37,7 +37,7 @@ class PostProcessingShaderConfigDialog : public QDialog
Q_OBJECT
public:
PostProcessingShaderConfigDialog(QWidget* parent, FrontendCommon::PostProcessingShader* shader);
PostProcessingShaderConfigDialog(QWidget* parent, PostProcessingShader* shader);
~PostProcessingShaderConfigDialog();
Q_SIGNALS:

View File

@ -378,7 +378,7 @@ static std::unique_ptr<GameList::Entry> s_game_settings_entry;
static std::vector<std::pair<std::string, bool>> s_game_list_directories_cache;
static std::vector<std::string> s_graphics_adapter_list_cache;
static std::vector<std::string> s_fullscreen_mode_list_cache;
static FrontendCommon::PostProcessingChain s_postprocessing_chain;
static PostProcessingChain s_postprocessing_chain;
static std::vector<const HotkeyInfo*> s_hotkey_list_cache;
static std::atomic_bool s_settings_changed{false};
static std::atomic_bool s_game_settings_changed{false};
@ -3866,7 +3866,7 @@ void FullscreenUI::DrawPostProcessingSettingsPage()
if (MenuButton(ICON_FA_PLUS " Add Shader", "Adds a new shader to the chain."))
{
ImGuiFullscreen::ChoiceDialogOptions options;
for (std::string& name : FrontendCommon::PostProcessingChain::GetAvailableShaderNames())
for (std::string& name : PostProcessingChain::GetAvailableShaderNames())
options.emplace_back(std::move(name), false);
OpenChoiceDialog(
@ -3912,7 +3912,7 @@ void FullscreenUI::DrawPostProcessingSettingsPage()
for (u32 stage_index = 0; stage_index < s_postprocessing_chain.GetStageCount(); stage_index++)
{
ImGui::PushID(stage_index);
FrontendCommon::PostProcessingShader& stage = s_postprocessing_chain.GetShaderStage(stage_index);
PostProcessingShader& stage = s_postprocessing_chain.GetShaderStage(stage_index);
str.Fmt("Stage {}: {}", stage_index + 1, stage.GetName());
MenuHeading(str);
@ -3936,11 +3936,11 @@ void FullscreenUI::DrawPostProcessingSettingsPage()
postprocessing_action_index = stage_index;
}
for (FrontendCommon::PostProcessingShader::Option& opt : stage.GetOptions())
for (PostProcessingShader::Option& opt : stage.GetOptions())
{
switch (opt.type)
{
case FrontendCommon::PostProcessingShader::Option::Type::Bool:
case PostProcessingShader::Option::Type::Bool:
{
bool value = (opt.value[0].int_value != 0);
tstr.Fmt(ICON_FA_COGS " {}", opt.ui_name);
@ -3953,7 +3953,7 @@ void FullscreenUI::DrawPostProcessingSettingsPage()
}
break;
case FrontendCommon::PostProcessingShader::Option::Type::Float:
case PostProcessingShader::Option::Type::Float:
{
tstr.Fmt(ICON_FA_RULER_VERTICAL " {}##{}", opt.ui_name, opt.name);
str.Fmt("Value: {} | Default: {} | Minimum: {} | Maximum: {}", opt.value[0].float_value,
@ -4056,7 +4056,7 @@ void FullscreenUI::DrawPostProcessingSettingsPage()
}
break;
case FrontendCommon::PostProcessingShader::Option::Type::Int:
case PostProcessingShader::Option::Type::Int:
{
tstr.Fmt(ICON_FA_RULER_VERTICAL " {}##{}", opt.ui_name, opt.name);
str.Fmt("Value: {} | Default: {} | Minimum: {} | Maximum: {}", opt.value[0].int_value,
@ -4168,7 +4168,7 @@ void FullscreenUI::DrawPostProcessingSettingsPage()
{
case POSTPROCESSING_ACTION_REMOVE:
{
FrontendCommon::PostProcessingShader& stage = s_postprocessing_chain.GetShaderStage(postprocessing_action_index);
PostProcessingShader& stage = s_postprocessing_chain.GetShaderStage(postprocessing_action_index);
ShowToast(std::string(), fmt::format("Removed stage {} ({}).", postprocessing_action_index + 1, stage.GetName()));
s_postprocessing_chain.RemoveStage(postprocessing_action_index);
SavePostProcessingChain();
@ -4454,7 +4454,9 @@ void FullscreenUI::DrawAchievementsSettingsPage()
EndMenuButtons();
}
void FullscreenUI::DrawAchievementsLoginWindow() {}
void FullscreenUI::DrawAchievementsLoginWindow()
{
}
#endif