bool GLDriver::compilePixelShader(PixelShader &pixel, uint8_t *buffer, size_t size) { auto sq_config = getRegister<latte::SQ_CONFIG>(latte::Register::SQ_CONFIG); auto spi_ps_in_control_0 = getRegister<latte::SPI_PS_IN_CONTROL_0>(latte::Register::SPI_PS_IN_CONTROL_0); auto spi_ps_in_control_1 = getRegister<latte::SPI_PS_IN_CONTROL_1>(latte::Register::SPI_PS_IN_CONTROL_1); auto cb_shader_mask = getRegister<latte::CB_SHADER_MASK>(latte::Register::CB_SHADER_MASK); fmt::MemoryWriter out; latte::Shader shader; std::string body; shader.type = latte::Shader::Pixel; if (!latte::decode(shader, gsl::as_span(buffer, size))) { gLog->error("Failed to decode pixel shader"); return false; } latte::disassemble(shader, pixel.disassembly); if (!latte::blockify(shader)) { gLog->error("Failed to blockify pixel shader"); return false; } if (!glsl::generateBody(shader, body)) { gLog->warn("Failed to translate 100% of instructions for pixel shader"); } // Get pixel sampler types for (auto i = 0; i < MAX_SAMPLERS_PER_TYPE; ++i) { auto sq_tex_resource_word0 = getRegister<latte::SQ_TEX_RESOURCE_WORD0_N>(latte::Register::SQ_TEX_RESOURCE_WORD0_0 + 4 * (latte::SQ_PS_TEX_RESOURCE_0 + i * 7)); auto sq_tex_resource_word4 = getRegister<latte::SQ_TEX_RESOURCE_WORD4_N>(latte::Register::SQ_TEX_RESOURCE_WORD4_0 + 4 * (latte::SQ_PS_TEX_RESOURCE_0 + i * 7)); pixel.samplerTypes[i] = getSamplerType(sq_tex_resource_word0.DIM, sq_tex_resource_word4.NUM_FORMAT_ALL, sq_tex_resource_word4.FORMAT_COMP_X); } // Write header writeHeader(out); // Uniforms writeUniforms(out, shader, sq_config, pixel.samplerTypes); out << '\n'; // Pixel Shader Inputs for (auto i = 0u; i < spi_ps_in_control_0.NUM_INTERP; ++i) { auto spi_ps_input_cntl = getRegister<latte::SPI_PS_INPUT_CNTL_0>(latte::Register::SPI_PS_INPUT_CNTL_0 + i * 4); if (spi_ps_input_cntl.FLAT_SHADE) { out << "flat "; } out << "in vec4 vs_out_" << spi_ps_input_cntl.SEMANTIC << ";\n"; } out << '\n'; // Pixel Shader Exports auto maskBits = cb_shader_mask.value; for (auto i = 0; i < 8; ++i) { if (maskBits & 0xf) { out << "out vec4 ps_out_" << i << ";\n"; } maskBits >>= 4; } out << '\n'; // Program code out << "void main()\n" << "{\n"; writeLocals(out, shader); writeExports(out, shader); // Assign vertex shader output to our GPR for (auto i = 0u; i < spi_ps_in_control_0.NUM_INTERP; ++i) { auto spi_ps_input_cntl = getRegister<latte::SPI_PS_INPUT_CNTL_0>(latte::Register::SPI_PS_INPUT_CNTL_0 + i * 4); auto id = spi_ps_input_cntl.SEMANTIC; if (id == 0xff) { continue; } out << "R[" << i << "] = vs_out_" << id << ";\n"; } out << '\n' << body << '\n'; for (auto exp : shader.exports) { switch (exp->exportType) { case latte::SQ_EXPORT_PIXEL: { auto mask = cb_shader_mask.value >> (4 * exp->arrayBase); if (!mask) { gLog->warn("Export is masked by cb_shader_mask"); } else { out << "ps_out_" << exp->arrayBase << " = exp_pixel_" << exp->arrayBase << '.'; if (mask & (1 << 0)) { out << 'x'; } if (mask & (1 << 1)) { out << 'y'; } if (mask & (1 << 2)) { out << 'z'; } if (mask & (1 << 3)) { out << 'w'; } out << ";\n"; } } break; case latte::SQ_EXPORT_POS: throw std::logic_error("Unexpected position export in pixel shader."); break; case latte::SQ_EXPORT_PARAM: throw std::logic_error("Unexpected parameter export in pixel shader."); break; } } out << "}\n"; pixel.code = out.str(); return true; }
std::string TransFunc::getShaderDefines() const { return "#define TF_SAMPLER_TYPE " + getSamplerType() + "\n"; }
bool GLDriver::compileVertexShader(VertexShader &vertex, FetchShader &fetch, uint8_t *buffer, size_t size) { auto sq_config = getRegister<latte::SQ_CONFIG>(latte::Register::SQ_CONFIG); auto spi_vs_out_config = getRegister<latte::SPI_VS_OUT_CONFIG>(latte::Register::SPI_VS_OUT_CONFIG); fmt::MemoryWriter out; latte::Shader shader; std::string body; FetchShader::Attrib *semanticAttribs[32]; memset(semanticAttribs, 0, sizeof(FetchShader::Attrib *) * 32); shader.type = latte::Shader::Vertex; if (!latte::decode(shader, gsl::as_span(buffer, size))) { gLog->error("Failed to decode vertex shader"); return false; } latte::disassemble(shader, vertex.disassembly); if (!latte::blockify(shader)) { gLog->error("Failed to blockify vertex shader"); return false; } if (!glsl::generateBody(shader, body)) { gLog->warn("Failed to translate 100% of instructions for vertex shader"); } // Get vertex sampler types for (auto i = 0; i < MAX_SAMPLERS_PER_TYPE; ++i) { auto sq_tex_resource_word0 = getRegister<latte::SQ_TEX_RESOURCE_WORD0_N>(latte::Register::SQ_TEX_RESOURCE_WORD0_0 + 4 * (latte::SQ_PS_TEX_RESOURCE_0 + i * 7)); auto sq_tex_resource_word4 = getRegister<latte::SQ_TEX_RESOURCE_WORD4_N>(latte::Register::SQ_TEX_RESOURCE_WORD4_0 + 4 * (latte::SQ_PS_TEX_RESOURCE_0 + i * 7)); vertex.samplerTypes[i] = getSamplerType(sq_tex_resource_word0.DIM, sq_tex_resource_word4.NUM_FORMAT_ALL, sq_tex_resource_word4.FORMAT_COMP_X); } // Write header writeHeader(out); // Uniforms writeUniforms(out, shader, sq_config, vertex.samplerTypes); out << '\n'; // Vertex Shader Inputs for (auto &attrib : fetch.attribs) { semanticAttribs[attrib.location] = &attrib; out << "in " << getGLSLDataFormat(attrib.format, attrib.numFormat, attrib.formatComp) << " fs_out_" << attrib.location << ";\n"; } out << '\n'; // Vertex Shader Exports for (auto i = 0u; i <= spi_vs_out_config.VS_EXPORT_COUNT; i++) { out << "out vec4 vs_out_" << i << ";\n"; } out << '\n'; // Program code out << "void main()\n" << "{\n"; writeLocals(out, shader); writeExports(out, shader); // Initialise registers if (shader.gprsUsed.find(0) != shader.gprsUsed.end()) { // TODO: Check which order of VertexID and InstanceID for r0.x, r0.y out << "R[0] = vec4(intBitsToFloat(gl_VertexID), intBitsToFloat(gl_InstanceID), 0.0, 0.0);\n"; } // Assign fetch shader output to our GPR for (auto i = 0u; i < 32; ++i) { auto sq_vtx_semantic = getRegister<latte::SQ_VTX_SEMANTIC_N>(latte::Register::SQ_VTX_SEMANTIC_0 + i * 4); auto id = sq_vtx_semantic.SEMANTIC_ID; if (sq_vtx_semantic.SEMANTIC_ID == 0xff) { continue; } auto attrib = semanticAttribs[id]; if (!attrib) { gLog->error("Invalid semantic mapping: {}", id); continue; } out << "R[" << (i + 1) << "] = "; auto channels = getDataFormatChannels(attrib->format); switch (channels) { case 1: out << "vec4(fs_out_" << attrib->location << ", 0.0, 0.0, 0.0);\n"; break; case 2: out << "vec4(fs_out_" << attrib->location << ", 0.0, 0.0);\n"; break; case 3: out << "vec4(fs_out_" << attrib->location << ", 0.0);\n"; break; case 4: out << "fs_out_" << attrib->location << ";\n"; break; } } out << '\n' << body << '\n'; for (auto exp : shader.exports) { switch (exp->exportType) { case latte::SQ_EXPORT_POS: out << "gl_Position = exp_position_" << (exp->arrayBase - 60) << ";\n"; break; case latte::SQ_EXPORT_PARAM: // TODO: Use vs_out semantics? out << "vs_out_" << exp->arrayBase << " = exp_param_" << exp->arrayBase << ";\n"; break; case latte::SQ_EXPORT_PIXEL: throw std::logic_error("Unexpected pixel export in vertex shader."); break; } } out << "}\n"; vertex.code = out.str(); return true; }