GPUDevice: Get rid of framebuffer abstraction
This commit is contained in:
parent
a9ee2a34d8
commit
3b2c70cda5
|
@ -10,7 +10,7 @@
|
|||
<PreprocessorDefinitions Condition="('$(Platform)'=='x64' Or '$(Platform)'=='ARM64')">ENABLE_MMAP_FASTMEM=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="('$(Platform)'=='x64' Or '$(Platform)'=='ARM64')">ENABLE_NEWREC=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)dep\xxhash\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\rcheevos\include;$(SolutionDir)dep\rapidjson\include;$(SolutionDir)dep\discord-rpc\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\rcheevos\include;$(SolutionDir)dep\rapidjson\include;$(SolutionDir)dep\discord-rpc\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories Condition="'$(Platform)'!='ARM64'">%(AdditionalIncludeDirectories);$(SolutionDir)dep\rainterface</AdditionalIncludeDirectories>
|
||||
|
||||
<AdditionalIncludeDirectories Condition="'$(Platform)'=='x64'">%(AdditionalIncludeDirectories);$(SolutionDir)dep\xbyak\xbyak</AdditionalIncludeDirectories>
|
||||
|
|
|
@ -1579,7 +1579,7 @@ bool GPU::CompileDisplayPipeline()
|
|||
plconfig.rasterization = GPUPipeline::RasterizationState::GetNoCullState();
|
||||
plconfig.depth = GPUPipeline::DepthState::GetNoTestsState();
|
||||
plconfig.blend = GPUPipeline::BlendState::GetNoBlendingState();
|
||||
plconfig.color_format = g_gpu_device->HasSurface() ? g_gpu_device->GetWindowFormat() : GPUTexture::Format::RGBA8;
|
||||
plconfig.SetTargetFormats(g_gpu_device->HasSurface() ? g_gpu_device->GetWindowFormat() : GPUTexture::Format::RGBA8);
|
||||
plconfig.depth_format = GPUTexture::Format::Unknown;
|
||||
plconfig.samples = 1;
|
||||
plconfig.per_sample_shading = false;
|
||||
|
@ -1670,9 +1670,10 @@ bool GPU::PresentDisplay()
|
|||
return RenderDisplay(nullptr, draw_rect, true);
|
||||
}
|
||||
|
||||
bool GPU::RenderDisplay(GPUFramebuffer* target, const Common::Rectangle<s32>& draw_rect, bool postfx)
|
||||
bool GPU::RenderDisplay(GPUTexture* target, const Common::Rectangle<s32>& draw_rect, bool postfx)
|
||||
{
|
||||
GL_SCOPE_FMT("RenderDisplay: {}x{} at {},{}", draw_rect.left, draw_rect.top, draw_rect.GetWidth(), draw_rect.GetHeight());
|
||||
GL_SCOPE_FMT("RenderDisplay: {}x{} at {},{}", draw_rect.left, draw_rect.top, draw_rect.GetWidth(),
|
||||
draw_rect.GetHeight());
|
||||
|
||||
if (m_display_texture)
|
||||
m_display_texture->MakeReadyForSampling();
|
||||
|
@ -1716,8 +1717,7 @@ bool GPU::RenderDisplay(GPUFramebuffer* target, const Common::Rectangle<s32>& dr
|
|||
break;
|
||||
}
|
||||
|
||||
const GPUTexture::Format hdformat =
|
||||
(target && target->GetRT()) ? target->GetRT()->GetFormat() : g_gpu_device->GetWindowFormat();
|
||||
const GPUTexture::Format hdformat = target ? target->GetFormat() : g_gpu_device->GetWindowFormat();
|
||||
const u32 target_width = target ? target->GetWidth() : g_gpu_device->GetWindowWidth();
|
||||
const u32 target_height = target ? target->GetHeight() : g_gpu_device->GetWindowHeight();
|
||||
const bool really_postfx = (postfx && HasDisplayTexture() && PostProcessing::IsActive() &&
|
||||
|
@ -1725,12 +1725,12 @@ bool GPU::RenderDisplay(GPUFramebuffer* target, const Common::Rectangle<s32>& dr
|
|||
if (really_postfx)
|
||||
{
|
||||
g_gpu_device->ClearRenderTarget(PostProcessing::GetInputTexture(), 0);
|
||||
g_gpu_device->SetFramebuffer(PostProcessing::GetInputFramebuffer());
|
||||
g_gpu_device->SetRenderTarget(PostProcessing::GetInputTexture());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target)
|
||||
g_gpu_device->SetFramebuffer(target);
|
||||
g_gpu_device->SetRenderTarget(target);
|
||||
else if (!g_gpu_device->BeginPresent(false))
|
||||
return false;
|
||||
}
|
||||
|
@ -2059,16 +2059,10 @@ bool GPU::RenderScreenshotToBuffer(u32 width, u32 height, const Common::Rectangl
|
|||
if (!render_texture)
|
||||
return false;
|
||||
|
||||
std::unique_ptr<GPUFramebuffer> render_fb = g_gpu_device->CreateFramebuffer(render_texture.get());
|
||||
if (!render_fb)
|
||||
return false;
|
||||
|
||||
g_gpu_device->ClearRenderTarget(render_texture.get(), 0);
|
||||
|
||||
// TODO: this should use copy shader instead.
|
||||
RenderDisplay(render_fb.get(), draw_rect, postfx);
|
||||
|
||||
g_gpu_device->SetFramebuffer(nullptr);
|
||||
RenderDisplay(render_texture.get(), draw_rect, postfx);
|
||||
|
||||
const u32 stride = GPUTexture::GetPixelSize(hdformat) * width;
|
||||
out_pixels->resize(width * height);
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
class StateWrapper;
|
||||
|
||||
class GPUDevice;
|
||||
class GPUFramebuffer;
|
||||
class GPUTexture;
|
||||
class GPUPipeline;
|
||||
|
||||
|
@ -585,7 +584,7 @@ protected:
|
|||
float* out_top_padding, float* out_scale, float* out_x_scale,
|
||||
bool apply_aspect_ratio = true) const;
|
||||
|
||||
bool RenderDisplay(GPUFramebuffer* target, const Common::Rectangle<s32>& draw_rect, bool postfx);
|
||||
bool RenderDisplay(GPUTexture* target, const Common::Rectangle<s32>& draw_rect, bool postfx);
|
||||
|
||||
s32 m_display_width = 0;
|
||||
s32 m_display_height = 0;
|
||||
|
|
|
@ -317,7 +317,7 @@ bool GPU_HW::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_di
|
|||
void GPU_HW::RestoreDeviceContext()
|
||||
{
|
||||
g_gpu_device->SetTextureSampler(0, m_vram_read_texture.get(), g_gpu_device->GetNearestSampler());
|
||||
g_gpu_device->SetFramebuffer(m_vram_framebuffer.get());
|
||||
g_gpu_device->SetRenderTarget(m_vram_texture.get(), m_vram_depth_texture.get());
|
||||
g_gpu_device->SetViewport(0, 0, m_vram_texture->GetWidth(), m_vram_texture->GetHeight());
|
||||
SetScissor();
|
||||
m_batch_ubo_dirty = true;
|
||||
|
@ -649,20 +649,6 @@ bool GPU_HW::CreateBuffers()
|
|||
GL_OBJECT_NAME(m_display_private_texture, "Display Texture");
|
||||
GL_OBJECT_NAME(m_vram_readback_texture, "VRAM Readback Texture");
|
||||
|
||||
// vram framebuffer has both colour and depth
|
||||
if (!(m_vram_framebuffer = g_gpu_device->CreateFramebuffer(m_vram_texture.get(), m_vram_depth_texture.get())) ||
|
||||
!(m_vram_update_depth_framebuffer = g_gpu_device->CreateFramebuffer(m_vram_depth_texture.get())) ||
|
||||
!(m_vram_readback_framebuffer = g_gpu_device->CreateFramebuffer(m_vram_readback_texture.get())) ||
|
||||
!(m_display_framebuffer = g_gpu_device->CreateFramebuffer(m_display_private_texture.get())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GL_OBJECT_NAME(m_vram_framebuffer, "VRAM Framebuffer");
|
||||
GL_OBJECT_NAME(m_vram_update_depth_framebuffer, "VRAM Update Depth Framebuffer");
|
||||
GL_OBJECT_NAME(m_vram_readback_framebuffer, "VRAM Readback Framebuffer");
|
||||
GL_OBJECT_NAME(m_display_framebuffer, "Display Framebuffer");
|
||||
|
||||
if (!(m_vram_upload_buffer =
|
||||
g_gpu_device->CreateTextureBuffer(GPUTextureBuffer::Format::R16UI, GPUDevice::MIN_TEXEL_BUFFER_ELEMENTS)))
|
||||
{
|
||||
|
@ -679,11 +665,9 @@ bool GPU_HW::CreateBuffers()
|
|||
GPUTexture::Type::Texture, VRAM_RT_FORMAT)) ||
|
||||
!(m_downsample_render_texture = g_gpu_device->CreateTexture(texture_width, texture_height, 1, 1, 1,
|
||||
GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)) ||
|
||||
!(m_downsample_framebuffer = g_gpu_device->CreateFramebuffer(m_downsample_render_texture.get())) ||
|
||||
!(m_downsample_weight_texture =
|
||||
g_gpu_device->CreateTexture(texture_width >> (levels - 1), texture_height >> (levels - 1), 1, 1, 1,
|
||||
GPUTexture::Type::RenderTarget, GPUTexture::Format::R8)) ||
|
||||
!(m_downsample_weight_framebuffer = g_gpu_device->CreateFramebuffer(m_downsample_weight_texture.get())))
|
||||
GPUTexture::Type::RenderTarget, GPUTexture::Format::R8)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -693,14 +677,13 @@ bool GPU_HW::CreateBuffers()
|
|||
const u32 downsample_scale = GetBoxDownsampleScale(m_resolution_scale);
|
||||
if (!(m_downsample_render_texture =
|
||||
g_gpu_device->CreateTexture(VRAM_WIDTH * downsample_scale, VRAM_HEIGHT * downsample_scale, 1, 1, 1,
|
||||
GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)) ||
|
||||
!(m_downsample_framebuffer = g_gpu_device->CreateFramebuffer(m_downsample_render_texture.get())))
|
||||
GPUTexture::Type::RenderTarget, VRAM_RT_FORMAT)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
g_gpu_device->SetFramebuffer(m_vram_framebuffer.get());
|
||||
g_gpu_device->SetRenderTarget(m_vram_texture.get(), m_vram_depth_texture.get());
|
||||
SetFullVRAMDirtyRectangle();
|
||||
return true;
|
||||
}
|
||||
|
@ -719,15 +702,9 @@ void GPU_HW::DestroyBuffers()
|
|||
ClearDisplayTexture();
|
||||
|
||||
m_vram_upload_buffer.reset();
|
||||
m_downsample_weight_framebuffer.reset();
|
||||
m_downsample_weight_texture.reset();
|
||||
m_downsample_framebuffer.reset();
|
||||
m_downsample_render_texture.reset();
|
||||
m_downsample_texture.reset();
|
||||
m_display_framebuffer.reset();
|
||||
m_vram_readback_framebuffer.reset();
|
||||
m_vram_update_depth_framebuffer.reset();
|
||||
m_vram_framebuffer.reset();
|
||||
m_vram_read_texture.reset();
|
||||
m_vram_depth_texture.reset();
|
||||
m_vram_texture.reset();
|
||||
|
@ -833,8 +810,7 @@ bool GPU_HW::CompilePipelines()
|
|||
plconfig.input_layout.vertex_stride = sizeof(BatchVertex);
|
||||
plconfig.rasterization = GPUPipeline::RasterizationState::GetNoCullState();
|
||||
plconfig.primitive = GPUPipeline::Primitive::Triangles;
|
||||
plconfig.color_format = VRAM_RT_FORMAT;
|
||||
plconfig.depth_format = VRAM_DS_FORMAT;
|
||||
plconfig.SetTargetFormats(VRAM_RT_FORMAT, VRAM_DS_FORMAT);
|
||||
plconfig.samples = m_multisamples;
|
||||
plconfig.per_sample_shading = m_per_sample_shading;
|
||||
plconfig.geometry_shader = nullptr;
|
||||
|
@ -1080,8 +1056,7 @@ bool GPU_HW::CompilePipelines()
|
|||
return false;
|
||||
|
||||
plconfig.fragment_shader = fs.get();
|
||||
plconfig.color_format = GPUTexture::Format::Unknown;
|
||||
plconfig.depth_format = VRAM_DS_FORMAT;
|
||||
plconfig.SetTargetFormats(GPUTexture::Format::Unknown, VRAM_DS_FORMAT);
|
||||
plconfig.depth = GPUPipeline::DepthState::GetAlwaysWriteState();
|
||||
plconfig.blend.write_mask = 0;
|
||||
|
||||
|
@ -1093,8 +1068,7 @@ bool GPU_HW::CompilePipelines()
|
|||
progress.Increment();
|
||||
}
|
||||
|
||||
plconfig.color_format = VRAM_RT_FORMAT;
|
||||
plconfig.depth_format = GPUTexture::Format::Unknown;
|
||||
plconfig.SetTargetFormats(VRAM_RT_FORMAT);
|
||||
plconfig.depth = GPUPipeline::DepthState::GetNoTestsState();
|
||||
plconfig.blend = GPUPipeline::BlendState::GetNoBlendingState();
|
||||
plconfig.samples = 1;
|
||||
|
@ -1181,7 +1155,7 @@ bool GPU_HW::CompilePipelines()
|
|||
return false;
|
||||
GL_OBJECT_NAME(fs, "Downsample Blur Pass Fragment Shader");
|
||||
plconfig.fragment_shader = fs.get();
|
||||
plconfig.color_format = GPUTexture::Format::R8;
|
||||
plconfig.SetTargetFormats(GPUTexture::Format::R8);
|
||||
if (!(m_downsample_blur_pass_pipeline = g_gpu_device->CreatePipeline(plconfig)))
|
||||
return false;
|
||||
GL_OBJECT_NAME(m_downsample_blur_pass_pipeline, "Downsample Blur Pass Pipeline");
|
||||
|
@ -1193,7 +1167,7 @@ bool GPU_HW::CompilePipelines()
|
|||
GL_OBJECT_NAME(fs, "Downsample Composite Pass Fragment Shader");
|
||||
plconfig.layout = GPUPipeline::Layout::MultiTextureAndPushConstants;
|
||||
plconfig.fragment_shader = fs.get();
|
||||
plconfig.color_format = VRAM_RT_FORMAT;
|
||||
plconfig.SetTargetFormats(VRAM_RT_FORMAT);
|
||||
if (!(m_downsample_composite_pass_pipeline = g_gpu_device->CreatePipeline(plconfig)))
|
||||
return false;
|
||||
GL_OBJECT_NAME(m_downsample_composite_pass_pipeline, "Downsample Blur Pass Pipeline");
|
||||
|
@ -1310,14 +1284,15 @@ void GPU_HW::UpdateDepthBufferFromMaskBit()
|
|||
|
||||
// Viewport should already be set full, only need to fudge the scissor.
|
||||
g_gpu_device->SetScissor(0, 0, m_vram_texture->GetWidth(), m_vram_texture->GetHeight());
|
||||
g_gpu_device->SetFramebuffer(m_vram_update_depth_framebuffer.get());
|
||||
g_gpu_device->InvalidateRenderTarget(m_vram_depth_texture.get());
|
||||
g_gpu_device->SetRenderTargets(nullptr, 0, m_vram_depth_texture.get());
|
||||
g_gpu_device->SetPipeline(m_vram_update_depth_pipeline.get());
|
||||
g_gpu_device->SetTextureSampler(0, m_vram_texture.get(), g_gpu_device->GetNearestSampler());
|
||||
g_gpu_device->Draw(3, 0);
|
||||
|
||||
// Restore.
|
||||
g_gpu_device->SetTextureSampler(0, m_vram_read_texture.get(), g_gpu_device->GetNearestSampler());
|
||||
g_gpu_device->SetFramebuffer(m_vram_framebuffer.get());
|
||||
g_gpu_device->SetRenderTarget(m_vram_texture.get(), m_vram_depth_texture.get());
|
||||
SetScissor();
|
||||
}
|
||||
|
||||
|
@ -2061,7 +2036,7 @@ bool GPU_HW::BlitVRAMReplacementTexture(const TextureReplacementTexture* tex, u3
|
|||
}
|
||||
}
|
||||
|
||||
g_gpu_device->SetFramebuffer(m_vram_framebuffer.get()); // TODO: needed?
|
||||
g_gpu_device->SetRenderTarget(m_vram_texture.get(), m_vram_depth_texture.get()); // TODO: needed?
|
||||
g_gpu_device->SetTextureSampler(0, m_vram_replacement_texture.get(), g_gpu_device->GetLinearSampler());
|
||||
g_gpu_device->SetPipeline(m_copy_pipeline.get());
|
||||
g_gpu_device->SetViewportAndScissor(dst_x, dst_y, width, height);
|
||||
|
@ -2364,7 +2339,7 @@ void GPU_HW::ReadVRAM(u32 x, u32 y, u32 width, u32 height)
|
|||
|
||||
// Encode the 24-bit texture as 16-bit.
|
||||
const u32 uniforms[4] = {copy_rect.left, copy_rect.top, copy_rect.GetWidth(), copy_rect.GetHeight()};
|
||||
g_gpu_device->SetFramebuffer(m_vram_readback_framebuffer.get());
|
||||
g_gpu_device->SetRenderTarget(m_vram_readback_texture.get());
|
||||
g_gpu_device->SetPipeline(m_vram_readback_pipeline.get());
|
||||
g_gpu_device->SetTextureSampler(0, m_vram_texture.get(), g_gpu_device->GetNearestSampler());
|
||||
g_gpu_device->SetViewportAndScissor(0, 0, encoded_width, encoded_height);
|
||||
|
@ -2811,7 +2786,7 @@ void GPU_HW::UpdateDisplay()
|
|||
if (interlaced == InterlacedRenderMode::None)
|
||||
g_gpu_device->InvalidateRenderTarget(m_display_private_texture.get());
|
||||
|
||||
g_gpu_device->SetFramebuffer(m_display_framebuffer.get());
|
||||
g_gpu_device->SetRenderTarget(m_display_private_texture.get());
|
||||
g_gpu_device->SetPipeline(
|
||||
m_display_pipelines[BoolToUInt8(m_GPUSTAT.display_area_color_depth_24)][static_cast<u8>(interlaced)].get());
|
||||
g_gpu_device->SetTextureSampler(0, m_vram_texture.get(), g_gpu_device->GetNearestSampler());
|
||||
|
@ -2883,7 +2858,7 @@ void GPU_HW::DownsampleFramebufferAdaptive(GPUTexture* source, u32 left, u32 top
|
|||
uniforms.lod = static_cast<float>(level - 1);
|
||||
|
||||
g_gpu_device->ClearRenderTarget(m_downsample_render_texture.get(), 0);
|
||||
g_gpu_device->SetFramebuffer(m_downsample_framebuffer.get());
|
||||
g_gpu_device->SetRenderTarget(m_downsample_render_texture.get());
|
||||
g_gpu_device->SetViewportAndScissor(0, 0, level_width, level_height);
|
||||
g_gpu_device->SetPipeline((level == 1) ? m_downsample_first_pass_pipeline.get() :
|
||||
m_downsample_mid_pass_pipeline.get());
|
||||
|
@ -2912,7 +2887,7 @@ void GPU_HW::DownsampleFramebufferAdaptive(GPUTexture* source, u32 left, u32 top
|
|||
|
||||
m_downsample_render_texture->MakeReadyForSampling();
|
||||
g_gpu_device->ClearRenderTarget(m_downsample_weight_texture.get(), 0);
|
||||
g_gpu_device->SetFramebuffer(m_downsample_weight_framebuffer.get());
|
||||
g_gpu_device->SetRenderTarget(m_downsample_weight_texture.get());
|
||||
g_gpu_device->SetTextureSampler(0, m_downsample_render_texture.get(), g_gpu_device->GetNearestSampler());
|
||||
g_gpu_device->SetViewportAndScissor(0, 0, last_width, last_height);
|
||||
g_gpu_device->SetPipeline(m_downsample_blur_pass_pipeline.get());
|
||||
|
@ -2926,7 +2901,7 @@ void GPU_HW::DownsampleFramebufferAdaptive(GPUTexture* source, u32 left, u32 top
|
|||
GL_SCOPE("Composite");
|
||||
|
||||
g_gpu_device->ClearRenderTarget(m_downsample_render_texture.get(), 0);
|
||||
g_gpu_device->SetFramebuffer(m_downsample_framebuffer.get());
|
||||
g_gpu_device->SetRenderTarget(m_downsample_render_texture.get());
|
||||
g_gpu_device->SetTextureSampler(0, m_downsample_texture.get(), m_downsample_composite_sampler.get());
|
||||
g_gpu_device->SetTextureSampler(1, m_downsample_weight_texture.get(), m_downsample_lod_sampler.get());
|
||||
g_gpu_device->SetViewportAndScissor(0, 0, width, height);
|
||||
|
@ -2953,7 +2928,7 @@ void GPU_HW::DownsampleFramebufferBoxFilter(GPUTexture* source, u32 left, u32 to
|
|||
source->MakeReadyForSampling();
|
||||
|
||||
g_gpu_device->ClearRenderTarget(m_downsample_render_texture.get(), 0);
|
||||
g_gpu_device->SetFramebuffer(m_downsample_framebuffer.get());
|
||||
g_gpu_device->SetRenderTarget(m_downsample_render_texture.get());
|
||||
g_gpu_device->SetPipeline(m_downsample_first_pass_pipeline.get());
|
||||
g_gpu_device->SetTextureSampler(0, source, g_gpu_device->GetNearestSampler());
|
||||
g_gpu_device->SetViewportAndScissor(ds_left, ds_top, ds_width, ds_height);
|
||||
|
|
|
@ -213,11 +213,6 @@ private:
|
|||
std::unique_ptr<GPUTexture> m_vram_replacement_texture;
|
||||
std::unique_ptr<GPUTexture> m_display_private_texture; // TODO: Move to base.
|
||||
|
||||
std::unique_ptr<GPUFramebuffer> m_vram_framebuffer;
|
||||
std::unique_ptr<GPUFramebuffer> m_vram_update_depth_framebuffer;
|
||||
std::unique_ptr<GPUFramebuffer> m_vram_readback_framebuffer;
|
||||
std::unique_ptr<GPUFramebuffer> m_display_framebuffer;
|
||||
|
||||
std::unique_ptr<GPUTextureBuffer> m_vram_upload_buffer;
|
||||
std::unique_ptr<GPUTexture> m_vram_write_texture;
|
||||
|
||||
|
@ -288,9 +283,7 @@ private:
|
|||
|
||||
std::unique_ptr<GPUTexture> m_downsample_texture;
|
||||
std::unique_ptr<GPUTexture> m_downsample_render_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;
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
#pragma once
|
||||
#include "common/types.h"
|
||||
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 10;
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 11;
|
|
@ -23,6 +23,7 @@ add_library(util
|
|||
cue_parser.h
|
||||
gpu_device.cpp
|
||||
gpu_device.h
|
||||
gpu_framebuffer_manager.h
|
||||
gpu_shader_cache.cpp
|
||||
gpu_shader_cache.h
|
||||
gpu_texture.cpp
|
||||
|
@ -72,7 +73,7 @@ target_precompile_headers(util PRIVATE "pch.h")
|
|||
target_include_directories(util PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..")
|
||||
target_include_directories(util PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..")
|
||||
target_link_libraries(util PUBLIC common simpleini imgui)
|
||||
target_link_libraries(util PRIVATE stb libchdr zlib soundtouch Zstd::Zstd reshadefx)
|
||||
target_link_libraries(util PRIVATE stb libchdr zlib soundtouch xxhash Zstd::Zstd reshadefx)
|
||||
|
||||
if(ENABLE_CUBEB)
|
||||
target_sources(util PRIVATE
|
||||
|
|
|
@ -536,24 +536,35 @@ void D3D11Device::ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u3
|
|||
src11->GetD3DTexture(), 0, dst11->GetDXGIFormat());
|
||||
}
|
||||
|
||||
bool D3D11Device::IsRenderTargetBound(const GPUTexture* tex) const
|
||||
{
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
if (m_current_render_targets[i] == tex)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void D3D11Device::ClearRenderTarget(GPUTexture* t, u32 c)
|
||||
{
|
||||
GPUDevice::ClearRenderTarget(t, c);
|
||||
if (m_current_framebuffer && m_current_framebuffer->GetRT() == t)
|
||||
if (IsRenderTargetBound(t))
|
||||
static_cast<D3D11Texture*>(t)->CommitClear(m_context.Get());
|
||||
}
|
||||
|
||||
void D3D11Device::ClearDepth(GPUTexture* t, float d)
|
||||
{
|
||||
GPUDevice::ClearDepth(t, d);
|
||||
if (m_current_framebuffer && m_current_framebuffer->GetDS() == t)
|
||||
if (m_current_depth_target == t)
|
||||
static_cast<D3D11Texture*>(t)->CommitClear(m_context.Get());
|
||||
}
|
||||
|
||||
void D3D11Device::InvalidateRenderTarget(GPUTexture* t)
|
||||
{
|
||||
GPUDevice::InvalidateRenderTarget(t);
|
||||
if (m_current_framebuffer && (m_current_framebuffer->GetRT() == t || m_current_framebuffer->GetDS() == t))
|
||||
if (t->IsRenderTarget() ? IsRenderTargetBound(t) : (m_current_depth_target == t))
|
||||
static_cast<D3D11Texture*>(t)->CommitClear(m_context.Get());
|
||||
}
|
||||
|
||||
|
@ -613,13 +624,15 @@ bool D3D11Device::BeginPresent(bool skip_present)
|
|||
static constexpr float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
m_context->ClearRenderTargetView(m_swap_chain_rtv.Get(), clear_color);
|
||||
m_context->OMSetRenderTargets(1, m_swap_chain_rtv.GetAddressOf(), nullptr);
|
||||
m_current_framebuffer = nullptr;
|
||||
m_num_current_render_targets = 0;
|
||||
std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
|
||||
m_current_depth_target = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D11Device::EndPresent()
|
||||
{
|
||||
DebugAssert(!m_current_framebuffer);
|
||||
DebugAssert(m_num_current_render_targets == 0 && !m_current_depth_target);
|
||||
|
||||
if (!m_vsync_enabled && m_gpu_timing_enabled)
|
||||
PopTimestampQuery();
|
||||
|
@ -873,34 +886,17 @@ void D3D11Device::UnmapUniformBuffer(u32 size)
|
|||
m_context->PSSetConstantBuffers1(0, 1, m_uniform_buffer.GetD3DBufferArray(), &first_constant, &num_constants);
|
||||
}
|
||||
|
||||
void D3D11Device::SetFramebuffer(GPUFramebuffer* fb)
|
||||
void D3D11Device::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds)
|
||||
{
|
||||
if (m_current_framebuffer == fb)
|
||||
return;
|
||||
ID3D11RenderTargetView* rtvs[MAX_RENDER_TARGETS];
|
||||
|
||||
m_current_framebuffer = static_cast<D3D11Framebuffer*>(fb);
|
||||
if (!m_current_framebuffer)
|
||||
{
|
||||
m_context->OMSetRenderTargets(0, nullptr, nullptr);
|
||||
return;
|
||||
}
|
||||
bool changed = (m_num_current_render_targets != num_rts || m_current_depth_target != ds);
|
||||
m_current_depth_target = static_cast<D3D11Texture*>(ds);
|
||||
|
||||
// Make sure textures aren't bound.
|
||||
if (D3D11Texture* rt = static_cast<D3D11Texture*>(fb->GetRT()); rt)
|
||||
if (ds)
|
||||
{
|
||||
const ID3D11ShaderResourceView* srv = rt->GetD3DSRV();
|
||||
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
||||
{
|
||||
if (m_current_textures[i] == srv)
|
||||
{
|
||||
m_current_textures[i] = nullptr;
|
||||
m_context->PSSetShaderResources(i, 1, &m_current_textures[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (D3D11Texture* ds = static_cast<D3D11Texture*>(fb->GetDS()); ds)
|
||||
{
|
||||
const ID3D11ShaderResourceView* srv = ds->GetD3DSRV();
|
||||
const ID3D11ShaderResourceView* srv = static_cast<D3D11Texture*>(ds)->GetD3DSRV();
|
||||
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
||||
{
|
||||
if (m_current_textures[i] == srv)
|
||||
|
@ -911,18 +907,31 @@ void D3D11Device::SetFramebuffer(GPUFramebuffer* fb)
|
|||
}
|
||||
}
|
||||
|
||||
m_current_framebuffer->CommitClear(m_context.Get());
|
||||
m_context->OMSetRenderTargets(m_current_framebuffer->GetNumRTVs(), m_current_framebuffer->GetRTVArray(),
|
||||
m_current_framebuffer->GetDSV());
|
||||
}
|
||||
for (u32 i = 0; i < num_rts; i++)
|
||||
{
|
||||
D3D11Texture* const dt = static_cast<D3D11Texture*>(rts[i]);
|
||||
changed |= m_current_render_targets[i] != dt;
|
||||
m_current_render_targets[i] = dt;
|
||||
rtvs[i] = dt->GetD3DRTV();
|
||||
dt->CommitClear(m_context.Get());
|
||||
|
||||
void D3D11Device::UnbindFramebuffer(D3D11Framebuffer* fb)
|
||||
{
|
||||
if (m_current_framebuffer != fb)
|
||||
const ID3D11ShaderResourceView* srv = dt->GetD3DSRV();
|
||||
for (u32 j = 0; j < MAX_TEXTURE_SAMPLERS; j++)
|
||||
{
|
||||
if (m_current_textures[j] == srv)
|
||||
{
|
||||
m_current_textures[j] = nullptr;
|
||||
m_context->PSSetShaderResources(j, 1, &m_current_textures[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (u32 i = num_rts; i < m_num_current_render_targets; i++)
|
||||
m_current_render_targets[i] = nullptr;
|
||||
m_num_current_render_targets = num_rts;
|
||||
if (!changed)
|
||||
return;
|
||||
|
||||
m_current_framebuffer = nullptr;
|
||||
m_context->OMSetRenderTargets(0, nullptr, nullptr);
|
||||
m_context->OMSetRenderTargets(num_rts, rtvs, ds ? static_cast<D3D11Texture*>(ds)->GetD3DDSV() : nullptr);
|
||||
}
|
||||
|
||||
void D3D11Device::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler)
|
||||
|
@ -931,8 +940,7 @@ void D3D11Device::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* s
|
|||
ID3D11SamplerState* S = sampler ? static_cast<D3D11Sampler*>(sampler)->GetSamplerState() : nullptr;
|
||||
|
||||
// Runtime will null these if we don't...
|
||||
DebugAssert(!m_current_framebuffer || !texture ||
|
||||
(m_current_framebuffer->GetRT() != texture && m_current_framebuffer->GetDS() != texture));
|
||||
DebugAssert(!texture || !IsRenderTargetBound(texture) || m_current_depth_target != texture);
|
||||
|
||||
if (m_current_textures[slot] != T)
|
||||
{
|
||||
|
@ -970,8 +978,23 @@ void D3D11Device::UnbindTexture(D3D11Texture* tex)
|
|||
}
|
||||
}
|
||||
|
||||
if (m_current_framebuffer && m_current_framebuffer->GetRT() == tex)
|
||||
SetFramebuffer(nullptr);
|
||||
if (tex->IsRenderTarget())
|
||||
{
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
if (m_current_render_targets[i] == tex)
|
||||
{
|
||||
Log_WarningPrint("Unbinding current RT");
|
||||
SetRenderTargets(nullptr, 0, m_current_depth_target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_current_depth_target == tex)
|
||||
{
|
||||
Log_WarningPrint("Unbinding current DS");
|
||||
SetRenderTargets(nullptr, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void D3D11Device::SetViewport(s32 x, s32 y, s32 width, s32 height)
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <vector>
|
||||
#include <wrl/client.h>
|
||||
|
||||
class D3D11Framebuffer;
|
||||
class D3D11Pipeline;
|
||||
class D3D11Shader;
|
||||
class D3D11Texture;
|
||||
|
@ -66,8 +65,6 @@ public:
|
|||
void ClearDepth(GPUTexture* t, float d) override;
|
||||
void InvalidateRenderTarget(GPUTexture* t) override;
|
||||
|
||||
std::unique_ptr<GPUFramebuffer> CreateFramebuffer(GPUTexture* rt_or_ds, GPUTexture* ds = nullptr) override;
|
||||
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, const std::string_view& source,
|
||||
const char* entry_point, DynamicHeapArray<u8>* binary) override;
|
||||
|
@ -85,7 +82,7 @@ public:
|
|||
void PushUniformBuffer(const void* data, u32 data_size) override;
|
||||
void* MapUniformBuffer(u32 size) override;
|
||||
void UnmapUniformBuffer(u32 size) override;
|
||||
void SetFramebuffer(GPUFramebuffer* fb) override;
|
||||
void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds) override;
|
||||
void SetPipeline(GPUPipeline* pipeline) override;
|
||||
void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
|
||||
void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
|
||||
|
@ -104,14 +101,14 @@ public:
|
|||
bool BeginPresent(bool skip_present) override;
|
||||
void EndPresent() override;
|
||||
|
||||
void UnbindFramebuffer(D3D11Framebuffer* fb);
|
||||
void UnbindPipeline(D3D11Pipeline* pl);
|
||||
void UnbindTexture(D3D11Texture* tex);
|
||||
|
||||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
||||
|
||||
protected:
|
||||
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features) override;
|
||||
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
|
||||
FeatureMask disabled_features) override;
|
||||
void DestroyDevice() override;
|
||||
|
||||
private:
|
||||
|
@ -141,6 +138,8 @@ private:
|
|||
bool CreateBuffers();
|
||||
void DestroyBuffers();
|
||||
|
||||
bool IsRenderTargetBound(const GPUTexture* tex) const;
|
||||
|
||||
ComPtr<ID3D11RasterizerState> GetRasterizationState(const GPUPipeline::RasterizationState& rs);
|
||||
ComPtr<ID3D11DepthStencilState> GetDepthState(const GPUPipeline::DepthState& ds);
|
||||
ComPtr<ID3D11BlendState> GetBlendState(const GPUPipeline::BlendState& bs);
|
||||
|
@ -178,8 +177,10 @@ private:
|
|||
D3D11StreamBuffer m_index_buffer;
|
||||
D3D11StreamBuffer m_uniform_buffer;
|
||||
|
||||
D3D11Framebuffer* m_current_framebuffer = nullptr;
|
||||
D3D11Pipeline* m_current_pipeline = nullptr;
|
||||
std::array<D3D11Texture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
|
||||
u32 m_num_current_render_targets = 0;
|
||||
D3D11Texture* m_current_depth_target = nullptr;
|
||||
|
||||
ID3D11InputLayout* m_current_input_layout = nullptr;
|
||||
ID3D11VertexShader* m_current_vertex_shader = nullptr;
|
||||
|
|
|
@ -93,73 +93,6 @@ bool D3D11Device::SupportsTextureFormat(GPUTexture::Format format) const
|
|||
return (SUCCEEDED(m_device->CheckFormatSupport(dfmt, &support)) && ((support & required) == required));
|
||||
}
|
||||
|
||||
D3D11Framebuffer::D3D11Framebuffer(GPUTexture* rt, GPUTexture* ds, u32 width, u32 height,
|
||||
ComPtr<ID3D11RenderTargetView> rtv, ComPtr<ID3D11DepthStencilView> dsv)
|
||||
: GPUFramebuffer(rt, ds, width, height), m_rtv(std::move(rtv)), m_dsv(std::move(dsv))
|
||||
{
|
||||
}
|
||||
|
||||
D3D11Framebuffer::~D3D11Framebuffer()
|
||||
{
|
||||
D3D11Device::GetInstance().UnbindFramebuffer(this);
|
||||
}
|
||||
|
||||
void D3D11Framebuffer::SetDebugName(const std::string_view& name)
|
||||
{
|
||||
if (m_rtv)
|
||||
SetD3DDebugObjectName(m_rtv.Get(), fmt::format("{} RTV", name));
|
||||
if (m_dsv)
|
||||
SetD3DDebugObjectName(m_dsv.Get(), fmt::format("{} DSV", name));
|
||||
}
|
||||
|
||||
void D3D11Framebuffer::CommitClear(ID3D11DeviceContext1* context)
|
||||
{
|
||||
if (m_rt && m_rt->GetState() != GPUTexture::State::Dirty) [[unlikely]]
|
||||
{
|
||||
if (m_rt->GetState() == GPUTexture::State::Invalidated)
|
||||
context->DiscardView(m_rtv.Get());
|
||||
else
|
||||
context->ClearRenderTargetView(m_rtv.Get(), m_rt->GetUNormClearColor().data());
|
||||
|
||||
m_rt->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
|
||||
if (m_ds && m_ds->GetState() != GPUTexture::State::Dirty) [[unlikely]]
|
||||
{
|
||||
if (m_ds->GetState() == GPUTexture::State::Invalidated)
|
||||
context->DiscardView(m_dsv.Get());
|
||||
else
|
||||
context->ClearDepthStencilView(m_dsv.Get(), D3D11_CLEAR_DEPTH, m_ds->GetClearDepth(), 0);
|
||||
|
||||
m_ds->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUFramebuffer> D3D11Device::CreateFramebuffer(GPUTexture* rt_or_ds, GPUTexture* ds)
|
||||
{
|
||||
DebugAssert((rt_or_ds || ds) && (!rt_or_ds || rt_or_ds->IsRenderTarget() || (rt_or_ds->IsDepthStencil() && !ds)));
|
||||
D3D11Texture* RT = static_cast<D3D11Texture*>((rt_or_ds && rt_or_ds->IsDepthStencil()) ? nullptr : rt_or_ds);
|
||||
D3D11Texture* DS = static_cast<D3D11Texture*>((rt_or_ds && rt_or_ds->IsDepthStencil()) ? rt_or_ds : ds);
|
||||
|
||||
ComPtr<ID3D11RenderTargetView> rtv;
|
||||
if (RT)
|
||||
{
|
||||
rtv = RT->GetD3DRTV();
|
||||
Assert(rtv);
|
||||
}
|
||||
|
||||
ComPtr<ID3D11DepthStencilView> dsv;
|
||||
if (DS)
|
||||
{
|
||||
dsv = DS->GetD3DDSV();
|
||||
Assert(dsv);
|
||||
}
|
||||
|
||||
return std::unique_ptr<GPUFramebuffer>(new D3D11Framebuffer(RT, DS, RT ? RT->GetWidth() : DS->GetWidth(),
|
||||
RT ? RT->GetHeight() : DS->GetHeight(), std::move(rtv),
|
||||
std::move(dsv)));
|
||||
}
|
||||
|
||||
D3D11Sampler::D3D11Sampler(ComPtr<ID3D11SamplerState> ss) : m_ss(std::move(ss))
|
||||
{
|
||||
}
|
||||
|
|
|
@ -13,32 +13,6 @@
|
|||
|
||||
class D3D11Device;
|
||||
|
||||
class D3D11Framebuffer final : public GPUFramebuffer
|
||||
{
|
||||
friend D3D11Device;
|
||||
|
||||
template<typename T>
|
||||
using ComPtr = Microsoft::WRL::ComPtr<T>;
|
||||
|
||||
public:
|
||||
~D3D11Framebuffer() override;
|
||||
|
||||
ALWAYS_INLINE u32 GetNumRTVs() const { return m_rtv ? 1 : 0; }
|
||||
ALWAYS_INLINE ID3D11RenderTargetView* GetRTV() const { return m_rtv.Get(); }
|
||||
ALWAYS_INLINE ID3D11RenderTargetView* const* GetRTVArray() const { return m_rtv.GetAddressOf(); }
|
||||
ALWAYS_INLINE ID3D11DepthStencilView* GetDSV() const { return m_dsv.Get(); }
|
||||
|
||||
void SetDebugName(const std::string_view& name) override;
|
||||
void CommitClear(ID3D11DeviceContext1* context);
|
||||
|
||||
private:
|
||||
D3D11Framebuffer(GPUTexture* rt, GPUTexture* ds, u32 width, u32 height, ComPtr<ID3D11RenderTargetView> rtv,
|
||||
ComPtr<ID3D11DepthStencilView> dsv);
|
||||
|
||||
ComPtr<ID3D11RenderTargetView> m_rtv;
|
||||
ComPtr<ID3D11DepthStencilView> m_dsv;
|
||||
};
|
||||
|
||||
class D3D11Sampler final : public GPUSampler
|
||||
{
|
||||
friend D3D11Device;
|
||||
|
|
|
@ -570,12 +570,9 @@ void D3D12Device::SubmitCommandListAndRestartRenderPass(const char* reason)
|
|||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
|
||||
D3D12Framebuffer* fb = m_current_framebuffer;
|
||||
D3D12Pipeline* pl = m_current_pipeline;
|
||||
SubmitCommandList(false, "%s", reason);
|
||||
|
||||
if (fb)
|
||||
SetFramebuffer(fb);
|
||||
SetPipeline(pl);
|
||||
BeginRenderPass();
|
||||
}
|
||||
|
@ -1091,7 +1088,7 @@ bool D3D12Device::BeginPresent(bool frame_skip)
|
|||
|
||||
void D3D12Device::EndPresent()
|
||||
{
|
||||
DebugAssert(InRenderPass() && !m_current_framebuffer);
|
||||
DebugAssert(InRenderPass() && m_num_current_render_targets == 0 && !m_current_depth_target);
|
||||
EndRenderPass();
|
||||
|
||||
const auto& swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer];
|
||||
|
@ -1316,25 +1313,22 @@ void D3D12Device::ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u3
|
|||
void D3D12Device::ClearRenderTarget(GPUTexture* t, u32 c)
|
||||
{
|
||||
GPUDevice::ClearRenderTarget(t, c);
|
||||
if (InRenderPass() && m_current_framebuffer && m_current_framebuffer->GetRT() == t)
|
||||
if (InRenderPass() && IsRenderTargetBound(t))
|
||||
EndRenderPass();
|
||||
}
|
||||
|
||||
void D3D12Device::ClearDepth(GPUTexture* t, float d)
|
||||
{
|
||||
GPUDevice::ClearDepth(t, d);
|
||||
if (InRenderPass() && m_current_framebuffer && m_current_framebuffer->GetDS() == t)
|
||||
if (InRenderPass() && m_current_depth_target == t)
|
||||
EndRenderPass();
|
||||
}
|
||||
|
||||
void D3D12Device::InvalidateRenderTarget(GPUTexture* t)
|
||||
{
|
||||
GPUDevice::InvalidateRenderTarget(t);
|
||||
if (InRenderPass() && m_current_framebuffer &&
|
||||
(m_current_framebuffer->GetRT() == t || m_current_framebuffer->GetDS() == t))
|
||||
{
|
||||
if (InRenderPass() && (t->IsRenderTarget() ? IsRenderTargetBound(t) : (m_current_depth_target == t)))
|
||||
EndRenderPass();
|
||||
}
|
||||
}
|
||||
|
||||
bool D3D12Device::CreateBuffers()
|
||||
|
@ -1530,60 +1524,71 @@ void D3D12Device::DestroyRootSignatures()
|
|||
it->Reset();
|
||||
}
|
||||
|
||||
void D3D12Device::SetFramebuffer(GPUFramebuffer* fb)
|
||||
void D3D12Device::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds)
|
||||
{
|
||||
if (m_current_framebuffer == fb)
|
||||
return;
|
||||
|
||||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
|
||||
m_current_framebuffer = static_cast<D3D12Framebuffer*>(fb);
|
||||
ID3D12GraphicsCommandList4* cmdlist = GetCommandList();
|
||||
|
||||
m_current_depth_target = static_cast<D3D12Texture*>(ds);
|
||||
for (u32 i = 0; i < num_rts; i++)
|
||||
{
|
||||
D3D12Texture* const dt = static_cast<D3D12Texture*>(rts[i]);
|
||||
m_current_render_targets[i] = dt;
|
||||
dt->CommitClear(cmdlist);
|
||||
}
|
||||
for (u32 i = num_rts; i < m_num_current_render_targets; i++)
|
||||
m_current_render_targets[i] = nullptr;
|
||||
m_num_current_render_targets = num_rts;
|
||||
}
|
||||
|
||||
void D3D12Device::BeginRenderPass()
|
||||
{
|
||||
DebugAssert(!InRenderPass());
|
||||
|
||||
D3D12_RENDER_PASS_RENDER_TARGET_DESC rt_desc;
|
||||
std::array<D3D12_RENDER_PASS_RENDER_TARGET_DESC, MAX_RENDER_TARGETS> rt_desc;
|
||||
D3D12_RENDER_PASS_DEPTH_STENCIL_DESC ds_desc;
|
||||
const D3D12_RENDER_PASS_RENDER_TARGET_DESC* rt_desc_p = nullptr;
|
||||
const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC* ds_desc_p = nullptr;
|
||||
|
||||
D3D12_RENDER_PASS_RENDER_TARGET_DESC* rt_desc_p = nullptr;
|
||||
D3D12_RENDER_PASS_DEPTH_STENCIL_DESC* ds_desc_p = nullptr;
|
||||
u32 num_rt_descs = 0;
|
||||
|
||||
ID3D12GraphicsCommandList4* cmdlist = GetCommandList();
|
||||
|
||||
if (m_current_framebuffer) [[likely]]
|
||||
if (m_num_current_render_targets > 0 || m_current_depth_target) [[likely]]
|
||||
{
|
||||
D3D12Texture* rt = static_cast<D3D12Texture*>(m_current_framebuffer->GetRT());
|
||||
if (rt)
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
D3D12Texture* const rt = m_current_render_targets[i];
|
||||
rt->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
rt->SetUseFenceValue(GetCurrentFenceValue());
|
||||
rt_desc_p = &rt_desc;
|
||||
rt_desc.cpuDescriptor = rt->GetWriteDescriptor();
|
||||
rt_desc.EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
|
||||
|
||||
D3D12_RENDER_PASS_RENDER_TARGET_DESC& desc = rt_desc[i];
|
||||
desc.cpuDescriptor = rt->GetWriteDescriptor();
|
||||
desc.EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
|
||||
|
||||
switch (rt->GetState())
|
||||
{
|
||||
case GPUTexture::State::Cleared:
|
||||
{
|
||||
rt_desc.BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
|
||||
std::memcpy(rt_desc.BeginningAccess.Clear.ClearValue.Color, rt->GetUNormClearColor().data(),
|
||||
sizeof(rt_desc.BeginningAccess.Clear.ClearValue.Color));
|
||||
desc.BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR;
|
||||
std::memcpy(desc.BeginningAccess.Clear.ClearValue.Color, rt->GetUNormClearColor().data(),
|
||||
sizeof(desc.BeginningAccess.Clear.ClearValue.Color));
|
||||
rt->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Invalidated:
|
||||
{
|
||||
rt_desc.BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD;
|
||||
desc.BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD;
|
||||
rt->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Dirty:
|
||||
{
|
||||
rt_desc.BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE;
|
||||
desc.BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1593,9 +1598,11 @@ void D3D12Device::BeginRenderPass()
|
|||
}
|
||||
}
|
||||
|
||||
D3D12Texture* ds = static_cast<D3D12Texture*>(m_current_framebuffer->GetDS());
|
||||
if (ds)
|
||||
rt_desc_p = (m_num_current_render_targets > 0) ? rt_desc.data() : nullptr;
|
||||
num_rt_descs = m_num_current_render_targets;
|
||||
if (m_current_depth_target)
|
||||
{
|
||||
D3D12Texture* const ds = m_current_depth_target;
|
||||
ds->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
ds->SetUseFenceValue(GetCurrentFenceValue());
|
||||
ds_desc_p = &ds_desc;
|
||||
|
@ -1631,16 +1638,19 @@ void D3D12Device::BeginRenderPass()
|
|||
UnreachableCode();
|
||||
break;
|
||||
}
|
||||
|
||||
ds_desc_p = &ds_desc;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Re-rendering to swap chain.
|
||||
const auto& swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer];
|
||||
rt_desc = {swap_chain_buf.second,
|
||||
{D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE, {}},
|
||||
{D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, {}}};
|
||||
rt_desc_p = &rt_desc;
|
||||
rt_desc[0] = {swap_chain_buf.second,
|
||||
{D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE, {}},
|
||||
{D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, {}}};
|
||||
rt_desc_p = &rt_desc[0];
|
||||
num_rt_descs = 1;
|
||||
}
|
||||
|
||||
// All textures should be in shader read only optimal already, but just in case..
|
||||
|
@ -1652,7 +1662,7 @@ void D3D12Device::BeginRenderPass()
|
|||
}
|
||||
|
||||
DebugAssert(rt_desc_p || ds_desc_p);
|
||||
cmdlist->BeginRenderPass(rt_desc_p ? 1 : 0, rt_desc_p, ds_desc_p, D3D12_RENDER_PASS_FLAG_NONE);
|
||||
cmdlist->BeginRenderPass(num_rt_descs, rt_desc_p, ds_desc_p, D3D12_RENDER_PASS_FLAG_NONE);
|
||||
|
||||
// TODO: Stats
|
||||
m_in_render_pass = true;
|
||||
|
@ -1686,7 +1696,9 @@ void D3D12Device::BeginSwapChainRenderPass()
|
|||
{D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, {}}};
|
||||
cmdlist->BeginRenderPass(1, &rt_desc, nullptr, D3D12_RENDER_PASS_FLAG_NONE);
|
||||
|
||||
m_current_framebuffer = nullptr;
|
||||
std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
|
||||
m_num_current_render_targets = 0;
|
||||
m_current_depth_target = nullptr;
|
||||
m_in_render_pass = true;
|
||||
|
||||
// Clear pipeline, it's likely incompatible.
|
||||
|
@ -1708,29 +1720,6 @@ void D3D12Device::EndRenderPass()
|
|||
GetCommandList()->EndRenderPass();
|
||||
}
|
||||
|
||||
void D3D12Device::UnbindFramebuffer(D3D12Framebuffer* fb)
|
||||
{
|
||||
if (m_current_framebuffer != fb)
|
||||
return;
|
||||
|
||||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
m_current_framebuffer = nullptr;
|
||||
}
|
||||
|
||||
void D3D12Device::UnbindFramebuffer(D3D12Texture* tex)
|
||||
{
|
||||
if (!m_current_framebuffer)
|
||||
return;
|
||||
|
||||
if (m_current_framebuffer->GetRT() != tex && m_current_framebuffer->GetDS() != tex)
|
||||
return;
|
||||
|
||||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
m_current_framebuffer = nullptr;
|
||||
}
|
||||
|
||||
void D3D12Device::SetPipeline(GPUPipeline* pipeline)
|
||||
{
|
||||
// First draw? Bind everything.
|
||||
|
@ -1789,11 +1778,21 @@ void D3D12Device::UnbindPipeline(D3D12Pipeline* pl)
|
|||
m_current_pipeline = nullptr;
|
||||
}
|
||||
|
||||
bool D3D12Device::IsRenderTargetBound(const GPUTexture* tex) const
|
||||
{
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
if (m_current_render_targets[i] == tex)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void D3D12Device::InvalidateCachedState()
|
||||
{
|
||||
m_dirty_flags = ALL_DIRTY_STATE;
|
||||
m_in_render_pass = false;
|
||||
m_current_framebuffer = nullptr;
|
||||
m_current_pipeline = nullptr;
|
||||
m_current_vertex_stride = 0;
|
||||
m_current_blend_constant = 0;
|
||||
|
@ -1901,6 +1900,28 @@ void D3D12Device::UnbindTexture(D3D12Texture* tex)
|
|||
m_dirty_flags |= DIRTY_FLAG_TEXTURES;
|
||||
}
|
||||
}
|
||||
|
||||
if (tex->IsRenderTarget())
|
||||
{
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
if (m_current_render_targets[i] == tex)
|
||||
{
|
||||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
m_current_render_targets[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tex->IsDepthStencil())
|
||||
{
|
||||
if (m_current_depth_target == tex)
|
||||
{
|
||||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
m_current_depth_target = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12Device::UnbindTextureBuffer(D3D12TextureBuffer* buf)
|
||||
|
|
|
@ -86,8 +86,6 @@ public:
|
|||
void ClearDepth(GPUTexture* t, float d) override;
|
||||
void InvalidateRenderTarget(GPUTexture* t) override;
|
||||
|
||||
std::unique_ptr<GPUFramebuffer> CreateFramebuffer(GPUTexture* rt_or_ds, GPUTexture* ds = nullptr) override;
|
||||
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, const std::string_view& source,
|
||||
const char* entry_point, DynamicHeapArray<u8>* out_binary) override;
|
||||
|
@ -105,7 +103,7 @@ public:
|
|||
void PushUniformBuffer(const void* data, u32 data_size) override;
|
||||
void* MapUniformBuffer(u32 size) override;
|
||||
void UnmapUniformBuffer(u32 size) override;
|
||||
void SetFramebuffer(GPUFramebuffer* fb) override;
|
||||
void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds) override;
|
||||
void SetPipeline(GPUPipeline* pipeline) override;
|
||||
void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
|
||||
void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
|
||||
|
@ -172,8 +170,6 @@ public:
|
|||
void SubmitCommandList(bool wait_for_completion, const char* reason, ...);
|
||||
void SubmitCommandListAndRestartRenderPass(const char* reason);
|
||||
|
||||
void UnbindFramebuffer(D3D12Framebuffer* fb);
|
||||
void UnbindFramebuffer(D3D12Texture* tex);
|
||||
void UnbindPipeline(D3D12Pipeline* pl);
|
||||
void UnbindTexture(D3D12Texture* tex);
|
||||
void UnbindTextureBuffer(D3D12TextureBuffer* buf);
|
||||
|
@ -246,6 +242,8 @@ private:
|
|||
bool CreateDSVDescriptor(ID3D12Resource* resource, u32 samples, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
|
||||
bool CreateUAVDescriptor(ID3D12Resource* resource, u32 samples, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
|
||||
|
||||
bool IsRenderTargetBound(const GPUTexture* tex) const;
|
||||
|
||||
bool CheckDownloadBufferSize(u32 required_size);
|
||||
void DestroyDownloadBuffer();
|
||||
|
||||
|
@ -330,10 +328,11 @@ private:
|
|||
// Which bindings/state has to be updated before the next draw.
|
||||
u32 m_dirty_flags = ALL_DIRTY_STATE;
|
||||
|
||||
D3D12Framebuffer* m_current_framebuffer = nullptr;
|
||||
|
||||
D3D12Pipeline* m_current_pipeline = nullptr;
|
||||
D3D12_PRIMITIVE_TOPOLOGY m_current_topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
|
||||
u32 m_num_current_render_targets = 0;
|
||||
std::array<D3D12Texture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
|
||||
D3D12Texture* m_current_depth_target = nullptr;
|
||||
u32 m_current_vertex_stride = 0;
|
||||
u32 m_current_blend_constant = 0;
|
||||
GPUPipeline::Layout m_current_pipeline_layout = GPUPipeline::Layout::SingleTextureAndPushConstants;
|
||||
|
|
|
@ -88,7 +88,7 @@ std::string D3D12Pipeline::GetPipelineName(const GraphicsConfig& config)
|
|||
hash.Update(shader->GetBytecodeData(), shader->GetBytecodeSize());
|
||||
if (const D3D12Shader* shader = static_cast<const D3D12Shader*>(config.geometry_shader))
|
||||
hash.Update(shader->GetBytecodeData(), shader->GetBytecodeSize());
|
||||
hash.Update(&config.color_format, sizeof(config.color_format));
|
||||
hash.Update(&config.color_formats, sizeof(config.color_formats));
|
||||
hash.Update(&config.depth_format, sizeof(config.depth_format));
|
||||
hash.Update(&config.samples, sizeof(config.samples));
|
||||
hash.Update(&config.per_sample_shading, sizeof(config.per_sample_shading));
|
||||
|
@ -212,8 +212,11 @@ std::unique_ptr<GPUPipeline> D3D12Device::CreatePipeline(const GPUPipeline::Grap
|
|||
blend_mapping[static_cast<u8>(config.blend.dst_alpha_blend.GetValue())],
|
||||
op_mapping[static_cast<u8>(config.blend.alpha_blend_op.GetValue())], config.blend.write_mask);
|
||||
|
||||
if (config.color_format != GPUTexture::Format::Unknown)
|
||||
gpb.SetRenderTarget(0, D3DCommon::GetFormatMapping(config.color_format).rtv_format);
|
||||
for (u32 i = 0; i < MAX_RENDER_TARGETS; i++)
|
||||
{
|
||||
if (config.color_formats[i] != GPUTexture::Format::Unknown)
|
||||
gpb.SetRenderTarget(i, D3DCommon::GetFormatMapping(config.color_formats[i]).rtv_format);
|
||||
}
|
||||
|
||||
if (config.depth_format != GPUTexture::Format::Unknown)
|
||||
gpb.SetDepthStencilFormat(D3DCommon::GetFormatMapping(config.depth_format).dsv_format);
|
||||
|
|
|
@ -847,43 +847,6 @@ std::unique_ptr<GPUSampler> D3D12Device::CreateSampler(const GPUSampler::Config&
|
|||
return std::unique_ptr<GPUSampler>(new D3D12Sampler(std::move(handle)));
|
||||
}
|
||||
|
||||
D3D12Framebuffer::D3D12Framebuffer(GPUTexture* rt, GPUTexture* ds, u32 width, u32 height, D3D12DescriptorHandle rtv,
|
||||
D3D12DescriptorHandle dsv)
|
||||
: GPUFramebuffer(rt, ds, width, height), m_rtv(std::move(rtv)), m_dsv(std::move(dsv))
|
||||
{
|
||||
}
|
||||
|
||||
D3D12Framebuffer::~D3D12Framebuffer()
|
||||
{
|
||||
D3D12Device& dev = D3D12Device::GetInstance();
|
||||
if (m_rtv)
|
||||
D3D12Device::GetInstance().DeferDescriptorDestruction(dev.GetRTVHeapManager(), &m_rtv);
|
||||
if (m_dsv)
|
||||
D3D12Device::GetInstance().DeferDescriptorDestruction(dev.GetDSVHeapManager(), &m_dsv);
|
||||
}
|
||||
|
||||
void D3D12Framebuffer::SetDebugName(const std::string_view& name)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUFramebuffer> D3D12Device::CreateFramebuffer(GPUTexture* rt_or_ds, GPUTexture* ds /*= nullptr*/)
|
||||
{
|
||||
DebugAssert((rt_or_ds || ds) && (!rt_or_ds || rt_or_ds->IsRenderTarget() || (rt_or_ds->IsDepthStencil() && !ds)));
|
||||
D3D12Texture* RT = static_cast<D3D12Texture*>((rt_or_ds && rt_or_ds->IsDepthStencil()) ? nullptr : rt_or_ds);
|
||||
D3D12Texture* DS = static_cast<D3D12Texture*>((rt_or_ds && rt_or_ds->IsDepthStencil()) ? rt_or_ds : ds);
|
||||
|
||||
const u32 width = RT ? RT->GetWidth() : DS->GetWidth();
|
||||
const u32 height = RT ? RT->GetHeight() : DS->GetHeight();
|
||||
|
||||
D3D12DescriptorHandle rtv, dsv;
|
||||
if (RT)
|
||||
rtv = RT->GetWriteDescriptor();
|
||||
if (DS)
|
||||
dsv = DS->GetWriteDescriptor();
|
||||
|
||||
return std::unique_ptr<GPUFramebuffer>(new D3D12Framebuffer(RT, DS, width, height, std::move(rtv), std::move(dsv)));
|
||||
}
|
||||
|
||||
D3D12TextureBuffer::D3D12TextureBuffer(Format format, u32 size_in_elements) : GPUTextureBuffer(format, size_in_elements)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -124,26 +124,6 @@ private:
|
|||
D3D12DescriptorHandle m_descriptor;
|
||||
};
|
||||
|
||||
class D3D12Framebuffer final : public GPUFramebuffer
|
||||
{
|
||||
friend D3D12Device;
|
||||
|
||||
public:
|
||||
~D3D12Framebuffer() override;
|
||||
|
||||
ALWAYS_INLINE const D3D12DescriptorHandle& GetRTV() const { return m_rtv; }
|
||||
ALWAYS_INLINE const D3D12DescriptorHandle& GetDSV() const { return m_dsv; }
|
||||
|
||||
void SetDebugName(const std::string_view& name) override;
|
||||
|
||||
private:
|
||||
D3D12Framebuffer(GPUTexture* rt, GPUTexture* ds, u32 width, u32 height, D3D12DescriptorHandle rtv,
|
||||
D3D12DescriptorHandle dsv);
|
||||
|
||||
D3D12DescriptorHandle m_rtv;
|
||||
D3D12DescriptorHandle m_dsv;
|
||||
};
|
||||
|
||||
class D3D12TextureBuffer final : public GPUTextureBuffer
|
||||
{
|
||||
friend D3D12Device;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "gpu_device.h"
|
||||
#include "core/host.h" // TODO: Remove, needed for getting fullscreen mode.
|
||||
#include "core/settings.h" // TODO: Remove, needed for dump directory.
|
||||
#include "gpu_framebuffer_manager.h"
|
||||
#include "shadergen.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
|
@ -15,6 +16,7 @@
|
|||
|
||||
#include "fmt/format.h"
|
||||
#include "imgui.h"
|
||||
#include "xxhash.h"
|
||||
|
||||
Log_SetChannel(GPUDevice);
|
||||
|
||||
|
@ -37,13 +39,6 @@ std::unique_ptr<GPUDevice> g_gpu_device;
|
|||
|
||||
static std::string s_pipeline_cache_path;
|
||||
|
||||
GPUFramebuffer::GPUFramebuffer(GPUTexture* rt, GPUTexture* ds, u32 width, u32 height)
|
||||
: m_rt(rt), m_ds(ds), m_width(width), m_height(height)
|
||||
{
|
||||
}
|
||||
|
||||
GPUFramebuffer::~GPUFramebuffer() = default;
|
||||
|
||||
GPUSampler::GPUSampler() = default;
|
||||
|
||||
GPUSampler::~GPUSampler() = default;
|
||||
|
@ -156,6 +151,15 @@ GPUPipeline::BlendState GPUPipeline::BlendState::GetAlphaBlendingState()
|
|||
return ret;
|
||||
}
|
||||
|
||||
void GPUPipeline::GraphicsConfig::SetTargetFormats(GPUTexture::Format color_format,
|
||||
GPUTexture::Format depth_format_ /* = GPUTexture::Format::Unknown */)
|
||||
{
|
||||
color_formats[0] = color_format;
|
||||
for (size_t i = 1; i < std::size(color_formats); i++)
|
||||
color_formats[i] = GPUTexture::Format::Unknown;
|
||||
depth_format = depth_format_;
|
||||
}
|
||||
|
||||
GPUTextureBuffer::GPUTextureBuffer(Format format, u32 size) : m_format(format), m_size_in_elements(size)
|
||||
{
|
||||
}
|
||||
|
@ -171,6 +175,35 @@ u32 GPUTextureBuffer::GetElementSize(Format format)
|
|||
return element_size[static_cast<u32>(format)];
|
||||
}
|
||||
|
||||
bool GPUFramebufferManagerBase::Key::operator==(const Key& rhs) const
|
||||
{
|
||||
return (std::memcmp(this, &rhs, sizeof(*this)) == 0);
|
||||
}
|
||||
|
||||
bool GPUFramebufferManagerBase::Key::operator!=(const Key& rhs) const
|
||||
{
|
||||
return (std::memcmp(this, &rhs, sizeof(*this)) != 0);
|
||||
}
|
||||
|
||||
bool GPUFramebufferManagerBase::Key::ContainsRT(const GPUTexture* tex) const
|
||||
{
|
||||
// num_rts is worse for predictability.
|
||||
for (u32 i = 0; i < GPUDevice::MAX_RENDER_TARGETS; i++)
|
||||
{
|
||||
if (rts[i] == tex)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t GPUFramebufferManagerBase::KeyHash::operator()(const Key& key) const
|
||||
{
|
||||
if constexpr (sizeof(void*) == 8)
|
||||
return XXH3_64bits(&key, sizeof(key));
|
||||
else
|
||||
return XXH32(&key, sizeof(key), 0x1337);
|
||||
}
|
||||
|
||||
GPUDevice::~GPUDevice() = default;
|
||||
|
||||
RenderAPI GPUDevice::GetPreferredAPI()
|
||||
|
@ -438,8 +471,7 @@ bool GPUDevice::CreateResources()
|
|||
plconfig.depth = GPUPipeline::DepthState::GetNoTestsState();
|
||||
plconfig.blend = GPUPipeline::BlendState::GetAlphaBlendingState();
|
||||
plconfig.blend.write_mask = 0x7;
|
||||
plconfig.color_format = HasSurface() ? m_window_info.surface_format : GPUTexture::Format::RGBA8;
|
||||
plconfig.depth_format = GPUTexture::Format::Unknown;
|
||||
plconfig.SetTargetFormats(HasSurface() ? m_window_info.surface_format : GPUTexture::Format::RGBA8);
|
||||
plconfig.samples = 1;
|
||||
plconfig.per_sample_shading = false;
|
||||
plconfig.vertex_shader = imgui_vs.get();
|
||||
|
@ -547,6 +579,11 @@ void GPUDevice::UploadUniformBuffer(const void* data, u32 data_size)
|
|||
UnmapUniformBuffer(data_size);
|
||||
}
|
||||
|
||||
void GPUDevice::SetRenderTarget(GPUTexture* rt, GPUTexture* ds /*= nullptr*/)
|
||||
{
|
||||
SetRenderTargets(rt ? &rt : nullptr, rt ? 1 : 0, ds);
|
||||
}
|
||||
|
||||
void GPUDevice::SetViewportAndScissor(s32 x, s32 y, s32 width, s32 height)
|
||||
{
|
||||
SetViewport(x, y, width, height);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// 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
|
||||
|
@ -32,27 +32,6 @@ enum class RenderAPI : u32
|
|||
Metal
|
||||
};
|
||||
|
||||
class GPUFramebuffer
|
||||
{
|
||||
public:
|
||||
GPUFramebuffer(GPUTexture* rt, GPUTexture* ds, u32 width, u32 height);
|
||||
virtual ~GPUFramebuffer();
|
||||
|
||||
ALWAYS_INLINE GPUTexture* GetRT() const { return m_rt; }
|
||||
ALWAYS_INLINE GPUTexture* GetDS() const { return m_ds; }
|
||||
|
||||
ALWAYS_INLINE u32 GetWidth() const { return m_width; }
|
||||
ALWAYS_INLINE u32 GetHeight() const { return m_height; }
|
||||
|
||||
virtual void SetDebugName(const std::string_view& name) = 0;
|
||||
|
||||
protected:
|
||||
GPUTexture* m_rt;
|
||||
GPUTexture* m_ds;
|
||||
u32 m_width;
|
||||
u32 m_height;
|
||||
};
|
||||
|
||||
class GPUSampler
|
||||
{
|
||||
public:
|
||||
|
@ -394,10 +373,13 @@ public:
|
|||
GPUShader* geometry_shader;
|
||||
GPUShader* fragment_shader;
|
||||
|
||||
GPUTexture::Format color_format;
|
||||
GPUTexture::Format color_formats[4];
|
||||
GPUTexture::Format depth_format;
|
||||
u32 samples;
|
||||
bool per_sample_shading;
|
||||
|
||||
void SetTargetFormats(GPUTexture::Format color_format,
|
||||
GPUTexture::Format depth_format_ = GPUTexture::Format::Unknown);
|
||||
};
|
||||
|
||||
GPUPipeline();
|
||||
|
@ -477,6 +459,8 @@ public:
|
|||
|
||||
static constexpr u32 MAX_TEXTURE_SAMPLERS = 8;
|
||||
static constexpr u32 MIN_TEXEL_BUFFER_ELEMENTS = 4 * 1024 * 512;
|
||||
static constexpr u32 MAX_RENDER_TARGETS = 4;
|
||||
static_assert(sizeof(GPUPipeline::GraphicsConfig::color_formats) == sizeof(GPUTexture::Format) * MAX_RENDER_TARGETS);
|
||||
|
||||
virtual ~GPUDevice();
|
||||
|
||||
|
@ -576,9 +560,6 @@ public:
|
|||
virtual void ClearDepth(GPUTexture* t, float d);
|
||||
virtual void InvalidateRenderTarget(GPUTexture* t);
|
||||
|
||||
/// Framebuffer abstraction.
|
||||
virtual std::unique_ptr<GPUFramebuffer> CreateFramebuffer(GPUTexture* rt_or_ds, GPUTexture* ds = nullptr) = 0;
|
||||
|
||||
/// Shader abstraction.
|
||||
std::unique_ptr<GPUShader> CreateShader(GPUShaderStage stage, const std::string_view& source,
|
||||
const char* entry_point = "main");
|
||||
|
@ -606,12 +587,13 @@ public:
|
|||
void UploadUniformBuffer(const void* data, u32 data_size);
|
||||
|
||||
/// Drawing setup abstraction.
|
||||
virtual void SetFramebuffer(GPUFramebuffer* fb) = 0;
|
||||
virtual void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds) = 0;
|
||||
virtual void SetPipeline(GPUPipeline* pipeline) = 0;
|
||||
virtual void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) = 0;
|
||||
virtual void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) = 0;
|
||||
virtual void SetViewport(s32 x, s32 y, s32 width, s32 height) = 0; // TODO: Rectangle
|
||||
virtual void SetScissor(s32 x, s32 y, s32 width, s32 height) = 0;
|
||||
void SetRenderTarget(GPUTexture* rt, GPUTexture* ds = nullptr);
|
||||
void SetViewportAndScissor(s32 x, s32 y, s32 width, s32 height);
|
||||
|
||||
// Drawing abstraction.
|
||||
|
@ -647,7 +629,8 @@ public:
|
|||
virtual float GetAndResetAccumulatedGPUTime();
|
||||
|
||||
protected:
|
||||
virtual bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features) = 0;
|
||||
virtual bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
|
||||
FeatureMask disabled_features) = 0;
|
||||
virtual void DestroyDevice() = 0;
|
||||
|
||||
std::string GetShaderCacheBaseName(const std::string_view& type) const;
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
// 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 "gpu_texture.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
class GPUFramebufferManagerBase
|
||||
{
|
||||
protected:
|
||||
struct Key
|
||||
{
|
||||
GPUTexture* rts[GPUDevice::MAX_RENDER_TARGETS];
|
||||
GPUTexture* ds;
|
||||
u32 num_rts;
|
||||
u32 flags;
|
||||
|
||||
bool operator==(const Key& rhs) const;
|
||||
bool operator!=(const Key& rhs) const;
|
||||
|
||||
bool ContainsRT(const GPUTexture* tex) const;
|
||||
};
|
||||
|
||||
struct KeyHash
|
||||
{
|
||||
size_t operator()(const Key& key) const;
|
||||
};
|
||||
};
|
||||
|
||||
template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
|
||||
void (*DestroyFunc)(FBOType fbo)>
|
||||
class GPUFramebufferManager : public GPUFramebufferManagerBase
|
||||
{
|
||||
public:
|
||||
GPUFramebufferManager() = default;
|
||||
~GPUFramebufferManager();
|
||||
|
||||
FBOType Lookup(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags);
|
||||
|
||||
void RemoveReferences(const GPUTexture* tex);
|
||||
void RemoveRTReferences(const GPUTexture* tex);
|
||||
void RemoveDSReferences(const GPUTexture* tex);
|
||||
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
using MapType = std::unordered_map<Key, FBOType, KeyHash>;
|
||||
|
||||
MapType m_map;
|
||||
};
|
||||
|
||||
template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
|
||||
void (*DestroyFunc)(FBOType fbo)>
|
||||
GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::~GPUFramebufferManager()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
|
||||
void (*DestroyFunc)(FBOType fbo)>
|
||||
FBOType GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::Lookup(GPUTexture* const* rts, u32 num_rts,
|
||||
GPUTexture* ds, u32 flags)
|
||||
{
|
||||
Key key;
|
||||
for (u32 i = 0; i < num_rts; i++)
|
||||
key.rts[i] = rts[i];
|
||||
for (u32 i = num_rts; i < GPUDevice::MAX_RENDER_TARGETS; i++)
|
||||
key.rts[i] = nullptr;
|
||||
key.ds = ds;
|
||||
key.num_rts = num_rts;
|
||||
key.flags = flags;
|
||||
|
||||
auto it = m_map.find(key);
|
||||
if (it == m_map.end())
|
||||
{
|
||||
FBOType fbo = FactoryFunc(rts, num_rts, ds, flags);
|
||||
if (!fbo)
|
||||
return fbo;
|
||||
|
||||
it = m_map.emplace(key, fbo).first;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
|
||||
void (*DestroyFunc)(FBOType fbo)>
|
||||
void GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::RemoveRTReferences(const GPUTexture* tex)
|
||||
{
|
||||
DebugAssert(tex->IsRenderTarget());
|
||||
for (auto it = m_map.begin(); it != m_map.end();)
|
||||
{
|
||||
if (!it->first.ContainsRT(tex))
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
DestroyFunc(it->second);
|
||||
it = m_map.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
|
||||
void (*DestroyFunc)(FBOType fbo)>
|
||||
void GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::RemoveDSReferences(const GPUTexture* tex)
|
||||
{
|
||||
DebugAssert(tex->IsDepthStencil());
|
||||
for (auto it = m_map.begin(); it != m_map.end();)
|
||||
{
|
||||
if (it->first.ds != tex)
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
DestroyFunc(it->second);
|
||||
it = m_map.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
|
||||
void (*DestroyFunc)(FBOType fbo)>
|
||||
void GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::RemoveReferences(const GPUTexture* tex)
|
||||
{
|
||||
if (tex->IsRenderTarget())
|
||||
RemoveRTReferences(tex);
|
||||
else if (tex->IsDepthStencil())
|
||||
RemoveDSReferences(tex);
|
||||
}
|
||||
|
||||
template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
|
||||
void (*DestroyFunc)(FBOType fbo)>
|
||||
void GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::Clear()
|
||||
{
|
||||
for (auto it : m_map)
|
||||
DestroyFunc(it.second);
|
||||
m_map.clear();
|
||||
}
|
|
@ -91,6 +91,12 @@ bool GPUTexture::IsDepthFormat(Format format)
|
|||
return (format == Format::D16);
|
||||
}
|
||||
|
||||
bool GPUTexture::IsDepthStencilFormat(Format format)
|
||||
{
|
||||
// None needed yet.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GPUTexture::ValidateConfig(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format)
|
||||
{
|
||||
if (width > MAX_WIDTH || height > MAX_HEIGHT || layers > MAX_LAYERS || levels > MAX_LEVELS || samples > MAX_SAMPLES)
|
||||
|
|
|
@ -91,6 +91,8 @@ public:
|
|||
|
||||
ALWAYS_INLINE State GetState() const { return m_state; }
|
||||
ALWAYS_INLINE void SetState(State state) { m_state = state; }
|
||||
ALWAYS_INLINE bool IsDirty() const { return (m_state == State::Dirty); }
|
||||
ALWAYS_INLINE bool IsClearedOrInvalidated() const { return (m_state != State::Dirty); }
|
||||
|
||||
ALWAYS_INLINE bool IsRenderTargetOrDepthStencil() const
|
||||
{
|
||||
|
@ -118,6 +120,7 @@ public:
|
|||
|
||||
static u32 GetPixelSize(GPUTexture::Format format);
|
||||
static bool IsDepthFormat(GPUTexture::Format format);
|
||||
static bool IsDepthStencilFormat(GPUTexture::Format format);
|
||||
static bool ValidateConfig(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format);
|
||||
|
||||
static bool ConvertTextureDataToRGBA8(u32 width, u32 height, std::vector<u32>& texture_data, u32& texture_data_stride,
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#include <vector>
|
||||
|
||||
class MetalDevice;
|
||||
class MetalFramebuffer;
|
||||
class MetalPipeline;
|
||||
class MetalTexture;
|
||||
|
||||
|
@ -161,28 +160,10 @@ private:
|
|||
MetalStreamBuffer m_buffer;
|
||||
};
|
||||
|
||||
class MetalFramebuffer final : public GPUFramebuffer
|
||||
{
|
||||
friend MetalDevice;
|
||||
|
||||
public:
|
||||
~MetalFramebuffer() override;
|
||||
|
||||
MTLRenderPassDescriptor* GetDescriptor() const;
|
||||
|
||||
void SetDebugName(const std::string_view& name) override;
|
||||
|
||||
private:
|
||||
MetalFramebuffer(GPUTexture* rt, GPUTexture* ds, u32 width, u32 height, id<MTLTexture> rt_tex, id<MTLTexture> ds_tex,
|
||||
MTLRenderPassDescriptor* descriptor);
|
||||
|
||||
id<MTLTexture> m_rt_tex;
|
||||
id<MTLTexture> m_ds_tex;
|
||||
MTLRenderPassDescriptor* m_descriptor;
|
||||
};
|
||||
|
||||
class MetalDevice final : public GPUDevice
|
||||
{
|
||||
friend MetalTexture;
|
||||
|
||||
public:
|
||||
ALWAYS_INLINE static MetalDevice& GetInstance() { return *static_cast<MetalDevice*>(g_gpu_device.get()); }
|
||||
ALWAYS_INLINE id<MTLDevice> GetMTLDevice() { return m_device; }
|
||||
|
@ -222,8 +203,6 @@ public:
|
|||
void ClearDepth(GPUTexture* t, float d) override;
|
||||
void InvalidateRenderTarget(GPUTexture* t) override;
|
||||
|
||||
std::unique_ptr<GPUFramebuffer> CreateFramebuffer(GPUTexture* rt_or_ds, GPUTexture* ds = nullptr) override;
|
||||
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, const std::string_view& source,
|
||||
const char* entry_point,
|
||||
|
@ -242,7 +221,7 @@ public:
|
|||
void PushUniformBuffer(const void* data, u32 data_size) override;
|
||||
void* MapUniformBuffer(u32 size) override;
|
||||
void UnmapUniformBuffer(u32 size) override;
|
||||
void SetFramebuffer(GPUFramebuffer* fb) override;
|
||||
void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds) override;
|
||||
void SetPipeline(GPUPipeline* pipeline) override;
|
||||
void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
|
||||
void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
|
||||
|
@ -271,8 +250,6 @@ public:
|
|||
|
||||
void CommitClear(MetalTexture* tex);
|
||||
|
||||
void UnbindFramebuffer(MetalFramebuffer* fb);
|
||||
void UnbindFramebuffer(MetalTexture* tex);
|
||||
void UnbindPipeline(MetalPipeline* pl);
|
||||
void UnbindTexture(MetalTexture* tex);
|
||||
void UnbindTextureBuffer(MetalTextureBuffer* buf);
|
||||
|
@ -283,7 +260,8 @@ public:
|
|||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
||||
|
||||
protected:
|
||||
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features) override;
|
||||
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
|
||||
FeatureMask disabled_features) override;
|
||||
void DestroyDevice() override;
|
||||
|
||||
private:
|
||||
|
@ -336,6 +314,8 @@ private:
|
|||
bool CreateBuffers();
|
||||
void DestroyBuffers();
|
||||
|
||||
bool IsRenderTargetBound(const GPUTexture* tex) const;
|
||||
|
||||
id<MTLDevice> m_device;
|
||||
id<MTLCommandQueue> m_queue;
|
||||
|
||||
|
@ -369,7 +349,9 @@ private:
|
|||
id<MTLCommandBuffer> m_render_cmdbuf = nil;
|
||||
id<MTLRenderCommandEncoder> m_render_encoder = nil;
|
||||
|
||||
MetalFramebuffer* m_current_framebuffer = nullptr;
|
||||
std::array<MetalTexture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
|
||||
u32 m_num_current_render_targets = 0;
|
||||
MetalTexture* m_current_depth_target = nullptr;
|
||||
|
||||
MetalPipeline* m_current_pipeline = nullptr;
|
||||
id<MTLDepthStencilState> m_current_depth_state = nil;
|
||||
|
|
|
@ -123,7 +123,8 @@ void MetalDevice::SetVSync(bool enabled)
|
|||
[m_layer setDisplaySyncEnabled:enabled];
|
||||
}
|
||||
|
||||
bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features)
|
||||
bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
|
||||
FeatureMask disabled_features)
|
||||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
|
@ -493,6 +494,17 @@ void MetalDevice::DestroyBuffers()
|
|||
m_depth_states.clear();
|
||||
}
|
||||
|
||||
bool MetalDevice::IsRenderTargetBound(const GPUTexture* tex) const
|
||||
{
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
if (m_current_render_targets[i] == tex)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
GPUDevice::AdapterAndModeList MetalDevice::StaticGetAdapterAndModeList()
|
||||
{
|
||||
AdapterAndModeList ret;
|
||||
|
@ -770,7 +782,12 @@ std::unique_ptr<GPUPipeline> MetalDevice::CreatePipeline(const GPUPipeline::Grap
|
|||
desc.vertexFunction = static_cast<const MetalShader*>(config.vertex_shader)->GetFunction();
|
||||
desc.fragmentFunction = static_cast<const MetalShader*>(config.fragment_shader)->GetFunction();
|
||||
|
||||
desc.colorAttachments[0].pixelFormat = s_pixel_format_mapping[static_cast<u8>(config.color_format)];
|
||||
for (u32 i = 0; i < MAX_RENDER_TARGETS; i++)
|
||||
{
|
||||
if (config.color_formats[i] == GPUTexture::Format::Unknown)
|
||||
break;
|
||||
desc.colorAttachments[0].pixelFormat = s_pixel_format_mapping[static_cast<u8>(config.color_formats[i])];
|
||||
}
|
||||
desc.depthAttachmentPixelFormat = s_pixel_format_mapping[static_cast<u8>(config.depth_format)];
|
||||
|
||||
// Input assembly.
|
||||
|
@ -998,7 +1015,12 @@ void MetalTexture::Unmap()
|
|||
|
||||
void MetalTexture::MakeReadyForSampling()
|
||||
{
|
||||
MetalDevice::GetInstance().UnbindFramebuffer(this);
|
||||
MetalDevice& dev = MetalDevice::GetInstance();
|
||||
if (!dev.InRenderPass())
|
||||
return;
|
||||
|
||||
if (IsRenderTarget() ? dev.IsRenderTargetBound(this) : (dev.m_current_depth_target == this))
|
||||
dev.EndRenderPass();
|
||||
}
|
||||
|
||||
void MetalTexture::SetDebugName(const std::string_view& name)
|
||||
|
@ -1088,130 +1110,6 @@ std::unique_ptr<GPUTexture> MetalDevice::CreateTexture(u32 width, u32 height, u3
|
|||
}
|
||||
}
|
||||
|
||||
MetalFramebuffer::MetalFramebuffer(GPUTexture* rt, GPUTexture* ds, u32 width, u32 height, id<MTLTexture> rt_tex,
|
||||
id<MTLTexture> ds_tex, MTLRenderPassDescriptor* descriptor)
|
||||
: GPUFramebuffer(rt, ds, width, height), m_rt_tex(rt_tex), m_ds_tex(ds_tex), m_descriptor(descriptor)
|
||||
{
|
||||
}
|
||||
|
||||
MetalFramebuffer::~MetalFramebuffer()
|
||||
{
|
||||
// TODO: safe deleting?
|
||||
if (m_rt_tex != nil)
|
||||
[m_rt_tex release];
|
||||
if (m_ds_tex != nil)
|
||||
[m_ds_tex release];
|
||||
[m_descriptor release];
|
||||
}
|
||||
|
||||
void MetalFramebuffer::SetDebugName(const std::string_view& name)
|
||||
{
|
||||
}
|
||||
|
||||
MTLRenderPassDescriptor* MetalFramebuffer::GetDescriptor() const
|
||||
{
|
||||
if (m_rt)
|
||||
{
|
||||
switch (m_rt->GetState())
|
||||
{
|
||||
case GPUTexture::State::Cleared:
|
||||
{
|
||||
const auto clear_color = m_rt->GetUNormClearColor();
|
||||
m_descriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||
m_descriptor.colorAttachments[0].clearColor =
|
||||
MTLClearColorMake(clear_color[0], clear_color[1], clear_color[2], clear_color[3]);
|
||||
m_rt->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Invalidated:
|
||||
{
|
||||
m_descriptor.colorAttachments[0].loadAction = MTLLoadActionDontCare;
|
||||
m_rt->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Dirty:
|
||||
{
|
||||
m_descriptor.colorAttachments[0].loadAction = MTLLoadActionLoad;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
UnreachableCode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_ds)
|
||||
{
|
||||
switch (m_ds->GetState())
|
||||
{
|
||||
case GPUTexture::State::Cleared:
|
||||
{
|
||||
m_descriptor.depthAttachment.loadAction = MTLLoadActionClear;
|
||||
m_descriptor.depthAttachment.clearDepth = m_ds->GetClearDepth();
|
||||
m_ds->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Invalidated:
|
||||
{
|
||||
m_descriptor.depthAttachment.loadAction = MTLLoadActionDontCare;
|
||||
m_ds->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Dirty:
|
||||
{
|
||||
m_descriptor.depthAttachment.loadAction = MTLLoadActionLoad;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
UnreachableCode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return m_descriptor;
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUFramebuffer> MetalDevice::CreateFramebuffer(GPUTexture* rt_or_ds, GPUTexture* ds)
|
||||
{
|
||||
DebugAssert((rt_or_ds || ds) && (!rt_or_ds || rt_or_ds->IsRenderTarget() || (rt_or_ds->IsDepthStencil() && !ds)));
|
||||
MetalTexture* RT = static_cast<MetalTexture*>((rt_or_ds && rt_or_ds->IsDepthStencil()) ? nullptr : rt_or_ds);
|
||||
MetalTexture* DS = static_cast<MetalTexture*>((rt_or_ds && rt_or_ds->IsDepthStencil()) ? rt_or_ds : ds);
|
||||
|
||||
@autoreleasepool
|
||||
{
|
||||
MTLRenderPassDescriptor* desc = [[MTLRenderPassDescriptor renderPassDescriptor] retain];
|
||||
id<MTLTexture> rt_tex = RT ? [RT->GetMTLTexture() retain] : nil;
|
||||
id<MTLTexture> ds_tex = DS ? [DS->GetMTLTexture() retain] : nil;
|
||||
|
||||
if (RT)
|
||||
{
|
||||
desc.colorAttachments[0].texture = rt_tex;
|
||||
desc.colorAttachments[0].loadAction = MTLLoadActionLoad;
|
||||
desc.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||
}
|
||||
|
||||
if (DS)
|
||||
{
|
||||
desc.depthAttachment.texture = ds_tex;
|
||||
desc.depthAttachment.loadAction = MTLLoadActionLoad;
|
||||
desc.depthAttachment.storeAction = MTLStoreActionStore;
|
||||
}
|
||||
|
||||
const u32 width = RT ? RT->GetWidth() : DS->GetWidth();
|
||||
const u32 height = RT ? RT->GetHeight() : DS->GetHeight();
|
||||
desc.renderTargetWidth = width;
|
||||
desc.renderTargetHeight = height;
|
||||
|
||||
return std::unique_ptr<GPUFramebuffer>(new MetalFramebuffer(RT, DS, width, height, rt_tex, ds_tex, desc));
|
||||
}
|
||||
}
|
||||
|
||||
MetalSampler::MetalSampler(id<MTLSamplerState> ss) : m_ss(ss)
|
||||
{
|
||||
}
|
||||
|
@ -1489,25 +1387,22 @@ void MetalDevice::ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u3
|
|||
void MetalDevice::ClearRenderTarget(GPUTexture* t, u32 c)
|
||||
{
|
||||
GPUDevice::ClearRenderTarget(t, c);
|
||||
if (InRenderPass() && m_current_framebuffer && m_current_framebuffer->GetRT() == t)
|
||||
if (InRenderPass() && IsRenderTargetBound(t))
|
||||
EndRenderPass();
|
||||
}
|
||||
|
||||
void MetalDevice::ClearDepth(GPUTexture* t, float d)
|
||||
{
|
||||
GPUDevice::ClearDepth(t, d);
|
||||
if (InRenderPass() && m_current_framebuffer && m_current_framebuffer->GetDS() == t)
|
||||
if (InRenderPass() && m_current_depth_target == t)
|
||||
EndRenderPass();
|
||||
}
|
||||
|
||||
void MetalDevice::InvalidateRenderTarget(GPUTexture* t)
|
||||
{
|
||||
GPUDevice::InvalidateRenderTarget(t);
|
||||
if (InRenderPass() && m_current_framebuffer &&
|
||||
(m_current_framebuffer->GetRT() == t || m_current_framebuffer->GetDS() == t))
|
||||
{
|
||||
if (InRenderPass() && (t->IsRenderTarget() ? IsRenderTargetBound(t) : (m_current_depth_target == t)))
|
||||
EndRenderPass();
|
||||
}
|
||||
}
|
||||
|
||||
void MetalDevice::CommitClear(MetalTexture* tex)
|
||||
|
@ -1689,44 +1584,29 @@ void MetalDevice::UnmapUniformBuffer(u32 size)
|
|||
}
|
||||
}
|
||||
|
||||
void MetalDevice::SetFramebuffer(GPUFramebuffer* fb)
|
||||
void MetalDevice::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds)
|
||||
{
|
||||
if (m_current_framebuffer == fb)
|
||||
return;
|
||||
bool changed = (m_num_current_render_targets != num_rts || m_current_depth_target != ds);
|
||||
bool needs_ds_clear = (ds && ds->IsClearedOrInvalidated());
|
||||
bool needs_rt_clear = false;
|
||||
|
||||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
m_current_depth_target = static_cast<MetalTexture*>(ds);
|
||||
for (u32 i = 0; i < num_rts; i++)
|
||||
{
|
||||
MetalTexture* const RT = static_cast<MetalTexture*>(rts[i]);
|
||||
changed |= m_current_render_targets[i] != RT;
|
||||
m_current_render_targets[i] = RT;
|
||||
needs_rt_clear |= RT->IsClearedOrInvalidated();
|
||||
}
|
||||
for (u32 i = num_rts; i < m_num_current_render_targets; i++)
|
||||
m_current_render_targets[i] = nullptr;
|
||||
m_num_current_render_targets = num_rts;
|
||||
|
||||
m_current_framebuffer = static_cast<MetalFramebuffer*>(fb);
|
||||
|
||||
// Current pipeline might be incompatible, so unbind it.
|
||||
// Otherwise it'll get bound to the new render encoder.
|
||||
// TODO: we shouldn't need to do this now
|
||||
m_current_pipeline = nullptr;
|
||||
m_current_depth_state = nil;
|
||||
}
|
||||
|
||||
void MetalDevice::UnbindFramebuffer(MetalFramebuffer* fb)
|
||||
{
|
||||
if (m_current_framebuffer != fb)
|
||||
return;
|
||||
|
||||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
m_current_framebuffer = nullptr;
|
||||
}
|
||||
|
||||
void MetalDevice::UnbindFramebuffer(MetalTexture* tex)
|
||||
{
|
||||
if (!m_current_framebuffer)
|
||||
return;
|
||||
|
||||
if (m_current_framebuffer->GetRT() != tex && m_current_framebuffer->GetDS() != tex)
|
||||
return;
|
||||
|
||||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
m_current_framebuffer = nullptr;
|
||||
if (changed || needs_rt_clear || needs_ds_clear)
|
||||
{
|
||||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
}
|
||||
}
|
||||
|
||||
void MetalDevice::SetPipeline(GPUPipeline* pipeline)
|
||||
|
@ -1815,6 +1695,27 @@ void MetalDevice::UnbindTexture(MetalTexture* tex)
|
|||
[m_render_encoder setFragmentTexture:nil atIndex:i];
|
||||
}
|
||||
}
|
||||
|
||||
if (tex->IsRenderTarget())
|
||||
{
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
if (m_current_render_targets[i] == tex)
|
||||
{
|
||||
Log_WarningPrint("Unbinding current RT");
|
||||
SetRenderTargets(nullptr, 0, m_current_depth_target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tex->IsDepthStencil())
|
||||
{
|
||||
if (m_current_depth_target == tex)
|
||||
{
|
||||
Log_WarningPrint("Unbinding current DS");
|
||||
SetRenderTargets(nullptr, 0, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetalDevice::UnbindTextureBuffer(MetalTextureBuffer* buf)
|
||||
|
@ -1863,21 +1764,85 @@ void MetalDevice::BeginRenderPass()
|
|||
|
||||
@autoreleasepool
|
||||
{
|
||||
MTLRenderPassDescriptor* desc;
|
||||
if (!m_current_framebuffer)
|
||||
MTLRenderPassDescriptor* desc = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
if (m_num_current_render_targets == 0 && !m_current_depth_target)
|
||||
{
|
||||
// Rendering to view, but we got interrupted...
|
||||
desc = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
desc.colorAttachments[0].texture = [m_layer_drawable texture];
|
||||
desc.colorAttachments[0].loadAction = MTLLoadActionLoad;
|
||||
}
|
||||
else
|
||||
{
|
||||
desc = m_current_framebuffer->GetDescriptor();
|
||||
if (MetalTexture* RT = static_cast<MetalTexture*>(m_current_framebuffer->GetRT()))
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
MetalTexture* const RT = m_current_render_targets[i];
|
||||
desc.colorAttachments[i].texture = RT->GetMTLTexture();
|
||||
RT->SetUseFenceCounter(m_current_fence_counter);
|
||||
if (MetalTexture* DS = static_cast<MetalTexture*>(m_current_framebuffer->GetDS()))
|
||||
|
||||
switch (RT->GetState())
|
||||
{
|
||||
case GPUTexture::State::Cleared:
|
||||
{
|
||||
const auto clear_color = RT->GetUNormClearColor();
|
||||
desc.colorAttachments[i].loadAction = MTLLoadActionClear;
|
||||
desc.colorAttachments[i].clearColor =
|
||||
MTLClearColorMake(clear_color[0], clear_color[1], clear_color[2], clear_color[3]);
|
||||
RT->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Invalidated:
|
||||
{
|
||||
desc.colorAttachments[i].loadAction = MTLLoadActionDontCare;
|
||||
RT->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Dirty:
|
||||
{
|
||||
desc.colorAttachments[i].loadAction = MTLLoadActionLoad;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
UnreachableCode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (MetalTexture* DS = m_current_depth_target)
|
||||
{
|
||||
desc.depthAttachment.texture = m_current_depth_target->GetMTLTexture();
|
||||
DS->SetUseFenceCounter(m_current_fence_counter);
|
||||
|
||||
switch (DS->GetState())
|
||||
{
|
||||
case GPUTexture::State::Cleared:
|
||||
{
|
||||
desc.depthAttachment.loadAction = MTLLoadActionClear;
|
||||
desc.depthAttachment.clearDepth = DS->GetClearDepth();
|
||||
DS->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Invalidated:
|
||||
{
|
||||
desc.depthAttachment.loadAction = MTLLoadActionDontCare;
|
||||
DS->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Dirty:
|
||||
{
|
||||
desc.depthAttachment.loadAction = MTLLoadActionLoad;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
UnreachableCode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_render_encoder = [[m_render_cmdbuf renderCommandEncoderWithDescriptor:desc] retain];
|
||||
|
@ -1948,8 +1913,10 @@ void MetalDevice::SetScissorInRenderEncoder()
|
|||
|
||||
Common::Rectangle<s32> MetalDevice::ClampToFramebufferSize(const Common::Rectangle<s32>& rc) const
|
||||
{
|
||||
const s32 clamp_width = m_current_framebuffer ? m_current_framebuffer->GetWidth() : m_window_info.surface_width;
|
||||
const s32 clamp_height = m_current_framebuffer ? m_current_framebuffer->GetHeight() : m_window_info.surface_height;
|
||||
const MetalTexture* rt_or_ds =
|
||||
(m_num_current_render_targets > 0) ? m_current_render_targets[0] : m_current_depth_target;
|
||||
const s32 clamp_width = rt_or_ds ? rt_or_ds->GetWidth() : m_window_info.surface_width;
|
||||
const s32 clamp_height = rt_or_ds ? rt_or_ds->GetHeight() : m_window_info.surface_height;
|
||||
return rc.ClampedSize(clamp_width, clamp_height);
|
||||
}
|
||||
|
||||
|
@ -2023,10 +1990,12 @@ bool MetalDevice::BeginPresent(bool skip_present)
|
|||
|
||||
// Set up rendering to layer.
|
||||
id<MTLTexture> layer_texture = [m_layer_drawable texture];
|
||||
m_current_framebuffer = nullptr;
|
||||
m_layer_pass_desc.colorAttachments[0].texture = layer_texture;
|
||||
m_layer_pass_desc.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||
m_render_encoder = [[m_render_cmdbuf renderCommandEncoderWithDescriptor:m_layer_pass_desc] retain];
|
||||
std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
|
||||
m_num_current_render_targets = 0;
|
||||
m_current_depth_target = nullptr;
|
||||
m_current_pipeline = nullptr;
|
||||
m_current_depth_state = nil;
|
||||
SetInitialEncoderState();
|
||||
|
@ -2036,7 +2005,7 @@ bool MetalDevice::BeginPresent(bool skip_present)
|
|||
|
||||
void MetalDevice::EndPresent()
|
||||
{
|
||||
DebugAssert(!m_current_framebuffer);
|
||||
DebugAssert(m_num_current_render_targets == 0 && !m_current_depth_target);
|
||||
EndAnyEncoding();
|
||||
|
||||
[m_render_cmdbuf presentDrawable:m_layer_drawable];
|
||||
|
|
|
@ -155,9 +155,9 @@ void OpenGLDevice::CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32
|
|||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
if (m_current_framebuffer)
|
||||
if (m_current_fbo)
|
||||
{
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_current_framebuffer ? m_current_framebuffer->GetGLId() : 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_current_fbo);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
}
|
||||
else
|
||||
|
@ -201,9 +201,9 @@ void OpenGLDevice::ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u
|
|||
GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
if (m_current_framebuffer)
|
||||
if (m_current_fbo)
|
||||
{
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_current_framebuffer ? m_current_framebuffer->GetGLId() : 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_current_fbo);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
}
|
||||
else
|
||||
|
@ -215,22 +215,31 @@ void OpenGLDevice::ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u
|
|||
void OpenGLDevice::ClearRenderTarget(GPUTexture* t, u32 c)
|
||||
{
|
||||
GPUDevice::ClearRenderTarget(t, c);
|
||||
if (m_current_framebuffer && m_current_framebuffer->GetRT() == t)
|
||||
CommitClear(m_current_framebuffer);
|
||||
if (const s32 idx = IsRenderTargetBound(t); idx >= 0)
|
||||
CommitRTClearInFB(static_cast<OpenGLTexture*>(t), static_cast<u32>(idx));
|
||||
}
|
||||
|
||||
void OpenGLDevice::ClearDepth(GPUTexture* t, float d)
|
||||
{
|
||||
GPUDevice::ClearDepth(t, d);
|
||||
if (m_current_framebuffer && m_current_framebuffer->GetDS() == t)
|
||||
CommitClear(m_current_framebuffer);
|
||||
if (m_current_depth_target == t)
|
||||
CommitDSClearInFB(static_cast<OpenGLTexture*>(t));
|
||||
}
|
||||
|
||||
void OpenGLDevice::InvalidateRenderTarget(GPUTexture* t)
|
||||
{
|
||||
GPUDevice::InvalidateRenderTarget(t);
|
||||
if (m_current_framebuffer && (m_current_framebuffer->GetRT() == t || m_current_framebuffer->GetDS() == t))
|
||||
CommitClear(m_current_framebuffer);
|
||||
if (t->IsRenderTarget())
|
||||
{
|
||||
if (const s32 idx = IsRenderTargetBound(t); idx >= 0)
|
||||
CommitRTClearInFB(static_cast<OpenGLTexture*>(t), static_cast<u32>(idx));
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugAssert(t->IsDepthStencil());
|
||||
if (m_current_depth_target == t)
|
||||
CommitDSClearInFB(static_cast<OpenGLTexture*>(t));
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDevice::PushDebugGroup(const char* name)
|
||||
|
@ -617,7 +626,56 @@ void OpenGLDevice::RenderBlankFrame()
|
|||
m_last_blend_state.write_a);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
m_gl_context->SwapBuffers();
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_current_framebuffer ? m_current_framebuffer->GetGLId() : 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_current_fbo);
|
||||
}
|
||||
|
||||
s32 OpenGLDevice::IsRenderTargetBound(const GPUTexture* tex) const
|
||||
{
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
if (m_current_render_targets[i] == tex)
|
||||
return static_cast<s32>(i);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
GLuint OpenGLDevice::CreateFramebuffer(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags)
|
||||
{
|
||||
glGetError();
|
||||
|
||||
GLuint fbo_id;
|
||||
glGenFramebuffers(1, &fbo_id);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_id);
|
||||
|
||||
for (u32 i = 0; i < num_rts; i++)
|
||||
{
|
||||
OpenGLTexture* const RT = static_cast<OpenGLTexture*>(rts[i]);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, RT->GetGLTarget(), RT->GetGLId(), 0);
|
||||
}
|
||||
|
||||
if (ds)
|
||||
{
|
||||
OpenGLTexture* const DS = static_cast<OpenGLTexture*>(ds);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, DS->GetGLTarget(), DS->GetGLId(), 0);
|
||||
}
|
||||
|
||||
if (glGetError() != GL_NO_ERROR || glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
Log_ErrorFmt("Failed to create GL framebuffer: {}", static_cast<s32>(glGetError()));
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OpenGLDevice::GetInstance().m_current_fbo);
|
||||
glDeleteFramebuffers(1, &fbo_id);
|
||||
return {};
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OpenGLDevice::GetInstance().m_current_fbo);
|
||||
return fbo_id;
|
||||
}
|
||||
|
||||
void OpenGLDevice::DestroyFramebuffer(GLuint fbo)
|
||||
{
|
||||
if (fbo != 0)
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
}
|
||||
|
||||
GPUDevice::AdapterAndModeList OpenGLDevice::GetAdapterAndModeList()
|
||||
|
@ -720,7 +778,12 @@ bool OpenGLDevice::BeginPresent(bool skip_present)
|
|||
|
||||
const Common::Rectangle<s32> window_rc =
|
||||
Common::Rectangle<s32>::FromExtents(0, 0, m_window_info.surface_width, m_window_info.surface_height);
|
||||
m_current_framebuffer = nullptr;
|
||||
|
||||
m_current_fbo = 0;
|
||||
m_num_current_render_targets = 0;
|
||||
std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
|
||||
m_current_depth_target = nullptr;
|
||||
|
||||
m_last_viewport = window_rc;
|
||||
m_last_scissor = window_rc;
|
||||
UpdateViewport();
|
||||
|
@ -730,7 +793,7 @@ bool OpenGLDevice::BeginPresent(bool skip_present)
|
|||
|
||||
void OpenGLDevice::EndPresent()
|
||||
{
|
||||
DebugAssert(!m_current_framebuffer);
|
||||
DebugAssert(m_current_fbo == 0);
|
||||
|
||||
if (m_gpu_timing_enabled)
|
||||
PopTimestampQuery();
|
||||
|
@ -886,6 +949,36 @@ void OpenGLDevice::UnbindTexture(GLuint id)
|
|||
}
|
||||
}
|
||||
|
||||
void OpenGLDevice::UnbindTexture(OpenGLTexture* tex)
|
||||
{
|
||||
UnbindTexture(tex->GetGLId());
|
||||
|
||||
if (tex->IsRenderTarget())
|
||||
{
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
if (m_current_render_targets[i] == tex)
|
||||
{
|
||||
Log_WarningPrint("Unbinding current RT");
|
||||
SetRenderTargets(nullptr, 0, m_current_depth_target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_framebuffer_manager.RemoveRTReferences(tex);
|
||||
}
|
||||
else if (tex->IsDepthStencil())
|
||||
{
|
||||
if (m_current_depth_target == tex)
|
||||
{
|
||||
Log_WarningPrint("Unbinding current DS");
|
||||
SetRenderTargets(nullptr, 0, nullptr);
|
||||
}
|
||||
|
||||
m_framebuffer_manager.RemoveDSReferences(tex);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDevice::UnbindSSBO(GLuint id)
|
||||
{
|
||||
if (m_last_ssbo != id)
|
||||
|
@ -908,15 +1001,6 @@ void OpenGLDevice::UnbindSampler(GLuint id)
|
|||
}
|
||||
}
|
||||
|
||||
void OpenGLDevice::UnbindFramebuffer(const OpenGLFramebuffer* fb)
|
||||
{
|
||||
if (m_current_framebuffer == fb)
|
||||
{
|
||||
m_current_framebuffer = nullptr;
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDevice::UnbindPipeline(const OpenGLPipeline* pl)
|
||||
{
|
||||
if (m_current_pipeline == pl)
|
||||
|
@ -984,25 +1068,55 @@ void OpenGLDevice::UnmapUniformBuffer(u32 size)
|
|||
glBindBufferRange(GL_UNIFORM_BUFFER, 1, m_uniform_buffer->GetGLBufferId(), pos, size);
|
||||
}
|
||||
|
||||
void OpenGLDevice::SetFramebuffer(GPUFramebuffer* fb)
|
||||
void OpenGLDevice::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds)
|
||||
{
|
||||
if (m_current_framebuffer == fb)
|
||||
return;
|
||||
bool changed = (m_num_current_render_targets != num_rts || m_current_depth_target != ds);
|
||||
bool needs_ds_clear = (ds && ds->IsClearedOrInvalidated());
|
||||
bool needs_rt_clear = false;
|
||||
|
||||
OpenGLFramebuffer* FB = static_cast<OpenGLFramebuffer*>(fb);
|
||||
const bool prev_was_window = (m_current_framebuffer == nullptr);
|
||||
const bool new_is_window = (FB == nullptr);
|
||||
m_current_framebuffer = FB;
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FB ? FB->GetGLId() : 0);
|
||||
if (prev_was_window != new_is_window)
|
||||
m_current_depth_target = static_cast<OpenGLTexture*>(ds);
|
||||
for (u32 i = 0; i < num_rts; i++)
|
||||
{
|
||||
UpdateViewport();
|
||||
UpdateScissor();
|
||||
OpenGLTexture* const dt = static_cast<OpenGLTexture*>(rts[i]);
|
||||
changed |= m_current_render_targets[i] != dt;
|
||||
m_current_render_targets[i] = dt;
|
||||
needs_rt_clear |= dt->IsClearedOrInvalidated();
|
||||
}
|
||||
for (u32 i = num_rts; i < m_num_current_render_targets; i++)
|
||||
m_current_render_targets[i] = nullptr;
|
||||
m_num_current_render_targets = num_rts;
|
||||
if (changed)
|
||||
{
|
||||
GLuint fbo = 0;
|
||||
if (m_num_current_render_targets > 0 || m_current_depth_target)
|
||||
{
|
||||
if ((fbo = m_framebuffer_manager.Lookup(rts, num_rts, ds, 0)) == 0)
|
||||
{
|
||||
Log_ErrorFmt("Failed to get FBO for {} render targets", num_rts);
|
||||
m_current_fbo = 0;
|
||||
std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
|
||||
m_num_current_render_targets = 0;
|
||||
m_current_depth_target = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_current_fbo = fbo;
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
|
||||
}
|
||||
|
||||
if (FB)
|
||||
CommitClear(FB);
|
||||
if (needs_rt_clear)
|
||||
{
|
||||
for (u32 i = 0; i < num_rts; i++)
|
||||
{
|
||||
OpenGLTexture* const dt = static_cast<OpenGLTexture*>(rts[i]);
|
||||
if (dt->IsClearedOrInvalidated())
|
||||
CommitRTClearInFB(dt, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (needs_ds_clear)
|
||||
CommitDSClearInFB(static_cast<OpenGLTexture*>(ds));
|
||||
}
|
||||
|
||||
void OpenGLDevice::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler)
|
||||
|
@ -1078,7 +1192,7 @@ std::tuple<s32, s32, s32, s32> OpenGLDevice::GetFlippedViewportScissor(const Com
|
|||
// Only when rendering to window framebuffer.
|
||||
// We draw everything else upside-down.
|
||||
s32 x, y, width, height;
|
||||
if (!m_current_framebuffer)
|
||||
if (m_current_fbo == 0)
|
||||
{
|
||||
const s32 sh = static_cast<s32>(m_window_info.surface_height);
|
||||
const s32 rh = rc.GetHeight();
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "gl/context.h"
|
||||
#include "gpu_device.h"
|
||||
#include "gpu_framebuffer_manager.h"
|
||||
#include "gpu_shader_cache.h"
|
||||
#include "opengl_loader.h"
|
||||
#include "opengl_pipeline.h"
|
||||
|
@ -16,7 +17,6 @@
|
|||
#include <memory>
|
||||
#include <tuple>
|
||||
|
||||
class OpenGLFramebuffer;
|
||||
class OpenGLPipeline;
|
||||
class OpenGLStreamBuffer;
|
||||
class OpenGLTexture;
|
||||
|
@ -65,8 +65,6 @@ public:
|
|||
void ClearDepth(GPUTexture* t, float d) override;
|
||||
void InvalidateRenderTarget(GPUTexture* t) override;
|
||||
|
||||
std::unique_ptr<GPUFramebuffer> CreateFramebuffer(GPUTexture* rt_or_ds, GPUTexture* ds = nullptr) override;
|
||||
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, const std::string_view& source,
|
||||
const char* entry_point, DynamicHeapArray<u8>* out_binary) override;
|
||||
|
@ -84,7 +82,7 @@ public:
|
|||
void PushUniformBuffer(const void* data, u32 data_size) override;
|
||||
void* MapUniformBuffer(u32 size) override;
|
||||
void UnmapUniformBuffer(u32 size) override;
|
||||
void SetFramebuffer(GPUFramebuffer* fb) override;
|
||||
void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds) override;
|
||||
void SetPipeline(GPUPipeline* pipeline) override;
|
||||
void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
|
||||
void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
|
||||
|
@ -102,7 +100,8 @@ public:
|
|||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
void CommitClear(OpenGLTexture* tex);
|
||||
void CommitClear(OpenGLFramebuffer* fb); // Assumes the FB has been bound.
|
||||
void CommitRTClearInFB(OpenGLTexture* tex, u32 idx);
|
||||
void CommitDSClearInFB(OpenGLTexture* tex);
|
||||
|
||||
GLuint LookupProgramCache(const OpenGLPipeline::ProgramCacheKey& key, const GPUPipeline::GraphicsConfig& plconfig);
|
||||
GLuint CompileProgram(const GPUPipeline::GraphicsConfig& plconfig);
|
||||
|
@ -115,9 +114,9 @@ public:
|
|||
|
||||
void SetActiveTexture(u32 slot);
|
||||
void UnbindTexture(GLuint id);
|
||||
void UnbindTexture(OpenGLTexture* tex);
|
||||
void UnbindSSBO(GLuint id);
|
||||
void UnbindSampler(GLuint id);
|
||||
void UnbindFramebuffer(const OpenGLFramebuffer* fb);
|
||||
void UnbindPipeline(const OpenGLPipeline* pl);
|
||||
|
||||
protected:
|
||||
|
@ -145,6 +144,10 @@ private:
|
|||
void SetSwapInterval();
|
||||
void RenderBlankFrame();
|
||||
|
||||
s32 IsRenderTargetBound(const GPUTexture* tex) const;
|
||||
static GLuint CreateFramebuffer(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags);
|
||||
static void DestroyFramebuffer(GLuint fbo);
|
||||
|
||||
std::tuple<s32, s32, s32, s32> GetFlippedViewportScissor(const Common::Rectangle<s32>& rc) const;
|
||||
void UpdateViewport();
|
||||
void UpdateScissor();
|
||||
|
@ -165,7 +168,6 @@ private:
|
|||
void ApplyBlendState(GPUPipeline::BlendState bs);
|
||||
|
||||
std::unique_ptr<GL::Context> m_gl_context;
|
||||
std::unique_ptr<OpenGLFramebuffer> m_window_framebuffer;
|
||||
|
||||
std::unique_ptr<OpenGLStreamBuffer> m_vertex_buffer;
|
||||
std::unique_ptr<OpenGLStreamBuffer> m_index_buffer;
|
||||
|
@ -175,6 +177,7 @@ private:
|
|||
// TODO: pass in file instead of blob for pipeline cache
|
||||
OpenGLPipeline::VertexArrayCache m_vao_cache;
|
||||
OpenGLPipeline::ProgramCache m_program_cache;
|
||||
GPUFramebufferManager<GLuint, CreateFramebuffer, DestroyFramebuffer> m_framebuffer_manager;
|
||||
|
||||
// VAO cache - fixed max as key
|
||||
GPUPipeline::BlendState m_last_blend_state = {};
|
||||
|
@ -193,7 +196,11 @@ private:
|
|||
GLuint m_read_fbo = 0;
|
||||
GLuint m_write_fbo = 0;
|
||||
|
||||
OpenGLFramebuffer* m_current_framebuffer = nullptr;
|
||||
GLuint m_current_fbo = 0;
|
||||
u32 m_num_current_render_targets = 0;
|
||||
std::array<OpenGLTexture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
|
||||
OpenGLTexture* m_current_depth_target = nullptr;
|
||||
|
||||
OpenGLPipeline* m_current_pipeline = nullptr;
|
||||
|
||||
std::array<GLuint, NUM_TIMESTAMP_QUERIES> m_timestamp_queries = {};
|
||||
|
|
|
@ -205,7 +205,7 @@ void OpenGLTexture::Destroy()
|
|||
{
|
||||
if (m_id != 0)
|
||||
{
|
||||
OpenGLDevice::GetInstance().UnbindTexture(m_id);
|
||||
OpenGLDevice::GetInstance().UnbindTexture(this);
|
||||
glDeleteTextures(1, &m_id);
|
||||
m_id = 0;
|
||||
}
|
||||
|
@ -410,58 +410,6 @@ std::unique_ptr<GPUSampler> OpenGLDevice::CreateSampler(const GPUSampler::Config
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
OpenGLFramebuffer::OpenGLFramebuffer(GPUTexture* rt, GPUTexture* ds, u32 width, u32 height, GLuint id)
|
||||
: GPUFramebuffer(rt, ds, width, height), m_id(id)
|
||||
{
|
||||
}
|
||||
|
||||
OpenGLFramebuffer::~OpenGLFramebuffer()
|
||||
{
|
||||
OpenGLDevice::GetInstance().UnbindFramebuffer(this);
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::SetDebugName(const std::string_view& name)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (glObjectLabel)
|
||||
glObjectLabel(GL_FRAMEBUFFER, m_id, static_cast<GLsizei>(name.length()), static_cast<const GLchar*>(name.data()));
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::Bind(GLenum target)
|
||||
{
|
||||
glBindFramebuffer(target, m_id);
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUFramebuffer> OpenGLDevice::CreateFramebuffer(GPUTexture* rt_or_ds, GPUTexture* ds /* = nullptr */)
|
||||
{
|
||||
glGetError();
|
||||
|
||||
GLuint fbo_id;
|
||||
glGenFramebuffers(1, &fbo_id);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_id);
|
||||
|
||||
DebugAssert((rt_or_ds || ds) && (!rt_or_ds || rt_or_ds->IsRenderTarget() || (rt_or_ds->IsDepthStencil() && !ds)));
|
||||
OpenGLTexture* RT = static_cast<OpenGLTexture*>((rt_or_ds && rt_or_ds->IsDepthStencil()) ? nullptr : rt_or_ds);
|
||||
OpenGLTexture* DS = static_cast<OpenGLTexture*>((rt_or_ds && rt_or_ds->IsDepthStencil()) ? rt_or_ds : ds);
|
||||
if (RT)
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, RT->GetGLTarget(), RT->GetGLId(), 0);
|
||||
if (DS)
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, DS->GetGLTarget(), DS->GetGLId(), 0);
|
||||
|
||||
if (glGetError() != GL_NO_ERROR || glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to create GL framebuffer: %u", glGetError());
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_current_framebuffer ? m_current_framebuffer->GetGLId() : 0);
|
||||
glDeleteFramebuffers(1, &fbo_id);
|
||||
return {};
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_current_framebuffer ? m_current_framebuffer->GetGLId() : 0);
|
||||
return std::unique_ptr<GPUFramebuffer>(new OpenGLFramebuffer(RT, DS, RT ? RT->GetWidth() : DS->GetWidth(),
|
||||
RT ? RT->GetHeight() : DS->GetHeight(), fbo_id));
|
||||
}
|
||||
|
||||
void OpenGLDevice::CommitClear(OpenGLTexture* tex)
|
||||
{
|
||||
switch (tex->GetState())
|
||||
|
@ -484,7 +432,7 @@ void OpenGLDevice::CommitClear(OpenGLTexture* tex)
|
|||
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, &attachment);
|
||||
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, GL_TEXTURE_2D, 0, 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_current_framebuffer ? m_current_framebuffer->GetGLId() : 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_current_fbo);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -525,7 +473,7 @@ void OpenGLDevice::CommitClear(OpenGLTexture* tex)
|
|||
}
|
||||
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, GL_TEXTURE_2D, 0, 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_current_framebuffer ? m_current_framebuffer->GetGLId() : 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_current_fbo);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -539,74 +487,68 @@ void OpenGLDevice::CommitClear(OpenGLTexture* tex)
|
|||
}
|
||||
}
|
||||
|
||||
void OpenGLDevice::CommitClear(OpenGLFramebuffer* fb)
|
||||
void OpenGLDevice::CommitRTClearInFB(OpenGLTexture* tex, u32 idx)
|
||||
{
|
||||
GLenum invalidate_attachments[2];
|
||||
GLuint num_invalidate_attachments = 0;
|
||||
|
||||
if (OpenGLTexture* FB = static_cast<OpenGLTexture*>(fb->GetRT()))
|
||||
switch (tex->GetState())
|
||||
{
|
||||
switch (FB->GetState())
|
||||
case GPUTexture::State::Invalidated:
|
||||
{
|
||||
case GPUTexture::State::Invalidated:
|
||||
{
|
||||
invalidate_attachments[num_invalidate_attachments++] = GL_COLOR_ATTACHMENT0;
|
||||
FB->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
const GLenum attachment = GL_COLOR_ATTACHMENT0 + idx;
|
||||
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, &attachment);
|
||||
tex->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Cleared:
|
||||
{
|
||||
const auto color = tex->GetUNormClearColor();
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glClearBufferfv(GL_COLOR, static_cast<GLint>(idx), color.data());
|
||||
glColorMask(m_last_blend_state.write_r, m_last_blend_state.write_g, m_last_blend_state.write_b,
|
||||
m_last_blend_state.write_a);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
tex->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
|
||||
case GPUTexture::State::Dirty:
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Cleared:
|
||||
{
|
||||
const auto color = FB->GetUNormClearColor();
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glClearBufferfv(GL_COLOR, 0, color.data());
|
||||
glColorMask(m_last_blend_state.write_r, m_last_blend_state.write_g, m_last_blend_state.write_b,
|
||||
m_last_blend_state.write_a);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
FB->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
|
||||
case GPUTexture::State::Dirty:
|
||||
break;
|
||||
|
||||
default:
|
||||
UnreachableCode();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UnreachableCode();
|
||||
break;
|
||||
}
|
||||
if (OpenGLTexture* DS = static_cast<OpenGLTexture*>(fb->GetDS()))
|
||||
}
|
||||
|
||||
void OpenGLDevice::CommitDSClearInFB(OpenGLTexture* tex)
|
||||
{
|
||||
switch (tex->GetState())
|
||||
{
|
||||
switch (DS->GetState())
|
||||
case GPUTexture::State::Invalidated:
|
||||
{
|
||||
case GPUTexture::State::Invalidated:
|
||||
{
|
||||
invalidate_attachments[num_invalidate_attachments++] = GL_DEPTH_ATTACHMENT;
|
||||
DS->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Cleared:
|
||||
{
|
||||
const float depth = DS->GetClearDepth();
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glClearBufferfv(GL_DEPTH, 0, &depth);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
DS->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Dirty:
|
||||
break;
|
||||
|
||||
default:
|
||||
UnreachableCode();
|
||||
break;
|
||||
const GLenum attachment = GL_DEPTH_ATTACHMENT;
|
||||
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, &attachment);
|
||||
tex->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
if (num_invalidate_attachments > 0 && glInvalidateFramebuffer)
|
||||
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, num_invalidate_attachments, invalidate_attachments);
|
||||
case GPUTexture::State::Cleared:
|
||||
{
|
||||
const float depth = tex->GetClearDepth();
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glClearBufferfv(GL_DEPTH, 0, &depth);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
tex->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Dirty:
|
||||
break;
|
||||
|
||||
default:
|
||||
UnreachableCode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -57,25 +57,6 @@ private:
|
|||
u8 m_map_level = 0;
|
||||
};
|
||||
|
||||
class OpenGLFramebuffer final : public GPUFramebuffer
|
||||
{
|
||||
friend OpenGLDevice;
|
||||
|
||||
public:
|
||||
~OpenGLFramebuffer() override;
|
||||
|
||||
ALWAYS_INLINE GLuint GetGLId() const { return m_id; }
|
||||
|
||||
void SetDebugName(const std::string_view& name) override;
|
||||
|
||||
void Bind(GLenum target);
|
||||
|
||||
private:
|
||||
OpenGLFramebuffer(GPUTexture* rt, GPUTexture* ds, u32 width, u32 height, GLuint id);
|
||||
|
||||
GLuint m_id;
|
||||
};
|
||||
|
||||
class OpenGLTextureBuffer final : public GPUTextureBuffer
|
||||
{
|
||||
friend OpenGLDevice;
|
||||
|
|
|
@ -53,10 +53,8 @@ static u32 s_target_height = 0;
|
|||
static Common::Timer s_timer;
|
||||
|
||||
static std::unique_ptr<GPUTexture> s_input_texture;
|
||||
static std::unique_ptr<GPUFramebuffer> s_input_framebuffer;
|
||||
|
||||
static std::unique_ptr<GPUTexture> s_output_texture;
|
||||
static std::unique_ptr<GPUFramebuffer> s_output_framebuffer;
|
||||
|
||||
static std::unordered_map<u64, std::unique_ptr<GPUSampler>> s_samplers;
|
||||
static std::unique_ptr<GPUTexture> s_dummy_texture;
|
||||
|
@ -602,11 +600,6 @@ GPUTexture* PostProcessing::GetInputTexture()
|
|||
return s_input_texture.get();
|
||||
}
|
||||
|
||||
GPUFramebuffer* PostProcessing::GetInputFramebuffer()
|
||||
{
|
||||
return s_input_framebuffer.get();
|
||||
}
|
||||
|
||||
const Common::Timer& PostProcessing::GetTimer()
|
||||
{
|
||||
return s_timer;
|
||||
|
@ -650,14 +643,8 @@ bool PostProcessing::CheckTargets(GPUTexture::Format target_format, u32 target_w
|
|||
|
||||
if (!(s_input_texture = g_gpu_device->CreateTexture(target_width, target_height, 1, 1, 1,
|
||||
GPUTexture::Type::RenderTarget, target_format)) ||
|
||||
!(s_input_framebuffer = g_gpu_device->CreateFramebuffer(s_input_texture.get())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(s_output_texture = g_gpu_device->CreateTexture(target_width, target_height, 1, 1, 1,
|
||||
GPUTexture::Type::RenderTarget, target_format)) ||
|
||||
!(s_output_framebuffer = g_gpu_device->CreateFramebuffer(s_output_texture.get())))
|
||||
!(s_output_texture = g_gpu_device->CreateTexture(target_width, target_height, 1, 1, 1,
|
||||
GPUTexture::Type::RenderTarget, target_format)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -688,36 +675,30 @@ void PostProcessing::DestroyTextures()
|
|||
s_target_width = 0;
|
||||
s_target_height = 0;
|
||||
|
||||
s_output_framebuffer.reset();
|
||||
s_output_texture.reset();
|
||||
|
||||
s_input_framebuffer.reset();
|
||||
s_input_texture.reset();
|
||||
}
|
||||
|
||||
bool PostProcessing::Apply(GPUFramebuffer* final_target, s32 final_left, s32 final_top, s32 final_width,
|
||||
s32 final_height, s32 orig_width, s32 orig_height)
|
||||
bool PostProcessing::Apply(GPUTexture* final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height,
|
||||
s32 orig_width, s32 orig_height)
|
||||
{
|
||||
GL_SCOPE("PostProcessing Apply");
|
||||
|
||||
const u32 target_width = final_target ? final_target->GetWidth() : g_gpu_device->GetWindowWidth();
|
||||
const u32 target_height = final_target ? final_target->GetHeight() : g_gpu_device->GetWindowHeight();
|
||||
const GPUTexture::Format target_format =
|
||||
final_target ? final_target->GetRT()->GetFormat() : g_gpu_device->GetWindowFormat();
|
||||
const GPUTexture::Format target_format = final_target ? final_target->GetFormat() : g_gpu_device->GetWindowFormat();
|
||||
if (!CheckTargets(target_format, target_width, target_height))
|
||||
return false;
|
||||
|
||||
GPUTexture* input = s_input_texture.get();
|
||||
GPUFramebuffer* input_fb = s_input_framebuffer.get();
|
||||
GPUTexture* output = s_output_texture.get();
|
||||
GPUFramebuffer* output_fb = s_output_framebuffer.get();
|
||||
input->MakeReadyForSampling();
|
||||
|
||||
for (const std::unique_ptr<Shader>& stage : s_stages)
|
||||
{
|
||||
const bool is_final = (stage.get() == s_stages.back().get());
|
||||
|
||||
if (!stage->Apply(input, is_final ? final_target : output_fb, final_left, final_top, final_width, final_height,
|
||||
if (!stage->Apply(input, is_final ? final_target : output, final_left, final_top, final_width, final_height,
|
||||
orig_width, orig_height, s_target_width, s_target_height))
|
||||
{
|
||||
return false;
|
||||
|
@ -727,7 +708,6 @@ bool PostProcessing::Apply(GPUFramebuffer* final_target, s32 final_left, s32 fin
|
|||
{
|
||||
output->MakeReadyForSampling();
|
||||
std::swap(input, output);
|
||||
std::swap(input_fb, output_fb);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,11 @@
|
|||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace Common
|
||||
{
|
||||
namespace Common {
|
||||
class Timer;
|
||||
}
|
||||
|
||||
class GPUSampler;
|
||||
class GPUFramebuffer;
|
||||
class GPUTexture;
|
||||
|
||||
class Error;
|
||||
|
@ -123,13 +121,12 @@ bool ReloadShaders();
|
|||
void Shutdown();
|
||||
|
||||
GPUTexture* GetInputTexture();
|
||||
GPUFramebuffer* GetInputFramebuffer();
|
||||
const Common::Timer& GetTimer();
|
||||
|
||||
bool CheckTargets(GPUTexture::Format target_format, u32 target_width, u32 target_height);
|
||||
|
||||
bool Apply(GPUFramebuffer* final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height,
|
||||
s32 orig_width, s32 orig_height);
|
||||
bool Apply(GPUTexture* final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height, s32 orig_width,
|
||||
s32 orig_height);
|
||||
|
||||
GPUSampler* GetSampler(const GPUSampler::Config& config);
|
||||
GPUTexture* GetDummyTexture();
|
||||
|
|
|
@ -47,7 +47,7 @@ public:
|
|||
|
||||
virtual bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height) = 0;
|
||||
|
||||
virtual bool Apply(GPUTexture* input, GPUFramebuffer* final_target, s32 final_left, s32 final_top, s32 final_width,
|
||||
virtual bool Apply(GPUTexture* input, GPUTexture* 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) = 0;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -1080,7 +1080,7 @@ const char* PostProcessing::ReShadeFXShader::GetTextureNameForID(TextureID id) c
|
|||
}
|
||||
|
||||
GPUTexture* PostProcessing::ReShadeFXShader::GetTextureByID(TextureID id, GPUTexture* input,
|
||||
GPUFramebuffer* final_target) const
|
||||
GPUTexture* final_target) const
|
||||
{
|
||||
if (id < 0)
|
||||
{
|
||||
|
@ -1093,29 +1093,6 @@ GPUTexture* PostProcessing::ReShadeFXShader::GetTextureByID(TextureID id, GPUTex
|
|||
return PostProcessing::GetDummyTexture();
|
||||
}
|
||||
else if (id == OUTPUT_COLOR_TEXTURE)
|
||||
{
|
||||
Panic("Wrong state for final target");
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
Panic("Unexpected reserved texture ID");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(id) >= m_textures.size())
|
||||
Panic("Unexpected texture ID");
|
||||
|
||||
return m_textures[static_cast<size_t>(id)].texture.get();
|
||||
}
|
||||
|
||||
GPUFramebuffer* PostProcessing::ReShadeFXShader::GetFramebufferByID(TextureID id, GPUTexture* input,
|
||||
GPUFramebuffer* final_target) const
|
||||
{
|
||||
if (id < 0)
|
||||
{
|
||||
if (id == OUTPUT_COLOR_TEXTURE)
|
||||
{
|
||||
return final_target;
|
||||
}
|
||||
|
@ -1129,9 +1106,7 @@ GPUFramebuffer* PostProcessing::ReShadeFXShader::GetFramebufferByID(TextureID id
|
|||
if (static_cast<size_t>(id) >= m_textures.size())
|
||||
Panic("Unexpected texture ID");
|
||||
|
||||
const Texture& tex = m_textures[static_cast<size_t>(id)];
|
||||
Assert(tex.framebuffer);
|
||||
return tex.framebuffer.get();
|
||||
return m_textures[static_cast<size_t>(id)].texture.get();
|
||||
}
|
||||
|
||||
bool PostProcessing::ReShadeFXShader::CompilePipeline(GPUTexture::Format format, u32 width, u32 height)
|
||||
|
@ -1243,7 +1218,7 @@ bool PostProcessing::ReShadeFXShader::CompilePipeline(GPUTexture::Format format,
|
|||
if (!vs || !fs)
|
||||
return false;
|
||||
|
||||
plconfig.color_format = (pass.render_target >= 0) ? m_textures[pass.render_target].format : format;
|
||||
plconfig.SetTargetFormats((pass.render_target >= 0) ? m_textures[pass.render_target].format : format);
|
||||
plconfig.blend = MapBlendState(info);
|
||||
plconfig.primitive = MapPrimitive(info.topology);
|
||||
plconfig.vertex_shader = vs.get();
|
||||
|
@ -1274,7 +1249,6 @@ bool PostProcessing::ReShadeFXShader::ResizeOutput(GPUTexture::Format format, u3
|
|||
if (tex.rt_scale == 0.0f)
|
||||
continue;
|
||||
|
||||
tex.framebuffer.reset();
|
||||
tex.texture.reset();
|
||||
|
||||
const u32 t_width = std::max(static_cast<u32>(static_cast<float>(width) * tex.rt_scale), 1u);
|
||||
|
@ -1285,22 +1259,15 @@ bool PostProcessing::ReShadeFXShader::ResizeOutput(GPUTexture::Format format, u3
|
|||
Log_ErrorPrintf("Failed to create %ux%u texture", t_width, t_height);
|
||||
return {};
|
||||
}
|
||||
|
||||
tex.framebuffer = g_gpu_device->CreateFramebuffer(tex.texture.get());
|
||||
if (!tex.framebuffer)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to create %ux%u texture framebuffer", t_width, t_height);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
m_valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PostProcessing::ReShadeFXShader::Apply(GPUTexture* input, 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)
|
||||
bool PostProcessing::ReShadeFXShader::Apply(GPUTexture* input, GPUTexture* 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)
|
||||
{
|
||||
GL_PUSH_FMT("PostProcessingShaderFX {}", m_name);
|
||||
|
||||
|
@ -1461,9 +1428,9 @@ bool PostProcessing::ReShadeFXShader::Apply(GPUTexture* input, GPUFramebuffer* f
|
|||
{
|
||||
GL_SCOPE_FMT("Draw pass {}", pass.name.c_str());
|
||||
GL_INS_FMT("Render Target: ID {} [{}]", pass.render_target, GetTextureNameForID(pass.render_target));
|
||||
GPUFramebuffer* output_fb = GetFramebufferByID(pass.render_target, input, final_target);
|
||||
GPUTexture* output = GetTextureByID(pass.render_target, input, final_target);
|
||||
|
||||
if (!output_fb)
|
||||
if (!output)
|
||||
{
|
||||
// Drawing to final buffer.
|
||||
if (!g_gpu_device->BeginPresent(false))
|
||||
|
@ -1474,7 +1441,7 @@ bool PostProcessing::ReShadeFXShader::Apply(GPUTexture* input, GPUFramebuffer* f
|
|||
}
|
||||
else
|
||||
{
|
||||
g_gpu_device->SetFramebuffer(output_fb);
|
||||
g_gpu_device->SetRenderTargets(&output, 1, nullptr);
|
||||
}
|
||||
|
||||
g_gpu_device->SetPipeline(pass.pipeline.get());
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
|
||||
bool ResizeOutput(GPUTexture::Format format, u32 width, u32 height) override;
|
||||
bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height) override;
|
||||
bool Apply(GPUTexture* input, GPUFramebuffer* final_target, s32 final_left, s32 final_top, s32 final_width,
|
||||
bool Apply(GPUTexture* input, GPUTexture* 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) override;
|
||||
|
||||
private:
|
||||
|
@ -80,15 +80,13 @@ private:
|
|||
bool CreatePasses(GPUTexture::Format backbuffer_format, reshadefx::module& mod, Error* error);
|
||||
|
||||
const char* GetTextureNameForID(TextureID id) const;
|
||||
GPUTexture* GetTextureByID(TextureID id, GPUTexture* input, GPUFramebuffer* final_target) const;
|
||||
GPUFramebuffer* GetFramebufferByID(TextureID id, GPUTexture* input, GPUFramebuffer* final_target) const;
|
||||
GPUTexture* GetTextureByID(TextureID id, GPUTexture* input, GPUTexture* final_target) const;
|
||||
|
||||
std::string m_filename;
|
||||
|
||||
struct Texture
|
||||
{
|
||||
std::unique_ptr<GPUTexture> texture;
|
||||
std::unique_ptr<GPUFramebuffer> framebuffer;
|
||||
std::string reshade_name; // TODO: we might be able to drop this
|
||||
GPUTexture::Format format;
|
||||
float rt_scale;
|
||||
|
|
|
@ -130,8 +130,7 @@ bool PostProcessing::GLSLShader::CompilePipeline(GPUTexture::Format format, u32
|
|||
GPUPipeline::GraphicsConfig plconfig;
|
||||
plconfig.layout = GPUPipeline::Layout::SingleTextureAndUBO;
|
||||
plconfig.primitive = GPUPipeline::Primitive::Triangles;
|
||||
plconfig.color_format = format;
|
||||
plconfig.depth_format = GPUTexture::Format::Unknown;
|
||||
plconfig.SetTargetFormats(format);
|
||||
plconfig.rasterization = GPUPipeline::RasterizationState::GetNoCullState();
|
||||
plconfig.depth = GPUPipeline::DepthState::GetNoTestsState();
|
||||
plconfig.blend = GPUPipeline::BlendState::GetNoBlendingState();
|
||||
|
@ -157,7 +156,7 @@ bool PostProcessing::GLSLShader::CompilePipeline(GPUTexture::Format format, u32
|
|||
return true;
|
||||
}
|
||||
|
||||
bool PostProcessing::GLSLShader::Apply(GPUTexture* input, GPUFramebuffer* final_target, s32 final_left, s32 final_top,
|
||||
bool PostProcessing::GLSLShader::Apply(GPUTexture* input, GPUTexture* 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)
|
||||
{
|
||||
|
@ -171,8 +170,8 @@ bool PostProcessing::GLSLShader::Apply(GPUTexture* input, GPUFramebuffer* final_
|
|||
}
|
||||
else
|
||||
{
|
||||
g_gpu_device->SetFramebuffer(final_target);
|
||||
g_gpu_device->ClearRenderTarget(final_target->GetRT(), 0); // TODO: Could use an invalidate here too.
|
||||
g_gpu_device->SetRenderTargets(&final_target, 1, nullptr);
|
||||
g_gpu_device->ClearRenderTarget(final_target, 0); // TODO: Could use an invalidate here too.
|
||||
}
|
||||
|
||||
g_gpu_device->SetPipeline(m_pipeline.get());
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
|
||||
bool ResizeOutput(GPUTexture::Format format, u32 width, u32 height) override;
|
||||
bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height) override;
|
||||
bool Apply(GPUTexture* input, GPUFramebuffer* final_target, s32 final_left, s32 final_top, s32 final_width,
|
||||
bool Apply(GPUTexture* input, GPUTexture* 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) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<PreprocessorDefinitions>ENABLE_CUBEB=1;ENABLE_SDL2=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="'$(Platform)'!='ARM64'">%(PreprocessorDefinitions);ENABLE_OPENGL=1;ENABLE_VULKAN=1</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="'$(Platform)'=='ARM64'">%(PreprocessorDefinitions);SOUNDTOUCH_USE_NEON</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)dep\soundtouch\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\d3d12ma\include;$(SolutionDir)dep\zstd\lib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)dep\xxhash\include;$(SolutionDir)dep\soundtouch\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\d3d12ma\include;$(SolutionDir)dep\zstd\lib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories Condition="'$(Platform)'!='ARM64'">%(AdditionalIncludeDirectories);$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan\include;$(SolutionDir)dep\glslang</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
<ExcludedFromBuild Condition="'$(Platform)'=='ARM64'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gpu_device.h" />
|
||||
<ClInclude Include="gpu_framebuffer_manager.h" />
|
||||
<ClInclude Include="gpu_shader_cache.h" />
|
||||
<ClInclude Include="gpu_texture.h" />
|
||||
<ClInclude Include="host.h" />
|
||||
|
@ -245,6 +246,19 @@
|
|||
<Project>{ee054e08-3799-4a59-a422-18259c105ffd}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="metal_device.mm">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
<FileType>Document</FileType>
|
||||
</ClCompile>
|
||||
<None Include="metal_shaders.metal">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</None>
|
||||
<ClCompile Include="metal_stream_buffer.mm">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
<FileType>Document</FileType>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{57F6206D-F264-4B07-BAF8-11B9BBE1F455}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
<ClInclude Include="http_downloader_curl.h" />
|
||||
<ClInclude Include="http_downloader_winhttp.h" />
|
||||
<ClInclude Include="http_downloader.h" />
|
||||
<ClInclude Include="gpu_framebuffer_manager.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="jit_code_buffer.cpp" />
|
||||
|
@ -149,10 +150,15 @@
|
|||
<ClCompile Include="http_downloader_curl.cpp" />
|
||||
<ClCompile Include="http_downloader_winhttp.cpp" />
|
||||
<ClCompile Include="http_downloader.cpp" />
|
||||
<ClCompile Include="metal_device.mm" />
|
||||
<ClCompile Include="metal_stream_buffer.mm" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="gl">
|
||||
<UniqueIdentifier>{e637fc5b-2483-4a31-abc3-89a16d45c223}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="metal_shaders.metal" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -264,6 +264,9 @@ void Vulkan::GraphicsPipelineBuilder::Clear()
|
|||
m_line_rasterization_state = {};
|
||||
m_line_rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT;
|
||||
|
||||
m_rendering = {};
|
||||
m_rendering.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR;
|
||||
|
||||
// set defaults
|
||||
SetNoCullRasterizationState();
|
||||
SetNoDepthTestState();
|
||||
|
@ -569,6 +572,29 @@ void Vulkan::GraphicsPipelineBuilder::SetProvokingVertex(VkProvokingVertexModeEX
|
|||
m_provoking_vertex.provokingVertexMode = mode;
|
||||
}
|
||||
|
||||
void Vulkan::GraphicsPipelineBuilder::SetDynamicRendering()
|
||||
{
|
||||
AddPointerToChain(&m_ci, &m_rendering);
|
||||
}
|
||||
|
||||
void Vulkan::GraphicsPipelineBuilder::AddDynamicRenderingColorAttachment(VkFormat format)
|
||||
{
|
||||
SetDynamicRendering();
|
||||
|
||||
DebugAssert(m_rendering.colorAttachmentCount < MAX_ATTACHMENTS);
|
||||
m_rendering_color_formats[m_rendering.colorAttachmentCount++] = format;
|
||||
|
||||
m_rendering.pColorAttachmentFormats = m_rendering_color_formats.data();
|
||||
}
|
||||
|
||||
void Vulkan::GraphicsPipelineBuilder::SetDynamicRenderingDepthAttachment(VkFormat depth_format, VkFormat stencil_format)
|
||||
{
|
||||
SetDynamicRendering();
|
||||
|
||||
m_rendering.depthAttachmentFormat = depth_format;
|
||||
m_rendering.stencilAttachmentFormat = stencil_format;
|
||||
}
|
||||
|
||||
Vulkan::ComputePipelineBuilder::ComputePipelineBuilder()
|
||||
{
|
||||
Clear();
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "gpu_device.h"
|
||||
#include "vulkan_loader.h"
|
||||
|
||||
#include "common/string_util.h"
|
||||
|
@ -79,7 +80,7 @@ public:
|
|||
MAX_SHADER_STAGES = 3,
|
||||
MAX_VERTEX_ATTRIBUTES = 16,
|
||||
MAX_VERTEX_BUFFERS = 8,
|
||||
MAX_ATTACHMENTS = 2,
|
||||
MAX_ATTACHMENTS = GPUDevice::MAX_RENDER_TARGETS + 1,
|
||||
MAX_DYNAMIC_STATE = 8
|
||||
};
|
||||
|
||||
|
@ -140,6 +141,10 @@ public:
|
|||
|
||||
void SetProvokingVertex(VkProvokingVertexModeEXT mode);
|
||||
|
||||
void SetDynamicRendering();
|
||||
void AddDynamicRenderingColorAttachment(VkFormat format);
|
||||
void SetDynamicRenderingDepthAttachment(VkFormat depth_format, VkFormat stencil_format);
|
||||
|
||||
private:
|
||||
VkGraphicsPipelineCreateInfo m_ci;
|
||||
std::array<VkPipelineShaderStageCreateInfo, MAX_SHADER_STAGES> m_shader_stages;
|
||||
|
@ -167,6 +172,9 @@ private:
|
|||
|
||||
VkPipelineRasterizationProvokingVertexStateCreateInfoEXT m_provoking_vertex;
|
||||
VkPipelineRasterizationLineStateCreateInfoEXT m_line_rasterization_state;
|
||||
|
||||
VkPipelineRenderingCreateInfoKHR m_rendering;
|
||||
std::array<VkFormat, MAX_ATTACHMENTS> m_rendering_color_formats;
|
||||
};
|
||||
|
||||
class ComputePipelineBuilder
|
||||
|
@ -271,7 +279,7 @@ class FramebufferBuilder
|
|||
{
|
||||
enum : u32
|
||||
{
|
||||
MAX_ATTACHMENTS = 2,
|
||||
MAX_ATTACHMENTS = GPUDevice::MAX_RENDER_TARGETS + 1,
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "common/small_string.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "xxhash.h"
|
||||
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
|
@ -39,6 +40,13 @@ struct VK_PIPELINE_CACHE_HEADER
|
|||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static VkAttachmentLoadOp GetLoadOpForTexture(const GPUTexture* tex)
|
||||
{
|
||||
static constexpr VkAttachmentLoadOp ops[3] = {VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_CLEAR,
|
||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE};
|
||||
return ops[static_cast<u8>(tex->GetState())];
|
||||
}
|
||||
|
||||
// Tweakables
|
||||
enum : u32
|
||||
{
|
||||
|
@ -84,6 +92,9 @@ const std::array<VkFormat, static_cast<u32>(GPUTexture::Format::MaxCount)> Vulka
|
|||
|
||||
static constexpr VkClearValue s_present_clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||
|
||||
// Handles are always 64-bit, even on 32-bit platforms.
|
||||
static const VkRenderPass DYNAMIC_RENDERING_RENDER_PASS = reinterpret_cast<VkRenderPass>(static_cast<s64>(-1LL));
|
||||
|
||||
#ifdef _DEBUG
|
||||
static u32 s_debug_scope_depth = 0;
|
||||
#endif
|
||||
|
@ -355,6 +366,10 @@ bool VulkanDevice::SelectDeviceExtensions(ExtensionList* extension_list, bool en
|
|||
m_optional_extensions.vk_ext_attachment_feedback_loop_layout =
|
||||
SupportsExtension(VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_khr_driver_properties = SupportsExtension(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_khr_dynamic_rendering =
|
||||
SupportsExtension(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME, false) &&
|
||||
SupportsExtension(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, false) &&
|
||||
SupportsExtension(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_khr_push_descriptor = SupportsExtension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, false);
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -501,11 +516,15 @@ bool VulkanDevice::CreateDevice(VkSurfaceKHR surface, bool enable_validation_lay
|
|||
VK_FALSE};
|
||||
VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT, nullptr, VK_TRUE};
|
||||
VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, nullptr, VK_TRUE};
|
||||
|
||||
if (m_optional_extensions.vk_ext_rasterization_order_attachment_access)
|
||||
Vulkan::AddPointerToChain(&device_info, &rasterization_order_access_feature);
|
||||
if (m_optional_extensions.vk_ext_attachment_feedback_loop_layout)
|
||||
Vulkan::AddPointerToChain(&device_info, &attachment_feedback_loop_feature);
|
||||
if (m_optional_extensions.vk_khr_dynamic_rendering)
|
||||
Vulkan::AddPointerToChain(&device_info, &dynamic_rendering_feature);
|
||||
|
||||
VkResult res = vkCreateDevice(m_physical_device, &device_info, nullptr, &m_device);
|
||||
if (res != VK_SUCCESS)
|
||||
|
@ -545,12 +564,16 @@ void VulkanDevice::ProcessDeviceExtensions()
|
|||
VK_FALSE};
|
||||
VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT, nullptr, VK_FALSE};
|
||||
VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, nullptr, VK_TRUE};
|
||||
|
||||
// add in optional feature structs
|
||||
if (m_optional_extensions.vk_ext_rasterization_order_attachment_access)
|
||||
Vulkan::AddPointerToChain(&features2, &rasterization_order_access_feature);
|
||||
if (m_optional_extensions.vk_ext_attachment_feedback_loop_layout)
|
||||
Vulkan::AddPointerToChain(&features2, &attachment_feedback_loop_feature);
|
||||
if (m_optional_extensions.vk_khr_dynamic_rendering)
|
||||
Vulkan::AddPointerToChain(&features2, &dynamic_rendering_feature);
|
||||
|
||||
// query
|
||||
vkGetPhysicalDeviceFeatures2(m_physical_device, &features2);
|
||||
|
@ -560,6 +583,7 @@ void VulkanDevice::ProcessDeviceExtensions()
|
|||
(rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess == VK_TRUE);
|
||||
m_optional_extensions.vk_ext_attachment_feedback_loop_layout &=
|
||||
(attachment_feedback_loop_feature.attachmentFeedbackLoopLayout == VK_TRUE);
|
||||
m_optional_extensions.vk_khr_dynamic_rendering &= (dynamic_rendering_feature.dynamicRendering == VK_TRUE);
|
||||
|
||||
VkPhysicalDeviceProperties2 properties2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, nullptr, {}};
|
||||
VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor_properties = {
|
||||
|
@ -584,6 +608,8 @@ void VulkanDevice::ProcessDeviceExtensions()
|
|||
m_optional_extensions.vk_ext_rasterization_order_attachment_access ? "supported" : "NOT supported");
|
||||
Log_InfoPrintf("VK_EXT_attachment_feedback_loop_layout is %s",
|
||||
m_optional_extensions.vk_ext_attachment_feedback_loop_layout ? "supported" : "NOT supported");
|
||||
Log_InfoPrintf("VK_KHR_dynamic_rendering is %s",
|
||||
m_optional_extensions.vk_khr_dynamic_rendering ? "supported" : "NOT supported");
|
||||
Log_InfoPrintf("VK_KHR_push_descriptor is %s",
|
||||
m_optional_extensions.vk_khr_push_descriptor ? "supported" : "NOT supported");
|
||||
}
|
||||
|
@ -794,33 +820,110 @@ void VulkanDevice::DestroyPersistentDescriptorPool()
|
|||
vkDestroyDescriptorPool(m_device, m_global_descriptor_pool, nullptr);
|
||||
}
|
||||
|
||||
VkRenderPass VulkanDevice::GetRenderPass(VkFormat color_format, VkFormat depth_format, VkSampleCountFlagBits samples,
|
||||
VkAttachmentLoadOp color_load_op /* = VK_ATTACHMENT_LOAD_OP_LOAD */,
|
||||
VkAttachmentStoreOp color_store_op /* = VK_ATTACHMENT_STORE_OP_STORE */,
|
||||
VkAttachmentLoadOp depth_load_op /* = VK_ATTACHMENT_LOAD_OP_LOAD */,
|
||||
VkAttachmentStoreOp depth_store_op /* = VK_ATTACHMENT_STORE_OP_STORE */,
|
||||
VkAttachmentLoadOp stencil_load_op /* = VK_ATTACHMENT_LOAD_OP_DONT_CARE */,
|
||||
VkAttachmentStoreOp stencil_store_op /* = VK_ATTACHMENT_STORE_OP_DONT_CARE */,
|
||||
bool VulkanDevice::RenderPassCacheKey::operator==(const RenderPassCacheKey& rhs) const
|
||||
{
|
||||
return (std::memcmp(this, &rhs, sizeof(*this)) == 0);
|
||||
}
|
||||
|
||||
bool VulkanDevice::RenderPassCacheKey::operator!=(const RenderPassCacheKey& rhs) const
|
||||
{
|
||||
return (std::memcmp(this, &rhs, sizeof(*this)) != 0);
|
||||
}
|
||||
|
||||
size_t VulkanDevice::RenderPassCacheKeyHash::operator()(const RenderPassCacheKey& rhs) const
|
||||
{
|
||||
if constexpr (sizeof(void*) == 8)
|
||||
return XXH3_64bits(&rhs, sizeof(rhs));
|
||||
else
|
||||
return XXH32(&rhs, sizeof(rhs), 0x1337);
|
||||
}
|
||||
|
||||
VkRenderPass VulkanDevice::GetRenderPass(const GPUPipeline::GraphicsConfig& config)
|
||||
{
|
||||
RenderPassCacheKey key;
|
||||
std::memset(&key, 0, sizeof(key));
|
||||
|
||||
for (u32 i = 0; i < MAX_RENDER_TARGETS; i++)
|
||||
{
|
||||
if (config.color_formats[i] == GPUTexture::Format::Unknown)
|
||||
break;
|
||||
|
||||
key.color[i].format = static_cast<u8>(config.color_formats[i]);
|
||||
key.color[i].load_op = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
key.color[i].store_op = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
}
|
||||
|
||||
if (config.depth_format != GPUTexture::Format::Unknown)
|
||||
{
|
||||
key.depth_format = static_cast<u8>(config.depth_format);
|
||||
key.depth_load_op = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
key.depth_store_op = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
const bool stencil = GPUTexture::IsDepthStencilFormat(config.depth_format);
|
||||
key.stencil_load_op = stencil ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
key.stencil_store_op = stencil ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
}
|
||||
|
||||
// key.color_feedback_loop = false;
|
||||
// key.depth_sampling = false;
|
||||
|
||||
key.samples = static_cast<u8>(config.samples);
|
||||
|
||||
const auto it = m_render_pass_cache.find(key);
|
||||
return (it != m_render_pass_cache.end()) ? it->second : CreateCachedRenderPass(key);
|
||||
}
|
||||
|
||||
VkRenderPass VulkanDevice::GetRenderPass(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
||||
bool color_feedback_loop /* = false */, bool depth_sampling /* = false */)
|
||||
{
|
||||
RenderPassCacheKey key = {};
|
||||
key.color_format = color_format;
|
||||
key.depth_format = depth_format;
|
||||
key.samples = samples;
|
||||
key.color_load_op = color_load_op;
|
||||
key.color_store_op = color_store_op;
|
||||
key.depth_load_op = depth_load_op;
|
||||
key.depth_store_op = depth_store_op;
|
||||
key.stencil_load_op = stencil_load_op;
|
||||
key.stencil_store_op = stencil_store_op;
|
||||
RenderPassCacheKey key;
|
||||
std::memset(&key, 0, sizeof(key));
|
||||
|
||||
static_assert(static_cast<u8>(GPUTexture::Format::Unknown) == 0);
|
||||
|
||||
for (u32 i = 0; i < num_rts; i++)
|
||||
{
|
||||
key.color[i].format = static_cast<u8>(rts[i]->GetFormat());
|
||||
key.color[i].load_op = GetLoadOpForTexture(rts[i]);
|
||||
key.color[i].store_op = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
key.samples = static_cast<u8>(rts[i]->GetSamples());
|
||||
}
|
||||
|
||||
if (ds)
|
||||
{
|
||||
const VkAttachmentLoadOp load_op = GetLoadOpForTexture(ds);
|
||||
key.depth_format = static_cast<u8>(ds->GetFormat());
|
||||
key.depth_load_op = load_op;
|
||||
key.depth_store_op = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
const bool stencil = GPUTexture::IsDepthStencilFormat(ds->GetFormat());
|
||||
key.stencil_load_op = stencil ? load_op : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
key.stencil_store_op = stencil ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
|
||||
key.samples = static_cast<u8>(ds->GetSamples());
|
||||
}
|
||||
|
||||
key.color_feedback_loop = color_feedback_loop;
|
||||
key.depth_sampling = depth_sampling;
|
||||
|
||||
auto it = m_render_pass_cache.find(key.key);
|
||||
if (it != m_render_pass_cache.end())
|
||||
return it->second;
|
||||
const auto it = m_render_pass_cache.find(key);
|
||||
return (it != m_render_pass_cache.end()) ? it->second : CreateCachedRenderPass(key);
|
||||
}
|
||||
|
||||
return CreateCachedRenderPass(key);
|
||||
VkRenderPass VulkanDevice::GetSwapChainRenderPass(GPUTexture::Format format, VkAttachmentLoadOp load_op)
|
||||
{
|
||||
DebugAssert(format != GPUTexture::Format::Unknown);
|
||||
|
||||
RenderPassCacheKey key;
|
||||
std::memset(&key, 0, sizeof(key));
|
||||
|
||||
key.color[0].format = static_cast<u8>(format);
|
||||
key.color[0].load_op = load_op;
|
||||
key.color[0].store_op = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
key.samples = 1;
|
||||
|
||||
const auto it = m_render_pass_cache.find(key);
|
||||
return (it != m_render_pass_cache.end()) ? it->second : CreateCachedRenderPass(key);
|
||||
}
|
||||
|
||||
VkRenderPass VulkanDevice::GetRenderPassForRestarting(VkRenderPass pass)
|
||||
|
@ -830,19 +933,22 @@ VkRenderPass VulkanDevice::GetRenderPassForRestarting(VkRenderPass pass)
|
|||
if (it.second != pass)
|
||||
continue;
|
||||
|
||||
RenderPassCacheKey modified_key;
|
||||
modified_key.key = it.first;
|
||||
if (modified_key.color_load_op == VK_ATTACHMENT_LOAD_OP_CLEAR)
|
||||
modified_key.color_load_op = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
RenderPassCacheKey modified_key = it.first;
|
||||
for (u32 i = 0; i < MAX_RENDER_TARGETS; i++)
|
||||
{
|
||||
if (modified_key.color[i].load_op == VK_ATTACHMENT_LOAD_OP_CLEAR)
|
||||
modified_key.color[i].load_op = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
}
|
||||
|
||||
if (modified_key.depth_load_op == VK_ATTACHMENT_LOAD_OP_CLEAR)
|
||||
modified_key.depth_load_op = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
if (modified_key.stencil_load_op == VK_ATTACHMENT_LOAD_OP_CLEAR)
|
||||
modified_key.stencil_load_op = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
|
||||
if (modified_key.key == it.first)
|
||||
if (modified_key == it.first)
|
||||
return pass;
|
||||
|
||||
auto fit = m_render_pass_cache.find(modified_key.key);
|
||||
auto fit = m_render_pass_cache.find(modified_key);
|
||||
if (fit != m_render_pass_cache.end())
|
||||
return fit->second;
|
||||
|
||||
|
@ -1261,12 +1367,9 @@ void VulkanDevice::SubmitCommandBufferAndRestartRenderPass(const char* reason)
|
|||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
|
||||
VulkanFramebuffer* fb = m_current_framebuffer;
|
||||
VulkanPipeline* pl = m_current_pipeline;
|
||||
SubmitCommandBuffer(false, "%s", reason);
|
||||
|
||||
if (fb)
|
||||
SetFramebuffer(fb);
|
||||
SetPipeline(pl);
|
||||
BeginRenderPass();
|
||||
}
|
||||
|
@ -1404,19 +1507,25 @@ VkRenderPass VulkanDevice::CreateCachedRenderPass(RenderPassCacheKey key)
|
|||
VkAttachmentReference* input_reference_ptr = nullptr;
|
||||
VkSubpassDependency subpass_dependency;
|
||||
VkSubpassDependency* subpass_dependency_ptr = nullptr;
|
||||
std::array<VkAttachmentDescription, 2> attachments;
|
||||
std::array<VkAttachmentDescription, MAX_RENDER_TARGETS + 1> attachments;
|
||||
u32 num_attachments = 0;
|
||||
if (key.color_format != VK_FORMAT_UNDEFINED)
|
||||
|
||||
for (u32 i = 0; i < MAX_RENDER_TARGETS; i++)
|
||||
{
|
||||
if (key.color[i].format == static_cast<u8>(GPUTexture::Format::Unknown))
|
||||
break;
|
||||
|
||||
const VkImageLayout layout =
|
||||
key.color_feedback_loop ?
|
||||
(UseFeedbackLoopLayout() ? VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT : VK_IMAGE_LAYOUT_GENERAL) :
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachments[num_attachments] = {0,
|
||||
static_cast<VkFormat>(key.color_format),
|
||||
|
||||
const RenderPassCacheKey::RenderTarget key_rt = key.color[i];
|
||||
attachments[num_attachments] = {i,
|
||||
TEXTURE_FORMAT_MAPPING[key_rt.format],
|
||||
static_cast<VkSampleCountFlagBits>(key.samples),
|
||||
static_cast<VkAttachmentLoadOp>(key.color_load_op),
|
||||
static_cast<VkAttachmentStoreOp>(key.color_store_op),
|
||||
static_cast<VkAttachmentLoadOp>(key_rt.load_op),
|
||||
static_cast<VkAttachmentStoreOp>(key_rt.store_op),
|
||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||
layout,
|
||||
|
@ -1453,14 +1562,17 @@ VkRenderPass VulkanDevice::CreateCachedRenderPass(RenderPassCacheKey key)
|
|||
|
||||
num_attachments++;
|
||||
}
|
||||
if (key.depth_format != VK_FORMAT_UNDEFINED)
|
||||
|
||||
const u32 num_rts = num_attachments;
|
||||
|
||||
if (key.depth_format != static_cast<u8>(GPUTexture::Format::Unknown))
|
||||
{
|
||||
const VkImageLayout layout =
|
||||
key.depth_sampling ?
|
||||
(UseFeedbackLoopLayout() ? VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT : VK_IMAGE_LAYOUT_GENERAL) :
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[num_attachments] = {0,
|
||||
static_cast<VkFormat>(key.depth_format),
|
||||
static_cast<VkFormat>(TEXTURE_FORMAT_MAPPING[key.depth_format]),
|
||||
static_cast<VkSampleCountFlagBits>(key.samples),
|
||||
static_cast<VkAttachmentLoadOp>(key.depth_load_op),
|
||||
static_cast<VkAttachmentStoreOp>(key.depth_store_op),
|
||||
|
@ -1480,10 +1592,10 @@ VkRenderPass VulkanDevice::CreateCachedRenderPass(RenderPassCacheKey key)
|
|||
0;
|
||||
const VkSubpassDescription subpass = {subpass_flags,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
input_reference_ptr ? 1u : 0u,
|
||||
input_reference_ptr ? input_reference_ptr : nullptr,
|
||||
color_reference_ptr ? 1u : 0u,
|
||||
color_reference_ptr ? color_reference_ptr : nullptr,
|
||||
input_reference_ptr ? num_rts : 0u,
|
||||
input_reference_ptr,
|
||||
num_rts,
|
||||
color_reference_ptr,
|
||||
nullptr,
|
||||
depth_reference_ptr,
|
||||
0,
|
||||
|
@ -1506,10 +1618,37 @@ VkRenderPass VulkanDevice::CreateCachedRenderPass(RenderPassCacheKey key)
|
|||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
m_render_pass_cache.emplace(key.key, pass);
|
||||
m_render_pass_cache.emplace(key, pass);
|
||||
return pass;
|
||||
}
|
||||
|
||||
VkFramebuffer VulkanDevice::CreateFramebuffer(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags)
|
||||
{
|
||||
VulkanDevice& dev = VulkanDevice::GetInstance();
|
||||
VkRenderPass render_pass = dev.GetRenderPass(rts, num_rts, ds, false, false);
|
||||
|
||||
const GPUTexture* rt_or_ds = (num_rts > 0) ? rts[0] : ds;
|
||||
DebugAssert(rt_or_ds);
|
||||
|
||||
Vulkan::FramebufferBuilder fbb;
|
||||
fbb.SetRenderPass(render_pass);
|
||||
fbb.SetSize(rt_or_ds->GetWidth(), rt_or_ds->GetHeight(), 1);
|
||||
for (u32 i = 0; i < num_rts; i++)
|
||||
fbb.AddAttachment(static_cast<VulkanTexture*>(rts[i])->GetView());
|
||||
if (ds)
|
||||
fbb.AddAttachment(static_cast<VulkanTexture*>(ds)->GetView());
|
||||
|
||||
return fbb.Create(dev.m_device, false);
|
||||
}
|
||||
|
||||
void VulkanDevice::DestroyFramebuffer(VkFramebuffer fbo)
|
||||
{
|
||||
if (fbo == VK_NULL_HANDLE)
|
||||
return;
|
||||
|
||||
VulkanDevice::GetInstance().DeferFramebufferDestruction(fbo);
|
||||
}
|
||||
|
||||
void VulkanDevice::GetAdapterAndModeList(AdapterAndModeList* ret, VkInstance instance)
|
||||
{
|
||||
GPUList gpus = EnumerateGPUs(instance);
|
||||
|
@ -2098,7 +2237,7 @@ bool VulkanDevice::BeginPresent(bool frame_skip)
|
|||
|
||||
void VulkanDevice::EndPresent()
|
||||
{
|
||||
DebugAssert(InRenderPass() && !m_current_framebuffer);
|
||||
DebugAssert(InRenderPass() && m_num_current_render_targets == 0 && !m_current_depth_target);
|
||||
EndRenderPass();
|
||||
|
||||
VkCommandBuffer cmdbuf = GetCurrentCommandBuffer();
|
||||
|
@ -2196,7 +2335,7 @@ bool VulkanDevice::CheckFeatures(FeatureMask disabled_features)
|
|||
|
||||
m_features.dual_source_blend =
|
||||
!(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND) && m_device_features.dualSrcBlend;
|
||||
m_features.framebuffer_fetch = /*!(disabled_features & FEATURE_MASK_FRAMEBUFFER_FETCH) && */false;
|
||||
m_features.framebuffer_fetch = /*!(disabled_features & FEATURE_MASK_FRAMEBUFFER_FETCH) && */ false;
|
||||
|
||||
if (!m_features.dual_source_blend)
|
||||
Log_WarningPrintf("Vulkan driver is missing dual-source blending. This will have an impact on performance.");
|
||||
|
@ -2354,25 +2493,22 @@ void VulkanDevice::ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u
|
|||
void VulkanDevice::ClearRenderTarget(GPUTexture* t, u32 c)
|
||||
{
|
||||
GPUDevice::ClearRenderTarget(t, c);
|
||||
if (InRenderPass() && m_current_framebuffer && m_current_framebuffer->GetRT() == t)
|
||||
if (InRenderPass() && IsRenderTargetBound(t))
|
||||
EndRenderPass();
|
||||
}
|
||||
|
||||
void VulkanDevice::ClearDepth(GPUTexture* t, float d)
|
||||
{
|
||||
GPUDevice::ClearDepth(t, d);
|
||||
if (InRenderPass() && m_current_framebuffer && m_current_framebuffer->GetDS() == t)
|
||||
if (InRenderPass() && m_current_depth_target == t)
|
||||
EndRenderPass();
|
||||
}
|
||||
|
||||
void VulkanDevice::InvalidateRenderTarget(GPUTexture* t)
|
||||
{
|
||||
GPUDevice::InvalidateRenderTarget(t);
|
||||
if (InRenderPass() && m_current_framebuffer &&
|
||||
(m_current_framebuffer->GetRT() == t || m_current_framebuffer->GetDS() == t))
|
||||
{
|
||||
if (InRenderPass() && (t->IsRenderTarget() ? IsRenderTargetBound(t) : (m_current_depth_target == t)))
|
||||
EndRenderPass();
|
||||
}
|
||||
}
|
||||
|
||||
bool VulkanDevice::CreateBuffers()
|
||||
|
@ -2670,143 +2806,213 @@ void VulkanDevice::RenderBlankFrame()
|
|||
InvalidateCachedState();
|
||||
}
|
||||
|
||||
void VulkanDevice::SetFramebuffer(GPUFramebuffer* fb)
|
||||
void VulkanDevice::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds)
|
||||
{
|
||||
if (m_current_framebuffer == fb)
|
||||
return;
|
||||
bool changed = (m_num_current_render_targets != num_rts || m_current_depth_target != ds);
|
||||
bool needs_ds_clear = (ds && ds->IsClearedOrInvalidated());
|
||||
bool needs_rt_clear = false;
|
||||
|
||||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
m_current_depth_target = ds;
|
||||
for (u32 i = 0; i < num_rts; i++)
|
||||
{
|
||||
VulkanTexture* const RT = static_cast<VulkanTexture*>(rts[i]);
|
||||
changed |= m_current_render_targets[i] != RT;
|
||||
m_current_render_targets[i] = RT;
|
||||
needs_rt_clear |= RT->IsClearedOrInvalidated();
|
||||
}
|
||||
for (u32 i = num_rts; i < m_num_current_render_targets; i++)
|
||||
m_current_render_targets[i] = nullptr;
|
||||
m_num_current_render_targets = num_rts;
|
||||
|
||||
m_current_framebuffer = static_cast<VulkanFramebuffer*>(fb);
|
||||
if (changed)
|
||||
{
|
||||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
|
||||
if (m_num_current_render_targets == 0 && !m_current_depth_target)
|
||||
{
|
||||
m_current_framebuffer = VK_NULL_HANDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_optional_extensions.vk_khr_dynamic_rendering)
|
||||
{
|
||||
m_current_framebuffer =
|
||||
m_framebuffer_manager.Lookup((m_num_current_render_targets > 0) ? m_current_render_targets.data() : nullptr,
|
||||
m_num_current_render_targets, m_current_depth_target, 0);
|
||||
if (m_current_framebuffer == VK_NULL_HANDLE)
|
||||
{
|
||||
Log_ErrorPrint("Failed to create framebuffer");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This could use vkCmdClearAttachments() instead.
|
||||
if (needs_rt_clear || needs_ds_clear)
|
||||
{
|
||||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanDevice::BeginRenderPass()
|
||||
{
|
||||
// TODO: Stats
|
||||
DebugAssert(!InRenderPass());
|
||||
|
||||
VkRenderPassBeginInfo bi = {
|
||||
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, VK_NULL_HANDLE, VK_NULL_HANDLE, {}, 0u, nullptr};
|
||||
std::array<VkClearValue, 2> clear_values;
|
||||
|
||||
if (m_current_framebuffer) [[likely]]
|
||||
{
|
||||
VkFormat rt_format = VK_FORMAT_UNDEFINED;
|
||||
VkFormat ds_format = VK_FORMAT_UNDEFINED;
|
||||
VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
VkAttachmentLoadOp rt_load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
VkAttachmentStoreOp rt_store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
VkAttachmentLoadOp ds_load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
VkAttachmentStoreOp ds_store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
|
||||
VulkanTexture* rt = static_cast<VulkanTexture*>(m_current_framebuffer->GetRT());
|
||||
if (rt)
|
||||
{
|
||||
samples = static_cast<VkSampleCountFlagBits>(rt->GetSamples());
|
||||
rt_format = rt->GetVkFormat();
|
||||
rt_store_op = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
switch (rt->GetState())
|
||||
{
|
||||
case GPUTexture::State::Cleared:
|
||||
{
|
||||
std::memcpy(clear_values[0].color.float32, rt->GetUNormClearColor().data(),
|
||||
sizeof(clear_values[0].color.float32));
|
||||
rt_load_op = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
rt->SetState(GPUTexture::State::Dirty);
|
||||
bi.pClearValues = clear_values.data();
|
||||
bi.clearValueCount = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Invalidated:
|
||||
{
|
||||
// already DONT_CARE
|
||||
rt->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Dirty:
|
||||
{
|
||||
rt_load_op = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
UnreachableCode();
|
||||
break;
|
||||
}
|
||||
|
||||
rt->TransitionToLayout(VulkanTexture::Layout::ColorAttachment);
|
||||
rt->SetUseFenceCounter(GetCurrentFenceCounter());
|
||||
}
|
||||
|
||||
VulkanTexture* ds = static_cast<VulkanTexture*>(m_current_framebuffer->GetDS());
|
||||
if (ds)
|
||||
{
|
||||
samples = static_cast<VkSampleCountFlagBits>(ds->GetSamples());
|
||||
ds_format = ds->GetVkFormat();
|
||||
ds_store_op = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
switch (ds->GetState())
|
||||
{
|
||||
case GPUTexture::State::Cleared:
|
||||
{
|
||||
const u32 idx = rt ? 1 : 0;
|
||||
clear_values[idx].depthStencil = {ds->GetClearDepth(), 0u};
|
||||
ds_load_op = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
ds->SetState(GPUTexture::State::Dirty);
|
||||
bi.pClearValues = clear_values.data();
|
||||
bi.clearValueCount = idx + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Invalidated:
|
||||
{
|
||||
// already DONT_CARE
|
||||
ds->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
break;
|
||||
|
||||
case GPUTexture::State::Dirty:
|
||||
{
|
||||
ds_load_op = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
UnreachableCode();
|
||||
break;
|
||||
}
|
||||
|
||||
ds->TransitionToLayout(VulkanTexture::Layout::DepthStencilAttachment);
|
||||
ds->SetUseFenceCounter(GetCurrentFenceCounter());
|
||||
}
|
||||
|
||||
bi.framebuffer = m_current_framebuffer->GetFramebuffer();
|
||||
bi.renderPass = m_current_render_pass =
|
||||
GetRenderPass(rt_format, ds_format, samples, rt_load_op, rt_store_op, ds_load_op, ds_store_op);
|
||||
bi.renderArea.extent = {m_current_framebuffer->GetWidth(), m_current_framebuffer->GetHeight()};
|
||||
}
|
||||
else
|
||||
{
|
||||
// Re-rendering to swap chain.
|
||||
bi.framebuffer = m_swap_chain->GetCurrentFramebuffer();
|
||||
bi.renderPass = m_current_render_pass =
|
||||
GetRenderPass(m_swap_chain->GetImageFormat(), VK_FORMAT_UNDEFINED, VK_SAMPLE_COUNT_1_BIT,
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE);
|
||||
bi.renderArea.extent = {m_swap_chain->GetWidth(), m_swap_chain->GetHeight()};
|
||||
}
|
||||
|
||||
DebugAssert(m_current_render_pass);
|
||||
|
||||
// All textures should be in shader read only optimal already, but just in case..
|
||||
const u32 num_textures = GetActiveTexturesForLayout(m_current_pipeline_layout);
|
||||
for (u32 i = 0; i < num_textures; i++)
|
||||
m_current_textures[i]->TransitionToLayout(VulkanTexture::Layout::ShaderReadOnly);
|
||||
|
||||
// TODO: Stats
|
||||
vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &bi, VK_SUBPASS_CONTENTS_INLINE);
|
||||
if (m_optional_extensions.vk_khr_dynamic_rendering)
|
||||
{
|
||||
VkRenderingInfoKHR ri = {
|
||||
VK_STRUCTURE_TYPE_RENDERING_INFO_KHR, nullptr, 0u, {}, 1u, 0u, 0u, nullptr, nullptr, nullptr};
|
||||
|
||||
std::array<VkRenderingAttachmentInfoKHR, MAX_RENDER_TARGETS> attachments;
|
||||
VkRenderingAttachmentInfoKHR depth_attachment;
|
||||
|
||||
if (m_num_current_render_targets > 0 || m_current_depth_target)
|
||||
{
|
||||
ri.colorAttachmentCount = m_num_current_render_targets;
|
||||
ri.pColorAttachments = (m_num_current_render_targets > 0) ? attachments.data() : nullptr;
|
||||
|
||||
// set up clear values and transition targets
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
VulkanTexture* const rt = static_cast<VulkanTexture*>(m_current_render_targets[i]);
|
||||
rt->TransitionToLayout(VulkanTexture::Layout::ColorAttachment);
|
||||
rt->SetUseFenceCounter(GetCurrentFenceCounter());
|
||||
|
||||
VkRenderingAttachmentInfo& ai = attachments[i];
|
||||
ai.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
|
||||
ai.pNext = nullptr;
|
||||
ai.imageView = rt->GetView();
|
||||
ai.imageLayout = rt->GetVkLayout();
|
||||
ai.resolveMode = VK_RESOLVE_MODE_NONE_KHR;
|
||||
ai.resolveImageView = VK_NULL_HANDLE;
|
||||
ai.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
ai.loadOp = GetLoadOpForTexture(rt);
|
||||
ai.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
if (rt->GetState() == GPUTexture::State::Cleared)
|
||||
{
|
||||
std::memcpy(ai.clearValue.color.float32, rt->GetUNormClearColor().data(),
|
||||
sizeof(ai.clearValue.color.float32));
|
||||
}
|
||||
rt->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
|
||||
if (VulkanTexture* const ds = static_cast<VulkanTexture*>(m_current_depth_target))
|
||||
{
|
||||
ds->TransitionToLayout(VulkanTexture::Layout::DepthStencilAttachment);
|
||||
ds->SetUseFenceCounter(GetCurrentFenceCounter());
|
||||
|
||||
depth_attachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
|
||||
depth_attachment.pNext = nullptr;
|
||||
depth_attachment.imageView = ds->GetView();
|
||||
depth_attachment.imageLayout = ds->GetVkLayout();
|
||||
depth_attachment.resolveMode = VK_RESOLVE_MODE_NONE_KHR;
|
||||
depth_attachment.resolveImageView = VK_NULL_HANDLE;
|
||||
depth_attachment.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
depth_attachment.loadOp = GetLoadOpForTexture(ds);
|
||||
depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
ri.pDepthAttachment = &depth_attachment;
|
||||
|
||||
if (ds->GetState() == GPUTexture::State::Cleared)
|
||||
depth_attachment.clearValue.depthStencil = {ds->GetClearDepth(), 0u};
|
||||
|
||||
ds->SetState(GPUTexture::State::Dirty);
|
||||
}
|
||||
|
||||
const VulkanTexture* const rt_or_ds = static_cast<const VulkanTexture*>(
|
||||
(m_num_current_render_targets > 0) ? m_current_render_targets[0] : m_current_depth_target);
|
||||
ri.renderArea = {{}, {rt_or_ds->GetWidth(), rt_or_ds->GetHeight()}};
|
||||
}
|
||||
else
|
||||
{
|
||||
VkRenderingAttachmentInfo& ai = attachments[0];
|
||||
ai.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
|
||||
ai.pNext = nullptr;
|
||||
ai.imageView = m_swap_chain->GetCurrentImageView();
|
||||
ai.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
ai.resolveMode = VK_RESOLVE_MODE_NONE_KHR;
|
||||
ai.resolveImageView = VK_NULL_HANDLE;
|
||||
ai.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
ai.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
ai.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
ri.colorAttachmentCount = 1;
|
||||
ri.pColorAttachments = attachments.data();
|
||||
ri.renderArea = {{}, {m_swap_chain->GetWidth(), m_swap_chain->GetHeight()}};
|
||||
}
|
||||
|
||||
m_current_render_pass = DYNAMIC_RENDERING_RENDER_PASS;
|
||||
vkCmdBeginRenderingKHR(GetCurrentCommandBuffer(), &ri);
|
||||
}
|
||||
else
|
||||
{
|
||||
VkRenderPassBeginInfo bi = {
|
||||
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, VK_NULL_HANDLE, VK_NULL_HANDLE, {}, 0u, nullptr};
|
||||
std::array<VkClearValue, MAX_RENDER_TARGETS + 1> clear_values;
|
||||
|
||||
if (m_current_framebuffer != VK_NULL_HANDLE)
|
||||
{
|
||||
bi.framebuffer = m_current_framebuffer;
|
||||
bi.renderPass = m_current_render_pass = GetRenderPass(
|
||||
m_current_render_targets.data(), m_num_current_render_targets, m_current_depth_target, false, false);
|
||||
if (bi.renderPass == VK_NULL_HANDLE)
|
||||
{
|
||||
Log_ErrorPrint("Failed to create render pass");
|
||||
return;
|
||||
}
|
||||
|
||||
// set up clear values and transition targets
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
VulkanTexture* const rt = static_cast<VulkanTexture*>(m_current_render_targets[i]);
|
||||
if (rt->GetState() == GPUTexture::State::Cleared)
|
||||
{
|
||||
std::memcpy(clear_values[i].color.float32, rt->GetUNormClearColor().data(),
|
||||
sizeof(clear_values[i].color.float32));
|
||||
bi.pClearValues = clear_values.data();
|
||||
bi.clearValueCount = i + 1;
|
||||
}
|
||||
rt->SetState(GPUTexture::State::Dirty);
|
||||
rt->TransitionToLayout(VulkanTexture::Layout::ColorAttachment);
|
||||
rt->SetUseFenceCounter(GetCurrentFenceCounter());
|
||||
}
|
||||
if (VulkanTexture* const ds = static_cast<VulkanTexture*>(m_current_depth_target))
|
||||
{
|
||||
if (ds->GetState() == GPUTexture::State::Cleared)
|
||||
{
|
||||
clear_values[m_num_current_render_targets].depthStencil = {ds->GetClearDepth(), 0u};
|
||||
bi.pClearValues = clear_values.data();
|
||||
bi.clearValueCount = m_num_current_render_targets + 1;
|
||||
}
|
||||
ds->SetState(GPUTexture::State::Dirty);
|
||||
ds->TransitionToLayout(VulkanTexture::Layout::DepthStencilAttachment);
|
||||
ds->SetUseFenceCounter(GetCurrentFenceCounter());
|
||||
}
|
||||
|
||||
const VulkanTexture* const rt_or_ds = static_cast<const VulkanTexture*>(
|
||||
(m_num_current_render_targets > 0) ? m_current_render_targets[0] : m_current_depth_target);
|
||||
bi.renderArea.extent = {rt_or_ds->GetWidth(), rt_or_ds->GetHeight()};
|
||||
}
|
||||
else
|
||||
{
|
||||
// Re-rendering to swap chain.
|
||||
bi.framebuffer = m_swap_chain->GetCurrentFramebuffer();
|
||||
bi.renderPass = m_current_render_pass =
|
||||
GetSwapChainRenderPass(m_swap_chain->GetWindowInfo().surface_format, VK_ATTACHMENT_LOAD_OP_LOAD);
|
||||
bi.renderArea.extent = {m_swap_chain->GetWidth(), m_swap_chain->GetHeight()};
|
||||
}
|
||||
|
||||
DebugAssert(m_current_render_pass);
|
||||
vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &bi, VK_SUBPASS_CONTENTS_INLINE);
|
||||
}
|
||||
|
||||
// If this is a new command buffer, bind the pipeline and such.
|
||||
if (m_dirty_flags & DIRTY_FLAG_INITIAL)
|
||||
|
@ -2830,21 +3036,53 @@ void VulkanDevice::BeginSwapChainRenderPass()
|
|||
for (u32 i = 0; i < num_textures; i++)
|
||||
m_current_textures[i]->TransitionToLayout(VulkanTexture::Layout::ShaderReadOnly);
|
||||
|
||||
const VkRenderPass render_pass =
|
||||
GetRenderPass(m_swap_chain->GetImageFormat(), VK_FORMAT_UNDEFINED, VK_SAMPLE_COUNT_1_BIT,
|
||||
VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE);
|
||||
DebugAssert(render_pass);
|
||||
if (m_optional_extensions.vk_khr_dynamic_rendering)
|
||||
{
|
||||
const VkRenderingAttachmentInfo ai = {VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR,
|
||||
nullptr,
|
||||
m_swap_chain->GetCurrentImageView(),
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
VK_RESOLVE_MODE_NONE_KHR,
|
||||
VK_NULL_HANDLE,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
VK_ATTACHMENT_STORE_OP_STORE,
|
||||
{}};
|
||||
|
||||
const VkRenderPassBeginInfo rp = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||
nullptr,
|
||||
render_pass,
|
||||
m_swap_chain->GetCurrentFramebuffer(),
|
||||
{{0, 0}, {m_swap_chain->GetWidth(), m_swap_chain->GetHeight()}},
|
||||
1u,
|
||||
&s_present_clear_color};
|
||||
vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &rp, VK_SUBPASS_CONTENTS_INLINE);
|
||||
m_current_render_pass = render_pass;
|
||||
m_current_framebuffer = nullptr;
|
||||
const VkRenderingInfoKHR ri = {VK_STRUCTURE_TYPE_RENDERING_INFO_KHR,
|
||||
nullptr,
|
||||
0u,
|
||||
{{}, {m_swap_chain->GetWidth(), m_swap_chain->GetHeight()}},
|
||||
1u,
|
||||
0u,
|
||||
1u,
|
||||
&ai,
|
||||
nullptr,
|
||||
nullptr};
|
||||
|
||||
m_current_render_pass = DYNAMIC_RENDERING_RENDER_PASS;
|
||||
vkCmdBeginRenderingKHR(GetCurrentCommandBuffer(), &ri);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_current_render_pass =
|
||||
GetSwapChainRenderPass(m_swap_chain->GetWindowInfo().surface_format, VK_ATTACHMENT_LOAD_OP_CLEAR);
|
||||
DebugAssert(m_current_render_pass);
|
||||
|
||||
const VkRenderPassBeginInfo rp = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||
nullptr,
|
||||
m_current_render_pass,
|
||||
m_swap_chain->GetCurrentFramebuffer(),
|
||||
{{0, 0}, {m_swap_chain->GetWidth(), m_swap_chain->GetHeight()}},
|
||||
1u,
|
||||
&s_present_clear_color};
|
||||
vkCmdBeginRenderPass(GetCurrentCommandBuffer(), &rp, VK_SUBPASS_CONTENTS_INLINE);
|
||||
}
|
||||
|
||||
m_num_current_render_targets = 0;
|
||||
std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
|
||||
m_current_depth_target = nullptr;
|
||||
m_current_framebuffer = VK_NULL_HANDLE;
|
||||
|
||||
// Clear pipeline, it's likely incompatible.
|
||||
m_current_pipeline = nullptr;
|
||||
|
@ -2860,32 +3098,11 @@ void VulkanDevice::EndRenderPass()
|
|||
DebugAssert(m_current_render_pass != VK_NULL_HANDLE);
|
||||
|
||||
// TODO: stats
|
||||
m_current_render_pass = VK_NULL_HANDLE;
|
||||
|
||||
vkCmdEndRenderPass(GetCurrentCommandBuffer());
|
||||
}
|
||||
|
||||
void VulkanDevice::UnbindFramebuffer(VulkanFramebuffer* fb)
|
||||
{
|
||||
if (m_current_framebuffer != fb)
|
||||
return;
|
||||
|
||||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
m_current_framebuffer = nullptr;
|
||||
}
|
||||
|
||||
void VulkanDevice::UnbindFramebuffer(VulkanTexture* tex)
|
||||
{
|
||||
if (!m_current_framebuffer)
|
||||
return;
|
||||
|
||||
if (m_current_framebuffer->GetRT() != tex && m_current_framebuffer->GetDS() != tex)
|
||||
return;
|
||||
|
||||
if (InRenderPass())
|
||||
EndRenderPass();
|
||||
m_current_framebuffer = nullptr;
|
||||
VkCommandBuffer cmdbuf = GetCurrentCommandBuffer();
|
||||
if (std::exchange(m_current_render_pass, VK_NULL_HANDLE) == DYNAMIC_RENDERING_RENDER_PASS)
|
||||
vkCmdEndRenderingKHR(cmdbuf);
|
||||
else
|
||||
vkCmdEndRenderPass(GetCurrentCommandBuffer());
|
||||
}
|
||||
|
||||
void VulkanDevice::SetPipeline(GPUPipeline* pipeline)
|
||||
|
@ -2928,10 +3145,20 @@ void VulkanDevice::InvalidateCachedState()
|
|||
{
|
||||
m_dirty_flags = ALL_DIRTY_STATE;
|
||||
m_current_render_pass = VK_NULL_HANDLE;
|
||||
m_current_framebuffer = nullptr;
|
||||
m_current_pipeline = nullptr;
|
||||
}
|
||||
|
||||
bool VulkanDevice::IsRenderTargetBound(const GPUTexture* tex) const
|
||||
{
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
if (m_current_render_targets[i] == tex)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
VkPipelineLayout VulkanDevice::GetCurrentVkPipelineLayout() const
|
||||
{
|
||||
return m_pipeline_layouts[static_cast<u8>(m_current_pipeline_layout)];
|
||||
|
@ -3008,6 +3235,31 @@ void VulkanDevice::UnbindTexture(VulkanTexture* tex)
|
|||
m_dirty_flags |= DIRTY_FLAG_TEXTURES_OR_SAMPLERS;
|
||||
}
|
||||
}
|
||||
|
||||
if (tex->IsRenderTarget())
|
||||
{
|
||||
for (u32 i = 0; i < m_num_current_render_targets; i++)
|
||||
{
|
||||
if (m_current_render_targets[i] == tex)
|
||||
{
|
||||
Log_WarningPrint("Unbinding current RT");
|
||||
SetRenderTargets(nullptr, 0, m_current_depth_target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_framebuffer_manager.RemoveRTReferences(tex);
|
||||
}
|
||||
else if (tex->IsDepthStencil())
|
||||
{
|
||||
if (m_current_depth_target == tex)
|
||||
{
|
||||
Log_WarningPrint("Unbinding current DS");
|
||||
SetRenderTargets(nullptr, 0, nullptr);
|
||||
}
|
||||
|
||||
m_framebuffer_manager.RemoveDSReferences(tex);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanDevice::UnbindTextureBuffer(VulkanTextureBuffer* buf)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "gpu_device.h"
|
||||
#include "gpu_framebuffer_manager.h"
|
||||
#include "gpu_texture.h"
|
||||
#include "vulkan_loader.h"
|
||||
#include "vulkan_stream_buffer.h"
|
||||
|
@ -20,7 +21,6 @@
|
|||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class VulkanFramebuffer;
|
||||
class VulkanPipeline;
|
||||
class VulkanSwapChain;
|
||||
class VulkanTexture;
|
||||
|
@ -45,6 +45,7 @@ public:
|
|||
bool vk_ext_attachment_feedback_loop_layout : 1;
|
||||
bool vk_ext_full_screen_exclusive : 1;
|
||||
bool vk_khr_driver_properties : 1;
|
||||
bool vk_khr_dynamic_rendering : 1;
|
||||
bool vk_khr_push_descriptor : 1;
|
||||
};
|
||||
|
||||
|
@ -87,8 +88,6 @@ public:
|
|||
void ClearDepth(GPUTexture* t, float d) override;
|
||||
void InvalidateRenderTarget(GPUTexture* t) override;
|
||||
|
||||
std::unique_ptr<GPUFramebuffer> CreateFramebuffer(GPUTexture* rt_or_ds, GPUTexture* ds = nullptr) override;
|
||||
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, const std::string_view& source,
|
||||
const char* entry_point, DynamicHeapArray<u8>* out_binary) override;
|
||||
|
@ -106,7 +105,7 @@ public:
|
|||
void PushUniformBuffer(const void* data, u32 data_size) override;
|
||||
void* MapUniformBuffer(u32 size) override;
|
||||
void UnmapUniformBuffer(u32 size) override;
|
||||
void SetFramebuffer(GPUFramebuffer* fb) override;
|
||||
void SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds) override;
|
||||
void SetPipeline(GPUPipeline* pipeline) override;
|
||||
void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) override;
|
||||
void SetTextureBuffer(u32 slot, GPUTextureBuffer* buffer) override;
|
||||
|
@ -156,14 +155,10 @@ public:
|
|||
void WaitForGPUIdle();
|
||||
|
||||
// Creates a simple render pass.
|
||||
VkRenderPass GetRenderPass(VkFormat color_format, VkFormat depth_format, VkSampleCountFlagBits samples,
|
||||
VkAttachmentLoadOp color_load_op = VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
VkAttachmentStoreOp color_store_op = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
VkAttachmentLoadOp depth_load_op = VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||
VkAttachmentStoreOp depth_store_op = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
VkAttachmentLoadOp stencil_load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
VkAttachmentStoreOp stencil_store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||
bool color_feedback_loop = false, bool depth_sampling = false);
|
||||
VkRenderPass GetRenderPass(const GPUPipeline::GraphicsConfig& config);
|
||||
VkRenderPass GetRenderPass(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, bool color_feedback_loop = false,
|
||||
bool depth_sampling = false);
|
||||
VkRenderPass GetSwapChainRenderPass(GPUTexture::Format format, VkAttachmentLoadOp load_op);
|
||||
|
||||
// Gets a non-clearing version of the specified render pass. Slow, don't call in hot path.
|
||||
VkRenderPass GetRenderPassForRestarting(VkRenderPass pass);
|
||||
|
@ -213,7 +208,6 @@ public:
|
|||
void SubmitCommandBuffer(bool wait_for_completion, const char* reason, ...);
|
||||
void SubmitCommandBufferAndRestartRenderPass(const char* reason);
|
||||
|
||||
void UnbindFramebuffer(VulkanFramebuffer* fb);
|
||||
void UnbindFramebuffer(VulkanTexture* tex);
|
||||
void UnbindPipeline(VulkanPipeline* pl);
|
||||
void UnbindTexture(VulkanTexture* tex);
|
||||
|
@ -239,24 +233,32 @@ private:
|
|||
DIRTY_FLAG_INITIAL | DIRTY_FLAG_PIPELINE_LAYOUT | DIRTY_FLAG_DYNAMIC_OFFSETS | DIRTY_FLAG_TEXTURES_OR_SAMPLERS,
|
||||
};
|
||||
|
||||
union RenderPassCacheKey
|
||||
struct RenderPassCacheKey
|
||||
{
|
||||
struct
|
||||
struct RenderTarget
|
||||
{
|
||||
u32 color_format : 8;
|
||||
u32 depth_format : 8;
|
||||
u32 samples : 4;
|
||||
u32 color_load_op : 2;
|
||||
u32 color_store_op : 1;
|
||||
u32 depth_load_op : 2;
|
||||
u32 depth_store_op : 1;
|
||||
u32 stencil_load_op : 2;
|
||||
u32 stencil_store_op : 1;
|
||||
u32 color_feedback_loop : 1;
|
||||
u32 depth_sampling : 1;
|
||||
u8 format : 5;
|
||||
u8 load_op : 2;
|
||||
u8 store_op : 1;
|
||||
};
|
||||
RenderTarget color[MAX_RENDER_TARGETS];
|
||||
|
||||
u32 key;
|
||||
u8 depth_format : 5;
|
||||
u8 depth_load_op : 2;
|
||||
u8 depth_store_op : 1;
|
||||
u8 stencil_load_op : 2;
|
||||
u8 stencil_store_op : 1;
|
||||
u8 depth_sampling : 1;
|
||||
u8 color_feedback_loop : 1;
|
||||
u8 samples;
|
||||
|
||||
bool operator==(const RenderPassCacheKey& rhs) const;
|
||||
bool operator!=(const RenderPassCacheKey& rhs) const;
|
||||
};
|
||||
|
||||
struct RenderPassCacheKeyHash
|
||||
{
|
||||
size_t operator()(const RenderPassCacheKey& rhs) const;
|
||||
};
|
||||
|
||||
struct CommandBuffer
|
||||
|
@ -332,6 +334,8 @@ private:
|
|||
/// Set dirty flags on everything to force re-bind at next draw time.
|
||||
void InvalidateCachedState();
|
||||
|
||||
bool IsRenderTargetBound(const GPUTexture* tex) const;
|
||||
|
||||
/// Applies any changed state.
|
||||
VkPipelineLayout GetCurrentVkPipelineLayout() const;
|
||||
void SetInitialPipelineState();
|
||||
|
@ -349,6 +353,8 @@ private:
|
|||
bool InRenderPass();
|
||||
|
||||
VkRenderPass CreateCachedRenderPass(RenderPassCacheKey key);
|
||||
static VkFramebuffer CreateFramebuffer(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags);
|
||||
static void DestroyFramebuffer(VkFramebuffer fbo);
|
||||
|
||||
void BeginCommandBuffer(u32 index);
|
||||
void WaitForCommandBufferCompletion(u32 index);
|
||||
|
@ -400,7 +406,8 @@ private:
|
|||
|
||||
QueuedPresent m_queued_present = {};
|
||||
|
||||
std::unordered_map<u32, VkRenderPass> m_render_pass_cache;
|
||||
std::unordered_map<RenderPassCacheKey, VkRenderPass, RenderPassCacheKeyHash> m_render_pass_cache;
|
||||
GPUFramebufferManager<VkFramebuffer, CreateFramebuffer, DestroyFramebuffer> m_framebuffer_manager;
|
||||
VkPipelineCache m_pipeline_cache = VK_NULL_HANDLE;
|
||||
|
||||
// TODO: Move to static?
|
||||
|
@ -438,7 +445,10 @@ private:
|
|||
// Which bindings/state has to be updated before the next draw.
|
||||
u32 m_dirty_flags = ALL_DIRTY_STATE;
|
||||
|
||||
VulkanFramebuffer* m_current_framebuffer = nullptr;
|
||||
u32 m_num_current_render_targets = 0;
|
||||
std::array<GPUTexture*, MAX_RENDER_TARGETS> m_current_render_targets = {};
|
||||
GPUTexture* m_current_depth_target = nullptr;
|
||||
VkFramebuffer m_current_framebuffer = VK_NULL_HANDLE;
|
||||
VkRenderPass m_current_render_pass = VK_NULL_HANDLE;
|
||||
|
||||
VulkanPipeline* m_current_pipeline = nullptr;
|
||||
|
|
|
@ -236,6 +236,10 @@ VULKAN_DEVICE_ENTRY_POINT(vkAcquireFullScreenExclusiveModeEXT, false)
|
|||
VULKAN_DEVICE_ENTRY_POINT(vkReleaseFullScreenExclusiveModeEXT, false)
|
||||
#endif
|
||||
|
||||
// VK_KHR_dynamic_rendering
|
||||
VULKAN_DEVICE_ENTRY_POINT(vkCmdBeginRenderingKHR, false)
|
||||
VULKAN_DEVICE_ENTRY_POINT(vkCmdEndRenderingKHR, false)
|
||||
|
||||
// VK_KHR_push_descriptor
|
||||
VULKAN_DEVICE_ENTRY_POINT(vkCmdPushDescriptorSetKHR, false)
|
||||
|
||||
|
|
|
@ -199,11 +199,31 @@ std::unique_ptr<GPUPipeline> VulkanDevice::CreatePipeline(const GPUPipeline::Gra
|
|||
|
||||
gpb.SetPipelineLayout(m_pipeline_layouts[static_cast<u8>(config.layout)]);
|
||||
|
||||
const VkRenderPass render_pass = GetRenderPass(TEXTURE_FORMAT_MAPPING[static_cast<u8>(config.color_format)],
|
||||
TEXTURE_FORMAT_MAPPING[static_cast<u8>(config.depth_format)],
|
||||
static_cast<VkSampleCountFlagBits>(config.samples));
|
||||
DebugAssert(render_pass);
|
||||
gpb.SetRenderPass(render_pass, 0);
|
||||
if (m_optional_extensions.vk_khr_dynamic_rendering)
|
||||
{
|
||||
gpb.SetDynamicRendering();
|
||||
|
||||
for (u32 i = 0; i < MAX_RENDER_TARGETS; i++)
|
||||
{
|
||||
if (config.color_formats[i] == GPUTexture::Format::Unknown)
|
||||
break;
|
||||
|
||||
gpb.AddDynamicRenderingColorAttachment(
|
||||
VulkanDevice::TEXTURE_FORMAT_MAPPING[static_cast<u8>(config.color_formats[i])]);
|
||||
}
|
||||
|
||||
if (config.depth_format != GPUTexture::Format::Unknown)
|
||||
{
|
||||
gpb.SetDynamicRenderingDepthAttachment(VulkanDevice::TEXTURE_FORMAT_MAPPING[static_cast<u8>(config.depth_format)],
|
||||
VK_FORMAT_UNDEFINED);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const VkRenderPass render_pass = GetRenderPass(config);
|
||||
DebugAssert(render_pass != VK_NULL_HANDLE);
|
||||
gpb.SetRenderPass(render_pass, 0);
|
||||
}
|
||||
|
||||
const VkPipeline pipeline = gpb.Create(m_device, m_pipeline_cache, false);
|
||||
if (!pipeline)
|
||||
|
|
|
@ -488,8 +488,7 @@ bool VulkanSwapChain::CreateSwapChain()
|
|||
res = vkGetSwapchainImagesKHR(dev.GetVulkanDevice(), m_swap_chain, &image_count, images.data());
|
||||
Assert(res == VK_SUCCESS);
|
||||
|
||||
VkRenderPass render_pass =
|
||||
dev.GetRenderPass(m_format, VK_FORMAT_UNDEFINED, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR);
|
||||
VkRenderPass render_pass = dev.GetSwapChainRenderPass(m_window_info.surface_format, VK_ATTACHMENT_LOAD_OP_CLEAR);
|
||||
if (render_pass == VK_NULL_HANDLE)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
ALWAYS_INLINE u32 GetImageCount() const { return static_cast<u32>(m_images.size()); }
|
||||
ALWAYS_INLINE VkFormat GetImageFormat() const { return m_format; }
|
||||
ALWAYS_INLINE VkImage GetCurrentImage() const { return m_images[m_current_image].image; }
|
||||
ALWAYS_INLINE VkImageView GetCurrentImageView() const { return m_images[m_current_image].view; }
|
||||
ALWAYS_INLINE VkFramebuffer GetCurrentFramebuffer() const { return m_images[m_current_image].framebuffer; }
|
||||
ALWAYS_INLINE VkSemaphore GetImageAvailableSemaphore() const
|
||||
{
|
||||
|
|
|
@ -961,54 +961,6 @@ std::unique_ptr<GPUSampler> VulkanDevice::CreateSampler(const GPUSampler::Config
|
|||
return std::unique_ptr<GPUSampler>(new VulkanSampler(vsampler));
|
||||
}
|
||||
|
||||
VulkanFramebuffer::VulkanFramebuffer(GPUTexture* rt, GPUTexture* ds, u32 width, u32 height, VkFramebuffer fb)
|
||||
: GPUFramebuffer(rt, ds, width, height), m_framebuffer(fb)
|
||||
{
|
||||
}
|
||||
|
||||
VulkanFramebuffer::~VulkanFramebuffer()
|
||||
{
|
||||
VulkanDevice::GetInstance().DeferFramebufferDestruction(m_framebuffer);
|
||||
}
|
||||
|
||||
void VulkanFramebuffer::SetDebugName(const std::string_view& name)
|
||||
{
|
||||
Vulkan::SetObjectName(VulkanDevice::GetInstance().GetVulkanDevice(), m_framebuffer, name);
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUFramebuffer> VulkanDevice::CreateFramebuffer(GPUTexture* rt_or_ds, GPUTexture* ds /*= nullptr*/)
|
||||
{
|
||||
DebugAssert((rt_or_ds || ds) && (!rt_or_ds || rt_or_ds->IsRenderTarget() || (rt_or_ds->IsDepthStencil() && !ds)));
|
||||
VulkanTexture* RT = static_cast<VulkanTexture*>((rt_or_ds && rt_or_ds->IsDepthStencil()) ? nullptr : rt_or_ds);
|
||||
VulkanTexture* DS = static_cast<VulkanTexture*>((rt_or_ds && rt_or_ds->IsDepthStencil()) ? rt_or_ds : ds);
|
||||
|
||||
const u32 width = RT ? RT->GetWidth() : DS->GetWidth();
|
||||
const u32 height = RT ? RT->GetHeight() : DS->GetHeight();
|
||||
|
||||
const VkRenderPass render_pass =
|
||||
GetRenderPass(RT ? RT->GetVkFormat() : VK_FORMAT_UNDEFINED, DS ? DS->GetVkFormat() : VK_FORMAT_UNDEFINED,
|
||||
static_cast<VkSampleCountFlagBits>(RT ? RT->GetSamples() : DS->GetSamples()),
|
||||
RT ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
RT ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||
DS ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
DS ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE);
|
||||
DebugAssert(render_pass != VK_NULL_HANDLE);
|
||||
|
||||
Vulkan::FramebufferBuilder fbb;
|
||||
fbb.SetRenderPass(render_pass);
|
||||
fbb.SetSize(width, height, 1);
|
||||
if (RT)
|
||||
fbb.AddAttachment(RT->GetView());
|
||||
if (DS)
|
||||
fbb.AddAttachment(DS->GetView());
|
||||
|
||||
const VkFramebuffer fb = fbb.Create(m_device, false);
|
||||
if (fb == VK_NULL_HANDLE)
|
||||
return {};
|
||||
|
||||
return std::unique_ptr<GPUFramebuffer>(new VulkanFramebuffer(RT, DS, width, height, fb));
|
||||
}
|
||||
|
||||
VulkanTextureBuffer::VulkanTextureBuffer(Format format, u32 size_in_elements)
|
||||
: GPUTextureBuffer(format, size_in_elements)
|
||||
{
|
||||
|
|
|
@ -126,25 +126,6 @@ private:
|
|||
VkSampler m_sampler;
|
||||
};
|
||||
|
||||
class VulkanFramebuffer final : public GPUFramebuffer
|
||||
{
|
||||
friend VulkanDevice;
|
||||
|
||||
public:
|
||||
~VulkanFramebuffer() override;
|
||||
|
||||
ALWAYS_INLINE VkFramebuffer GetFramebuffer() const { return m_framebuffer; }
|
||||
|
||||
void SetDebugName(const std::string_view& name) override;
|
||||
|
||||
// TODO: Maybe render passes should be in here to avoid the map lookup...
|
||||
|
||||
private:
|
||||
VulkanFramebuffer(GPUTexture* rt, GPUTexture* ds, u32 width, u32 height, VkFramebuffer fb);
|
||||
|
||||
VkFramebuffer m_framebuffer;
|
||||
};
|
||||
|
||||
class VulkanTextureBuffer final : public GPUTextureBuffer
|
||||
{
|
||||
friend VulkanDevice;
|
||||
|
|
Loading…
Reference in New Issue