Add support for VK_KHR_shader_fma

This commit is contained in:
baldurk
2026-07-24 17:52:47 +01:00
parent f820816452
commit d83d6a184b
13 changed files with 122 additions and 25 deletions
+5 -2
View File
@@ -1276,12 +1276,15 @@ public:
return true;
}
virtual bool QueueCalculateMathOp(rdcspv::GLSLstd450 op,
virtual bool QueueCalculateMathOp(rdcspv::Op opcode, rdcspv::GLSLstd450 glslop,
const rdcarray<ShaderVariable> &params) override
{
CHECK_DEVICE_THREAD();
RDCASSERT(params.size() <= 3, params.size());
// only support GLSL std450 ops
RDCASSERT(opcode == rdcspv::Op::ExtInst && glslop != rdcspv::GLSLstd450::Invalid, opcode, glslop);
RDCASSERTEQUAL(params[0].type, VarType::Float);
GLMarkerRegion markerRegion("QueueCalculateMathOp");
@@ -1363,7 +1366,7 @@ public:
}
// push the operation afterwards
GL.glUniform1i(GL.glGetUniformLocation(mathProg, "op"), (int32_t)op);
GL.glUniform1i(GL.glGetUniformLocation(mathProg, "op"), (int32_t)glslop);
GL.glDispatchCompute(1, 1, 1);
+32 -4
View File
@@ -2938,6 +2938,34 @@ void ThreadState::StepNext(bool useDebugState, const uint32_t steps,
break;
}
case Op::FmaKHR:
{
OpFmaKHR fma(it);
const DataType &resultType = debugger.GetType(fma.resultType);
if(IsPendingResultReady())
{
ShaderVariable result = GetPendingResult();
result.rows = 1;
result.columns = RDCMAX(1U, resultType.vector().count) & 0xff;
SetDst(fma.result, result);
break;
}
rdcarray<ShaderVariable> paramVars;
paramVars.push_back(GetSrc(fma.operand1));
paramVars.push_back(GetSrc(fma.operand2));
paramVars.push_back(GetSrc(fma.operand3));
ShaderVariable ret = paramVars[0];
QueueMathOp(Op::FmaKHR, GLSLstd450::Invalid, paramVars, ret);
break;
}
//////////////////////////////////////////////////////////////////////////////
//
// Subgroup opcodes
@@ -5400,7 +5428,6 @@ void ThreadState::StepNext(bool useDebugState, const uint32_t steps,
case Op::CompositeConstructCoopMatQCOM:
case Op::CompositeExtractCoopMatQCOM:
case Op::ExtractSubArrayQCOM:
case Op::FmaKHR:
case Op::BufferPointerEXT:
case Op::UntypedImageTexelPointerEXT:
case Op::ConstantSizeOfEXT:
@@ -5729,13 +5756,14 @@ void ThreadState::ExecuteMemoryBarrier(Id semanticsId)
}
}
void ThreadState::QueueMathOp(GLSLstd450 op, const rdcarray<ShaderVariable> &paramVars,
const ShaderVariable &result)
void ThreadState::QueueMathOp(Op opcode, GLSLstd450 glslop,
const rdcarray<ShaderVariable> &paramVars, const ShaderVariable &result)
{
SPIRV_DEBUG_RDCASSERT(!IsPendingResultPending());
pendingResultData = result;
queuedGpuMathOp.workgroupIndex = workgroupIndex;
queuedGpuMathOp.op = op;
queuedGpuMathOp.opcode = opcode;
queuedGpuMathOp.glslop = glslop;
queuedGpuMathOp.paramVars = paramVars;
queuedGpuMathOp.result = &pendingResultData;
SetStepNeedsGpuMathOp();
+5 -3
View File
@@ -156,7 +156,8 @@ public:
const ShaderVariable &compare, GatherChannel gatherChannel,
const rdcspv::ImageOperandsAndParamDatas &operands,
ShaderVariable &output, bool &hasResult) = 0;
virtual bool QueueCalculateMathOp(GLSLstd450 op, const rdcarray<ShaderVariable> &params) = 0;
virtual bool QueueCalculateMathOp(Op opcode, GLSLstd450 op,
const rdcarray<ShaderVariable> &params) = 0;
virtual bool GetQueuedResults(rdcarray<ShaderVariable *> &mathOpResults,
rdcarray<ShaderVariable *> &sampleGatherResults) = 0;
virtual bool QueuedOpsHasSpace() = 0;
@@ -285,7 +286,8 @@ private:
struct GpuMathOperation
{
uint32_t workgroupIndex;
GLSLstd450 op;
Op opcode;
GLSLstd450 glslop;
rdcarray<ShaderVariable> paramVars;
ShaderVariable *result;
};
@@ -419,7 +421,7 @@ struct ThreadState
Stepped,
};
void QueueMathOp(GLSLstd450 op, const rdcarray<ShaderVariable> &paramVars,
void QueueMathOp(Op opcode, GLSLstd450 op, const rdcarray<ShaderVariable> &paramVars,
const ShaderVariable &result);
void QueueSampleGather(Op opcode, DebugAPIWrapper::TextureType texType,
const ShaderBindIndex &imageBind, const ShaderBindIndex &samplerBind,
@@ -1242,7 +1242,7 @@ ShaderVariable GPUOp(ThreadState &state, uint32_t instruction, const rdcarray<Id
if(op == rdcspv::GLSLstd450::Length || op == rdcspv::GLSLstd450::Distance)
ret.columns = 1;
state.QueueMathOp(op, paramVars, ret);
state.QueueMathOp(rdcspv::Op::ExtInst, op, paramVars, ret);
return ret;
}
@@ -446,6 +446,7 @@ void Reflector::CheckDebuggable(bool &debuggable, rdcstr &debugStatus) const
"SPV_KHR_device_group",
"SPV_KHR_expect_assume",
"SPV_KHR_float_controls",
"SPV_KHR_fma",
"SPV_KHR_maximal_reconvergence",
"SPV_KHR_multiview",
"SPV_KHR_no_integer_wrap_decoration",
@@ -626,6 +627,7 @@ void Reflector::CheckDebuggable(bool &debuggable, rdcstr &debugStatus) const
case Capability::DotProductInputAll:
case Capability::AbortKHR:
case Capability::ConstantDataKHR:
case Capability::FMAKHR:
{
supported = true;
break;
@@ -672,13 +674,6 @@ void Reflector::CheckDebuggable(bool &debuggable, rdcstr &debugStatus) const
break;
}
// SPV_KHR_fma
case Capability::FMAKHR:
{
supported = false;
break;
}
// SPV_KHR_fragment_shader_barycentric
case Capability::FragmentBarycentricKHR:
{
@@ -747,6 +742,7 @@ void Reflector::CheckDebuggable(bool &debuggable, rdcstr &debugStatus) const
break;
}
// SPV_EXT_replicated_composites
case Capability::ReplicatedCompositesEXT:
{
supported = false;
@@ -5081,7 +5077,7 @@ void Debugger::ProcessQueuedGpuMathOps()
const GpuMathOperation &mathOp = workgroup[lane].GetQueuedGpuMathOp();
uint32_t workgroupIndex = mathOp.workgroupIndex;
if(apiWrapper->QueueCalculateMathOp(mathOp.op, mathOp.paramVars))
if(apiWrapper->QueueCalculateMathOp(mathOp.opcode, mathOp.glslop, mathOp.paramVars))
{
pendingGpuMathsOpsResults.push_back(mathOp.result);
}
+1 -1
View File
@@ -229,6 +229,7 @@ Maintainers can update this file by updating vk.xml in this folder and running `
* `VK_KHR_shader_float_controls`
* `VK_KHR_shader_float_controls2`
* `VK_KHR_shader_float16_int8`
* `VK_KHR_shader_fma`
* `VK_KHR_shader_integer_dot_product`
* `VK_KHR_shader_maximal_reconvergence`
* `VK_KHR_shader_non_semantic_info`
@@ -300,7 +301,6 @@ KHR extensions will definitely be implemented at some point, though KHR extensio
* `VK_KHR_maintenance11`
* `VK_KHR_opacity_micromap`
* `VK_KHR_pipeline_binary`
* `VK_KHR_shader_fma`
* `VK_KHR_shader_untyped_pointers`
## KHR Portability
+2
View File
@@ -1836,6 +1836,7 @@ DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceShaderDrawParametersFeatures);
DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceShaderExpectAssumeFeatures);
DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceShaderFloat16Int8Features);
DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceShaderFloatControls2Features);
DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceShaderFmaFeaturesKHR);
DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT);
DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceShaderImageFootprintFeaturesNV);
DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceShaderIntegerDotProductFeatures);
@@ -2390,6 +2391,7 @@ DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceShaderDrawParametersFeatures);
DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceShaderExpectAssumeFeatures);
DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceShaderFloat16Int8Features);
DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceShaderFloatControls2Features);
DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceShaderFmaFeaturesKHR);
DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT);
DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceShaderImageFootprintFeaturesNV);
DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceShaderIntegerDotProductFeatures);
+4
View File
@@ -1916,6 +1916,10 @@ static const VkExtensionProperties supportedExtensions[] = {
VK_KHR_SHADER_FLOAT_CONTROLS_2_EXTENSION_NAME,
VK_KHR_SHADER_FLOAT_CONTROLS_2_SPEC_VERSION,
},
{
VK_KHR_SHADER_FMA_EXTENSION_NAME,
VK_KHR_SHADER_FMA_SPEC_VERSION,
},
{
VK_KHR_SHADER_INTEGER_DOT_PRODUCT_EXTENSION_NAME,
VK_KHR_SHADER_INTEGER_DOT_PRODUCT_SPEC_VERSION,
+2
View File
@@ -547,6 +547,7 @@ private:
bool m_Maintenance9 = false;
bool m_DescriptorBuffers = false;
bool m_MultiviewPerViewViewports = false;
uint32_t m_PreciseFMAMask = 0;
uint32_t m_RTCaptureReplayHandleSize = 0;
@@ -1516,6 +1517,7 @@ public:
bool DescriptorBuffers() const { return m_DescriptorBuffers; }
bool MultiViewGeometryShaders() const { return m_MultiViewGeometryShaders; }
bool MultiviewPerViewViewports() const { return m_MultiviewPerViewViewports; }
uint32_t PreciseFMAMask() const { return m_PreciseFMAMask; }
VulkanRenderState &GetRenderState() { return m_RenderState; }
void SetActionCB(VulkanActionCallback *cb) { m_ActionCallback = cb; }
void SetSubmitChain(void *submitChain) { m_SubmitChain = submitChain; }
+2 -1
View File
@@ -576,6 +576,8 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct,
VkPhysicalDeviceShaderFloat16Int8Features); \
COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT_CONTROLS_2_FEATURES, \
VkPhysicalDeviceShaderFloatControls2Features); \
COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FMA_FEATURES_KHR, \
VkPhysicalDeviceShaderFmaFeaturesKHR); \
COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT, \
VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT); \
COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV, \
@@ -1404,7 +1406,6 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct,
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_ARM: \
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD: \
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT8_FEATURES_EXT: \
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FMA_FEATURES_KHR: \
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INSTRUMENTATION_FEATURES_ARM: \
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INSTRUMENTATION_PROPERTIES_ARM: \
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL: \
+22 -3
View File
@@ -1546,6 +1546,10 @@ SERIALISE_VK_HANDLES();
PNEXT_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT_CONTROLS_2_FEATURES, \
VkPhysicalDeviceShaderFloatControls2Features) \
\
/* VK_KHR_shader_fma */ \
PNEXT_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FMA_FEATURES_KHR, \
VkPhysicalDeviceShaderFmaFeaturesKHR) \
\
/* VK_KHR_shader_integer_dot_product */ \
PNEXT_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES, \
VkPhysicalDeviceShaderIntegerDotProductFeatures) \
@@ -2224,9 +2228,6 @@ SERIALISE_VK_HANDLES();
PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_DEVICE_PIPELINE_BINARY_INTERNAL_CACHE_CONTROL_KHR) \
PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PIPELINE_BINARY_HANDLES_INFO_KHR) \
\
/* VK_KHR_shader_fma */ \
PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FMA_FEATURES_KHR) \
\
/* VK_KHR_shader_untyped_pointers */ \
PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_UNTYPED_POINTERS_FEATURES_KHR) \
\
@@ -12426,6 +12427,23 @@ void Deserialise(const VkPhysicalDeviceShaderFloat16Int8Features &el)
DeserialiseNext(el.pNext);
}
template <typename SerialiserType>
void DoSerialise(SerialiserType &ser, VkPhysicalDeviceShaderFmaFeaturesKHR &el)
{
RDCASSERT(ser.IsReading() || el.sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FMA_FEATURES_KHR);
SerialiseNext(ser, el.sType, el.pNext);
SERIALISE_MEMBER(shaderFmaFloat16);
SERIALISE_MEMBER(shaderFmaFloat32);
SERIALISE_MEMBER(shaderFmaFloat64);
}
template <>
void Deserialise(const VkPhysicalDeviceShaderFmaFeaturesKHR &el)
{
DeserialiseNext(el.pNext);
}
template <typename SerialiserType>
void DoSerialise(SerialiserType &ser, VkPhysicalDeviceShaderFloatControls2Features &el)
{
@@ -15708,6 +15726,7 @@ INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceShaderDrawParametersFeatures);
INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceShaderExpectAssumeFeatures)
INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceShaderFloat16Int8Features);
INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceShaderFloatControls2Features);
INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceShaderFmaFeaturesKHR);
INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT);
INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceShaderImageFootprintFeaturesNV);
INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceShaderIntegerDotProductFeatures);
+26 -2
View File
@@ -1557,7 +1557,7 @@ public:
return true;
}
virtual bool QueueCalculateMathOp(rdcspv::GLSLstd450 op,
virtual bool QueueCalculateMathOp(rdcspv::Op opcode, rdcspv::GLSLstd450 glslop,
const rdcarray<ShaderVariable> &params) override
{
CHECK_DEVICE_THREAD();
@@ -1645,8 +1645,16 @@ public:
}
// push the operation afterwards
if(glslop == rdcspv::GLSLstd450::Invalid)
{
RDCCOMPILE_ASSERT(rdcspv::GLSLstd450::Max < (rdcspv::GLSLstd450)1000,
"GLSL std450 ops max is higher than expected");
glslop = (rdcspv::GLSLstd450)(1000 + (uint32_t)opcode);
}
ObjDisp(cmd)->CmdPushConstants(Unwrap(cmd), Unwrap(m_DebugData.PipeLayout), VK_SHADER_STAGE_ALL,
sizeof(Vec4f) * 6, sizeof(uint32_t), &op);
sizeof(Vec4f) * 6, sizeof(uint32_t), &glslop);
ObjDisp(cmd)->CmdDispatch(Unwrap(cmd), 1, 1, 1);
@@ -2766,6 +2774,22 @@ private:
cases.add(rdcspv::OpBranch(breakLabel));
}
// non-glsl opcodes
if(m_pDriver->PreciseFMAMask() & floatBitSize)
{
editor.AddCapability(rdcspv::Capability::FMAKHR);
uint32_t op = 1000 + (uint32_t)rdcspv::Op::FmaKHR;
rdcspv::Id label = editor.MakeId();
targets.push_back({(uint32_t)op, label});
cases.add(rdcspv::OpLabel(label));
rdcspv::Id result = cases.add(rdcspv::OpFmaKHR(vec4Type, editor.MakeId(), a, b, c));
cases.add(rdcspv::OpStore(outVar, result));
cases.add(rdcspv::OpBranch(breakLabel));
}
func.add(rdcspv::OpSelectionMerge(breakLabel, rdcspv::SelectionControl::None));
func.add(rdcspv::OpSwitch32(opParam, defaultLabel, targets));
@@ -3723,6 +3723,22 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi
CHECK_PHYS_EXT_FEATURE(shaderAbort);
}
END_PHYS_EXT_CHECK();
BEGIN_PHYS_EXT_CHECK(VkPhysicalDeviceShaderFmaFeaturesKHR,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FMA_FEATURES_KHR);
{
CHECK_PHYS_EXT_FEATURE(shaderFmaFloat16);
CHECK_PHYS_EXT_FEATURE(shaderFmaFloat32);
CHECK_PHYS_EXT_FEATURE(shaderFmaFloat64);
if(ext->shaderFmaFloat16)
m_PreciseFMAMask |= 16;
if(ext->shaderFmaFloat32)
m_PreciseFMAMask |= 32;
if(ext->shaderFmaFloat64)
m_PreciseFMAMask |= 64;
}
END_PHYS_EXT_CHECK();
}
if(availFeatures.depthClamp)