Procházet zdrojové kódy

vk_shader_decompiler: Implement Layer output attribute

SPIR-V's Layer is GLSL's gl_Layer. It lets the application choose from a
shader stage (vertex, tessellation or geometry) which framebuffer layer
write the output fragments to.
ReinUsesLisp před 6 roky
rodič
revize
1caf3f11c8

+ 30 - 6
src/video_core/renderer_vulkan/vk_shader_decompiler.cpp

@@ -86,6 +86,7 @@ struct AttributeType {
 
 
 struct VertexIndices {
 struct VertexIndices {
     std::optional<u32> position;
     std::optional<u32> position;
+    std::optional<u32> layer;
     std::optional<u32> viewport;
     std::optional<u32> viewport;
     std::optional<u32> point_size;
     std::optional<u32> point_size;
     std::optional<u32> clip_distances;
     std::optional<u32> clip_distances;
@@ -282,9 +283,11 @@ public:
         AddExtension("SPV_KHR_storage_buffer_storage_class");
         AddExtension("SPV_KHR_storage_buffer_storage_class");
         AddExtension("SPV_KHR_variable_pointers");
         AddExtension("SPV_KHR_variable_pointers");
 
 
-        if (ir.UsesViewportIndex()) {
-            AddCapability(spv::Capability::MultiViewport);
-            if (device.IsExtShaderViewportIndexLayerSupported()) {
+        if (ir.UsesLayer() || ir.UsesViewportIndex()) {
+            if (ir.UsesViewportIndex()) {
+                AddCapability(spv::Capability::MultiViewport);
+            }
+            if (stage != ShaderType::Geometry && device.IsExtShaderViewportIndexLayerSupported()) {
                 AddExtension("SPV_EXT_shader_viewport_index_layer");
                 AddExtension("SPV_EXT_shader_viewport_index_layer");
                 AddCapability(spv::Capability::ShaderViewportIndexLayerEXT);
                 AddCapability(spv::Capability::ShaderViewportIndexLayerEXT);
             }
             }
@@ -920,13 +923,22 @@ private:
         VertexIndices indices;
         VertexIndices indices;
         indices.position = AddBuiltIn(t_float4, spv::BuiltIn::Position, "position");
         indices.position = AddBuiltIn(t_float4, spv::BuiltIn::Position, "position");
 
 
+        if (ir.UsesLayer()) {
+            if (stage != ShaderType::Vertex || device.IsExtShaderViewportIndexLayerSupported()) {
+                indices.layer = AddBuiltIn(t_int, spv::BuiltIn::Layer, "layer");
+            } else {
+                LOG_ERROR(
+                    Render_Vulkan,
+                    "Shader requires Layer but it's not supported on this stage with this device.");
+            }
+        }
+
         if (ir.UsesViewportIndex()) {
         if (ir.UsesViewportIndex()) {
             if (stage != ShaderType::Vertex || device.IsExtShaderViewportIndexLayerSupported()) {
             if (stage != ShaderType::Vertex || device.IsExtShaderViewportIndexLayerSupported()) {
                 indices.viewport = AddBuiltIn(t_int, spv::BuiltIn::ViewportIndex, "viewport_index");
                 indices.viewport = AddBuiltIn(t_int, spv::BuiltIn::ViewportIndex, "viewport_index");
             } else {
             } else {
-                LOG_ERROR(Render_Vulkan,
-                          "Shader requires ViewportIndex but it's not supported on this "
-                          "stage with this device.");
+                LOG_ERROR(Render_Vulkan, "Shader requires ViewportIndex but it's not supported on "
+                                         "this stage with this device.");
             }
             }
         }
         }
 
 
@@ -1285,6 +1297,13 @@ private:
                 }
                 }
                 case Attribute::Index::LayerViewportPointSize:
                 case Attribute::Index::LayerViewportPointSize:
                     switch (element) {
                     switch (element) {
+                    case 1: {
+                        if (!out_indices.layer) {
+                            return {};
+                        }
+                        const u32 index = out_indices.layer.value();
+                        return {AccessElement(t_out_int, out_vertex, index), Type::Int};
+                    }
                     case 2: {
                     case 2: {
                         if (!out_indices.viewport) {
                         if (!out_indices.viewport) {
                             return {};
                             return {};
@@ -1355,6 +1374,11 @@ private:
             UNIMPLEMENTED();
             UNIMPLEMENTED();
         }
         }
 
 
+        if (!target.id) {
+            // On failure we return a nullptr target.id, skip these stores.
+            return {};
+        }
+
         OpStore(target.id, As(Visit(src), target.type));
         OpStore(target.id, As(Visit(src), target.type));
         return {};
         return {};
     }
     }