shader: keep fragment layer values under lane masks

Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
This commit is contained in:
nmzik
2026-09-05 11:43:49 +04:00
parent 2ec0e9e8f3
commit b96a30ed88
16 changed files with 458 additions and 25 deletions
@@ -32,6 +32,10 @@ uint32_t Builder::AllocateId() {
return m_next_id++;
}
void Builder::RequireVersion(uint32_t version) {
m_version = std::max(m_version, version);
}
void Builder::RequireCapability(uint32_t capability) {
if (m_required_capabilities.insert(capability).second) {
AddCapability({capability});
@@ -28,6 +28,7 @@ public:
KYTY_CLASS_DEFAULT_COPY(Builder);
uint32_t AllocateId();
void RequireVersion(uint32_t version);
void RequireCapability(uint32_t capability);
void RequireExtension(const char* name);
uint32_t Import(const char* name);
@@ -71,7 +71,8 @@ uint32_t EmitBuiltinU32(ValueEmitContext& ctx, IR::StageInputKind kind, uint32_t
{OpSelect, TypeU32(state), bits, value, ConstantU32(state, 1), ConstantU32(state, 0)});
return bits;
}
if (kind == IR::StageInputKind::VertexIndex || kind == IR::StageInputKind::InstanceIndex) {
if (kind == IR::StageInputKind::VertexIndex || kind == IR::StageInputKind::InstanceIndex ||
kind == IR::StageInputKind::Layer) {
const auto value = state.builder.AllocateId();
const auto bits = state.builder.AllocateId();
state.builder.AddFunction({OpLoad, TypeI32(state), value, variable});
@@ -50,8 +50,8 @@ enum : uint32_t {
CapabilityGroupNonUniform = 61,
CapabilityGroupNonUniformBallot = 64,
CapabilityGroupNonUniformShuffle = 65,
CapabilityShaderLayer = 69,
CapabilitySignedZeroInfNanPreserve = 4466,
CapabilityShaderViewportIndexLayerEXT = 5254,
CapabilityFragmentBarycentricKHR = 5284,
CapabilityComputeDerivativeGroupQuadsKHR = 5288,
CapabilityPhysicalStorageBufferAddresses = 5347,
@@ -518,6 +518,7 @@ uint32_t BuiltInForInput(IR::StageInputKind kind) {
case IR::StageInputKind::InstanceIndex: return BuiltInInstanceIndex;
case IR::StageInputKind::FragCoord: return BuiltInFragCoord;
case IR::StageInputKind::FrontFacing: return BuiltInFrontFacing;
case IR::StageInputKind::Layer: return BuiltInLayer;
case IR::StageInputKind::BaryCoordSmooth: return BuiltInBaryCoordKHR;
case IR::StageInputKind::BaryCoordNoPerspective: return BuiltInBaryCoordNoPerspKHR;
case IR::StageInputKind::WorkgroupId: return BuiltInWorkgroupId;
@@ -541,6 +542,9 @@ void AddInputAnnotationsAndNames(EmitterState& state) {
}
for (const auto& input: state.inputs) {
state.builder.AddName(input.variable_id, input.debug_name.c_str());
if (input.kind == IR::StageInputKind::Layer) {
state.builder.AddAnnotation({OpDecorate, input.variable_id, DecorationFlat});
}
if (input.kind == IR::StageInputKind::Parameter) {
const auto flat = PixelParameterIsFlat(state, input.location);
if (input.per_vertex) {
@@ -710,9 +714,9 @@ void DefineModule(EmitterState& state) {
if (state.cull_distance_variable != 0) {
state.builder.RequireCapability(CapabilityCullDistance);
}
if (state.layer_variable != 0) {
state.builder.RequireCapability(CapabilityShaderViewportIndexLayerEXT);
state.builder.RequireExtension("SPV_EXT_shader_viewport_index_layer");
if (state.layer_variable != 0 || InputVariableForKind(state, IR::StageInputKind::Layer) != 0) {
state.builder.RequireVersion(0x00010500u);
state.builder.RequireCapability(CapabilityShaderLayer);
}
if (state.requirements.image_gather_extended) {
state.builder.RequireCapability(CapabilityImageGatherExtended);
@@ -805,6 +809,7 @@ void DefineModule(EmitterState& state) {
switch (input.kind) {
case IR::StageInputKind::VertexIndex:
case IR::StageInputKind::InstanceIndex:
case IR::StageInputKind::Layer:
ptr_type = TypePointer(state, StorageClassInput, TypeI32(state));
break;
case IR::StageInputKind::WorkgroupId: