diff --git a/CMakeLists.txt b/CMakeLists.txt index f5b78edc4..62c62c39a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,8 +272,7 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$") endif() if (ENABLE_VULKAN) - find_library(SHADERC_LIB shaderc) - find_library(SHADERC_UTIL_LIB shaderc_util) + find_package(glslang CONFIG REQUIRED) endif() # Setup a custom clang-format target (if clang-format can be found) that will run diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp index 3f731f624..0753de565 100644 --- a/src/input_common/touch_from_button.cpp +++ b/src/input_common/touch_from_button.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include "core/3ds.h" #include "core/settings.h" #include "input_common/touch_from_button.h" diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 6085e259c..72087a6cd 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -13,4 +13,4 @@ add_library(network STATIC create_target_directory_groups(network) -target_link_libraries(network PRIVATE common unofficial-enet Boost::serialization) +target_link_libraries(network PRIVATE common unofficial::enet::enet Boost::serialization) diff --git a/src/tests/video_core/shader/shader_jit_x64_compiler.cpp b/src/tests/video_core/shader/shader_jit_x64_compiler.cpp index 514b8405d..1e0a01fe7 100644 --- a/src/tests/video_core/shader/shader_jit_x64_compiler.cpp +++ b/src/tests/video_core/shader/shader_jit_x64_compiler.cpp @@ -66,9 +66,9 @@ TEST_CASE("LG2", "[video_core][shader][shader_jit]") { REQUIRE(std::isnan(shader.Run(NAN))); REQUIRE(std::isnan(shader.Run(-1.f))); REQUIRE(std::isinf(shader.Run(0.f))); - REQUIRE(shader.Run(4.f) == Catch2::Approx(2.f)); - REQUIRE(shader.Run(64.f) == Catch2::Approx(6.f)); - REQUIRE(shader.Run(1.e24f) == Catch2::Approx(79.7262742773f)); + REQUIRE(shader.Run(4.f) == Catch::Approx(2.f)); + REQUIRE(shader.Run(64.f) == Catch::Approx(6.f)); + REQUIRE(shader.Run(1.e24f) == Catch::Approx(79.7262742773f)); } TEST_CASE("EX2", "[video_core][shader][shader_jit]") { @@ -83,10 +83,10 @@ TEST_CASE("EX2", "[video_core][shader][shader_jit]") { }); REQUIRE(std::isnan(shader.Run(NAN))); - REQUIRE(shader.Run(-800.f) == Catch2::Approx(0.f)); - REQUIRE(shader.Run(0.f) == Catch2::Approx(1.f)); - REQUIRE(shader.Run(2.f) == Catch2::Approx(4.f)); - REQUIRE(shader.Run(6.f) == Catch2::Approx(64.f)); - REQUIRE(shader.Run(79.7262742773f) == Catch2::Approx(1.e24f)); + REQUIRE(shader.Run(-800.f) == Catch::Approx(0.f)); + REQUIRE(shader.Run(0.f) == Catch::Approx(1.f)); + REQUIRE(shader.Run(2.f) == Catch::Approx(4.f)); + REQUIRE(shader.Run(6.f) == Catch::Approx(64.f)); + REQUIRE(shader.Run(79.7262742773f) == Catch::Approx(1.e24f)); REQUIRE(std::isinf(shader.Run(800.f))); } diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index cc3eabca1..2e2d47c0d 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -180,7 +180,7 @@ target_link_libraries(video_core PRIVATE glad::glad glm::glm nihstro-headers Boo # Include Vulkan headers target_include_directories(video_core PRIVATE ../../externals/Vulkan-Headers/include) target_include_directories(video_core PRIVATE ../../externals/vma/include) -target_link_libraries(video_core PRIVATE ${SHADERC_LIB} ${SHADERC_UTIL_LIB}) +target_link_libraries(video_core PRIVATE glslang SPIRV glslang-default-resource-limits OGLCompiler) if (ARCHITECTURE_x86_64) target_link_libraries(video_core PUBLIC xbyak::xbyak) diff --git a/src/video_core/renderer_vulkan/vk_shader_gen.cpp b/src/video_core/renderer_vulkan/vk_shader_gen.cpp index c92851b70..832632fec 100644 --- a/src/video_core/renderer_vulkan/vk_shader_gen.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_gen.cpp @@ -5,8 +5,6 @@ #include #include #include -#include -#include #include "common/assert.h" #include "common/bit_field.h" #include "common/bit_set.h" @@ -23,6 +21,10 @@ #include "video_core/renderer_opengl/gl_shader_util.h" #include "video_core/video_core.h" +#include +#include +#include + using Pica::FramebufferRegs; using Pica::LightingRegs; using Pica::RasterizerRegs; @@ -1663,42 +1665,205 @@ void main() { return out; } -vk::ShaderModule CompileShader(const std::string& source, vk::ShaderStageFlagBits stage) { - shaderc::Compiler compiler; - shaderc::CompileOptions options; - options.SetOptimizationLevel(shaderc_optimization_level_zero); - options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_1); - options.SetWarningsAsErrors(); - options.SetSourceLanguage(shaderc_source_language_glsl); +bool InitializeCompiler() { + static bool glslang_initialized = false; - shaderc_shader_kind kind{}; - std::string name{}; - switch (stage) { + if (glslang_initialized) { + return true; + } + + if (!glslang::InitializeProcess()) { + LOG_CRITICAL(Render_Vulkan, "Failed to initialize glslang shader compiler"); + return false; + } + + std::atexit([]() { glslang::FinalizeProcess(); }); + + glslang_initialized = true; + return true; +} + +const TBuiltInResource DefaultTBuiltInResource = { + .maxLights = 32, + .maxClipPlanes = 6, + .maxTextureUnits = 32, + .maxTextureCoords = 32, + .maxVertexAttribs = 64, + .maxVertexUniformComponents = 4096, + .maxVaryingFloats = 64, + .maxVertexTextureImageUnits = 32, + .maxCombinedTextureImageUnits = 80, + .maxTextureImageUnits = 32, + .maxFragmentUniformComponents = 4096, + .maxDrawBuffers = 32, + .maxVertexUniformVectors = 128, + .maxVaryingVectors = 8, + .maxFragmentUniformVectors = 16, + .maxVertexOutputVectors = 16, + .maxFragmentInputVectors = 15, + .minProgramTexelOffset = -8, + .maxProgramTexelOffset = 7, + .maxClipDistances = 8, + .maxComputeWorkGroupCountX = 65535, + .maxComputeWorkGroupCountY = 65535, + .maxComputeWorkGroupCountZ = 65535, + .maxComputeWorkGroupSizeX = 1024, + .maxComputeWorkGroupSizeY = 1024, + .maxComputeWorkGroupSizeZ = 64, + .maxComputeUniformComponents = 1024, + .maxComputeTextureImageUnits = 16, + .maxComputeImageUniforms = 8, + .maxComputeAtomicCounters = 8, + .maxComputeAtomicCounterBuffers = 1, + .maxVaryingComponents = 60, + .maxVertexOutputComponents = 64, + .maxGeometryInputComponents = 64, + .maxGeometryOutputComponents = 128, + .maxFragmentInputComponents = 128, + .maxImageUnits = 8, + .maxCombinedImageUnitsAndFragmentOutputs = 8, + .maxCombinedShaderOutputResources = 8, + .maxImageSamples = 0, + .maxVertexImageUniforms = 0, + .maxTessControlImageUniforms = 0, + .maxTessEvaluationImageUniforms = 0, + .maxGeometryImageUniforms = 0, + .maxFragmentImageUniforms = 8, + .maxCombinedImageUniforms = 8, + .maxGeometryTextureImageUnits = 16, + .maxGeometryOutputVertices = 256, + .maxGeometryTotalOutputComponents = 1024, + .maxGeometryUniformComponents = 1024, + .maxGeometryVaryingComponents = 64, + .maxTessControlInputComponents = 128, + .maxTessControlOutputComponents = 128, + .maxTessControlTextureImageUnits = 16, + .maxTessControlUniformComponents = 1024, + .maxTessControlTotalOutputComponents = 4096, + .maxTessEvaluationInputComponents = 128, + .maxTessEvaluationOutputComponents = 128, + .maxTessEvaluationTextureImageUnits = 16, + .maxTessEvaluationUniformComponents = 1024, + .maxTessPatchComponents = 120, + .maxPatchVertices = 32, + .maxTessGenLevel = 64, + .maxViewports = 16, + .maxVertexAtomicCounters = 0, + .maxTessControlAtomicCounters = 0, + .maxTessEvaluationAtomicCounters = 0, + .maxGeometryAtomicCounters = 0, + .maxFragmentAtomicCounters = 8, + .maxCombinedAtomicCounters = 8, + .maxAtomicCounterBindings = 1, + .maxVertexAtomicCounterBuffers = 0, + .maxTessControlAtomicCounterBuffers = 0, + .maxTessEvaluationAtomicCounterBuffers = 0, + .maxGeometryAtomicCounterBuffers = 0, + .maxFragmentAtomicCounterBuffers = 1, + .maxCombinedAtomicCounterBuffers = 1, + .maxAtomicCounterBufferSize = 16384, + .maxTransformFeedbackBuffers = 4, + .maxTransformFeedbackInterleavedComponents = 64, + .maxCullDistances = 8, + .maxCombinedClipAndCullDistances = 8, + .maxSamples = 4, + .maxMeshOutputVerticesNV = 256, + .maxMeshOutputPrimitivesNV = 512, + .maxMeshWorkGroupSizeX_NV = 32, + .maxMeshWorkGroupSizeY_NV = 1, + .maxMeshWorkGroupSizeZ_NV = 1, + .maxTaskWorkGroupSizeX_NV = 32, + .maxTaskWorkGroupSizeY_NV = 1, + .maxTaskWorkGroupSizeZ_NV = 1, + .maxMeshViewCountNV = 4, + .maxDualSourceDrawBuffersEXT = 1, + .limits = TLimits{ + .nonInductiveForLoops = 1, + .whileLoops = 1, + .doWhileLoops = 1, + .generalUniformIndexing = 1, + .generalAttributeMatrixVectorIndexing = 1, + .generalVaryingIndexing = 1, + .generalSamplerIndexing = 1, + .generalVariableIndexing = 1, + .generalConstantMatrixVectorIndexing = 1, + }}; + +vk::ShaderModule CompileShader(const std::string& source, vk::ShaderStageFlagBits vk_stage) { + if (!InitializeCompiler()) { + return VK_NULL_HANDLE; + } + + EShLanguage stage; + switch (vk_stage) { case vk::ShaderStageFlagBits::eVertex: - kind = shaderc_glsl_vertex_shader; - name = "vertex shader"; + stage = EShLangVertex; break; case vk::ShaderStageFlagBits::eFragment: - kind = shaderc_glsl_fragment_shader; - name = "fragment shader"; + stage = EShLangFragment; break; default: LOG_CRITICAL(Render_Vulkan, "Unknown shader stage"); UNREACHABLE(); } - auto shader_module = compiler.CompileGlslToSpv(source.data(), kind, name.c_str(), options); - if (shader_module.GetCompilationStatus() != shaderc_compilation_status_success) { - LOG_CRITICAL(Render_Vulkan, shader_module.GetErrorMessage().c_str()); - std::cout << shader_module.GetErrorMessage() << '\n'; + std::unique_ptr shader = std::make_unique(stage); + std::unique_ptr program; + glslang::TShader::ForbidIncluder includer; + EProfile profile = ECoreProfile; + EShMessages messages = static_cast(EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules); + + int default_version = 450; + const char* pass_source_code = source.data(); + int pass_source_code_length = static_cast(source.size()); + + shader->setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetLanguageVersion::EShTargetSpv_1_3); + shader->setStringsWithLengths(&pass_source_code, &pass_source_code_length, 1); + + if (!shader->parse(&DefaultTBuiltInResource, default_version, profile, false, true, messages, includer)) { + LOG_CRITICAL(Render_Vulkan, "Shader Info Log:\n{}\n{}", shader->getInfoLog(), shader->getInfoDebugLog()); + return VK_NULL_HANDLE; } - auto shader_code = std::vector{shader_module.cbegin(), shader_module.cend()}; - vk::ShaderModuleCreateInfo shader_info{{}, shader_code}; + // Even though there's only a single shader, we still need to link it to generate SPV + program = std::make_unique(); + program->addShader(shader.get()); + if (!program->link(messages)) { + LOG_CRITICAL(Render_Vulkan, "Program Info Log:\n{}\n{}", program->getInfoLog(), program->getInfoDebugLog()); + return VK_NULL_HANDLE; + } + + glslang::TIntermediate* intermediate = program->getIntermediate(stage); + std::vector out_code; + spv::SpvBuildLogger logger; + glslang::SpvOptions options; + + // Compile the SPIR-V module without optimizations for easier debugging in RenderDoc. + if (true) { + intermediate->addSourceText(pass_source_code, pass_source_code_length); + options.generateDebugInfo = true; + options.disableOptimizer = true; + options.optimizeSize = false; + options.disassemble = false; + options.validate = true; + } + else { + options.disableOptimizer = false; + options.stripDebugInfo = true; + } + + glslang::GlslangToSpv(*intermediate, out_code, &logger, &options); + + const std::string spv_messages = logger.getAllMessages(); + if (!spv_messages.empty()) { + LOG_INFO(Render_Vulkan, "SPIR-V conversion messages: {}", spv_messages); + } + + vk::ShaderModuleCreateInfo shader_info{{}, out_code.size() * sizeof(u32), out_code.data()}; + const vk::Device device = g_vk_instace->GetDevice(); + vk::ShaderModule shader_module = device.createShaderModule(shader_info); + return shader_module; - auto device = g_vk_instace->GetDevice(); - auto shader = device.createShaderModule(shader_info); - return shader; } } // namespace Vulkan diff --git a/vcpkg.json b/vcpkg.json index 2d4491fd0..a8b4431c9 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -36,7 +36,7 @@ "libusb", "libyuv", "lodepng", - "shaderc", + "glslang", "soundtouch", "xbyak", "zstd",