diff options
Diffstat (limited to 'src/video_core')
-rw-r--r-- | src/video_core/engines/shader_bytecode.h | 8 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 85 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 2 |
3 files changed, 81 insertions, 14 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 3ba6fe614..875b90359 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h @@ -477,7 +477,9 @@ union Instruction { if (texture_info >= 12 && texture_info <= 13) return TextureType::TextureCube; - UNIMPLEMENTED(); + LOG_CRITICAL(HW_GPU, "Unhandled texture_info: {}", + static_cast<u32>(texture_info.Value())); + UNREACHABLE(); } bool IsArrayTexture() const { @@ -523,7 +525,9 @@ union Instruction { return TextureType::Texture3D; } - UNIMPLEMENTED(); + LOG_CRITICAL(HW_GPU, "Unhandled texture_info: {}", + static_cast<u32>(texture_info.Value())); + UNREACHABLE(); } bool IsArrayTexture() const { diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index ac6ccfec7..6fb663bbc 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -26,6 +26,7 @@ using Tegra::Shader::Sampler; using Tegra::Shader::SubOp; constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH; +constexpr u32 PROGRAM_HEADER_SIZE = 0x50; class DecompileFail : public std::runtime_error { public: @@ -621,6 +622,23 @@ public: } private: + // Shader program header for a Fragment Shader. + struct FragmentHeader { + INSERT_PADDING_WORDS(5); + INSERT_PADDING_WORDS(13); + u32 enabled_color_outputs; + union { + BitField<0, 1, u32> writes_samplemask; + BitField<1, 1, u32> writes_depth; + }; + + bool IsColorComponentOutputEnabled(u32 render_target, u32 component) const { + u32 bit = render_target * 4 + component; + return enabled_color_outputs & (1 << bit); + } + }; + static_assert(sizeof(FragmentHeader) == PROGRAM_HEADER_SIZE, "FragmentHeader size is wrong"); + /// Gets the Subroutine object corresponding to the specified address. const Subroutine& GetSubroutine(u32 begin, u32 end) const { auto iter = subroutines.find(Subroutine{begin, end, suffix}); @@ -894,6 +912,31 @@ private: shader.AddLine('}'); } + /// Writes the output values from a fragment shader to the corresponding GLSL output variables. + void EmitFragmentOutputsWrite() { + ASSERT(stage == Maxwell3D::Regs::ShaderStage::Fragment); + FragmentHeader header; + std::memcpy(&header, program_code.data(), PROGRAM_HEADER_SIZE); + + ASSERT_MSG(header.writes_depth == 0, "Depth write is unimplemented"); + ASSERT_MSG(header.writes_samplemask == 0, "Samplemask write is unimplemented"); + + // Write the color outputs using the data in the shader registers, disabled + // rendertargets/components are skipped in the register assignment. + u32 current_reg = 0; + for (u32 render_target = 0; render_target < Maxwell3D::Regs::NumRenderTargets; + ++render_target) { + // TODO(Subv): Figure out how dual-source blending is configured in the Switch. + for (u32 component = 0; component < 4; ++component) { + if (header.IsColorComponentOutputEnabled(render_target, component)) { + shader.AddLine(fmt::format("color[{}][{}] = {};", render_target, component, + regs.GetRegisterAsFloat(current_reg))); + ++current_reg; + } + } + } + } + /** * Compiles a single instruction from Tegra to GLSL. * @param offset the offset of the Tegra shader instruction. @@ -1514,7 +1557,7 @@ private: switch (instr.tex.texture_type) { case Tegra::Shader::TextureType::Texture2D: { std::string x = regs.GetRegisterAsFloat(instr.gpr8); - std::string y = regs.GetRegisterAsFloat(instr.gpr20); + std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); coord = "vec2 coords = vec2(" + x + ", " + y + ");"; break; } @@ -1525,8 +1568,18 @@ private: coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; break; } + case Tegra::Shader::TextureType::TextureCube: { + std::string x = regs.GetRegisterAsFloat(instr.gpr8); + std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2); + ASSERT(instr.gpr20.Value() == Register::ZeroIndex); + coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; + break; + } default: - UNIMPLEMENTED(); + LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", + static_cast<u32>(instr.tex.texture_type.Value())); + UNREACHABLE(); } const std::string sampler = @@ -1568,6 +1621,13 @@ private: } break; } + case Tegra::Shader::TextureType::Texture3D: { + std::string x = regs.GetRegisterAsFloat(instr.gpr8); + std::string y = regs.GetRegisterAsFloat(instr.gpr20); + std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); + coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; + break; + } case Tegra::Shader::TextureType::TextureCube: { std::string x = regs.GetRegisterAsFloat(instr.gpr8); std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); @@ -1576,7 +1636,9 @@ private: break; } default: - UNIMPLEMENTED(); + LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", + static_cast<u32>(instr.texs.GetTextureType())); + UNREACHABLE(); } const std::string sampler = GetSampler(instr.sampler, instr.texs.GetTextureType(), instr.texs.IsArrayTexture()); @@ -1593,7 +1655,8 @@ private: switch (instr.tlds.GetTextureType()) { case Tegra::Shader::TextureType::Texture2D: { if (instr.tlds.IsArrayTexture()) { - UNIMPLEMENTED(); + LOG_CRITICAL(HW_GPU, "Unhandled 2d array texture"); + UNREACHABLE(); } else { std::string x = regs.GetRegisterAsInteger(instr.gpr8); std::string y = regs.GetRegisterAsInteger(instr.gpr20); @@ -1602,7 +1665,9 @@ private: break; } default: - UNIMPLEMENTED(); + LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", + static_cast<u32>(instr.tlds.GetTextureType())); + UNREACHABLE(); } const std::string sampler = GetSampler(instr.sampler, instr.tlds.GetTextureType(), instr.tlds.IsArrayTexture()); @@ -1623,7 +1688,9 @@ private: break; } default: - UNIMPLEMENTED(); + LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", + static_cast<u32>(instr.tld4.texture_type.Value())); + UNREACHABLE(); } const std::string sampler = @@ -1960,12 +2027,8 @@ private: default: { switch (opcode->GetId()) { case OpCode::Id::EXIT: { - // Final color output is currently hardcoded to GPR0-3 for fragment shaders if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { - shader.AddLine("color.r = " + regs.GetRegisterAsFloat(0) + ';'); - shader.AddLine("color.g = " + regs.GetRegisterAsFloat(1) + ';'); - shader.AddLine("color.b = " + regs.GetRegisterAsFloat(2) + ';'); - shader.AddLine("color.a = " + regs.GetRegisterAsFloat(3) + ';'); + EmitFragmentOutputsWrite(); } switch (instr.flow.cond) { diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 57e0e1726..01c7b9720 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -87,7 +87,7 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSCo .get_value_or({}); out += R"( in vec4 position; -out vec4 color; +layout(location = 0) out vec4 color[8]; layout (std140) uniform fs_config { vec4 viewport_flip; |