mirror of
https://github.com/stenzek/duckstation.git
synced 2024-11-23 05:49:43 +00:00
GPUDevice: Support transpiling shaders at compile time
And use it for GLSL postprocessing shaders.
This commit is contained in:
parent
f0c2832d03
commit
ef69c31e9f
@ -34,21 +34,20 @@ if(ENABLE_WAYLAND)
|
||||
find_package(Wayland REQUIRED Egl)
|
||||
endif()
|
||||
|
||||
if(ENABLE_VULKAN OR APPLE)
|
||||
if(ENABLE_VULKAN)
|
||||
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.
|
||||
get_filename_component(SHADERC_LIBRARY_DIRECTORY ${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()
|
||||
|
||||
if(APPLE)
|
||||
# SPIRV-Cross is currently only used on MacOS.
|
||||
find_package(spirv_cross_c_shared REQUIRED)
|
||||
endif()
|
||||
|
||||
if(LINUX)
|
||||
find_package(UDEV REQUIRED)
|
||||
endif()
|
||||
|
@ -56,7 +56,8 @@ APPDIRNAME=DuckStation.AppDir
|
||||
STRIP=strip
|
||||
|
||||
declare -a MANUAL_LIBS=(
|
||||
"libshaderc_shared.so.1"
|
||||
"libshaderc_shared.so"
|
||||
"libspirv-cross-c-shared.so"
|
||||
)
|
||||
|
||||
declare -a MANUAL_QT_LIBS=(
|
||||
@ -95,7 +96,7 @@ OUTDIR=$(realpath "./$APPDIRNAME")
|
||||
rm -fr "$OUTDIR"
|
||||
|
||||
echo "Locating extra libraries..."
|
||||
EXTRA_LIBS_ARGS=""
|
||||
EXTRA_LIBS_ARGS=()
|
||||
for lib in "${MANUAL_LIBS[@]}"; do
|
||||
srcpath=$(find "$DEPSDIR" -name "$lib")
|
||||
if [ ! -f "$srcpath" ]; then
|
||||
@ -104,12 +105,7 @@ for lib in "${MANUAL_LIBS[@]}"; do
|
||||
fi
|
||||
|
||||
echo "Found $lib at $srcpath."
|
||||
|
||||
if [ "$EXTRA_LIBS_ARGS" == "" ]; then
|
||||
EXTRA_LIBS_ARGS="--library=$srcpath"
|
||||
else
|
||||
EXTRA_LIBS_ARGS="$EXTRA_LIBS_ARGS,$srcpath"
|
||||
fi
|
||||
EXTRA_LIBS_ARGS+=("--library=$srcpath")
|
||||
done
|
||||
|
||||
# Why the nastyness? linuxdeploy strips our main binary, and there's no option to turn it off.
|
||||
@ -134,7 +130,7 @@ EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so" \
|
||||
DEPLOY_PLATFORM_THEMES="1" \
|
||||
QMAKE="$DEPSDIR/bin/qmake" \
|
||||
NO_STRIP="1" \
|
||||
$LINUXDEPLOY --plugin qt --appdir="$OUTDIR" --executable="$BUILDDIR/bin/duckstation-qt" $EXTRA_LIBS_ARGS \
|
||||
$LINUXDEPLOY --plugin qt --appdir="$OUTDIR" --executable="$BUILDDIR/bin/duckstation-qt" ${EXTRA_LIBS_ARGS[@]} \
|
||||
--desktop-file="$ROOTDIR/scripts/org.duckstation.DuckStation.desktop" \
|
||||
--icon-file="$ROOTDIR/scripts/org.duckstation.DuckStation.png" \
|
||||
|
||||
|
@ -92,7 +92,7 @@ eb11e1b3715b2211442b7e5933a1135885b664cc10530a1a022355fe9e1bb4ac SPIRV-Cross-$S
|
||||
EOF
|
||||
|
||||
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 "https://libsdl.org/release/$SDL.tar.gz" \
|
||||
-O "http://zlib.net/zlib-$ZLIB.tar.gz" \
|
||||
@ -123,16 +123,6 @@ make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
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..."
|
||||
rm -fr "zstd-$ZSTD"
|
||||
tar xf "zstd-$ZSTD.tar.gz"
|
||||
|
43
scripts/flatpak/modules/23-spirv-cross.json
Normal file
43
scripts/flatpak/modules/23-spirv-cross.json
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "spirv-cross",
|
||||
"buildsystem": "cmake-ninja",
|
||||
"builddir": true,
|
||||
"config-opts": [
|
||||
"-DCMAKE_BUILD_TYPE=Release",
|
||||
"-DSPIRV_CROSS_SHARED=ON",
|
||||
"-DSPIRV_CROSS_STATIC=OFF",
|
||||
"-DSPIRV_CROSS_CLI=OFF",
|
||||
"-DSPIRV_CROSS_ENABLE_TESTS=OFF",
|
||||
"-DSPIRV_CROSS_ENABLE_GLSL=ON",
|
||||
"-DSPIRV_CROSS_ENABLE_HLSL=OFF",
|
||||
"-DSPIRV_CROSS_ENABLE_MSL=OFF",
|
||||
"-DSPIRV_CROSS_ENABLE_CPP=OFF",
|
||||
"-DSPIRV_CROSS_ENABLE_REFLECT=OFF",
|
||||
"-DSPIRV_CROSS_ENABLE_C_API=ON",
|
||||
"-DSPIRV_CROSS_ENABLE_UTIL=ON"
|
||||
],
|
||||
"build-options": {
|
||||
"strip": true
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/KhronosGroup/SPIRV-Cross.git",
|
||||
"tag": "vulkan-sdk-1.3.280.0",
|
||||
"commit": "2a7c8184921897ff3d6c6c3f70af4099e2e00331"
|
||||
},
|
||||
{
|
||||
"type": "patch",
|
||||
"path": "../../spirv-cross-changes.patch"
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
||||
"/bin",
|
||||
"/include",
|
||||
"/lib/*.a",
|
||||
"/lib/*.la",
|
||||
"/lib/cmake",
|
||||
"/lib/pkgconfig",
|
||||
"/share"
|
||||
]
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
"modules/20-sdl2.json",
|
||||
"modules/21-libbacktrace.json",
|
||||
"modules/22-shaderc.json",
|
||||
"modules/23-spirv-cross.json",
|
||||
{
|
||||
"name": "duckstation",
|
||||
"buildsystem": "cmake-ninja",
|
||||
|
@ -43,7 +43,7 @@ diff --git a/libshaderc/CMakeLists.txt b/libshaderc/CMakeLists.txt
|
||||
index df9a88d..b15e5d7 100644
|
||||
--- a/libshaderc/CMakeLists.txt
|
||||
+++ b/libshaderc/CMakeLists.txt
|
||||
@@ -24,13 +24,6 @@ set(SHADERC_SOURCES
|
||||
@@ -24,13 +24,6 @@
|
||||
src/shaderc_private.h
|
||||
)
|
||||
|
||||
@ -57,7 +57,15 @@ index df9a88d..b15e5d7 100644
|
||||
add_library(shaderc_shared SHARED ${SHADERC_SOURCES})
|
||||
shaderc_default_compile_options(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
|
||||
${CMAKE_INSTALL_INCLUDEDIR}/shaderc)
|
||||
|
||||
@ -66,14 +74,14 @@ index df9a88d..b15e5d7 100644
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
@@ -69,20 +62,8 @@ set(SHADERC_LIBS
|
||||
@@ -69,21 +61,9 @@
|
||||
SPIRV-Tools
|
||||
)
|
||||
|
||||
-target_link_libraries(shaderc PRIVATE ${SHADERC_LIBS})
|
||||
target_link_libraries(shaderc_shared PRIVATE ${SHADERC_LIBS})
|
||||
|
||||
-shaderc_add_tests(
|
||||
shaderc_add_tests(
|
||||
- TEST_PREFIX shaderc
|
||||
- LINK_LIBS shaderc
|
||||
- INCLUDE_DIRS include ${shaderc_SOURCE_DIR}/libshaderc_util/include ${glslang_SOURCE_DIR}
|
||||
@ -84,10 +92,11 @@ index df9a88d..b15e5d7 100644
|
||||
- shaderc_cpp
|
||||
- shaderc_private)
|
||||
-
|
||||
shaderc_add_tests(
|
||||
-shaderc_add_tests(
|
||||
TEST_PREFIX shaderc_shared
|
||||
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_private)
|
||||
|
||||
|
@ -12,3 +12,16 @@
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} describe --always --tags --dirty=+
|
||||
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;
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUShader> vso = g_gpu_device->CreateShader(GPUShaderStage::Vertex, vs);
|
||||
std::unique_ptr<GPUShader> fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, fs);
|
||||
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, shadergen.GetLanguage(), fs);
|
||||
if (!vso || !fso)
|
||||
return false;
|
||||
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);
|
||||
|
||||
std::unique_ptr<GPUShader> vso =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GenerateScreenQuadVertexShader());
|
||||
std::unique_ptr<GPUShader> vso = g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GetLanguage(),
|
||||
shadergen.GenerateScreenQuadVertexShader());
|
||||
if (!vso)
|
||||
return false;
|
||||
GL_OBJECT_NAME(vso, "Deinterlace Vertex Shader");
|
||||
|
||||
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())))
|
||||
{
|
||||
return false;
|
||||
@ -1806,7 +1806,7 @@ bool GPU::CompileDisplayPipelines(bool display, bool deinterlace, bool chroma_sm
|
||||
|
||||
case DisplayDeinterlacingMode::Weave:
|
||||
{
|
||||
if (!(fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment,
|
||||
if (!(fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||
shadergen.GenerateDeinterlaceWeaveFragmentShader())))
|
||||
{
|
||||
return false;
|
||||
@ -1826,7 +1826,7 @@ bool GPU::CompileDisplayPipelines(bool display, bool deinterlace, bool chroma_sm
|
||||
|
||||
case DisplayDeinterlacingMode::Blend:
|
||||
{
|
||||
if (!(fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment,
|
||||
if (!(fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||
shadergen.GenerateDeinterlaceBlendFragmentShader())))
|
||||
{
|
||||
return false;
|
||||
@ -1846,8 +1846,8 @@ bool GPU::CompileDisplayPipelines(bool display, bool deinterlace, bool chroma_sm
|
||||
|
||||
case DisplayDeinterlacingMode::Adaptive:
|
||||
{
|
||||
fso =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateFastMADReconstructFragmentShader());
|
||||
fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||
shadergen.GenerateFastMADReconstructFragmentShader());
|
||||
if (!fso)
|
||||
return false;
|
||||
|
||||
@ -1877,10 +1877,10 @@ bool GPU::CompileDisplayPipelines(bool display, bool deinterlace, bool chroma_sm
|
||||
plconfig.layout = GPUPipeline::Layout::SingleTextureAndPushConstants;
|
||||
plconfig.SetTargetFormats(GPUTexture::Format::RGBA8);
|
||||
|
||||
std::unique_ptr<GPUShader> vso =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GenerateScreenQuadVertexShader());
|
||||
std::unique_ptr<GPUShader> fso =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateChromaSmoothingFragmentShader());
|
||||
std::unique_ptr<GPUShader> vso = g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GetLanguage(),
|
||||
shadergen.GenerateScreenQuadVertexShader());
|
||||
std::unique_ptr<GPUShader> fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||
shadergen.GenerateChromaSmoothingFragmentShader());
|
||||
if (!vso || !fso)
|
||||
return false;
|
||||
GL_OBJECT_NAME(vso, "Chroma Smoothing Vertex Shader");
|
||||
|
@ -813,8 +813,11 @@ bool GPU_HW::CompilePipelines()
|
||||
for (u8 textured = 0; textured < 2; textured++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
progress.Increment();
|
||||
}
|
||||
@ -857,7 +860,8 @@ bool GPU_HW::CompilePipelines()
|
||||
ConvertToBoolUnchecked(interlacing), ConvertToBoolUnchecked(check_mask));
|
||||
|
||||
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;
|
||||
}
|
||||
@ -1033,10 +1037,10 @@ bool GPU_HW::CompilePipelines()
|
||||
|
||||
if (m_wireframe_mode != GPUWireframeMode::Disabled)
|
||||
{
|
||||
std::unique_ptr<GPUShader> gs =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Geometry, shadergen.GenerateWireframeGeometryShader());
|
||||
std::unique_ptr<GPUShader> fs =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateWireframeFragmentShader());
|
||||
std::unique_ptr<GPUShader> gs = g_gpu_device->CreateShader(GPUShaderStage::Geometry, shadergen.GetLanguage(),
|
||||
shadergen.GenerateWireframeGeometryShader());
|
||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||
shadergen.GenerateWireframeFragmentShader());
|
||||
if (!gs || !fs)
|
||||
return false;
|
||||
|
||||
@ -1069,8 +1073,8 @@ bool GPU_HW::CompilePipelines()
|
||||
batch_shader_guard.Run();
|
||||
|
||||
// use a depth of 1, that way writes will reset the depth
|
||||
std::unique_ptr<GPUShader> fullscreen_quad_vertex_shader =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GenerateScreenQuadVertexShader(1.0f));
|
||||
std::unique_ptr<GPUShader> fullscreen_quad_vertex_shader = g_gpu_device->CreateShader(
|
||||
GPUShaderStage::Vertex, shadergen.GetLanguage(), shadergen.GenerateScreenQuadVertexShader(1.0f));
|
||||
if (!fullscreen_quad_vertex_shader)
|
||||
return false;
|
||||
|
||||
@ -1090,7 +1094,7 @@ bool GPU_HW::CompilePipelines()
|
||||
for (u8 interlaced = 0; interlaced < 2; interlaced++)
|
||||
{
|
||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(
|
||||
GPUShaderStage::Fragment,
|
||||
GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||
shadergen.GenerateVRAMFillFragmentShader(ConvertToBoolUnchecked(wrapped), ConvertToBoolUnchecked(interlaced)));
|
||||
if (!fs)
|
||||
return false;
|
||||
@ -1108,8 +1112,8 @@ bool GPU_HW::CompilePipelines()
|
||||
|
||||
// VRAM copy
|
||||
{
|
||||
std::unique_ptr<GPUShader> fs =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateVRAMCopyFragmentShader());
|
||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||
shadergen.GenerateVRAMCopyFragmentShader());
|
||||
if (!fs)
|
||||
return false;
|
||||
|
||||
@ -1136,8 +1140,9 @@ bool GPU_HW::CompilePipelines()
|
||||
{
|
||||
const bool use_buffer = features.supports_texture_buffers;
|
||||
const bool use_ssbo = features.texture_buffers_emulated_with_ssbo;
|
||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(
|
||||
GPUShaderStage::Fragment, shadergen.GenerateVRAMWriteFragmentShader(use_buffer, use_ssbo));
|
||||
std::unique_ptr<GPUShader> fs =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||
shadergen.GenerateVRAMWriteFragmentShader(use_buffer, use_ssbo));
|
||||
if (!fs)
|
||||
return false;
|
||||
|
||||
@ -1166,8 +1171,8 @@ bool GPU_HW::CompilePipelines()
|
||||
|
||||
// VRAM write replacement
|
||||
{
|
||||
std::unique_ptr<GPUShader> fs =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateCopyFragmentShader());
|
||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||
shadergen.GenerateCopyFragmentShader());
|
||||
if (!fs)
|
||||
return false;
|
||||
|
||||
@ -1184,8 +1189,8 @@ bool GPU_HW::CompilePipelines()
|
||||
// VRAM update depth
|
||||
if (needs_depth_buffer)
|
||||
{
|
||||
std::unique_ptr<GPUShader> fs =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateVRAMUpdateDepthFragmentShader());
|
||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||
shadergen.GenerateVRAMUpdateDepthFragmentShader());
|
||||
if (!fs)
|
||||
return false;
|
||||
|
||||
@ -1210,8 +1215,8 @@ bool GPU_HW::CompilePipelines()
|
||||
|
||||
// VRAM read
|
||||
{
|
||||
std::unique_ptr<GPUShader> fs =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateVRAMReadFragmentShader());
|
||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||
shadergen.GenerateVRAMReadFragmentShader());
|
||||
if (!fs)
|
||||
return false;
|
||||
|
||||
@ -1228,8 +1233,9 @@ bool GPU_HW::CompilePipelines()
|
||||
{
|
||||
for (u8 depth_24 = 0; depth_24 < 2; depth_24++)
|
||||
{
|
||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(
|
||||
GPUShaderStage::Fragment, shadergen.GenerateVRAMExtractFragmentShader(ConvertToBoolUnchecked(depth_24)));
|
||||
std::unique_ptr<GPUShader> fs =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||
shadergen.GenerateVRAMExtractFragmentShader(ConvertToBoolUnchecked(depth_24)));
|
||||
if (!fs)
|
||||
return false;
|
||||
|
||||
@ -1244,10 +1250,10 @@ bool GPU_HW::CompilePipelines()
|
||||
|
||||
if (m_downsample_mode == GPUDownsampleMode::Adaptive)
|
||||
{
|
||||
std::unique_ptr<GPUShader> vs =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GenerateAdaptiveDownsampleVertexShader());
|
||||
std::unique_ptr<GPUShader> fs =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GenerateAdaptiveDownsampleMipFragmentShader(true));
|
||||
std::unique_ptr<GPUShader> vs = g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GetLanguage(),
|
||||
shadergen.GenerateAdaptiveDownsampleVertexShader());
|
||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(
|
||||
GPUShaderStage::Fragment, shadergen.GetLanguage(), shadergen.GenerateAdaptiveDownsampleMipFragmentShader(true));
|
||||
if (!vs || !fs)
|
||||
return false;
|
||||
GL_OBJECT_NAME(fs, "Downsample Vertex Shader");
|
||||
@ -1258,7 +1264,7 @@ bool GPU_HW::CompilePipelines()
|
||||
return false;
|
||||
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));
|
||||
if (!fs)
|
||||
return false;
|
||||
@ -1268,7 +1274,8 @@ bool GPU_HW::CompilePipelines()
|
||||
return false;
|
||||
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)
|
||||
return false;
|
||||
GL_OBJECT_NAME(fs, "Downsample Blur Pass Fragment Shader");
|
||||
@ -1278,7 +1285,7 @@ bool GPU_HW::CompilePipelines()
|
||||
return false;
|
||||
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());
|
||||
if (!fs)
|
||||
return false;
|
||||
@ -1304,9 +1311,10 @@ bool GPU_HW::CompilePipelines()
|
||||
}
|
||||
else if (m_downsample_mode == GPUDownsampleMode::Box)
|
||||
{
|
||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(
|
||||
GPUShaderStage::Fragment, shadergen.GenerateBoxSampleDownsampleFragmentShader(
|
||||
m_resolution_scale / GetBoxDownsampleScale(m_resolution_scale)));
|
||||
std::unique_ptr<GPUShader> fs =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||
shadergen.GenerateBoxSampleDownsampleFragmentShader(
|
||||
m_resolution_scale / GetBoxDownsampleScale(m_resolution_scale)));
|
||||
if (!fs)
|
||||
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,
|
||||
bool disable_color_perspective, bool supports_dual_source_blend,
|
||||
bool supports_framebuffer_fetch, bool debanding)
|
||||
: ShaderGen(render_api, supports_dual_source_blend, supports_framebuffer_fetch), m_resolution_scale(resolution_scale),
|
||||
m_multisamples(multisamples), m_per_sample_shading(per_sample_shading), m_true_color(true_color),
|
||||
m_scaled_dithering(scaled_dithering), m_texture_filter(texture_filtering), m_uv_limits(uv_limits),
|
||||
m_write_mask_as_depth(write_mask_as_depth), m_disable_color_perspective(disable_color_perspective),
|
||||
m_debanding(debanding)
|
||||
: ShaderGen(render_api, GetShaderLanguageForAPI(render_api), supports_dual_source_blend, supports_framebuffer_fetch),
|
||||
m_resolution_scale(resolution_scale), m_multisamples(multisamples), m_per_sample_shading(per_sample_shading),
|
||||
m_true_color(true_color), m_scaled_dithering(scaled_dithering), m_texture_filter(texture_filtering),
|
||||
m_uv_limits(uv_limits), m_write_mask_as_depth(write_mask_as_depth),
|
||||
m_disable_color_perspective(disable_color_perspective), m_debanding(debanding)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "gpu_shadergen.h"
|
||||
|
||||
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
|
||||
#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(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})
|
||||
list(APPEND DEP_BINS "${CMAKE_PREFIX_PATH}/bin/${DEP}")
|
||||
endforeach()
|
||||
@ -244,8 +244,9 @@ elseif(APPLE)
|
||||
endif()
|
||||
|
||||
# Copy shaderc into the bundle
|
||||
target_sources(duckstation-qt PRIVATE "${SHADERC_LIBRARY}")
|
||||
set_source_files_properties("${SHADERC_LIBRARY}" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks)
|
||||
get_target_property(SPIRV_CROSS_LIBRARY spirv-cross-c-shared IMPORTED_LOCATION_RELEASE)
|
||||
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
|
||||
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(METAL_LIBRARY Metal)
|
||||
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)
|
||||
elseif(NOT ANDROID)
|
||||
target_sources(util PRIVATE
|
||||
|
@ -68,9 +68,11 @@ public:
|
||||
void ClearDepth(GPUTexture* t, float d) override;
|
||||
void InvalidateRenderTarget(GPUTexture* t) override;
|
||||
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
||||
const char* entry_point, DynamicHeapArray<u8>* binary) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
|
||||
Error* error) 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;
|
||||
|
||||
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)
|
||||
|
||||
#include "d3d11_pipeline.h"
|
||||
#include "d3d11_device.h"
|
||||
#include "d3d_common.h"
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/log.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
@ -51,7 +52,8 @@ void D3D11Shader::SetDebugName(std::string_view 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;
|
||||
std::vector<u8> bytecode;
|
||||
@ -87,21 +89,31 @@ std::unique_ptr<GPUShader> D3D11Device::CreateShaderFromBinary(GPUShaderStage st
|
||||
}
|
||||
|
||||
if (FAILED(hr) || !shader)
|
||||
{
|
||||
Error::SetHResult(error, "Create[Typed]Shader() failed: ", hr);
|
||||
return {};
|
||||
}
|
||||
|
||||
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,
|
||||
const char* entry_point,
|
||||
DynamicHeapArray<u8>* out_binary)
|
||||
std::unique_ptr<GPUShader> D3D11Device::CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||
std::string_view source, const char* entry_point,
|
||||
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 =
|
||||
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())
|
||||
return {};
|
||||
|
||||
std::unique_ptr<GPUShader> ret = CreateShaderFromBinary(stage, bytecode.value());
|
||||
std::unique_ptr<GPUShader> ret = CreateShaderFromBinary(stage, bytecode.value(), error);
|
||||
if (ret && out_binary)
|
||||
*out_binary = std::move(bytecode.value());
|
||||
|
||||
|
@ -90,9 +90,11 @@ public:
|
||||
void ClearDepth(GPUTexture* t, float d) override;
|
||||
void InvalidateRenderTarget(GPUTexture* t) override;
|
||||
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
||||
const char* entry_point, DynamicHeapArray<u8>* out_binary) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
|
||||
Error* error) 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;
|
||||
|
||||
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.
|
||||
std::vector bytecode(data.begin(), data.end());
|
||||
return std::unique_ptr<GPUShader>(new D3D12Shader(stage, std::move(bytecode)));
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUShader> D3D12Device::CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
||||
const char* entry_point,
|
||||
DynamicHeapArray<u8>* out_binary)
|
||||
std::unique_ptr<GPUShader> D3D12Device::CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||
std::string_view source, const char* entry_point,
|
||||
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 =
|
||||
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())
|
||||
return {};
|
||||
|
||||
std::unique_ptr<GPUShader> ret = CreateShaderFromBinary(stage, bytecode.value());
|
||||
std::unique_ptr<GPUShader> ret = CreateShaderFromBinary(stage, bytecode.value(), error);
|
||||
if (ret && out_binary)
|
||||
*out_binary = std::move(bytecode.value());
|
||||
|
||||
|
@ -372,14 +372,33 @@ std::string D3DCommon::GetDriverVersionFromLUID(const LUID& luid)
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::optional<DynamicHeapArray<u8>> D3DCommon::CompileShader(D3D_FEATURE_LEVEL feature_level, bool debug_device,
|
||||
GPUShaderStage stage, std::string_view source,
|
||||
const char* entry_point)
|
||||
u32 D3DCommon::GetShaderModelForFeatureLevel(D3D_FEATURE_LEVEL feature_level)
|
||||
{
|
||||
const char* target;
|
||||
switch (feature_level)
|
||||
{
|
||||
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 = {
|
||||
{"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;
|
||||
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
case 41:
|
||||
{
|
||||
static constexpr std::array<const char*, static_cast<u32>(GPUShaderStage::MaxCount)> targets = {
|
||||
{"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;
|
||||
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
case 50:
|
||||
{
|
||||
static constexpr std::array<const char*, static_cast<u32>(GPUShaderStage::MaxCount)> targets = {
|
||||
{"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;
|
||||
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
default:
|
||||
case 51:
|
||||
{
|
||||
static constexpr std::array<const char*, static_cast<u32>(GPUShaderStage::MaxCount)> targets = {
|
||||
{"vs_5_1", "ps_5_1", "gs_5_1", "cs_5_1"}};
|
||||
target = targets[static_cast<int>(stage)];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Error::SetStringFmt(error, "Unknown shader model: {}", shader_model);
|
||||
return {};
|
||||
}
|
||||
|
||||
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;
|
||||
if (error_blob)
|
||||
{
|
||||
error_string =
|
||||
std::string_view(static_cast<const char*>(error_blob->GetBufferPointer()), error_blob->GetBufferSize());
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
ERROR_LOG("Failed to compile '{}':\n{}", target, error_string);
|
||||
GPUDevice::DumpBadShader(source, error_string);
|
||||
Error::SetHResult(error, "D3DCompile() failed: ", hr);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -60,9 +60,10 @@ std::string GetAdapterName(IDXGIAdapter1* adapter);
|
||||
// returns the driver version from the registry as a string
|
||||
std::string GetDriverVersionFromLUID(const LUID& luid);
|
||||
|
||||
std::optional<DynamicHeapArray<u8>> CompileShader(D3D_FEATURE_LEVEL feature_level, bool debug_device,
|
||||
GPUShaderStage stage, std::string_view source,
|
||||
const char* entry_point);
|
||||
u32 GetShaderModelForFeatureLevel(D3D_FEATURE_LEVEL feature_level);
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -13,11 +13,14 @@
|
||||
#include "common/file_system.h"
|
||||
#include "common/log.h"
|
||||
#include "common/path.h"
|
||||
#include "common/scoped_guard.h"
|
||||
#include "common/string_util.h"
|
||||
#include "common/timer.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "imgui.h"
|
||||
#include "shaderc/shaderc.h"
|
||||
#include "spirv_cross/spirv_cross_c.h"
|
||||
#include "xxhash.h"
|
||||
|
||||
Log_SetChannel(GPUDevice);
|
||||
@ -37,10 +40,6 @@ Log_SetChannel(GPUDevice);
|
||||
#include "vulkan_device.h"
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_VULKAN) || defined(__APPLE__)
|
||||
#include "shaderc/shaderc.h"
|
||||
#endif
|
||||
|
||||
std::unique_ptr<GPUDevice> g_gpu_device;
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
if (!CreateResources())
|
||||
if (!CreateResources(error))
|
||||
{
|
||||
Error::SetStringView(error, "Failed to create base resources.");
|
||||
Error::AddPrefix(error, "Failed to create base resources.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -459,18 +476,23 @@ bool GPUDevice::AcquireWindow(bool recreate_window)
|
||||
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;
|
||||
}
|
||||
|
||||
if (!(m_linear_sampler = CreateSampler(GPUSampler::GetLinearConfig())))
|
||||
return false;
|
||||
const RenderAPI render_api = GetRenderAPI();
|
||||
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.GenerateImGuiVertexShader());
|
||||
std::unique_ptr<GPUShader> imgui_fs = CreateShader(GPUShaderStage::Fragment, shadergen.GenerateImGuiFragmentShader());
|
||||
std::unique_ptr<GPUShader> imgui_vs =
|
||||
CreateShader(GPUShaderStage::Vertex, shadergen.GetLanguage(), shadergen.GenerateImGuiVertexShader(), error);
|
||||
std::unique_ptr<GPUShader> imgui_fs =
|
||||
CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(), shadergen.GenerateImGuiFragmentShader(), error);
|
||||
if (!imgui_vs || !imgui_fs)
|
||||
return false;
|
||||
GL_OBJECT_NAME(imgui_vs, "ImGui Vertex Shader");
|
||||
@ -505,7 +527,7 @@ bool GPUDevice::CreateResources()
|
||||
m_imgui_pipeline = CreatePipeline(plconfig);
|
||||
if (!m_imgui_pipeline)
|
||||
{
|
||||
ERROR_LOG("Failed to compile ImGui pipeline.");
|
||||
Error::SetStringView(error, "Failed to compile ImGui pipeline.");
|
||||
return false;
|
||||
}
|
||||
GL_OBJECT_NAME(m_imgui_pipeline, "ImGui Pipeline");
|
||||
@ -642,21 +664,22 @@ void GPUDevice::InvalidateRenderTarget(GPUTexture* t)
|
||||
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" */)
|
||||
{
|
||||
std::unique_ptr<GPUShader> shader;
|
||||
if (!m_shader_cache.IsOpen())
|
||||
{
|
||||
shader = CreateShaderFromSource(stage, source, entry_point, nullptr);
|
||||
shader = CreateShaderFromSource(stage, language, source, entry_point, nullptr, error);
|
||||
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;
|
||||
if (m_shader_cache.Lookup(key, &binary))
|
||||
{
|
||||
shader = CreateShaderFromBinary(stage, binary);
|
||||
shader = CreateShaderFromBinary(stage, binary, error);
|
||||
if (shader)
|
||||
return shader;
|
||||
|
||||
@ -664,7 +687,7 @@ std::unique_ptr<GPUShader> GPUDevice::CreateShader(GPUShaderStage stage, std::st
|
||||
m_shader_cache.Clear();
|
||||
}
|
||||
|
||||
shader = CreateShaderFromSource(stage, source, entry_point, &binary);
|
||||
shader = CreateShaderFromSource(stage, language, source, entry_point, &binary, error);
|
||||
if (!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) \
|
||||
X(shaderc_compiler_initialize) \
|
||||
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_error_message)
|
||||
|
||||
// TODO: NOT thread safe, yet.
|
||||
namespace dyn_shaderc {
|
||||
static bool Open();
|
||||
static void Close();
|
||||
#define SPIRV_CROSS_FUNCTIONS(X) \
|
||||
X(spvc_context_create) \
|
||||
X(spvc_context_destroy) \
|
||||
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;
|
||||
static shaderc_compiler_t s_compiler = nullptr;
|
||||
#ifdef _WIN32
|
||||
#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;
|
||||
SHADERC_FUNCTIONS(ADD_FUNC)
|
||||
SPIRV_CROSS_FUNCTIONS(ADD_FUNC)
|
||||
SPIRV_CROSS_HLSL_FUNCTIONS(ADD_FUNC)
|
||||
SPIRV_CROSS_MSL_FUNCTIONS(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;
|
||||
|
||||
Error error;
|
||||
|
||||
#ifdef _WIN32
|
||||
const std::string libname = DynamicLibrary::GetVersionedFilename("shaderc_shared");
|
||||
#else
|
||||
// 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))
|
||||
if (!s_shaderc_library.Open(libname.c_str(), error))
|
||||
{
|
||||
ERROR_LOG("Failed to load shaderc: {}", error.GetDescription());
|
||||
Error::AddPrefix(error, "Failed to load shaderc: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
#define LOAD_FUNC(F) \
|
||||
if (!s_library.GetSymbol(#F, &F)) \
|
||||
if (!s_shaderc_library.GetSymbol(#F, &F)) \
|
||||
{ \
|
||||
ERROR_LOG("Failed to find function {}", #F); \
|
||||
Close(); \
|
||||
Error::SetStringFmt(error, "Failed to find function {}", #F); \
|
||||
CloseShaderc(); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
SHADERC_FUNCTIONS(LOAD_FUNC)
|
||||
#undef LOAD_FUNC
|
||||
|
||||
s_compiler = shaderc_compiler_initialize();
|
||||
if (!s_compiler)
|
||||
s_shaderc_compiler = shaderc_compiler_initialize();
|
||||
if (!s_shaderc_compiler)
|
||||
{
|
||||
ERROR_LOG("shaderc_compiler_initialize() failed");
|
||||
Close();
|
||||
Error::SetStringView(error, "shaderc_compiler_initialize() failed");
|
||||
CloseShaderc();
|
||||
return false;
|
||||
}
|
||||
|
||||
std::atexit(&dyn_shaderc::Close);
|
||||
if (!s_close_registered)
|
||||
{
|
||||
s_close_registered = true;
|
||||
std::atexit(&dyn_libs::CloseAll);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dyn_shaderc::Close()
|
||||
void dyn_libs::CloseShaderc()
|
||||
{
|
||||
if (s_compiler)
|
||||
if (s_shaderc_compiler)
|
||||
{
|
||||
shaderc_compiler_release(s_compiler);
|
||||
s_compiler = nullptr;
|
||||
shaderc_compiler_release(s_shaderc_compiler);
|
||||
s_shaderc_compiler = nullptr;
|
||||
}
|
||||
|
||||
#define UNLOAD_FUNC(F) F = nullptr;
|
||||
SHADERC_FUNCTIONS(UNLOAD_FUNC)
|
||||
#undef UNLOAD_FUNC
|
||||
|
||||
s_library.Close();
|
||||
s_shaderc_library.Close();
|
||||
}
|
||||
|
||||
#undef SHADERC_FUNCTIONS
|
||||
#undef SHADERC_INIT_FUNCTIONS
|
||||
bool dyn_libs::OpenSpirvCross(Error* error)
|
||||
{
|
||||
if (s_spirv_cross_library.IsOpen())
|
||||
return true;
|
||||
|
||||
bool GPUDevice::CompileGLSLShaderToVulkanSpv(GPUShaderStage stage, std::string_view source, const char* entry_point,
|
||||
bool nonsemantic_debug_info, DynamicHeapArray<u8>* out_binary)
|
||||
const std::string libname = DynamicLibrary::GetVersionedFilename("spirv-cross-c-shared");
|
||||
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 = {{
|
||||
shaderc_glsl_vertex_shader,
|
||||
@ -1197,46 +1308,323 @@ bool GPUDevice::CompileGLSLShaderToVulkanSpv(GPUShaderStage stage, std::string_v
|
||||
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;
|
||||
|
||||
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");
|
||||
|
||||
dyn_shaderc::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_shaderc::shaderc_compile_options_set_generate_debug_info(options, m_debug_device,
|
||||
m_debug_device && nonsemantic_debug_info);
|
||||
dyn_shaderc::shaderc_compile_options_set_optimization_level(
|
||||
dyn_libs::shaderc_compile_options_set_source_language(options, shaderc_source_language_glsl);
|
||||
dyn_libs::shaderc_compile_options_set_target_env(options, shaderc_target_env_vulkan, 0);
|
||||
dyn_libs::shaderc_compile_options_set_generate_debug_info(options, m_debug_device,
|
||||
m_debug_device && nonsemantic_debug_info);
|
||||
dyn_libs::shaderc_compile_options_set_optimization_level(
|
||||
options, m_debug_device ? shaderc_optimization_level_zero : shaderc_optimization_level_performance);
|
||||
|
||||
shaderc_compilation_result_t result;
|
||||
const shaderc_compilation_status status = dyn_shaderc::shaderc_compile_into_spv(
|
||||
dyn_shaderc::s_compiler, source.data(), source.length(), stage_kinds[static_cast<size_t>(stage)], "source",
|
||||
const shaderc_compilation_status status = dyn_libs::shaderc_compile_into_spv(
|
||||
dyn_libs::s_shaderc_compiler, source.data(), source.length(), stage_kinds[static_cast<size_t>(stage)], "source",
|
||||
entry_point, options, &result);
|
||||
if (status != shaderc_compilation_status_success)
|
||||
{
|
||||
const std::string_view errors(result ? dyn_shaderc::shaderc_result_get_error_message(result) :
|
||||
"null result object");
|
||||
ERROR_LOG("Failed to compile shader to SPIR-V: {}\n{}", dyn_shaderc::shaderc_compilation_status_to_string(status),
|
||||
const std::string_view errors(result ? dyn_libs::shaderc_result_get_error_message(result) : "null result object");
|
||||
Error::SetStringFmt(error, "Failed to compile shader to SPIR-V: {}\n{}",
|
||||
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);
|
||||
DumpBadShader(source, errors);
|
||||
}
|
||||
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)
|
||||
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);
|
||||
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_shaderc::shaderc_compile_options_release(options);
|
||||
dyn_libs::shaderc_result_release(result);
|
||||
dyn_libs::shaderc_compile_options_release(options);
|
||||
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
|
||||
}
|
||||
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
|
||||
};
|
||||
|
||||
enum class GPUShaderLanguage : u8
|
||||
{
|
||||
None,
|
||||
HLSL,
|
||||
GLSL,
|
||||
GLSLES,
|
||||
GLSLVK,
|
||||
MSL,
|
||||
SPV,
|
||||
Count
|
||||
};
|
||||
|
||||
class GPUShader
|
||||
{
|
||||
public:
|
||||
@ -522,6 +534,9 @@ public:
|
||||
/// Returns a string representing the specified 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.
|
||||
static std::unique_ptr<GPUDevice> CreateDeviceForAPI(RenderAPI api);
|
||||
|
||||
@ -630,8 +645,8 @@ public:
|
||||
virtual void InvalidateRenderTarget(GPUTexture* t);
|
||||
|
||||
/// Shader abstraction.
|
||||
std::unique_ptr<GPUShader> CreateShader(GPUShaderStage stage, std::string_view source,
|
||||
const char* entry_point = "main");
|
||||
std::unique_ptr<GPUShader> CreateShader(GPUShaderStage stage, GPUShaderLanguage language, std::string_view source,
|
||||
Error* error = nullptr, const char* entry_point = "main");
|
||||
virtual std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) = 0;
|
||||
|
||||
/// Debug messaging.
|
||||
@ -716,19 +731,26 @@ protected:
|
||||
virtual bool ReadPipelineCache(const std::string& filename);
|
||||
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> CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
||||
const char* entry_point,
|
||||
DynamicHeapArray<u8>* out_binary) = 0;
|
||||
virtual std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
|
||||
Error* error) = 0;
|
||||
virtual std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||
std::string_view source, const char* entry_point,
|
||||
DynamicHeapArray<u8>* out_binary, Error* error) = 0;
|
||||
|
||||
bool AcquireWindow(bool recreate_window);
|
||||
|
||||
void TrimTexturePool();
|
||||
|
||||
#if defined(ENABLE_VULKAN) || defined(__APPLE__)
|
||||
bool CompileGLSLShaderToVulkanSpv(GPUShaderStage stage, std::string_view source, const char* entry_point,
|
||||
bool nonsemantic_debug_info, DynamicHeapArray<u8>* out_binary);
|
||||
#endif
|
||||
bool CompileGLSLShaderToVulkanSpv(GPUShaderStage stage, GPUShaderLanguage source_language, std::string_view source,
|
||||
const char* entry_point, bool nonsemantic_debug_info,
|
||||
DynamicHeapArray<u8>* out_binary, Error* error);
|
||||
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 = {};
|
||||
u32 m_max_texture_size = 0;
|
||||
@ -778,7 +800,7 @@ private:
|
||||
|
||||
void OpenShaderCache(std::string_view base_path, u32 version);
|
||||
void CloseShaderCache();
|
||||
bool CreateResources();
|
||||
bool CreateResources(Error* error);
|
||||
void DestroyResources();
|
||||
|
||||
static bool IsTexturePoolType(GPUTexture::Type type);
|
||||
|
@ -20,7 +20,9 @@ Log_SetChannel(GPUShaderCache);
|
||||
#pragma pack(push, 1)
|
||||
struct CacheIndexEntry
|
||||
{
|
||||
u32 shader_type;
|
||||
u8 shader_type;
|
||||
u8 shader_language;
|
||||
u8 unused[2];
|
||||
u32 source_length;
|
||||
u64 source_hash_low;
|
||||
u64 source_hash_high;
|
||||
@ -202,8 +204,9 @@ bool GPUShaderCache::ReadExisting(const std::string& index_filename, const std::
|
||||
return false;
|
||||
}
|
||||
|
||||
const CacheIndexKey key{entry.shader_type, entry.source_length, entry.source_hash_low,
|
||||
entry.source_hash_high, entry.entry_point_low, entry.entry_point_high};
|
||||
const CacheIndexKey key{entry.shader_type, entry.shader_language, {},
|
||||
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};
|
||||
m_index.emplace(key, data);
|
||||
}
|
||||
@ -215,8 +218,8 @@ bool GPUShaderCache::ReadExisting(const std::string& index_filename, const std::
|
||||
return true;
|
||||
}
|
||||
|
||||
GPUShaderCache::CacheIndexKey GPUShaderCache::GetCacheKey(GPUShaderStage stage, std::string_view shader_code,
|
||||
std::string_view entry_point)
|
||||
GPUShaderCache::CacheIndexKey GPUShaderCache::GetCacheKey(GPUShaderStage stage, GPUShaderLanguage language,
|
||||
std::string_view shader_code, std::string_view entry_point)
|
||||
{
|
||||
union
|
||||
{
|
||||
@ -229,7 +232,8 @@ GPUShaderCache::CacheIndexKey GPUShaderCache::GetCacheKey(GPUShaderStage stage,
|
||||
} h;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
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_hash_low = key.source_hash_low;
|
||||
entry.source_hash_high = key.source_hash_high;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <vector>
|
||||
|
||||
enum class GPUShaderStage : u8;
|
||||
enum class GPUShaderLanguage : u8;
|
||||
|
||||
class GPUShaderCache
|
||||
{
|
||||
@ -21,7 +22,9 @@ public:
|
||||
|
||||
struct alignas(8) CacheIndexKey
|
||||
{
|
||||
u32 shader_type;
|
||||
u8 shader_type;
|
||||
u8 shader_language;
|
||||
u8 unused[2];
|
||||
u32 source_length;
|
||||
u64 source_hash_low;
|
||||
u64 source_hash_high;
|
||||
@ -50,7 +53,8 @@ public:
|
||||
bool Create();
|
||||
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 Insert(const CacheIndexKey& key, const void* data, u32 data_size);
|
||||
|
@ -231,10 +231,11 @@ public:
|
||||
void ClearDepth(GPUTexture* t, float d) override;
|
||||
void InvalidateRenderTarget(GPUTexture* t) override;
|
||||
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
||||
const char* entry_point,
|
||||
DynamicHeapArray<u8>* out_binary = nullptr) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
|
||||
Error* error) 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;
|
||||
|
||||
void PushDebugGroup(const char* name) override;
|
||||
@ -328,7 +329,7 @@ private:
|
||||
id<MTLRenderPipelineState> GetClearDepthPipeline(const ClearPipelineConfig& config);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -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)
|
||||
|
||||
#include "metal_device.h"
|
||||
@ -16,8 +16,6 @@
|
||||
#define FMT_EXCEPTIONS 0
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "spirv_cross_c.h"
|
||||
|
||||
#include <array>
|
||||
#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::string_view entry_point)
|
||||
std::string_view entry_point, Error* error)
|
||||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
NSString* const ns_source = StringViewToNSString(source);
|
||||
NSError* error = nullptr;
|
||||
id<MTLLibrary> library = [m_device newLibraryWithSource:ns_source options:nil error:&error];
|
||||
NSError* nserror = nullptr;
|
||||
id<MTLLibrary> library = [m_device newLibraryWithSource:ns_source options:nil error:&nserror];
|
||||
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];
|
||||
DumpBadShader(source, fmt::format("Error {}: {}", static_cast<u32>(error.code), utf_error ? utf_error : ""));
|
||||
const char* utf_error = [nserror.description UTF8String];
|
||||
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 {};
|
||||
}
|
||||
|
||||
@ -632,6 +632,7 @@ std::unique_ptr<GPUShader> MetalDevice::CreateShaderFromMSL(GPUShaderStage stage
|
||||
if (!function)
|
||||
{
|
||||
ERROR_LOG("Failed to get main function in compiled library");
|
||||
Error::SetStringView(error, "Failed to get main function in compiled library");
|
||||
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());
|
||||
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,
|
||||
const char* entry_point,
|
||||
DynamicHeapArray<u8>* out_binary /* = nullptr */)
|
||||
std::unique_ptr<GPUShader> MetalDevice::CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||
std::string_view source, const char* entry_point,
|
||||
DynamicHeapArray<u8>* out_binary, Error* error)
|
||||
{
|
||||
static constexpr bool dump_shaders = false;
|
||||
|
||||
DynamicHeapArray<u8> local_binary;
|
||||
DynamicHeapArray<u8>* dest_binary = out_binary ? out_binary : &local_binary;
|
||||
if (!CompileGLSLShaderToVulkanSpv(stage, source, entry_point, false, dest_binary))
|
||||
DynamicHeapArray<u8> spv;
|
||||
if (!CompileGLSLShaderToVulkanSpv(stage, language, source, entry_point, false, &spv, error))
|
||||
return {};
|
||||
|
||||
AssertMsg((dest_binary->size() % 4) == 0, "Compile result should be 4 byte aligned.");
|
||||
|
||||
spvc_context sctx;
|
||||
spvc_result sres;
|
||||
if ((sres = spvc_context_create(&sctx)) != SPVC_SUCCESS)
|
||||
{
|
||||
ERROR_LOG("spvc_context_create() failed: {}", static_cast<int>(sres));
|
||||
std::string msl;
|
||||
if (!TranslateVulkanSpvToLanguage(spv.cspan(), stage, GPUShaderLanguage::MSL, 230, &msl, error))
|
||||
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)
|
||||
{
|
||||
static unsigned s_next_id = 0;
|
||||
++s_next_id;
|
||||
DumpShader(s_next_id, "_input", source);
|
||||
DumpShader(s_next_id, "_msl", mslv);
|
||||
DumpShader(s_next_id, "_msl", msl);
|
||||
}
|
||||
|
||||
if (out_binary)
|
||||
{
|
||||
out_binary->resize(mslv.size());
|
||||
std::memcpy(out_binary->data(), mslv.data(), mslv.size());
|
||||
out_binary->resize(msl.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,
|
||||
@ -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));
|
||||
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);
|
||||
DEV_LOG("Trying to import {} bytes of memory at {} for download texture", page_aligned_memory,
|
||||
page_aligned_size);
|
||||
DEV_LOG("Trying to import {} bytes of memory at {} for download texture", page_aligned_memory, page_aligned_size);
|
||||
|
||||
buffer = [[dev.m_device newBufferWithBytesNoCopy:page_aligned_memory
|
||||
length:page_aligned_size
|
||||
|
@ -1092,7 +1092,7 @@ void OpenGLDevice::PushUniformBuffer(const void* data, u32 data_size)
|
||||
std::memcpy(res.pointer, data, data_size);
|
||||
m_uniform_buffer->Unmap(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)
|
||||
@ -1105,7 +1105,7 @@ void OpenGLDevice::UnmapUniformBuffer(u32 size)
|
||||
{
|
||||
const u32 pos = m_uniform_buffer->Unmap(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,
|
||||
|
@ -72,9 +72,11 @@ public:
|
||||
void ClearDepth(GPUTexture* t, float d) override;
|
||||
void InvalidateRenderTarget(GPUTexture* t) override;
|
||||
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
||||
const char* entry_point, DynamicHeapArray<u8>* out_binary) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data,
|
||||
Error* error) 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;
|
||||
|
||||
void PushDebugGroup(const char* name) override;
|
||||
|
@ -158,24 +158,35 @@ bool OpenGLShader::Compile()
|
||||
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...
|
||||
Error::SetStringView(error, "Not supported.");
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUShader> OpenGLDevice::CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
||||
const char* entry_point,
|
||||
DynamicHeapArray<u8>* out_binary)
|
||||
std::unique_ptr<GPUShader> OpenGLDevice::CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||
std::string_view source, const char* entry_point,
|
||||
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)
|
||||
{
|
||||
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 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)
|
||||
{
|
||||
ERROR_LOG("Program linked with warnings:\n{}", info_log.c_str());
|
||||
ERROR_LOG("Program linked with warnings:\n{}", info_log);
|
||||
}
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
@ -402,7 +428,7 @@ void OpenGLDevice::PostLinkProgram(const GPUPipeline::GraphicsConfig& plconfig,
|
||||
{
|
||||
GLint location = glGetUniformBlockIndex(program_id, "UBOBlock");
|
||||
if (location >= 0)
|
||||
glUniformBlockBinding(program_id, location, 1);
|
||||
glUniformBlockBinding(program_id, location, 0);
|
||||
|
||||
glUseProgram(program_id);
|
||||
|
||||
|
@ -22,6 +22,7 @@ public:
|
||||
|
||||
ALWAYS_INLINE GLuint GetGLId() const { return m_id.value(); }
|
||||
ALWAYS_INLINE const GPUShaderCache::CacheIndexKey& GetKey() const { return m_key; }
|
||||
ALWAYS_INLINE const std::string& GetSource() const { return m_source; }
|
||||
|
||||
private:
|
||||
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";
|
||||
#ifdef ENABLE_OPENGL
|
||||
if (api == RenderAPI::OpenGL || api == RenderAPI::OpenGLES)
|
||||
version_string = ShaderGen::GetGLSLVersionString(api);
|
||||
version_string = ShaderGen::GetGLSLVersionString(api, ShaderGen::GetGLSLVersion(api));
|
||||
#endif
|
||||
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);
|
||||
|
||||
std::unique_ptr<GPUShader> sshader =
|
||||
g_gpu_device->CreateShader(stage, real_code, needs_main_defn ? "main" : name.c_str());
|
||||
Error error;
|
||||
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)
|
||||
ERROR_LOG("Failed to compile function '{}'", name);
|
||||
ERROR_LOG("Failed to compile function '{}': {}", name, error.GetDescription());
|
||||
|
||||
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,
|
||||
g_gpu_device->GetFeatures().framebuffer_fetch);
|
||||
|
||||
std::unique_ptr<GPUShader> vs =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GeneratePostProcessingVertexShader(*this));
|
||||
std::unique_ptr<GPUShader> fs =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GeneratePostProcessingFragmentShader(*this));
|
||||
std::unique_ptr<GPUShader> vs = g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GetLanguage(),
|
||||
shadergen.GeneratePostProcessingVertexShader(*this));
|
||||
std::unique_ptr<GPUShader> fs = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||
shadergen.GeneratePostProcessingFragmentShader(*this));
|
||||
if (!vs || !fs)
|
||||
return false;
|
||||
|
||||
@ -328,7 +328,7 @@ void PostProcessing::GLSLShader::LoadOptions()
|
||||
|
||||
PostProcessingGLSLShaderGen::PostProcessingGLSLShaderGen(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, GPUShaderLanguage::GLSLVK, supports_dual_source_blend, supports_framebuffer_fetch)
|
||||
{
|
||||
}
|
||||
|
||||
@ -365,49 +365,13 @@ std::string PostProcessingGLSLShaderGen::GeneratePostProcessingFragmentShader(co
|
||||
WriteUniformBuffer(ss, shader, false);
|
||||
DeclareTexture(ss, "samp0", 0);
|
||||
|
||||
// Rename main, since we need to set up globals
|
||||
if (!m_glsl)
|
||||
{
|
||||
// TODO: vecn -> floatn
|
||||
|
||||
ss << R"(
|
||||
#define main real_main
|
||||
static float2 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";
|
||||
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"(
|
||||
layout(location = 0) in VertexData {
|
||||
vec2 v_tex0;
|
||||
};
|
||||
|
||||
layout(location = 0) out float4 o_col0;
|
||||
|
||||
float4 Sample() { return texture(samp0, v_tex0); }
|
||||
float4 SampleLocation(float2 location) { return texture(samp0, location); }
|
||||
#define SampleOffset(offset) textureOffset(samp0, v_tex0, offset)
|
||||
@ -439,21 +403,6 @@ float2 GetWindowResolution() { return u_window_size; }
|
||||
)";
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -17,39 +17,66 @@
|
||||
|
||||
Log_SetChannel(ShaderGen);
|
||||
|
||||
ShaderGen::ShaderGen(RenderAPI render_api, bool supports_dual_source_blend, bool supports_framebuffer_fetch)
|
||||
: m_render_api(render_api), m_glsl(render_api != RenderAPI::D3D11 && render_api != RenderAPI::D3D12),
|
||||
m_spirv(render_api == RenderAPI::Vulkan || render_api == RenderAPI::Metal),
|
||||
m_supports_dual_source_blend(supports_dual_source_blend), m_supports_framebuffer_fetch(supports_framebuffer_fetch),
|
||||
m_use_glsl_interface_blocks(false)
|
||||
ShaderGen::ShaderGen(RenderAPI render_api, GPUShaderLanguage shader_language, bool supports_dual_source_blend,
|
||||
bool supports_framebuffer_fetch)
|
||||
: m_render_api(render_api), m_shader_language(shader_language),
|
||||
m_glsl(shader_language == GPUShaderLanguage::GLSL || shader_language == GPUShaderLanguage::GLSLES ||
|
||||
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)
|
||||
{
|
||||
#ifdef ENABLE_OPENGL
|
||||
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_binding_layout = (IsVulkan() || IsMetal() || UseGLSLBindingLayout());
|
||||
m_use_glsl_interface_blocks =
|
||||
(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.
|
||||
const char* gl_vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
||||
if (std::strcmp(gl_vendor, "ATI Technologies Inc.") == 0)
|
||||
m_use_glsl_interface_blocks = false;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
m_use_glsl_interface_blocks = true;
|
||||
m_use_glsl_binding_layout = true;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
#ifdef ENABLE_OPENGL
|
||||
@ -72,7 +99,7 @@ void ShaderGen::DefineMacro(std::stringstream& ss, const char* name, s32 value)
|
||||
}
|
||||
|
||||
#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 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,
|
||||
(glsl_es && major_version >= 3) ? " es" : "");
|
||||
}
|
||||
@ -115,7 +151,7 @@ TinyString ShaderGen::GetGLSLVersionString(RenderAPI render_api)
|
||||
|
||||
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";
|
||||
else if (m_spirv)
|
||||
ss << "#version 450 core\n\n";
|
||||
@ -131,7 +167,7 @@ void ShaderGen::WriteHeader(std::stringstream& ss)
|
||||
|
||||
#ifdef ENABLE_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)
|
||||
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";
|
||||
}
|
||||
|
||||
if (m_render_api == RenderAPI::OpenGLES)
|
||||
if (m_shader_language == GPUShaderLanguage::GLSLES)
|
||||
{
|
||||
// Enable EXT_blend_func_extended for dual-source blend on OpenGL ES.
|
||||
if (GLAD_GL_EXT_blend_func_extended)
|
||||
@ -158,7 +194,7 @@ void ShaderGen::WriteHeader(std::stringstream& ss)
|
||||
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.
|
||||
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);
|
||||
|
||||
#ifdef ENABLE_OPENGL
|
||||
if (m_render_api == RenderAPI::OpenGLES)
|
||||
if (m_shader_language == GPUShaderLanguage::GLSLES)
|
||||
{
|
||||
ss << "precision highp float;\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)
|
||||
{
|
||||
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";
|
||||
}
|
||||
@ -311,15 +347,10 @@ void ShaderGen::WriteUniformBufferDeclaration(std::stringstream& ss, bool push_c
|
||||
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)
|
||||
{
|
||||
if (m_use_glsl_binding_layout)
|
||||
ss << "layout(std140, binding = 1) uniform UBOBlock\n";
|
||||
ss << "layout(std140, binding = 0) uniform UBOBlock\n";
|
||||
else
|
||||
ss << "layout(std140) uniform UBOBlock\n";
|
||||
|
||||
|
@ -13,15 +13,20 @@
|
||||
class ShaderGen
|
||||
{
|
||||
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();
|
||||
|
||||
static GPUShaderLanguage GetShaderLanguageForAPI(RenderAPI api);
|
||||
static bool UseGLSLBindingLayout();
|
||||
|
||||
#ifdef ENABLE_OPENGL
|
||||
static TinyString GetGLSLVersionString(RenderAPI render_api);
|
||||
static u32 GetGLSLVersion(RenderAPI render_api);
|
||||
static TinyString GetGLSLVersionString(RenderAPI render_api, u32 version);
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE GPUShaderLanguage GetLanguage() const { return m_shader_language; }
|
||||
|
||||
std::string GenerateScreenQuadVertexShader(float z = 0.0f);
|
||||
std::string GenerateUVQuadVertexShader();
|
||||
std::string GenerateFillFragmentShader();
|
||||
@ -58,6 +63,7 @@ protected:
|
||||
bool noperspective_color = false, bool feedback_loop = false);
|
||||
|
||||
RenderAPI m_render_api;
|
||||
GPUShaderLanguage m_shader_language;
|
||||
bool m_glsl;
|
||||
bool m_spirv;
|
||||
bool m_supports_dual_source_blend;
|
||||
|
@ -39,6 +39,7 @@
|
||||
<DepsDLLs Include="$(DepsBinDir)libwebp.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)SDL2.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)shaderc_shared.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)spirv-cross-c-shared.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)zlib1.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)zstd.dll" />
|
||||
</ItemGroup>
|
||||
|
@ -98,9 +98,10 @@ public:
|
||||
void ClearDepth(GPUTexture* t, float d) override;
|
||||
void InvalidateRenderTarget(GPUTexture* t) override;
|
||||
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
||||
const char* entry_point, DynamicHeapArray<u8>* out_binary) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShaderStage stage, std::span<const u8> data, Error* error) 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;
|
||||
|
||||
void PushDebugGroup(const char* name) override;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "vulkan_device.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
#include "common/log.h"
|
||||
|
||||
Log_SetChannel(VulkanDevice);
|
||||
@ -24,7 +25,8 @@ void VulkanShader::SetDebugName(std::string_view 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;
|
||||
|
||||
@ -34,27 +36,37 @@ std::unique_ptr<GPUShader> VulkanDevice::CreateShaderFromBinary(GPUShaderStage s
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateShaderModule() failed: ");
|
||||
Error::SetStringFmt(error, "vkCreateShaderModule() failed: {}", Vulkan::VkResultToString(res));
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::unique_ptr<GPUShader>(new VulkanShader(stage, mod));
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUShader> VulkanDevice::CreateShaderFromSource(GPUShaderStage stage, std::string_view source,
|
||||
const char* entry_point,
|
||||
DynamicHeapArray<u8>* out_binary)
|
||||
std::unique_ptr<GPUShader> VulkanDevice::CreateShaderFromSource(GPUShaderStage stage, GPUShaderLanguage language,
|
||||
std::string_view source, const char* entry_point,
|
||||
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>* dest_binary = out_binary ? out_binary : &local_binary;
|
||||
if (!CompileGLSLShaderToVulkanSpv(stage, source, entry_point, m_optional_extensions.vk_khr_shader_non_semantic_info,
|
||||
dest_binary))
|
||||
if (!CompileGLSLShaderToVulkanSpv(stage, language, source, entry_point,
|
||||
m_optional_extensions.vk_khr_shader_non_semantic_info, dest_binary, error))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
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
Block a user