diff options
| author | 2014-12-21 03:01:35 +0100 | |
|---|---|---|
| committer | 2015-02-18 14:02:59 +0100 | |
| commit | 70a764d992937b2919c6262c70c85117fe22d7d9 (patch) | |
| tree | c563b2532e2335c7dbac08394abb616b77bc6b42 /src | |
| parent | Pica/CommandProcessor: Properly implement shader load destination offset regi... (diff) | |
| download | yuzu-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.cpp | 50 |
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); |