mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-08 20:58:41 +00:00
shader_recompiler: Support PointSize and ViewportIndex attributes. (#3541)
This commit is contained in:
@@ -272,9 +272,6 @@ void SetupCapabilities(const Info& info, const Profile& profile, const RuntimeIn
|
||||
if (info.has_image_query) {
|
||||
ctx.AddCapability(spv::Capability::ImageQuery);
|
||||
}
|
||||
if (info.has_layer_output) {
|
||||
ctx.AddCapability(spv::Capability::ShaderLayer);
|
||||
}
|
||||
if ((info.uses_image_atomic_float_min_max && profile.supports_image_fp32_atomic_min_max) ||
|
||||
(info.uses_buffer_atomic_float_min_max && profile.supports_buffer_fp32_atomic_min_max)) {
|
||||
ctx.AddExtension("SPV_EXT_shader_atomic_float_min_max");
|
||||
@@ -312,6 +309,17 @@ void SetupCapabilities(const Info& info, const Profile& profile, const RuntimeIn
|
||||
if (stage == LogicalStage::TessellationControl || stage == LogicalStage::TessellationEval) {
|
||||
ctx.AddCapability(spv::Capability::Tessellation);
|
||||
}
|
||||
if (stage == LogicalStage::Vertex || stage == LogicalStage::TessellationControl ||
|
||||
stage == LogicalStage::TessellationEval) {
|
||||
if (info.has_layer_output) {
|
||||
ctx.AddCapability(spv::Capability::ShaderLayer);
|
||||
}
|
||||
if (info.has_viewport_index_output) {
|
||||
ctx.AddCapability(spv::Capability::ShaderViewportIndex);
|
||||
}
|
||||
} else if (stage == LogicalStage::Geometry && info.has_viewport_index_output) {
|
||||
ctx.AddCapability(spv::Capability::MultiViewport);
|
||||
}
|
||||
if (info.uses_dma) {
|
||||
ctx.AddCapability(spv::Capability::PhysicalStorageBufferAddresses);
|
||||
ctx.AddExtension("SPV_KHR_physical_storage_buffer");
|
||||
|
||||
@@ -49,8 +49,12 @@ Id OutputAttrPointer(EmitContext& ctx, IR::Attribute attr, u32 element) {
|
||||
return ctx.OpAccessChain(ctx.output_f32, ctx.clip_distances, ctx.ConstU32(element));
|
||||
case IR::Attribute::CullDistance:
|
||||
return ctx.OpAccessChain(ctx.output_f32, ctx.cull_distances, ctx.ConstU32(element));
|
||||
case IR::Attribute::RenderTargetId:
|
||||
case IR::Attribute::PointSize:
|
||||
return ctx.output_point_size;
|
||||
case IR::Attribute::RenderTargetIndex:
|
||||
return ctx.output_layer;
|
||||
case IR::Attribute::ViewportIndex:
|
||||
return ctx.output_viewport_index;
|
||||
case IR::Attribute::Depth:
|
||||
return ctx.frag_depth;
|
||||
default:
|
||||
@@ -74,9 +78,10 @@ std::pair<Id, bool> OutputAttrComponentType(EmitContext& ctx, IR::Attribute attr
|
||||
case IR::Attribute::ClipDistance:
|
||||
case IR::Attribute::CullDistance:
|
||||
case IR::Attribute::Depth:
|
||||
case IR::Attribute::PointSize:
|
||||
return {ctx.F32[1], false};
|
||||
case IR::Attribute::RenderTargetId:
|
||||
case IR::Attribute::ViewportId:
|
||||
case IR::Attribute::RenderTargetIndex:
|
||||
case IR::Attribute::ViewportIndex:
|
||||
return {ctx.S32[1], true};
|
||||
default:
|
||||
UNREACHABLE_MSG("Write attribute {}", attr);
|
||||
|
||||
@@ -28,6 +28,9 @@ void ConvertDepthMode(EmitContext& ctx) {
|
||||
}
|
||||
|
||||
void ConvertPositionToClipSpace(EmitContext& ctx) {
|
||||
ASSERT_MSG(!ctx.info.has_viewport_index_output,
|
||||
"Multi-viewport with shader clip space conversion not yet implemented.");
|
||||
|
||||
const Id type{ctx.F32[1]};
|
||||
Id position{ctx.OpLoad(ctx.F32[4], ctx.output_position)};
|
||||
const Id x{ctx.OpCompositeExtract(type, position, 0u)};
|
||||
|
||||
@@ -555,9 +555,17 @@ void EmitContext::DefineVertexBlock() {
|
||||
cull_distances = DefineVariable(type, spv::BuiltIn::CullDistance, spv::StorageClass::Output,
|
||||
initializer);
|
||||
}
|
||||
if (info.stores.GetAny(IR::Attribute::RenderTargetId)) {
|
||||
if (info.stores.GetAny(IR::Attribute::PointSize)) {
|
||||
output_point_size =
|
||||
DefineVariable(F32[1], spv::BuiltIn::PointSize, spv::StorageClass::Output);
|
||||
}
|
||||
if (info.stores.GetAny(IR::Attribute::RenderTargetIndex)) {
|
||||
output_layer = DefineVariable(S32[1], spv::BuiltIn::Layer, spv::StorageClass::Output);
|
||||
}
|
||||
if (info.stores.GetAny(IR::Attribute::ViewportIndex)) {
|
||||
output_viewport_index =
|
||||
DefineVariable(S32[1], spv::BuiltIn::ViewportIndex, spv::StorageClass::Output);
|
||||
}
|
||||
}
|
||||
|
||||
void EmitContext::DefineOutputs() {
|
||||
|
||||
@@ -245,7 +245,9 @@ public:
|
||||
boost::container::small_vector<Id, 16> interfaces;
|
||||
|
||||
Id output_position{};
|
||||
Id output_point_size{};
|
||||
Id output_layer{};
|
||||
Id output_viewport_index{};
|
||||
Id primitive_id{};
|
||||
Id vertex_index{};
|
||||
Id instance_id{};
|
||||
|
||||
@@ -211,6 +211,7 @@ struct Info {
|
||||
bool has_image_gather{};
|
||||
bool has_image_query{};
|
||||
bool has_layer_output{};
|
||||
bool has_viewport_index_output{};
|
||||
bool uses_buffer_atomic_float_min_max{};
|
||||
bool uses_image_atomic_float_min_max{};
|
||||
bool uses_lane_id{};
|
||||
|
||||
@@ -104,10 +104,10 @@ std::string NameOf(Attribute attribute) {
|
||||
return "ClipDistanace";
|
||||
case Attribute::CullDistance:
|
||||
return "CullDistance";
|
||||
case Attribute::RenderTargetId:
|
||||
return "RenderTargetId";
|
||||
case Attribute::ViewportId:
|
||||
return "ViewportId";
|
||||
case Attribute::RenderTargetIndex:
|
||||
return "RenderTargetIndex";
|
||||
case Attribute::ViewportIndex:
|
||||
return "ViewportIndex";
|
||||
case Attribute::VertexId:
|
||||
return "VertexId";
|
||||
case Attribute::PrimitiveId:
|
||||
@@ -158,6 +158,8 @@ std::string NameOf(Attribute attribute) {
|
||||
return "PackedHullInvocationInfo";
|
||||
case Attribute::TessFactorsBufferBase:
|
||||
return "TessFactorsBufferBase";
|
||||
case Attribute::PointSize:
|
||||
return "PointSize";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ enum class Attribute : u64 {
|
||||
// System values
|
||||
ClipDistance = 64,
|
||||
CullDistance = 65,
|
||||
RenderTargetId = 66,
|
||||
ViewportId = 67,
|
||||
RenderTargetIndex = 66,
|
||||
ViewportIndex = 67,
|
||||
VertexId = 68,
|
||||
PrimitiveId = 69,
|
||||
InstanceId = 70,
|
||||
@@ -87,6 +87,7 @@ enum class Attribute : u64 {
|
||||
PackedHullInvocationInfo = 90, // contains patch id within the VGT and invocation ID
|
||||
OffChipLdsBase = 91,
|
||||
TessFactorsBufferBase = 92,
|
||||
PointSize = 93,
|
||||
Max,
|
||||
};
|
||||
|
||||
|
||||
@@ -160,9 +160,12 @@ void CollectShaderInfoPass(IR::Program& program, const Profile& profile) {
|
||||
}
|
||||
}
|
||||
|
||||
if (info.stores.GetAny(IR::Attribute::RenderTargetId)) {
|
||||
if (info.stores.GetAny(IR::Attribute::RenderTargetIndex)) {
|
||||
info.has_layer_output = true;
|
||||
}
|
||||
if (info.stores.GetAny(IR::Attribute::ViewportIndex)) {
|
||||
info.has_viewport_index_output = true;
|
||||
}
|
||||
|
||||
// In case Flatbuf has not already been bound by IR and is needed
|
||||
// to query buffer sizes, bind it now.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
#include "common/logging/log.h"
|
||||
#include "shader_recompiler/ir/ir_emitter.h"
|
||||
#include "shader_recompiler/runtime_info.h"
|
||||
@@ -17,8 +18,26 @@ inline void ExportPosition(IREmitter& ir, const StageRuntimeInfo& stage, Attribu
|
||||
ir.SetAttribute(attribute, value, comp);
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 index = u32(attribute) - u32(Attribute::Position1);
|
||||
const auto output = stage.outputs[index][comp];
|
||||
if constexpr (std::is_same_v<StageRuntimeInfo, VertexRuntimeInfo>) {
|
||||
// Certain outputs are supposed to be set by the last pre-rasterization stage. We don't
|
||||
// currently have a mechanism for passing these on when emulating rect/quad lists using
|
||||
// tessellation, which comes after, so just ignore the export for now. Note that this
|
||||
// only matters for vertex shaders, as geometry shaders come last in pre-rasterization.
|
||||
const auto last_stage_required = output == Output::PointSize ||
|
||||
output == Output::RenderTargetIndex ||
|
||||
output == Output::ViewportIndex;
|
||||
if (stage.tess_emulated_primitive && last_stage_required) {
|
||||
LOG_WARNING(Render,
|
||||
"{} is exported in vertex shader but tessellation-based primitive "
|
||||
"emulation is active. Not implemented yet.",
|
||||
magic_enum::enum_name(output));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (output) {
|
||||
case Output::ClipDist0:
|
||||
case Output::ClipDist1:
|
||||
@@ -44,20 +63,14 @@ inline void ExportPosition(IREmitter& ir, const StageRuntimeInfo& stage, Attribu
|
||||
ir.SetAttribute(IR::Attribute::CullDistance, value, index);
|
||||
break;
|
||||
}
|
||||
case Output::GsMrtIndex:
|
||||
if constexpr (std::is_same_v<StageRuntimeInfo, VertexRuntimeInfo>) {
|
||||
// When using tessellation, layer is supposed to be set by the tessellation evaluation
|
||||
// stage. We don't currently have a mechanism for that when emulating rect/quad lists
|
||||
// using tessellation, so just ignore the write for now. Note that this only matters
|
||||
// for vertex shaders, as geometry shaders come last in the pre-rasterization stage.
|
||||
if (stage.tess_emulated_primitive) {
|
||||
LOG_WARNING(Render,
|
||||
"Exporting Layer from a vertex shader when using tessellation-based "
|
||||
"primitive emulation is currently unsupported.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
ir.SetAttribute(IR::Attribute::RenderTargetId, value);
|
||||
case Output::PointSize:
|
||||
ir.SetAttribute(IR::Attribute::PointSize, value);
|
||||
break;
|
||||
case Output::RenderTargetIndex:
|
||||
ir.SetAttribute(IR::Attribute::RenderTargetIndex, value);
|
||||
break;
|
||||
case Output::ViewportIndex:
|
||||
ir.SetAttribute(IR::Attribute::ViewportIndex, value);
|
||||
break;
|
||||
case Output::None:
|
||||
LOG_WARNING(Render_Recompiler, "The {} component of {} isn't mapped, skipping",
|
||||
|
||||
@@ -54,12 +54,12 @@ struct ExportRuntimeInfo {
|
||||
|
||||
enum class Output : u8 {
|
||||
None,
|
||||
PointSprite,
|
||||
PointSize,
|
||||
EdgeFlag,
|
||||
KillFlag,
|
||||
GsCutFlag,
|
||||
GsMrtIndex,
|
||||
GsVpIndex,
|
||||
RenderTargetIndex,
|
||||
ViewportIndex,
|
||||
CullDist0,
|
||||
CullDist1,
|
||||
CullDist2,
|
||||
|
||||
@@ -42,14 +42,15 @@ static u32 MapOutputs(std::span<Shader::OutputMap, 3> outputs,
|
||||
|
||||
if (ctl.vs_out_misc_enable) {
|
||||
auto& misc_vec = outputs[num_outputs++];
|
||||
misc_vec[0] = ctl.use_vtx_point_size ? Output::PointSprite : Output::None;
|
||||
misc_vec[0] = ctl.use_vtx_point_size ? Output::PointSize : Output::None;
|
||||
misc_vec[1] = ctl.use_vtx_edge_flag
|
||||
? Output::EdgeFlag
|
||||
: (ctl.use_vtx_gs_cut_flag ? Output::GsCutFlag : Output::None);
|
||||
misc_vec[2] = ctl.use_vtx_kill_flag
|
||||
? Output::KillFlag
|
||||
: (ctl.use_vtx_render_target_idx ? Output::GsMrtIndex : Output::None);
|
||||
misc_vec[3] = ctl.use_vtx_viewport_idx ? Output::GsVpIndex : Output::None;
|
||||
misc_vec[2] =
|
||||
ctl.use_vtx_kill_flag
|
||||
? Output::KillFlag
|
||||
: (ctl.use_vtx_render_target_idx ? Output::RenderTargetIndex : Output::None);
|
||||
misc_vec[3] = ctl.use_vtx_viewport_idx ? Output::ViewportIndex : Output::None;
|
||||
}
|
||||
|
||||
if (ctl.vs_out_ccdist0_enable) {
|
||||
|
||||
Reference in New Issue
Block a user