GPUDevice: Support transpiling shaders at compile time
And use it for GLSL postprocessing shaders.
This commit is contained in:
parent
f0c2832d03
commit
f176fa0228
|
@ -34,21 +34,20 @@ if(ENABLE_WAYLAND)
|
||||||
find_package(Wayland REQUIRED Egl)
|
find_package(Wayland REQUIRED Egl)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_VULKAN OR APPLE)
|
if(ENABLE_VULKAN)
|
||||||
find_package(Shaderc REQUIRED)
|
find_package(Shaderc REQUIRED)
|
||||||
|
find_package(spirv_cross_c_shared REQUIRED)
|
||||||
|
|
||||||
if(LINUX AND ENABLE_VULKAN)
|
if(LINUX)
|
||||||
# We need to add the rpath for shaderc to the executable.
|
# We need to add the rpath for shaderc to the executable.
|
||||||
get_filename_component(SHADERC_LIBRARY_DIRECTORY ${SHADERC_LIBRARY} DIRECTORY)
|
get_filename_component(SHADERC_LIBRARY_DIRECTORY ${SHADERC_LIBRARY} DIRECTORY)
|
||||||
list(APPEND CMAKE_BUILD_RPATH ${SHADERC_LIBRARY_DIRECTORY})
|
list(APPEND CMAKE_BUILD_RPATH ${SHADERC_LIBRARY_DIRECTORY})
|
||||||
|
get_target_property(SPIRV_CROSS_LIBRARY spirv-cross-c-shared IMPORTED_LOCATION)
|
||||||
|
get_filename_component(SPIRV_CROSS_LIBRARY_DIRECTORY ${SPIRV_CROSS_LIBRARY} DIRECTORY)
|
||||||
|
list(APPEND CMAKE_BUILD_RPATH ${SPIRV_CROSS_LIBRARY_DIRECTORY})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
|
||||||
# SPIRV-Cross is currently only used on MacOS.
|
|
||||||
find_package(spirv_cross_c_shared REQUIRED)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(LINUX)
|
if(LINUX)
|
||||||
find_package(UDEV REQUIRED)
|
find_package(UDEV REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -57,6 +57,7 @@ STRIP=strip
|
||||||
|
|
||||||
declare -a MANUAL_LIBS=(
|
declare -a MANUAL_LIBS=(
|
||||||
"libshaderc_shared.so.1"
|
"libshaderc_shared.so.1"
|
||||||
|
"libspirv-cross-c-shared.so.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
declare -a MANUAL_QT_LIBS=(
|
declare -a MANUAL_QT_LIBS=(
|
||||||
|
|
|
@ -92,7 +92,7 @@ eb11e1b3715b2211442b7e5933a1135885b664cc10530a1a022355fe9e1bb4ac SPIRV-Cross-$S
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
curl -L \
|
curl -L \
|
||||||
-O "https://download.savannah.gnu.org/releases/freetype/freetype-$FREETYPE.tar.xz" \
|
-o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download" \
|
||||||
-o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz" \
|
-o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz" \
|
||||||
-O "https://libsdl.org/release/$SDL.tar.gz" \
|
-O "https://libsdl.org/release/$SDL.tar.gz" \
|
||||||
-O "http://zlib.net/zlib-$ZLIB.tar.gz" \
|
-O "http://zlib.net/zlib-$ZLIB.tar.gz" \
|
||||||
|
@ -123,16 +123,6 @@ make -C build "-j$NPROCS"
|
||||||
make -C build install
|
make -C build install
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
# Temporarily disabled, because the updater doesn't get fixup'd, so the dylib doesn't get added to its bundle.
|
|
||||||
#echo "Installing Zlib..."
|
|
||||||
#rm -fr "zlib-$ZLIB"
|
|
||||||
#tar xf "zlib-$ZLIB.tar.gz"
|
|
||||||
#cd "zlib-$ZLIB"
|
|
||||||
#cmake -B build "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DBUILD_SHARED_LIBS=ON -DZLIB_BUILD_EXAMPLES=OFF
|
|
||||||
#make -C build "-j$NPROCS"
|
|
||||||
#make -C build install
|
|
||||||
#cd ..
|
|
||||||
|
|
||||||
echo "Installing Zstd..."
|
echo "Installing Zstd..."
|
||||||
rm -fr "zstd-$ZSTD"
|
rm -fr "zstd-$ZSTD"
|
||||||
tar xf "zstd-$ZSTD.tar.gz"
|
tar xf "zstd-$ZSTD.tar.gz"
|
||||||
|
|
|
@ -43,7 +43,7 @@ diff --git a/libshaderc/CMakeLists.txt b/libshaderc/CMakeLists.txt
|
||||||
index df9a88d..b15e5d7 100644
|
index df9a88d..b15e5d7 100644
|
||||||
--- a/libshaderc/CMakeLists.txt
|
--- a/libshaderc/CMakeLists.txt
|
||||||
+++ b/libshaderc/CMakeLists.txt
|
+++ b/libshaderc/CMakeLists.txt
|
||||||
@@ -24,13 +24,6 @@ set(SHADERC_SOURCES
|
@@ -24,13 +24,6 @@
|
||||||
src/shaderc_private.h
|
src/shaderc_private.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -57,7 +57,15 @@ index df9a88d..b15e5d7 100644
|
||||||
add_library(shaderc_shared SHARED ${SHADERC_SOURCES})
|
add_library(shaderc_shared SHARED ${SHADERC_SOURCES})
|
||||||
shaderc_default_compile_options(shaderc_shared)
|
shaderc_default_compile_options(shaderc_shared)
|
||||||
target_include_directories(shaderc_shared
|
target_include_directories(shaderc_shared
|
||||||
@@ -54,7 +47,7 @@ if(SHADERC_ENABLE_INSTALL)
|
@@ -41,7 +34,6 @@
|
||||||
|
PRIVATE SHADERC_IMPLEMENTATION
|
||||||
|
PUBLIC SHADERC_SHAREDLIB
|
||||||
|
)
|
||||||
|
-set_target_properties(shaderc_shared PROPERTIES SOVERSION 1)
|
||||||
|
|
||||||
|
if(SHADERC_ENABLE_INSTALL)
|
||||||
|
install(
|
||||||
|
@@ -54,7 +46,7 @@
|
||||||
DESTINATION
|
DESTINATION
|
||||||
${CMAKE_INSTALL_INCLUDEDIR}/shaderc)
|
${CMAKE_INSTALL_INCLUDEDIR}/shaderc)
|
||||||
|
|
||||||
|
@ -66,14 +74,14 @@ index df9a88d..b15e5d7 100644
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
|
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
@@ -69,20 +62,8 @@ set(SHADERC_LIBS
|
@@ -69,21 +61,9 @@
|
||||||
SPIRV-Tools
|
SPIRV-Tools
|
||||||
)
|
)
|
||||||
|
|
||||||
-target_link_libraries(shaderc PRIVATE ${SHADERC_LIBS})
|
-target_link_libraries(shaderc PRIVATE ${SHADERC_LIBS})
|
||||||
target_link_libraries(shaderc_shared PRIVATE ${SHADERC_LIBS})
|
target_link_libraries(shaderc_shared PRIVATE ${SHADERC_LIBS})
|
||||||
|
|
||||||
-shaderc_add_tests(
|
shaderc_add_tests(
|
||||||
- TEST_PREFIX shaderc
|
- TEST_PREFIX shaderc
|
||||||
- LINK_LIBS shaderc
|
- LINK_LIBS shaderc
|
||||||
- INCLUDE_DIRS include ${shaderc_SOURCE_DIR}/libshaderc_util/include ${glslang_SOURCE_DIR}
|
- INCLUDE_DIRS include ${shaderc_SOURCE_DIR}/libshaderc_util/include ${glslang_SOURCE_DIR}
|
||||||
|
@ -84,10 +92,11 @@ index df9a88d..b15e5d7 100644
|
||||||
- shaderc_cpp
|
- shaderc_cpp
|
||||||
- shaderc_private)
|
- shaderc_private)
|
||||||
-
|
-
|
||||||
shaderc_add_tests(
|
-shaderc_add_tests(
|
||||||
TEST_PREFIX shaderc_shared
|
TEST_PREFIX shaderc_shared
|
||||||
LINK_LIBS shaderc_shared SPIRV-Tools
|
LINK_LIBS shaderc_shared SPIRV-Tools
|
||||||
@@ -94,22 +75,6 @@ shaderc_add_tests(
|
INCLUDE_DIRS include ${shaderc_SOURCE_DIR}/libshaderc_util/include ${glslang_SOURCE_DIR}
|
||||||
|
@@ -94,22 +74,6 @@
|
||||||
shaderc_cpp
|
shaderc_cpp
|
||||||
shaderc_private)
|
shaderc_private)
|
||||||
|
|
||||||
|
|
|
@ -12,3 +12,16 @@
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND ${GIT_EXECUTABLE} describe --always --tags --dirty=+
|
COMMAND ${GIT_EXECUTABLE} describe --always --tags --dirty=+
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
@@ -409,9 +409,9 @@
|
||||||
|
|
||||||
|
target_compile_definitions(spirv-cross-c-shared PRIVATE SPVC_EXPORT_SYMBOLS)
|
||||||
|
|
||||||
|
- set_target_properties(spirv-cross-c-shared PROPERTIES
|
||||||
|
- VERSION ${SPIRV_CROSS_VERSION}
|
||||||
|
- SOVERSION ${spirv-cross-abi-major})
|
||||||
|
+ #set_target_properties(spirv-cross-c-shared PROPERTIES
|
||||||
|
+ # VERSION ${SPIRV_CROSS_VERSION}
|
||||||
|
+ # SOVERSION ${spirv-cross-abi-major})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (SPIRV_CROSS_CLI)
|
||||||
|
|
|
@ -1756,8 +1756,8 @@ bool GPU::CompileDisplayPipelines(bool display, bool deinterlace, bool chroma_sm
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> vso = g_gpu_device->CreateShader(GPUShaderStage::Vertex, vs);
|
std::unique_ptr<GPUShader> vso = g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GetLanguage(), vs);
|
||||||
std::unique_ptr<GPUShader> fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, fs);
|
std::unique_ptr<GPUShader> fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(), fs);
|
||||||
if (!vso || !fso)
|
if (!vso || !fso)
|
||||||
return false;
|
return false;
|
||||||
GL_OBJECT_NAME(vso, "Display Vertex Shader");
|
GL_OBJECT_NAME(vso, "Display Vertex Shader");
|
||||||
|
@ -1776,14 +1776,14 @@ bool GPU::CompileDisplayPipelines(bool display, bool deinterlace, bool chroma_sm
|
||||||
{
|
{
|
||||||
plconfig.SetTargetFormats(GPUTexture::Format::RGBA8);
|
plconfig.SetTargetFormats(GPUTexture::Format::RGBA8);
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> vso =
|
std::unique_ptr<GPUShader> vso = g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GetLanguage(),
|
||||||
g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GenerateScreenQuadVertexShader());
|
shadergen.GenerateScreenQuadVertexShader());
|
||||||
if (!vso)
|
if (!vso)
|
||||||
return false;
|
return false;
|
||||||
GL_OBJECT_NAME(vso, "Deinterlace Vertex Shader");
|
GL_OBJECT_NAME(vso, "Deinterlace Vertex Shader");
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> fso;
|
std::unique_ptr<GPUShader> fso;
|
||||||
if (!(fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment,
|
if (!(fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
shadergen.GenerateInterleavedFieldExtractFragmentShader())))
|
shadergen.GenerateInterleavedFieldExtractFragmentShader())))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -1806,7 +1806,7 @@ bool GPU::CompileDisplayPipelines(bool display, bool deinterlace, bool chroma_sm
|
||||||
|
|
||||||
case DisplayDeinterlacingMode::Weave:
|
case DisplayDeinterlacingMode::Weave:
|
||||||
{
|
{
|
||||||
if (!(fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment,
|
if (!(fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
shadergen.GenerateDeinterlaceWeaveFragmentShader())))
|
shadergen.GenerateDeinterlaceWeaveFragmentShader())))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -1826,7 +1826,7 @@ bool GPU::CompileDisplayPipelines(bool display, bool deinterlace, bool chroma_sm
|
||||||
|
|
||||||
case DisplayDeinterlacingMode::Blend:
|
case DisplayDeinterlacingMode::Blend:
|
||||||
{
|
{
|
||||||
if (!(fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment,
|
if (!(fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
shadergen.GenerateDeinterlaceBlendFragmentShader())))
|
shadergen.GenerateDeinterlaceBlendFragmentShader())))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -1846,8 +1846,8 @@ bool GPU::CompileDisplayPipelines(bool display, bool deinterlace, bool chroma_sm
|
||||||
|
|
||||||
case DisplayDeinterlacingMode::Adaptive:
|
case DisplayDeinterlacingMode::Adaptive:
|
||||||
{
|
{
|
||||||
fso =
|
fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateFastMADReconstructFragmentShader());
|
shadergen.GenerateFastMADReconstructFragmentShader());
|
||||||
if (!fso)
|
if (!fso)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1877,10 +1877,10 @@ bool GPU::CompileDisplayPipelines(bool display, bool deinterlace, bool chroma_sm
|
||||||
plconfig.layout = GPUPipeline::Layout::SingleTextureAndPushConstants;
|
plconfig.layout = GPUPipeline::Layout::SingleTextureAndPushConstants;
|
||||||
plconfig.SetTargetFormats(GPUTexture::Format::RGBA8);
|
plconfig.SetTargetFormats(GPUTexture::Format::RGBA8);
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> vso =
|
std::unique_ptr<GPUShader> vso = g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GetLanguage(),
|
||||||
g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GenerateScreenQuadVertexShader());
|
shadergen.GenerateScreenQuadVertexShader());
|
||||||
std::unique_ptr<GPUShader> fso =
|
std::unique_ptr<GPUShader> fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateChromaSmoothingFragmentShader());
|
shadergen.GenerateChromaSmoothingFragmentShader());
|
||||||
if (!vso || !fso)
|
if (!vso || !fso)
|
||||||
return false;
|
return false;
|
||||||
GL_OBJECT_NAME(vso, "Chroma Smoothing Vertex Shader");
|
GL_OBJECT_NAME(vso, "Chroma Smoothing Vertex Shader");
|
||||||
|
|
|
@ -813,8 +813,11 @@ bool GPU_HW::CompilePipelines()
|
||||||
for (u8 textured = 0; textured < 2; textured++)
|
for (u8 textured = 0; textured < 2; textured++)
|
||||||
{
|
{
|
||||||
const std::string vs = shadergen.GenerateBatchVertexShader(ConvertToBoolUnchecked(textured), m_pgxp_depth_buffer);
|
const std::string vs = shadergen.GenerateBatchVertexShader(ConvertToBoolUnchecked(textured), m_pgxp_depth_buffer);
|
||||||
if (!(batch_vertex_shaders[textured] = g_gpu_device->CreateShader(GPUShaderStage::Vertex, vs)))
|
if (!(batch_vertex_shaders[textured] =
|
||||||
|
g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GetLanguage(), vs)))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
progress.Increment();
|
progress.Increment();
|
||||||
}
|
}
|
||||||
|
@ -857,7 +860,8 @@ bool GPU_HW::CompilePipelines()
|
||||||
ConvertToBoolUnchecked(interlacing), ConvertToBoolUnchecked(check_mask));
|
ConvertToBoolUnchecked(interlacing), ConvertToBoolUnchecked(check_mask));
|
||||||
|
|
||||||
if (!(batch_fragment_shaders[render_mode][transparency_mode][texture_mode][check_mask][dithering]
|
if (!(batch_fragment_shaders[render_mode][transparency_mode][texture_mode][check_mask][dithering]
|
||||||
[interlacing] = g_gpu_device->CreateShader(GPUShaderStage::Fragment, fs)))
|
[interlacing] = g_gpu_device->CreateShader(GPUShaderStage::Fragment,
|
||||||
|
shadergen.GetLanguage(), fs)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1033,10 +1037,10 @@ bool GPU_HW::CompilePipelines()
|
||||||
|
|
||||||
if (m_wireframe_mode != GPUWireframeMode::Disabled)
|
if (m_wireframe_mode != GPUWireframeMode::Disabled)
|
||||||
{
|
{
|
||||||
std::unique_ptr<GPUShader> gs =
|
std::unique_ptr<GPUShader> gs = g_gpu_device->CreateShader(GPUShaderStage::Geometry, shadergen.GetLanguage(),
|
||||||
g_gpu_device->CreateShader(GPUShaderStage::Geometry, shadergen.GenerateWireframeGeometryShader());
|
shadergen.GenerateWireframeGeometryShader());
|
||||||
std::unique_ptr<GPUShader> fs =
|
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateWireframeFragmentShader());
|
shadergen.GenerateWireframeFragmentShader());
|
||||||
if (!gs || !fs)
|
if (!gs || !fs)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1069,8 +1073,8 @@ bool GPU_HW::CompilePipelines()
|
||||||
batch_shader_guard.Run();
|
batch_shader_guard.Run();
|
||||||
|
|
||||||
// use a depth of 1, that way writes will reset the depth
|
// use a depth of 1, that way writes will reset the depth
|
||||||
std::unique_ptr<GPUShader> fullscreen_quad_vertex_shader =
|
std::unique_ptr<GPUShader> fullscreen_quad_vertex_shader = g_gpu_device->CreateShader(
|
||||||
g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GenerateScreenQuadVertexShader(1.0f));
|
GPUShaderStage::Vertex, shadergen.GetLanguage(), shadergen.GenerateScreenQuadVertexShader(1.0f));
|
||||||
if (!fullscreen_quad_vertex_shader)
|
if (!fullscreen_quad_vertex_shader)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1090,7 +1094,7 @@ bool GPU_HW::CompilePipelines()
|
||||||
for (u8 interlaced = 0; interlaced < 2; interlaced++)
|
for (u8 interlaced = 0; interlaced < 2; interlaced++)
|
||||||
{
|
{
|
||||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(
|
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(
|
||||||
GPUShaderStage::Fragment,
|
GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
shadergen.GenerateVRAMFillFragmentShader(ConvertToBoolUnchecked(wrapped), ConvertToBoolUnchecked(interlaced)));
|
shadergen.GenerateVRAMFillFragmentShader(ConvertToBoolUnchecked(wrapped), ConvertToBoolUnchecked(interlaced)));
|
||||||
if (!fs)
|
if (!fs)
|
||||||
return false;
|
return false;
|
||||||
|
@ -1108,8 +1112,8 @@ bool GPU_HW::CompilePipelines()
|
||||||
|
|
||||||
// VRAM copy
|
// VRAM copy
|
||||||
{
|
{
|
||||||
std::unique_ptr<GPUShader> fs =
|
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateVRAMCopyFragmentShader());
|
shadergen.GenerateVRAMCopyFragmentShader());
|
||||||
if (!fs)
|
if (!fs)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1136,8 +1140,9 @@ bool GPU_HW::CompilePipelines()
|
||||||
{
|
{
|
||||||
const bool use_buffer = features.supports_texture_buffers;
|
const bool use_buffer = features.supports_texture_buffers;
|
||||||
const bool use_ssbo = features.texture_buffers_emulated_with_ssbo;
|
const bool use_ssbo = features.texture_buffers_emulated_with_ssbo;
|
||||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(
|
std::unique_ptr<GPUShader> fs =
|
||||||
GPUShaderStage::Fragment, shadergen.GenerateVRAMWriteFragmentShader(use_buffer, use_ssbo));
|
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
|
shadergen.GenerateVRAMWriteFragmentShader(use_buffer, use_ssbo));
|
||||||
if (!fs)
|
if (!fs)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1166,8 +1171,8 @@ bool GPU_HW::CompilePipelines()
|
||||||
|
|
||||||
// VRAM write replacement
|
// VRAM write replacement
|
||||||
{
|
{
|
||||||
std::unique_ptr<GPUShader> fs =
|
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateCopyFragmentShader());
|
shadergen.GenerateCopyFragmentShader());
|
||||||
if (!fs)
|
if (!fs)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1184,8 +1189,8 @@ bool GPU_HW::CompilePipelines()
|
||||||
// VRAM update depth
|
// VRAM update depth
|
||||||
if (needs_depth_buffer)
|
if (needs_depth_buffer)
|
||||||
{
|
{
|
||||||
std::unique_ptr<GPUShader> fs =
|
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateVRAMUpdateDepthFragmentShader());
|
shadergen.GenerateVRAMUpdateDepthFragmentShader());
|
||||||
if (!fs)
|
if (!fs)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1210,8 +1215,8 @@ bool GPU_HW::CompilePipelines()
|
||||||
|
|
||||||
// VRAM read
|
// VRAM read
|
||||||
{
|
{
|
||||||
std::unique_ptr<GPUShader> fs =
|
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateVRAMReadFragmentShader());
|
shadergen.GenerateVRAMReadFragmentShader());
|
||||||
if (!fs)
|
if (!fs)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1228,8 +1233,9 @@ bool GPU_HW::CompilePipelines()
|
||||||
{
|
{
|
||||||
for (u8 depth_24 = 0; depth_24 < 2; depth_24++)
|
for (u8 depth_24 = 0; depth_24 < 2; depth_24++)
|
||||||
{
|
{
|
||||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(
|
std::unique_ptr<GPUShader> fs =
|
||||||
GPUShaderStage::Fragment, shadergen.GenerateVRAMExtractFragmentShader(ConvertToBoolUnchecked(depth_24)));
|
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
|
shadergen.GenerateVRAMExtractFragmentShader(ConvertToBoolUnchecked(depth_24)));
|
||||||
if (!fs)
|
if (!fs)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1244,10 +1250,10 @@ bool GPU_HW::CompilePipelines()
|
||||||
|
|
||||||
if (m_downsample_mode == GPUDownsampleMode::Adaptive)
|
if (m_downsample_mode == GPUDownsampleMode::Adaptive)
|
||||||
{
|
{
|
||||||
std::unique_ptr<GPUShader> vs =
|
std::unique_ptr<GPUShader> vs = g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GetLanguage(),
|
||||||
g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GenerateAdaptiveDownsampleVertexShader());
|
shadergen.GenerateAdaptiveDownsampleVertexShader());
|
||||||
std::unique_ptr<GPUShader> fs =
|
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(
|
||||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateAdaptiveDownsampleMipFragmentShader(true));
|
GPUShaderStage::Fragment, shadergen.GetLanguage(), shadergen.GenerateAdaptiveDownsampleMipFragmentShader(true));
|
||||||
if (!vs || !fs)
|
if (!vs || !fs)
|
||||||
return false;
|
return false;
|
||||||
GL_OBJECT_NAME(fs, "Downsample Vertex Shader");
|
GL_OBJECT_NAME(fs, "Downsample Vertex Shader");
|
||||||
|
@ -1258,7 +1264,7 @@ bool GPU_HW::CompilePipelines()
|
||||||
return false;
|
return false;
|
||||||
GL_OBJECT_NAME(m_downsample_first_pass_pipeline, "Downsample First Pass Pipeline");
|
GL_OBJECT_NAME(m_downsample_first_pass_pipeline, "Downsample First Pass Pipeline");
|
||||||
|
|
||||||
fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment,
|
fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
shadergen.GenerateAdaptiveDownsampleMipFragmentShader(false));
|
shadergen.GenerateAdaptiveDownsampleMipFragmentShader(false));
|
||||||
if (!fs)
|
if (!fs)
|
||||||
return false;
|
return false;
|
||||||
|
@ -1268,7 +1274,8 @@ bool GPU_HW::CompilePipelines()
|
||||||
return false;
|
return false;
|
||||||
GL_OBJECT_NAME(m_downsample_mid_pass_pipeline, "Downsample Mid Pass Pipeline");
|
GL_OBJECT_NAME(m_downsample_mid_pass_pipeline, "Downsample Mid Pass Pipeline");
|
||||||
|
|
||||||
fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateAdaptiveDownsampleBlurFragmentShader());
|
fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
|
shadergen.GenerateAdaptiveDownsampleBlurFragmentShader());
|
||||||
if (!fs)
|
if (!fs)
|
||||||
return false;
|
return false;
|
||||||
GL_OBJECT_NAME(fs, "Downsample Blur Pass Fragment Shader");
|
GL_OBJECT_NAME(fs, "Downsample Blur Pass Fragment Shader");
|
||||||
|
@ -1278,7 +1285,7 @@ bool GPU_HW::CompilePipelines()
|
||||||
return false;
|
return false;
|
||||||
GL_OBJECT_NAME(m_downsample_blur_pass_pipeline, "Downsample Blur Pass Pipeline");
|
GL_OBJECT_NAME(m_downsample_blur_pass_pipeline, "Downsample Blur Pass Pipeline");
|
||||||
|
|
||||||
fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment,
|
fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
shadergen.GenerateAdaptiveDownsampleCompositeFragmentShader());
|
shadergen.GenerateAdaptiveDownsampleCompositeFragmentShader());
|
||||||
if (!fs)
|
if (!fs)
|
||||||
return false;
|
return false;
|
||||||
|
@ -1304,8 +1311,9 @@ bool GPU_HW::CompilePipelines()
|
||||||
}
|
}
|
||||||
else if (m_downsample_mode == GPUDownsampleMode::Box)
|
else if (m_downsample_mode == GPUDownsampleMode::Box)
|
||||||
{
|
{
|
||||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(
|
std::unique_ptr<GPUShader> fs =
|
||||||
GPUShaderStage::Fragment, shadergen.GenerateBoxSampleDownsampleFragmentShader(
|
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
|
shadergen.GenerateBoxSampleDownsampleFragmentShader(
|
||||||
m_resolution_scale / GetBoxDownsampleScale(m_resolution_scale)));
|
m_resolution_scale / GetBoxDownsampleScale(m_resolution_scale)));
|
||||||
if (!fs)
|
if (!fs)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -10,11 +10,11 @@ GPU_HW_ShaderGen::GPU_HW_ShaderGen(RenderAPI render_api, u32 resolution_scale, u
|
||||||
GPUTextureFilter texture_filtering, bool uv_limits, bool write_mask_as_depth,
|
GPUTextureFilter texture_filtering, bool uv_limits, bool write_mask_as_depth,
|
||||||
bool disable_color_perspective, bool supports_dual_source_blend,
|
bool disable_color_perspective, bool supports_dual_source_blend,
|
||||||
bool supports_framebuffer_fetch, bool debanding)
|
bool supports_framebuffer_fetch, bool debanding)
|
||||||
: ShaderGen(render_api, supports_dual_source_blend, supports_framebuffer_fetch), m_resolution_scale(resolution_scale),
|
: ShaderGen(render_api, GetShaderLanguageForAPI(render_api), supports_dual_source_blend, supports_framebuffer_fetch),
|
||||||
m_multisamples(multisamples), m_per_sample_shading(per_sample_shading), m_true_color(true_color),
|
m_resolution_scale(resolution_scale), m_multisamples(multisamples), m_per_sample_shading(per_sample_shading),
|
||||||
m_scaled_dithering(scaled_dithering), m_texture_filter(texture_filtering), m_uv_limits(uv_limits),
|
m_true_color(true_color), m_scaled_dithering(scaled_dithering), m_texture_filter(texture_filtering),
|
||||||
m_write_mask_as_depth(write_mask_as_depth), m_disable_color_perspective(disable_color_perspective),
|
m_uv_limits(uv_limits), m_write_mask_as_depth(write_mask_as_depth),
|
||||||
m_debanding(debanding)
|
m_disable_color_perspective(disable_color_perspective), m_debanding(debanding)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "gpu_shadergen.h"
|
#include "gpu_shadergen.h"
|
||||||
|
|
||||||
GPUShaderGen::GPUShaderGen(RenderAPI render_api, bool supports_dual_source_blend, bool supports_framebuffer_fetch)
|
GPUShaderGen::GPUShaderGen(RenderAPI render_api, bool supports_dual_source_blend, bool supports_framebuffer_fetch)
|
||||||
: ShaderGen(render_api, supports_dual_source_blend, supports_framebuffer_fetch)
|
: ShaderGen(render_api, GetShaderLanguageForAPI(render_api), supports_dual_source_blend, supports_framebuffer_fetch)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,4 +4,4 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
static constexpr u32 SHADER_CACHE_VERSION = 14;
|
static constexpr u32 SHADER_CACHE_VERSION = 15;
|
||||||
|
|
|
@ -209,7 +209,7 @@ if(WIN32)
|
||||||
)
|
)
|
||||||
#set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/translations")
|
#set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/translations")
|
||||||
|
|
||||||
set(DEPS_TO_COPY freetype.dll harfbuzz.dll libjpeg.dll libpng16.dll libsharpyuv.dll libwebp.dll SDL2.dll shaderc_shared.dll zlib1.dll zstd.dll)
|
set(DEPS_TO_COPY freetype.dll harfbuzz.dll libjpeg.dll libpng16.dll libsharpyuv.dll libwebp.dll SDL2.dll shaderc_shared.dll spirv-cross-c-shared.dll zlib1.dll zstd.dll)
|
||||||
foreach(DEP ${DEPS_TO_COPY})
|
foreach(DEP ${DEPS_TO_COPY})
|
||||||
list(APPEND DEP_BINS "${CMAKE_PREFIX_PATH}/bin/${DEP}")
|
list(APPEND DEP_BINS "${CMAKE_PREFIX_PATH}/bin/${DEP}")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
@ -244,8 +244,9 @@ elseif(APPLE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Copy shaderc into the bundle
|
# Copy shaderc into the bundle
|
||||||
target_sources(duckstation-qt PRIVATE "${SHADERC_LIBRARY}")
|
get_target_property(SPIRV_CROSS_LIBRARY spirv-cross-c-shared IMPORTED_LOCATION_RELEASE)
|
||||||
set_source_files_properties("${SHADERC_LIBRARY}" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks)
|
target_sources(duckstation-qt PRIVATE "${SHADERC_LIBRARY}" "${SPIRV_CROSS_LIBRARY}")
|
||||||
|
set_source_files_properties("${SHADERC_LIBRARY}" "${SPIRV_CROSS_LIBRARY}" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks)
|
||||||
|
|
||||||
# Copy icon into the bundle
|
# Copy icon into the bundle
|
||||||
target_sources(duckstation-qt PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/DuckStation.icns")
|
target_sources(duckstation-qt PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/DuckStation.icns")
|
||||||
|
|
|
@ -248,7 +248,7 @@ elseif(APPLE)
|
||||||
find_library(IOK_LIBRARY IOKit REQUIRED)
|
find_library(IOK_LIBRARY IOKit REQUIRED)
|
||||||
find_library(METAL_LIBRARY Metal)
|
find_library(METAL_LIBRARY Metal)
|
||||||
find_library(QUARTZCORE_LIBRARY QuartzCore)
|
find_library(QUARTZCORE_LIBRARY QuartzCore)
|
||||||
target_link_libraries(util PRIVATE ${METAL_LIBRARY} ${QUARTZCORE_LIBRARY} ${IOK_LIBRARY} spirv-cross-c-shared)
|
target_link_libraries(util PRIVATE ${METAL_LIBRARY} ${QUARTZCORE_LIBRARY} ${IOK_LIBRARY})
|
||||||
set_source_files_properties(${MAC_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE)
|
set_source_files_properties(${MAC_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE)
|
||||||
elseif(NOT ANDROID)
|
elseif(NOT ANDROID)
|
||||||
target_sources(util PRIVATE
|
target_sources(util PRIVATE
|
||||||
|
|
|
@ -68,9 +68,11 @@ public:
|
||||||
void ClearDepth(GPUTexture* t, float d) override;
|
void ClearDepth(GPUTexture* t, float d) override;
|
||||||
void InvalidateRenderTarget(GPUTexture* t) override;
|
void InvalidateRenderTarget(GPUTexture* t) override;
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) override;
|
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
|
||||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
Error* error) override;
|
||||||
const char* entry_point, DynamicHeapArray<u8>* binary) override;
|
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||||
|
std::string_view source, const char* entry_point,
|
||||||
|
DynamicHeapArray<u8>* out_binary, Error* error) override;
|
||||||
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override;
|
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override;
|
||||||
|
|
||||||
void PushDebugGroup(const char* name) override;
|
void PushDebugGroup(const char* name) override;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||||
// 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)
|
||||||
|
|
||||||
#include "d3d11_pipeline.h"
|
#include "d3d11_pipeline.h"
|
||||||
#include "d3d11_device.h"
|
#include "d3d11_device.h"
|
||||||
#include "d3d_common.h"
|
#include "d3d_common.h"
|
||||||
|
|
||||||
|
#include "common/error.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
|
@ -51,7 +52,8 @@ void D3D11Shader::SetDebugName(std::string_view name)
|
||||||
SetD3DDebugObjectName(m_shader.Get(), name);
|
SetD3DDebugObjectName(m_shader.Get(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> D3D11Device::CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data)
|
std::unique_ptr<GPUShader> D3D11Device::CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
|
||||||
|
Error* error)
|
||||||
{
|
{
|
||||||
ComPtr<ID3D11DeviceChild> shader;
|
ComPtr<ID3D11DeviceChild> shader;
|
||||||
std::vector<u8> bytecode;
|
std::vector<u8> bytecode;
|
||||||
|
@ -87,21 +89,31 @@ std::unique_ptr<GPUShader> D3D11Device::CreateShaderFromBinary(GPUShaderStage st
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(hr) || !shader)
|
if (FAILED(hr) || !shader)
|
||||||
|
{
|
||||||
|
Error::SetHResult(error, "Create[Typed]Shader() failed: ", hr);
|
||||||
return {};
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
return std::unique_ptr<GPUShader>(new D3D11Shader(stage, std::move(shader), std::move(bytecode)));
|
return std::unique_ptr<GPUShader>(new D3D11Shader(stage, std::move(shader), std::move(bytecode)));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> D3D11Device::CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
std::unique_ptr<GPUShader> D3D11Device::CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||||
const char* entry_point,
|
std::string_view source, const char* entry_point,
|
||||||
DynamicHeapArray<u8>* out_binary)
|
DynamicHeapArray<u8>* out_binary, Error* error)
|
||||||
{
|
{
|
||||||
|
const u32 shader_model = D3DCommon::GetShaderModelForFeatureLevel(m_device->GetFeatureLevel());
|
||||||
|
if (language != GPUShaderLanguage::HLSL)
|
||||||
|
{
|
||||||
|
return TranspileAndCreateShaderFromSource(stage, language, source, entry_point, GPUShaderLanguage::HLSL,
|
||||||
|
shader_model, out_binary, error);
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<DynamicHeapArray<u8>> bytecode =
|
std::optional<DynamicHeapArray<u8>> bytecode =
|
||||||
D3DCommon::CompileShader(m_device->GetFeatureLevel(), m_debug_device, stage, source, entry_point);
|
D3DCommon::CompileShader(shader_model, m_debug_device, stage, source, entry_point, error);
|
||||||
if (!bytecode.has_value())
|
if (!bytecode.has_value())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> ret = CreateShaderFromBinary(stage, bytecode.value());
|
std::unique_ptr<GPUShader> ret = CreateShaderFromBinary(stage, bytecode.value(), error);
|
||||||
if (ret && out_binary)
|
if (ret && out_binary)
|
||||||
*out_binary = std::move(bytecode.value());
|
*out_binary = std::move(bytecode.value());
|
||||||
|
|
||||||
|
|
|
@ -90,9 +90,11 @@ public:
|
||||||
void ClearDepth(GPUTexture* t, float d) override;
|
void ClearDepth(GPUTexture* t, float d) override;
|
||||||
void InvalidateRenderTarget(GPUTexture* t) override;
|
void InvalidateRenderTarget(GPUTexture* t) override;
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) override;
|
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
|
||||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
Error* error) override;
|
||||||
const char* entry_point, DynamicHeapArray<u8>* out_binary) override;
|
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||||
|
std::string_view source, const char* entry_point,
|
||||||
|
DynamicHeapArray<u8>* out_binary, Error* error) override;
|
||||||
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override;
|
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override;
|
||||||
|
|
||||||
void PushDebugGroup(const char* name) override;
|
void PushDebugGroup(const char* name) override;
|
||||||
|
|
|
@ -25,23 +25,31 @@ void D3D12Shader::SetDebugName(std::string_view name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> D3D12Device::CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data)
|
std::unique_ptr<GPUShader> D3D12Device::CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
|
||||||
|
Error* error)
|
||||||
{
|
{
|
||||||
// Can't do much at this point.
|
// Can't do much at this point.
|
||||||
std::vector bytecode(data.begin(), data.end());
|
std::vector bytecode(data.begin(), data.end());
|
||||||
return std::unique_ptr<GPUShader>(new D3D12Shader(stage, std::move(bytecode)));
|
return std::unique_ptr<GPUShader>(new D3D12Shader(stage, std::move(bytecode)));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> D3D12Device::CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
std::unique_ptr<GPUShader> D3D12Device::CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||||
const char* entry_point,
|
std::string_view source, const char* entry_point,
|
||||||
DynamicHeapArray<u8>* out_binary)
|
DynamicHeapArray<u8>* out_binary, Error* error)
|
||||||
{
|
{
|
||||||
|
const u32 shader_model = D3DCommon::GetShaderModelForFeatureLevel(m_feature_level);
|
||||||
|
if (language != GPUShaderLanguage::HLSL)
|
||||||
|
{
|
||||||
|
return TranspileAndCreateShaderFromSource(stage, language, source, entry_point, GPUShaderLanguage::HLSL,
|
||||||
|
shader_model, out_binary, error);
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<DynamicHeapArray<u8>> bytecode =
|
std::optional<DynamicHeapArray<u8>> bytecode =
|
||||||
D3DCommon::CompileShader(m_feature_level, m_debug_device, stage, source, entry_point);
|
D3DCommon::CompileShader(shader_model, m_debug_device, stage, source, entry_point, error);
|
||||||
if (!bytecode.has_value())
|
if (!bytecode.has_value())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> ret = CreateShaderFromBinary(stage, bytecode.value());
|
std::unique_ptr<GPUShader> ret = CreateShaderFromBinary(stage, bytecode.value(), error);
|
||||||
if (ret && out_binary)
|
if (ret && out_binary)
|
||||||
*out_binary = std::move(bytecode.value());
|
*out_binary = std::move(bytecode.value());
|
||||||
|
|
||||||
|
|
|
@ -372,14 +372,33 @@ std::string D3DCommon::GetDriverVersionFromLUID(const LUID& luid)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<DynamicHeapArray<u8>> D3DCommon::CompileShader(D3D_FEATURE_LEVEL feature_level, bool debug_device,
|
u32 D3DCommon::GetShaderModelForFeatureLevel(D3D_FEATURE_LEVEL feature_level)
|
||||||
GPUShaderStage stage, std::string_view source,
|
|
||||||
const char* entry_point)
|
|
||||||
{
|
{
|
||||||
const char* target;
|
|
||||||
switch (feature_level)
|
switch (feature_level)
|
||||||
{
|
{
|
||||||
case D3D_FEATURE_LEVEL_10_0:
|
case D3D_FEATURE_LEVEL_10_0:
|
||||||
|
return 40;
|
||||||
|
|
||||||
|
case D3D_FEATURE_LEVEL_10_1:
|
||||||
|
return 41;
|
||||||
|
|
||||||
|
case D3D_FEATURE_LEVEL_11_0:
|
||||||
|
return 50;
|
||||||
|
|
||||||
|
case D3D_FEATURE_LEVEL_11_1:
|
||||||
|
default:
|
||||||
|
return 51;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<DynamicHeapArray<u8>> D3DCommon::CompileShader(u32 shader_model, bool debug_device, GPUShaderStage stage,
|
||||||
|
std::string_view source, const char* entry_point,
|
||||||
|
Error* error)
|
||||||
|
{
|
||||||
|
const char* target;
|
||||||
|
switch (shader_model)
|
||||||
|
{
|
||||||
|
case 40:
|
||||||
{
|
{
|
||||||
static constexpr std::array<const char*, static_cast<u32>(GPUShaderStage::MaxCount)> targets = {
|
static constexpr std::array<const char*, static_cast<u32>(GPUShaderStage::MaxCount)> targets = {
|
||||||
{"vs_4_0", "ps_4_0", "gs_4_0", "cs_4_0"}};
|
{"vs_4_0", "ps_4_0", "gs_4_0", "cs_4_0"}};
|
||||||
|
@ -387,7 +406,7 @@ std::optional<DynamicHeapArray<u8>> D3DCommon::CompileShader(D3D_FEATURE_LEVEL f
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_10_1:
|
case 41:
|
||||||
{
|
{
|
||||||
static constexpr std::array<const char*, static_cast<u32>(GPUShaderStage::MaxCount)> targets = {
|
static constexpr std::array<const char*, static_cast<u32>(GPUShaderStage::MaxCount)> targets = {
|
||||||
{"vs_4_1", "ps_4_1", "gs_4_0", "cs_4_1"}};
|
{"vs_4_1", "ps_4_1", "gs_4_0", "cs_4_1"}};
|
||||||
|
@ -395,7 +414,7 @@ std::optional<DynamicHeapArray<u8>> D3DCommon::CompileShader(D3D_FEATURE_LEVEL f
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_11_0:
|
case 50:
|
||||||
{
|
{
|
||||||
static constexpr std::array<const char*, static_cast<u32>(GPUShaderStage::MaxCount)> targets = {
|
static constexpr std::array<const char*, static_cast<u32>(GPUShaderStage::MaxCount)> targets = {
|
||||||
{"vs_5_0", "ps_5_0", "gs_5_0", "cs_5_0"}};
|
{"vs_5_0", "ps_5_0", "gs_5_0", "cs_5_0"}};
|
||||||
|
@ -403,14 +422,17 @@ std::optional<DynamicHeapArray<u8>> D3DCommon::CompileShader(D3D_FEATURE_LEVEL f
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case D3D_FEATURE_LEVEL_11_1:
|
case 51:
|
||||||
default:
|
|
||||||
{
|
{
|
||||||
static constexpr std::array<const char*, static_cast<u32>(GPUShaderStage::MaxCount)> targets = {
|
static constexpr std::array<const char*, static_cast<u32>(GPUShaderStage::MaxCount)> targets = {
|
||||||
{"vs_5_1", "ps_5_1", "gs_5_1", "cs_5_1"}};
|
{"vs_5_1", "ps_5_1", "gs_5_1", "cs_5_1"}};
|
||||||
target = targets[static_cast<int>(stage)];
|
target = targets[static_cast<int>(stage)];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Error::SetStringFmt(error, "Unknown shader model: {}", shader_model);
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr UINT flags_non_debug = D3DCOMPILE_OPTIMIZATION_LEVEL3;
|
static constexpr UINT flags_non_debug = D3DCOMPILE_OPTIMIZATION_LEVEL3;
|
||||||
|
@ -424,13 +446,16 @@ std::optional<DynamicHeapArray<u8>> D3DCommon::CompileShader(D3D_FEATURE_LEVEL f
|
||||||
|
|
||||||
std::string_view error_string;
|
std::string_view error_string;
|
||||||
if (error_blob)
|
if (error_blob)
|
||||||
|
{
|
||||||
error_string =
|
error_string =
|
||||||
std::string_view(static_cast<const char*>(error_blob->GetBufferPointer()), error_blob->GetBufferSize());
|
std::string_view(static_cast<const char*>(error_blob->GetBufferPointer()), error_blob->GetBufferSize());
|
||||||
|
}
|
||||||
|
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
ERROR_LOG("Failed to compile '{}':\n{}", target, error_string);
|
ERROR_LOG("Failed to compile '{}':\n{}", target, error_string);
|
||||||
GPUDevice::DumpBadShader(source, error_string);
|
GPUDevice::DumpBadShader(source, error_string);
|
||||||
|
Error::SetHResult(error, "D3DCompile() failed: ", hr);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,9 +60,10 @@ std::string GetAdapterName(IDXGIAdapter1* adapter);
|
||||||
// returns the driver version from the registry as a string
|
// returns the driver version from the registry as a string
|
||||||
std::string GetDriverVersionFromLUID(const LUID& luid);
|
std::string GetDriverVersionFromLUID(const LUID& luid);
|
||||||
|
|
||||||
std::optional<DynamicHeapArray<u8>> CompileShader(D3D_FEATURE_LEVEL feature_level, bool debug_device,
|
u32 GetShaderModelForFeatureLevel(D3D_FEATURE_LEVEL feature_level);
|
||||||
GPUShaderStage stage, std::string_view source,
|
|
||||||
const char* entry_point);
|
std::optional<DynamicHeapArray<u8>> CompileShader(u32 shader_model, bool debug_device, GPUShaderStage stage,
|
||||||
|
std::string_view source, const char* entry_point, Error* error);
|
||||||
|
|
||||||
struct DXGIFormatMapping
|
struct DXGIFormatMapping
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,11 +13,14 @@
|
||||||
#include "common/file_system.h"
|
#include "common/file_system.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "common/path.h"
|
#include "common/path.h"
|
||||||
|
#include "common/scoped_guard.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
#include "common/timer.h"
|
#include "common/timer.h"
|
||||||
|
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
#include "shaderc/shaderc.h"
|
||||||
|
#include "spirv_cross/spirv_cross_c.h"
|
||||||
#include "xxhash.h"
|
#include "xxhash.h"
|
||||||
|
|
||||||
Log_SetChannel(GPUDevice);
|
Log_SetChannel(GPUDevice);
|
||||||
|
@ -37,10 +40,6 @@ Log_SetChannel(GPUDevice);
|
||||||
#include "vulkan_device.h"
|
#include "vulkan_device.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ENABLE_VULKAN) || defined(__APPLE__)
|
|
||||||
#include "shaderc/shaderc.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::unique_ptr<GPUDevice> g_gpu_device;
|
std::unique_ptr<GPUDevice> g_gpu_device;
|
||||||
|
|
||||||
static std::string s_pipeline_cache_path;
|
static std::string s_pipeline_cache_path;
|
||||||
|
@ -269,6 +268,24 @@ const char* GPUDevice::RenderAPIToString(RenderAPI api)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* GPUDevice::ShaderLanguageToString(GPUShaderLanguage language)
|
||||||
|
{
|
||||||
|
switch (language)
|
||||||
|
{
|
||||||
|
// clang-format off
|
||||||
|
#define CASE(x) case GPUShaderLanguage::x: return #x
|
||||||
|
CASE(HLSL);
|
||||||
|
CASE(GLSL);
|
||||||
|
CASE(GLSLES);
|
||||||
|
CASE(MSL);
|
||||||
|
CASE(SPV);
|
||||||
|
#undef CASE
|
||||||
|
// clang-format on
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool GPUDevice::IsSameRenderAPI(RenderAPI lhs, RenderAPI rhs)
|
bool GPUDevice::IsSameRenderAPI(RenderAPI lhs, RenderAPI rhs)
|
||||||
{
|
{
|
||||||
return (lhs == rhs || ((lhs == RenderAPI::OpenGL || lhs == RenderAPI::OpenGLES) &&
|
return (lhs == rhs || ((lhs == RenderAPI::OpenGL || lhs == RenderAPI::OpenGLES) &&
|
||||||
|
@ -300,9 +317,9 @@ bool GPUDevice::Create(std::string_view adapter, std::string_view shader_cache_p
|
||||||
|
|
||||||
OpenShaderCache(shader_cache_path, shader_cache_version);
|
OpenShaderCache(shader_cache_path, shader_cache_version);
|
||||||
|
|
||||||
if (!CreateResources())
|
if (!CreateResources(error))
|
||||||
{
|
{
|
||||||
Error::SetStringView(error, "Failed to create base resources.");
|
Error::AddPrefix(error, "Failed to create base resources.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,18 +476,23 @@ bool GPUDevice::AcquireWindow(bool recreate_window)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPUDevice::CreateResources()
|
bool GPUDevice::CreateResources(Error* error)
|
||||||
{
|
{
|
||||||
if (!(m_nearest_sampler = CreateSampler(GPUSampler::GetNearestConfig())))
|
if (!(m_nearest_sampler = CreateSampler(GPUSampler::GetNearestConfig())) ||
|
||||||
|
!(m_linear_sampler = CreateSampler(GPUSampler::GetLinearConfig())))
|
||||||
|
{
|
||||||
|
Error::SetStringView(error, "Failed to create samplers");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(m_linear_sampler = CreateSampler(GPUSampler::GetLinearConfig())))
|
const RenderAPI render_api = GetRenderAPI();
|
||||||
return false;
|
ShaderGen shadergen(render_api, ShaderGen::GetShaderLanguageForAPI(render_api), m_features.dual_source_blend,
|
||||||
|
m_features.framebuffer_fetch);
|
||||||
|
|
||||||
ShaderGen shadergen(GetRenderAPI(), m_features.dual_source_blend, m_features.framebuffer_fetch);
|
std::unique_ptr<GPUShader> imgui_vs =
|
||||||
|
CreateShader(GPUShaderStage::Vertex, shadergen.GetLanguage(), shadergen.GenerateImGuiVertexShader(), error);
|
||||||
std::unique_ptr<GPUShader> imgui_vs = CreateShader(GPUShaderStage::Vertex, shadergen.GenerateImGuiVertexShader());
|
std::unique_ptr<GPUShader> imgui_fs =
|
||||||
std::unique_ptr<GPUShader> imgui_fs = CreateShader(GPUShaderStage::Fragment, shadergen.GenerateImGuiFragmentShader());
|
CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(), shadergen.GenerateImGuiFragmentShader(), error);
|
||||||
if (!imgui_vs || !imgui_fs)
|
if (!imgui_vs || !imgui_fs)
|
||||||
return false;
|
return false;
|
||||||
GL_OBJECT_NAME(imgui_vs, "ImGui Vertex Shader");
|
GL_OBJECT_NAME(imgui_vs, "ImGui Vertex Shader");
|
||||||
|
@ -505,7 +527,7 @@ bool GPUDevice::CreateResources()
|
||||||
m_imgui_pipeline = CreatePipeline(plconfig);
|
m_imgui_pipeline = CreatePipeline(plconfig);
|
||||||
if (!m_imgui_pipeline)
|
if (!m_imgui_pipeline)
|
||||||
{
|
{
|
||||||
ERROR_LOG("Failed to compile ImGui pipeline.");
|
Error::SetStringView(error, "Failed to compile ImGui pipeline.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
GL_OBJECT_NAME(m_imgui_pipeline, "ImGui Pipeline");
|
GL_OBJECT_NAME(m_imgui_pipeline, "ImGui Pipeline");
|
||||||
|
@ -642,21 +664,22 @@ void GPUDevice::InvalidateRenderTarget(GPUTexture* t)
|
||||||
t->SetState(GPUTexture::State::Invalidated);
|
t->SetState(GPUTexture::State::Invalidated);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> GPUDevice::CreateShader(GPUShaderStage stage, std::string_view source,
|
std::unique_ptr<GPUShader> GPUDevice::CreateShader(GPUShaderStage stage, GPUShaderLanguage language,
|
||||||
|
std::string_view source, Error* error /* = nullptr */,
|
||||||
const char* entry_point /* = "main" */)
|
const char* entry_point /* = "main" */)
|
||||||
{
|
{
|
||||||
std::unique_ptr<GPUShader> shader;
|
std::unique_ptr<GPUShader> shader;
|
||||||
if (!m_shader_cache.IsOpen())
|
if (!m_shader_cache.IsOpen())
|
||||||
{
|
{
|
||||||
shader = CreateShaderFromSource(stage, source, entry_point, nullptr);
|
shader = CreateShaderFromSource(stage, language, source, entry_point, nullptr, error);
|
||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GPUShaderCache::CacheIndexKey key = m_shader_cache.GetCacheKey(stage, source, entry_point);
|
const GPUShaderCache::CacheIndexKey key = m_shader_cache.GetCacheKey(stage, language, source, entry_point);
|
||||||
DynamicHeapArray<u8> binary;
|
DynamicHeapArray<u8> binary;
|
||||||
if (m_shader_cache.Lookup(key, &binary))
|
if (m_shader_cache.Lookup(key, &binary))
|
||||||
{
|
{
|
||||||
shader = CreateShaderFromBinary(stage, binary);
|
shader = CreateShaderFromBinary(stage, binary, error);
|
||||||
if (shader)
|
if (shader)
|
||||||
return shader;
|
return shader;
|
||||||
|
|
||||||
|
@ -664,7 +687,7 @@ std::unique_ptr<GPUShader> GPUDevice::CreateShader(GPUShaderStage stage, std::st
|
||||||
m_shader_cache.Clear();
|
m_shader_cache.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
shader = CreateShaderFromSource(stage, source, entry_point, &binary);
|
shader = CreateShaderFromSource(stage, language, source, entry_point, &binary, error);
|
||||||
if (!shader)
|
if (!shader)
|
||||||
return shader;
|
return shader;
|
||||||
|
|
||||||
|
@ -1095,7 +1118,6 @@ std::unique_ptr<GPUDevice> GPUDevice::CreateDeviceForAPI(RenderAPI api)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ENABLE_VULKAN) || defined(__APPLE__)
|
|
||||||
#define SHADERC_FUNCTIONS(X) \
|
#define SHADERC_FUNCTIONS(X) \
|
||||||
X(shaderc_compiler_initialize) \
|
X(shaderc_compiler_initialize) \
|
||||||
X(shaderc_compiler_release) \
|
X(shaderc_compiler_release) \
|
||||||
|
@ -1113,82 +1135,171 @@ std::unique_ptr<GPUDevice> GPUDevice::CreateDeviceForAPI(RenderAPI api)
|
||||||
X(shaderc_result_get_bytes) \
|
X(shaderc_result_get_bytes) \
|
||||||
X(shaderc_result_get_error_message)
|
X(shaderc_result_get_error_message)
|
||||||
|
|
||||||
// TODO: NOT thread safe, yet.
|
#define SPIRV_CROSS_FUNCTIONS(X) \
|
||||||
namespace dyn_shaderc {
|
X(spvc_context_create) \
|
||||||
static bool Open();
|
X(spvc_context_destroy) \
|
||||||
static void Close();
|
X(spvc_context_set_error_callback) \
|
||||||
|
X(spvc_context_parse_spirv) \
|
||||||
|
X(spvc_context_create_compiler) \
|
||||||
|
X(spvc_compiler_create_compiler_options) \
|
||||||
|
X(spvc_compiler_create_shader_resources) \
|
||||||
|
X(spvc_compiler_get_execution_model) \
|
||||||
|
X(spvc_compiler_options_set_bool) \
|
||||||
|
X(spvc_compiler_options_set_uint) \
|
||||||
|
X(spvc_compiler_install_compiler_options) \
|
||||||
|
X(spvc_compiler_compile) \
|
||||||
|
X(spvc_resources_get_resource_list_for_type)
|
||||||
|
|
||||||
static DynamicLibrary s_library;
|
#ifdef _WIN32
|
||||||
static shaderc_compiler_t s_compiler = nullptr;
|
#define SPIRV_CROSS_HLSL_FUNCTIONS(X) X(spvc_compiler_hlsl_add_resource_binding)
|
||||||
|
#else
|
||||||
|
#define SPIRV_CROSS_HLSL_FUNCTIONS(X)
|
||||||
|
#endif
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#define SPIRV_CROSS_MSL_FUNCTIONS(X) X(spvc_compiler_msl_add_resource_binding)
|
||||||
|
#else
|
||||||
|
#define SPIRV_CROSS_MSL_FUNCTIONS(X)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TODO: NOT thread safe, yet.
|
||||||
|
namespace dyn_libs {
|
||||||
|
static bool OpenShaderc(Error* error);
|
||||||
|
static void CloseShaderc();
|
||||||
|
static bool OpenSpirvCross(Error* error);
|
||||||
|
static void CloseSpirvCross();
|
||||||
|
static void CloseAll();
|
||||||
|
|
||||||
|
static DynamicLibrary s_shaderc_library;
|
||||||
|
static DynamicLibrary s_spirv_cross_library;
|
||||||
|
|
||||||
|
static shaderc_compiler_t s_shaderc_compiler = nullptr;
|
||||||
|
|
||||||
|
static bool s_close_registered = false;
|
||||||
|
|
||||||
#define ADD_FUNC(F) static decltype(&::F) F;
|
#define ADD_FUNC(F) static decltype(&::F) F;
|
||||||
SHADERC_FUNCTIONS(ADD_FUNC)
|
SHADERC_FUNCTIONS(ADD_FUNC)
|
||||||
|
SPIRV_CROSS_FUNCTIONS(ADD_FUNC)
|
||||||
|
SPIRV_CROSS_HLSL_FUNCTIONS(ADD_FUNC)
|
||||||
|
SPIRV_CROSS_MSL_FUNCTIONS(ADD_FUNC)
|
||||||
#undef ADD_FUNC
|
#undef ADD_FUNC
|
||||||
|
|
||||||
} // namespace dyn_shaderc
|
} // namespace dyn_libs
|
||||||
|
|
||||||
bool dyn_shaderc::Open()
|
bool dyn_libs::OpenShaderc(Error* error)
|
||||||
{
|
{
|
||||||
if (s_library.IsOpen())
|
if (s_shaderc_library.IsOpen())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Error error;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
const std::string libname = DynamicLibrary::GetVersionedFilename("shaderc_shared");
|
const std::string libname = DynamicLibrary::GetVersionedFilename("shaderc_shared");
|
||||||
#else
|
if (!s_shaderc_library.Open(libname.c_str(), error))
|
||||||
// Use versioned, bundle post-processing adds it..
|
|
||||||
const std::string libname = DynamicLibrary::GetVersionedFilename("shaderc_shared", 1);
|
|
||||||
#endif
|
|
||||||
if (!s_library.Open(libname.c_str(), &error))
|
|
||||||
{
|
{
|
||||||
ERROR_LOG("Failed to load shaderc: {}", error.GetDescription());
|
Error::AddPrefix(error, "Failed to load shaderc: ");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LOAD_FUNC(F) \
|
#define LOAD_FUNC(F) \
|
||||||
if (!s_library.GetSymbol(#F, &F)) \
|
if (!s_shaderc_library.GetSymbol(#F, &F)) \
|
||||||
{ \
|
{ \
|
||||||
ERROR_LOG("Failed to find function {}", #F); \
|
Error::SetStringFmt(error, "Failed to find function {}", #F); \
|
||||||
Close(); \
|
CloseShaderc(); \
|
||||||
return false; \
|
return false; \
|
||||||
}
|
}
|
||||||
|
|
||||||
SHADERC_FUNCTIONS(LOAD_FUNC)
|
SHADERC_FUNCTIONS(LOAD_FUNC)
|
||||||
#undef LOAD_FUNC
|
#undef LOAD_FUNC
|
||||||
|
|
||||||
s_compiler = shaderc_compiler_initialize();
|
s_shaderc_compiler = shaderc_compiler_initialize();
|
||||||
if (!s_compiler)
|
if (!s_shaderc_compiler)
|
||||||
{
|
{
|
||||||
ERROR_LOG("shaderc_compiler_initialize() failed");
|
Error::SetStringView(error, "shaderc_compiler_initialize() failed");
|
||||||
Close();
|
CloseShaderc();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::atexit(&dyn_shaderc::Close);
|
if (!s_close_registered)
|
||||||
|
{
|
||||||
|
s_close_registered = true;
|
||||||
|
std::atexit(&dyn_libs::CloseAll);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dyn_shaderc::Close()
|
void dyn_libs::CloseShaderc()
|
||||||
{
|
{
|
||||||
if (s_compiler)
|
if (s_shaderc_compiler)
|
||||||
{
|
{
|
||||||
shaderc_compiler_release(s_compiler);
|
shaderc_compiler_release(s_shaderc_compiler);
|
||||||
s_compiler = nullptr;
|
s_shaderc_compiler = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define UNLOAD_FUNC(F) F = nullptr;
|
#define UNLOAD_FUNC(F) F = nullptr;
|
||||||
SHADERC_FUNCTIONS(UNLOAD_FUNC)
|
SHADERC_FUNCTIONS(UNLOAD_FUNC)
|
||||||
#undef UNLOAD_FUNC
|
#undef UNLOAD_FUNC
|
||||||
|
|
||||||
s_library.Close();
|
s_shaderc_library.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef SHADERC_FUNCTIONS
|
bool dyn_libs::OpenSpirvCross(Error* error)
|
||||||
#undef SHADERC_INIT_FUNCTIONS
|
{
|
||||||
|
if (s_spirv_cross_library.IsOpen())
|
||||||
|
return true;
|
||||||
|
|
||||||
bool GPUDevice::CompileGLSLShaderToVulkanSpv(GPUShaderStage stage, std::string_view source, const char* entry_point,
|
const std::string libname = DynamicLibrary::GetVersionedFilename("spirv-cross-c-shared");
|
||||||
bool nonsemantic_debug_info, DynamicHeapArray<u8>* out_binary)
|
if (!s_spirv_cross_library.Open(libname.c_str(), error))
|
||||||
|
{
|
||||||
|
Error::AddPrefix(error, "Failed to load spirv-cross: ");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOAD_FUNC(F) \
|
||||||
|
if (!s_spirv_cross_library.GetSymbol(#F, &F)) \
|
||||||
|
{ \
|
||||||
|
Error::SetStringFmt(error, "Failed to find function {}", #F); \
|
||||||
|
CloseShaderc(); \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
|
SPIRV_CROSS_FUNCTIONS(LOAD_FUNC)
|
||||||
|
SPIRV_CROSS_HLSL_FUNCTIONS(LOAD_FUNC)
|
||||||
|
SPIRV_CROSS_MSL_FUNCTIONS(LOAD_FUNC)
|
||||||
|
#undef LOAD_FUNC
|
||||||
|
|
||||||
|
if (!s_close_registered)
|
||||||
|
{
|
||||||
|
s_close_registered = true;
|
||||||
|
std::atexit(&dyn_libs::CloseAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dyn_libs::CloseSpirvCross()
|
||||||
|
{
|
||||||
|
#define UNLOAD_FUNC(F) F = nullptr;
|
||||||
|
SPIRV_CROSS_FUNCTIONS(UNLOAD_FUNC)
|
||||||
|
SPIRV_CROSS_HLSL_FUNCTIONS(UNLOAD_FUNC)
|
||||||
|
SPIRV_CROSS_MSL_FUNCTIONS(UNLOAD_FUNC)
|
||||||
|
#undef UNLOAD_FUNC
|
||||||
|
|
||||||
|
s_spirv_cross_library.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dyn_libs::CloseAll()
|
||||||
|
{
|
||||||
|
CloseShaderc();
|
||||||
|
CloseSpirvCross();
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef SPIRV_CROSS_HLSL_FUNCTIONS
|
||||||
|
#undef SPIRV_CROSS_MSL_FUNCTIONS
|
||||||
|
#undef SPIRV_CROSS_FUNCTIONS
|
||||||
|
#undef SHADERC_FUNCTIONS
|
||||||
|
|
||||||
|
bool GPUDevice::CompileGLSLShaderToVulkanSpv(GPUShaderStage stage, GPUShaderLanguage source_language,
|
||||||
|
std::string_view source, const char* entry_point,
|
||||||
|
bool nonsemantic_debug_info, DynamicHeapArray<u8>* out_binary,
|
||||||
|
Error* error)
|
||||||
{
|
{
|
||||||
static constexpr const std::array<shaderc_shader_kind, static_cast<size_t>(GPUShaderStage::MaxCount)> stage_kinds = {{
|
static constexpr const std::array<shaderc_shader_kind, static_cast<size_t>(GPUShaderStage::MaxCount)> stage_kinds = {{
|
||||||
shaderc_glsl_vertex_shader,
|
shaderc_glsl_vertex_shader,
|
||||||
|
@ -1197,46 +1308,323 @@ bool GPUDevice::CompileGLSLShaderToVulkanSpv(GPUShaderStage stage, std::string_v
|
||||||
shaderc_glsl_compute_shader,
|
shaderc_glsl_compute_shader,
|
||||||
}};
|
}};
|
||||||
|
|
||||||
if (!dyn_shaderc::Open())
|
if (source_language != GPUShaderLanguage::GLSLVK)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "Unsupported source language for transpile: {}",
|
||||||
|
ShaderLanguageToString(source_language));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dyn_libs::OpenShaderc(error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
shaderc_compile_options_t options = dyn_shaderc::shaderc_compile_options_initialize();
|
shaderc_compile_options_t options = dyn_libs::shaderc_compile_options_initialize();
|
||||||
AssertMsg(options, "shaderc_compile_options_initialize() failed");
|
AssertMsg(options, "shaderc_compile_options_initialize() failed");
|
||||||
|
|
||||||
dyn_shaderc::shaderc_compile_options_set_source_language(options, shaderc_source_language_glsl);
|
dyn_libs::shaderc_compile_options_set_source_language(options, shaderc_source_language_glsl);
|
||||||
dyn_shaderc::shaderc_compile_options_set_target_env(options, shaderc_target_env_vulkan, 0);
|
dyn_libs::shaderc_compile_options_set_target_env(options, shaderc_target_env_vulkan, 0);
|
||||||
dyn_shaderc::shaderc_compile_options_set_generate_debug_info(options, m_debug_device,
|
dyn_libs::shaderc_compile_options_set_generate_debug_info(options, m_debug_device,
|
||||||
m_debug_device && nonsemantic_debug_info);
|
m_debug_device && nonsemantic_debug_info);
|
||||||
dyn_shaderc::shaderc_compile_options_set_optimization_level(
|
dyn_libs::shaderc_compile_options_set_optimization_level(
|
||||||
options, m_debug_device ? shaderc_optimization_level_zero : shaderc_optimization_level_performance);
|
options, m_debug_device ? shaderc_optimization_level_zero : shaderc_optimization_level_performance);
|
||||||
|
|
||||||
shaderc_compilation_result_t result;
|
shaderc_compilation_result_t result;
|
||||||
const shaderc_compilation_status status = dyn_shaderc::shaderc_compile_into_spv(
|
const shaderc_compilation_status status = dyn_libs::shaderc_compile_into_spv(
|
||||||
dyn_shaderc::s_compiler, source.data(), source.length(), stage_kinds[static_cast<size_t>(stage)], "source",
|
dyn_libs::s_shaderc_compiler, source.data(), source.length(), stage_kinds[static_cast<size_t>(stage)], "source",
|
||||||
entry_point, options, &result);
|
entry_point, options, &result);
|
||||||
if (status != shaderc_compilation_status_success)
|
if (status != shaderc_compilation_status_success)
|
||||||
{
|
{
|
||||||
const std::string_view errors(result ? dyn_shaderc::shaderc_result_get_error_message(result) :
|
const std::string_view errors(result ? dyn_libs::shaderc_result_get_error_message(result) : "null result object");
|
||||||
"null result object");
|
Error::SetStringFmt(error, "Failed to compile shader to SPIR-V: {}\n{}",
|
||||||
ERROR_LOG("Failed to compile shader to SPIR-V: {}\n{}", dyn_shaderc::shaderc_compilation_status_to_string(status),
|
dyn_libs::shaderc_compilation_status_to_string(status), errors);
|
||||||
|
ERROR_LOG("Failed to compile shader to SPIR-V: {}\n{}", dyn_libs::shaderc_compilation_status_to_string(status),
|
||||||
errors);
|
errors);
|
||||||
DumpBadShader(source, errors);
|
DumpBadShader(source, errors);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const size_t num_warnings = dyn_shaderc::shaderc_result_get_num_warnings(result);
|
const size_t num_warnings = dyn_libs::shaderc_result_get_num_warnings(result);
|
||||||
if (num_warnings > 0)
|
if (num_warnings > 0)
|
||||||
WARNING_LOG("Shader compiled with warnings:\n{}", dyn_shaderc::shaderc_result_get_error_message(result));
|
WARNING_LOG("Shader compiled with warnings:\n{}", dyn_libs::shaderc_result_get_error_message(result));
|
||||||
|
|
||||||
const size_t spirv_size = dyn_shaderc::shaderc_result_get_length(result);
|
const size_t spirv_size = dyn_libs::shaderc_result_get_length(result);
|
||||||
DebugAssert(spirv_size > 0);
|
DebugAssert(spirv_size > 0);
|
||||||
out_binary->resize(spirv_size);
|
out_binary->resize(spirv_size);
|
||||||
std::memcpy(out_binary->data(), dyn_shaderc::shaderc_result_get_bytes(result), spirv_size);
|
std::memcpy(out_binary->data(), dyn_libs::shaderc_result_get_bytes(result), spirv_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
dyn_shaderc::shaderc_result_release(result);
|
dyn_libs::shaderc_result_release(result);
|
||||||
dyn_shaderc::shaderc_compile_options_release(options);
|
dyn_libs::shaderc_compile_options_release(options);
|
||||||
return (status == shaderc_compilation_status_success);
|
return (status == shaderc_compilation_status_success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span<const u8> spirv, GPUShaderStage stage,
|
||||||
|
GPUShaderLanguage target_language, u32 target_version, std::string* output,
|
||||||
|
Error* error)
|
||||||
|
{
|
||||||
|
if (!dyn_libs::OpenSpirvCross(error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
spvc_context sctx;
|
||||||
|
spvc_result sres;
|
||||||
|
if ((sres = dyn_libs::spvc_context_create(&sctx)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_context_create() failed: {}", static_cast<int>(sres));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ScopedGuard sctx_guard = [&sctx]() { dyn_libs::spvc_context_destroy(sctx); };
|
||||||
|
|
||||||
|
dyn_libs::spvc_context_set_error_callback(
|
||||||
|
sctx,
|
||||||
|
[](void* error, const char* errormsg) {
|
||||||
|
ERROR_LOG("SPIRV-Cross reported an error: {}", errormsg);
|
||||||
|
Error::SetStringView(static_cast<Error*>(error), errormsg);
|
||||||
|
},
|
||||||
|
error);
|
||||||
|
|
||||||
|
spvc_parsed_ir sir;
|
||||||
|
if ((sres = dyn_libs::spvc_context_parse_spirv(sctx, reinterpret_cast<const u32*>(spirv.data()), spirv.size() / 4,
|
||||||
|
&sir)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_context_parse_spirv() failed: {}", static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr std::array<spvc_backend, static_cast<size_t>(GPUShaderLanguage::Count)> backends = {
|
||||||
|
{SPVC_BACKEND_NONE, SPVC_BACKEND_HLSL, SPVC_BACKEND_GLSL, SPVC_BACKEND_GLSL, SPVC_BACKEND_GLSL, SPVC_BACKEND_MSL,
|
||||||
|
SPVC_BACKEND_NONE}};
|
||||||
|
|
||||||
|
spvc_compiler scompiler;
|
||||||
|
if ((sres = dyn_libs::spvc_context_create_compiler(sctx, backends[static_cast<size_t>(target_language)], sir,
|
||||||
|
SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &scompiler)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_context_create_compiler() failed: {}", static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
spvc_compiler_options soptions;
|
||||||
|
if ((sres = dyn_libs::spvc_compiler_create_compiler_options(scompiler, &soptions)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_compiler_create_compiler_options() failed: {}", static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
spvc_resources resources;
|
||||||
|
if ((sres = dyn_libs::spvc_compiler_create_shader_resources(scompiler, &resources)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_compiler_create_shader_resources() failed: {}", static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to know if there's UBOs for mapping.
|
||||||
|
const spvc_reflected_resource *ubos, *textures;
|
||||||
|
size_t ubos_count, textures_count;
|
||||||
|
if ((sres = dyn_libs::spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &ubos,
|
||||||
|
&ubos_count)) != SPVC_SUCCESS ||
|
||||||
|
(sres = dyn_libs::spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE,
|
||||||
|
&textures, &textures_count)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_resources_get_resource_list_for_type() failed: {}", static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] const SpvExecutionModel execmodel = dyn_libs::spvc_compiler_get_execution_model(scompiler);
|
||||||
|
|
||||||
|
switch (target_language)
|
||||||
|
{
|
||||||
|
case GPUShaderLanguage::HLSL:
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
if ((sres = dyn_libs::spvc_compiler_options_set_uint(soptions, SPVC_COMPILER_OPTION_HLSL_SHADER_MODEL,
|
||||||
|
target_version)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_compiler_options_set_uint(SPVC_COMPILER_OPTION_HLSL_SHADER_MODEL) failed: {}",
|
||||||
|
static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sres = dyn_libs::spvc_compiler_options_set_bool(
|
||||||
|
soptions, SPVC_COMPILER_OPTION_HLSL_SUPPORT_NONZERO_BASE_VERTEX_BASE_INSTANCE, false)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error,
|
||||||
|
"spvc_compiler_options_set_bool(SPVC_COMPILER_OPTION_HLSL_SUPPORT_NONZERO_BASE_VERTEX_"
|
||||||
|
"BASE_INSTANCE) failed: {}",
|
||||||
|
static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 start_set = 0;
|
||||||
|
if (ubos_count > 0)
|
||||||
|
{
|
||||||
|
const spvc_hlsl_resource_binding rb = {.stage = execmodel,
|
||||||
|
.desc_set = start_set++,
|
||||||
|
.binding = 0,
|
||||||
|
.cbv = {.register_space = 0, .register_binding = 0}};
|
||||||
|
if ((sres = dyn_libs::spvc_compiler_hlsl_add_resource_binding(scompiler, &rb)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_compiler_hlsl_add_resource_binding() failed: {}", static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textures_count > 0)
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
||||||
|
{
|
||||||
|
const spvc_hlsl_resource_binding rb = {.stage = execmodel,
|
||||||
|
.desc_set = start_set++,
|
||||||
|
.binding = i,
|
||||||
|
.srv = {.register_space = 0, .register_binding = i},
|
||||||
|
.sampler = {.register_space = 0, .register_binding = i}};
|
||||||
|
if ((sres = dyn_libs::spvc_compiler_hlsl_add_resource_binding(scompiler, &rb)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_compiler_hlsl_add_resource_binding() failed: {}", static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Error::SetStringView(error, "Unsupported platform.");
|
||||||
|
return {};
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GPUShaderLanguage::GLSL:
|
||||||
|
case GPUShaderLanguage::GLSLES:
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_OPENGL
|
||||||
|
if ((sres = dyn_libs::spvc_compiler_options_set_uint(soptions, SPVC_COMPILER_OPTION_GLSL_VERSION,
|
||||||
|
target_version)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_compiler_options_set_uint(SPVC_COMPILER_OPTION_GLSL_VERSION) failed: {}",
|
||||||
|
static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool is_gles = (target_language == GPUShaderLanguage::GLSLES);
|
||||||
|
if ((sres = dyn_libs::spvc_compiler_options_set_bool(soptions, SPVC_COMPILER_OPTION_GLSL_ES, is_gles)) !=
|
||||||
|
SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_compiler_options_set_bool(SPVC_COMPILER_OPTION_GLSL_ES) failed: {}",
|
||||||
|
static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
Error::SetStringView(error, "Unsupported platform.");
|
||||||
|
return {};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GPUShaderLanguage::MSL:
|
||||||
|
{
|
||||||
|
#ifdef __APPLE__
|
||||||
|
if ((sres = dyn_libs::spvc_compiler_options_set_bool(
|
||||||
|
soptions, SPVC_COMPILER_OPTION_MSL_PAD_FRAGMENT_OUTPUT_COMPONENTS, true)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(
|
||||||
|
error, "spvc_compiler_options_set_bool(SPVC_COMPILER_OPTION_MSL_PAD_FRAGMENT_OUTPUT_COMPONENTS) failed: {}",
|
||||||
|
static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sres = dyn_libs::spvc_compiler_options_set_bool(soptions, SPVC_COMPILER_OPTION_MSL_FRAMEBUFFER_FETCH_SUBPASS,
|
||||||
|
m_features.framebuffer_fetch)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(
|
||||||
|
error, "spvc_compiler_options_set_bool(SPVC_COMPILER_OPTION_MSL_FRAMEBUFFER_FETCH_SUBPASS) failed: {}",
|
||||||
|
static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_features.framebuffer_fetch &&
|
||||||
|
((sres = dyn_libs::spvc_compiler_options_set_uint(soptions, SPVC_COMPILER_OPTION_MSL_VERSION,
|
||||||
|
SPVC_MAKE_MSL_VERSION(2, 3, 0))) != SPVC_SUCCESS))
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_compiler_options_set_uint(SPVC_COMPILER_OPTION_MSL_VERSION) failed: {}",
|
||||||
|
static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stage == GPUShaderStage::Fragment)
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
||||||
|
{
|
||||||
|
const spvc_msl_resource_binding rb = {.stage = SpvExecutionModelFragment,
|
||||||
|
.desc_set = 1,
|
||||||
|
.binding = i,
|
||||||
|
.msl_buffer = i,
|
||||||
|
.msl_texture = i,
|
||||||
|
.msl_sampler = i};
|
||||||
|
|
||||||
|
if ((sres = dyn_libs::spvc_compiler_msl_add_resource_binding(scompiler, &rb)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_compiler_msl_add_resource_binding() failed: {}", static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_features.framebuffer_fetch)
|
||||||
|
{
|
||||||
|
const spvc_msl_resource_binding rb = {
|
||||||
|
.stage = SpvExecutionModelFragment, .desc_set = 2, .binding = 0, .msl_texture = MAX_TEXTURE_SAMPLERS};
|
||||||
|
|
||||||
|
if ((sres = dyn_libs::spvc_compiler_msl_add_resource_binding(scompiler, &rb)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_compiler_msl_add_resource_binding() for FB failed: {}",
|
||||||
|
static_cast<int>(sres));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Error::SetStringView(error, "Unsupported platform.");
|
||||||
|
return {};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sres = dyn_libs::spvc_compiler_install_compiler_options(scompiler, soptions)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_compiler_install_compiler_options() failed: {}", static_cast<int>(sres));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* out_src;
|
||||||
|
if ((sres = dyn_libs::spvc_compiler_compile(scompiler, &out_src)) != SPVC_SUCCESS)
|
||||||
|
{
|
||||||
|
Error::SetStringFmt(error, "spvc_compiler_compile() failed: {}", static_cast<int>(sres));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t out_src_length = out_src ? std::strlen(out_src) : 0;
|
||||||
|
if (out_src_length == 0)
|
||||||
|
{
|
||||||
|
Error::SetStringView(error, "Failed to compile SPIR-V to target language.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
output->assign(out_src, out_src_length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<GPUShader> GPUDevice::TranspileAndCreateShaderFromSource(
|
||||||
|
GPUShaderStage stage, GPUShaderLanguage source_language, std::string_view source, const char* entry_point,
|
||||||
|
GPUShaderLanguage target_language, u32 target_version, DynamicHeapArray<u8>* out_binary, Error* error)
|
||||||
|
{
|
||||||
|
DynamicHeapArray<u8> spv;
|
||||||
|
if (!CompileGLSLShaderToVulkanSpv(stage, source_language, source, entry_point, false, &spv, error))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
std::string dest_source;
|
||||||
|
if (!TranslateVulkanSpvToLanguage(spv.cspan(), stage, target_language, target_version, &dest_source, error))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// TODO: MSL needs entry point suffixed.
|
||||||
|
|
||||||
|
return CreateShaderFromSource(stage, target_language, dest_source, entry_point, out_binary, error);
|
||||||
|
}
|
||||||
|
|
|
@ -112,6 +112,18 @@ enum class GPUShaderStage : u8
|
||||||
MaxCount
|
MaxCount
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class GPUShaderLanguage : u8
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
HLSL,
|
||||||
|
GLSL,
|
||||||
|
GLSLES,
|
||||||
|
GLSLVK,
|
||||||
|
MSL,
|
||||||
|
SPV,
|
||||||
|
Count
|
||||||
|
};
|
||||||
|
|
||||||
class GPUShader
|
class GPUShader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -522,6 +534,9 @@ public:
|
||||||
/// Returns a string representing the specified API.
|
/// Returns a string representing the specified API.
|
||||||
static const char* RenderAPIToString(RenderAPI api);
|
static const char* RenderAPIToString(RenderAPI api);
|
||||||
|
|
||||||
|
/// Returns a string representing the specified language.
|
||||||
|
static const char* ShaderLanguageToString(GPUShaderLanguage language);
|
||||||
|
|
||||||
/// Returns a new device for the specified API.
|
/// Returns a new device for the specified API.
|
||||||
static std::unique_ptr<GPUDevice> CreateDeviceForAPI(RenderAPI api);
|
static std::unique_ptr<GPUDevice> CreateDeviceForAPI(RenderAPI api);
|
||||||
|
|
||||||
|
@ -630,8 +645,8 @@ public:
|
||||||
virtual void InvalidateRenderTarget(GPUTexture* t);
|
virtual void InvalidateRenderTarget(GPUTexture* t);
|
||||||
|
|
||||||
/// Shader abstraction.
|
/// Shader abstraction.
|
||||||
std::unique_ptr<GPUShader> CreateShader(GPUShaderStage stage, std::string_view source,
|
std::unique_ptr<GPUShader> CreateShader(GPUShaderStage stage, GPUShaderLanguage language, std::string_view source,
|
||||||
const char* entry_point = "main");
|
Error* error = nullptr, const char* entry_point = "main");
|
||||||
virtual std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) = 0;
|
virtual std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) = 0;
|
||||||
|
|
||||||
/// Debug messaging.
|
/// Debug messaging.
|
||||||
|
@ -716,19 +731,26 @@ protected:
|
||||||
virtual bool ReadPipelineCache(const std::string& filename);
|
virtual bool ReadPipelineCache(const std::string& filename);
|
||||||
virtual bool GetPipelineCacheData(DynamicHeapArray<u8>* data);
|
virtual bool GetPipelineCacheData(DynamicHeapArray<u8>* data);
|
||||||
|
|
||||||
virtual std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) = 0;
|
virtual std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
|
||||||
virtual std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
Error* error) = 0;
|
||||||
const char* entry_point,
|
virtual std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||||
DynamicHeapArray<u8>* out_binary) = 0;
|
std::string_view source, const char* entry_point,
|
||||||
|
DynamicHeapArray<u8>* out_binary, Error* error) = 0;
|
||||||
|
|
||||||
bool AcquireWindow(bool recreate_window);
|
bool AcquireWindow(bool recreate_window);
|
||||||
|
|
||||||
void TrimTexturePool();
|
void TrimTexturePool();
|
||||||
|
|
||||||
#if defined(ENABLE_VULKAN) || defined(__APPLE__)
|
bool CompileGLSLShaderToVulkanSpv(GPUShaderStage stage, GPUShaderLanguage source_language, std::string_view source,
|
||||||
bool CompileGLSLShaderToVulkanSpv(GPUShaderStage stage, std::string_view source, const char* entry_point,
|
const char* entry_point, bool nonsemantic_debug_info,
|
||||||
bool nonsemantic_debug_info, DynamicHeapArray<u8>* out_binary);
|
DynamicHeapArray<u8>* out_binary, Error* error);
|
||||||
#endif
|
bool TranslateVulkanSpvToLanguage(const std::span<const u8> spirv, GPUShaderStage stage,
|
||||||
|
GPUShaderLanguage target_language, u32 target_version, std::string* output,
|
||||||
|
Error* error);
|
||||||
|
std::unique_ptr<GPUShader> TranspileAndCreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage source_language,
|
||||||
|
std::string_view source, const char* entry_point,
|
||||||
|
GPUShaderLanguage target_language, u32 target_version,
|
||||||
|
DynamicHeapArray<u8>* out_binary, Error* error);
|
||||||
|
|
||||||
Features m_features = {};
|
Features m_features = {};
|
||||||
u32 m_max_texture_size = 0;
|
u32 m_max_texture_size = 0;
|
||||||
|
@ -778,7 +800,7 @@ private:
|
||||||
|
|
||||||
void OpenShaderCache(std::string_view base_path, u32 version);
|
void OpenShaderCache(std::string_view base_path, u32 version);
|
||||||
void CloseShaderCache();
|
void CloseShaderCache();
|
||||||
bool CreateResources();
|
bool CreateResources(Error* error);
|
||||||
void DestroyResources();
|
void DestroyResources();
|
||||||
|
|
||||||
static bool IsTexturePoolType(GPUTexture::Type type);
|
static bool IsTexturePoolType(GPUTexture::Type type);
|
||||||
|
|
|
@ -20,7 +20,9 @@ Log_SetChannel(GPUShaderCache);
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct CacheIndexEntry
|
struct CacheIndexEntry
|
||||||
{
|
{
|
||||||
u32 shader_type;
|
u8 shader_type;
|
||||||
|
u8 shader_language;
|
||||||
|
u8 unused[2];
|
||||||
u32 source_length;
|
u32 source_length;
|
||||||
u64 source_hash_low;
|
u64 source_hash_low;
|
||||||
u64 source_hash_high;
|
u64 source_hash_high;
|
||||||
|
@ -202,8 +204,9 @@ bool GPUShaderCache::ReadExisting(const std::string& index_filename, const std::
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CacheIndexKey key{entry.shader_type, entry.source_length, entry.source_hash_low,
|
const CacheIndexKey key{entry.shader_type, entry.shader_language, {},
|
||||||
entry.source_hash_high, entry.entry_point_low, entry.entry_point_high};
|
entry.source_length, entry.source_hash_low, entry.source_hash_high,
|
||||||
|
entry.entry_point_low, entry.entry_point_high};
|
||||||
const CacheIndexData data{entry.file_offset, entry.compressed_size, entry.uncompressed_size};
|
const CacheIndexData data{entry.file_offset, entry.compressed_size, entry.uncompressed_size};
|
||||||
m_index.emplace(key, data);
|
m_index.emplace(key, data);
|
||||||
}
|
}
|
||||||
|
@ -215,8 +218,8 @@ bool GPUShaderCache::ReadExisting(const std::string& index_filename, const std::
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GPUShaderCache::CacheIndexKey GPUShaderCache::GetCacheKey(GPUShaderStage stage, std::string_view shader_code,
|
GPUShaderCache::CacheIndexKey GPUShaderCache::GetCacheKey(GPUShaderStage stage, GPUShaderLanguage language,
|
||||||
std::string_view entry_point)
|
std::string_view shader_code, std::string_view entry_point)
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
|
@ -229,7 +232,8 @@ GPUShaderCache::CacheIndexKey GPUShaderCache::GetCacheKey(GPUShaderStage stage,
|
||||||
} h;
|
} h;
|
||||||
|
|
||||||
CacheIndexKey key = {};
|
CacheIndexKey key = {};
|
||||||
key.shader_type = static_cast<u32>(stage);
|
key.shader_type = static_cast<u8>(stage);
|
||||||
|
key.shader_language = static_cast<u8>(language);
|
||||||
|
|
||||||
MD5Digest digest;
|
MD5Digest digest;
|
||||||
digest.Update(shader_code.data(), static_cast<u32>(shader_code.length()));
|
digest.Update(shader_code.data(), static_cast<u32>(shader_code.length()));
|
||||||
|
@ -295,7 +299,8 @@ bool GPUShaderCache::Insert(const CacheIndexKey& key, const void* data, u32 data
|
||||||
idata.uncompressed_size = data_size;
|
idata.uncompressed_size = data_size;
|
||||||
|
|
||||||
CacheIndexEntry entry = {};
|
CacheIndexEntry entry = {};
|
||||||
entry.shader_type = static_cast<u32>(key.shader_type);
|
entry.shader_type = static_cast<u8>(key.shader_type);
|
||||||
|
entry.shader_language = static_cast<u8>(key.shader_language);
|
||||||
entry.source_length = key.source_length;
|
entry.source_length = key.source_length;
|
||||||
entry.source_hash_low = key.source_hash_low;
|
entry.source_hash_low = key.source_hash_low;
|
||||||
entry.source_hash_high = key.source_hash_high;
|
entry.source_hash_high = key.source_hash_high;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
enum class GPUShaderStage : u8;
|
enum class GPUShaderStage : u8;
|
||||||
|
enum class GPUShaderLanguage : u8;
|
||||||
|
|
||||||
class GPUShaderCache
|
class GPUShaderCache
|
||||||
{
|
{
|
||||||
|
@ -21,7 +22,9 @@ public:
|
||||||
|
|
||||||
struct alignas(8) CacheIndexKey
|
struct alignas(8) CacheIndexKey
|
||||||
{
|
{
|
||||||
u32 shader_type;
|
u8 shader_type;
|
||||||
|
u8 shader_language;
|
||||||
|
u8 unused[2];
|
||||||
u32 source_length;
|
u32 source_length;
|
||||||
u64 source_hash_low;
|
u64 source_hash_low;
|
||||||
u64 source_hash_high;
|
u64 source_hash_high;
|
||||||
|
@ -50,7 +53,8 @@ public:
|
||||||
bool Create();
|
bool Create();
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
static CacheIndexKey GetCacheKey(GPUShaderStage stage, std::string_view shader_code, std::string_view entry_point);
|
static CacheIndexKey GetCacheKey(GPUShaderStage stage, GPUShaderLanguage language, std::string_view shader_code,
|
||||||
|
std::string_view entry_point);
|
||||||
|
|
||||||
bool Lookup(const CacheIndexKey& key, ShaderBinary* binary);
|
bool Lookup(const CacheIndexKey& key, ShaderBinary* binary);
|
||||||
bool Insert(const CacheIndexKey& key, const void* data, u32 data_size);
|
bool Insert(const CacheIndexKey& key, const void* data, u32 data_size);
|
||||||
|
|
|
@ -231,10 +231,11 @@ public:
|
||||||
void ClearDepth(GPUTexture* t, float d) override;
|
void ClearDepth(GPUTexture* t, float d) override;
|
||||||
void InvalidateRenderTarget(GPUTexture* t) override;
|
void InvalidateRenderTarget(GPUTexture* t) override;
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) override;
|
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
|
||||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
Error* error) override;
|
||||||
const char* entry_point,
|
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||||
DynamicHeapArray<u8>* out_binary = nullptr) override;
|
std::string_view source, const char* entry_point,
|
||||||
|
DynamicHeapArray<u8>* out_binary, Error* error) override;
|
||||||
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override;
|
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override;
|
||||||
|
|
||||||
void PushDebugGroup(const char* name) override;
|
void PushDebugGroup(const char* name) override;
|
||||||
|
@ -328,7 +329,7 @@ private:
|
||||||
id<MTLRenderPipelineState> GetClearDepthPipeline(const ClearPipelineConfig& config);
|
id<MTLRenderPipelineState> GetClearDepthPipeline(const ClearPipelineConfig& config);
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> CreateShaderFromMSL(GPUShaderStage stage, std::string_view source,
|
std::unique_ptr<GPUShader> CreateShaderFromMSL(GPUShaderStage stage, std::string_view source,
|
||||||
std::string_view entry_point);
|
std::string_view entry_point, Error* error);
|
||||||
|
|
||||||
id<MTLDepthStencilState> GetDepthState(const GPUPipeline::DepthState& ds);
|
id<MTLDepthStencilState> GetDepthState(const GPUPipeline::DepthState& ds);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2024 Connor McLaughlin <stenzek@gmail.com>
|
||||||
// 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)
|
||||||
|
|
||||||
#include "metal_device.h"
|
#include "metal_device.h"
|
||||||
|
@ -16,8 +16,6 @@
|
||||||
#define FMT_EXCEPTIONS 0
|
#define FMT_EXCEPTIONS 0
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
|
|
||||||
#include "spirv_cross_c.h"
|
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
@ -612,19 +610,21 @@ static void DumpShader(u32 n, std::string_view suffix, std::string_view data)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> MetalDevice::CreateShaderFromMSL(GPUShaderStage stage, std::string_view source,
|
std::unique_ptr<GPUShader> MetalDevice::CreateShaderFromMSL(GPUShaderStage stage, std::string_view source,
|
||||||
std::string_view entry_point)
|
std::string_view entry_point, Error* error)
|
||||||
{
|
{
|
||||||
@autoreleasepool
|
@autoreleasepool
|
||||||
{
|
{
|
||||||
NSString* const ns_source = StringViewToNSString(source);
|
NSString* const ns_source = StringViewToNSString(source);
|
||||||
NSError* error = nullptr;
|
NSError* nserror = nullptr;
|
||||||
id<MTLLibrary> library = [m_device newLibraryWithSource:ns_source options:nil error:&error];
|
id<MTLLibrary> library = [m_device newLibraryWithSource:ns_source options:nil error:&nserror];
|
||||||
if (!library)
|
if (!library)
|
||||||
{
|
{
|
||||||
LogNSError(error, TinyString::from_format("Failed to compile {} shader", GPUShader::GetStageName(stage)));
|
LogNSError(nserror, TinyString::from_format("Failed to compile {} shader", GPUShader::GetStageName(stage)));
|
||||||
|
|
||||||
const char* utf_error = [error.description UTF8String];
|
const char* utf_error = [nserror.description UTF8String];
|
||||||
DumpBadShader(source, fmt::format("Error {}: {}", static_cast<u32>(error.code), utf_error ? utf_error : ""));
|
DumpBadShader(source, fmt::format("Error {}: {}", static_cast<u32>(nserror.code), utf_error ? utf_error : ""));
|
||||||
|
Error::SetStringFmt(error, "Failed to compile {} shader: Error {}: {}", GPUShader::GetStageName(stage),
|
||||||
|
static_cast<u32>(nserror.code), utf_error ? utf_error : "");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,6 +632,7 @@ std::unique_ptr<GPUShader> MetalDevice::CreateShaderFromMSL(GPUShaderStage stage
|
||||||
if (!function)
|
if (!function)
|
||||||
{
|
{
|
||||||
ERROR_LOG("Failed to get main function in compiled library");
|
ERROR_LOG("Failed to get main function in compiled library");
|
||||||
|
Error::SetStringView(error, "Failed to get main function in compiled library");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,154 +640,42 @@ std::unique_ptr<GPUShader> MetalDevice::CreateShaderFromMSL(GPUShaderStage stage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> MetalDevice::CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data)
|
std::unique_ptr<GPUShader> MetalDevice::CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
|
||||||
|
Error* error)
|
||||||
{
|
{
|
||||||
const std::string_view str_data(reinterpret_cast<const char*>(data.data()), data.size());
|
const std::string_view str_data(reinterpret_cast<const char*>(data.data()), data.size());
|
||||||
return CreateShaderFromMSL(stage, str_data, "main0");
|
return CreateShaderFromMSL(stage, str_data, "main0", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> MetalDevice::CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
std::unique_ptr<GPUShader> MetalDevice::CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||||
const char* entry_point,
|
std::string_view source, const char* entry_point,
|
||||||
DynamicHeapArray<u8>* out_binary /* = nullptr */)
|
DynamicHeapArray<u8>* out_binary, Error* error)
|
||||||
{
|
{
|
||||||
static constexpr bool dump_shaders = false;
|
static constexpr bool dump_shaders = false;
|
||||||
|
|
||||||
DynamicHeapArray<u8> local_binary;
|
DynamicHeapArray<u8> spv;
|
||||||
DynamicHeapArray<u8>* dest_binary = out_binary ? out_binary : &local_binary;
|
if (!CompileGLSLShaderToVulkanSpv(stage, language, source, entry_point, false, &spv, error))
|
||||||
if (!CompileGLSLShaderToVulkanSpv(stage, source, entry_point, false, dest_binary))
|
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
AssertMsg((dest_binary->size() % 4) == 0, "Compile result should be 4 byte aligned.");
|
std::string msl;
|
||||||
|
if (!TranslateVulkanSpvToLanguage(spv.cspan(), stage, GPUShaderLanguage::MSL, 230, &msl, error))
|
||||||
spvc_context sctx;
|
|
||||||
spvc_result sres;
|
|
||||||
if ((sres = spvc_context_create(&sctx)) != SPVC_SUCCESS)
|
|
||||||
{
|
|
||||||
ERROR_LOG("spvc_context_create() failed: {}", static_cast<int>(sres));
|
|
||||||
return {};
|
return {};
|
||||||
}
|
|
||||||
|
|
||||||
const ScopedGuard sctx_guard = [&sctx]() { spvc_context_destroy(sctx); };
|
|
||||||
|
|
||||||
spvc_context_set_error_callback(
|
|
||||||
sctx, [](void*, const char* error) { ERROR_LOG("SPIRV-Cross reported an error: {}", error); }, nullptr);
|
|
||||||
|
|
||||||
spvc_parsed_ir sir;
|
|
||||||
if ((sres = spvc_context_parse_spirv(sctx, reinterpret_cast<const u32*>(dest_binary->data()), dest_binary->size() / 4, &sir)) != SPVC_SUCCESS)
|
|
||||||
{
|
|
||||||
ERROR_LOG("spvc_context_parse_spirv() failed: {}", static_cast<int>(sres));
|
|
||||||
DumpBadShader(source, std::string_view());
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
spvc_compiler scompiler;
|
|
||||||
if ((sres = spvc_context_create_compiler(sctx, SPVC_BACKEND_MSL, sir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP,
|
|
||||||
&scompiler)) != SPVC_SUCCESS)
|
|
||||||
{
|
|
||||||
ERROR_LOG("spvc_context_create_compiler() failed: {}", static_cast<int>(sres));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
spvc_compiler_options soptions;
|
|
||||||
if ((sres = spvc_compiler_create_compiler_options(scompiler, &soptions)) != SPVC_SUCCESS)
|
|
||||||
{
|
|
||||||
ERROR_LOG("spvc_compiler_create_compiler_options() failed: {}", static_cast<int>(sres));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((sres = spvc_compiler_options_set_bool(soptions, SPVC_COMPILER_OPTION_MSL_PAD_FRAGMENT_OUTPUT_COMPONENTS,
|
|
||||||
true)) != SPVC_SUCCESS)
|
|
||||||
{
|
|
||||||
ERROR_LOG("spvc_compiler_options_set_bool(SPVC_COMPILER_OPTION_MSL_PAD_FRAGMENT_OUTPUT_COMPONENTS) failed: {}",
|
|
||||||
static_cast<int>(sres));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((sres = spvc_compiler_options_set_bool(soptions, SPVC_COMPILER_OPTION_MSL_FRAMEBUFFER_FETCH_SUBPASS,
|
|
||||||
m_features.framebuffer_fetch)) != SPVC_SUCCESS)
|
|
||||||
{
|
|
||||||
ERROR_LOG("spvc_compiler_options_set_bool(SPVC_COMPILER_OPTION_MSL_FRAMEBUFFER_FETCH_SUBPASS) failed: {}",
|
|
||||||
static_cast<int>(sres));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_features.framebuffer_fetch &&
|
|
||||||
((sres = spvc_compiler_options_set_uint(soptions, SPVC_COMPILER_OPTION_MSL_VERSION,
|
|
||||||
SPVC_MAKE_MSL_VERSION(2, 3, 0))) != SPVC_SUCCESS))
|
|
||||||
{
|
|
||||||
ERROR_LOG("spvc_compiler_options_set_uint(SPVC_COMPILER_OPTION_MSL_VERSION) failed: {}", static_cast<int>(sres));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stage == GPUShaderStage::Fragment)
|
|
||||||
{
|
|
||||||
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
|
||||||
{
|
|
||||||
const spvc_msl_resource_binding rb = {.stage = SpvExecutionModelFragment,
|
|
||||||
.desc_set = 1,
|
|
||||||
.binding = i,
|
|
||||||
.msl_buffer = i,
|
|
||||||
.msl_texture = i,
|
|
||||||
.msl_sampler = i};
|
|
||||||
|
|
||||||
if ((sres = spvc_compiler_msl_add_resource_binding(scompiler, &rb)) != SPVC_SUCCESS)
|
|
||||||
{
|
|
||||||
ERROR_LOG("spvc_compiler_msl_add_resource_binding() failed: {}", static_cast<int>(sres));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_features.framebuffer_fetch)
|
|
||||||
{
|
|
||||||
const spvc_msl_resource_binding rb = {
|
|
||||||
.stage = SpvExecutionModelFragment, .desc_set = 2, .binding = 0, .msl_texture = MAX_TEXTURE_SAMPLERS};
|
|
||||||
|
|
||||||
if ((sres = spvc_compiler_msl_add_resource_binding(scompiler, &rb)) != SPVC_SUCCESS)
|
|
||||||
{
|
|
||||||
ERROR_LOG("spvc_compiler_msl_add_resource_binding() for FB failed: {}", static_cast<int>(sres));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((sres = spvc_compiler_install_compiler_options(scompiler, soptions)) != SPVC_SUCCESS)
|
|
||||||
{
|
|
||||||
ERROR_LOG("spvc_compiler_install_compiler_options() failed: {}", static_cast<int>(sres));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* msl;
|
|
||||||
if ((sres = spvc_compiler_compile(scompiler, &msl)) != SPVC_SUCCESS)
|
|
||||||
{
|
|
||||||
ERROR_LOG("spvc_compiler_compile() failed: {}", static_cast<int>(sres));
|
|
||||||
DumpBadShader(source, std::string_view());
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t msl_length = msl ? std::strlen(msl) : 0;
|
|
||||||
if (msl_length == 0)
|
|
||||||
{
|
|
||||||
ERROR_LOG("Failed to compile SPIR-V to MSL.");
|
|
||||||
DumpBadShader(source, std::string_view());
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string_view mslv(msl, msl_length);
|
|
||||||
if constexpr (dump_shaders)
|
if constexpr (dump_shaders)
|
||||||
{
|
{
|
||||||
static unsigned s_next_id = 0;
|
static unsigned s_next_id = 0;
|
||||||
++s_next_id;
|
++s_next_id;
|
||||||
DumpShader(s_next_id, "_input", source);
|
DumpShader(s_next_id, "_input", source);
|
||||||
DumpShader(s_next_id, "_msl", mslv);
|
DumpShader(s_next_id, "_msl", msl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out_binary)
|
if (out_binary)
|
||||||
{
|
{
|
||||||
out_binary->resize(mslv.size());
|
out_binary->resize(msl.size());
|
||||||
std::memcpy(out_binary->data(), mslv.data(), mslv.size());
|
std::memcpy(out_binary->data(), msl.data(), msl.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateShaderFromMSL(stage, mslv, "main0");
|
return CreateShaderFromMSL(stage, msl, "main0", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
MetalPipeline::MetalPipeline(id<MTLRenderPipelineState> pipeline, id<MTLDepthStencilState> depth, MTLCullMode cull_mode,
|
MetalPipeline::MetalPipeline(id<MTLRenderPipelineState> pipeline, id<MTLDepthStencilState> depth, MTLCullMode cull_mode,
|
||||||
|
@ -1282,8 +1171,7 @@ std::unique_ptr<MetalDownloadTexture> MetalDownloadTexture::Create(u32 width, u3
|
||||||
reinterpret_cast<void*>(Common::AlignDownPow2(reinterpret_cast<uintptr_t>(memory), HOST_PAGE_SIZE));
|
reinterpret_cast<void*>(Common::AlignDownPow2(reinterpret_cast<uintptr_t>(memory), HOST_PAGE_SIZE));
|
||||||
const size_t page_offset = static_cast<size_t>(static_cast<u8*>(memory) - static_cast<u8*>(page_aligned_memory));
|
const size_t page_offset = static_cast<size_t>(static_cast<u8*>(memory) - static_cast<u8*>(page_aligned_memory));
|
||||||
const size_t page_aligned_size = Common::AlignUpPow2(page_offset + memory_size, HOST_PAGE_SIZE);
|
const size_t page_aligned_size = Common::AlignUpPow2(page_offset + memory_size, HOST_PAGE_SIZE);
|
||||||
DEV_LOG("Trying to import {} bytes of memory at {} for download texture", page_aligned_memory,
|
DEV_LOG("Trying to import {} bytes of memory at {} for download texture", page_aligned_memory, page_aligned_size);
|
||||||
page_aligned_size);
|
|
||||||
|
|
||||||
buffer = [[dev.m_device newBufferWithBytesNoCopy:page_aligned_memory
|
buffer = [[dev.m_device newBufferWithBytesNoCopy:page_aligned_memory
|
||||||
length:page_aligned_size
|
length:page_aligned_size
|
||||||
|
|
|
@ -1092,7 +1092,7 @@ void OpenGLDevice::PushUniformBuffer(const void* data, u32 data_size)
|
||||||
std::memcpy(res.pointer, data, data_size);
|
std::memcpy(res.pointer, data, data_size);
|
||||||
m_uniform_buffer->Unmap(data_size);
|
m_uniform_buffer->Unmap(data_size);
|
||||||
s_stats.buffer_streamed += data_size;
|
s_stats.buffer_streamed += data_size;
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, 1, m_uniform_buffer->GetGLBufferId(), res.buffer_offset, data_size);
|
glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_uniform_buffer->GetGLBufferId(), res.buffer_offset, data_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* OpenGLDevice::MapUniformBuffer(u32 size)
|
void* OpenGLDevice::MapUniformBuffer(u32 size)
|
||||||
|
@ -1105,7 +1105,7 @@ void OpenGLDevice::UnmapUniformBuffer(u32 size)
|
||||||
{
|
{
|
||||||
const u32 pos = m_uniform_buffer->Unmap(size);
|
const u32 pos = m_uniform_buffer->Unmap(size);
|
||||||
s_stats.buffer_streamed += size;
|
s_stats.buffer_streamed += size;
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, 1, m_uniform_buffer->GetGLBufferId(), pos, size);
|
glBindBufferRange(GL_UNIFORM_BUFFER, 0, m_uniform_buffer->GetGLBufferId(), pos, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDevice::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
void OpenGLDevice::SetRenderTargets(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds,
|
||||||
|
|
|
@ -72,9 +72,11 @@ public:
|
||||||
void ClearDepth(GPUTexture* t, float d) override;
|
void ClearDepth(GPUTexture* t, float d) override;
|
||||||
void InvalidateRenderTarget(GPUTexture* t) override;
|
void InvalidateRenderTarget(GPUTexture* t) override;
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) override;
|
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
|
||||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
Error* error) override;
|
||||||
const char* entry_point, DynamicHeapArray<u8>* out_binary) override;
|
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||||
|
std::string_view source, const char* entry_point,
|
||||||
|
DynamicHeapArray<u8>* out_binary, Error* error) override;
|
||||||
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override;
|
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override;
|
||||||
|
|
||||||
void PushDebugGroup(const char* name) override;
|
void PushDebugGroup(const char* name) override;
|
||||||
|
|
|
@ -158,24 +158,35 @@ bool OpenGLShader::Compile()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> OpenGLDevice::CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data)
|
std::unique_ptr<GPUShader> OpenGLDevice::CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
|
||||||
|
Error* error)
|
||||||
{
|
{
|
||||||
// Not supported.. except spir-v maybe? but no point really...
|
// Not supported.. except spir-v maybe? but no point really...
|
||||||
|
Error::SetStringView(error, "Not supported.");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> OpenGLDevice::CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
std::unique_ptr<GPUShader> OpenGLDevice::CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||||
const char* entry_point,
|
std::string_view source, const char* entry_point,
|
||||||
DynamicHeapArray<u8>* out_binary)
|
DynamicHeapArray<u8>* out_binary, Error* error)
|
||||||
{
|
{
|
||||||
|
const GPUShaderLanguage expected_language = IsGLES() ? GPUShaderLanguage::GLSLES : GPUShaderLanguage::GLSL;
|
||||||
|
if (language != expected_language)
|
||||||
|
{
|
||||||
|
return TranspileAndCreateShaderFromSource(
|
||||||
|
stage, language, source, entry_point, expected_language,
|
||||||
|
ShaderGen::GetGLSLVersion(IsGLES() ? RenderAPI::OpenGLES : RenderAPI::OpenGL), out_binary, error);
|
||||||
|
}
|
||||||
|
|
||||||
if (std::strcmp(entry_point, "main") != 0)
|
if (std::strcmp(entry_point, "main") != 0)
|
||||||
{
|
{
|
||||||
ERROR_LOG("Entry point must be 'main', but got '{}' instead.", entry_point);
|
ERROR_LOG("Entry point must be 'main', but got '{}' instead.", entry_point);
|
||||||
|
Error::SetStringFmt(error, "Entry point must be 'main', but got '{}' instead.", entry_point);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::unique_ptr<GPUShader>(
|
return std::unique_ptr<GPUShader>(
|
||||||
new OpenGLShader(stage, GPUShaderCache::GetCacheKey(stage, source, entry_point), std::string(source)));
|
new OpenGLShader(stage, GPUShaderCache::GetCacheKey(stage, language, source, entry_point), std::string(source)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -381,11 +392,26 @@ GLuint OpenGLDevice::CompileProgram(const GPUPipeline::GraphicsConfig& plconfig)
|
||||||
|
|
||||||
if (status == GL_TRUE)
|
if (status == GL_TRUE)
|
||||||
{
|
{
|
||||||
ERROR_LOG("Program linked with warnings:\n{}", info_log.c_str());
|
ERROR_LOG("Program linked with warnings:\n{}", info_log);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ERROR_LOG("Program failed to link:\n{}", info_log.c_str());
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "########## VERTEX SHADER ##########\n";
|
||||||
|
ss << vertex_shader->GetSource();
|
||||||
|
if (geometry_shader)
|
||||||
|
{
|
||||||
|
ss << "\n########## GEOMETRY SHADER ##########\n";
|
||||||
|
ss << geometry_shader->GetSource();
|
||||||
|
}
|
||||||
|
ss << "\n########## FRAGMENT SHADER ##########\n";
|
||||||
|
ss << fragment_shader->GetSource();
|
||||||
|
ss << "\n#####################################\n";
|
||||||
|
DumpBadShader(ss.str(), info_log);
|
||||||
|
}
|
||||||
|
|
||||||
|
ERROR_LOG("Program failed to link:\n{}", info_log);
|
||||||
glDeleteProgram(program_id);
|
glDeleteProgram(program_id);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -402,7 +428,7 @@ void OpenGLDevice::PostLinkProgram(const GPUPipeline::GraphicsConfig& plconfig,
|
||||||
{
|
{
|
||||||
GLint location = glGetUniformBlockIndex(program_id, "UBOBlock");
|
GLint location = glGetUniformBlockIndex(program_id, "UBOBlock");
|
||||||
if (location >= 0)
|
if (location >= 0)
|
||||||
glUniformBlockBinding(program_id, location, 1);
|
glUniformBlockBinding(program_id, location, 0);
|
||||||
|
|
||||||
glUseProgram(program_id);
|
glUseProgram(program_id);
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ public:
|
||||||
|
|
||||||
ALWAYS_INLINE GLuint GetGLId() const { return m_id.value(); }
|
ALWAYS_INLINE GLuint GetGLId() const { return m_id.value(); }
|
||||||
ALWAYS_INLINE const GPUShaderCache::CacheIndexKey& GetKey() const { return m_key; }
|
ALWAYS_INLINE const GPUShaderCache::CacheIndexKey& GetKey() const { return m_key; }
|
||||||
|
ALWAYS_INLINE const std::string& GetSource() const { return m_source; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OpenGLShader(GPUShaderStage stage, const GPUShaderCache::CacheIndexKey& key, std::string source);
|
OpenGLShader(GPUShaderStage stage, const GPUShaderCache::CacheIndexKey& key, std::string source);
|
||||||
|
|
|
@ -1324,7 +1324,7 @@ bool PostProcessing::ReShadeFXShader::CompilePipeline(GPUTexture::Format format,
|
||||||
TinyString version_string = "#version 460 core\n";
|
TinyString version_string = "#version 460 core\n";
|
||||||
#ifdef ENABLE_OPENGL
|
#ifdef ENABLE_OPENGL
|
||||||
if (api == RenderAPI::OpenGL || api == RenderAPI::OpenGLES)
|
if (api == RenderAPI::OpenGL || api == RenderAPI::OpenGLES)
|
||||||
version_string = ShaderGen::GetGLSLVersionString(api);
|
version_string = ShaderGen::GetGLSLVersionString(api, ShaderGen::GetGLSLVersion(api));
|
||||||
#endif
|
#endif
|
||||||
real_code = fmt::format("{}\n#define ENTRY_POINT_{}\n{}\n{}\n{}", version_string, name, defns, precision, code);
|
real_code = fmt::format("{}\n#define ENTRY_POINT_{}\n{}\n{}\n{}", version_string, name, defns, precision, code);
|
||||||
|
|
||||||
|
@ -1355,10 +1355,11 @@ bool PostProcessing::ReShadeFXShader::CompilePipeline(GPUTexture::Format format,
|
||||||
|
|
||||||
// FileSystem::WriteStringToFile("D:\\foo.txt", real_code);
|
// FileSystem::WriteStringToFile("D:\\foo.txt", real_code);
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> sshader =
|
Error error;
|
||||||
g_gpu_device->CreateShader(stage, real_code, needs_main_defn ? "main" : name.c_str());
|
std::unique_ptr<GPUShader> sshader = g_gpu_device->CreateShader(
|
||||||
|
stage, ShaderGen::GetShaderLanguageForAPI(api), real_code, &error, needs_main_defn ? "main" : name.c_str());
|
||||||
if (!sshader)
|
if (!sshader)
|
||||||
ERROR_LOG("Failed to compile function '{}'", name);
|
ERROR_LOG("Failed to compile function '{}': {}", name, error.GetDescription());
|
||||||
|
|
||||||
return sshader;
|
return sshader;
|
||||||
};
|
};
|
||||||
|
|
|
@ -125,10 +125,10 @@ bool PostProcessing::GLSLShader::CompilePipeline(GPUTexture::Format format, u32
|
||||||
PostProcessingGLSLShaderGen shadergen(g_gpu_device->GetRenderAPI(), g_gpu_device->GetFeatures().dual_source_blend,
|
PostProcessingGLSLShaderGen shadergen(g_gpu_device->GetRenderAPI(), g_gpu_device->GetFeatures().dual_source_blend,
|
||||||
g_gpu_device->GetFeatures().framebuffer_fetch);
|
g_gpu_device->GetFeatures().framebuffer_fetch);
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> vs =
|
std::unique_ptr<GPUShader> vs = g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GetLanguage(),
|
||||||
g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GeneratePostProcessingVertexShader(*this));
|
shadergen.GeneratePostProcessingVertexShader(*this));
|
||||||
std::unique_ptr<GPUShader> fs =
|
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GeneratePostProcessingFragmentShader(*this));
|
shadergen.GeneratePostProcessingFragmentShader(*this));
|
||||||
if (!vs || !fs)
|
if (!vs || !fs)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -328,7 +328,7 @@ void PostProcessing::GLSLShader::LoadOptions()
|
||||||
|
|
||||||
PostProcessingGLSLShaderGen::PostProcessingGLSLShaderGen(RenderAPI render_api, bool supports_dual_source_blend,
|
PostProcessingGLSLShaderGen::PostProcessingGLSLShaderGen(RenderAPI render_api, bool supports_dual_source_blend,
|
||||||
bool supports_framebuffer_fetch)
|
bool supports_framebuffer_fetch)
|
||||||
: ShaderGen(render_api, supports_dual_source_blend, supports_framebuffer_fetch)
|
: ShaderGen(render_api, GPUShaderLanguage::GLSLVK, supports_dual_source_blend, supports_framebuffer_fetch)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,49 +365,13 @@ std::string PostProcessingGLSLShaderGen::GeneratePostProcessingFragmentShader(co
|
||||||
WriteUniformBuffer(ss, shader, false);
|
WriteUniformBuffer(ss, shader, false);
|
||||||
DeclareTexture(ss, "samp0", 0);
|
DeclareTexture(ss, "samp0", 0);
|
||||||
|
|
||||||
// Rename main, since we need to set up globals
|
|
||||||
if (!m_glsl)
|
|
||||||
{
|
|
||||||
// TODO: vecn -> floatn
|
|
||||||
|
|
||||||
ss << R"(
|
ss << R"(
|
||||||
#define main real_main
|
layout(location = 0) in VertexData {
|
||||||
static float2 v_tex0;
|
vec2 v_tex0;
|
||||||
static float4 v_pos;
|
};
|
||||||
static float4 o_col0;
|
|
||||||
// Wrappers for sampling functions.
|
|
||||||
#define texture(sampler, coords) sampler.Sample(sampler##_ss, coords)
|
|
||||||
#define textureOffset(sampler, coords, offset) sampler.Sample(sampler##_ss, coords, offset)
|
|
||||||
#define gl_FragCoord v_pos
|
|
||||||
)";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (m_use_glsl_interface_blocks)
|
|
||||||
{
|
|
||||||
if (IsVulkan() || IsMetal())
|
|
||||||
ss << "layout(location = 0) ";
|
|
||||||
|
|
||||||
ss << "in VertexData {\n";
|
layout(location = 0) out float4 o_col0;
|
||||||
ss << " float2 v_tex0;\n";
|
|
||||||
ss << "};\n";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ss << "in float2 v_tex0;\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_use_glsl_binding_layout)
|
|
||||||
{
|
|
||||||
ss << "layout(location = 0) out float4 o_col0;\n";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ss << "out float4 o_col0;\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ss << R"(
|
|
||||||
float4 Sample() { return texture(samp0, v_tex0); }
|
float4 Sample() { return texture(samp0, v_tex0); }
|
||||||
float4 SampleLocation(float2 location) { return texture(samp0, location); }
|
float4 SampleLocation(float2 location) { return texture(samp0, location); }
|
||||||
#define SampleOffset(offset) textureOffset(samp0, v_tex0, offset)
|
#define SampleOffset(offset) textureOffset(samp0, v_tex0, offset)
|
||||||
|
@ -439,21 +403,6 @@ float2 GetWindowResolution() { return u_window_size; }
|
||||||
)";
|
)";
|
||||||
|
|
||||||
ss << shader.GetCode();
|
ss << shader.GetCode();
|
||||||
|
|
||||||
if (!m_glsl)
|
|
||||||
{
|
|
||||||
ss << R"(
|
|
||||||
#undef main
|
|
||||||
void main(in float2 v_tex0_ : TEXCOORD0, in float4 v_pos_ : SV_Position, out float4 o_col0_ : SV_Target)
|
|
||||||
{
|
|
||||||
v_pos = v_pos_;
|
|
||||||
v_tex0 = v_tex0_;
|
|
||||||
real_main();
|
|
||||||
o_col0_ = o_col0;
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
}
|
|
||||||
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,39 +17,66 @@
|
||||||
|
|
||||||
Log_SetChannel(ShaderGen);
|
Log_SetChannel(ShaderGen);
|
||||||
|
|
||||||
ShaderGen::ShaderGen(RenderAPI render_api, bool supports_dual_source_blend, bool supports_framebuffer_fetch)
|
ShaderGen::ShaderGen(RenderAPI render_api, GPUShaderLanguage shader_language, bool supports_dual_source_blend,
|
||||||
: m_render_api(render_api), m_glsl(render_api != RenderAPI::D3D11 && render_api != RenderAPI::D3D12),
|
bool supports_framebuffer_fetch)
|
||||||
m_spirv(render_api == RenderAPI::Vulkan || render_api == RenderAPI::Metal),
|
: m_render_api(render_api), m_shader_language(shader_language),
|
||||||
m_supports_dual_source_blend(supports_dual_source_blend), m_supports_framebuffer_fetch(supports_framebuffer_fetch),
|
m_glsl(shader_language == GPUShaderLanguage::GLSL || shader_language == GPUShaderLanguage::GLSLES ||
|
||||||
m_use_glsl_interface_blocks(false)
|
shader_language == GPUShaderLanguage::GLSLVK),
|
||||||
|
m_spirv(shader_language == GPUShaderLanguage::GLSLVK), m_supports_dual_source_blend(supports_dual_source_blend),
|
||||||
|
m_supports_framebuffer_fetch(supports_framebuffer_fetch), m_use_glsl_interface_blocks(false)
|
||||||
{
|
{
|
||||||
#if defined(ENABLE_OPENGL) || defined(ENABLE_VULKAN) || defined(__APPLE__)
|
|
||||||
if (m_glsl)
|
if (m_glsl)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_OPENGL
|
#ifdef ENABLE_OPENGL
|
||||||
if (m_render_api == RenderAPI::OpenGL || m_render_api == RenderAPI::OpenGLES)
|
if (m_render_api == RenderAPI::OpenGL || m_render_api == RenderAPI::OpenGLES)
|
||||||
m_glsl_version_string = GetGLSLVersionString(m_render_api);
|
m_glsl_version_string = GetGLSLVersionString(m_render_api, GetGLSLVersion(render_api));
|
||||||
|
|
||||||
m_use_glsl_interface_blocks = (IsVulkan() || IsMetal() || GLAD_GL_ES_VERSION_3_2 || GLAD_GL_VERSION_3_2);
|
m_use_glsl_interface_blocks =
|
||||||
m_use_glsl_binding_layout = (IsVulkan() || IsMetal() || UseGLSLBindingLayout());
|
(shader_language == GPUShaderLanguage::GLSLVK || GLAD_GL_ES_VERSION_3_2 || GLAD_GL_VERSION_3_2);
|
||||||
|
m_use_glsl_binding_layout = (shader_language == GPUShaderLanguage::GLSLVK || UseGLSLBindingLayout());
|
||||||
|
|
||||||
if (m_render_api == RenderAPI::OpenGL)
|
#ifdef _WIN32
|
||||||
|
if (m_shader_language == GPUShaderLanguage::GLSL)
|
||||||
{
|
{
|
||||||
// SSAA with interface blocks is broken on AMD's OpenGL driver.
|
// SSAA with interface blocks is broken on AMD's OpenGL driver.
|
||||||
const char* gl_vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
const char* gl_vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
||||||
if (std::strcmp(gl_vendor, "ATI Technologies Inc.") == 0)
|
if (std::strcmp(gl_vendor, "ATI Technologies Inc.") == 0)
|
||||||
m_use_glsl_interface_blocks = false;
|
m_use_glsl_interface_blocks = false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
m_use_glsl_interface_blocks = true;
|
m_use_glsl_interface_blocks = true;
|
||||||
m_use_glsl_binding_layout = true;
|
m_use_glsl_binding_layout = true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderGen::~ShaderGen() = default;
|
ShaderGen::~ShaderGen() = default;
|
||||||
|
|
||||||
|
GPUShaderLanguage ShaderGen::GetShaderLanguageForAPI(RenderAPI api)
|
||||||
|
{
|
||||||
|
switch (api)
|
||||||
|
{
|
||||||
|
case RenderAPI::D3D11:
|
||||||
|
case RenderAPI::D3D12:
|
||||||
|
return GPUShaderLanguage::HLSL;
|
||||||
|
|
||||||
|
case RenderAPI::Vulkan:
|
||||||
|
case RenderAPI::Metal:
|
||||||
|
return GPUShaderLanguage::GLSLVK;
|
||||||
|
|
||||||
|
case RenderAPI::OpenGL:
|
||||||
|
return GPUShaderLanguage::GLSL;
|
||||||
|
|
||||||
|
case RenderAPI::OpenGLES:
|
||||||
|
return GPUShaderLanguage::GLSLES;
|
||||||
|
|
||||||
|
case RenderAPI::None:
|
||||||
|
default:
|
||||||
|
return GPUShaderLanguage::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ShaderGen::UseGLSLBindingLayout()
|
bool ShaderGen::UseGLSLBindingLayout()
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_OPENGL
|
#ifdef ENABLE_OPENGL
|
||||||
|
@ -72,7 +99,7 @@ void ShaderGen::DefineMacro(std::stringstream& ss, const char* name, s32 value)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_OPENGL
|
#ifdef ENABLE_OPENGL
|
||||||
TinyString ShaderGen::GetGLSLVersionString(RenderAPI render_api)
|
u32 ShaderGen::GetGLSLVersion(RenderAPI render_api)
|
||||||
{
|
{
|
||||||
const char* glsl_version = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
|
const char* glsl_version = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||||
const bool glsl_es = (render_api == RenderAPI::OpenGLES);
|
const bool glsl_es = (render_api == RenderAPI::OpenGLES);
|
||||||
|
@ -108,6 +135,15 @@ TinyString ShaderGen::GetGLSLVersionString(RenderAPI render_api)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (static_cast<u32>(major_version) * 100) + static_cast<u32>(minor_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
TinyString ShaderGen::GetGLSLVersionString(RenderAPI render_api, u32 version)
|
||||||
|
{
|
||||||
|
const bool glsl_es = (render_api == RenderAPI::OpenGLES);
|
||||||
|
const u32 major_version = (version / 100);
|
||||||
|
const u32 minor_version = (version % 100);
|
||||||
|
|
||||||
return TinyString::from_format("#version {}{:02d}{}", major_version, minor_version,
|
return TinyString::from_format("#version {}{:02d}{}", major_version, minor_version,
|
||||||
(glsl_es && major_version >= 3) ? " es" : "");
|
(glsl_es && major_version >= 3) ? " es" : "");
|
||||||
}
|
}
|
||||||
|
@ -115,7 +151,7 @@ TinyString ShaderGen::GetGLSLVersionString(RenderAPI render_api)
|
||||||
|
|
||||||
void ShaderGen::WriteHeader(std::stringstream& ss)
|
void ShaderGen::WriteHeader(std::stringstream& ss)
|
||||||
{
|
{
|
||||||
if (m_render_api == RenderAPI::OpenGL || m_render_api == RenderAPI::OpenGLES)
|
if (m_shader_language == GPUShaderLanguage::GLSL || m_shader_language == GPUShaderLanguage::GLSLES)
|
||||||
ss << m_glsl_version_string << "\n\n";
|
ss << m_glsl_version_string << "\n\n";
|
||||||
else if (m_spirv)
|
else if (m_spirv)
|
||||||
ss << "#version 450 core\n\n";
|
ss << "#version 450 core\n\n";
|
||||||
|
@ -131,7 +167,7 @@ void ShaderGen::WriteHeader(std::stringstream& ss)
|
||||||
|
|
||||||
#ifdef ENABLE_OPENGL
|
#ifdef ENABLE_OPENGL
|
||||||
// Extension enabling for OpenGL.
|
// Extension enabling for OpenGL.
|
||||||
if (m_render_api == RenderAPI::OpenGL || m_render_api == RenderAPI::OpenGLES)
|
if (m_shader_language == GPUShaderLanguage::GLSL || m_shader_language == GPUShaderLanguage::GLSLES)
|
||||||
{
|
{
|
||||||
if (GLAD_GL_EXT_shader_framebuffer_fetch)
|
if (GLAD_GL_EXT_shader_framebuffer_fetch)
|
||||||
ss << "#extension GL_EXT_shader_framebuffer_fetch : require\n";
|
ss << "#extension GL_EXT_shader_framebuffer_fetch : require\n";
|
||||||
|
@ -139,7 +175,7 @@ void ShaderGen::WriteHeader(std::stringstream& ss)
|
||||||
ss << "#extension GL_ARM_shader_framebuffer_fetch : require\n";
|
ss << "#extension GL_ARM_shader_framebuffer_fetch : require\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_render_api == RenderAPI::OpenGLES)
|
if (m_shader_language == GPUShaderLanguage::GLSLES)
|
||||||
{
|
{
|
||||||
// Enable EXT_blend_func_extended for dual-source blend on OpenGL ES.
|
// Enable EXT_blend_func_extended for dual-source blend on OpenGL ES.
|
||||||
if (GLAD_GL_EXT_blend_func_extended)
|
if (GLAD_GL_EXT_blend_func_extended)
|
||||||
|
@ -158,7 +194,7 @@ void ShaderGen::WriteHeader(std::stringstream& ss)
|
||||||
ss << "#define DRIVER_POWERVR 1\n";
|
ss << "#define DRIVER_POWERVR 1\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (m_render_api == RenderAPI::OpenGL)
|
else if (m_shader_language == GPUShaderLanguage::GLSL)
|
||||||
{
|
{
|
||||||
// Need extensions for binding layout if GL<4.3.
|
// Need extensions for binding layout if GL<4.3.
|
||||||
if (m_use_glsl_binding_layout && !GLAD_GL_VERSION_4_3)
|
if (m_use_glsl_binding_layout && !GLAD_GL_VERSION_4_3)
|
||||||
|
@ -185,7 +221,7 @@ void ShaderGen::WriteHeader(std::stringstream& ss)
|
||||||
DefineMacro(ss, "API_METAL", m_render_api == RenderAPI::Metal);
|
DefineMacro(ss, "API_METAL", m_render_api == RenderAPI::Metal);
|
||||||
|
|
||||||
#ifdef ENABLE_OPENGL
|
#ifdef ENABLE_OPENGL
|
||||||
if (m_render_api == RenderAPI::OpenGLES)
|
if (m_shader_language == GPUShaderLanguage::GLSLES)
|
||||||
{
|
{
|
||||||
ss << "precision highp float;\n";
|
ss << "precision highp float;\n";
|
||||||
ss << "precision highp int;\n";
|
ss << "precision highp int;\n";
|
||||||
|
@ -299,9 +335,9 @@ void ShaderGen::WriteHeader(std::stringstream& ss)
|
||||||
|
|
||||||
void ShaderGen::WriteUniformBufferDeclaration(std::stringstream& ss, bool push_constant_on_vulkan)
|
void ShaderGen::WriteUniformBufferDeclaration(std::stringstream& ss, bool push_constant_on_vulkan)
|
||||||
{
|
{
|
||||||
if (IsVulkan())
|
if (m_shader_language == GPUShaderLanguage::GLSLVK)
|
||||||
{
|
{
|
||||||
if (push_constant_on_vulkan)
|
if (m_render_api == RenderAPI::Vulkan && push_constant_on_vulkan)
|
||||||
{
|
{
|
||||||
ss << "layout(push_constant) uniform PushConstants\n";
|
ss << "layout(push_constant) uniform PushConstants\n";
|
||||||
}
|
}
|
||||||
|
@ -311,15 +347,10 @@ void ShaderGen::WriteUniformBufferDeclaration(std::stringstream& ss, bool push_c
|
||||||
m_has_uniform_buffer = true;
|
m_has_uniform_buffer = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IsMetal())
|
|
||||||
{
|
|
||||||
ss << "layout(std140, set = 0, binding = 0) uniform UBOBlock\n";
|
|
||||||
m_has_uniform_buffer = true;
|
|
||||||
}
|
|
||||||
else if (m_glsl)
|
else if (m_glsl)
|
||||||
{
|
{
|
||||||
if (m_use_glsl_binding_layout)
|
if (m_use_glsl_binding_layout)
|
||||||
ss << "layout(std140, binding = 1) uniform UBOBlock\n";
|
ss << "layout(std140, binding = 0) uniform UBOBlock\n";
|
||||||
else
|
else
|
||||||
ss << "layout(std140) uniform UBOBlock\n";
|
ss << "layout(std140) uniform UBOBlock\n";
|
||||||
|
|
||||||
|
|
|
@ -13,15 +13,20 @@
|
||||||
class ShaderGen
|
class ShaderGen
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ShaderGen(RenderAPI render_api, bool supports_dual_source_blend, bool supports_framebuffer_fetch);
|
ShaderGen(RenderAPI render_api, GPUShaderLanguage language, bool supports_dual_source_blend,
|
||||||
|
bool supports_framebuffer_fetch);
|
||||||
~ShaderGen();
|
~ShaderGen();
|
||||||
|
|
||||||
|
static GPUShaderLanguage GetShaderLanguageForAPI(RenderAPI api);
|
||||||
static bool UseGLSLBindingLayout();
|
static bool UseGLSLBindingLayout();
|
||||||
|
|
||||||
#ifdef ENABLE_OPENGL
|
#ifdef ENABLE_OPENGL
|
||||||
static TinyString GetGLSLVersionString(RenderAPI render_api);
|
static u32 GetGLSLVersion(RenderAPI render_api);
|
||||||
|
static TinyString GetGLSLVersionString(RenderAPI render_api, u32 version);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ALWAYS_INLINE GPUShaderLanguage GetLanguage() const { return m_shader_language; }
|
||||||
|
|
||||||
std::string GenerateScreenQuadVertexShader(float z = 0.0f);
|
std::string GenerateScreenQuadVertexShader(float z = 0.0f);
|
||||||
std::string GenerateUVQuadVertexShader();
|
std::string GenerateUVQuadVertexShader();
|
||||||
std::string GenerateFillFragmentShader();
|
std::string GenerateFillFragmentShader();
|
||||||
|
@ -58,6 +63,7 @@ protected:
|
||||||
bool noperspective_color = false, bool feedback_loop = false);
|
bool noperspective_color = false, bool feedback_loop = false);
|
||||||
|
|
||||||
RenderAPI m_render_api;
|
RenderAPI m_render_api;
|
||||||
|
GPUShaderLanguage m_shader_language;
|
||||||
bool m_glsl;
|
bool m_glsl;
|
||||||
bool m_spirv;
|
bool m_spirv;
|
||||||
bool m_supports_dual_source_blend;
|
bool m_supports_dual_source_blend;
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
<DepsDLLs Include="$(DepsBinDir)libwebp.dll" />
|
<DepsDLLs Include="$(DepsBinDir)libwebp.dll" />
|
||||||
<DepsDLLs Include="$(DepsBinDir)SDL2.dll" />
|
<DepsDLLs Include="$(DepsBinDir)SDL2.dll" />
|
||||||
<DepsDLLs Include="$(DepsBinDir)shaderc_shared.dll" />
|
<DepsDLLs Include="$(DepsBinDir)shaderc_shared.dll" />
|
||||||
|
<DepsDLLs Include="$(DepsBinDir)spirv-cross-c-shared.dll" />
|
||||||
<DepsDLLs Include="$(DepsBinDir)zlib1.dll" />
|
<DepsDLLs Include="$(DepsBinDir)zlib1.dll" />
|
||||||
<DepsDLLs Include="$(DepsBinDir)zstd.dll" />
|
<DepsDLLs Include="$(DepsBinDir)zstd.dll" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -98,9 +98,10 @@ public:
|
||||||
void ClearDepth(GPUTexture* t, float d) override;
|
void ClearDepth(GPUTexture* t, float d) override;
|
||||||
void InvalidateRenderTarget(GPUTexture* t) override;
|
void InvalidateRenderTarget(GPUTexture* t) override;
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) override;
|
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data, Error* error) override;
|
||||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||||
const char* entry_point, DynamicHeapArray<u8>* out_binary) override;
|
std::string_view source, const char* entry_point,
|
||||||
|
DynamicHeapArray<u8>* out_binary, Error* error) override;
|
||||||
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override;
|
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override;
|
||||||
|
|
||||||
void PushDebugGroup(const char* name) override;
|
void PushDebugGroup(const char* name) override;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "vulkan_device.h"
|
#include "vulkan_device.h"
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/error.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
|
||||||
Log_SetChannel(VulkanDevice);
|
Log_SetChannel(VulkanDevice);
|
||||||
|
@ -24,7 +25,8 @@ void VulkanShader::SetDebugName(std::string_view name)
|
||||||
Vulkan::SetObjectName(VulkanDevice::GetInstance().GetVulkanDevice(), m_module, name);
|
Vulkan::SetObjectName(VulkanDevice::GetInstance().GetVulkanDevice(), m_module, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> VulkanDevice::CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data)
|
std::unique_ptr<GPUShader> VulkanDevice::CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
|
||||||
|
Error* error)
|
||||||
{
|
{
|
||||||
VkShaderModule mod;
|
VkShaderModule mod;
|
||||||
|
|
||||||
|
@ -34,27 +36,37 @@ std::unique_ptr<GPUShader> VulkanDevice::CreateShaderFromBinary(GPUShaderStage s
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkCreateShaderModule() failed: ");
|
LOG_VULKAN_ERROR(res, "vkCreateShaderModule() failed: ");
|
||||||
|
Error::SetStringFmt(error, "vkCreateShaderModule() failed: {}", Vulkan::VkResultToString(res));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::unique_ptr<GPUShader>(new VulkanShader(stage, mod));
|
return std::unique_ptr<GPUShader>(new VulkanShader(stage, mod));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<GPUShader> VulkanDevice::CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
std::unique_ptr<GPUShader> VulkanDevice::CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||||
const char* entry_point,
|
std::string_view source, const char* entry_point,
|
||||||
DynamicHeapArray<u8>* out_binary)
|
DynamicHeapArray<u8>* out_binary, Error* error)
|
||||||
{
|
{
|
||||||
|
if (language == GPUShaderLanguage::SPV)
|
||||||
|
{
|
||||||
|
if (out_binary)
|
||||||
|
out_binary->assign(reinterpret_cast<const u8*>(source.data()), source.length());
|
||||||
|
|
||||||
|
return CreateShaderFromBinary(
|
||||||
|
stage, std::span<const u8>(reinterpret_cast<const u8*>(source.data()), source.length()), error);
|
||||||
|
}
|
||||||
|
|
||||||
DynamicHeapArray<u8> local_binary;
|
DynamicHeapArray<u8> local_binary;
|
||||||
DynamicHeapArray<u8>* dest_binary = out_binary ? out_binary : &local_binary;
|
DynamicHeapArray<u8>* dest_binary = out_binary ? out_binary : &local_binary;
|
||||||
if (!CompileGLSLShaderToVulkanSpv(stage, source, entry_point, m_optional_extensions.vk_khr_shader_non_semantic_info,
|
if (!CompileGLSLShaderToVulkanSpv(stage, language, source, entry_point,
|
||||||
dest_binary))
|
m_optional_extensions.vk_khr_shader_non_semantic_info, dest_binary, error))
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
AssertMsg((dest_binary->size() % 4) == 0, "Compile result should be 4 byte aligned.");
|
AssertMsg((dest_binary->size() % 4) == 0, "Compile result should be 4 byte aligned.");
|
||||||
|
|
||||||
return CreateShaderFromBinary(stage, dest_binary->cspan());
|
return CreateShaderFromBinary(stage, dest_binary->cspan(), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
Loading…
Reference in New Issue