forked from eden-emu/eden
		
	gl_shader_decompiler: Implement gl_ViewportIndex and gl_Layer in vertex shaders
This commit implements gl_ViewportIndex and gl_Layer in vertex and geometry shaders. In the case it's used in a vertex shader, it requires ARB_shader_viewport_layer_array. This extension is available on AMD and Nvidia devices (mesa and proprietary drivers), but not available on Intel on any platform. At the moment of writing this description I don't know if this is a hardware limitation or a driver limitation. In the case that ARB_shader_viewport_layer_array is not available, writes to these registers on a vertex shader are ignored, with the appropriate logging.
This commit is contained in:
		
							parent
							
								
									8afed6aae6
								
							
						
					
					
						commit
						a650406899
					
				
					 10 changed files with 136 additions and 40 deletions
				
			
		|  | @ -78,7 +78,7 @@ union Attribute { | ||||||
|     constexpr explicit Attribute(u64 value) : value(value) {} |     constexpr explicit Attribute(u64 value) : value(value) {} | ||||||
| 
 | 
 | ||||||
|     enum class Index : u64 { |     enum class Index : u64 { | ||||||
|         PointSize = 6, |         LayerViewportPointSize = 6, | ||||||
|         Position = 7, |         Position = 7, | ||||||
|         Attribute_0 = 8, |         Attribute_0 = 8, | ||||||
|         Attribute_31 = 39, |         Attribute_31 = 39, | ||||||
|  |  | ||||||
|  | @ -26,6 +26,7 @@ Device::Device() { | ||||||
|     uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); |     uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); | ||||||
|     max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS); |     max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS); | ||||||
|     max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS); |     max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS); | ||||||
|  |     has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array; | ||||||
|     has_variable_aoffi = TestVariableAoffi(); |     has_variable_aoffi = TestVariableAoffi(); | ||||||
|     has_component_indexing_bug = TestComponentIndexingBug(); |     has_component_indexing_bug = TestComponentIndexingBug(); | ||||||
| } | } | ||||||
|  | @ -34,6 +35,7 @@ Device::Device(std::nullptr_t) { | ||||||
|     uniform_buffer_alignment = 0; |     uniform_buffer_alignment = 0; | ||||||
|     max_vertex_attributes = 16; |     max_vertex_attributes = 16; | ||||||
|     max_varyings = 15; |     max_varyings = 15; | ||||||
|  |     has_vertex_viewport_layer = true; | ||||||
|     has_variable_aoffi = true; |     has_variable_aoffi = true; | ||||||
|     has_component_indexing_bug = false; |     has_component_indexing_bug = false; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -26,6 +26,10 @@ public: | ||||||
|         return max_varyings; |         return max_varyings; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     bool HasVertexViewportLayer() const { | ||||||
|  |         return has_vertex_viewport_layer; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     bool HasVariableAoffi() const { |     bool HasVariableAoffi() const { | ||||||
|         return has_variable_aoffi; |         return has_variable_aoffi; | ||||||
|     } |     } | ||||||
|  | @ -41,6 +45,7 @@ private: | ||||||
|     std::size_t uniform_buffer_alignment{}; |     std::size_t uniform_buffer_alignment{}; | ||||||
|     u32 max_vertex_attributes{}; |     u32 max_vertex_attributes{}; | ||||||
|     u32 max_varyings{}; |     u32 max_varyings{}; | ||||||
|  |     bool has_vertex_viewport_layer{}; | ||||||
|     bool has_variable_aoffi{}; |     bool has_variable_aoffi{}; | ||||||
|     bool has_component_indexing_bug{}; |     bool has_component_indexing_bug{}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -182,8 +182,11 @@ CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEn | ||||||
|     const auto texture_buffer_usage{variant.texture_buffer_usage}; |     const auto texture_buffer_usage{variant.texture_buffer_usage}; | ||||||
| 
 | 
 | ||||||
|     std::string source = "#version 430 core\n" |     std::string source = "#version 430 core\n" | ||||||
|                          "#extension GL_ARB_separate_shader_objects : enable\n\n"; |                          "#extension GL_ARB_separate_shader_objects : enable\n"; | ||||||
|     source += fmt::format("#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++); |     if (entries.shader_viewport_layer_array) { | ||||||
|  |         source += "#extension GL_ARB_shader_viewport_layer_array : enable\n"; | ||||||
|  |     } | ||||||
|  |     source += fmt::format("\n#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++); | ||||||
| 
 | 
 | ||||||
|     for (const auto& cbuf : entries.const_buffers) { |     for (const auto& cbuf : entries.const_buffers) { | ||||||
|         source += |         source += | ||||||
|  |  | ||||||
|  | @ -14,6 +14,7 @@ | ||||||
| #include "common/alignment.h" | #include "common/alignment.h" | ||||||
| #include "common/assert.h" | #include "common/assert.h" | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  | #include "common/logging/log.h" | ||||||
| #include "video_core/engines/maxwell_3d.h" | #include "video_core/engines/maxwell_3d.h" | ||||||
| #include "video_core/renderer_opengl/gl_device.h" | #include "video_core/renderer_opengl/gl_device.h" | ||||||
| #include "video_core/renderer_opengl/gl_rasterizer.h" | #include "video_core/renderer_opengl/gl_rasterizer.h" | ||||||
|  | @ -244,6 +245,8 @@ public: | ||||||
|                                                        usage.is_read, usage.is_written); |                                                        usage.is_read, usage.is_written); | ||||||
|         } |         } | ||||||
|         entries.clip_distances = ir.GetClipDistances(); |         entries.clip_distances = ir.GetClipDistances(); | ||||||
|  |         entries.shader_viewport_layer_array = | ||||||
|  |             stage == ShaderStage::Vertex && (ir.UsesLayer() || ir.UsesPointSize()); | ||||||
|         entries.shader_length = ir.GetLength(); |         entries.shader_length = ir.GetLength(); | ||||||
|         return entries; |         return entries; | ||||||
|     } |     } | ||||||
|  | @ -280,22 +283,34 @@ private: | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void DeclareVertexRedeclarations() { |     void DeclareVertexRedeclarations() { | ||||||
|         bool clip_distances_declared = false; |  | ||||||
| 
 |  | ||||||
|         code.AddLine("out gl_PerVertex {{"); |         code.AddLine("out gl_PerVertex {{"); | ||||||
|         ++code.scope; |         ++code.scope; | ||||||
| 
 | 
 | ||||||
|         code.AddLine("vec4 gl_Position;"); |         code.AddLine("vec4 gl_Position;"); | ||||||
| 
 | 
 | ||||||
|         for (const auto o : ir.GetOutputAttributes()) { |         for (const auto attribute : ir.GetOutputAttributes()) { | ||||||
|             if (o == Attribute::Index::PointSize) |             if (attribute == Attribute::Index::ClipDistances0123 || | ||||||
|                 code.AddLine("float gl_PointSize;"); |                 attribute == Attribute::Index::ClipDistances4567) { | ||||||
|             if (!clip_distances_declared && (o == Attribute::Index::ClipDistances0123 || |  | ||||||
|                                              o == Attribute::Index::ClipDistances4567)) { |  | ||||||
|                 code.AddLine("float gl_ClipDistance[];"); |                 code.AddLine("float gl_ClipDistance[];"); | ||||||
|                 clip_distances_declared = true; |                 break; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         if (stage != ShaderStage::Vertex || device.HasVertexViewportLayer()) { | ||||||
|  |             if (ir.UsesLayer()) { | ||||||
|  |                 code.AddLine("int gl_Layer;"); | ||||||
|  |             } | ||||||
|  |             if (ir.UsesViewportIndex()) { | ||||||
|  |                 code.AddLine("int gl_ViewportIndex;"); | ||||||
|  |             } | ||||||
|  |         } else if (stage == ShaderStage::Vertex && !device.HasVertexViewportLayer()) { | ||||||
|  |             LOG_ERROR( | ||||||
|  |                 Render_OpenGL, | ||||||
|  |                 "GL_ARB_shader_viewport_layer_array is not available and its required by a shader"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (ir.UsesPointSize()) { | ||||||
|  |             code.AddLine("int gl_PointSize;"); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         --code.scope; |         --code.scope; | ||||||
|         code.AddLine("}};"); |         code.AddLine("}};"); | ||||||
|  | @ -803,6 +818,45 @@ private: | ||||||
|         return CastOperand(VisitOperand(operation, operand_index), type); |         return CastOperand(VisitOperand(operation, operand_index), type); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     std::optional<std::pair<std::string, bool>> GetOutputAttribute(const AbufNode* abuf) { | ||||||
|  |         switch (const auto attribute = abuf->GetIndex()) { | ||||||
|  |         case Attribute::Index::Position: | ||||||
|  |             return std::make_pair("gl_Position"s + GetSwizzle(abuf->GetElement()), false); | ||||||
|  |         case Attribute::Index::LayerViewportPointSize: | ||||||
|  |             switch (abuf->GetElement()) { | ||||||
|  |             case 0: | ||||||
|  |                 UNIMPLEMENTED(); | ||||||
|  |                 return {}; | ||||||
|  |             case 1: | ||||||
|  |                 if (stage == ShaderStage::Vertex && !device.HasVertexViewportLayer()) { | ||||||
|  |                     return {}; | ||||||
|  |                 } | ||||||
|  |                 return std::make_pair("gl_Layer", true); | ||||||
|  |             case 2: | ||||||
|  |                 if (stage == ShaderStage::Vertex && !device.HasVertexViewportLayer()) { | ||||||
|  |                     return {}; | ||||||
|  |                 } | ||||||
|  |                 return std::make_pair("gl_ViewportIndex", true); | ||||||
|  |             case 3: | ||||||
|  |                 UNIMPLEMENTED_MSG("Requires some state changes for gl_PointSize to work in shader"); | ||||||
|  |                 return std::make_pair("gl_PointSize", false); | ||||||
|  |             } | ||||||
|  |             return {}; | ||||||
|  |         case Attribute::Index::ClipDistances0123: | ||||||
|  |             return std::make_pair(fmt::format("gl_ClipDistance[{}]", abuf->GetElement()), false); | ||||||
|  |         case Attribute::Index::ClipDistances4567: | ||||||
|  |             return std::make_pair(fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4), | ||||||
|  |                                   false); | ||||||
|  |         default: | ||||||
|  |             if (IsGenericAttribute(attribute)) { | ||||||
|  |                 return std::make_pair( | ||||||
|  |                     GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()), false); | ||||||
|  |             } | ||||||
|  |             UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute)); | ||||||
|  |             return {}; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     std::string CastOperand(const std::string& value, Type type) const { |     std::string CastOperand(const std::string& value, Type type) const { | ||||||
|         switch (type) { |         switch (type) { | ||||||
|         case Type::Bool: |         case Type::Bool: | ||||||
|  | @ -999,6 +1053,8 @@ private: | ||||||
|         const Node& src = operation[1]; |         const Node& src = operation[1]; | ||||||
| 
 | 
 | ||||||
|         std::string target; |         std::string target; | ||||||
|  |         bool is_integer = false; | ||||||
|  | 
 | ||||||
|         if (const auto gpr = std::get_if<GprNode>(&*dest)) { |         if (const auto gpr = std::get_if<GprNode>(&*dest)) { | ||||||
|             if (gpr->GetIndex() == Register::ZeroIndex) { |             if (gpr->GetIndex() == Register::ZeroIndex) { | ||||||
|                 // Writing to Register::ZeroIndex is a no op
 |                 // Writing to Register::ZeroIndex is a no op
 | ||||||
|  | @ -1007,26 +1063,12 @@ private: | ||||||
|             target = GetRegister(gpr->GetIndex()); |             target = GetRegister(gpr->GetIndex()); | ||||||
|         } else if (const auto abuf = std::get_if<AbufNode>(&*dest)) { |         } else if (const auto abuf = std::get_if<AbufNode>(&*dest)) { | ||||||
|             UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer()); |             UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer()); | ||||||
| 
 |             const auto result = GetOutputAttribute(abuf); | ||||||
|             target = [&]() -> std::string { |             if (!result) { | ||||||
|                 switch (const auto attribute = abuf->GetIndex(); abuf->GetIndex()) { |                 return {}; | ||||||
|                 case Attribute::Index::Position: |             } | ||||||
|                     return "gl_Position"s + GetSwizzle(abuf->GetElement()); |             target = result->first; | ||||||
|                 case Attribute::Index::PointSize: |             is_integer = result->second; | ||||||
|                     return "gl_PointSize"; |  | ||||||
|                 case Attribute::Index::ClipDistances0123: |  | ||||||
|                     return fmt::format("gl_ClipDistance[{}]", abuf->GetElement()); |  | ||||||
|                 case Attribute::Index::ClipDistances4567: |  | ||||||
|                     return fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4); |  | ||||||
|                 default: |  | ||||||
|                     if (IsGenericAttribute(attribute)) { |  | ||||||
|                         return GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()); |  | ||||||
|                     } |  | ||||||
|                     UNIMPLEMENTED_MSG("Unhandled output attribute: {}", |  | ||||||
|                                       static_cast<u32>(attribute)); |  | ||||||
|                     return "0"; |  | ||||||
|                 } |  | ||||||
|             }(); |  | ||||||
|         } else if (const auto lmem = std::get_if<LmemNode>(&*dest)) { |         } else if (const auto lmem = std::get_if<LmemNode>(&*dest)) { | ||||||
|             target = fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); |             target = fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); | ||||||
|         } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) { |         } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) { | ||||||
|  | @ -1038,7 +1080,11 @@ private: | ||||||
|             UNREACHABLE_MSG("Assign called without a proper target"); |             UNREACHABLE_MSG("Assign called without a proper target"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         code.AddLine("{} = {};", target, Visit(src)); |         if (is_integer) { | ||||||
|  |             code.AddLine("{} = ftoi({});", target, Visit(src)); | ||||||
|  |         } else { | ||||||
|  |             code.AddLine("{} = {};", target, Visit(src)); | ||||||
|  |         } | ||||||
|         return {}; |         return {}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -78,6 +78,7 @@ struct ShaderEntries { | ||||||
|     std::vector<ImageEntry> images; |     std::vector<ImageEntry> images; | ||||||
|     std::vector<GlobalMemoryEntry> global_memory_entries; |     std::vector<GlobalMemoryEntry> global_memory_entries; | ||||||
|     std::array<bool, Maxwell::NumClipDistances> clip_distances{}; |     std::array<bool, Maxwell::NumClipDistances> clip_distances{}; | ||||||
|  |     bool shader_viewport_layer_array{}; | ||||||
|     std::size_t shader_length{}; |     std::size_t shader_length{}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -373,6 +373,12 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     bool shader_viewport_layer_array{}; | ||||||
|  |     if (!LoadObjectFromPrecompiled(shader_viewport_layer_array)) { | ||||||
|  |         return {}; | ||||||
|  |     } | ||||||
|  |     entry.entries.shader_viewport_layer_array = shader_viewport_layer_array; | ||||||
|  | 
 | ||||||
|     u64 shader_length{}; |     u64 shader_length{}; | ||||||
|     if (!LoadObjectFromPrecompiled(shader_length)) { |     if (!LoadObjectFromPrecompiled(shader_length)) { | ||||||
|         return {}; |         return {}; | ||||||
|  | @ -445,6 +451,10 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std: | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (!SaveObjectToPrecompiled(entries.shader_viewport_layer_array)) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if (!SaveObjectToPrecompiled(static_cast<u64>(entries.shader_length))) { |     if (!SaveObjectToPrecompiled(static_cast<u64>(entries.shader_length))) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -430,20 +430,17 @@ private: | ||||||
|         instance_index = DeclareBuiltIn(spv::BuiltIn::InstanceIndex, spv::StorageClass::Input, |         instance_index = DeclareBuiltIn(spv::BuiltIn::InstanceIndex, spv::StorageClass::Input, | ||||||
|                                         t_in_uint, "instance_index"); |                                         t_in_uint, "instance_index"); | ||||||
| 
 | 
 | ||||||
|         bool is_point_size_declared = false; |  | ||||||
|         bool is_clip_distances_declared = false; |         bool is_clip_distances_declared = false; | ||||||
|         for (const auto index : ir.GetOutputAttributes()) { |         for (const auto index : ir.GetOutputAttributes()) { | ||||||
|             if (index == Attribute::Index::PointSize) { |             if (index == Attribute::Index::ClipDistances0123 || | ||||||
|                 is_point_size_declared = true; |                 index == Attribute::Index::ClipDistances4567) { | ||||||
|             } else if (index == Attribute::Index::ClipDistances0123 || |  | ||||||
|                        index == Attribute::Index::ClipDistances4567) { |  | ||||||
|                 is_clip_distances_declared = true; |                 is_clip_distances_declared = true; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         std::vector<Id> members; |         std::vector<Id> members; | ||||||
|         members.push_back(t_float4); |         members.push_back(t_float4); | ||||||
|         if (is_point_size_declared) { |         if (ir.UsesPointSize()) { | ||||||
|             members.push_back(t_float); |             members.push_back(t_float); | ||||||
|         } |         } | ||||||
|         if (is_clip_distances_declared) { |         if (is_clip_distances_declared) { | ||||||
|  | @ -466,7 +463,7 @@ private: | ||||||
| 
 | 
 | ||||||
|         position_index = MemberDecorateBuiltIn(spv::BuiltIn::Position, "position", true); |         position_index = MemberDecorateBuiltIn(spv::BuiltIn::Position, "position", true); | ||||||
|         point_size_index = |         point_size_index = | ||||||
|             MemberDecorateBuiltIn(spv::BuiltIn::PointSize, "point_size", is_point_size_declared); |             MemberDecorateBuiltIn(spv::BuiltIn::PointSize, "point_size", ir.UsesPointSize()); | ||||||
|         clip_distances_index = MemberDecorateBuiltIn(spv::BuiltIn::ClipDistance, "clip_distances", |         clip_distances_index = MemberDecorateBuiltIn(spv::BuiltIn::ClipDistance, "clip_distances", | ||||||
|                                                      is_clip_distances_declared); |                                                      is_clip_distances_declared); | ||||||
| 
 | 
 | ||||||
|  | @ -712,7 +709,8 @@ private: | ||||||
|                 case Attribute::Index::Position: |                 case Attribute::Index::Position: | ||||||
|                     return AccessElement(t_out_float, per_vertex, position_index, |                     return AccessElement(t_out_float, per_vertex, position_index, | ||||||
|                                          abuf->GetElement()); |                                          abuf->GetElement()); | ||||||
|                 case Attribute::Index::PointSize: |                 case Attribute::Index::LayerViewportPointSize: | ||||||
|  |                     UNIMPLEMENTED_IF(abuf->GetElement() != 3); | ||||||
|                     return AccessElement(t_out_float, per_vertex, point_size_index); |                     return AccessElement(t_out_float, per_vertex, point_size_index); | ||||||
|                 case Attribute::Index::ClipDistances0123: |                 case Attribute::Index::ClipDistances0123: | ||||||
|                     return AccessElement(t_out_float, per_vertex, clip_distances_index, |                     return AccessElement(t_out_float, per_vertex, clip_distances_index, | ||||||
|  |  | ||||||
|  | @ -89,6 +89,22 @@ Node ShaderIR::GetPhysicalInputAttribute(Tegra::Shader::Register physical_addres | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) { | Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) { | ||||||
|  |     if (index == Attribute::Index::LayerViewportPointSize) { | ||||||
|  |         switch (element) { | ||||||
|  |         case 0: | ||||||
|  |             UNIMPLEMENTED(); | ||||||
|  |             break; | ||||||
|  |         case 1: | ||||||
|  |             uses_layer = true; | ||||||
|  |             break; | ||||||
|  |         case 2: | ||||||
|  |             uses_viewport_index = true; | ||||||
|  |             break; | ||||||
|  |         case 3: | ||||||
|  |             uses_point_size = true; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|     if (index == Attribute::Index::ClipDistances0123 || |     if (index == Attribute::Index::ClipDistances0123 || | ||||||
|         index == Attribute::Index::ClipDistances4567) { |         index == Attribute::Index::ClipDistances4567) { | ||||||
|         const auto clip_index = |         const auto clip_index = | ||||||
|  |  | ||||||
|  | @ -121,6 +121,18 @@ public: | ||||||
|         return static_cast<std::size_t>(coverage_end * sizeof(u64)); |         return static_cast<std::size_t>(coverage_end * sizeof(u64)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     bool UsesLayer() const { | ||||||
|  |         return uses_layer; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool UsesViewportIndex() const { | ||||||
|  |         return uses_viewport_index; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool UsesPointSize() const { | ||||||
|  |         return uses_point_size; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     bool HasPhysicalAttributes() const { |     bool HasPhysicalAttributes() const { | ||||||
|         return uses_physical_attributes; |         return uses_physical_attributes; | ||||||
|     } |     } | ||||||
|  | @ -343,6 +355,9 @@ private: | ||||||
|     std::set<Image> used_images; |     std::set<Image> used_images; | ||||||
|     std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{}; |     std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{}; | ||||||
|     std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory; |     std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory; | ||||||
|  |     bool uses_layer{}; | ||||||
|  |     bool uses_viewport_index{}; | ||||||
|  |     bool uses_point_size{}; | ||||||
|     bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes
 |     bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes
 | ||||||
| 
 | 
 | ||||||
|     Tegra::Shader::Header header; |     Tegra::Shader::Header header; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 ReinUsesLisp
						ReinUsesLisp