@ -26,6 +26,7 @@ using Tegra::Shader::Sampler;
using Tegra : : Shader : : SubOp ;
using Tegra : : Shader : : SubOp ;
constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH ;
constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH ;
constexpr u32 PROGRAM_HEADER_SIZE = 0x50 ;
class DecompileFail : public std : : runtime_error {
class DecompileFail : public std : : runtime_error {
public :
public :
@ -616,6 +617,23 @@ public:
}
}
private :
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.
/// Gets the Subroutine object corresponding to the specified address.
const Subroutine & GetSubroutine ( u32 begin , u32 end ) const {
const Subroutine & GetSubroutine ( u32 begin , u32 end ) const {
auto iter = subroutines . find ( Subroutine { begin , end , suffix } ) ;
auto iter = subroutines . find ( Subroutine { begin , end , suffix } ) ;
@ -815,6 +833,31 @@ private:
shader . AddLine ( ' } ' ) ;
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 .
* Compiles a single instruction from Tegra to GLSL .
* @ param offset the offset of the Tegra shader instruction .
* @ param offset the offset of the Tegra shader instruction .
@ -1779,12 +1822,8 @@ private:
default : {
default : {
switch ( opcode - > GetId ( ) ) {
switch ( opcode - > GetId ( ) ) {
case OpCode : : Id : : EXIT : {
case OpCode : : Id : : EXIT : {
// Final color output is currently hardcoded to GPR0-3 for fragment shaders
if ( stage = = Maxwell3D : : Regs : : ShaderStage : : Fragment ) {
if ( stage = = Maxwell3D : : Regs : : ShaderStage : : Fragment ) {
shader . AddLine ( " color.r = " + regs . GetRegisterAsFloat ( 0 ) + ' ; ' ) ;
EmitFragmentOutputsWrite ( ) ;
shader . AddLine ( " color.g = " + regs . GetRegisterAsFloat ( 1 ) + ' ; ' ) ;
shader . AddLine ( " color.b = " + regs . GetRegisterAsFloat ( 2 ) + ' ; ' ) ;
shader . AddLine ( " color.a = " + regs . GetRegisterAsFloat ( 3 ) + ' ; ' ) ;
}
}
switch ( instr . flow . cond ) {
switch ( instr . flow . cond ) {