// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include "common/types.h" #include "shader_recompiler/info.h" namespace Shader::Gcn { struct VertexAttribute { enum InstanceIdType : u8 { None = 0, OverStepRate0 = 1, OverStepRate1 = 2, Plain = 3, }; u8 semantic; ///< Semantic index of the attribute u8 dest_vgpr; ///< Destination VGPR to load first component. u8 num_elements; ///< Number of components to load u8 sgpr_base; ///< SGPR that contains the pointer to the list of vertex V# u8 dword_offset; ///< The dword offset of the V# that describes this attribute. u8 instance_data; ///< Indicates that the buffer will be accessed in instance rate [[nodiscard]] InstanceIdType GetStepRate() const { return static_cast(instance_data); } [[nodiscard]] bool UsesStepRates() const { const auto step_rate = GetStepRate(); return step_rate == OverStepRate0 || step_rate == OverStepRate1; } [[nodiscard]] constexpr AmdGpu::Buffer GetSharp(const Shader::Info& info) const noexcept { return info.ReadUdReg(sgpr_base, dword_offset); } bool operator==(const VertexAttribute& other) const { return semantic == other.semantic && dest_vgpr == other.dest_vgpr && num_elements == other.num_elements && sgpr_base == other.sgpr_base && dword_offset == other.dword_offset && instance_data == other.instance_data; } }; struct FetchShaderData { const u32* code; u32 size = 0; std::vector attributes; s8 vertex_offset_sgpr = -1; ///< SGPR of vertex offset from VADDR s8 instance_offset_sgpr = -1; ///< SGPR of instance offset from VADDR [[nodiscard]] bool UsesStepRates() const { return std::ranges::find_if(attributes, [](const VertexAttribute& attribute) { return attribute.UsesStepRates(); }) != attributes.end(); } [[nodiscard]] std::pair GetDrawOffsets(const AmdGpu::Liverpool::Regs& regs, const Info& info) const { u32 vertex_offset = regs.index_offset; u32 instance_offset = 0; if (vertex_offset == 0 && vertex_offset_sgpr != -1) { vertex_offset = info.user_data[vertex_offset_sgpr]; } if (instance_offset_sgpr != -1) { instance_offset = info.user_data[instance_offset_sgpr]; } return {vertex_offset, instance_offset}; } bool operator==(const FetchShaderData& other) const { return attributes == other.attributes && vertex_offset_sgpr == other.vertex_offset_sgpr && instance_offset_sgpr == other.instance_offset_sgpr; } }; std::optional ParseFetchShader(const Shader::Info& info); } // namespace Shader::Gcn