فهرست منبع

VideoCore: Fix values of unset components in input attribute arrays

If an input attribute array had a field with less than 4 components, the
remaining components were left unset if not specified by a default
vertex attribute. If neither mechanism would set a component, it would
assume a garbage value.

It has been verified that the hardware behavior is to instead to set the
missing components from the fixed default of (0 0 0 1). The default
vertex attribute values aren't used at all if a vertex array is
specified for that attribute.

Fixes UI graphics on Fire Emblem: Awakening, a small texturing glitch
when selecting a character in Cubic Ninja, as well as eliminating the
unset-W hack which was required for Ocarina of Time to not have
garbled triangles.

This change has been tested against hardware.
Yuri Kunde Schlesner 11 سال پیش
والد
کامیت
1fe9b0b82e
1فایلهای تغییر یافته به همراه38 افزوده شده و 42 حذف شده
  1. 38 42
      src/video_core/command_processor.cpp

+ 38 - 42
src/video_core/command_processor.cpp

@@ -217,57 +217,53 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
                 // Initialize data for the current vertex
                 VertexShader::InputVertex input;
 
-                // Load a debugging token to check whether this gets loaded by the running
-                // application or not.
-                static const float24 debug_token = float24::FromRawFloat24(0x00abcdef);
-                input.attr[0].w = debug_token;
-
                 for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) {
-                    // Load the default attribute if we're configured to do so, this data will be overwritten by the loader data if it's set
-                    if (attribute_config.IsDefaultAttribute(i)) {
+                    if (vertex_attribute_elements[i] != 0) {
+                        // Default attribute values set if array elements have < 4 components. This
+                        // is *not* carried over from the default attribute settings even if they're
+                        // enabled for this attribute.
+                        static const float24 zero = float24::FromFloat32(0.0f);
+                        static const float24 one = float24::FromFloat32(1.0f);
+                        input.attr[i] = Math::Vec4<float24>(zero, zero, zero, one);
+
+                        // Load per-vertex data from the loader arrays
+                        for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
+                            u32 source_addr = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i];
+                            const u8* srcdata = Memory::GetPhysicalPointer(source_addr);
+
+                            if (g_debug_context && Pica::g_debug_context->recorder) {
+                                memory_accesses.AddAccess(source_addr,
+                                    (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT) ? 4
+                                    : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? 2 : 1);
+                            }
+
+                            const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata :
+                                (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata :
+                                (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? *(s16*)srcdata :
+                                *(float*)srcdata;
+
+                            input.attr[i][comp] = float24::FromFloat32(srcval);
+                            LOG_TRACE(HW_GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f",
+                                comp, i, vertex, index,
+                                attribute_config.GetPhysicalBaseAddress(),
+                                vertex_attribute_sources[i] - base_address,
+                                vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i],
+                                input.attr[i][comp].ToFloat32());
+                        }
+                    } else if (attribute_config.IsDefaultAttribute(i)) {
+                        // Load the default attribute if we're configured to do so
                         input.attr[i] = g_state.vs.default_attributes[i];
                         LOG_TRACE(HW_GPU, "Loaded default attribute %x for vertex %x (index %x): (%f, %f, %f, %f)",
                                   i, vertex, index,
                                   input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(),
                                   input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32());
-                    }
-
-                    // Load per-vertex data from the loader arrays
-                    for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
-                        u32 source_addr = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i];
-                        const u8* srcdata = Memory::GetPhysicalPointer(source_addr);
-
-                        if (g_debug_context && Pica::g_debug_context->recorder) {
-                            memory_accesses.AddAccess(source_addr,
-                                    (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT) ? 4
-                                    : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? 2 : 1);
-                        }
-
-                        const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata :
-                            (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata :
-                            (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? *(s16*)srcdata :
-                            *(float*)srcdata;
-
-                        input.attr[i][comp] = float24::FromFloat32(srcval);
-                        LOG_TRACE(HW_GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f",
-                            comp, i, vertex, index,
-                            attribute_config.GetPhysicalBaseAddress(),
-                            vertex_attribute_sources[i] - base_address,
-                            vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i],
-                            input.attr[i][comp].ToFloat32());
+                    } else {
+                        // TODO(yuriks): In this case, no data gets loaded and the vertex remains
+                        //              with the last value it had. This isn't currently maintained
+                        //              as global state, however, and so won't work in Cita yet.
                     }
                 }
 
-                // HACK: Some games do not initialize the vertex position's w component. This leads
-                //       to critical issues since it messes up perspective division. As a
-                //       workaround, we force the fourth component to 1.0 if we find this to be the
-                //       case.
-                //       To do this, we additionally have to assume that the first input attribute
-                //       is the vertex position, since there's no information about this other than
-                //       the empiric observation that this is usually the case.
-                if (input.attr[0].w == debug_token)
-                    input.attr[0].w = float24::FromFloat32(1.0);
-
                 if (g_debug_context)
                     g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, (void*)&input);