diff --git a/src/xenia/gpu/spirv_shader_translator.cc b/src/xenia/gpu/spirv_shader_translator.cc index f46d76bbd..f6f2ba229 100644 --- a/src/xenia/gpu/spirv_shader_translator.cc +++ b/src/xenia/gpu/spirv_shader_translator.cc @@ -47,21 +47,10 @@ void SpirvShaderTranslator::StartTranslation() { b.addCapability(spv::Capability::CapabilityDerivativeControl); } - // main() entry point. - auto mainFn = b.makeMain(); - if (is_vertex_shader()) { - b.addEntryPoint(spv::ExecutionModel::ExecutionModelVertex, mainFn, "main"); - } else { - b.addEntryPoint(spv::ExecutionModel::ExecutionModelFragment, mainFn, - "main"); - b.addExecutionMode(mainFn, spv::ExecutionModeOriginUpperLeft); - } - - // TODO(benvanik): transform feedback. - if (false) { - b.addCapability(spv::Capability::CapabilityTransformFeedback); - b.addExecutionMode(mainFn, spv::ExecutionMode::ExecutionModeXfb); - } + spv::Block* function_block = nullptr; + translated_main_ = b.makeFunctionEntry(spv::Decoration::DecorationInvariant, + b.makeVoidType(), "translated_main", + {}, {}, &function_block); bool_type_ = b.makeBoolType(); float_type_ = b.makeFloatType(32); @@ -144,6 +133,27 @@ void SpirvShaderTranslator::StartTranslation() { b.addDecoration(consts_, spv::Decoration::DecorationBinding, 1); } + // Push constants. + Id push_constants_type = + b.makeStructType({vec4_float_type_, vec4_float_type_, vec4_float_type_}, + "push_consts_type"); + + b.addMemberDecoration(push_constants_type, 0, + spv::Decoration::DecorationOffset, 0); + b.addMemberName(push_constants_type, 0, "window_scale"); + + b.addMemberDecoration(push_constants_type, 1, + spv::Decoration::DecorationOffset, 4 * sizeof(float)); + b.addMemberName(push_constants_type, 1, "vtx_fmt"); + + b.addMemberDecoration(push_constants_type, 2, + spv::Decoration::DecorationOffset, + 2 * 4 * sizeof(float)); + b.addMemberName(push_constants_type, 2, "alpha_test"); + + push_consts_ = b.createVariable(spv::StorageClass::StorageClassPushConstant, + push_constants_type, "push_consts"); + // Interpolators. Id interpolators_type = b.makeArrayType(vec4_float_type_, b.makeUintConstant(16), 0); @@ -231,6 +241,55 @@ std::vector SpirvShaderTranslator::CompleteTranslation() { b.makeReturn(false); + // main() entry point. + auto mainFn = b.makeMain(); + if (is_vertex_shader()) { + b.addEntryPoint(spv::ExecutionModel::ExecutionModelVertex, mainFn, "main"); + } else { + b.addEntryPoint(spv::ExecutionModel::ExecutionModelFragment, mainFn, + "main"); + b.addExecutionMode(mainFn, spv::ExecutionModeOriginUpperLeft); + } + + // TODO(benvanik): transform feedback. + if (false) { + b.addCapability(spv::Capability::CapabilityTransformFeedback); + b.addExecutionMode(mainFn, spv::ExecutionMode::ExecutionModeXfb); + } + + b.createFunctionCall(translated_main_, std::vector({})); + if (is_vertex_shader()) { + // gl_Position transform + auto vtx_fmt_ptr = b.createAccessChain( + spv::StorageClass::StorageClassPushConstant, push_consts_, + std::vector({b.makeUintConstant(1)})); + auto vtx_fmt = b.createLoad(vtx_fmt_ptr); + + auto p = b.createLoad(pos_); + auto c = b.createBinOp(spv::Op::OpFOrdNotEqual, vec4_bool_type_, vtx_fmt, + b.makeFloatConstant(0.f)); + + // pos.w = vtx_fmt.w != 0.0 ? 1.0 / pos.w : pos.w + auto c_w = b.createCompositeExtract(c, bool_type_, 3); + auto p_w = b.createCompositeExtract(p, float_type_, 3); + auto p_w_inv = b.createBinOp(spv::Op::OpFDiv, float_type_, + b.makeFloatConstant(1.f), p_w); + p_w = b.createTriOp(spv::Op::OpSelect, float_type_, c_w, p_w_inv, p_w); + + // pos.xyz = vtx_fmt.xyz != 0.0 ? pos.xyz / pos.w : pos.xyz + auto p_all_w = b.smearScalar(spv::Decoration::DecorationInvariant, p_w, + vec4_float_type_); + auto p_inv = b.createBinOp(spv::Op::OpFDiv, vec4_float_type_, p, p_all_w); + p = b.createTriOp(spv::Op::OpSelect, vec4_float_type_, c, p_inv, p); + + // Reinsert w + p = b.createCompositeInsert(p_w, p, vec4_float_type_, 3); + + b.createStore(p, pos_); + } + + b.makeReturn(false); + std::vector spirv_words; b.dump(spirv_words); @@ -526,6 +585,30 @@ void SpirvShaderTranslator::ProcessVectorAluInstruction( sources[1]); } break; + case AluVectorOpcode::kCndEq: { + // dest = src0 == 0.0 ? src1 : src2; + auto c = b.createBinOp(spv::Op::OpFOrdEqual, vec4_bool_type_, sources[0], + b.makeFloatConstant(0.f)); + dest = b.createTriOp(spv::Op::OpSelect, vec4_float_type_, c, sources[1], + sources[2]); + } break; + + case AluVectorOpcode::kCndGe: { + // dest = src0 == 0.0 ? src1 : src2; + auto c = b.createBinOp(spv::Op::OpFOrdGreaterThanEqual, vec4_bool_type_, + sources[0], b.makeFloatConstant(0.f)); + dest = b.createTriOp(spv::Op::OpSelect, vec4_float_type_, c, sources[1], + sources[2]); + } break; + + case AluVectorOpcode::kCndGt: { + // dest = src0 == 0.0 ? src1 : src2; + auto c = b.createBinOp(spv::Op::OpFOrdGreaterThan, vec4_bool_type_, + sources[0], b.makeFloatConstant(0.f)); + dest = b.createTriOp(spv::Op::OpSelect, vec4_float_type_, c, sources[1], + sources[2]); + } break; + case AluVectorOpcode::kCube: { // TODO: } break; @@ -1130,7 +1213,6 @@ void SpirvShaderTranslator::StoreToResult(Id source_value_id, } // swizzle - // TODO: 0.0 and 1.0 swizzles if (!result.is_standard_swizzle()) { std::vector operands; operands.push_back(source_value_id); diff --git a/src/xenia/gpu/spirv_shader_translator.h b/src/xenia/gpu/spirv_shader_translator.h index aabd6fec1..8138bbdc9 100644 --- a/src/xenia/gpu/spirv_shader_translator.h +++ b/src/xenia/gpu/spirv_shader_translator.h @@ -78,6 +78,9 @@ class SpirvShaderTranslator : public ShaderTranslator { std::unique_ptr builder_; spv::Id glsl_std_450_instruction_set_ = 0; + // Generated function + spv::Function* translated_main_ = 0; + // Types. spv::Id float_type_ = 0, bool_type_ = 0; spv::Id vec2_float_type_ = 0, vec3_float_type_ = 0, vec4_float_type_ = 0; @@ -93,6 +96,7 @@ class SpirvShaderTranslator : public ShaderTranslator { spv::Id consts_ = 0, a0_ = 0, aL_ = 0, p0_ = 0; spv::Id ps_ = 0, pv_ = 0; // IDs of previous results spv::Id pos_ = 0; + spv::Id push_consts_ = 0; spv::Id interpolators_ = 0; spv::Id frag_outputs_ = 0;