vertex_loader.cpp
1 // Copyright 2023 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #include "common/alignment.h" 6 #include "common/logging/log.h" 7 #include "video_core/pica/vertex_loader.h" 8 9 namespace Pica { 10 11 VertexLoader::VertexLoader(Memory::MemorySystem& memory_, const PipelineRegs& regs) 12 : memory{memory_} { 13 const auto& attribute_config = regs.vertex_attributes; 14 num_total_attributes = attribute_config.GetNumTotalAttributes(); 15 16 vertex_attribute_sources.fill(0xdeadbeef); 17 18 for (u32 i = 0; i < 16; i++) { 19 vertex_attribute_is_default[i] = attribute_config.IsDefaultAttribute(i); 20 } 21 22 // Setup attribute data from loaders 23 for (u32 loader = 0; loader < 12; ++loader) { 24 const auto& loader_config = attribute_config.attribute_loaders[loader]; 25 26 u32 offset = 0; 27 28 // TODO: What happens if a loader overwrites a previous one's data? 29 for (u32 component = 0; component < loader_config.component_count; ++component) { 30 if (component >= 12) { 31 LOG_ERROR(HW_GPU, 32 "Overflow in the vertex attribute loader {} trying to load component {}", 33 loader, component); 34 continue; 35 } 36 37 u32 attribute_index = loader_config.GetComponent(component); 38 if (attribute_index < 12) { 39 offset = Common::AlignUp(offset, 40 attribute_config.GetElementSizeInBytes(attribute_index)); 41 vertex_attribute_sources[attribute_index] = loader_config.data_offset + offset; 42 vertex_attribute_strides[attribute_index] = 43 static_cast<u32>(loader_config.byte_count); 44 vertex_attribute_formats[attribute_index] = 45 attribute_config.GetFormat(attribute_index); 46 vertex_attribute_elements[attribute_index] = 47 attribute_config.GetNumElements(attribute_index); 48 offset += attribute_config.GetStride(attribute_index); 49 } else if (attribute_index < 16) { 50 // Attribute ids 12, 13, 14 and 15 signify 4, 8, 12 and 16-byte paddings, 51 // respectively 52 offset = Common::AlignUp(offset, 4); 53 offset += (attribute_index - 11) * 4; 54 } else { 55 UNREACHABLE(); // This is truly unreachable due to the number of bits for each 56 // component 57 } 58 } 59 } 60 } 61 62 VertexLoader::~VertexLoader() = default; 63 64 void VertexLoader::LoadVertex(PAddr base_address, u32 index, u32 vertex, AttributeBuffer& input, 65 AttributeBuffer& input_default_attributes) const { 66 for (s32 i = 0; i < num_total_attributes; ++i) { 67 // Load the default attribute if we're configured to do so 68 if (vertex_attribute_is_default[i]) { 69 input[i] = input_default_attributes[i]; 70 continue; 71 } 72 73 // TODO(yuriks): In this case, no data gets loaded and the vertex 74 // remains with the last value it had. This isn't currently maintained 75 // as global state, however, and so won't work in Citra yet. 76 if (vertex_attribute_elements[i] == 0) { 77 LOG_ERROR(HW_GPU, "Vertex retension unimplemented"); 78 continue; 79 } 80 81 // Load per-vertex data from the loader arrays 82 const PAddr source_addr = 83 base_address + vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex; 84 85 switch (vertex_attribute_formats[i]) { 86 case PipelineRegs::VertexAttributeFormat::BYTE: 87 LoadAttribute<s8>(source_addr, i, input); 88 break; 89 case PipelineRegs::VertexAttributeFormat::UBYTE: 90 LoadAttribute<u8>(source_addr, i, input); 91 break; 92 case PipelineRegs::VertexAttributeFormat::SHORT: 93 LoadAttribute<s16>(source_addr, i, input); 94 break; 95 case PipelineRegs::VertexAttributeFormat::FLOAT: 96 LoadAttribute<f32>(source_addr, i, input); 97 break; 98 } 99 100 // Default attribute values set if array elements have < 4 components. This 101 // is *not* carried over from the default attribute settings even if they're 102 // enabled for this attribute. 103 for (u32 comp = vertex_attribute_elements[i]; comp < 4; comp++) { 104 input[i][comp] = comp == 3 ? f24::One() : f24::Zero(); 105 } 106 } 107 } 108 109 } // namespace Pica