More abstraction
This commit is contained in:
parent
dbf31ff75d
commit
de08feeffb
|
@ -15,8 +15,6 @@ add_library(common
|
||||||
fifo_queue.h
|
fifo_queue.h
|
||||||
file_system.cpp
|
file_system.cpp
|
||||||
file_system.h
|
file_system.h
|
||||||
gpu_texture.cpp
|
|
||||||
gpu_texture.h
|
|
||||||
image.cpp
|
image.cpp
|
||||||
image.h
|
image.h
|
||||||
hash_combine.h
|
hash_combine.h
|
||||||
|
@ -66,28 +64,6 @@ target_link_libraries(common PRIVATE stb libchdr zlib minizip Zstd::Zstd "${CMAK
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_sources(common PRIVATE
|
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.cpp
|
||||||
http_downloader_winhttp.h
|
http_downloader_winhttp.h
|
||||||
thirdparty/StackWalker.cpp
|
thirdparty/StackWalker.cpp
|
||||||
|
@ -113,147 +89,6 @@ if(ANDROID)
|
||||||
target_link_libraries(common PRIVATE log)
|
target_link_libraries(common PRIVATE log)
|
||||||
endif()
|
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")
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
# We need -lrt for shm_unlink
|
# We need -lrt for shm_unlink
|
||||||
target_link_libraries(common PRIVATE rt)
|
target_link_libraries(common PRIVATE rt)
|
||||||
|
|
|
@ -54,8 +54,6 @@ add_library(core
|
||||||
gte_types.h
|
gte_types.h
|
||||||
host.cpp
|
host.cpp
|
||||||
host.h
|
host.h
|
||||||
host_display.cpp
|
|
||||||
host_display.h
|
|
||||||
host_interface_progress_callback.cpp
|
host_interface_progress_callback.cpp
|
||||||
host_interface_progress_callback.h
|
host_interface_progress_callback.h
|
||||||
host_settings.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 PUBLIC Threads::Threads common util zlib)
|
||||||
target_link_libraries(core PRIVATE stb xxhash imgui rapidjson tinyxml2)
|
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)
|
if(WIN32)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
gpu_hw_d3d12.cpp
|
gpu_hw_d3d12.cpp
|
||||||
|
@ -132,10 +171,116 @@ if(WIN32)
|
||||||
target_link_libraries(core PRIVATE winmm.lib)
|
target_link_libraries(core PRIVATE winmm.lib)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_CUBEB)
|
if(USE_X11)
|
||||||
target_compile_definitions(core PUBLIC "WITH_CUBEB=1")
|
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()
|
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)
|
if(ENABLE_OPENGL)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
gpu_hw_opengl.cpp
|
gpu_hw_opengl.cpp
|
||||||
|
@ -144,6 +289,35 @@ if(ENABLE_OPENGL)
|
||||||
target_link_libraries(core PRIVATE glad)
|
target_link_libraries(core PRIVATE glad)
|
||||||
endif()
|
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)
|
if(ENABLE_VULKAN)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
gpu_hw_vulkan.cpp
|
gpu_hw_vulkan.cpp
|
||||||
|
@ -151,6 +325,10 @@ if(ENABLE_VULKAN)
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(ENABLE_CUBEB)
|
||||||
|
target_compile_definitions(core PUBLIC "WITH_CUBEB=1")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(${CPU_ARCH} STREQUAL "x64")
|
if(${CPU_ARCH} STREQUAL "x64")
|
||||||
target_include_directories(core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../../dep/xbyak/xbyak")
|
target_include_directories(core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../../dep/xbyak/xbyak")
|
||||||
target_compile_definitions(core PUBLIC "WITH_RECOMPILER=1" "WITH_MMAP_FASTMEM=1")
|
target_compile_definitions(core PUBLIC "WITH_RECOMPILER=1" "WITH_MMAP_FASTMEM=1")
|
||||||
|
|
|
@ -37,8 +37,6 @@
|
||||||
<ClCompile Include="gpu\d3d11\shader_compiler.cpp" />
|
<ClCompile Include="gpu\d3d11\shader_compiler.cpp" />
|
||||||
<ClCompile Include="gpu\d3d11\stream_buffer.cpp" />
|
<ClCompile Include="gpu\d3d11\stream_buffer.cpp" />
|
||||||
<ClCompile Include="gpu\d3d11_device.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\d3d11_texture.cpp" />
|
||||||
<ClCompile Include="gpu\d3d12\context.cpp" />
|
<ClCompile Include="gpu\d3d12\context.cpp" />
|
||||||
<ClCompile Include="gpu\d3d12\descriptor_heap_manager.cpp" />
|
<ClCompile Include="gpu\d3d12\descriptor_heap_manager.cpp" />
|
||||||
|
@ -163,8 +161,6 @@
|
||||||
<ClInclude Include="gpu\d3d11\shader_compiler.h" />
|
<ClInclude Include="gpu\d3d11\shader_compiler.h" />
|
||||||
<ClInclude Include="gpu\d3d11\stream_buffer.h" />
|
<ClInclude Include="gpu\d3d11\stream_buffer.h" />
|
||||||
<ClInclude Include="gpu\d3d11_device.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\d3d_shaders.h" />
|
||||||
<ClInclude Include="gpu\d3d11_texture.h" />
|
<ClInclude Include="gpu\d3d11_texture.h" />
|
||||||
<ClInclude Include="gpu\d3d12\context.h" />
|
<ClInclude Include="gpu\d3d12\context.h" />
|
||||||
|
@ -201,8 +197,6 @@
|
||||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="gpu\gpu_device.h" />
|
<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\gpu_texture.h" />
|
||||||
<ClInclude Include="gpu\imgui_impl_dx12.h" />
|
<ClInclude Include="gpu\imgui_impl_dx12.h" />
|
||||||
<ClInclude Include="gpu\imgui_impl_opengl3.h" />
|
<ClInclude Include="gpu\imgui_impl_opengl3.h" />
|
||||||
|
|
|
@ -188,12 +188,6 @@
|
||||||
<ClCompile Include="gpu\d3d11_texture.cpp">
|
<ClCompile Include="gpu\d3d11_texture.cpp">
|
||||||
<Filter>gpu</Filter>
|
<Filter>gpu</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="gpu\d3d11_shader.cpp">
|
|
||||||
<Filter>gpu</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="gpu\d3d11_pipeline.cpp">
|
|
||||||
<Filter>gpu</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="types.h" />
|
<ClInclude Include="types.h" />
|
||||||
|
@ -401,18 +395,6 @@
|
||||||
<ClInclude Include="gpu\d3d_shaders.h">
|
<ClInclude Include="gpu\d3d_shaders.h">
|
||||||
<Filter>gpu</Filter>
|
<Filter>gpu</Filter>
|
||||||
</ClInclude>
|
</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>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="gpu">
|
<Filter Include="gpu">
|
||||||
|
|
|
@ -558,6 +558,9 @@ bool D3D11Device::SetFullscreen(bool fullscreen, u32 width, u32 height, float re
|
||||||
|
|
||||||
bool D3D11Device::CreateResources()
|
bool D3D11Device::CreateResources()
|
||||||
{
|
{
|
||||||
|
if (!GPUDevice::CreateResources())
|
||||||
|
return false;
|
||||||
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
m_display_vertex_shader =
|
m_display_vertex_shader =
|
||||||
|
@ -1304,3 +1307,505 @@ float D3D11Device::GetAndResetAccumulatedGPUTime()
|
||||||
m_accumulated_gpu_time = 0.0f;
|
m_accumulated_gpu_time = 0.0f;
|
||||||
return value;
|
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)]));
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include "d3d11/stream_buffer.h"
|
#include "d3d11/stream_buffer.h"
|
||||||
#include "d3d11_texture.h"
|
#include "d3d11_texture.h"
|
||||||
#include "gpu_device.h"
|
#include "gpu_device.h"
|
||||||
#include "gpu_pipeline.h"
|
|
||||||
#include "postprocessing_chain.h"
|
#include "postprocessing_chain.h"
|
||||||
#include <d3d11.h>
|
#include <d3d11.h>
|
||||||
#include <dxgi.h>
|
#include <dxgi.h>
|
||||||
|
@ -19,8 +18,107 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <wrl/client.h>
|
#include <wrl/client.h>
|
||||||
|
|
||||||
class D3D11Pipeline;
|
class D3D11Device;
|
||||||
class D3D11Shader;
|
|
||||||
|
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
|
class D3D11Device final : public GPUDevice
|
||||||
{
|
{
|
||||||
|
@ -62,6 +160,8 @@ public:
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data = nullptr, u32 data_stride = 0,
|
const void* data = nullptr, u32 data_stride = 0,
|
||||||
bool dynamic = false) override;
|
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,
|
bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||||
u32 out_data_stride) override;
|
u32 out_data_stride) override;
|
||||||
bool SupportsTextureFormat(GPUTexture::Format format) const 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,
|
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;
|
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> CreateShaderFromBinary(GPUShader::Stage stage, gsl::span<const u8> data) override;
|
||||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShader::Stage stage, const std::string_view& source,
|
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShader::Stage stage, const std::string_view& source,
|
||||||
std::vector<u8>* out_binary = nullptr) override;
|
std::vector<u8>* out_binary = nullptr) override;
|
||||||
|
@ -92,7 +195,8 @@ private:
|
||||||
using RasterizationStateMap = std::unordered_map<u8, ComPtr<ID3D11RasterizerState>>;
|
using RasterizationStateMap = std::unordered_map<u8, ComPtr<ID3D11RasterizerState>>;
|
||||||
using DepthStateMap = std::unordered_map<u8, ComPtr<ID3D11DepthStencilState>>;
|
using DepthStateMap = std::unordered_map<u8, ComPtr<ID3D11DepthStencilState>>;
|
||||||
using BlendStateMap = std::unordered_map<u32, ComPtr<ID3D11BlendState>>;
|
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 DISPLAY_UNIFORM_BUFFER_SIZE = 64;
|
||||||
static constexpr u32 IMGUI_VERTEX_BUFFER_SIZE = 4 * 1024 * 1024;
|
static constexpr u32 IMGUI_VERTEX_BUFFER_SIZE = 4 * 1024 * 1024;
|
||||||
|
|
|
@ -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)]));
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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()));
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
};
|
|
|
@ -21,6 +21,10 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
Log_SetChannel(GPUDevice);
|
Log_SetChannel(GPUDevice);
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
#include "common/windows_headers.h"
|
||||||
|
#include "d3d_shaders.h"
|
||||||
|
|
||||||
std::unique_ptr<GPUDevice> g_host_display;
|
std::unique_ptr<GPUDevice> g_host_display;
|
||||||
|
|
||||||
size_t GPUPipeline::InputLayoutHash::operator()(const InputLayout& il) const
|
size_t GPUPipeline::InputLayoutHash::operator()(const InputLayout& il) const
|
||||||
|
@ -103,12 +107,182 @@ RenderAPI GPUDevice::GetPreferredAPI()
|
||||||
#endif
|
#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()
|
void GPUDevice::DestroyResources()
|
||||||
{
|
{
|
||||||
|
DestroyImGuiResources();
|
||||||
|
|
||||||
m_cursor_texture.reset();
|
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();
|
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,
|
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)
|
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 {};
|
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)
|
bool GPUDevice::ParseFullscreenMode(const std::string_view& mode, u32* width, u32* height, float* refresh_rate)
|
||||||
{
|
{
|
||||||
if (!mode.empty())
|
if (!mode.empty())
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "gpu_pipeline.h"
|
|
||||||
#include "gpu_shader.h"
|
|
||||||
#include "gpu_texture.h"
|
#include "gpu_texture.h"
|
||||||
|
|
||||||
|
#include "common/bitfield.h"
|
||||||
#include "common/rectangle.h"
|
#include "common/rectangle.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
#include "common/window_info.h"
|
#include "common/window_info.h"
|
||||||
|
@ -28,7 +28,307 @@ enum class RenderAPI : u32
|
||||||
OpenGLES
|
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
|
class GPUDevice
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -86,7 +386,7 @@ public:
|
||||||
virtual bool IsFullscreen() = 0;
|
virtual bool IsFullscreen() = 0;
|
||||||
virtual bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) = 0;
|
virtual bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) = 0;
|
||||||
virtual AdapterAndModeList GetAdapterAndModeList() = 0;
|
virtual AdapterAndModeList GetAdapterAndModeList() = 0;
|
||||||
virtual bool CreateResources() = 0;
|
virtual bool CreateResources();
|
||||||
virtual void DestroyResources();
|
virtual void DestroyResources();
|
||||||
|
|
||||||
virtual bool SetPostProcessingChain(const std::string_view& config) = 0;
|
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.
|
/// Call when the window size changes externally to recreate any resources.
|
||||||
virtual void ResizeWindow(s32 new_window_width, s32 new_window_height) = 0;
|
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.
|
/// 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,
|
virtual std::unique_ptr<GPUTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||||
GPUTexture::Type type, GPUTexture::Format format,
|
GPUTexture::Type type, GPUTexture::Format format,
|
||||||
const void* data = nullptr, u32 data_stride = 0,
|
const void* data = nullptr, u32 data_stride = 0,
|
||||||
bool dynamic = false) = 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,
|
virtual bool DownloadTexture(GPUTexture* texture, u32 x, u32 y, u32 width, u32 height, void* out_data,
|
||||||
u32 out_data_stride) = 0;
|
u32 out_data_stride) = 0;
|
||||||
virtual void CopyTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src,
|
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,
|
GPUTexture* src, u32 src_x, u32 src_y, u32 src_layer, u32 src_level, u32 width,
|
||||||
u32 height);
|
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.
|
/// Shader abstraction.
|
||||||
virtual std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShader::Stage stage, gsl::span<const u8> data);
|
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,
|
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() const;
|
||||||
std::tuple<s32, s32, s32, s32> CalculateSoftwareCursorDrawRect(s32 cursor_x, s32 cursor_y) const;
|
std::tuple<s32, s32, s32, s32> CalculateSoftwareCursorDrawRect(s32 cursor_x, s32 cursor_y) const;
|
||||||
|
|
||||||
|
bool CreateImGuiResources();
|
||||||
|
void DestroyImGuiResources();
|
||||||
|
|
||||||
WindowInfo m_window_info;
|
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;
|
u64 m_last_frame_displayed_time = 0;
|
||||||
|
|
||||||
s32 m_mouse_position_x = 0;
|
s32 m_mouse_position_x = 0;
|
||||||
|
@ -252,6 +588,7 @@ protected:
|
||||||
s32 m_display_texture_view_width = 0;
|
s32 m_display_texture_view_width = 0;
|
||||||
s32 m_display_texture_view_height = 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_imgui_font_texture;
|
||||||
|
|
||||||
std::unique_ptr<GPUTexture> m_cursor_texture;
|
std::unique_ptr<GPUTexture> m_cursor_texture;
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -19,12 +19,6 @@ add_library(frontend-common
|
||||||
imgui_overlays.cpp
|
imgui_overlays.cpp
|
||||||
imgui_overlays.h
|
imgui_overlays.h
|
||||||
platform_misc.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)
|
target_link_libraries(frontend-common PUBLIC core common imgui tinyxml2 rapidjson scmversion)
|
||||||
|
@ -39,16 +33,8 @@ endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_sources(frontend-common PRIVATE
|
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.cpp
|
||||||
dinput_source.h
|
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.cpp
|
||||||
win32_raw_input_source.h
|
win32_raw_input_source.h
|
||||||
xaudio2_audio_stream.cpp
|
xaudio2_audio_stream.cpp
|
||||||
|
@ -59,25 +45,6 @@ if(WIN32)
|
||||||
target_link_libraries(frontend-common PRIVATE d3d11.lib dxgi.lib)
|
target_link_libraries(frontend-common PRIVATE d3d11.lib dxgi.lib)
|
||||||
endif()
|
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)
|
if(WIN32)
|
||||||
target_sources(frontend-common PRIVATE
|
target_sources(frontend-common PRIVATE
|
||||||
platform_misc_win32.cpp
|
platform_misc_win32.cpp
|
||||||
|
|
Loading…
Reference in New Issue