mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 05:46:56 +01:00
shader: fix auxiliary position exports
This commit is contained in:
@@ -276,6 +276,22 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa
|
|||||||
LOGF("depthBiasClamp is not supported\n");
|
LOGF("depthBiasClamp is not supported\n");
|
||||||
skip_device = true;
|
skip_device = true;
|
||||||
}
|
}
|
||||||
|
if (device_features2.features.shaderClipDistance != VK_TRUE) {
|
||||||
|
LOGF("shaderClipDistance is not supported\n");
|
||||||
|
skip_device = true;
|
||||||
|
}
|
||||||
|
if (device_features2.features.shaderCullDistance != VK_TRUE) {
|
||||||
|
LOGF("shaderCullDistance is not supported\n");
|
||||||
|
skip_device = true;
|
||||||
|
}
|
||||||
|
if (device_features2.features.largePoints != VK_TRUE) {
|
||||||
|
LOGF("largePoints is not supported\n");
|
||||||
|
skip_device = true;
|
||||||
|
}
|
||||||
|
if (features12.shaderOutputLayer != VK_TRUE) {
|
||||||
|
LOGF("shaderOutputLayer is not supported\n");
|
||||||
|
skip_device = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (device_features2.features.fragmentStoresAndAtomics != VK_TRUE) {
|
if (device_features2.features.fragmentStoresAndAtomics != VK_TRUE) {
|
||||||
LOGF("fragmentStoresAndAtomics is not supported\n");
|
LOGF("fragmentStoresAndAtomics is not supported\n");
|
||||||
@@ -570,10 +586,15 @@ static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, const V
|
|||||||
supported_features13.synchronization2 != VK_TRUE);
|
supported_features13.synchronization2 != VK_TRUE);
|
||||||
EXIT_NOT_IMPLEMENTED(supported_features2.features.sampleRateShading != VK_TRUE);
|
EXIT_NOT_IMPLEMENTED(supported_features2.features.sampleRateShading != VK_TRUE);
|
||||||
EXIT_NOT_IMPLEMENTED(supported_features2.features.depthBiasClamp != VK_TRUE);
|
EXIT_NOT_IMPLEMENTED(supported_features2.features.depthBiasClamp != VK_TRUE);
|
||||||
|
EXIT_NOT_IMPLEMENTED(supported_features2.features.shaderClipDistance != VK_TRUE);
|
||||||
|
EXIT_NOT_IMPLEMENTED(supported_features2.features.shaderCullDistance != VK_TRUE);
|
||||||
|
EXIT_NOT_IMPLEMENTED(supported_features2.features.largePoints != VK_TRUE);
|
||||||
|
EXIT_NOT_IMPLEMENTED(supported_features12.shaderOutputLayer != VK_TRUE);
|
||||||
#if !defined(__APPLE__)
|
#if !defined(__APPLE__)
|
||||||
EXIT_NOT_IMPLEMENTED(supported_fragment_barycentric.fragmentShaderBarycentric != VK_TRUE);
|
EXIT_NOT_IMPLEMENTED(supported_fragment_barycentric.fragmentShaderBarycentric != VK_TRUE);
|
||||||
#endif
|
#endif
|
||||||
features12.timelineSemaphore = VK_TRUE;
|
features12.timelineSemaphore = VK_TRUE;
|
||||||
|
features12.shaderOutputLayer = VK_TRUE;
|
||||||
|
|
||||||
if (Config::GpuAssistedValidationEnabled()) {
|
if (Config::GpuAssistedValidationEnabled()) {
|
||||||
if (supported_features12.bufferDeviceAddress != VK_TRUE) {
|
if (supported_features12.bufferDeviceAddress != VK_TRUE) {
|
||||||
@@ -596,6 +617,9 @@ static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, const V
|
|||||||
device_features.tessellationShader = VK_TRUE;
|
device_features.tessellationShader = VK_TRUE;
|
||||||
device_features.sampleRateShading = VK_TRUE;
|
device_features.sampleRateShading = VK_TRUE;
|
||||||
device_features.depthBiasClamp = VK_TRUE;
|
device_features.depthBiasClamp = VK_TRUE;
|
||||||
|
device_features.shaderClipDistance = VK_TRUE;
|
||||||
|
device_features.shaderCullDistance = VK_TRUE;
|
||||||
|
device_features.largePoints = VK_TRUE;
|
||||||
graphics.sample_rate_shading_enabled = true;
|
graphics.sample_rate_shading_enabled = true;
|
||||||
device_features.vertexPipelineStoresAndAtomics =
|
device_features.vertexPipelineStoresAndAtomics =
|
||||||
supported_features2.features.vertexPipelineStoresAndAtomics;
|
supported_features2.features.vertexPipelineStoresAndAtomics;
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ void CopyProgramInputsAndOutputs(EmitterState& state, const IR::Program& program
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t OutputVariableForExport(const EmitterState& state, const IR::ExportInfo& exp) {
|
uint32_t OutputVariableForExport(const EmitterState& state, const IR::ExportInfo& exp) {
|
||||||
if (exp.kind == IR::ExportTargetKind::Position) {
|
if (exp.kind == IR::ExportTargetKind::Position && exp.index == 0) {
|
||||||
return state.per_vertex_variable;
|
return state.per_vertex_variable;
|
||||||
}
|
}
|
||||||
if (exp.kind == IR::ExportTargetKind::MrtZ) {
|
if (exp.kind == IR::ExportTargetKind::MrtZ) {
|
||||||
|
|||||||
@@ -367,6 +367,49 @@ uint32_t ExportVector(ValueEmitContext& ctx, uint32_t data, const IR::ExportInfo
|
|||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitAuxPositionExport(ValueEmitContext& ctx, uint32_t data, const IR::ExportInfo& exp) {
|
||||||
|
auto& state = ctx.state;
|
||||||
|
for (uint32_t component = 0; component < 4; component++) {
|
||||||
|
if ((exp.en & (1u << component)) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto output = IR::DecodePositionExportComponent(
|
||||||
|
state.input_info.vertex->pa_cl_vs_out_cntl, exp.index, component);
|
||||||
|
if (output.layer) {
|
||||||
|
const auto raw = ExportRawComponent(ctx, data, component);
|
||||||
|
const auto layer = state.builder.AllocateId();
|
||||||
|
state.builder.AddFunction({OpBitwiseAnd, TypeU32(state), layer, raw,
|
||||||
|
ConstantU32(state, 0x7ffu)});
|
||||||
|
state.builder.AddFunction({OpStore, state.layer_variable, layer});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!output.point_size && output.clip_distance == UINT32_MAX &&
|
||||||
|
output.cull_distance == UINT32_MAX) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto raw = ExportRawComponent(ctx, data, component);
|
||||||
|
const auto f32 = state.builder.AllocateId();
|
||||||
|
state.builder.AddFunction({OpBitcast, TypeF32(state), f32, raw});
|
||||||
|
if (output.point_size) {
|
||||||
|
state.builder.AddFunction({OpStore, state.point_size_variable, f32});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto StoreDistance = [&](uint32_t variable, uint32_t index) {
|
||||||
|
if (index == UINT32_MAX) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto pointer = state.builder.AllocateId();
|
||||||
|
state.builder.AddFunction(
|
||||||
|
{OpAccessChain, TypePointer(state, StorageClassOutput, TypeF32(state)), pointer,
|
||||||
|
variable, ConstantU32(state, index)});
|
||||||
|
state.builder.AddFunction({OpStore, pointer, f32});
|
||||||
|
};
|
||||||
|
StoreDistance(state.clip_distance_variable, output.clip_distance);
|
||||||
|
StoreDistance(state.cull_distance_variable, output.cull_distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmitExport(ValueEmitContext& ctx, const IR::Inst& inst) {
|
void EmitExport(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||||
auto& state = ctx.state;
|
auto& state = ctx.state;
|
||||||
const auto& exp = ctx.Export(inst);
|
const auto& exp = ctx.Export(inst);
|
||||||
@@ -384,6 +427,10 @@ void EmitExport(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
}
|
}
|
||||||
EmitIfCondition(state, exec, [&]() {
|
EmitIfCondition(state, exec, [&]() {
|
||||||
const auto data = ctx.Arg(inst, 0);
|
const auto data = ctx.Arg(inst, 0);
|
||||||
|
if (exp.kind == IR::ExportTargetKind::Position && exp.index != 0) {
|
||||||
|
EmitAuxPositionExport(ctx, data, exp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (exp.kind == IR::ExportTargetKind::MrtZ) {
|
if (exp.kind == IR::ExportTargetKind::MrtZ) {
|
||||||
if ((exp.en & 1u) != 0u && state.depth_variable != 0) {
|
if ((exp.en & 1u) != 0u && state.depth_variable != 0) {
|
||||||
const auto raw = ExportRawComponent(ctx, data, 0);
|
const auto raw = ExportRawComponent(ctx, data, 0);
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ enum : uint32_t {
|
|||||||
MemoryModelGLSL450 = 1,
|
MemoryModelGLSL450 = 1,
|
||||||
CapabilityShader = 1,
|
CapabilityShader = 1,
|
||||||
CapabilityImageGatherExtended = 25,
|
CapabilityImageGatherExtended = 25,
|
||||||
|
CapabilityClipDistance = 32,
|
||||||
|
CapabilityCullDistance = 33,
|
||||||
CapabilitySampled1D = 43,
|
CapabilitySampled1D = 43,
|
||||||
CapabilityImage1D = 44,
|
CapabilityImage1D = 44,
|
||||||
CapabilityImageQuery = 50,
|
CapabilityImageQuery = 50,
|
||||||
@@ -47,6 +49,7 @@ enum : uint32_t {
|
|||||||
CapabilityGroupNonUniformBallot = 64,
|
CapabilityGroupNonUniformBallot = 64,
|
||||||
CapabilityGroupNonUniformShuffle = 65,
|
CapabilityGroupNonUniformShuffle = 65,
|
||||||
CapabilitySignedZeroInfNanPreserve = 4466,
|
CapabilitySignedZeroInfNanPreserve = 4466,
|
||||||
|
CapabilityShaderViewportIndexLayerEXT = 5254,
|
||||||
CapabilityFragmentBarycentricKHR = 5284,
|
CapabilityFragmentBarycentricKHR = 5284,
|
||||||
CapabilityComputeDerivativeGroupQuadsKHR = 5288,
|
CapabilityComputeDerivativeGroupQuadsKHR = 5288,
|
||||||
StorageClassUniformConstant = 0,
|
StorageClassUniformConstant = 0,
|
||||||
@@ -77,6 +80,10 @@ enum : uint32_t {
|
|||||||
|
|
||||||
enum : uint32_t {
|
enum : uint32_t {
|
||||||
BuiltInPosition = 0,
|
BuiltInPosition = 0,
|
||||||
|
BuiltInPointSize = 1,
|
||||||
|
BuiltInClipDistance = 3,
|
||||||
|
BuiltInCullDistance = 4,
|
||||||
|
BuiltInLayer = 9,
|
||||||
BuiltInFragCoord = 15,
|
BuiltInFragCoord = 15,
|
||||||
BuiltInFrontFacing = 17,
|
BuiltInFrontFacing = 17,
|
||||||
BuiltInSampleMask = 20,
|
BuiltInSampleMask = 20,
|
||||||
@@ -359,6 +366,12 @@ struct EmitterState {
|
|||||||
uint32_t pixel_valid_mask_variable = 0;
|
uint32_t pixel_valid_mask_variable = 0;
|
||||||
uint32_t subgroup_local_invocation_id_variable = 0;
|
uint32_t subgroup_local_invocation_id_variable = 0;
|
||||||
uint32_t per_vertex_variable = 0;
|
uint32_t per_vertex_variable = 0;
|
||||||
|
uint32_t point_size_variable = 0;
|
||||||
|
uint32_t clip_distance_variable = 0;
|
||||||
|
uint32_t cull_distance_variable = 0;
|
||||||
|
uint32_t layer_variable = 0;
|
||||||
|
uint32_t clip_distance_count = 0;
|
||||||
|
uint32_t cull_distance_count = 0;
|
||||||
uint32_t depth_variable = 0;
|
uint32_t depth_variable = 0;
|
||||||
uint32_t sample_mask_variable = 0;
|
uint32_t sample_mask_variable = 0;
|
||||||
std::vector<InputBinding> inputs;
|
std::vector<InputBinding> inputs;
|
||||||
|
|||||||
@@ -130,6 +130,10 @@ uint32_t SampleMaskArrayType(EmitterState& state) {
|
|||||||
return state.builder.Type(OpTypeArray, {TypeI32(state), ConstantU32(state, 1)});
|
return state.builder.Type(OpTypeArray, {TypeI32(state), ConstantU32(state, 1)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t F32ArrayType(EmitterState& state, uint32_t count) {
|
||||||
|
return state.builder.Type(OpTypeArray, {TypeF32(state), ConstantU32(state, count)});
|
||||||
|
}
|
||||||
|
|
||||||
void DefineDescriptorVariables(EmitterState& state) {
|
void DefineDescriptorVariables(EmitterState& state) {
|
||||||
if (DescriptorBinding(state, IR::DescriptorBindingKind::Buffers) != nullptr) {
|
if (DescriptorBinding(state, IR::DescriptorBindingKind::Buffers) != nullptr) {
|
||||||
const auto count =
|
const auto count =
|
||||||
@@ -420,6 +424,23 @@ void AllocateOutputVariables(EmitterState& state) {
|
|||||||
binding.variable_id =
|
binding.variable_id =
|
||||||
AllocateSharedOutputVariable(state, state.per_vertex_variable);
|
AllocateSharedOutputVariable(state, state.per_vertex_variable);
|
||||||
break;
|
break;
|
||||||
|
case IR::StageOutputKind::PointSize:
|
||||||
|
binding.variable_id =
|
||||||
|
AllocateSharedOutputVariable(state, state.point_size_variable);
|
||||||
|
break;
|
||||||
|
case IR::StageOutputKind::ClipDistance:
|
||||||
|
binding.variable_id =
|
||||||
|
AllocateSharedOutputVariable(state, state.clip_distance_variable);
|
||||||
|
state.clip_distance_count = std::max(state.clip_distance_count, binding.index + 1);
|
||||||
|
break;
|
||||||
|
case IR::StageOutputKind::CullDistance:
|
||||||
|
binding.variable_id =
|
||||||
|
AllocateSharedOutputVariable(state, state.cull_distance_variable);
|
||||||
|
state.cull_distance_count = std::max(state.cull_distance_count, binding.index + 1);
|
||||||
|
break;
|
||||||
|
case IR::StageOutputKind::Layer:
|
||||||
|
binding.variable_id = AllocateSharedOutputVariable(state, state.layer_variable);
|
||||||
|
break;
|
||||||
case IR::StageOutputKind::Depth:
|
case IR::StageOutputKind::Depth:
|
||||||
binding.variable_id = AllocateSharedOutputVariable(state, state.depth_variable);
|
binding.variable_id = AllocateSharedOutputVariable(state, state.depth_variable);
|
||||||
break;
|
break;
|
||||||
@@ -495,6 +516,16 @@ void AddOutputAnnotationsAndNames(EmitterState& state) {
|
|||||||
state.builder.AddName(PerVertexType(state), "gl_PerVertex");
|
state.builder.AddName(PerVertexType(state), "gl_PerVertex");
|
||||||
state.builder.AddName(state.per_vertex_variable, "outPerVertex");
|
state.builder.AddName(state.per_vertex_variable, "outPerVertex");
|
||||||
}
|
}
|
||||||
|
auto AddBuiltIn = [&](uint32_t variable, const char* name, uint32_t builtin) {
|
||||||
|
if (variable != 0) {
|
||||||
|
state.builder.AddName(variable, name);
|
||||||
|
state.builder.AddAnnotation({OpDecorate, variable, DecorationBuiltIn, builtin});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
AddBuiltIn(state.point_size_variable, "gl_PointSize", BuiltInPointSize);
|
||||||
|
AddBuiltIn(state.clip_distance_variable, "gl_ClipDistance", BuiltInClipDistance);
|
||||||
|
AddBuiltIn(state.cull_distance_variable, "gl_CullDistance", BuiltInCullDistance);
|
||||||
|
AddBuiltIn(state.layer_variable, "gl_Layer", BuiltInLayer);
|
||||||
if (state.depth_variable != 0) {
|
if (state.depth_variable != 0) {
|
||||||
state.builder.AddName(state.depth_variable, "gl_FragDepth");
|
state.builder.AddName(state.depth_variable, "gl_FragDepth");
|
||||||
state.builder.AddAnnotation(
|
state.builder.AddAnnotation(
|
||||||
@@ -613,6 +644,16 @@ void DefineModule(EmitterState& state) {
|
|||||||
|
|
||||||
state.builder.RequireCapability(CapabilityShader);
|
state.builder.RequireCapability(CapabilityShader);
|
||||||
state.builder.RequireCapability(CapabilitySignedZeroInfNanPreserve);
|
state.builder.RequireCapability(CapabilitySignedZeroInfNanPreserve);
|
||||||
|
if (state.clip_distance_variable != 0) {
|
||||||
|
state.builder.RequireCapability(CapabilityClipDistance);
|
||||||
|
}
|
||||||
|
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.requirements.image_gather_extended) {
|
if (state.requirements.image_gather_extended) {
|
||||||
state.builder.RequireCapability(CapabilityImageGatherExtended);
|
state.builder.RequireCapability(CapabilityImageGatherExtended);
|
||||||
}
|
}
|
||||||
@@ -733,6 +774,30 @@ void DefineModule(EmitterState& state) {
|
|||||||
state.per_vertex_variable, TypePointer(state, StorageClassOutput, PerVertexType(state)),
|
state.per_vertex_variable, TypePointer(state, StorageClassOutput, PerVertexType(state)),
|
||||||
StorageClassOutput);
|
StorageClassOutput);
|
||||||
}
|
}
|
||||||
|
if (state.point_size_variable != 0) {
|
||||||
|
state.builder.DefineGlobalVariable(
|
||||||
|
state.point_size_variable, TypePointer(state, StorageClassOutput, TypeF32(state)),
|
||||||
|
StorageClassOutput);
|
||||||
|
}
|
||||||
|
if (state.clip_distance_variable != 0) {
|
||||||
|
state.builder.DefineGlobalVariable(
|
||||||
|
state.clip_distance_variable,
|
||||||
|
TypePointer(state, StorageClassOutput,
|
||||||
|
F32ArrayType(state, state.clip_distance_count)),
|
||||||
|
StorageClassOutput);
|
||||||
|
}
|
||||||
|
if (state.cull_distance_variable != 0) {
|
||||||
|
state.builder.DefineGlobalVariable(
|
||||||
|
state.cull_distance_variable,
|
||||||
|
TypePointer(state, StorageClassOutput,
|
||||||
|
F32ArrayType(state, state.cull_distance_count)),
|
||||||
|
StorageClassOutput);
|
||||||
|
}
|
||||||
|
if (state.layer_variable != 0) {
|
||||||
|
state.builder.DefineGlobalVariable(
|
||||||
|
state.layer_variable, TypePointer(state, StorageClassOutput, TypeU32(state)),
|
||||||
|
StorageClassOutput);
|
||||||
|
}
|
||||||
for (const auto& binding: state.outputs) {
|
for (const auto& binding: state.outputs) {
|
||||||
if (binding.kind == IR::StageOutputKind::Parameter ||
|
if (binding.kind == IR::StageOutputKind::Parameter ||
|
||||||
binding.kind == IR::StageOutputKind::Mrt) {
|
binding.kind == IR::StageOutputKind::Mrt) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "graphics/shader/shader.h"
|
#include "graphics/shader/shader.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <bit>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
@@ -282,7 +283,70 @@ enum class StageInputKind {
|
|||||||
Parameter,
|
Parameter,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class StageOutputKind { Position, Parameter, Mrt, Depth, SampleMask };
|
enum class StageOutputKind {
|
||||||
|
Position,
|
||||||
|
Parameter,
|
||||||
|
Mrt,
|
||||||
|
Depth,
|
||||||
|
SampleMask,
|
||||||
|
PointSize,
|
||||||
|
ClipDistance,
|
||||||
|
CullDistance,
|
||||||
|
Layer
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PositionExportComponent {
|
||||||
|
uint32_t clip_distance = UINT32_MAX;
|
||||||
|
uint32_t cull_distance = UINT32_MAX;
|
||||||
|
bool valid = false;
|
||||||
|
bool point_size = false;
|
||||||
|
bool layer = false;
|
||||||
|
bool viewport = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline PositionExportComponent DecodePositionExportComponent(uint32_t control,
|
||||||
|
uint32_t pos_index,
|
||||||
|
uint32_t component) {
|
||||||
|
PositionExportComponent result;
|
||||||
|
if (pos_index == 0 || component >= 4) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t slot = pos_index - 1;
|
||||||
|
uint32_t vector = 3;
|
||||||
|
for (uint32_t i = 0; i < 3; i++) {
|
||||||
|
if ((control & (1u << (21u + i))) != 0) {
|
||||||
|
if (slot == 0) {
|
||||||
|
vector = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
slot--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vector == 3) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.valid = true;
|
||||||
|
if (vector == 0) {
|
||||||
|
result.point_size = component == 0 && (control & (1u << 16u)) != 0;
|
||||||
|
result.layer = component == 2 && (control & (1u << 18u)) != 0;
|
||||||
|
result.viewport = component == 2 && (control & (1u << 19u)) != 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto scalar = (vector - 1) * 4 + component;
|
||||||
|
const auto lower = (1u << scalar) - 1u;
|
||||||
|
const auto clip = control & 0xffu;
|
||||||
|
const auto cull = (control >> 8u) & 0xffu;
|
||||||
|
if ((clip & (1u << scalar)) != 0) {
|
||||||
|
result.clip_distance = std::popcount(clip & lower);
|
||||||
|
}
|
||||||
|
if ((cull & (1u << scalar)) != 0) {
|
||||||
|
result.cull_distance = std::popcount(cull & lower);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
struct StageInput {
|
struct StageInput {
|
||||||
StageInputKind kind = StageInputKind::VertexIndex;
|
StageInputKind kind = StageInputKind::VertexIndex;
|
||||||
|
|||||||
@@ -269,7 +269,14 @@ void CollectBuiltinInputs(const Program& program, ShaderInfo& info) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectOutputs(const Program& program, const ShaderPixelInputInfo* pixel, ShaderInfo& info) {
|
bool CollectOutputs(const Program& program, const ShaderVertexInputInfo* vertex,
|
||||||
|
const ShaderPixelInputInfo* pixel, ShaderInfo& info, std::string* error) {
|
||||||
|
auto Fail = [&](std::string message) {
|
||||||
|
if (error != nullptr) {
|
||||||
|
*error = std::move(message);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
for (const auto* block: program.values->blocks) {
|
for (const auto* block: program.values->blocks) {
|
||||||
for (const auto& inst: *block) {
|
for (const auto& inst: *block) {
|
||||||
if (inst.GetOpcode() != ValueOpcode::SetAttribute) {
|
if (inst.GetOpcode() != ValueOpcode::SetAttribute) {
|
||||||
@@ -292,8 +299,41 @@ void CollectOutputs(const Program& program, const ShaderPixelInputInfo* pixel, S
|
|||||||
}
|
}
|
||||||
switch (export_info.kind) {
|
switch (export_info.kind) {
|
||||||
case ExportTargetKind::Position:
|
case ExportTargetKind::Position:
|
||||||
AddOutput(info, StageOutputKind::Position, export_info.index, 0,
|
if (export_info.index == 0) {
|
||||||
"out_position");
|
AddOutput(info, StageOutputKind::Position, 0, 0, "out_position");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (export_info.compr) {
|
||||||
|
return Fail("compressed auxiliary position export is unsupported");
|
||||||
|
}
|
||||||
|
for (uint32_t component = 0; component < 4; component++) {
|
||||||
|
if ((export_info.en & (1u << component)) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto output = DecodePositionExportComponent(
|
||||||
|
vertex->pa_cl_vs_out_cntl, export_info.index, component);
|
||||||
|
if (!output.valid) {
|
||||||
|
return Fail(fmt::format("unsupported POS{} auxiliary/stereo export",
|
||||||
|
export_info.index));
|
||||||
|
}
|
||||||
|
if (output.viewport) {
|
||||||
|
return Fail("vertex viewport-index export is unsupported");
|
||||||
|
}
|
||||||
|
if (output.point_size) {
|
||||||
|
AddOutput(info, StageOutputKind::PointSize, 0, 0, "gl_PointSize");
|
||||||
|
}
|
||||||
|
if (output.layer) {
|
||||||
|
AddOutput(info, StageOutputKind::Layer, 0, 0, "gl_Layer");
|
||||||
|
}
|
||||||
|
if (output.clip_distance != UINT32_MAX) {
|
||||||
|
AddOutput(info, StageOutputKind::ClipDistance, output.clip_distance, 0,
|
||||||
|
"gl_ClipDistance");
|
||||||
|
}
|
||||||
|
if (output.cull_distance != UINT32_MAX) {
|
||||||
|
AddOutput(info, StageOutputKind::CullDistance, output.cull_distance, 0,
|
||||||
|
"gl_CullDistance");
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ExportTargetKind::Parameter:
|
case ExportTargetKind::Parameter:
|
||||||
AddOutput(info, StageOutputKind::Parameter, export_info.index,
|
AddOutput(info, StageOutputKind::Parameter, export_info.index,
|
||||||
@@ -307,6 +347,7 @@ void CollectOutputs(const Program& program, const ShaderPixelInputInfo* pixel, S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -348,7 +389,9 @@ bool CollectShaderInfo(Program& program, const ShaderInfoOptions& options, std::
|
|||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
CollectBuiltinInputs(program, next);
|
CollectBuiltinInputs(program, next);
|
||||||
CollectOutputs(program, options.pixel, next);
|
if (!CollectOutputs(program, options.vertex, options.pixel, next, error)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
program.info = std::move(next);
|
program.info = std::move(next);
|
||||||
program.shader_info_complete = true;
|
program.shader_info_complete = true;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -783,7 +783,8 @@ static bool ShaderGetStaticInputInfoVS(const HW::VertexShaderInfo& regs,
|
|||||||
|
|
||||||
info = {};
|
info = {};
|
||||||
|
|
||||||
info.export_count = static_cast<int>(sh.GetExportCount());
|
info.export_count = static_cast<int>(sh.GetExportCount());
|
||||||
|
info.pa_cl_vs_out_cntl = sh.m_paClVsOutCntl;
|
||||||
|
|
||||||
EXIT_NOT_IMPLEMENTED(regs.es_regs.data_addr == 0 || regs.gs_regs.chksum == 0);
|
EXIT_NOT_IMPLEMENTED(regs.es_regs.data_addr == 0 || regs.gs_regs.chksum == 0);
|
||||||
|
|
||||||
@@ -1452,6 +1453,7 @@ bool ShaderCompileSpirvVS(const HW::VertexShaderInfo& regs, const HW::ShaderRegi
|
|||||||
KYTY_PROFILER_FUNCTION(profiler::colors::Amber300);
|
KYTY_PROFILER_FUNCTION(profiler::colors::Amber300);
|
||||||
|
|
||||||
EXIT_NOT_IMPLEMENTED(regs.es_regs.data_addr == 0 || regs.gs_regs.chksum == 0);
|
EXIT_NOT_IMPLEMENTED(regs.es_regs.data_addr == 0 || regs.gs_regs.chksum == 0);
|
||||||
|
input_info.pa_cl_vs_out_cntl = sh.m_paClVsOutCntl;
|
||||||
|
|
||||||
const uint64_t shader_addr = regs.es_regs.data_addr;
|
const uint64_t shader_addr = regs.es_regs.data_addr;
|
||||||
const auto code = ShaderGetMappedCode(shader_addr, "ShaderRecompiler VS", regs.gs_regs.chksum);
|
const auto code = ShaderGetMappedCode(shader_addr, "ShaderRecompiler VS", regs.gs_regs.chksum);
|
||||||
@@ -1619,6 +1621,7 @@ ShaderId ShaderGetIdVS(const HW::VertexShaderInfo& regs, const ShaderVertexInput
|
|||||||
ret.ids.push_back(input_info.resources_num);
|
ret.ids.push_back(input_info.resources_num);
|
||||||
ret.ids.push_back(input_info.export_count);
|
ret.ids.push_back(input_info.export_count);
|
||||||
ret.ids.push_back(input_info.scratch_size_dwords);
|
ret.ids.push_back(input_info.scratch_size_dwords);
|
||||||
|
ret.ids.push_back(input_info.pa_cl_vs_out_cntl);
|
||||||
|
|
||||||
for (int i = 0; i < input_info.resources_num; i++) {
|
for (int i = 0; i < input_info.resources_num; i++) {
|
||||||
const auto& r = input_info.resources[i];
|
const auto& r = input_info.resources[i];
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ struct ShaderVertexInputInfo {
|
|||||||
int export_count = 0;
|
int export_count = 0;
|
||||||
uint32_t scratch_size_dwords = 0;
|
uint32_t scratch_size_dwords = 0;
|
||||||
uint32_t param_export_mask = 0;
|
uint32_t param_export_mask = 0;
|
||||||
|
uint32_t pa_cl_vs_out_cntl = 0;
|
||||||
bool fetch_external = false;
|
bool fetch_external = false;
|
||||||
bool fetch_embedded = false;
|
bool fetch_embedded = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10624,6 +10624,15 @@ private:
|
|||||||
if ((queues[i].queueFlags &
|
if ((queues[i].queueFlags &
|
||||||
(vk::QueueFlagBits::eCompute | vk::QueueFlagBits::eGraphics)) ==
|
(vk::QueueFlagBits::eCompute | vk::QueueFlagBits::eGraphics)) ==
|
||||||
(vk::QueueFlagBits::eCompute | vk::QueueFlagBits::eGraphics)) {
|
(vk::QueueFlagBits::eCompute | vk::QueueFlagBits::eGraphics)) {
|
||||||
|
vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR barycentric{};
|
||||||
|
barycentric.sType = vk::StructureType::ePhysicalDeviceFragmentShaderBarycentricFeaturesKHR;
|
||||||
|
vk::PhysicalDeviceFeatures2 features{};
|
||||||
|
features.sType = vk::StructureType::ePhysicalDeviceFeatures2;
|
||||||
|
features.pNext = &barycentric;
|
||||||
|
physical.getFeatures2(&features);
|
||||||
|
if (barycentric.fragmentShaderBarycentric != true) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
m_physical_device = physical;
|
m_physical_device = physical;
|
||||||
m_queue_family = i;
|
m_queue_family = i;
|
||||||
break;
|
break;
|
||||||
@@ -10634,7 +10643,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Require("VulkanHarness", "dispatch", m_physical_device != nullptr,
|
Require("VulkanHarness", "dispatch", m_physical_device != nullptr,
|
||||||
"no Vulkan graphics+compute queue family");
|
"no Vulkan graphics+compute device with fragment barycentrics");
|
||||||
m_physical_device.getMemoryProperties(&m_memory_properties);
|
m_physical_device.getMemoryProperties(&m_memory_properties);
|
||||||
|
|
||||||
vk::PhysicalDeviceFeatures available_features{};
|
vk::PhysicalDeviceFeatures available_features{};
|
||||||
@@ -10681,10 +10690,14 @@ private:
|
|||||||
device_features12.sType =
|
device_features12.sType =
|
||||||
vk::StructureType::ePhysicalDeviceVulkan12Features;
|
vk::StructureType::ePhysicalDeviceVulkan12Features;
|
||||||
device_features12.timelineSemaphore = true;
|
device_features12.timelineSemaphore = true;
|
||||||
|
vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR barycentric{};
|
||||||
|
barycentric.sType = vk::StructureType::ePhysicalDeviceFragmentShaderBarycentricFeaturesKHR;
|
||||||
|
barycentric.pNext = &device_features12;
|
||||||
|
barycentric.fragmentShaderBarycentric = true;
|
||||||
vk::PhysicalDeviceVulkan13Features device_features13{};
|
vk::PhysicalDeviceVulkan13Features device_features13{};
|
||||||
device_features13.sType =
|
device_features13.sType =
|
||||||
vk::StructureType::ePhysicalDeviceVulkan13Features;
|
vk::StructureType::ePhysicalDeviceVulkan13Features;
|
||||||
device_features13.pNext = &device_features12;
|
device_features13.pNext = &barycentric;
|
||||||
device_features13.dynamicRendering = true;
|
device_features13.dynamicRendering = true;
|
||||||
device_features13.synchronization2 = true;
|
device_features13.synchronization2 = true;
|
||||||
device_info.pNext = &device_features13;
|
device_info.pNext = &device_features13;
|
||||||
@@ -10693,7 +10706,8 @@ private:
|
|||||||
device_features.sampleRateShading = true;
|
device_features.sampleRateShading = true;
|
||||||
device_info.pEnabledFeatures = &device_features;
|
device_info.pEnabledFeatures = &device_features;
|
||||||
constexpr const char *device_extensions[] = {
|
constexpr const char *device_extensions[] = {
|
||||||
VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME};
|
VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,
|
||||||
|
VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME};
|
||||||
device_info.enabledExtensionCount = std::size(device_extensions);
|
device_info.enabledExtensionCount = std::size(device_extensions);
|
||||||
device_info.ppEnabledExtensionNames = device_extensions;
|
device_info.ppEnabledExtensionNames = device_extensions;
|
||||||
RequireVk("VulkanHarness", "dispatch",
|
RequireVk("VulkanHarness", "dispatch",
|
||||||
|
|||||||
@@ -728,6 +728,136 @@ SpirvDecorationValueTargets(const std::vector<uint32_t> &binary,
|
|||||||
return targets;
|
return targets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<uint32_t>
|
||||||
|
SpirvStoredBuiltInElements(const std::vector<uint32_t> &binary,
|
||||||
|
uint32_t builtin) {
|
||||||
|
struct Access {
|
||||||
|
uint32_t base = 0;
|
||||||
|
std::vector<uint32_t> indices;
|
||||||
|
};
|
||||||
|
std::unordered_map<uint32_t, uint32_t> direct_builtins;
|
||||||
|
std::unordered_map<uint64_t, uint32_t> member_builtins;
|
||||||
|
std::unordered_map<uint32_t, uint32_t> pointer_pointees;
|
||||||
|
std::unordered_map<uint32_t, uint32_t> variable_types;
|
||||||
|
std::unordered_map<uint32_t, uint32_t> constants;
|
||||||
|
std::unordered_map<uint32_t, Access> accesses;
|
||||||
|
std::vector<uint32_t> stores;
|
||||||
|
|
||||||
|
for (size_t i = 5; i < binary.size();) {
|
||||||
|
const uint32_t opcode = binary[i] & 0xffffu;
|
||||||
|
const uint32_t count = binary[i] >> 16u;
|
||||||
|
if (count == 0 || i + count > binary.size()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (opcode == 71u && count >= 4u && binary[i + 2] == 11u) {
|
||||||
|
direct_builtins[binary[i + 1]] = binary[i + 3];
|
||||||
|
} else if (opcode == 72u && count >= 5u && binary[i + 3] == 11u) {
|
||||||
|
const uint64_t key = (static_cast<uint64_t>(binary[i + 1]) << 32u) |
|
||||||
|
binary[i + 2];
|
||||||
|
member_builtins[key] = binary[i + 4];
|
||||||
|
} else if (opcode == 32u && count == 4u) {
|
||||||
|
pointer_pointees[binary[i + 1]] = binary[i + 3];
|
||||||
|
} else if (opcode == 43u && count >= 4u) {
|
||||||
|
constants[binary[i + 2]] = binary[i + 3];
|
||||||
|
} else if (opcode == 59u && count >= 4u) {
|
||||||
|
variable_types[binary[i + 2]] = binary[i + 1];
|
||||||
|
} else if (opcode == 65u && count >= 5u) {
|
||||||
|
accesses[binary[i + 2]] =
|
||||||
|
{binary[i + 3], std::vector<uint32_t>(binary.begin() + i + 4,
|
||||||
|
binary.begin() + i + count)};
|
||||||
|
} else if (opcode == 62u && count >= 3u) {
|
||||||
|
stores.push_back(binary[i + 1]);
|
||||||
|
}
|
||||||
|
i += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint32_t> elements;
|
||||||
|
for (const auto pointer : stores) {
|
||||||
|
if (const auto decorated = direct_builtins.find(pointer);
|
||||||
|
decorated != direct_builtins.end()) {
|
||||||
|
if (decorated->second == builtin) {
|
||||||
|
elements.push_back(UINT32_MAX);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto access = accesses.find(pointer);
|
||||||
|
if (access == accesses.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (const auto decorated = direct_builtins.find(access->second.base);
|
||||||
|
decorated != direct_builtins.end()) {
|
||||||
|
if (decorated->second == builtin && !access->second.indices.empty()) {
|
||||||
|
const auto index = constants.find(access->second.indices.back());
|
||||||
|
if (index != constants.end()) {
|
||||||
|
elements.push_back(index->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto variable = variable_types.find(access->second.base);
|
||||||
|
if (variable == variable_types.end() || access->second.indices.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto pointee = pointer_pointees.find(variable->second);
|
||||||
|
const auto member = constants.find(access->second.indices.front());
|
||||||
|
if (pointee == pointer_pointees.end() || member == constants.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const uint64_t key = (static_cast<uint64_t>(pointee->second) << 32u) |
|
||||||
|
member->second;
|
||||||
|
if (const auto decorated = member_builtins.find(key);
|
||||||
|
decorated != member_builtins.end() && decorated->second == builtin) {
|
||||||
|
elements.push_back(UINT32_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::sort(elements.begin(), elements.end());
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpirvBuiltInStoreUsesAndConstant(const std::vector<uint32_t> &binary,
|
||||||
|
uint32_t builtin,
|
||||||
|
uint32_t constant) {
|
||||||
|
std::unordered_set<uint32_t> variables;
|
||||||
|
std::unordered_map<uint32_t, uint32_t> constants;
|
||||||
|
std::unordered_map<uint32_t, std::array<uint32_t, 2>> bitwise_ands;
|
||||||
|
std::unordered_map<uint32_t, uint32_t> stores;
|
||||||
|
for (size_t i = 5; i < binary.size();) {
|
||||||
|
const uint32_t opcode = binary[i] & 0xffffu;
|
||||||
|
const uint32_t count = binary[i] >> 16u;
|
||||||
|
if (count == 0 || i + count > binary.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (opcode == 71u && count >= 4u && binary[i + 2] == 11u &&
|
||||||
|
binary[i + 3] == builtin) {
|
||||||
|
variables.insert(binary[i + 1]);
|
||||||
|
} else if (opcode == 43u && count >= 4u) {
|
||||||
|
constants[binary[i + 2]] = binary[i + 3];
|
||||||
|
} else if (opcode == 199u && count == 5u) {
|
||||||
|
bitwise_ands[binary[i + 2]] = {binary[i + 3], binary[i + 4]};
|
||||||
|
} else if (opcode == 62u && count >= 3u) {
|
||||||
|
stores[binary[i + 1]] = binary[i + 2];
|
||||||
|
}
|
||||||
|
i += count;
|
||||||
|
}
|
||||||
|
for (const auto variable : variables) {
|
||||||
|
const auto store = stores.find(variable);
|
||||||
|
if (store == stores.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto value = bitwise_ands.find(store->second);
|
||||||
|
if (value == bitwise_ands.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (const auto operand : value->second) {
|
||||||
|
const auto literal = constants.find(operand);
|
||||||
|
if (literal != constants.end() && literal->second == constant) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool SpirvTargetHasDecoration(const std::vector<uint32_t> &binary,
|
bool SpirvTargetHasDecoration(const std::vector<uint32_t> &binary,
|
||||||
uint32_t target, uint32_t decoration) {
|
uint32_t target, uint32_t decoration) {
|
||||||
for (size_t i = 5; i < binary.size();) {
|
for (size_t i = 5; i < binary.size();) {
|
||||||
@@ -8605,6 +8735,123 @@ void TestNewShaderRecompilerExpVertexOutputs() {
|
|||||||
CheckSpirvBinaryValidates(result.spirv);
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestNewShaderRecompilerAuxPositionExports() {
|
||||||
|
const auto compile = [](std::span<const uint32_t> shader, uint32_t control) {
|
||||||
|
ShaderVertexInputInfo vertex{};
|
||||||
|
vertex.pa_cl_vs_out_cntl = control;
|
||||||
|
auto options = MakeCompileOptions(ShaderType::Vertex);
|
||||||
|
options.input_info.vertex = &vertex;
|
||||||
|
|
||||||
|
ShaderRecompiler::CompileResult result;
|
||||||
|
std::string error;
|
||||||
|
Check(ShaderRecompiler::TryRecompile(shader, options, result, &error),
|
||||||
|
error.c_str());
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32_t all_outputs[] = {
|
||||||
|
EncodeExp0(0x0c, 0xf, false), EncodeExp1(0, 1, 2, 3),
|
||||||
|
EncodeExp0(0x0d, 0x5, false), EncodeExp1(4, 5, 6, 7),
|
||||||
|
EncodeExp0(0x0e, 0xb, false), EncodeExp1(8, 9, 10, 11),
|
||||||
|
EncodeExp0(0x0f, 0x6), EncodeExp1(12, 13, 14, 15),
|
||||||
|
0xbf810000u,
|
||||||
|
};
|
||||||
|
const auto all = compile(all_outputs, 0x00e5aa55u);
|
||||||
|
CheckSpirvBinaryValidates(all.spirv);
|
||||||
|
Check(SpirvStoredBuiltInElements(all.spirv, 0u) ==
|
||||||
|
std::vector<uint32_t>({UINT32_MAX}),
|
||||||
|
"POS1-POS3 overwrote gl_Position");
|
||||||
|
Check(SpirvStoredBuiltInElements(all.spirv, 1u) ==
|
||||||
|
std::vector<uint32_t>({UINT32_MAX}) &&
|
||||||
|
SpirvStoredBuiltInElements(all.spirv, 9u) ==
|
||||||
|
std::vector<uint32_t>({UINT32_MAX}),
|
||||||
|
"MISC point-size/layer stores are missing");
|
||||||
|
Check(SpirvStoredBuiltInElements(all.spirv, 3u) ==
|
||||||
|
std::vector<uint32_t>({0u, 3u}) &&
|
||||||
|
SpirvStoredBuiltInElements(all.spirv, 4u) ==
|
||||||
|
std::vector<uint32_t>({0u, 1u, 2u}),
|
||||||
|
"partial clip/cull exports used the wrong dense elements");
|
||||||
|
Check(SpirvHasDecorationValue(all.spirv, 11u, 1u) &&
|
||||||
|
SpirvHasDecorationValue(all.spirv, 11u, 3u) &&
|
||||||
|
SpirvHasDecorationValue(all.spirv, 11u, 4u) &&
|
||||||
|
SpirvHasDecorationValue(all.spirv, 11u, 9u) &&
|
||||||
|
SpirvContainsCapability(all.spirv, 32u) &&
|
||||||
|
SpirvContainsCapability(all.spirv, 33u) &&
|
||||||
|
SpirvContainsCapability(all.spirv, 5254u),
|
||||||
|
"auxiliary vertex BuiltIns or capabilities are missing");
|
||||||
|
const auto all_source = DisassembleSpirvBinary(all.spirv);
|
||||||
|
Check(Common::ContainsStr(all_source, "SPV_EXT_shader_viewport_index_layer") &&
|
||||||
|
SpirvBuiltInStoreUsesAndConstant(all.spirv, 9u, 0x7ffu),
|
||||||
|
"layer export extension or GFX10 layer mask is missing");
|
||||||
|
const auto positions = std::count_if(
|
||||||
|
all.program.info.outputs.begin(), all.program.info.outputs.end(),
|
||||||
|
[](const auto &output) {
|
||||||
|
return output.kind == ShaderRecompiler::IR::StageOutputKind::Position;
|
||||||
|
});
|
||||||
|
Check(positions == 1 &&
|
||||||
|
std::ranges::find_if(all.program.info.outputs, [](const auto &output) {
|
||||||
|
return output.kind == ShaderRecompiler::IR::StageOutputKind::Position;
|
||||||
|
})->index == 0,
|
||||||
|
"shader info did not reserve Position exclusively for POS0");
|
||||||
|
|
||||||
|
const uint32_t cc1_only[] = {
|
||||||
|
EncodeExp0(0x0c, 0xf, false), EncodeExp1(0, 1, 2, 3),
|
||||||
|
EncodeExp0(0x0d, 0x6), EncodeExp1(4, 5, 6, 7),
|
||||||
|
0xbf810000u,
|
||||||
|
};
|
||||||
|
const auto dense = compile(cc1_only, 0x0080a050u);
|
||||||
|
CheckSpirvBinaryValidates(dense.spirv);
|
||||||
|
Check(SpirvStoredBuiltInElements(dense.spirv, 0u).size() == 1u &&
|
||||||
|
SpirvStoredBuiltInElements(dense.spirv, 3u) ==
|
||||||
|
std::vector<uint32_t>({1u}) &&
|
||||||
|
SpirvStoredBuiltInElements(dense.spirv, 4u) ==
|
||||||
|
std::vector<uint32_t>({0u}),
|
||||||
|
"CCDIST1 was not densely packed into POS1");
|
||||||
|
|
||||||
|
const uint32_t middle_hole[] = {
|
||||||
|
EncodeExp0(0x0c, 0xf, false), EncodeExp1(0, 1, 2, 3),
|
||||||
|
EncodeExp0(0x0d, 0x1, false), EncodeExp1(4, 5, 6, 7),
|
||||||
|
EncodeExp0(0x0e, 0x3), EncodeExp1(8, 9, 10, 11),
|
||||||
|
0xbf810000u,
|
||||||
|
};
|
||||||
|
const auto shifted = compile(middle_hole, 0x00a12010u);
|
||||||
|
CheckSpirvBinaryValidates(shifted.spirv);
|
||||||
|
Check(SpirvStoredBuiltInElements(shifted.spirv, 1u).size() == 1u &&
|
||||||
|
SpirvStoredBuiltInElements(shifted.spirv, 3u) ==
|
||||||
|
std::vector<uint32_t>({0u}) &&
|
||||||
|
SpirvStoredBuiltInElements(shifted.spirv, 4u) ==
|
||||||
|
std::vector<uint32_t>({0u}),
|
||||||
|
"CCDIST1 did not shift across a disabled CCDIST0 vector");
|
||||||
|
|
||||||
|
const auto rejects = [](uint32_t control, uint32_t en, const char *message) {
|
||||||
|
const uint32_t shader[] = {
|
||||||
|
EncodeExp0(0x0c, 0xf, false), EncodeExp1(0, 1, 2, 3),
|
||||||
|
EncodeExp0(0x0d, en), EncodeExp1(4, 5, 6, 7),
|
||||||
|
0xbf810000u,
|
||||||
|
};
|
||||||
|
ShaderVertexInputInfo vertex{};
|
||||||
|
vertex.pa_cl_vs_out_cntl = control;
|
||||||
|
auto options = MakeCompileOptions(ShaderType::Vertex);
|
||||||
|
options.input_info.vertex = &vertex;
|
||||||
|
ShaderRecompiler::CompileResult result;
|
||||||
|
std::string error;
|
||||||
|
Check(!ShaderRecompiler::TryRecompile(shader, options, result, &error) &&
|
||||||
|
Common::ContainsStr(error, message),
|
||||||
|
"unsupported auxiliary position export did not fail explicitly");
|
||||||
|
};
|
||||||
|
rejects(0x00280000u, 0x4u, "viewport-index");
|
||||||
|
rejects(0u, 0x1u, "auxiliary/stereo");
|
||||||
|
|
||||||
|
HW::VertexShaderInfo regs{};
|
||||||
|
regs.es_regs.data_addr = 1;
|
||||||
|
regs.gs_regs.chksum = 1;
|
||||||
|
ShaderVertexInputInfo key0{};
|
||||||
|
ShaderVertexInputInfo key1{};
|
||||||
|
key1.pa_cl_vs_out_cntl = 1;
|
||||||
|
Check(ShaderGetIdVS(regs, key0, false) != ShaderGetIdVS(regs, key1, false),
|
||||||
|
"PA_CL_VS_OUT_CNTL is absent from the vertex shader cache key");
|
||||||
|
}
|
||||||
|
|
||||||
void TestDemandDrivenSpirvDeclarations() {
|
void TestDemandDrivenSpirvDeclarations() {
|
||||||
using ShaderRecompiler::Spirv::Builder;
|
using ShaderRecompiler::Spirv::Builder;
|
||||||
|
|
||||||
@@ -11661,6 +11908,7 @@ int main() {
|
|||||||
TestNewShaderRecompilerSpirvSizeBaselines();
|
TestNewShaderRecompilerSpirvSizeBaselines();
|
||||||
TestDemandDrivenSpirvDeclarations();
|
TestDemandDrivenSpirvDeclarations();
|
||||||
TestNewShaderRecompilerSMovB32();
|
TestNewShaderRecompilerSMovB32();
|
||||||
|
TestNewShaderRecompilerAuxPositionExports();
|
||||||
TestNewShaderRecompilerNativeWideScalarMemoryIr();
|
TestNewShaderRecompilerNativeWideScalarMemoryIr();
|
||||||
TestNewShaderRecompilerNativeWideBufferIr();
|
TestNewShaderRecompilerNativeWideBufferIr();
|
||||||
TestNewShaderRecompilerScalarB64LaneLowering();
|
TestNewShaderRecompilerScalarB64LaneLowering();
|
||||||
|
|||||||
Reference in New Issue
Block a user