From 3faddd5e0321b23e29a68c7767c1f24128222c5e Mon Sep 17 00:00:00 2001 From: GPUCode <47210458+GPUCode@users.noreply.github.com> Date: Mon, 19 Jun 2023 17:02:18 +0300 Subject: [PATCH] video_core: Add vulkan shaders (#6619) --- src/video_core/host_shaders/CMakeLists.txt | 49 ++++++++++++++++++- .../vulkan_d24s8_to_rgba8.comp | 26 ++++++++++ .../host_shaders/full_screen_triangle.vert | 16 +++++- .../texture_filtering/xbrz_freescale.frag | 9 +++- .../vulkan_blit_depth_stencil.frag | 16 ++++++ .../host_shaders/vulkan_depth_to_buffer.comp | 29 +++++++++++ .../host_shaders/vulkan_present.frag | 25 ++++++++++ .../host_shaders/vulkan_present.vert | 25 ++++++++++ .../host_shaders/vulkan_present_anaglyph.frag | 39 +++++++++++++++ .../vulkan_present_interlaced.frag | 29 +++++++++++ .../rasterizer_cache/rasterizer_cache.h | 6 +-- src/video_core/rasterizer_cache/utils.h | 2 +- .../renderer_opengl/gl_texture_runtime.cpp | 2 +- 13 files changed, 263 insertions(+), 10 deletions(-) create mode 100644 src/video_core/host_shaders/format_reinterpreter/vulkan_d24s8_to_rgba8.comp create mode 100644 src/video_core/host_shaders/vulkan_blit_depth_stencil.frag create mode 100644 src/video_core/host_shaders/vulkan_depth_to_buffer.comp create mode 100644 src/video_core/host_shaders/vulkan_present.frag create mode 100644 src/video_core/host_shaders/vulkan_present.vert create mode 100644 src/video_core/host_shaders/vulkan_present_anaglyph.frag create mode 100644 src/video_core/host_shaders/vulkan_present_interlaced.frag diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt index 1f4943518..1c054978f 100644 --- a/src/video_core/host_shaders/CMakeLists.txt +++ b/src/video_core/host_shaders/CMakeLists.txt @@ -4,13 +4,12 @@ set(SHADER_FILES format_reinterpreter/d24s8_to_rgba8.frag - format_reinterpreter/fullscreen_quad.vert format_reinterpreter/rgba4_to_rgb5a1.frag + format_reinterpreter/vulkan_d24s8_to_rgba8.comp texture_filtering/bicubic.frag texture_filtering/nearest_neighbor.frag texture_filtering/refine.frag texture_filtering/scale_force.frag - texture_filtering/tex_coord.vert texture_filtering/xbrz_freescale.frag texture_filtering/mmpx.frag texture_filtering/x_gradient.frag @@ -20,8 +19,22 @@ set(SHADER_FILES opengl_present.vert opengl_present_anaglyph.frag opengl_present_interlaced.frag + vulkan_depth_to_buffer.comp + vulkan_present.frag + vulkan_present.vert + vulkan_present_anaglyph.frag + vulkan_present_interlaced.frag + vulkan_blit_depth_stencil.frag ) +find_program(GLSLANGVALIDATOR "glslangValidator") +if ("${GLSLANGVALIDATOR}" STREQUAL "GLSLANGVALIDATOR-NOTFOUND") + message(FATAL_ERROR "Required program `glslangValidator` not found.") +endif() + +set(MACROS "-Dgl_VertexID=gl_VertexIndex") +set(QUIET_FLAG "--quiet") + set(SHADER_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/include) set(SHADER_DIR ${SHADER_INCLUDE}/video_core/host_shaders) set(HOST_SHADERS_INCLUDE ${SHADER_INCLUDE} PARENT_SCOPE) @@ -29,6 +42,23 @@ set(HOST_SHADERS_INCLUDE ${SHADER_INCLUDE} PARENT_SCOPE) set(INPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/source_shader.h.in) set(HEADER_GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/StringShaderHeader.cmake) +# Check if `--quiet` is available on host's glslangValidator version +# glslangValidator prints to STDERR iff an unrecognized flag is passed to it +execute_process( + COMMAND + ${GLSLANGVALIDATOR} ${QUIET_FLAG} + ERROR_VARIABLE + GLSLANG_ERROR + # STDOUT variable defined to silence unnecessary output during CMake configuration + OUTPUT_VARIABLE + GLSLANG_OUTPUT +) + +if (NOT GLSLANG_ERROR STREQUAL "") + message(WARNING "Refusing to use unavailable flag `${QUIET_FLAG}` on `${GLSLANGVALIDATOR}`") + set(QUIET_FLAG "") +endif() + foreach(FILENAME IN ITEMS ${SHADER_FILES}) string(REPLACE "." "_" SHADER_NAME ${FILENAME}) set(SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}) @@ -48,6 +78,21 @@ foreach(FILENAME IN ITEMS ${SHADER_FILES}) ) set(SHADER_HEADERS ${SHADER_HEADERS} ${SOURCE_HEADER_FILE}) endif() + # Skip compiling to SPIR-V OpenGL exclusive files + if (NOT ${FILENAME} MATCHES "opengl.*") + get_filename_component(FILE_NAME ${SHADER_NAME} NAME) + string(TOUPPER ${FILE_NAME}_SPV SPIRV_VARIABLE_NAME) + set(SPIRV_HEADER_FILE ${SHADER_DIR}/${SHADER_NAME}_spv.h) + add_custom_command( + OUTPUT + ${SPIRV_HEADER_FILE} + COMMAND + ${GLSLANGVALIDATOR} --target-env vulkan1.1 --glsl-version 450 ${QUIET_FLAG} ${MACROS} --variable-name ${SPIRV_VARIABLE_NAME} -o ${SPIRV_HEADER_FILE} ${SOURCE_FILE} + MAIN_DEPENDENCY + ${SOURCE_FILE} + ) + set(SHADER_HEADERS ${SHADER_HEADERS} ${SPIRV_HEADER_FILE}) + endif() endforeach() set(SHADER_SOURCES ${SHADER_FILES}) diff --git a/src/video_core/host_shaders/format_reinterpreter/vulkan_d24s8_to_rgba8.comp b/src/video_core/host_shaders/format_reinterpreter/vulkan_d24s8_to_rgba8.comp new file mode 100644 index 000000000..a3e4c4037 --- /dev/null +++ b/src/video_core/host_shaders/format_reinterpreter/vulkan_d24s8_to_rgba8.comp @@ -0,0 +1,26 @@ +// Copyright 2023 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#version 450 core +#extension GL_EXT_samplerless_texture_functions : require + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; +layout(set = 0, binding = 0) uniform highp texture2D depth; +layout(set = 0, binding = 1) uniform lowp utexture2D stencil; +layout(set = 0, binding = 2, rgba8) uniform highp writeonly image2D color; + +layout(push_constant, std140) uniform ComputeInfo { + mediump ivec2 src_offset; + mediump ivec2 extent; +}; + +void main() { + ivec2 tex_coord = src_offset + ivec2(gl_GlobalInvocationID.xy); + highp uint depth_val = + uint(texelFetch(depth, tex_coord, 0).x * (exp2(32.0) - 1.0)); + lowp uint stencil_val = texelFetch(stencil, tex_coord, 0).x; + highp uvec4 components = + uvec4(stencil_val, (uvec3(depth_val) >> uvec3(24u, 16u, 8u)) & 0x000000FFu); + imageStore(color, tex_coord, vec4(components) / (exp2(8.0) - 1.0)); +} diff --git a/src/video_core/host_shaders/full_screen_triangle.vert b/src/video_core/host_shaders/full_screen_triangle.vert index 7b85e4477..7f3459f46 100644 --- a/src/video_core/host_shaders/full_screen_triangle.vert +++ b/src/video_core/host_shaders/full_screen_triangle.vert @@ -9,8 +9,20 @@ out gl_PerVertex { layout(location = 0) out vec2 texcoord; -layout (location = 0) uniform vec2 tex_scale; -layout (location = 1) uniform vec2 tex_offset; +#ifdef VULKAN +#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants { +#define END_PUSH_CONSTANTS }; +#define UNIFORM(n) +#else // if OpenGL +#define BEGIN_PUSH_CONSTANTS +#define END_PUSH_CONSTANTS +#define UNIFORM(n) layout (location = n) uniform +#endif + +BEGIN_PUSH_CONSTANTS +UNIFORM(0) vec2 tex_scale; +UNIFORM(1) vec2 tex_offset; +END_PUSH_CONSTANTS void main() { float x = float((gl_VertexID & 1) << 2); diff --git a/src/video_core/host_shaders/texture_filtering/xbrz_freescale.frag b/src/video_core/host_shaders/texture_filtering/xbrz_freescale.frag index 48032ddbd..0b4ac65d0 100644 --- a/src/video_core/host_shaders/texture_filtering/xbrz_freescale.frag +++ b/src/video_core/host_shaders/texture_filtering/xbrz_freescale.frag @@ -9,7 +9,14 @@ layout(location = 0) in vec2 tex_coord; layout(location = 0) out vec4 frag_color; layout(binding = 0) uniform sampler2D tex; -layout(location = 2) uniform lowp float scale; + +#ifdef VULKAN +layout(push_constant, std140) uniform XbrzInfo { + float scale; +}; +#else +layout(location = 2) uniform float scale; +#endif const int BLEND_NONE = 0; const int BLEND_NORMAL = 1; diff --git a/src/video_core/host_shaders/vulkan_blit_depth_stencil.frag b/src/video_core/host_shaders/vulkan_blit_depth_stencil.frag new file mode 100644 index 000000000..eb327361c --- /dev/null +++ b/src/video_core/host_shaders/vulkan_blit_depth_stencil.frag @@ -0,0 +1,16 @@ +// Copyright 2022 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#version 450 core +#extension GL_ARB_shader_stencil_export : require + +layout(binding = 0) uniform sampler2D depth_tex; +layout(binding = 1) uniform usampler2D stencil_tex; + +layout(location = 0) in vec2 texcoord; + +void main() { + gl_FragDepth = textureLod(depth_tex, texcoord, 0).r; + gl_FragStencilRefARB = int(textureLod(stencil_tex, texcoord, 0).r); +} diff --git a/src/video_core/host_shaders/vulkan_depth_to_buffer.comp b/src/video_core/host_shaders/vulkan_depth_to_buffer.comp new file mode 100644 index 000000000..f88209c66 --- /dev/null +++ b/src/video_core/host_shaders/vulkan_depth_to_buffer.comp @@ -0,0 +1,29 @@ +// Copyright 2023 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#version 450 core + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; +layout(binding = 0) uniform highp sampler2D depth; +layout(binding = 1) uniform lowp usampler2D stencil; + +layout(binding = 2) writeonly buffer OutputBuffer{ + uint pixels[]; +} staging; + +layout(push_constant, std140) uniform ComputeInfo { + mediump ivec2 src_offset; + mediump ivec2 extent; +}; + +void main() { + ivec2 rect = ivec2(gl_NumWorkGroups.xy) * ivec2(8); + ivec2 dst_coord = ivec2(gl_GlobalInvocationID.xy); + ivec2 tex_icoord = src_offset + dst_coord; + highp vec2 tex_coord = vec2(tex_icoord) / vec2(extent); + highp uint depth_val = uint(texture(depth, tex_coord).x * (exp2(24.0) - 1.0)); + lowp uint stencil_val = texture(stencil, tex_coord).x; + highp uint value = stencil_val | (depth_val << 8); + staging.pixels[dst_coord.y * rect.x + dst_coord.x] = value; +} diff --git a/src/video_core/host_shaders/vulkan_present.frag b/src/video_core/host_shaders/vulkan_present.frag new file mode 100644 index 000000000..8fb0643a0 --- /dev/null +++ b/src/video_core/host_shaders/vulkan_present.frag @@ -0,0 +1,25 @@ +// Copyright 2022 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#version 450 core +#extension GL_ARB_separate_shader_objects : enable + +layout (location = 0) in vec2 frag_tex_coord; +layout (location = 0) out vec4 color; + +layout (push_constant, std140) uniform DrawInfo { + mat4 modelview_matrix; + vec4 i_resolution; + vec4 o_resolution; + int screen_id_l; + int screen_id_r; + int layer; + int reverse_interlaced; +}; + +layout (set = 0, binding = 0) uniform sampler2D screen_textures[3]; + +void main() { + color = texture(screen_textures[screen_id_l], frag_tex_coord); +} diff --git a/src/video_core/host_shaders/vulkan_present.vert b/src/video_core/host_shaders/vulkan_present.vert new file mode 100644 index 000000000..08b4d252c --- /dev/null +++ b/src/video_core/host_shaders/vulkan_present.vert @@ -0,0 +1,25 @@ +// Copyright 2022 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#version 450 core +#extension GL_ARB_separate_shader_objects : enable + +layout (location = 0) in vec2 vert_position; +layout (location = 1) in vec2 vert_tex_coord; +layout (location = 0) out vec2 frag_tex_coord; + +layout (push_constant, std140) uniform DrawInfo { + mat4 modelview_matrix; + vec4 i_resolution; + vec4 o_resolution; + int screen_id_l; + int screen_id_r; + int layer; +}; + +void main() { + vec4 position = vec4(vert_position, 0.0, 1.0) * modelview_matrix; + gl_Position = vec4(position.x, position.y, 0.0, 1.0); + frag_tex_coord = vert_tex_coord; +} diff --git a/src/video_core/host_shaders/vulkan_present_anaglyph.frag b/src/video_core/host_shaders/vulkan_present_anaglyph.frag new file mode 100644 index 000000000..4d39678e4 --- /dev/null +++ b/src/video_core/host_shaders/vulkan_present_anaglyph.frag @@ -0,0 +1,39 @@ +// Copyright 2022 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#version 450 core +#extension GL_ARB_separate_shader_objects : enable + +layout (location = 0) in vec2 frag_tex_coord; +layout (location = 0) out vec4 color; + +// Anaglyph Red-Cyan shader based on Dubois algorithm +// Constants taken from the paper: +// "Conversion of a Stereo Pair to Anaglyph with +// the Least-Squares Projection Method" +// Eric Dubois, March 2009 +const mat3 l = mat3( 0.437, 0.449, 0.164, + -0.062,-0.062,-0.024, + -0.048,-0.050,-0.017); +const mat3 r = mat3(-0.011,-0.032,-0.007, + 0.377, 0.761, 0.009, + -0.026,-0.093, 1.234); + +layout (push_constant, std140) uniform DrawInfo { + mat4 modelview_matrix; + vec4 i_resolution; + vec4 o_resolution; + int screen_id_l; + int screen_id_r; + int layer; + int reverse_interlaced; +}; + +layout (set = 0, binding = 0) uniform sampler2D screen_textures[3]; + +void main() { + vec4 color_tex_l = texture(screen_textures[screen_id_l], frag_tex_coord); + vec4 color_tex_r = texture(screen_textures[screen_id_r], frag_tex_coord); + color = vec4(color_tex_l.rgb*l+color_tex_r.rgb*r, color_tex_l.a); +} diff --git a/src/video_core/host_shaders/vulkan_present_interlaced.frag b/src/video_core/host_shaders/vulkan_present_interlaced.frag new file mode 100644 index 000000000..2f5a18b90 --- /dev/null +++ b/src/video_core/host_shaders/vulkan_present_interlaced.frag @@ -0,0 +1,29 @@ +// Copyright 2022 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#version 450 core +#extension GL_ARB_separate_shader_objects : enable + +layout (location = 0) in vec2 frag_tex_coord; +layout (location = 0) out vec4 color; + +layout (push_constant, std140) uniform DrawInfo { + mat4 modelview_matrix; + vec4 i_resolution; + vec4 o_resolution; + int screen_id_l; + int screen_id_r; + int layer; + int reverse_interlaced; +}; + +layout (set = 0, binding = 0) uniform sampler2D screen_textures[3]; + +void main() { + float screen_row = o_resolution.x * frag_tex_coord.x; + if (int(screen_row) % 2 == reverse_interlaced) + color = texture(screen_textures[screen_id_l], frag_tex_coord); + else + color = texture(screen_textures[screen_id_r], frag_tex_coord); +} diff --git a/src/video_core/rasterizer_cache/rasterizer_cache.h b/src/video_core/rasterizer_cache/rasterizer_cache.h index 685c5d381..357cf8d5a 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache/rasterizer_cache.h @@ -1000,7 +1000,7 @@ void RasterizerCache::UploadSurface(Surface& surface, SurfaceInterval interva } const BufferTextureCopy upload = { - .buffer_offset = 0, + .buffer_offset = staging.offset, .buffer_size = staging.size, .texture_rect = surface.GetSubRect(load_info), .texture_level = surface.LevelOf(load_info.addr), @@ -1080,7 +1080,7 @@ void RasterizerCache::DownloadSurface(Surface& surface, SurfaceInterval inter flush_info.width * flush_info.height * surface.GetInternalBytesPerPixel(), false); const BufferTextureCopy download = { - .buffer_offset = 0, + .buffer_offset = staging.offset, .buffer_size = staging.size, .texture_rect = surface.GetSubRect(flush_info), .texture_level = surface.LevelOf(flush_start), @@ -1137,7 +1137,7 @@ bool RasterizerCache::ValidateByReinterpretation(Surface& surface, SurfacePar if (reinterpret_id) { Surface& src_surface = slot_surfaces[reinterpret_id]; const SurfaceInterval copy_interval = src_surface.GetCopyableInterval(params); - if (boost::icl::is_empty(copy_interval)) { + if (boost::icl::is_empty(copy_interval & interval)) { return false; } const PAddr addr = boost::icl::lower(interval); diff --git a/src/video_core/rasterizer_cache/utils.h b/src/video_core/rasterizer_cache/utils.h index 678e27aba..3f6ee1f97 100644 --- a/src/video_core/rasterizer_cache/utils.h +++ b/src/video_core/rasterizer_cache/utils.h @@ -75,8 +75,8 @@ struct BufferTextureCopy { struct StagingData { u32 size; + u32 offset; std::span mapped; - u64 buffer_offset; }; struct TextureCubeConfig { diff --git a/src/video_core/renderer_opengl/gl_texture_runtime.cpp b/src/video_core/renderer_opengl/gl_texture_runtime.cpp index fe2c19070..c6920f812 100644 --- a/src/video_core/renderer_opengl/gl_texture_runtime.cpp +++ b/src/video_core/renderer_opengl/gl_texture_runtime.cpp @@ -144,8 +144,8 @@ VideoCore::StagingData TextureRuntime::FindStaging(u32 size, bool upload) { } return VideoCore::StagingData{ .size = size, + .offset = 0, .mapped = std::span{staging_buffer.data(), size}, - .buffer_offset = 0, }; }