From de08feeffb1e08227b2f7ae884464175a5a21379 Mon Sep 17 00:00:00 2001 From: Stenzek <stenzek@gmail.com> Date: Mon, 31 Jul 2023 23:33:02 +1000 Subject: [PATCH] More abstraction --- src/common/CMakeLists.txt | 165 ---------- src/core/CMakeLists.txt | 186 ++++++++++- src/core/core.vcxproj | 6 - src/core/core.vcxproj.filters | 18 - src/core/gpu/d3d11_device.cpp | 505 +++++++++++++++++++++++++++++ src/core/gpu/d3d11_device.h | 112 ++++++- src/core/gpu/d3d11_pipeline.cpp | 242 -------------- src/core/gpu/d3d11_pipeline.h | 53 --- src/core/gpu/d3d11_shader.cpp | 113 ------- src/core/gpu/d3d11_shader.h | 40 --- src/core/gpu/gpu_device.cpp | 189 +++++++++++ src/core/gpu/gpu_device.h | 345 +++++++++++++++++++- src/core/gpu/gpu_pipeline.h | 199 ------------ src/core/gpu/gpu_shader.h | 29 -- src/frontend-common/CMakeLists.txt | 33 -- 15 files changed, 1325 insertions(+), 910 deletions(-) delete mode 100644 src/core/gpu/d3d11_pipeline.cpp delete mode 100644 src/core/gpu/d3d11_pipeline.h delete mode 100644 src/core/gpu/d3d11_shader.cpp delete mode 100644 src/core/gpu/d3d11_shader.h delete mode 100644 src/core/gpu/gpu_pipeline.h delete mode 100644 src/core/gpu/gpu_shader.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 370a89849..829244272 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -15,8 +15,6 @@ add_library(common fifo_queue.h file_system.cpp file_system.h - gpu_texture.cpp - gpu_texture.h image.cpp image.h hash_combine.h @@ -66,28 +64,6 @@ target_link_libraries(common PRIVATE stb libchdr zlib minizip Zstd::Zstd "${CMAK if(WIN32) target_sources(common PRIVATE - d3d12/context.cpp - d3d12/context.h - d3d12/descriptor_heap_manager.cpp - d3d12/descriptor_heap_manager.h - d3d12/shader_cache.cpp - d3d12/shader_cache.h - d3d12/staging_texture.cpp - d3d12/staging_texture.h - d3d12/stream_buffer.cpp - d3d12/stream_buffer.h - d3d12/texture.cpp - d3d12/texture.h - d3d12/util.cpp - d3d12/util.h - d3d11/shader_cache.cpp - d3d11/shader_cache.h - d3d11/shader_compiler.cpp - d3d11/shader_compiler.h - d3d11/stream_buffer.cpp - d3d11/stream_buffer.h - d3d11/texture.cpp - d3d11/texture.h http_downloader_winhttp.cpp http_downloader_winhttp.h thirdparty/StackWalker.cpp @@ -113,147 +89,6 @@ if(ANDROID) target_link_libraries(common PRIVATE log) endif() -if(USE_X11) - target_sources(common PRIVATE - gl/x11_window.cpp - gl/x11_window.h - ) - target_compile_definitions(common PRIVATE "-DUSE_X11=1") - target_include_directories(common PRIVATE "${X11_INCLUDE_DIR}" "${X11_Xrandr_INCLUDE_PATH}") - target_link_libraries(common PRIVATE "${X11_LIBRARIES}" "${X11_Xrandr_LIB}") -endif() - -if(USE_WAYLAND) - target_compile_definitions(common PRIVATE "-DUSE_WAYLAND=1") -elseif(SUPPORTS_WAYLAND) - message(WARNING "Wayland support for renderers is disabled.\nDuckStation will FAIL to start on Wayland.") -endif() - -if(USE_DRMKMS) - target_sources(common PRIVATE - drm_display.cpp - drm_display.h - ) - target_link_libraries(common PUBLIC Libdrm::Libdrm) -endif() - -if(ENABLE_OPENGL) - target_sources(common PRIVATE - gl/context.cpp - gl/context.h - gl/program.cpp - gl/program.h - gl/shader_cache.cpp - gl/shader_cache.h - gl/stream_buffer.cpp - gl/stream_buffer.h - gl/texture.cpp - gl/texture.h - ) - target_compile_definitions(common PUBLIC "WITH_OPENGL=1") - target_link_libraries(common PRIVATE glad) - - if(WIN32) - target_sources(common PRIVATE - gl/context_wgl.cpp - gl/context_wgl.h - ) - endif() - - if(USE_EGL) - target_sources(common PRIVATE - gl/context_egl.cpp - gl/context_egl.h - ) - target_compile_definitions(common PRIVATE "-DUSE_EGL=1") - - if(USE_X11) - target_sources(common PRIVATE - gl/context_egl_x11.cpp - gl/context_egl_x11.h - ) - - # We set EGL_NO_X11 because otherwise X comes in with its macros and breaks - # a bunch of files from compiling, if we include the EGL headers. This just - # makes the data types opaque, we can still use it with X11 if needed. - target_compile_definitions(common PRIVATE "-DEGL_NO_X11=1") - endif() - if(ANDROID AND USE_EGL) - target_sources(common PRIVATE - gl/context_egl_android.cpp - gl/context_egl_android.h - ) - endif() - if(USE_DRMKMS) - target_compile_definitions(common PRIVATE "-DUSE_GBM=1") - target_sources(common PRIVATE - gl/context_egl_gbm.cpp - gl/context_egl_gbm.h - ) - target_link_libraries(common PUBLIC GBM::GBM) - endif() - if(USE_FBDEV) - target_compile_definitions(common PRIVATE "-DUSE_FBDEV=1") - target_sources(common PRIVATE - gl/context_egl_fbdev.cpp - gl/context_egl_fbdev.h - ) - endif() - endif() - - if(USE_X11) - target_sources(common PRIVATE - gl/context_glx.cpp - gl/context_glx.h - ) - target_compile_definitions(common PRIVATE "-DUSE_GLX=1") - endif() - - if(USE_WAYLAND) - target_sources(common PRIVATE - gl/context_egl_wayland.cpp - gl/context_egl_wayland.h - ) - endif() - - if(APPLE) - target_sources(common PRIVATE - gl/context_agl.mm - gl/context_agl.h - ) - endif() -endif() - -if(ENABLE_VULKAN) - target_sources(common PRIVATE - vulkan/builders.cpp - vulkan/builders.h - vulkan/context.cpp - vulkan/context.h - vulkan/loader.h - vulkan/loader.cpp - vulkan/shader_cache.cpp - vulkan/shader_cache.h - vulkan/shader_compiler.cpp - vulkan/shader_compiler.h - vulkan/stream_buffer.cpp - vulkan/stream_buffer.h - vulkan/swap_chain.cpp - vulkan/swap_chain.h - vulkan/texture.cpp - vulkan/texture.h - vulkan/util.cpp - vulkan/util.h - ) - target_compile_definitions(common PUBLIC "WITH_VULKAN=1") - target_link_libraries(common PRIVATE glslang) - - if(APPLE) - # Needed for Vulkan Swap Chain. - target_link_libraries(common PRIVATE "objc") - endif() -endif() - if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") # We need -lrt for shm_unlink target_link_libraries(common PRIVATE rt) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 158af6b30..e6c7e8cbe 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -54,8 +54,6 @@ add_library(core gte_types.h host.cpp host.h - host_display.cpp - host_display.h host_interface_progress_callback.cpp host_interface_progress_callback.h host_settings.h @@ -122,6 +120,47 @@ target_include_directories(core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") target_link_libraries(core PUBLIC Threads::Threads common util zlib) target_link_libraries(core PRIVATE stb xxhash imgui rapidjson tinyxml2) +target_sources(core PRIVATE + gpu/gpu_device.cpp + gpu/gpu_device.h + gpu/gpu_pipeline.h + gpu/gpu_shader.h + gpu/gpu_texture.cpp + gpu/gpu_texture.h + gpu/postprocessing_chain.cpp + gpu/postprocessing_chain.h + gpu/postprocessing_shader.cpp + gpu/postprocessing_shader.h + gpu/postprocessing_shadergen.cpp + gpu/postprocessing_shadergen.h +) + +if(WIN32) + target_sources(core PRIVATE + d3d12/context.cpp + d3d12/context.h + d3d12/descriptor_heap_manager.cpp + d3d12/descriptor_heap_manager.h + d3d12/shader_cache.cpp + d3d12/shader_cache.h + d3d12/staging_texture.cpp + d3d12/staging_texture.h + d3d12/stream_buffer.cpp + d3d12/stream_buffer.h + d3d12/texture.cpp + d3d12/texture.h + d3d12/util.cpp + d3d12/util.h + d3d11/shader_cache.cpp + d3d11/shader_cache.h + d3d11/shader_compiler.cpp + d3d11/shader_compiler.h + d3d11/stream_buffer.cpp + d3d11/stream_buffer.h + d3d11/texture.cpp + d3d11/texture.h + ) +endif() if(WIN32) target_sources(core PRIVATE gpu_hw_d3d12.cpp @@ -132,10 +171,116 @@ if(WIN32) target_link_libraries(core PRIVATE winmm.lib) endif() -if(ENABLE_CUBEB) - target_compile_definitions(core PUBLIC "WITH_CUBEB=1") +if(USE_X11) + target_sources(common PRIVATE + gl/x11_window.cpp + gl/x11_window.h + ) + target_compile_definitions(common PRIVATE "-DUSE_X11=1") + target_include_directories(common PRIVATE "${X11_INCLUDE_DIR}" "${X11_Xrandr_INCLUDE_PATH}") + target_link_libraries(common PRIVATE "${X11_LIBRARIES}" "${X11_Xrandr_LIB}") endif() +if(USE_WAYLAND) + target_compile_definitions(common PRIVATE "-DUSE_WAYLAND=1") +elseif(SUPPORTS_WAYLAND) + message(WARNING "Wayland support for renderers is disabled.\nDuckStation will FAIL to start on Wayland.") +endif() + +if(USE_DRMKMS) + target_sources(common PRIVATE + drm_display.cpp + drm_display.h + ) + target_link_libraries(common PUBLIC Libdrm::Libdrm) +endif() + +if(ENABLE_OPENGL) + target_sources(common PRIVATE + gpu/gl/context.cpp + gpu/gl/context.h + gpu/gl/program.cpp + gpu/gl/program.h + gpu/gl/shader_cache.cpp + gpu/gl/shader_cache.h + gpu/gl/stream_buffer.cpp + gpu/gl/stream_buffer.h + gpu/gl/texture.cpp + gpu/gl/texture.h + ) + target_compile_definitions(common PUBLIC "WITH_OPENGL=1") + target_link_libraries(common PRIVATE glad) + + if(WIN32) + target_sources(common PRIVATE + gl/context_wgl.cpp + gl/context_wgl.h + ) + endif() + + if(USE_EGL) + target_sources(common PRIVATE + gl/context_egl.cpp + gl/context_egl.h + ) + target_compile_definitions(common PRIVATE "-DUSE_EGL=1") + + if(USE_X11) + target_sources(common PRIVATE + gl/context_egl_x11.cpp + gl/context_egl_x11.h + ) + + # We set EGL_NO_X11 because otherwise X comes in with its macros and breaks + # a bunch of files from compiling, if we include the EGL headers. This just + # makes the data types opaque, we can still use it with X11 if needed. + target_compile_definitions(common PRIVATE "-DEGL_NO_X11=1") + endif() + if(ANDROID AND USE_EGL) + target_sources(common PRIVATE + gl/context_egl_android.cpp + gl/context_egl_android.h + ) + endif() + if(USE_DRMKMS) + target_compile_definitions(common PRIVATE "-DUSE_GBM=1") + target_sources(common PRIVATE + gl/context_egl_gbm.cpp + gl/context_egl_gbm.h + ) + target_link_libraries(common PUBLIC GBM::GBM) + endif() + if(USE_FBDEV) + target_compile_definitions(common PRIVATE "-DUSE_FBDEV=1") + target_sources(common PRIVATE + gl/context_egl_fbdev.cpp + gl/context_egl_fbdev.h + ) + endif() + endif() + + if(USE_X11) + target_sources(common PRIVATE + gl/context_glx.cpp + gl/context_glx.h + ) + target_compile_definitions(common PRIVATE "-DUSE_GLX=1") + endif() + + if(USE_WAYLAND) + target_sources(common PRIVATE + gl/context_egl_wayland.cpp + gl/context_egl_wayland.h + ) + endif() + + if(APPLE) + target_sources(common PRIVATE + gpu/gl/context_agl.mm + gpu/gl/context_agl.h + ) + endif() +endif() if(ENABLE_OPENGL) target_sources(core PRIVATE gpu_hw_opengl.cpp @@ -144,6 +289,35 @@ if(ENABLE_OPENGL) target_link_libraries(core PRIVATE glad) endif() +if(ENABLE_VULKAN) + target_sources(common PRIVATE + gpu/vulkan/builders.cpp + gpu/vulkan/builders.h + gpu/vulkan/context.cpp + gpu/vulkan/context.h + gpu/vulkan/loader.h + gpu/vulkan/loader.cpp + gpu/vulkan/shader_cache.cpp + gpu/vulkan/shader_cache.h + gpu/vulkan/shader_compiler.cpp + gpu/vulkan/shader_compiler.h + gpu/vulkan/stream_buffer.cpp + gpu/vulkan/stream_buffer.h + gpu/vulkan/swap_chain.cpp + gpu/vulkan/swap_chain.h + gpu/vulkan/texture.cpp + gpu/vulkan/texture.h + gpu/vulkan/util.cpp + gpu/vulkan/util.h + ) + target_compile_definitions(common PUBLIC "WITH_VULKAN=1") + target_link_libraries(common PRIVATE glslang) + + if(APPLE) + # Needed for Vulkan Swap Chain. + target_link_libraries(common PRIVATE "objc") + endif() +endif() if(ENABLE_VULKAN) target_sources(core PRIVATE gpu_hw_vulkan.cpp @@ -151,6 +325,10 @@ if(ENABLE_VULKAN) ) endif() +if(ENABLE_CUBEB) + target_compile_definitions(core PUBLIC "WITH_CUBEB=1") +endif() + if(${CPU_ARCH} STREQUAL "x64") target_include_directories(core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../../dep/xbyak/xbyak") target_compile_definitions(core PUBLIC "WITH_RECOMPILER=1" "WITH_MMAP_FASTMEM=1") diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index 19f685eb4..22fe45004 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -37,8 +37,6 @@ <ClCompile Include="gpu\d3d11\shader_compiler.cpp" /> <ClCompile Include="gpu\d3d11\stream_buffer.cpp" /> <ClCompile Include="gpu\d3d11_device.cpp" /> - <ClCompile Include="gpu\d3d11_pipeline.cpp" /> - <ClCompile Include="gpu\d3d11_shader.cpp" /> <ClCompile Include="gpu\d3d11_texture.cpp" /> <ClCompile Include="gpu\d3d12\context.cpp" /> <ClCompile Include="gpu\d3d12\descriptor_heap_manager.cpp" /> @@ -163,8 +161,6 @@ <ClInclude Include="gpu\d3d11\shader_compiler.h" /> <ClInclude Include="gpu\d3d11\stream_buffer.h" /> <ClInclude Include="gpu\d3d11_device.h" /> - <ClInclude Include="gpu\d3d11_pipeline.h" /> - <ClInclude Include="gpu\d3d11_shader.h" /> <ClInclude Include="gpu\d3d_shaders.h" /> <ClInclude Include="gpu\d3d11_texture.h" /> <ClInclude Include="gpu\d3d12\context.h" /> @@ -201,8 +197,6 @@ <ExcludedFromBuild>true</ExcludedFromBuild> </ClInclude> <ClInclude Include="gpu\gpu_device.h" /> - <ClInclude Include="gpu\gpu_pipeline.h" /> - <ClInclude Include="gpu\gpu_shader.h" /> <ClInclude Include="gpu\gpu_texture.h" /> <ClInclude Include="gpu\imgui_impl_dx12.h" /> <ClInclude Include="gpu\imgui_impl_opengl3.h" /> diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index d4e9fd66a..3109cb210 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -188,12 +188,6 @@ <ClCompile Include="gpu\d3d11_texture.cpp"> <Filter>gpu</Filter> </ClCompile> - <ClCompile Include="gpu\d3d11_shader.cpp"> - <Filter>gpu</Filter> - </ClCompile> - <ClCompile Include="gpu\d3d11_pipeline.cpp"> - <Filter>gpu</Filter> - </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="types.h" /> @@ -401,18 +395,6 @@ <ClInclude Include="gpu\d3d_shaders.h"> <Filter>gpu</Filter> </ClInclude> - <ClInclude Include="gpu\gpu_pipeline.h"> - <Filter>gpu</Filter> - </ClInclude> - <ClInclude Include="gpu\gpu_shader.h"> - <Filter>gpu</Filter> - </ClInclude> - <ClInclude Include="gpu\d3d11_shader.h"> - <Filter>gpu</Filter> - </ClInclude> - <ClInclude Include="gpu\d3d11_pipeline.h"> - <Filter>gpu</Filter> - </ClInclude> </ItemGroup> <ItemGroup> <Filter Include="gpu"> diff --git a/src/core/gpu/d3d11_device.cpp b/src/core/gpu/d3d11_device.cpp index fcc54b4bc..a167e4e9f 100644 --- a/src/core/gpu/d3d11_device.cpp +++ b/src/core/gpu/d3d11_device.cpp @@ -558,6 +558,9 @@ bool D3D11Device::SetFullscreen(bool fullscreen, u32 width, u32 height, float re bool D3D11Device::CreateResources() { + if (!GPUDevice::CreateResources()) + return false; + HRESULT hr; m_display_vertex_shader = @@ -1304,3 +1307,505 @@ float D3D11Device::GetAndResetAccumulatedGPUTime() m_accumulated_gpu_time = 0.0f; return value; } + +D3D11Framebuffer::D3D11Framebuffer(ComPtr<ID3D11RenderTargetView> rtv, ComPtr<ID3D11DepthStencilView> dsv) + : m_rtv(std::move(rtv)), m_dsv(std::move(dsv)) +{ +} + +D3D11Framebuffer::~D3D11Framebuffer() = default; + +void D3D11Framebuffer::SetDebugName(const std::string_view& name) +{ + Panic("Implement me"); +} + +std::unique_ptr<GPUFramebuffer> D3D11Device::CreateFramebuffer(GPUTexture* rt, u32 rt_layer, u32 rt_level, + GPUTexture* ds, u32 ds_layer, u32 ds_level) +{ + ComPtr<ID3D11RenderTargetView> rtv; + ComPtr<ID3D11DepthStencilView> dsv; + HRESULT hr; + + if (rt) + { + D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = {}; + rtv_desc.Format = static_cast<D3D11Texture*>(rt)->GetDXGIFormat(); + if (rt->IsMultisampled()) + { + Assert(rt_level == 0); + if (rt->GetLayers() > 1) + { + rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY; + rtv_desc.Texture2DMSArray.ArraySize = rt->GetLayers(); + rtv_desc.Texture2DMSArray.FirstArraySlice = rt_layer; + } + else + { + rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; + } + } + else + { + if (rt->GetLayers() > 1) + { + rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtv_desc.Texture2DArray.ArraySize = rt->GetLayers(); + rtv_desc.Texture2DArray.FirstArraySlice = rt_layer; + rtv_desc.Texture2DArray.MipSlice = rt_level; + } + else + { + rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtv_desc.Texture2D.MipSlice = rt_level; + } + } + + if (FAILED(hr = m_device->CreateRenderTargetView(static_cast<D3D11Texture*>(rt)->GetD3DTexture(), &rtv_desc, + rtv.GetAddressOf()))) + { + Log_ErrorPrintf("CreateRenderTargetView() failed: %08X", hr); + return {}; + } + } + + if (ds) + { + D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = {}; + dsv_desc.Format = static_cast<D3D11Texture*>(ds)->GetDXGIFormat(); + if (ds->IsMultisampled()) + { + Assert(rt_level == 0); + if (ds->GetLayers() > 1) + { + dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY; + dsv_desc.Texture2DMSArray.ArraySize = ds->GetLayers(); + dsv_desc.Texture2DMSArray.FirstArraySlice = rt_layer; + } + else + { + dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; + } + } + else + { + if (ds->GetLayers() > 1) + { + dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + dsv_desc.Texture2DArray.ArraySize = ds->GetLayers(); + dsv_desc.Texture2DArray.FirstArraySlice = rt_layer; + dsv_desc.Texture2DArray.MipSlice = rt_level; + } + else + { + dsv_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + dsv_desc.Texture2D.MipSlice = rt_level; + } + } + + if (FAILED(hr = m_device->CreateDepthStencilView(static_cast<D3D11Texture*>(ds)->GetD3DTexture(), &dsv_desc, + dsv.GetAddressOf()))) + { + Log_ErrorPrintf("CreateDepthStencilView() failed: %08X", hr); + return {}; + } + } + + return std::unique_ptr<GPUFramebuffer>(new D3D11Framebuffer(std::move(rtv), std::move(dsv))); +} + +D3D11Sampler::D3D11Sampler(ComPtr<ID3D11SamplerState> ss) : m_ss(std::move(ss)) {} + +D3D11Sampler::~D3D11Sampler() = default; + +void D3D11Sampler::SetDebugName(const std::string_view& name) +{ + Panic("Not implemented"); +} + +std::unique_ptr<GPUSampler> D3D11Device::CreateSampler(const GPUSampler::Config& config) +{ + static constexpr std::array<D3D11_TEXTURE_ADDRESS_MODE, static_cast<u8>(GPUSampler::AddressMode::MaxCount)> ta = {{ + D3D11_TEXTURE_ADDRESS_WRAP, // Repeat + D3D11_TEXTURE_ADDRESS_CLAMP, // ClampToEdge + D3D11_TEXTURE_ADDRESS_BORDER, // ClampToBorder + }}; + + D3D11_SAMPLER_DESC desc = {}; + desc.AddressU = ta[static_cast<u8>(config.address_u.GetValue())]; + desc.AddressV = ta[static_cast<u8>(config.address_v.GetValue())]; + desc.AddressW = ta[static_cast<u8>(config.address_w.GetValue())]; + desc.BorderColor[0] = static_cast<float>(config.border_color & 0xFF) / 255.0f; + desc.BorderColor[1] = static_cast<float>((config.border_color >> 8) & 0xFF) / 255.0f; + desc.BorderColor[2] = static_cast<float>((config.border_color >> 16) & 0xFF) / 255.0f; + desc.BorderColor[3] = static_cast<float>((config.border_color >> 24) & 0xFF) / 255.0f; + desc.MinLOD = static_cast<float>(config.min_lod); + desc.MaxLOD = static_cast<float>(config.max_lod); + + if (config.anisotropy > 0) + { + desc.Filter = D3D11_FILTER_ANISOTROPIC; + desc.MaxAnisotropy = config.anisotropy; + } + else + { + static constexpr u8 filter_count = static_cast<u8>(GPUSampler::Filter::MaxCount); + static constexpr D3D11_FILTER filters[filter_count][filter_count][filter_count] = { + { + {D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT}, + {D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT, D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT}, + }, + { + {D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR, D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR}, + {D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR, D3D11_FILTER_MIN_MAG_MIP_LINEAR}, + }}; + + desc.Filter = filters[static_cast<u8>(config.mip_filter.GetValue())][static_cast<u8>(config.min_filter.GetValue())] + [static_cast<u8>(config.mag_filter.GetValue())]; + desc.MaxAnisotropy = 1; + } + + // TODO: Pool? + ComPtr<ID3D11SamplerState> ss; + const HRESULT hr = m_device->CreateSamplerState(&desc, ss.GetAddressOf()); + if (FAILED(hr)) + { + Log_ErrorPrintf("CreateSamplerState() failed: %08X", hr); + return {}; + } + + return std::unique_ptr<GPUSampler>(new D3D11Sampler(std::move(ss))); +} + +D3D11Shader::D3D11Shader(Stage stage, Microsoft::WRL::ComPtr<ID3D11DeviceChild> shader, std::vector<u8> bytecode) + : GPUShader(stage), m_shader(std::move(shader)), m_bytecode(std::move(bytecode)) +{ +} + +D3D11Shader::~D3D11Shader() = default; + +ID3D11VertexShader* D3D11Shader::GetVertexShader() const +{ + DebugAssert(m_stage == Stage::Vertex); + return static_cast<ID3D11VertexShader*>(m_shader.Get()); +} + +ID3D11PixelShader* D3D11Shader::GetPixelShader() const +{ + DebugAssert(m_stage == Stage::Pixel); + return static_cast<ID3D11PixelShader*>(m_shader.Get()); +} + +ID3D11ComputeShader* D3D11Shader::GetComputeShader() const +{ + DebugAssert(m_stage == Stage::Compute); + return static_cast<ID3D11ComputeShader*>(m_shader.Get()); +} + +void D3D11Shader::SetDebugName(const std::string_view& name) +{ + Panic("Implement me"); +} + +std::unique_ptr<GPUShader> D3D11Device::CreateShaderFromBinary(GPUShader::Stage stage, gsl::span<const u8> data) +{ + ComPtr<ID3D11DeviceChild> shader; + std::vector<u8> bytecode; + switch (stage) + { + case GPUShader::Stage::Vertex: + shader = D3D11::ShaderCompiler::CreateVertexShader(D3D11Device::GetD3DDevice(), data.data(), data.size()); + bytecode.resize(data.size()); + std::memcpy(bytecode.data(), data.data(), data.size()); + break; + + case GPUShader::Stage::Pixel: + shader = D3D11::ShaderCompiler::CreatePixelShader(D3D11Device::GetD3DDevice(), data.data(), data.size()); + break; + + case GPUShader::Stage::Compute: + shader = D3D11::ShaderCompiler::CreateComputeShader(D3D11Device::GetD3DDevice(), data.data(), data.size()); + break; + + default: + UnreachableCode(); + break; + } + + if (!shader) + return {}; + + return std::unique_ptr<GPUShader>(new D3D11Shader(stage, std::move(shader), std::move(bytecode))); +} + +std::unique_ptr<GPUShader> D3D11Device::CreateShaderFromSource(GPUShader::Stage stage, const std::string_view& source, + std::vector<u8>* out_binary /* = nullptr */) +{ + // TODO: This shouldn't be dependent on build type. +#ifdef _DEBUG + constexpr bool debug = true; +#else + constexpr bool debug = false; +#endif + + ComPtr<ID3DBlob> blob; + switch (stage) + { + case GPUShader::Stage::Vertex: + blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Vertex, m_device->GetFeatureLevel(), + source, debug); + break; + + case GPUShader::Stage::Pixel: + blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Pixel, m_device->GetFeatureLevel(), + source, debug); + break; + + case GPUShader::Stage::Compute: + blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Compute, m_device->GetFeatureLevel(), + source, debug); + break; + + default: + UnreachableCode(); + break; + } + + if (out_binary) + { + const size_t size = blob->GetBufferSize(); + out_binary->resize(size); + std::memcpy(out_binary->data(), blob->GetBufferPointer(), size); + } + + return CreateShaderFromBinary( + stage, gsl::span<const u8>(static_cast<const u8*>(blob->GetBufferPointer()), blob->GetBufferSize())); +} + +D3D11Pipeline::D3D11Pipeline(ComPtr<ID3D11RasterizerState> rs, ComPtr<ID3D11DepthStencilState> ds, + ComPtr<ID3D11BlendState> bs, ComPtr<ID3D11InputLayout> il, ComPtr<ID3D11VertexShader> vs, + ComPtr<ID3D11PixelShader> ps, D3D11_PRIMITIVE_TOPOLOGY topology) + : m_rs(std::move(rs)), m_ds(std::move(ds)), m_bs(std::move(bs)), m_il(std::move(il)), m_vs(std::move(vs)), + m_ps(std::move(ps)), m_topology(topology) +{ +} + +D3D11Pipeline::~D3D11Pipeline() = default; + +void D3D11Pipeline::SetDebugName(const std::string_view& name) +{ + UnreachableCode(); +} + +void D3D11Pipeline::Bind(ID3D11DeviceContext* context) +{ + context->IASetInputLayout(GetInputLayout()); + context->IASetPrimitiveTopology(GetPrimitiveTopology()); + context->RSSetState(GetRasterizerState()); + context->OMSetDepthStencilState(GetDepthStencilState(), 0); + context->OMSetBlendState(GetBlendState(), nullptr, 0xFFFFFFFFu); + context->VSSetShader(GetVertexShader(), nullptr, 0); + context->PSSetShader(GetPixelShader(), nullptr, 0); +} + +D3D11Device::ComPtr<ID3D11RasterizerState> D3D11Device::GetRasterizationState(const GPUPipeline::RasterizationState& rs) +{ + ComPtr<ID3D11RasterizerState> drs; + + const auto it = m_rasterization_states.find(rs.key); + if (it != m_rasterization_states.end()) + { + drs = it->second; + return drs; + } + + static constexpr std::array<D3D11_CULL_MODE, static_cast<u32>(GPUPipeline::CullMode::MaxCount)> cull_mapping = {{ + D3D11_CULL_NONE, // None + D3D11_CULL_FRONT, // Front + D3D11_CULL_BACK, // Back + }}; + + D3D11_RASTERIZER_DESC desc = {}; + desc.FillMode = D3D11_FILL_SOLID; + desc.CullMode = cull_mapping[static_cast<u8>(rs.cull_mode.GetValue())]; + desc.ScissorEnable = TRUE; + // desc.MultisampleEnable ??? + + HRESULT hr = m_device->CreateRasterizerState(&desc, drs.GetAddressOf()); + if (FAILED(hr)) + Log_ErrorPrintf("Failed to create depth state with %08X", hr); + + m_rasterization_states.emplace(rs.key, drs); + return drs; +} + +D3D11Device::ComPtr<ID3D11DepthStencilState> D3D11Device::GetDepthState(const GPUPipeline::DepthState& ds) +{ + ComPtr<ID3D11DepthStencilState> dds; + + const auto it = m_depth_states.find(ds.key); + if (it != m_depth_states.end()) + { + dds = it->second; + return dds; + } + + static constexpr std::array<D3D11_COMPARISON_FUNC, static_cast<u32>(GPUPipeline::DepthFunc::MaxCount)> func_mapping = + {{ + D3D11_COMPARISON_NEVER, // Never + D3D11_COMPARISON_ALWAYS, // Always + D3D11_COMPARISON_LESS, // Less + D3D11_COMPARISON_LESS_EQUAL, // LessEqual + D3D11_COMPARISON_GREATER, // Greater + D3D11_COMPARISON_GREATER_EQUAL, // GreaterEqual + D3D11_COMPARISON_EQUAL, // Equal + }}; + + D3D11_DEPTH_STENCIL_DESC desc = {}; + desc.DepthEnable = ds.depth_test != GPUPipeline::DepthFunc::Never; + desc.DepthFunc = func_mapping[static_cast<u8>(ds.depth_test.GetValue())]; + desc.DepthWriteMask = ds.depth_write ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + + HRESULT hr = m_device->CreateDepthStencilState(&desc, dds.GetAddressOf()); + if (FAILED(hr)) + Log_ErrorPrintf("Failed to create depth state with %08X", hr); + + m_depth_states.emplace(ds.key, dds); + return dds; +} + +D3D11Device::ComPtr<ID3D11BlendState> D3D11Device::GetBlendState(const GPUPipeline::BlendState& bs) +{ + ComPtr<ID3D11BlendState> dbs; + + const auto it = m_blend_states.find(bs.key); + if (it != m_blend_states.end()) + { + dbs = it->second; + return dbs; + } + + static constexpr std::array<D3D11_BLEND, static_cast<u32>(GPUPipeline::BlendFunc::MaxCount)> blend_mapping = {{ + D3D11_BLEND_ZERO, // Zero + D3D11_BLEND_ONE, // One + D3D11_BLEND_SRC_COLOR, // SrcColor + D3D11_BLEND_INV_SRC_COLOR, // InvSrcColor + D3D11_BLEND_DEST_COLOR, // DstColor + D3D11_BLEND_INV_DEST_COLOR, // InvDstColor + D3D11_BLEND_SRC_ALPHA, // SrcAlpha + D3D11_BLEND_INV_SRC_ALPHA, // InvSrcAlpha + D3D11_BLEND_SRC1_ALPHA, // SrcAlpha1 + D3D11_BLEND_INV_SRC1_ALPHA, // InvSrcAlpha1 + D3D11_BLEND_DEST_ALPHA, // DstAlpha + D3D11_BLEND_INV_DEST_ALPHA, // InvDstAlpha + }}; + + static constexpr std::array<D3D11_BLEND_OP, static_cast<u32>(GPUPipeline::BlendOp::MaxCount)> op_mapping = {{ + D3D11_BLEND_OP_ADD, // Add + D3D11_BLEND_OP_SUBTRACT, // Subtract + D3D11_BLEND_OP_REV_SUBTRACT, // ReverseSubtract + D3D11_BLEND_OP_MIN, // Min + D3D11_BLEND_OP_MAX, // Max + }}; + + D3D11_BLEND_DESC blend_desc = {}; + D3D11_RENDER_TARGET_BLEND_DESC& tgt_desc = blend_desc.RenderTarget[0]; + tgt_desc.BlendEnable = bs.enable; + tgt_desc.RenderTargetWriteMask = bs.write_mask; + if (bs.enable) + { + tgt_desc.SrcBlend = blend_mapping[static_cast<u8>(bs.src_blend.GetValue())]; + tgt_desc.DestBlend = blend_mapping[static_cast<u8>(bs.dst_blend.GetValue())]; + tgt_desc.BlendOp = op_mapping[static_cast<u8>(bs.blend_op.GetValue())]; + tgt_desc.SrcBlendAlpha = blend_mapping[static_cast<u8>(bs.src_alpha_blend.GetValue())]; + tgt_desc.DestBlendAlpha = blend_mapping[static_cast<u8>(bs.dst_alpha_blend.GetValue())]; + tgt_desc.BlendOpAlpha = op_mapping[static_cast<u8>(bs.alpha_blend_op.GetValue())]; + } + + HRESULT hr = m_device->CreateBlendState(&blend_desc, dbs.GetAddressOf()); + if (FAILED(hr)) + Log_ErrorPrintf("Failed to create blend state with %08X", hr); + + m_blend_states.emplace(bs.key, dbs); + return dbs; +} + +D3D11Device::ComPtr<ID3D11InputLayout> D3D11Device::GetInputLayout(const GPUPipeline::InputLayout& il, + const D3D11Shader* vs) +{ + ComPtr<ID3D11InputLayout> dil; + const auto it = m_input_layouts.find(il); + if (it != m_input_layouts.end()) + { + dil = it->second; + return dil; + } + + static constexpr std::array<const char*, static_cast<u32>(GPUPipeline::VertexAttribute::Semantic::MaxCount)> + semantics = {{ + "POSITION", // Position + "TEXCOORD", // Texcoord + "COLOR", // Color + }}; + + static constexpr u32 MAX_COMPONENTS = 4; + static constexpr const DXGI_FORMAT + format_mapping[static_cast<u8>(GPUPipeline::VertexAttribute::Type::MaxCount)][MAX_COMPONENTS] = { + {DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT, + DXGI_FORMAT_R32G32B32A32_FLOAT}, // Float + {DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UINT}, // UInt8 + {DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_SINT}, // SInt8 + {DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM}, // UNorm8 + {DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R16G16B16A16_UINT}, // UInt16 + {DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R16G16B16A16_SINT}, // SInt16 + {DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R16G16B16A16_UNORM}, // UNorm16 + {DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32A32_UINT}, // UInt32 + {DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32A32_SINT}, // SInt32 + }; + + D3D11_INPUT_ELEMENT_DESC* elems = + static_cast<D3D11_INPUT_ELEMENT_DESC*>(alloca(sizeof(D3D11_INPUT_ELEMENT_DESC) * il.vertex_attributes.size())); + for (size_t i = 0; i < il.vertex_attributes.size(); i++) + { + const GPUPipeline::VertexAttribute& va = il.vertex_attributes[i]; + Assert(va.components > 0 && va.components < MAX_COMPONENTS); + + D3D11_INPUT_ELEMENT_DESC& elem = elems[i]; + elem.SemanticName = semantics[static_cast<u8>(va.semantic.GetValue())]; + elem.SemanticIndex = va.semantic_index; + elem.Format = format_mapping[static_cast<u8>(va.type.GetValue())][va.components - 1]; + elem.InputSlot = 0; + elem.AlignedByteOffset = va.offset; + elem.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + elem.InstanceDataStepRate = 0; + } + + HRESULT hr = m_device->CreateInputLayout(elems, static_cast<UINT>(il.vertex_attributes.size()), + vs->GetBytecode().data(), vs->GetBytecode().size(), dil.GetAddressOf()); + if (FAILED(hr)) + Log_ErrorPrintf("Failed to create input layout with %08X", hr); + + m_input_layouts.emplace(il, dil); + return dil; +} + +std::unique_ptr<GPUPipeline> D3D11Device::CreatePipeline(const GPUPipeline::GraphicsConfig& config) +{ + ComPtr<ID3D11RasterizerState> rs = GetRasterizationState(config.rasterization); + ComPtr<ID3D11DepthStencilState> ds = GetDepthState(config.depth); + ComPtr<ID3D11BlendState> bs = GetBlendState(config.blend); + + static constexpr std::array<D3D11_PRIMITIVE_TOPOLOGY, static_cast<u32>(GPUPipeline::Primitive::MaxCount)> primitives = + {{ + D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, // Points + D3D11_PRIMITIVE_TOPOLOGY_LINELIST, // Lines + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // Triangles + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, // TriangleStrips + }}; + + return std::unique_ptr<GPUPipeline>( + new D3D11Pipeline(std::move(rs), std::move(ds), std::move(bs), nullptr, + static_cast<const D3D11Shader*>(config.vertex_shader)->GetVertexShader(), + static_cast<const D3D11Shader*>(config.pixel_shader)->GetPixelShader(), + primitives[static_cast<u8>(config.primitive)])); +} diff --git a/src/core/gpu/d3d11_device.h b/src/core/gpu/d3d11_device.h index c6bb1b8aa..63de54a52 100644 --- a/src/core/gpu/d3d11_device.h +++ b/src/core/gpu/d3d11_device.h @@ -8,7 +8,6 @@ #include "d3d11/stream_buffer.h" #include "d3d11_texture.h" #include "gpu_device.h" -#include "gpu_pipeline.h" #include "postprocessing_chain.h" #include <d3d11.h> #include <dxgi.h> @@ -19,8 +18,107 @@ #include <vector> #include <wrl/client.h> -class D3D11Pipeline; -class D3D11Shader; +class D3D11Device; + +class D3D11Framebuffer final : public GPUFramebuffer +{ + friend D3D11Device; + + template<typename T> + using ComPtr = Microsoft::WRL::ComPtr<T>; + +public: + ~D3D11Framebuffer() override; + + ALWAYS_INLINE ID3D11RenderTargetView* GetRTV() const { return m_rtv.Get(); } + ALWAYS_INLINE ID3D11DepthStencilView* GetDSV() const { return m_dsv.Get(); } + + void SetDebugName(const std::string_view& name) override; + +private: + D3D11Framebuffer(ComPtr<ID3D11RenderTargetView> rtv, ComPtr<ID3D11DepthStencilView> dsv); + + ComPtr<ID3D11RenderTargetView> m_rtv; + ComPtr<ID3D11DepthStencilView> m_dsv; +}; + +class D3D11Sampler final : public GPUSampler +{ + friend D3D11Device; + + template<typename T> + using ComPtr = Microsoft::WRL::ComPtr<T>; + +public: + ~D3D11Sampler() override; + + ALWAYS_INLINE ID3D11SamplerState* GetSamplerState() const { return m_ss.Get(); } + + void SetDebugName(const std::string_view& name) override; + +private: + D3D11Sampler(ComPtr<ID3D11SamplerState> ss); + + ComPtr<ID3D11SamplerState> m_ss; +}; + +class D3D11Shader final : public GPUShader +{ + friend D3D11Device; + +public: + ~D3D11Shader() override; + + ID3D11VertexShader* GetVertexShader() const; + ID3D11PixelShader* GetPixelShader() const; + ID3D11ComputeShader* GetComputeShader() const; + + ALWAYS_INLINE const std::vector<u8>& GetBytecode() const { return m_bytecode; } + + void SetDebugName(const std::string_view& name) override; + +private: + D3D11Shader(Stage stage, Microsoft::WRL::ComPtr<ID3D11DeviceChild> shader, std::vector<u8> bytecode); + + Microsoft::WRL::ComPtr<ID3D11DeviceChild> m_shader; + std::vector<u8> m_bytecode; // only for VS +}; + +class D3D11Pipeline final : public GPUPipeline +{ + friend D3D11Device; + + template<typename T> + using ComPtr = Microsoft::WRL::ComPtr<T>; + +public: + ~D3D11Pipeline() override; + + void SetDebugName(const std::string_view& name) override; + + ALWAYS_INLINE ID3D11RasterizerState* GetRasterizerState() const { return m_rs.Get(); } + ALWAYS_INLINE ID3D11DepthStencilState* GetDepthStencilState() const { return m_ds.Get(); } + ALWAYS_INLINE ID3D11BlendState* GetBlendState() const { return m_bs.Get(); } + ALWAYS_INLINE ID3D11InputLayout* GetInputLayout() const { return m_il.Get(); } + ALWAYS_INLINE ID3D11VertexShader* GetVertexShader() const { return m_vs.Get(); } + ALWAYS_INLINE ID3D11PixelShader* GetPixelShader() const { return m_ps.Get(); } + ALWAYS_INLINE D3D11_PRIMITIVE_TOPOLOGY GetPrimitiveTopology() const { return m_topology; } + + void Bind(ID3D11DeviceContext* context); + +private: + D3D11Pipeline(ComPtr<ID3D11RasterizerState> rs, ComPtr<ID3D11DepthStencilState> ds, ComPtr<ID3D11BlendState> bs, + ComPtr<ID3D11InputLayout> il, ComPtr<ID3D11VertexShader> vs, ComPtr<ID3D11PixelShader> ps, + D3D11_PRIMITIVE_TOPOLOGY topology); + + ComPtr<ID3D11RasterizerState> m_rs; + ComPtr<ID3D11DepthStencilState> m_ds; + ComPtr<ID3D11BlendState> m_bs; + ComPtr<ID3D11InputLayout> m_il; + ComPtr<ID3D11VertexShader> m_vs; + ComPtr<ID3D11PixelShader> m_ps; + D3D11_PRIMITIVE_TOPOLOGY m_topology; +}; class D3D11Device final : public GPUDevice { @@ -62,6 +160,8 @@ public: GPUTexture::Type type, GPUTexture::Format format, const void* data = nullptr, u32 data_stride = 0, bool dynamic = false) override; + std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config) override; + bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data, u32 out_data_stride) override; bool SupportsTextureFormat(GPUTexture::Format format) const override; @@ -70,6 +170,9 @@ public: void ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src, u32 src_x, u32 src_y, u32 src_layer, u32 src_level, u32 width, u32 height) override; + std::unique_ptr<GPUFramebuffer> CreateFramebuffer(GPUTexture* rt, u32 rt_layer, u32 rt_level, GPUTexture* ds, + u32 ds_layer, u32 ds_level) override; + std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShader::Stage stage, gsl::span<const u8> data) override; std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShader::Stage stage, const std::string_view& source, std::vector<u8>* out_binary = nullptr) override; @@ -92,7 +195,8 @@ private: using RasterizationStateMap = std::unordered_map<u8, ComPtr<ID3D11RasterizerState>>; using DepthStateMap = std::unordered_map<u8, ComPtr<ID3D11DepthStencilState>>; using BlendStateMap = std::unordered_map<u32, ComPtr<ID3D11BlendState>>; - using InputLayoutMap = std::unordered_map<GPUPipeline::InputLayout, ComPtr<ID3D11InputLayout>, GPUPipeline::InputLayoutHash>; + using InputLayoutMap = + std::unordered_map<GPUPipeline::InputLayout, ComPtr<ID3D11InputLayout>, GPUPipeline::InputLayoutHash>; static constexpr u32 DISPLAY_UNIFORM_BUFFER_SIZE = 64; static constexpr u32 IMGUI_VERTEX_BUFFER_SIZE = 4 * 1024 * 1024; diff --git a/src/core/gpu/d3d11_pipeline.cpp b/src/core/gpu/d3d11_pipeline.cpp deleted file mode 100644 index dade73170..000000000 --- a/src/core/gpu/d3d11_pipeline.cpp +++ /dev/null @@ -1,242 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com> -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#include "d3d11_pipeline.h" -#include "d3d11_device.h" -#include "d3d11_shader.h" - -#include "common/assert.h" -#include "common/log.h" - -#include <array> -#include <malloc.h> - -Log_SetChannel(D3D11Device); - -D3D11Pipeline::D3D11Pipeline(ComPtr<ID3D11RasterizerState> rs, ComPtr<ID3D11DepthStencilState> ds, - ComPtr<ID3D11BlendState> bs, ComPtr<ID3D11InputLayout> il, ComPtr<ID3D11VertexShader> vs, - ComPtr<ID3D11PixelShader> ps, D3D11_PRIMITIVE_TOPOLOGY topology) - : m_rs(std::move(rs)), m_ds(std::move(ds)), m_bs(std::move(bs)), m_il(std::move(il)), m_vs(std::move(vs)), - m_ps(std::move(ps)), m_topology(topology) -{ -} - -D3D11Pipeline::~D3D11Pipeline() = default; - -void D3D11Pipeline::SetDebugName(const std::string_view& name) -{ - UnreachableCode(); -} - -void D3D11Pipeline::Bind(ID3D11DeviceContext* context) -{ - context->IASetInputLayout(GetInputLayout()); - context->IASetPrimitiveTopology(GetPrimitiveTopology()); - context->RSSetState(GetRasterizerState()); - context->OMSetDepthStencilState(GetDepthStencilState(), 0); - context->OMSetBlendState(GetBlendState(), nullptr, 0xFFFFFFFFu); - context->VSSetShader(GetVertexShader(), nullptr, 0); - context->PSSetShader(GetPixelShader(), nullptr, 0); -} - -D3D11Device::ComPtr<ID3D11RasterizerState> D3D11Device::GetRasterizationState(const GPUPipeline::RasterizationState& rs) -{ - ComPtr<ID3D11RasterizerState> drs; - - const auto it = m_rasterization_states.find(rs.key); - if (it != m_rasterization_states.end()) - { - drs = it->second; - return drs; - } - - static constexpr std::array<D3D11_CULL_MODE, static_cast<u32>(GPUPipeline::CullMode::MaxCount)> cull_mapping = {{ - D3D11_CULL_NONE, // None - D3D11_CULL_FRONT, // Front - D3D11_CULL_BACK, // Back - }}; - - D3D11_RASTERIZER_DESC desc = {}; - desc.FillMode = D3D11_FILL_SOLID; - desc.CullMode = cull_mapping[static_cast<u8>(rs.cull_mode.GetValue())]; - desc.ScissorEnable = TRUE; - // desc.MultisampleEnable ??? - - HRESULT hr = m_device->CreateRasterizerState(&desc, drs.GetAddressOf()); - if (FAILED(hr)) - Log_ErrorPrintf("Failed to create depth state with %08X", hr); - - m_rasterization_states.emplace(rs.key, drs); - return drs; -} - -D3D11Device::ComPtr<ID3D11DepthStencilState> D3D11Device::GetDepthState(const GPUPipeline::DepthState& ds) -{ - ComPtr<ID3D11DepthStencilState> dds; - - const auto it = m_depth_states.find(ds.key); - if (it != m_depth_states.end()) - { - dds = it->second; - return dds; - } - - static constexpr std::array<D3D11_COMPARISON_FUNC, static_cast<u32>(GPUPipeline::DepthFunc::MaxCount)> func_mapping = - {{ - D3D11_COMPARISON_NEVER, // Never - D3D11_COMPARISON_ALWAYS, // Always - D3D11_COMPARISON_LESS, // Less - D3D11_COMPARISON_LESS_EQUAL, // LessEqual - D3D11_COMPARISON_GREATER, // Greater - D3D11_COMPARISON_GREATER_EQUAL, // GreaterEqual - D3D11_COMPARISON_EQUAL, // Equal - }}; - - D3D11_DEPTH_STENCIL_DESC desc = {}; - desc.DepthEnable = ds.depth_test != GPUPipeline::DepthFunc::Never; - desc.DepthFunc = func_mapping[static_cast<u8>(ds.depth_test.GetValue())]; - desc.DepthWriteMask = ds.depth_write ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; - - HRESULT hr = m_device->CreateDepthStencilState(&desc, dds.GetAddressOf()); - if (FAILED(hr)) - Log_ErrorPrintf("Failed to create depth state with %08X", hr); - - m_depth_states.emplace(ds.key, dds); - return dds; -} - -D3D11Device::ComPtr<ID3D11BlendState> D3D11Device::GetBlendState(const GPUPipeline::BlendState& bs) -{ - ComPtr<ID3D11BlendState> dbs; - - const auto it = m_blend_states.find(bs.key); - if (it != m_blend_states.end()) - { - dbs = it->second; - return dbs; - } - - static constexpr std::array<D3D11_BLEND, static_cast<u32>(GPUPipeline::BlendFunc::MaxCount)> blend_mapping = {{ - D3D11_BLEND_ZERO, // Zero - D3D11_BLEND_ONE, // One - D3D11_BLEND_SRC_COLOR, // SrcColor - D3D11_BLEND_INV_SRC_COLOR, // InvSrcColor - D3D11_BLEND_DEST_COLOR, // DstColor - D3D11_BLEND_INV_DEST_COLOR, // InvDstColor - D3D11_BLEND_SRC_ALPHA, // SrcAlpha - D3D11_BLEND_INV_SRC_ALPHA, // InvSrcAlpha - D3D11_BLEND_SRC1_ALPHA, // SrcAlpha1 - D3D11_BLEND_INV_SRC1_ALPHA, // InvSrcAlpha1 - D3D11_BLEND_DEST_ALPHA, // DstAlpha - D3D11_BLEND_INV_DEST_ALPHA, // InvDstAlpha - }}; - - static constexpr std::array<D3D11_BLEND_OP, static_cast<u32>(GPUPipeline::BlendOp::MaxCount)> op_mapping = {{ - D3D11_BLEND_OP_ADD, // Add - D3D11_BLEND_OP_SUBTRACT, // Subtract - D3D11_BLEND_OP_REV_SUBTRACT, // ReverseSubtract - D3D11_BLEND_OP_MIN, // Min - D3D11_BLEND_OP_MAX, // Max - }}; - - D3D11_BLEND_DESC blend_desc = {}; - D3D11_RENDER_TARGET_BLEND_DESC& tgt_desc = blend_desc.RenderTarget[0]; - tgt_desc.BlendEnable = bs.enable; - tgt_desc.RenderTargetWriteMask = bs.write_mask; - if (bs.enable) - { - tgt_desc.SrcBlend = blend_mapping[static_cast<u8>(bs.src_blend.GetValue())]; - tgt_desc.DestBlend = blend_mapping[static_cast<u8>(bs.dst_blend.GetValue())]; - tgt_desc.BlendOp = op_mapping[static_cast<u8>(bs.blend_op.GetValue())]; - tgt_desc.SrcBlendAlpha = blend_mapping[static_cast<u8>(bs.src_alpha_blend.GetValue())]; - tgt_desc.DestBlendAlpha = blend_mapping[static_cast<u8>(bs.dst_alpha_blend.GetValue())]; - tgt_desc.BlendOpAlpha = op_mapping[static_cast<u8>(bs.alpha_blend_op.GetValue())]; - } - - HRESULT hr = m_device->CreateBlendState(&blend_desc, dbs.GetAddressOf()); - if (FAILED(hr)) - Log_ErrorPrintf("Failed to create blend state with %08X", hr); - - m_blend_states.emplace(bs.key, dbs); - return dbs; -} - -D3D11Device::ComPtr<ID3D11InputLayout> D3D11Device::GetInputLayout(const GPUPipeline::InputLayout& il, - const D3D11Shader* vs) -{ - ComPtr<ID3D11InputLayout> dil; - const auto it = m_input_layouts.find(il); - if (it != m_input_layouts.end()) - { - dil = it->second; - return dil; - } - - static constexpr std::array<const char*, static_cast<u32>(GPUPipeline::VertexAttribute::Semantic::MaxCount)> - semantics = {{ - "POSITION", // Position - "TEXCOORD", // Texcoord - "COLOR", // Color - }}; - - static constexpr u32 MAX_COMPONENTS = 4; - static constexpr const DXGI_FORMAT - format_mapping[static_cast<u8>(GPUPipeline::VertexAttribute::Type::MaxCount)][MAX_COMPONENTS] = { - {DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT, - DXGI_FORMAT_R32G32B32A32_FLOAT}, // Float - {DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UINT}, // UInt8 - {DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_SINT}, // SInt8 - {DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM}, // UNorm8 - {DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R16G16B16A16_UINT}, // UInt16 - {DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R16G16B16A16_SINT}, // SInt16 - {DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R16G16B16A16_UNORM}, // UNorm16 - {DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32A32_UINT}, // UInt32 - {DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32A32_SINT}, // SInt32 - }; - - D3D11_INPUT_ELEMENT_DESC* elems = - static_cast<D3D11_INPUT_ELEMENT_DESC*>(alloca(sizeof(D3D11_INPUT_ELEMENT_DESC) * il.vertex_attributes.size())); - for (size_t i = 0; i < il.vertex_attributes.size(); i++) - { - const GPUPipeline::VertexAttribute& va = il.vertex_attributes[i]; - Assert(va.components > 0 && va.components < MAX_COMPONENTS); - - D3D11_INPUT_ELEMENT_DESC& elem = elems[i]; - elem.SemanticName = semantics[static_cast<u8>(va.semantic.GetValue())]; - elem.SemanticIndex = va.semantic_index; - elem.Format = format_mapping[static_cast<u8>(va.type.GetValue())][va.components - 1]; - elem.InputSlot = 0; - elem.AlignedByteOffset = va.offset; - elem.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - elem.InstanceDataStepRate = 0; - } - - HRESULT hr = m_device->CreateInputLayout(elems, static_cast<UINT>(il.vertex_attributes.size()), - vs->GetBytecode().data(), vs->GetBytecode().size(), dil.GetAddressOf()); - if (FAILED(hr)) - Log_ErrorPrintf("Failed to create input layout with %08X", hr); - - m_input_layouts.emplace(il, dil); - return dil; -} - -std::unique_ptr<GPUPipeline> D3D11Device::CreatePipeline(const GPUPipeline::GraphicsConfig& config) -{ - ComPtr<ID3D11RasterizerState> rs = GetRasterizationState(config.rasterization); - ComPtr<ID3D11DepthStencilState> ds = GetDepthState(config.depth); - ComPtr<ID3D11BlendState> bs = GetBlendState(config.blend); - - static constexpr std::array<D3D11_PRIMITIVE_TOPOLOGY, static_cast<u32>(GPUPipeline::Primitive::MaxCount)> primitives = - {{ - D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, // Points - D3D11_PRIMITIVE_TOPOLOGY_LINELIST, // Lines - D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // Triangles - D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, // TriangleStrips - }}; - - return std::unique_ptr<GPUPipeline>( - new D3D11Pipeline(std::move(rs), std::move(ds), std::move(bs), nullptr, - static_cast<const D3D11Shader*>(config.vertex_shader)->GetD3DVertexShader(), - static_cast<const D3D11Shader*>(config.pixel_shader)->GetD3DPixelShader(), - primitives[static_cast<u8>(config.primitive)])); -} diff --git a/src/core/gpu/d3d11_pipeline.h b/src/core/gpu/d3d11_pipeline.h deleted file mode 100644 index fbffc8e68..000000000 --- a/src/core/gpu/d3d11_pipeline.h +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com> -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#pragma once - -#include "gpu_pipeline.h" - -#include "common/windows_headers.h" - -#include <memory> - -#include <d3d11.h> -#include <wrl/client.h> - -#include "gsl/span" - -class D3D11Device; - -class D3D11Pipeline final : public GPUPipeline -{ - friend D3D11Device; - - template<typename T> - using ComPtr = Microsoft::WRL::ComPtr<T>; - -public: - ~D3D11Pipeline() override; - - void SetDebugName(const std::string_view& name) override; - - ALWAYS_INLINE ID3D11RasterizerState* GetRasterizerState() const { return m_rs.Get(); } - ALWAYS_INLINE ID3D11DepthStencilState* GetDepthStencilState() const { return m_ds.Get(); } - ALWAYS_INLINE ID3D11BlendState* GetBlendState() const { return m_bs.Get(); } - ALWAYS_INLINE ID3D11InputLayout* GetInputLayout() const { return m_il.Get(); } - ALWAYS_INLINE ID3D11VertexShader* GetVertexShader() const { return m_vs.Get(); } - ALWAYS_INLINE ID3D11PixelShader* GetPixelShader() const { return m_ps.Get(); } - ALWAYS_INLINE D3D11_PRIMITIVE_TOPOLOGY GetPrimitiveTopology() const { return m_topology; } - - void Bind(ID3D11DeviceContext* context); - -private: - D3D11Pipeline(ComPtr<ID3D11RasterizerState> rs, ComPtr<ID3D11DepthStencilState> ds, ComPtr<ID3D11BlendState> bs, - ComPtr<ID3D11InputLayout> il, ComPtr<ID3D11VertexShader> vs, ComPtr<ID3D11PixelShader> ps, - D3D11_PRIMITIVE_TOPOLOGY topology); - - ComPtr<ID3D11RasterizerState> m_rs; - ComPtr<ID3D11DepthStencilState> m_ds; - ComPtr<ID3D11BlendState> m_bs; - ComPtr<ID3D11InputLayout> m_il; - ComPtr<ID3D11VertexShader> m_vs; - ComPtr<ID3D11PixelShader> m_ps; - D3D11_PRIMITIVE_TOPOLOGY m_topology; -}; diff --git a/src/core/gpu/d3d11_shader.cpp b/src/core/gpu/d3d11_shader.cpp deleted file mode 100644 index cc124678b..000000000 --- a/src/core/gpu/d3d11_shader.cpp +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com> -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#include "d3d11_shader.h" -#include "d3d11/shader_compiler.h" -#include "d3d11_device.h" - -#include "common/assert.h" - -D3D11Shader::D3D11Shader(Stage stage, Microsoft::WRL::ComPtr<ID3D11DeviceChild> shader) - : GPUShader(stage), m_shader(std::move(shader)) -{ -} - -D3D11Shader::~D3D11Shader() = default; - -ID3D11VertexShader* D3D11Shader::GetD3DVertexShader() const -{ - DebugAssert(m_stage == Stage::Vertex); - return static_cast<ID3D11VertexShader*>(m_shader.Get()); -} - -ID3D11PixelShader* D3D11Shader::GetD3DPixelShader() const -{ - DebugAssert(m_stage == Stage::Pixel); - return static_cast<ID3D11PixelShader*>(m_shader.Get()); -} - -ID3D11ComputeShader* D3D11Shader::GetD3DComputeShader() const -{ - DebugAssert(m_stage == Stage::Compute); - return static_cast<ID3D11ComputeShader*>(m_shader.Get()); -} - -void D3D11Shader::SetDebugName(const std::string_view& name) -{ - Panic("Implement me"); -} - -std::unique_ptr<GPUShader> D3D11Device::CreateShaderFromBinary(GPUShader::Stage stage, gsl::span<const u8> data) -{ - ComPtr<ID3D11DeviceChild> shader; - std::vector<u8> bytecode; - switch (stage) - { - case GPUShader::Stage::Vertex: - shader = D3D11::ShaderCompiler::CreateVertexShader(D3D11Device::GetD3DDevice(), data.data(), data.size()); - bytecode.resize(data.size()); - std::memcpy(bytecode.data(), data.data(), data.size()); - break; - - case GPUShader::Stage::Pixel: - shader = D3D11::ShaderCompiler::CreatePixelShader(D3D11Device::GetD3DDevice(), data.data(), data.size()); - break; - - case GPUShader::Stage::Compute: - shader = D3D11::ShaderCompiler::CreateComputeShader(D3D11Device::GetD3DDevice(), data.data(), data.size()); - break; - - default: - UnreachableCode(); - break; - } - - if (!shader) - return {}; - - return std::unique_ptr<GPUShader>(new D3D11Shader(stage, std::move(shader), std::move(bytecode))); -} - -std::unique_ptr<GPUShader> D3D11Device::CreateShaderFromSource(GPUShader::Stage stage, const std::string_view& source, - std::vector<u8>* out_binary /* = nullptr */) -{ - // TODO: This shouldn't be dependent on build type. -#ifdef _DEBUG - constexpr bool debug = true; -#else - constexpr bool debug = false; -#endif - - ComPtr<ID3DBlob> blob; - switch (stage) - { - case GPUShader::Stage::Vertex: - blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Vertex, m_device->GetFeatureLevel(), - source, debug); - break; - - case GPUShader::Stage::Pixel: - blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Pixel, m_device->GetFeatureLevel(), - source, debug); - break; - - case GPUShader::Stage::Compute: - blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Compute, m_device->GetFeatureLevel(), - source, debug); - break; - - default: - UnreachableCode(); - break; - } - - if (out_binary) - { - const size_t size = blob->GetBufferSize(); - out_binary->resize(size); - std::memcpy(out_binary->data(), blob->GetBufferPointer(), size); - } - - return CreateShaderFromBinary( - stage, gsl::span<const u8>(static_cast<const u8*>(blob->GetBufferPointer()), blob->GetBufferSize())); -} diff --git a/src/core/gpu/d3d11_shader.h b/src/core/gpu/d3d11_shader.h deleted file mode 100644 index e37406a69..000000000 --- a/src/core/gpu/d3d11_shader.h +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com> -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#pragma once - -#include "gpu_shader.h" - -#include "common/windows_headers.h" - -#include <memory> -#include <vector> - -#include <d3d11.h> -#include <wrl/client.h> - -#include "gsl/span" - -class D3D11Device; - -class D3D11Shader final : public GPUShader -{ - friend D3D11Device; - -public: - ~D3D11Shader() override; - - ID3D11VertexShader* GetD3DVertexShader() const; - ID3D11PixelShader* GetD3DPixelShader() const; - ID3D11ComputeShader* GetD3DComputeShader() const; - - ALWAYS_INLINE const std::vector<u8>& GetBytecode() const { return m_bytecode; } - - void SetDebugName(const std::string_view& name) override; - -private: - D3D11Shader(Stage stage, Microsoft::WRL::ComPtr<ID3D11DeviceChild> shader, std::vector<u8> bytecode); - - Microsoft::WRL::ComPtr<ID3D11DeviceChild> m_shader; - std::vector<u8> m_bytecode; // only for VS -}; diff --git a/src/core/gpu/gpu_device.cpp b/src/core/gpu/gpu_device.cpp index d3894b6f2..fb0e69627 100644 --- a/src/core/gpu/gpu_device.cpp +++ b/src/core/gpu/gpu_device.cpp @@ -21,6 +21,10 @@ #include <vector> Log_SetChannel(GPUDevice); +// FIXME +#include "common/windows_headers.h" +#include "d3d_shaders.h" + std::unique_ptr<GPUDevice> g_host_display; size_t GPUPipeline::InputLayoutHash::operator()(const InputLayout& il) const @@ -103,12 +107,182 @@ RenderAPI GPUDevice::GetPreferredAPI() #endif } +bool GPUDevice::CreateResources() +{ + GPUSampler::Config config = {}; + config.address_u = GPUSampler::AddressMode::ClampToEdge; + config.address_v = GPUSampler::AddressMode::ClampToEdge; + config.address_w = GPUSampler::AddressMode::ClampToEdge; + config.min_filter = GPUSampler::Filter::Nearest; + config.mag_filter = GPUSampler::Filter::Nearest; + if (!(m_point_sampler = CreateSampler(config))) + return false; + + config.min_filter = GPUSampler::Filter::Linear; + config.mag_filter = GPUSampler::Filter::Linear; + if (!(m_linear_sampler = CreateSampler(config))) + return false; + + if (!CreateImGuiResources()) + return false; + + return true; +} + void GPUDevice::DestroyResources() { + DestroyImGuiResources(); + m_cursor_texture.reset(); + m_linear_sampler.reset(); + m_point_sampler.reset(); +} + +bool GPUDevice::CreateImGuiResources() +{ + std::unique_ptr<GPUShader> imgui_vs = CreateShaderFromBinary(GPUShader::Stage::Vertex, s_imgui_vs_bytecode); + std::unique_ptr<GPUShader> imgui_ps = CreateShaderFromBinary(GPUShader::Stage::Pixel, s_imgui_ps_bytecode); + if (!imgui_vs || !imgui_ps) + { + Log_ErrorPrintf("Failed to create ImGui shaders."); + return false; + } + + static constexpr GPUPipeline::VertexAttribute attributes[] = { + GPUPipeline::VertexAttribute::Make(GPUPipeline::VertexAttribute::Semantic::Position, 0, + GPUPipeline::VertexAttribute::Type::Float, 2, offsetof(ImDrawVert, pos)), + GPUPipeline::VertexAttribute::Make(GPUPipeline::VertexAttribute::Semantic::Texcoord, 0, + GPUPipeline::VertexAttribute::Type::Float, 2, offsetof(ImDrawVert, uv)), + GPUPipeline::VertexAttribute::Make(GPUPipeline::VertexAttribute::Semantic::Color, 0, + GPUPipeline::VertexAttribute::Type::UNorm8, 4, offsetof(ImDrawVert, col)), + }; + + GPUPipeline::GraphicsConfig config; + config.layout = GPUPipeline::Layout::SingleTexture; + config.primitive = GPUPipeline::Primitive::Triangles; + config.input_layout.vertex_attributes = attributes; + config.input_layout.vertex_stride = sizeof(ImDrawVert); + config.vertex_shader = imgui_vs.get(); + config.pixel_shader = imgui_ps.get(); + config.rasterization = GPUPipeline::RasterizationState::GetNoCullState(); + config.depth = GPUPipeline::DepthState::GetNoTestsState(); + config.blend = GPUPipeline::BlendState::GetAlphaBlendingState(); + config.color_format = GPUTexture::Format::RGBA8; // FIXME m_window_info.surface_format; + config.depth_format = GPUTexture::Format::Unknown; + config.samples = 1; + config.per_sample_shading = false; + + m_imgui_pipeline = CreatePipeline(config); + if (!m_imgui_pipeline) + { + Log_ErrorPrintf("Failed to compile ImGui pipeline."); + return false; + } + + return true; +} + +void GPUDevice::DestroyImGuiResources() +{ m_imgui_font_texture.reset(); } +void GPUDevice::MapVertexBuffer(u32 vertex_size, u32 vertex_count, void** map_ptr, u32* map_space, u32* map_base_vertex) +{ + // TODO: REMOVE ME + UnreachableCode(); +} + +void GPUDevice::UnmapVertexBuffer(u32 used_vertex_count) +{ + // TODO: REMOVE ME + UnreachableCode(); +} + +void GPUDevice::MapIndexBuffer(u32 index_count, u16** map_ptr, u32* map_space, u32* map_base_index) +{ + // TODO: REMOVE ME + UnreachableCode(); +} + +void GPUDevice::UnmapIndexBuffer(u32 used_index_count) +{ + // TODO: REMOVE ME + UnreachableCode(); +} + +void GPUDevice::UploadVertexBuffer(const void* vertices, u32 vertex_size, u32 vertex_count, u32* base_vertex) +{ + void* map; + u32 space; + MapVertexBuffer(vertex_size, vertex_count, &map, &space, base_vertex); + std::memcpy(map, vertices, vertex_size * vertex_count); + UnmapVertexBuffer(vertex_count); +} + +void GPUDevice::UploadIndexBuffer(const u16* indices, u32 index_count, u32* base_index) +{ + u16* map; + u32 space; + MapIndexBuffer(index_count, &map, &space, base_index); + std::memcpy(map, indices, sizeof(u16) * index_count); + UnmapIndexBuffer(index_count); +} + +void GPUDevice::PushUniformBuffer(const void* data, u32 data_size) +{ + // TODO: REMOVE ME + UnreachableCode(); +} + +void GPUDevice::SetFramebuffer(GPUFramebuffer* fb) +{ + // TODO: REMOVE ME + UnreachableCode(); +} + +void GPUDevice::SetPipeline(GPUPipeline* pipeline) +{ + // TODO: REMOVE ME + UnreachableCode(); +} + +void GPUDevice::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler) +{ + // TODO: REMOVE ME + UnreachableCode(); +} + +void GPUDevice::SetViewport(u32 x, u32 y, u32 width, u32 height) +{ + // TODO: REMOVE ME + UnreachableCode(); +} + +void GPUDevice::SetScissor(u32 x, u32 y, u32 width, u32 height) +{ + // TODO: REMOVE ME + UnreachableCode(); +} + +void GPUDevice::SetViewportAndScissor(u32 x, u32 y, u32 width, u32 height) +{ + // TODO: REMOVE ME + UnreachableCode(); +} + +void GPUDevice::Draw(u32 base_vertex, u32 vertex_count) +{ + // TODO: REMOVE ME + UnreachableCode(); +} + +void GPUDevice::DrawIndexed(u32 base_index, u32 index_count, u32 base_vertex) +{ + // TODO: REMOVE ME + UnreachableCode(); +} + void GPUDevice::CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src, u32 src_x, u32 src_y, u32 src_layer, u32 src_level, u32 width, u32 height) { @@ -146,6 +320,21 @@ std::unique_ptr<GPUPipeline> GPUDevice::CreatePipeline(const GPUPipeline::Graphi return {}; } +std::unique_ptr<GPUSampler> GPUDevice::CreateSampler(const GPUSampler::Config& config) +{ + // TODO: REMOVE ME + UnreachableCode(); + return {}; +} + +std::unique_ptr<GPUFramebuffer> GPUDevice::CreateFramebuffer(GPUTexture* rt, u32 rt_layer, u32 rt_level, GPUTexture* ds, + u32 ds_layer, u32 ds_level) +{ + // TODO: REMOVE ME + UnreachableCode(); + return {}; +} + bool GPUDevice::ParseFullscreenMode(const std::string_view& mode, u32* width, u32* height, float* refresh_rate) { if (!mode.empty()) diff --git a/src/core/gpu/gpu_device.h b/src/core/gpu/gpu_device.h index c48f2687c..55bbf7e4a 100644 --- a/src/core/gpu/gpu_device.h +++ b/src/core/gpu/gpu_device.h @@ -2,10 +2,10 @@ // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once -#include "gpu_pipeline.h" -#include "gpu_shader.h" + #include "gpu_texture.h" +#include "common/bitfield.h" #include "common/rectangle.h" #include "common/types.h" #include "common/window_info.h" @@ -28,7 +28,307 @@ enum class RenderAPI : u32 OpenGLES }; -// Interface to the frontend's renderer. +class GPUFramebuffer +{ +public: + GPUFramebuffer() = default; + virtual ~GPUFramebuffer() = default; + + virtual void SetDebugName(const std::string_view& name) = 0; +}; + +class GPUSampler +{ +public: + enum class Filter + { + Nearest, + Linear, + + MaxCount + }; + + enum class AddressMode + { + Repeat, + ClampToEdge, + ClampToBorder, + + MaxCount + }; + + struct Config + { + BitField<u64, Filter, 0, 1> min_filter; + BitField<u64, Filter, 1, 1> mag_filter; + BitField<u64, Filter, 2, 1> mip_filter; + BitField<u64, AddressMode, 3, 2> address_u; + BitField<u64, AddressMode, 5, 2> address_v; + BitField<u64, AddressMode, 7, 2> address_w; + BitField<u64, u8, 9, 5> anisotropy; + BitField<u64, u8, 14, 4> min_lod; + BitField<u64, u8, 18, 4> max_lod; + BitField<u64, u32, 32, 32> border_color; + u64 key; + }; + + GPUSampler() = default; + virtual ~GPUSampler() = default; + + virtual void SetDebugName(const std::string_view& name) = 0; +}; + +class GPUShader +{ +public: + enum class Stage + { + Vertex, + Pixel, + Compute + }; + + GPUShader(Stage stage) : m_stage(stage) {} + virtual ~GPUShader() = default; + + ALWAYS_INLINE Stage GetStage() const { return m_stage; } + + virtual void SetDebugName(const std::string_view& name) = 0; + +protected: + Stage m_stage; +}; + +class GPUPipeline +{ +public: + enum class Layout : u8 + { + // 128 byte UBO via push constants, 1 texture. + SingleTexture, + + MaxCount + }; + + enum class Primitive : u8 + { + Points, + Lines, + Triangles, + TriangleStrips, + + MaxCount + }; + + union VertexAttribute + { + enum class Semantic : u8 + { + Position, + Texcoord, + Color, + + MaxCount + }; + + enum class Type : u8 + { + Float, + UInt8, + SInt8, + UNorm8, + UInt16, + SInt16, + UNorm16, + UInt32, + SInt32, + + MaxCount + }; + + BitField<u32, Semantic, 0, 3> semantic; + BitField<u32, u8, 4, 8> semantic_index; + BitField<u32, Type, 12, 4> type; + BitField<u32, u8, 16, 3> components; + BitField<u32, u8, 19, 8> offset; + u32 key; + + // clang-format off + ALWAYS_INLINE VertexAttribute& operator=(const VertexAttribute& rhs) { key = rhs.key; return *this; } + ALWAYS_INLINE bool operator==(const VertexAttribute& rhs) const { return key == rhs.key; } + ALWAYS_INLINE bool operator!=(const VertexAttribute& rhs) const { return key != rhs.key; } + ALWAYS_INLINE bool operator<(const VertexAttribute& rhs) const { return key < rhs.key; } + // clang-format on + + static constexpr VertexAttribute Make(Semantic semantic, u8 semantic_index, Type type, u8 components, u8 offset) + { + VertexAttribute ret = {}; +#if 0 + ret.semantic = semantic; + ret.semantic_index = semantic_index; + ret.type = type; + ret.components = components; + ret.offset = offset; +#else + // Nasty :/ can't access an inactive element of a union here.. + ret.key = (static_cast<u32>(semantic) & 0x7) | ((static_cast<u32>(semantic_index) & 0xff) << 4) | + ((static_cast<u32>(type) & 0xf) << 12) | ((static_cast<u32>(components) & 0x7) << 16) | + ((static_cast<u32>(offset) & 0xff) << 19); +#endif + return ret; + } + }; + + struct InputLayout + { + gsl::span<const VertexAttribute> vertex_attributes; + u32 vertex_stride; + + bool operator==(const InputLayout& rhs) const; + bool operator!=(const InputLayout& rhs) const; + }; + + struct InputLayoutHash + { + size_t operator()(const InputLayout& il) const; + }; + + enum class CullMode : u8 + { + None, + Front, + Back, + + MaxCount + }; + + enum class DepthFunc : u8 + { + Never, + Always, + Less, + LessEqual, + Greater, + GreaterEqual, + Equal, + + MaxCount + }; + + enum class BlendFunc : u8 + { + Zero, + One, + SrcColor, + InvSrcColor, + DstColor, + InvDstColor, + SrcAlpha, + InvSrcAlpha, + SrcAlpha1, + InvSrcAlpha1, + DstAlpha, + InvDstAlpha, + + MaxCount + }; + + enum class BlendOp : u8 + { + Add, + Subtract, + ReverseSubtract, + Min, + Max, + + MaxCount + }; + + union RasterizationState + { + BitField<u8, CullMode, 0, 2> cull_mode; + u8 key; + + // clang-format off + ALWAYS_INLINE RasterizationState& operator=(const RasterizationState& rhs) { key = rhs.key; return *this; } + ALWAYS_INLINE bool operator==(const RasterizationState& rhs) const { return key == rhs.key; } + ALWAYS_INLINE bool operator!=(const RasterizationState& rhs) const { return key != rhs.key; } + ALWAYS_INLINE bool operator<(const RasterizationState& rhs) const { return key < rhs.key; } + // clang-format on + + static RasterizationState GetNoCullState(); + }; + + struct DepthState + { + BitField<u8, DepthFunc, 0, 3> depth_test; + BitField<u8, bool, 4, 1> depth_write; + u8 key; + + // clang-format off + ALWAYS_INLINE DepthState& operator=(const DepthState& rhs) { key = rhs.key; return *this; } + ALWAYS_INLINE bool operator==(const DepthState& rhs) const { return key == rhs.key; } + ALWAYS_INLINE bool operator!=(const DepthState& rhs) const { return key != rhs.key; } + ALWAYS_INLINE bool operator<(const DepthState& rhs) const { return key < rhs.key; } + // clang-format on + + static DepthState GetNoTestsState(); + static DepthState GetAlwaysWriteState(); + }; + + struct BlendState + { + BitField<u32, bool, 0, 1> enable; + BitField<u32, BlendFunc, 1, 4> src_blend; + BitField<u32, BlendFunc, 5, 4> src_alpha_blend; + BitField<u32, BlendFunc, 9, 4> dst_blend; + BitField<u32, BlendFunc, 13, 4> dst_alpha_blend; + BitField<u32, BlendOp, 17, 3> blend_op; + BitField<u32, BlendOp, 20, 3> alpha_blend_op; + BitField<u32, bool, 24, 1> write_r; + BitField<u32, bool, 25, 1> write_g; + BitField<u32, bool, 26, 1> write_b; + BitField<u32, bool, 27, 1> write_a; + BitField<u32, u8, 24, 4> write_mask; + u32 key; + + // clang-format off + ALWAYS_INLINE BlendState& operator=(const BlendState& rhs) { key = rhs.key; return *this; } + ALWAYS_INLINE bool operator==(const BlendState& rhs) const { return key == rhs.key; } + ALWAYS_INLINE bool operator!=(const BlendState& rhs) const { return key != rhs.key; } + ALWAYS_INLINE bool operator<(const BlendState& rhs) const { return key < rhs.key; } + // clang-format on + + static BlendState GetNoBlendingState(); + static BlendState GetAlphaBlendingState(); + }; + + struct GraphicsConfig + { + Layout layout; + + Primitive primitive; + InputLayout input_layout; + + RasterizationState rasterization; + DepthState depth; + BlendState blend; + + const GPUShader* vertex_shader; + const GPUShader* pixel_shader; + + GPUTexture::Format color_format; + GPUTexture::Format depth_format; + u32 samples; + bool per_sample_shading; + }; + + GPUPipeline() = default; + virtual ~GPUPipeline() = default; + + virtual void SetDebugName(const std::string_view& name) = 0; +}; + class GPUDevice { public: @@ -86,7 +386,7 @@ public: virtual bool IsFullscreen() = 0; virtual bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) = 0; virtual AdapterAndModeList GetAdapterAndModeList() = 0; - virtual bool CreateResources() = 0; + virtual bool CreateResources(); virtual void DestroyResources(); virtual bool SetPostProcessingChain(const std::string_view& config) = 0; @@ -94,11 +394,37 @@ public: /// Call when the window size changes externally to recreate any resources. virtual void ResizeWindow(s32 new_window_width, s32 new_window_height) = 0; + /// Vertex/index buffer abstraction. + virtual void MapVertexBuffer(u32 vertex_size, u32 vertex_count, void** map_ptr, u32* map_space, u32* map_base_vertex); + virtual void UnmapVertexBuffer(u32 used_vertex_count); + virtual void MapIndexBuffer(u32 index_count, u16** map_ptr, u32* map_space, u32* map_base_index); + virtual void UnmapIndexBuffer(u32 used_index_count); + + void UploadVertexBuffer(const void* vertices, u32 vertex_size, u32 vertex_count, u32* base_vertex); + void UploadIndexBuffer(const u16* indices, u32 index_count, u32* base_index); + + /// Uniform buffer abstraction. + virtual void PushUniformBuffer(const void* data, u32 data_size); + + /// Drawing setup abstraction. + virtual void SetFramebuffer(GPUFramebuffer* fb); + virtual void SetPipeline(GPUPipeline* pipeline); + virtual void SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler); + virtual void SetViewport(u32 x, u32 y, u32 width, u32 height); + virtual void SetScissor(u32 x, u32 y, u32 width, u32 height); + void SetViewportAndScissor(u32 x, u32 y, u32 width, u32 height); + + // Drawing abstraction. + virtual void Draw(u32 base_vertex, u32 vertex_count); + virtual void DrawIndexed(u32 base_index, u32 index_count, u32 base_vertex); + /// Creates an abstracted RGBA8 texture. If dynamic, the texture can be updated with UpdateTexture() below. virtual std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type, GPUTexture::Format format, const void* data = nullptr, u32 data_stride = 0, bool dynamic = false) = 0; + virtual std::unique_ptr<GPUSampler> CreateSampler(const GPUSampler::Config& config); + virtual bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data, u32 out_data_stride) = 0; virtual void CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src, @@ -107,6 +433,10 @@ public: GPUTexture* src, u32 src_x, u32 src_y, u32 src_layer, u32 src_level, u32 width, u32 height); + /// Framebuffer abstraction. + virtual std::unique_ptr<GPUFramebuffer> CreateFramebuffer(GPUTexture* rt, u32 rt_layer, u32 rt_level, GPUTexture* ds, + u32 ds_layer, u32 ds_level); + /// Shader abstraction. virtual std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShader::Stage stage, gsl::span<const u8> data); virtual std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShader::Stage stage, const std::string_view& source, @@ -230,8 +560,14 @@ protected: std::tuple<s32, s32, s32, s32> CalculateSoftwareCursorDrawRect() const; std::tuple<s32, s32, s32, s32> CalculateSoftwareCursorDrawRect(s32 cursor_x, s32 cursor_y) const; + bool CreateImGuiResources(); + void DestroyImGuiResources(); + WindowInfo m_window_info; + std::unique_ptr<GPUSampler> m_point_sampler; + std::unique_ptr<GPUSampler> m_linear_sampler; + u64 m_last_frame_displayed_time = 0; s32 m_mouse_position_x = 0; @@ -252,6 +588,7 @@ protected: s32 m_display_texture_view_width = 0; s32 m_display_texture_view_height = 0; + std::unique_ptr<GPUPipeline> m_imgui_pipeline; std::unique_ptr<GPUTexture> m_imgui_font_texture; std::unique_ptr<GPUTexture> m_cursor_texture; diff --git a/src/core/gpu/gpu_pipeline.h b/src/core/gpu/gpu_pipeline.h deleted file mode 100644 index abbfb7457..000000000 --- a/src/core/gpu/gpu_pipeline.h +++ /dev/null @@ -1,199 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com> -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#pragma once - -#include "gpu_texture.h" - -#include "common/bitfield.h" -#include "common/types.h" - -#include "gsl/span" - -#include <string_view> - -class GPUShader; - -class GPUPipeline -{ -public: - enum class Layout : u8 - { - // 128 byte UBO via push constants, 1 texture. - SingleTexture, - - MaxCount - }; - - enum class Primitive : u8 - { - Points, - Lines, - Triangles, - TriangleStrips, - - MaxCount - }; - - union VertexAttribute - { - enum class Semantic : u8 - { - Position, - Texcoord, - Color, - - MaxCount - }; - - enum class Type : u8 - { - Float, - UInt8, - SInt8, - UNorm8, - UInt16, - SInt16, - UNorm16, - UInt32, - SInt32, - - MaxCount - }; - - BitField<u32, Semantic, 0, 3> semantic; - BitField<u32, u8, 4, 8> semantic_index; - BitField<u32, Type, 12, 4> type; - BitField<u32, u8, 16, 2> components; - BitField<u32, u8, 18, 8> offset; - u32 key; - }; - - struct InputLayout - { - gsl::span<const VertexAttribute> vertex_attributes; - u32 vertex_stride; - - bool operator==(const InputLayout& rhs) const; - bool operator!=(const InputLayout& rhs) const; - }; - - struct InputLayoutHash - { - size_t operator()(const InputLayout& il) const; - }; - - enum class CullMode : u8 - { - None, - Front, - Back, - - MaxCount - }; - - enum class DepthFunc : u8 - { - Never, - Always, - Less, - LessEqual, - Greater, - GreaterEqual, - Equal, - - MaxCount - }; - - enum class BlendFunc : u8 - { - Zero, - One, - SrcColor, - InvSrcColor, - DstColor, - InvDstColor, - SrcAlpha, - InvSrcAlpha, - SrcAlpha1, - InvSrcAlpha1, - DstAlpha, - InvDstAlpha, - - MaxCount - }; - - enum class BlendOp : u8 - { - Add, - Subtract, - ReverseSubtract, - Min, - Max, - - MaxCount - }; - - union RasterizationState - { - BitField<u8, CullMode, 0, 2> cull_mode; - u8 key; - - static RasterizationState GetNoCullState(); - }; - - struct DepthState - { - BitField<u8, DepthFunc, 0, 3> depth_test; - BitField<u8, bool, 4, 1> depth_write; - u8 key; - - static DepthState GetNoTestsState(); - static DepthState GetAlwaysWriteState(); - }; - - struct BlendState - { - BitField<u32, bool, 0, 1> enable; - BitField<u32, BlendFunc, 1, 4> src_blend; - BitField<u32, BlendFunc, 5, 4> src_alpha_blend; - BitField<u32, BlendFunc, 9, 4> dst_blend; - BitField<u32, BlendFunc, 13, 4> dst_alpha_blend; - BitField<u32, BlendOp, 17, 3> blend_op; - BitField<u32, BlendOp, 20, 3> alpha_blend_op; - BitField<u32, bool, 24, 1> write_r; - BitField<u32, bool, 25, 1> write_g; - BitField<u32, bool, 26, 1> write_b; - BitField<u32, bool, 27, 1> write_a; - BitField<u32, u8, 24, 4> write_mask; - u32 key; - - static BlendState GetNoBlendingState(); - static BlendState GetAlphaBlendingState(); - }; - - struct GraphicsConfig - { - Layout layout; - - Primitive primitive; - InputLayout input_layout; - - RasterizationState rasterization; - DepthState depth; - BlendState blend; - - const GPUShader* vertex_shader; - const GPUShader* pixel_shader; - - GPUTexture::Format color_format; - GPUTexture::Format depth_format; - u32 samples; - bool per_sample_shading; - }; - - GPUPipeline() = default; - virtual ~GPUPipeline() = default; - - virtual void SetDebugName(const std::string_view& name) = 0; -}; diff --git a/src/core/gpu/gpu_shader.h b/src/core/gpu/gpu_shader.h deleted file mode 100644 index 84183edec..000000000 --- a/src/core/gpu/gpu_shader.h +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com> -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#pragma once - -#include <string_view> - -#include "common/types.h" - -class GPUShader -{ -public: - enum class Stage - { - Vertex, - Pixel, - Compute - }; - - GPUShader(Stage stage) : m_stage(stage) {} - virtual ~GPUShader() = default; - - ALWAYS_INLINE Stage GetStage() const { return m_stage; } - - virtual void SetDebugName(const std::string_view& name) = 0; - -protected: - Stage m_stage; -}; diff --git a/src/frontend-common/CMakeLists.txt b/src/frontend-common/CMakeLists.txt index 1496aad3f..2e66254fd 100644 --- a/src/frontend-common/CMakeLists.txt +++ b/src/frontend-common/CMakeLists.txt @@ -19,12 +19,6 @@ add_library(frontend-common imgui_overlays.cpp imgui_overlays.h platform_misc.h - postprocessing_chain.cpp - postprocessing_chain.h - postprocessing_shader.cpp - postprocessing_shader.h - postprocessing_shadergen.cpp - postprocessing_shadergen.h ) target_link_libraries(frontend-common PUBLIC core common imgui tinyxml2 rapidjson scmversion) @@ -39,16 +33,8 @@ endif() if(WIN32) target_sources(frontend-common PRIVATE - d3d11_host_display.cpp - d3d11_host_display.h - d3d12_host_display.cpp - d3d12_host_display.h dinput_source.cpp dinput_source.h - imgui_impl_dx11.cpp - imgui_impl_dx11.h - imgui_impl_dx12.cpp - imgui_impl_dx12.h win32_raw_input_source.cpp win32_raw_input_source.h xaudio2_audio_stream.cpp @@ -59,25 +45,6 @@ if(WIN32) target_link_libraries(frontend-common PRIVATE d3d11.lib dxgi.lib) endif() -if(ENABLE_OPENGL) - target_sources(frontend-common PRIVATE - opengl_host_display.cpp - opengl_host_display.h - imgui_impl_opengl3.cpp - imgui_impl_opengl3.h - ) - target_link_libraries(frontend-common PRIVATE glad) -endif() - -if(ENABLE_VULKAN) - target_sources(frontend-common PRIVATE - imgui_impl_vulkan.cpp - imgui_impl_vulkan.h - vulkan_host_display.cpp - vulkan_host_display.h - ) -endif() - if(WIN32) target_sources(frontend-common PRIVATE platform_misc_win32.cpp