// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "shader_recompiler/backend/spirv/emit_spirv_instructions.h" #include "shader_recompiler/backend/spirv/spirv_emit_context.h" #include "shader_recompiler/ir/debug_print.h" namespace Shader::Backend::SPIRV { void EmitPrologue(EmitContext& ctx) { if (ctx.stage == Stage::Fragment) { ctx.DefineInterpolatedAttribs(); } if (ctx.info.loads.Get(IR::Attribute::WorkgroupIndex)) { ctx.DefineWorkgroupIndex(); } ctx.DefineBufferOffsets(); } void ConvertDepthMode(EmitContext& ctx) { const Id type{ctx.F32[1]}; const Id position{ctx.OpLoad(ctx.F32[4], ctx.output_position)}; const Id z{ctx.OpCompositeExtract(type, position, 2u)}; const Id w{ctx.OpCompositeExtract(type, position, 3u)}; const Id screen_depth{ctx.OpFMul(type, ctx.OpFAdd(type, z, w), ctx.Constant(type, 0.5f))}; const Id vector{ctx.OpCompositeInsert(ctx.F32[4], screen_depth, position, 2u)}; ctx.OpStore(ctx.output_position, vector); } void ConvertPositionToClipSpace(EmitContext& ctx) { const Id type{ctx.F32[1]}; Id position{ctx.OpLoad(ctx.F32[4], ctx.output_position)}; const Id x{ctx.OpCompositeExtract(type, position, 0u)}; const Id y{ctx.OpCompositeExtract(type, position, 1u)}; const Id z{ctx.OpCompositeExtract(type, position, 2u)}; const Id w{ctx.OpCompositeExtract(type, position, 3u)}; const Id xoffset_ptr{ctx.OpAccessChain(ctx.TypePointer(spv::StorageClass::PushConstant, type), ctx.push_data_block, ctx.ConstU32(PushData::XOffsetIndex))}; const Id xoffset{ctx.OpLoad(type, xoffset_ptr)}; const Id yoffset_ptr{ctx.OpAccessChain(ctx.TypePointer(spv::StorageClass::PushConstant, type), ctx.push_data_block, ctx.ConstU32(PushData::YOffsetIndex))}; const Id yoffset{ctx.OpLoad(type, yoffset_ptr)}; const Id xscale_ptr{ctx.OpAccessChain(ctx.TypePointer(spv::StorageClass::PushConstant, type), ctx.push_data_block, ctx.ConstU32(PushData::XScaleIndex))}; const Id xscale{ctx.OpLoad(type, xscale_ptr)}; const Id yscale_ptr{ctx.OpAccessChain(ctx.TypePointer(spv::StorageClass::PushConstant, type), ctx.push_data_block, ctx.ConstU32(PushData::YScaleIndex))}; const Id yscale{ctx.OpLoad(type, yscale_ptr)}; const Id vport_w = ctx.Constant(type, float(std::min(ctx.profile.max_viewport_width / 2, 8_KB))); const Id wnd_x = ctx.OpFAdd(type, ctx.OpFMul(type, x, xscale), xoffset); const Id ndc_x = ctx.OpFSub(type, ctx.OpFDiv(type, wnd_x, vport_w), ctx.Constant(type, 1.f)); const Id vport_h = ctx.Constant(type, float(std::min(ctx.profile.max_viewport_height / 2, 8_KB))); const Id wnd_y = ctx.OpFAdd(type, ctx.OpFMul(type, y, yscale), yoffset); const Id ndc_y = ctx.OpFSub(type, ctx.OpFDiv(type, wnd_y, vport_h), ctx.Constant(type, 1.f)); const Id vector{ctx.OpCompositeConstruct(ctx.F32[4], std::array({ndc_x, ndc_y, z, w}))}; ctx.OpStore(ctx.output_position, vector); } void EmitEpilogue(EmitContext& ctx) { if (ctx.stage == Stage::Vertex && ctx.runtime_info.vs_info.emulate_depth_negative_one_to_one) { ConvertDepthMode(ctx); } if (ctx.stage == Stage::Vertex && ctx.runtime_info.vs_info.clip_disable) { ConvertPositionToClipSpace(ctx); } } void EmitDiscard(EmitContext& ctx) { ctx.OpDemoteToHelperInvocationEXT(); } void EmitDiscardCond(EmitContext& ctx, Id condition) { const Id kill_label{ctx.OpLabel()}; const Id merge_label{ctx.OpLabel()}; ctx.OpSelectionMerge(merge_label, spv::SelectionControlMask::MaskNone); ctx.OpBranchConditional(condition, kill_label, merge_label); ctx.AddLabel(kill_label); ctx.OpDemoteToHelperInvocationEXT(); ctx.OpBranch(merge_label); ctx.AddLabel(merge_label); } void EmitEmitVertex(EmitContext& ctx) { ctx.OpEmitVertex(); } void EmitEmitPrimitive(EmitContext& ctx) { ctx.OpEndPrimitive(); } void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) { throw NotImplementedException("Geometry streams"); } void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) { throw NotImplementedException("Geometry streams"); } void EmitDebugPrint(EmitContext& ctx, IR::Inst* inst, Id fmt, Id arg0, Id arg1, Id arg2, Id arg3) { IR::DebugPrintFlags flags = inst->Flags(); std::array fmt_args = {arg0, arg1, arg2, arg3}; auto fmt_args_span = std::span(fmt_args.begin(), fmt_args.begin() + flags.num_args); ctx.OpDebugPrintf(fmt, fmt_args_span); } } // namespace Shader::Backend::SPIRV