summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2015-05-06 19:33:03 -0400
committerGravatar bunnei2015-05-06 19:33:03 -0400
commit337f1e1b96445b81c40c313b1bf680fe660f14f5 (patch)
tree2a2a37c9b7c938e3e1abf3b36c637cd6b5c25d1f
parentMerge pull request #720 from yuriks/svc-cleanup (diff)
parentGPU: Implemented default vertex shader attributes. (diff)
downloadyuzu-337f1e1b96445b81c40c313b1bf680fe660f14f5.tar.gz
yuzu-337f1e1b96445b81c40c313b1bf680fe660f14f5.tar.xz
yuzu-337f1e1b96445b81c40c313b1bf680fe660f14f5.zip
Merge pull request #695 from Subv/crash_f
GPU: Implemented default vertex shader attributes.
Diffstat (limited to '')
-rw-r--r--src/video_core/command_processor.cpp98
-rw-r--r--src/video_core/pica.h67
-rw-r--r--src/video_core/vertex_shader.cpp39
-rw-r--r--src/video_core/vertex_shader.h1
4 files changed, 137 insertions, 68 deletions
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index e031871e8..c4cdf672b 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -27,6 +27,10 @@ static int float_regs_counter = 0;
27 27
28static u32 uniform_write_buffer[4]; 28static u32 uniform_write_buffer[4];
29 29
30static int default_attr_counter = 0;
31
32static u32 default_attr_write_buffer[3];
33
30Common::Profiling::TimingCategory category_drawing("Drawing"); 34Common::Profiling::TimingCategory category_drawing("Drawing");
31 35
32static inline void WritePicaReg(u32 id, u32 value, u32 mask) { 36static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
@@ -71,12 +75,9 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
71 u32 vertex_attribute_sources[16]; 75 u32 vertex_attribute_sources[16];
72 boost::fill(vertex_attribute_sources, 0xdeadbeef); 76 boost::fill(vertex_attribute_sources, 0xdeadbeef);
73 u32 vertex_attribute_strides[16]; 77 u32 vertex_attribute_strides[16];
74 u32 vertex_attribute_formats[16]; 78 Regs::VertexAttributeFormat vertex_attribute_formats[16];
75 79
76 // HACK: Initialize vertex_attribute_elements to zero to prevent infinite loops below. 80 u32 vertex_attribute_elements[16];
77 // This is one of the hacks required to deal with uninitalized vertex attributes.
78 // TODO: Fix this properly.
79 u32 vertex_attribute_elements[16] = {};
80 u32 vertex_attribute_element_size[16]; 81 u32 vertex_attribute_element_size[16];
81 82
82 // Setup attribute data from loaders 83 // Setup attribute data from loaders
@@ -90,7 +91,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
90 u32 attribute_index = loader_config.GetComponent(component); 91 u32 attribute_index = loader_config.GetComponent(component);
91 vertex_attribute_sources[attribute_index] = load_address; 92 vertex_attribute_sources[attribute_index] = load_address;
92 vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count); 93 vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count);
93 vertex_attribute_formats[attribute_index] = static_cast<u32>(attribute_config.GetFormat(attribute_index)); 94 vertex_attribute_formats[attribute_index] = attribute_config.GetFormat(attribute_index);
94 vertex_attribute_elements[attribute_index] = attribute_config.GetNumElements(attribute_index); 95 vertex_attribute_elements[attribute_index] = attribute_config.GetNumElements(attribute_index);
95 vertex_attribute_element_size[attribute_index] = attribute_config.GetElementSizeInBytes(attribute_index); 96 vertex_attribute_element_size[attribute_index] = attribute_config.GetElementSizeInBytes(attribute_index);
96 load_address += attribute_config.GetStride(attribute_index); 97 load_address += attribute_config.GetStride(attribute_index);
@@ -126,26 +127,29 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
126 input.attr[0].w = debug_token; 127 input.attr[0].w = debug_token;
127 128
128 for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) { 129 for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) {
129 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 130 if (attribute_config.IsDefaultAttribute(i)) {
130 const u8* srcdata = Memory::GetPointer(PAddrToVAddr(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i])); 131 input.attr[i] = VertexShader::GetDefaultAttribute(i);
131 132 LOG_TRACE(HW_GPU, "Loaded default attribute %x for vertex %x (index %x): (%f, %f, %f, %f)",
132 // TODO(neobrain): Ocarina of Time 3D has GetNumTotalAttributes return 8, 133 i, vertex, index,
133 // yet only provides 2 valid source data addresses. Need to figure out 134 input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(),
134 // what's wrong there, until then we just continue when address lookup fails 135 input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32());
135 if (srcdata == nullptr) 136 } else {
136 continue; 137 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
137 138 const u8* srcdata = Memory::GetPointer(PAddrToVAddr(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]));
138 const float srcval = (vertex_attribute_formats[i] == 0) ? *(s8*)srcdata : 139
139 (vertex_attribute_formats[i] == 1) ? *(u8*)srcdata : 140 const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata :
140 (vertex_attribute_formats[i] == 2) ? *(s16*)srcdata : 141 (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata :
141 *(float*)srcdata; 142 (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? *(s16*)srcdata :
142 input.attr[i][comp] = float24::FromFloat32(srcval); 143 *(float*)srcdata;
143 LOG_TRACE(HW_GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f", 144
144 comp, i, vertex, index, 145 input.attr[i][comp] = float24::FromFloat32(srcval);
145 attribute_config.GetPhysicalBaseAddress(), 146 LOG_TRACE(HW_GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f",
146 vertex_attribute_sources[i] - base_address, 147 comp, i, vertex, index,
147 vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i], 148 attribute_config.GetPhysicalBaseAddress(),
148 input.attr[i][comp].ToFloat32()); 149 vertex_attribute_sources[i] - base_address,
150 vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i],
151 input.attr[i][comp].ToFloat32());
152 }
149 } 153 }
150 } 154 }
151 155
@@ -224,7 +228,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
224 // it directly write the values? 228 // it directly write the values?
225 uniform_write_buffer[float_regs_counter++] = value; 229 uniform_write_buffer[float_regs_counter++] = value;
226 230
227 // Uniforms are written in a packed format such that 4 float24 values are encoded in 231 // Uniforms are written in a packed format such that four float24 values are encoded in
228 // three 32-bit numbers. We write to internal memory once a full such vector is 232 // three 32-bit numbers. We write to internal memory once a full such vector is
229 // written. 233 // written.
230 if ((float_regs_counter >= 4 && uniform_setup.IsFloat32()) || 234 if ((float_regs_counter >= 4 && uniform_setup.IsFloat32()) ||
@@ -259,6 +263,46 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
259 } 263 }
260 break; 264 break;
261 } 265 }
266
267 // Load default vertex input attributes
268 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233):
269 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234):
270 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[2], 0x235):
271 {
272 // TODO: Does actual hardware indeed keep an intermediate buffer or does
273 // it directly write the values?
274 default_attr_write_buffer[default_attr_counter++] = value;
275
276 // Default attributes are written in a packed format such that four float24 values are encoded in
277 // three 32-bit numbers. We write to internal memory once a full such vector is
278 // written.
279 if (default_attr_counter >= 3) {
280 default_attr_counter = 0;
281
282 auto& setup = registers.vs_default_attributes_setup;
283
284 if (setup.index >= 16) {
285 LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index);
286 break;
287 }
288
289 Math::Vec4<float24>& attribute = VertexShader::GetDefaultAttribute(setup.index);
290
291 // NOTE: The destination component order indeed is "backwards"
292 attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8);
293 attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF));
294 attribute.y = float24::FromRawFloat24(((default_attr_write_buffer[1] & 0xFFFF) << 8) | ((default_attr_write_buffer[2] >> 24) & 0xFF));
295 attribute.x = float24::FromRawFloat24(default_attr_write_buffer[2] & 0xFFFFFF);
296
297 LOG_TRACE(HW_GPU, "Set default VS attribute %x to (%f %f %f %f)", (int)setup.index,
298 attribute.x.ToFloat32(), attribute.y.ToFloat32(), attribute.z.ToFloat32(),
299 attribute.w.ToFloat32());
300
301 // TODO: Verify that this actually modifies the register!
302 setup.index = setup.index + 1;
303 }
304 break;
305 }
262 306
263 // Load shader program code 307 // Load shader program code
264 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[0], 0x2cc): 308 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[0], 0x2cc):
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index fe20cd77d..8acad8676 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -489,14 +489,14 @@ struct Regs {
489 489
490 INSERT_PADDING_WORDS(0xe0); 490 INSERT_PADDING_WORDS(0xe0);
491 491
492 struct { 492 enum class VertexAttributeFormat : u64 {
493 enum class Format : u64 { 493 BYTE = 0,
494 BYTE = 0, 494 UBYTE = 1,
495 UBYTE = 1, 495 SHORT = 2,
496 SHORT = 2, 496 FLOAT = 3,
497 FLOAT = 3, 497 };
498 };
499 498
499 struct {
500 BitField<0, 29, u32> base_address; 500 BitField<0, 29, u32> base_address;
501 501
502 u32 GetPhysicalBaseAddress() const { 502 u32 GetPhysicalBaseAddress() const {
@@ -505,29 +505,29 @@ struct Regs {
505 505
506 // Descriptor for internal vertex attributes 506 // Descriptor for internal vertex attributes
507 union { 507 union {
508 BitField< 0, 2, Format> format0; // size of one element 508 BitField< 0, 2, VertexAttributeFormat> format0; // size of one element
509 BitField< 2, 2, u64> size0; // number of elements minus 1 509 BitField< 2, 2, u64> size0; // number of elements minus 1
510 BitField< 4, 2, Format> format1; 510 BitField< 4, 2, VertexAttributeFormat> format1;
511 BitField< 6, 2, u64> size1; 511 BitField< 6, 2, u64> size1;
512 BitField< 8, 2, Format> format2; 512 BitField< 8, 2, VertexAttributeFormat> format2;
513 BitField<10, 2, u64> size2; 513 BitField<10, 2, u64> size2;
514 BitField<12, 2, Format> format3; 514 BitField<12, 2, VertexAttributeFormat> format3;
515 BitField<14, 2, u64> size3; 515 BitField<14, 2, u64> size3;
516 BitField<16, 2, Format> format4; 516 BitField<16, 2, VertexAttributeFormat> format4;
517 BitField<18, 2, u64> size4; 517 BitField<18, 2, u64> size4;
518 BitField<20, 2, Format> format5; 518 BitField<20, 2, VertexAttributeFormat> format5;
519 BitField<22, 2, u64> size5; 519 BitField<22, 2, u64> size5;
520 BitField<24, 2, Format> format6; 520 BitField<24, 2, VertexAttributeFormat> format6;
521 BitField<26, 2, u64> size6; 521 BitField<26, 2, u64> size6;
522 BitField<28, 2, Format> format7; 522 BitField<28, 2, VertexAttributeFormat> format7;
523 BitField<30, 2, u64> size7; 523 BitField<30, 2, u64> size7;
524 BitField<32, 2, Format> format8; 524 BitField<32, 2, VertexAttributeFormat> format8;
525 BitField<34, 2, u64> size8; 525 BitField<34, 2, u64> size8;
526 BitField<36, 2, Format> format9; 526 BitField<36, 2, VertexAttributeFormat> format9;
527 BitField<38, 2, u64> size9; 527 BitField<38, 2, u64> size9;
528 BitField<40, 2, Format> format10; 528 BitField<40, 2, VertexAttributeFormat> format10;
529 BitField<42, 2, u64> size10; 529 BitField<42, 2, u64> size10;
530 BitField<44, 2, Format> format11; 530 BitField<44, 2, VertexAttributeFormat> format11;
531 BitField<46, 2, u64> size11; 531 BitField<46, 2, u64> size11;
532 532
533 BitField<48, 12, u64> attribute_mask; 533 BitField<48, 12, u64> attribute_mask;
@@ -536,8 +536,8 @@ struct Regs {
536 BitField<60, 4, u64> num_extra_attributes; 536 BitField<60, 4, u64> num_extra_attributes;
537 }; 537 };
538 538
539 inline Format GetFormat(int n) const { 539 inline VertexAttributeFormat GetFormat(int n) const {
540 Format formats[] = { 540 VertexAttributeFormat formats[] = {
541 format0, format1, format2, format3, 541 format0, format1, format2, format3,
542 format4, format5, format6, format7, 542 format4, format5, format6, format7,
543 format8, format9, format10, format11 543 format8, format9, format10, format11
@@ -555,14 +555,18 @@ struct Regs {
555 } 555 }
556 556
557 inline int GetElementSizeInBytes(int n) const { 557 inline int GetElementSizeInBytes(int n) const {
558 return (GetFormat(n) == Format::FLOAT) ? 4 : 558 return (GetFormat(n) == VertexAttributeFormat::FLOAT) ? 4 :
559 (GetFormat(n) == Format::SHORT) ? 2 : 1; 559 (GetFormat(n) == VertexAttributeFormat::SHORT) ? 2 : 1;
560 } 560 }
561 561
562 inline int GetStride(int n) const { 562 inline int GetStride(int n) const {
563 return GetNumElements(n) * GetElementSizeInBytes(n); 563 return GetNumElements(n) * GetElementSizeInBytes(n);
564 } 564 }
565 565
566 inline bool IsDefaultAttribute(int id) const {
567 return (id >= 12) || (attribute_mask & (1 << id)) != 0;
568 }
569
566 inline int GetNumTotalAttributes() const { 570 inline int GetNumTotalAttributes() const {
567 return (int)num_extra_attributes+1; 571 return (int)num_extra_attributes+1;
568 } 572 }
@@ -625,7 +629,18 @@ struct Regs {
625 u32 trigger_draw; 629 u32 trigger_draw;
626 u32 trigger_draw_indexed; 630 u32 trigger_draw_indexed;
627 631
628 INSERT_PADDING_WORDS(0x2e); 632 INSERT_PADDING_WORDS(0x2);
633
634 // These registers are used to setup the default "fall-back" vertex shader attributes
635 struct {
636 // Index of the current default attribute
637 u32 index;
638
639 // Writing to these registers sets the "current" default attribute.
640 u32 set_value[3];
641 } vs_default_attributes_setup;
642
643 INSERT_PADDING_WORDS(0x28);
629 644
630 enum class TriangleTopology : u32 { 645 enum class TriangleTopology : u32 {
631 List = 0, 646 List = 0,
@@ -669,7 +684,7 @@ struct Regs {
669 BitField<56, 4, u64> attribute14_register; 684 BitField<56, 4, u64> attribute14_register;
670 BitField<60, 4, u64> attribute15_register; 685 BitField<60, 4, u64> attribute15_register;
671 686
672 int GetRegisterForAttribute(int attribute_index) { 687 int GetRegisterForAttribute(int attribute_index) const {
673 u64 fields[] = { 688 u64 fields[] = {
674 attribute0_register, attribute1_register, attribute2_register, attribute3_register, 689 attribute0_register, attribute1_register, attribute2_register, attribute3_register,
675 attribute4_register, attribute5_register, attribute6_register, attribute7_register, 690 attribute4_register, attribute5_register, attribute6_register, attribute7_register,
@@ -775,6 +790,7 @@ struct Regs {
775 ADD_FIELD(num_vertices); 790 ADD_FIELD(num_vertices);
776 ADD_FIELD(trigger_draw); 791 ADD_FIELD(trigger_draw);
777 ADD_FIELD(trigger_draw_indexed); 792 ADD_FIELD(trigger_draw_indexed);
793 ADD_FIELD(vs_default_attributes_setup);
778 ADD_FIELD(triangle_topology); 794 ADD_FIELD(triangle_topology);
779 ADD_FIELD(vs_bool_uniforms); 795 ADD_FIELD(vs_bool_uniforms);
780 ADD_FIELD(vs_int_uniforms); 796 ADD_FIELD(vs_int_uniforms);
@@ -849,6 +865,7 @@ ASSERT_REG_POSITION(index_array, 0x227);
849ASSERT_REG_POSITION(num_vertices, 0x228); 865ASSERT_REG_POSITION(num_vertices, 0x228);
850ASSERT_REG_POSITION(trigger_draw, 0x22e); 866ASSERT_REG_POSITION(trigger_draw, 0x22e);
851ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f); 867ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f);
868ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232);
852ASSERT_REG_POSITION(triangle_topology, 0x25e); 869ASSERT_REG_POSITION(triangle_topology, 0x25e);
853ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0); 870ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0);
854ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1); 871ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1);
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp
index e8d865172..51f4e58bf 100644
--- a/src/video_core/vertex_shader.cpp
+++ b/src/video_core/vertex_shader.cpp
@@ -35,6 +35,8 @@ static struct {
35 std::array<Math::Vec4<u8>,4> i; 35 std::array<Math::Vec4<u8>,4> i;
36} shader_uniforms; 36} shader_uniforms;
37 37
38static Math::Vec4<float24> vs_default_attributes[16];
39
38// TODO: Not sure where the shader binary and swizzle patterns are supposed to be loaded to! 40// TODO: Not sure where the shader binary and swizzle patterns are supposed to be loaded to!
39// For now, we just keep these local arrays around. 41// For now, we just keep these local arrays around.
40static std::array<u32, 1024> shader_memory; 42static std::array<u32, 1024> shader_memory;
@@ -60,6 +62,10 @@ Math::Vec4<u8>& GetIntUniform(u32 index) {
60 return shader_uniforms.i[index]; 62 return shader_uniforms.i[index];
61} 63}
62 64
65Math::Vec4<float24>& GetDefaultAttribute(u32 index) {
66 return vs_default_attributes[index];
67}
68
63const std::array<u32, 1024>& GetShaderBinary() { 69const std::array<u32, 1024>& GetShaderBinary() {
64 return shader_memory; 70 return shader_memory;
65} 71}
@@ -568,22 +574,23 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes) {
568 const auto& attribute_register_map = registers.vs_input_register_map; 574 const auto& attribute_register_map = registers.vs_input_register_map;
569 float24 dummy_register; 575 float24 dummy_register;
570 boost::fill(state.input_register_table, &dummy_register); 576 boost::fill(state.input_register_table, &dummy_register);
571 if(num_attributes > 0) state.input_register_table[attribute_register_map.attribute0_register] = &input.attr[0].x; 577
572 if(num_attributes > 1) state.input_register_table[attribute_register_map.attribute1_register] = &input.attr[1].x; 578 if (num_attributes > 0) state.input_register_table[attribute_register_map.attribute0_register] = &input.attr[0].x;
573 if(num_attributes > 2) state.input_register_table[attribute_register_map.attribute2_register] = &input.attr[2].x; 579 if (num_attributes > 1) state.input_register_table[attribute_register_map.attribute1_register] = &input.attr[1].x;
574 if(num_attributes > 3) state.input_register_table[attribute_register_map.attribute3_register] = &input.attr[3].x; 580 if (num_attributes > 2) state.input_register_table[attribute_register_map.attribute2_register] = &input.attr[2].x;
575 if(num_attributes > 4) state.input_register_table[attribute_register_map.attribute4_register] = &input.attr[4].x; 581 if (num_attributes > 3) state.input_register_table[attribute_register_map.attribute3_register] = &input.attr[3].x;
576 if(num_attributes > 5) state.input_register_table[attribute_register_map.attribute5_register] = &input.attr[5].x; 582 if (num_attributes > 4) state.input_register_table[attribute_register_map.attribute4_register] = &input.attr[4].x;
577 if(num_attributes > 6) state.input_register_table[attribute_register_map.attribute6_register] = &input.attr[6].x; 583 if (num_attributes > 5) state.input_register_table[attribute_register_map.attribute5_register] = &input.attr[5].x;
578 if(num_attributes > 7) state.input_register_table[attribute_register_map.attribute7_register] = &input.attr[7].x; 584 if (num_attributes > 6) state.input_register_table[attribute_register_map.attribute6_register] = &input.attr[6].x;
579 if(num_attributes > 8) state.input_register_table[attribute_register_map.attribute8_register] = &input.attr[8].x; 585 if (num_attributes > 7) state.input_register_table[attribute_register_map.attribute7_register] = &input.attr[7].x;
580 if(num_attributes > 9) state.input_register_table[attribute_register_map.attribute9_register] = &input.attr[9].x; 586 if (num_attributes > 8) state.input_register_table[attribute_register_map.attribute8_register] = &input.attr[8].x;
581 if(num_attributes > 10) state.input_register_table[attribute_register_map.attribute10_register] = &input.attr[10].x; 587 if (num_attributes > 9) state.input_register_table[attribute_register_map.attribute9_register] = &input.attr[9].x;
582 if(num_attributes > 11) state.input_register_table[attribute_register_map.attribute11_register] = &input.attr[11].x; 588 if (num_attributes > 10) state.input_register_table[attribute_register_map.attribute10_register] = &input.attr[10].x;
583 if(num_attributes > 12) state.input_register_table[attribute_register_map.attribute12_register] = &input.attr[12].x; 589 if (num_attributes > 11) state.input_register_table[attribute_register_map.attribute11_register] = &input.attr[11].x;
584 if(num_attributes > 13) state.input_register_table[attribute_register_map.attribute13_register] = &input.attr[13].x; 590 if (num_attributes > 12) state.input_register_table[attribute_register_map.attribute12_register] = &input.attr[12].x;
585 if(num_attributes > 14) state.input_register_table[attribute_register_map.attribute14_register] = &input.attr[14].x; 591 if (num_attributes > 13) state.input_register_table[attribute_register_map.attribute13_register] = &input.attr[13].x;
586 if(num_attributes > 15) state.input_register_table[attribute_register_map.attribute15_register] = &input.attr[15].x; 592 if (num_attributes > 14) state.input_register_table[attribute_register_map.attribute14_register] = &input.attr[14].x;
593 if (num_attributes > 15) state.input_register_table[attribute_register_map.attribute15_register] = &input.attr[15].x;
587 594
588 state.conditional_code[0] = false; 595 state.conditional_code[0] = false;
589 state.conditional_code[1] = false; 596 state.conditional_code[1] = false;
diff --git a/src/video_core/vertex_shader.h b/src/video_core/vertex_shader.h
index 3a68a3409..c26709bbc 100644
--- a/src/video_core/vertex_shader.h
+++ b/src/video_core/vertex_shader.h
@@ -74,6 +74,7 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes);
74Math::Vec4<float24>& GetFloatUniform(u32 index); 74Math::Vec4<float24>& GetFloatUniform(u32 index);
75bool& GetBoolUniform(u32 index); 75bool& GetBoolUniform(u32 index);
76Math::Vec4<u8>& GetIntUniform(u32 index); 76Math::Vec4<u8>& GetIntUniform(u32 index);
77Math::Vec4<float24>& GetDefaultAttribute(u32 index);
77 78
78const std::array<u32, 1024>& GetShaderBinary(); 79const std::array<u32, 1024>& GetShaderBinary();
79const std::array<u32, 1024>& GetSwizzlePatterns(); 80const std::array<u32, 1024>& GetSwizzlePatterns();