More abstraction

This commit is contained in:
Stenzek 2023-07-31 23:33:02 +10:00
parent dbf31ff75d
commit de08feeffb
15 changed files with 1325 additions and 910 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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