Sfoglia il codice sorgente

shader: Implement ViewportIndex

FernandoS27 5 anni fa
parent
commit
d819ba4489

+ 6 - 0
src/shader_recompiler/backend/spirv/emit_context.cpp

@@ -509,6 +509,12 @@ void EmitContext::DefineOutputs(const Info& info) {
         const Id type{TypeArray(F32[1], Constant(U32[1], 8U))};
         clip_distances = DefineOutput(*this, type, spv::BuiltIn::ClipDistance);
     }
+    if (info.stores_viewport_index && !ignore_viewport_layer) {
+        if (stage == Stage::Fragment) {
+            throw NotImplementedException("Storing ViewportIndex in Fragment stage");
+        }
+        viewport_index = DefineOutput(*this, U32[1], spv::BuiltIn::ViewportIndex);
+    }
     for (size_t i = 0; i < info.stores_generics.size(); ++i) {
         if (info.stores_generics[i]) {
             output_generics[i] = DefineOutput(*this, F32[4]);

+ 3 - 0
src/shader_recompiler/backend/spirv/emit_context.h

@@ -106,6 +106,7 @@ public:
     Id front_face{};
     Id point_coord{};
     Id clip_distances{};
+    Id viewport_index{};
 
     Id fswzadd_lut_a{};
     Id fswzadd_lut_b{};
@@ -133,6 +134,8 @@ public:
 
     std::vector<Id> interfaces;
 
+    bool ignore_viewport_layer{};
+
 private:
     void DefineCommonTypes(const Info& info);
     void DefineCommonConstants();

+ 10 - 0
src/shader_recompiler/backend/spirv/emit_spirv.cpp

@@ -225,6 +225,16 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
         ctx.AddExtension("SPV_EXT_demote_to_helper_invocation");
         ctx.AddCapability(spv::Capability::DemoteToHelperInvocationEXT);
     }
+    if (info.stores_viewport_index) {
+        ctx.AddCapability(spv::Capability::MultiViewport);
+        if (profile.support_viewport_index_layer_non_geometry &&
+            ctx.stage == Shader::Stage::VertexB) {
+            ctx.AddExtension("SPV_EXT_shader_viewport_index_layer");
+            ctx.AddCapability(spv::Capability::ShaderViewportIndexLayerEXT);
+        } else {
+            ctx.ignore_viewport_layer = true;
+        }
+    }
     if (!profile.support_vertex_instance_id && (info.loads_instance_id || info.loads_vertex_id)) {
         ctx.AddExtension("SPV_KHR_shader_draw_parameters");
         ctx.AddCapability(spv::Capability::DrawParameters);

+ 8 - 2
src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp

@@ -29,7 +29,7 @@ std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) {
     throw InvalidArgument("Invalid attribute type {}", type);
 }
 
-Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
+std::optional<Id> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
     const u32 element{static_cast<u32>(attr) % 4};
     const auto element_id{[&] { return ctx.Constant(ctx.U32[1], element); }};
     if (IR::IsGeneric(attr)) {
@@ -57,6 +57,8 @@ Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
         const Id clip_num{ctx.Constant(ctx.U32[1], index)};
         return ctx.OpAccessChain(ctx.output_f32, ctx.clip_distances, clip_num);
     }
+    case IR::Attribute::ViewportIndex:
+        return ctx.ignore_viewport_layer ? std::nullopt : std::optional<Id>{ctx.viewport_index};
     default:
         throw NotImplementedException("Read attribute {}", attr);
     }
@@ -204,7 +206,11 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr) {
 }
 
 void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value) {
-    ctx.OpStore(OutputAttrPointer(ctx, attr), value);
+    auto output = OutputAttrPointer(ctx, attr);
+    if (!output) {
+        return;
+    }
+    ctx.OpStore(*output, value);
 }
 
 void EmitGetAttributeIndexed(EmitContext&) {

+ 3 - 0
src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp

@@ -81,6 +81,9 @@ void SetAttribute(Info& info, IR::Attribute attribute) {
     case IR::Attribute::ClipDistance7:
         info.stores_clip_distance = true;
         break;
+    case IR::Attribute::ViewportIndex:
+        info.stores_viewport_index = true;
+        break;
     default:
         throw NotImplementedException("Set attribute {}", attribute);
     }

+ 1 - 0
src/shader_recompiler/profile.h

@@ -35,6 +35,7 @@ struct Profile {
     bool support_fp64_signed_zero_nan_preserve{};
     bool support_explicit_workgroup_layout{};
     bool support_vote{};
+    bool support_viewport_index_layer_non_geometry{};
     bool warp_size_potentially_larger_than_guest{};
 
     // FClamp is broken and OpFMax + OpFMin should be used instead

+ 1 - 0
src/shader_recompiler/shader_info.h

@@ -82,6 +82,7 @@ struct Info {
     bool stores_position{};
     bool stores_point_size{};
     bool stores_clip_distance{};
+    bool stores_viewport_index{};
 
     bool uses_fp16{};
     bool uses_fp64{};

+ 1 - 0
src/video_core/renderer_vulkan/vk_pipeline_cache.cpp

@@ -631,6 +631,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_,
             float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE,
         .support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(),
         .support_vote = true,
+        .support_viewport_index_layer_non_geometry = device.IsExtShaderViewportIndexLayerSupported(),
         .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
         .has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR,
         .generic_input_types{},