summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Tony Wasserka2014-12-21 03:01:35 +0100
committerGravatar Tony Wasserka2015-02-18 14:02:59 +0100
commit70a764d992937b2919c6262c70c85117fe22d7d9 (patch)
treec563b2532e2335c7dbac08394abb616b77bc6b42 /src
parentPica/CommandProcessor: Properly implement shader load destination offset regi... (diff)
downloadyuzu-70a764d992937b2919c6262c70c85117fe22d7d9.tar.gz
yuzu-70a764d992937b2919c6262c70c85117fe22d7d9.tar.xz
yuzu-70a764d992937b2919c6262c70c85117fe22d7d9.zip
Pica/VertexShader: Implement the LOOP instruction.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/vertex_shader.cpp50
1 files changed, 36 insertions, 14 deletions
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp
index 80935a50a..def868ac7 100644
--- a/src/video_core/vertex_shader.cpp
+++ b/src/video_core/vertex_shader.cpp
@@ -85,8 +85,11 @@ struct VertexShaderState {
85 }; 85 };
86 86
87 struct CallStackElement { 87 struct CallStackElement {
88 u32 final_address; 88 u32 final_address; // Address upon which we jump to return_address
89 u32 return_address; 89 u32 return_address; // Where to jump when leaving scope
90 u8 repeat_counter; // How often to repeat until this call stack element is removed
91 u8 loop_increment; // Which value to add to the loop counter after an iteration
92 // TODO: Should this be a signed value? Does it even matter?
90 }; 93 };
91 94
92 // TODO: Is there a maximal size for this? 95 // TODO: Is there a maximal size for this?
@@ -105,9 +108,14 @@ static void ProcessShaderCode(VertexShaderState& state) {
105 108
106 while (true) { 109 while (true) {
107 if (!state.call_stack.empty()) { 110 if (!state.call_stack.empty()) {
108 if (state.program_counter - shader_memory.data() == state.call_stack.top().final_address) { 111 auto& top = state.call_stack.top();
109 state.program_counter = &shader_memory[state.call_stack.top().return_address]; 112 if (state.program_counter - shader_memory.data() == top.final_address) {
110 state.call_stack.pop(); 113 state.address_registers[2] += top.loop_increment;
114
115 if (top.repeat_counter-- == 0) {
116 state.program_counter = &shader_memory[top.return_address];
117 state.call_stack.pop();
118 }
111 119
112 // TODO: Is "trying again" accurate to hardware? 120 // TODO: Is "trying again" accurate to hardware?
113 continue; 121 continue;
@@ -118,9 +126,10 @@ static void ProcessShaderCode(VertexShaderState& state) {
118 const Instruction& instr = *(const Instruction*)state.program_counter; 126 const Instruction& instr = *(const Instruction*)state.program_counter;
119 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id]; 127 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id];
120 128
121 auto call = [&](VertexShaderState& state, u32 offset, u32 num_instructions, u32 return_offset) { 129 static auto call = [](VertexShaderState& state, u32 offset, u32 num_instructions,
130 u32 return_offset, u8 repeat_count, u8 loop_increment) {
122 state.program_counter = &shader_memory[offset] - 1; // -1 to make sure when incrementing the PC we end up at the correct offset 131 state.program_counter = &shader_memory[offset] - 1; // -1 to make sure when incrementing the PC we end up at the correct offset
123 state.call_stack.push({ offset + num_instructions, return_offset }); 132 state.call_stack.push({ offset + num_instructions, return_offset, repeat_count, loop_increment });
124 }; 133 };
125 u32 binary_offset = state.program_counter - shader_memory.data(); 134 u32 binary_offset = state.program_counter - shader_memory.data();
126 135
@@ -457,7 +466,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
457 call(state, 466 call(state,
458 instr.flow_control.dest_offset, 467 instr.flow_control.dest_offset,
459 instr.flow_control.num_instructions, 468 instr.flow_control.num_instructions,
460 binary_offset + 1); 469 binary_offset + 1, 0, 0);
461 break; 470 break;
462 471
463 case Instruction::OpCode::CALLU: 472 case Instruction::OpCode::CALLU:
@@ -465,7 +474,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
465 call(state, 474 call(state,
466 instr.flow_control.dest_offset, 475 instr.flow_control.dest_offset,
467 instr.flow_control.num_instructions, 476 instr.flow_control.num_instructions,
468 binary_offset + 1); 477 binary_offset + 1, 0, 0);
469 } 478 }
470 break; 479 break;
471 480
@@ -474,7 +483,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
474 call(state, 483 call(state,
475 instr.flow_control.dest_offset, 484 instr.flow_control.dest_offset,
476 instr.flow_control.num_instructions, 485 instr.flow_control.num_instructions,
477 binary_offset + 1); 486 binary_offset + 1, 0, 0);
478 } 487 }
479 break; 488 break;
480 489
@@ -486,12 +495,12 @@ static void ProcessShaderCode(VertexShaderState& state) {
486 call(state, 495 call(state,
487 binary_offset + 1, 496 binary_offset + 1,
488 instr.flow_control.dest_offset - binary_offset - 1, 497 instr.flow_control.dest_offset - binary_offset - 1,
489 instr.flow_control.dest_offset + instr.flow_control.num_instructions); 498 instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0);
490 } else { 499 } else {
491 call(state, 500 call(state,
492 instr.flow_control.dest_offset, 501 instr.flow_control.dest_offset,
493 instr.flow_control.num_instructions, 502 instr.flow_control.num_instructions,
494 instr.flow_control.dest_offset + instr.flow_control.num_instructions); 503 instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0);
495 } 504 }
496 505
497 break; 506 break;
@@ -504,17 +513,30 @@ static void ProcessShaderCode(VertexShaderState& state) {
504 call(state, 513 call(state,
505 binary_offset + 1, 514 binary_offset + 1,
506 instr.flow_control.dest_offset - binary_offset - 1, 515 instr.flow_control.dest_offset - binary_offset - 1,
507 instr.flow_control.dest_offset + instr.flow_control.num_instructions); 516 instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0);
508 } else { 517 } else {
509 call(state, 518 call(state,
510 instr.flow_control.dest_offset, 519 instr.flow_control.dest_offset,
511 instr.flow_control.num_instructions, 520 instr.flow_control.num_instructions,
512 instr.flow_control.dest_offset + instr.flow_control.num_instructions); 521 instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0);
513 } 522 }
514 523
515 break; 524 break;
516 } 525 }
517 526
527 case Instruction::OpCode::LOOP:
528 {
529 state.address_registers[2] = shader_uniforms.i[instr.flow_control.int_uniform_id].y;
530
531 call(state,
532 binary_offset + 1,
533 instr.flow_control.dest_offset - binary_offset + 1,
534 instr.flow_control.dest_offset + 1,
535 shader_uniforms.i[instr.flow_control.int_uniform_id].x,
536 shader_uniforms.i[instr.flow_control.int_uniform_id].z);
537 break;
538 }
539
518 default: 540 default:
519 LOG_ERROR(HW_GPU, "Unhandled instruction: 0x%02x (%s): 0x%08x", 541 LOG_ERROR(HW_GPU, "Unhandled instruction: 0x%02x (%s): 0x%08x",
520 (int)instr.opcode.Value(), instr.opcode.GetInfo().name, instr.hex); 542 (int)instr.opcode.Value(), instr.opcode.GetInfo().name, instr.hex);