|
@@ -77,6 +77,20 @@ ShaderModuleSpirV(Stage stage, std::vector<uint32_t> words, BamCacheRecord *reco
|
|
|
_used_caps |= C_atomic_counters;
|
|
_used_caps |= C_atomic_counters;
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
|
|
+ case spv::CapabilityUniformBufferArrayDynamicIndexing:
|
|
|
|
|
+ case spv::CapabilitySampledImageArrayDynamicIndexing:
|
|
|
|
|
+ case spv::CapabilityStorageBufferArrayDynamicIndexing:
|
|
|
|
|
+ case spv::CapabilityStorageImageArrayDynamicIndexing:
|
|
|
|
|
+ case spv::CapabilityInputAttachmentArrayDynamicIndexing:
|
|
|
|
|
+ case spv::CapabilityUniformTexelBufferArrayDynamicIndexing:
|
|
|
|
|
+ case spv::CapabilityStorageTexelBufferArrayDynamicIndexing:
|
|
|
|
|
+ // It would be great if we could rely on this and call this a day.
|
|
|
|
|
+ // However, glslang is not currently capable of detecting and generating
|
|
|
|
|
+ // this capability (see KhronosGroup/glslang#2056). So we still have to
|
|
|
|
|
+ // go through the trouble of determining this ourselves.
|
|
|
|
|
+ _used_caps |= C_dynamic_indexing;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
case spv::CapabilityClipDistance:
|
|
case spv::CapabilityClipDistance:
|
|
|
_used_caps |= C_clip_distance;
|
|
_used_caps |= C_clip_distance;
|
|
|
break;
|
|
break;
|
|
@@ -209,8 +223,14 @@ ShaderModuleSpirV(Stage stage, std::vector<uint32_t> words, BamCacheRecord *reco
|
|
|
case Texture::TT_2d_texture_array:
|
|
case Texture::TT_2d_texture_array:
|
|
|
_used_caps |= C_texture_array;
|
|
_used_caps |= C_texture_array;
|
|
|
break;
|
|
break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ if (def._flags & DF_dynamically_indexed &&
|
|
|
|
|
+ (sampled_image_type != nullptr || def._type->contains_opaque_type())) {
|
|
|
|
|
+ _used_caps |= C_dynamic_indexing;
|
|
|
|
|
+ }
|
|
|
_parameters.push_back(std::move(var));
|
|
_parameters.push_back(std::move(var));
|
|
|
}
|
|
}
|
|
|
else if (def._storage_class == spv::StorageClassStorageBuffer) {
|
|
else if (def._storage_class == spv::StorageClassStorageBuffer) {
|
|
@@ -332,6 +352,8 @@ ShaderModuleSpirV(Stage stage, std::vector<uint32_t> words, BamCacheRecord *reco
|
|
|
case spv::DecorationComponent:
|
|
case spv::DecorationComponent:
|
|
|
_used_caps |= C_enhanced_layouts;
|
|
_used_caps |= C_enhanced_layouts;
|
|
|
break;
|
|
break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -1144,6 +1166,7 @@ remove_unused_variables() {
|
|
|
case spv::OpAccessChain:
|
|
case spv::OpAccessChain:
|
|
|
case spv::OpInBoundsAccessChain:
|
|
case spv::OpInBoundsAccessChain:
|
|
|
case spv::OpPtrAccessChain:
|
|
case spv::OpPtrAccessChain:
|
|
|
|
|
+ case spv::OpInBoundsPtrAccessChain:
|
|
|
case spv::OpCopyObject:
|
|
case spv::OpCopyObject:
|
|
|
case spv::OpBitcast:
|
|
case spv::OpBitcast:
|
|
|
case spv::OpCopyLogical:
|
|
case spv::OpCopyLogical:
|
|
@@ -1264,6 +1287,7 @@ flatten_struct(uint32_t type_id) {
|
|
|
case spv::OpAccessChain:
|
|
case spv::OpAccessChain:
|
|
|
case spv::OpInBoundsAccessChain:
|
|
case spv::OpInBoundsAccessChain:
|
|
|
case spv::OpPtrAccessChain:
|
|
case spv::OpPtrAccessChain:
|
|
|
|
|
+ case spv::OpInBoundsPtrAccessChain:
|
|
|
if (deleted_ids.count(op.args[2])) {
|
|
if (deleted_ids.count(op.args[2])) {
|
|
|
uint32_t index = _defs[op.args[3]]._constant;
|
|
uint32_t index = _defs[op.args[3]]._constant;
|
|
|
if (op.nargs > 4) {
|
|
if (op.nargs > 4) {
|
|
@@ -2595,10 +2619,14 @@ parse_instruction(const Instruction &op, uint32_t ¤t_function_id) {
|
|
|
record_constant(op.args[1], op.args[0], nullptr, 0);
|
|
record_constant(op.args[1], op.args[0], nullptr, 0);
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
|
|
+ case spv::OpConstantComposite:
|
|
|
|
|
+ case spv::OpSpecConstantComposite:
|
|
|
|
|
+ modify_definition(op.args[1])._flags |= DF_constant_expression;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
case spv::OpSpecConstantTrue:
|
|
case spv::OpSpecConstantTrue:
|
|
|
case spv::OpSpecConstantFalse:
|
|
case spv::OpSpecConstantFalse:
|
|
|
case spv::OpSpecConstant:
|
|
case spv::OpSpecConstant:
|
|
|
- // A specialization constant.
|
|
|
|
|
record_spec_constant(op.args[1], op.args[0]);
|
|
record_spec_constant(op.args[1], op.args[0]);
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
@@ -2711,19 +2739,35 @@ parse_instruction(const Instruction &op, uint32_t ¤t_function_id) {
|
|
|
mark_used(op.args[0]);
|
|
mark_used(op.args[0]);
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
|
|
+ case spv::OpCopyMemory:
|
|
|
|
|
+ case spv::OpCopyMemorySized:
|
|
|
|
|
+ mark_used(op.args[0]);
|
|
|
|
|
+ mark_used(op.args[1]);
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
case spv::OpAccessChain:
|
|
case spv::OpAccessChain:
|
|
|
case spv::OpInBoundsAccessChain:
|
|
case spv::OpInBoundsAccessChain:
|
|
|
case spv::OpPtrAccessChain:
|
|
case spv::OpPtrAccessChain:
|
|
|
- case spv::OpCopyObject:
|
|
|
|
|
|
|
+ case spv::OpInBoundsPtrAccessChain:
|
|
|
// Record the access chain or pointer copy, so that as soon as something is
|
|
// Record the access chain or pointer copy, so that as soon as something is
|
|
|
// loaded through them we can transitively mark everything as "used".
|
|
// loaded through them we can transitively mark everything as "used".
|
|
|
record_temporary(op.args[1], op.args[0], op.args[2], current_function_id);
|
|
record_temporary(op.args[1], op.args[0], op.args[2], current_function_id);
|
|
|
|
|
+
|
|
|
|
|
+ // If one of the indices (including the base element for OpPtrAccessChain)
|
|
|
|
|
+ // isn't a constant expression, we mark the variable as dynamically-indexed.
|
|
|
|
|
+ for (size_t i = 3; i < op.nargs; ++i) {
|
|
|
|
|
+ if ((_defs[op.args[i]]._flags & DF_constant_expression) == 0) {
|
|
|
|
|
+ const Definition &def = get_definition(op.args[1]);
|
|
|
|
|
+ nassertv(def._origin_id != 0);
|
|
|
|
|
+ _defs[def._origin_id]._flags |= DF_dynamically_indexed;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
- case spv::OpCopyMemory:
|
|
|
|
|
- case spv::OpCopyMemorySized:
|
|
|
|
|
- mark_used(op.args[0]);
|
|
|
|
|
- mark_used(op.args[1]);
|
|
|
|
|
|
|
+ case spv::OpArrayLength:
|
|
|
|
|
+ case spv::OpConvertPtrToU:
|
|
|
|
|
+ mark_used(op.args[2]);
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case spv::OpDecorate:
|
|
case spv::OpDecorate:
|
|
@@ -2776,9 +2820,15 @@ parse_instruction(const Instruction &op, uint32_t ¤t_function_id) {
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
- case spv::OpArrayLength:
|
|
|
|
|
- case spv::OpConvertPtrToU:
|
|
|
|
|
- mark_used(op.args[2]);
|
|
|
|
|
|
|
+ case spv::OpCopyObject:
|
|
|
|
|
+ record_temporary(op.args[1], op.args[0], op.args[2], current_function_id);
|
|
|
|
|
+ // fall through
|
|
|
|
|
+
|
|
|
|
|
+ case spv::OpCompositeExtract:
|
|
|
|
|
+ // Composite types are used for some arithmetic ops.
|
|
|
|
|
+ if (_defs[op.args[2]]._flags & DF_constant_expression) {
|
|
|
|
|
+ _defs[op.args[1]]._flags |= DF_constant_expression;
|
|
|
|
|
+ }
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case spv::OpImageSampleImplicitLod:
|
|
case spv::OpImageSampleImplicitLod:
|
|
@@ -2821,13 +2871,6 @@ parse_instruction(const Instruction &op, uint32_t ¤t_function_id) {
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
- case spv::OpSelect:
|
|
|
|
|
- // This can in theory operate on pointers, which is why we handle this
|
|
|
|
|
- //mark_used(op.args[2]);
|
|
|
|
|
- mark_used(op.args[3]);
|
|
|
|
|
- mark_used(op.args[4]);
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
case spv::OpBitcast:
|
|
case spv::OpBitcast:
|
|
|
record_temporary(op.args[1], op.args[0], op.args[2], current_function_id);
|
|
record_temporary(op.args[1], op.args[0], op.args[2], current_function_id);
|
|
|
|
|
|
|
@@ -2835,6 +2878,79 @@ parse_instruction(const Instruction &op, uint32_t ¤t_function_id) {
|
|
|
if (_defs[op.args[0]]._dtype != DT_type_pointer) {
|
|
if (_defs[op.args[0]]._dtype != DT_type_pointer) {
|
|
|
mark_used(op.args[1]);
|
|
mark_used(op.args[1]);
|
|
|
}
|
|
}
|
|
|
|
|
+ // fall through, counts as unary arithmetic
|
|
|
|
|
+ case spv::OpConvertFToU:
|
|
|
|
|
+ case spv::OpConvertFToS:
|
|
|
|
|
+ case spv::OpConvertSToF:
|
|
|
|
|
+ case spv::OpConvertUToF:
|
|
|
|
|
+ case spv::OpQuantizeToF16:
|
|
|
|
|
+ case spv::OpSatConvertSToU:
|
|
|
|
|
+ case spv::OpSatConvertUToS:
|
|
|
|
|
+ case spv::OpConvertUToPtr:
|
|
|
|
|
+ case spv::OpSNegate:
|
|
|
|
|
+ case spv::OpFNegate:
|
|
|
|
|
+ case spv::OpAny:
|
|
|
|
|
+ case spv::OpAll:
|
|
|
|
|
+ case spv::OpIsNan:
|
|
|
|
|
+ case spv::OpIsInf:
|
|
|
|
|
+ case spv::OpIsFinite:
|
|
|
|
|
+ case spv::OpIsNormal:
|
|
|
|
|
+ case spv::OpSignBitSet:
|
|
|
|
|
+ case spv::OpNot:
|
|
|
|
|
+ if ((_defs[op.args[2]]._flags & DF_constant_expression) != 0) {
|
|
|
|
|
+ _defs[op.args[1]]._flags |= DF_constant_expression;
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ // Binary arithmetic operators
|
|
|
|
|
+ case spv::OpIAdd:
|
|
|
|
|
+ case spv::OpFAdd:
|
|
|
|
|
+ case spv::OpISub:
|
|
|
|
|
+ case spv::OpFSub:
|
|
|
|
|
+ case spv::OpIMul:
|
|
|
|
|
+ case spv::OpFMul:
|
|
|
|
|
+ case spv::OpUDiv:
|
|
|
|
|
+ case spv::OpSDiv:
|
|
|
|
|
+ case spv::OpFDiv:
|
|
|
|
|
+ case spv::OpUMod:
|
|
|
|
|
+ case spv::OpSRem:
|
|
|
|
|
+ case spv::OpSMod:
|
|
|
|
|
+ case spv::OpFRem:
|
|
|
|
|
+ case spv::OpFMod:
|
|
|
|
|
+ case spv::OpVectorTimesScalar:
|
|
|
|
|
+ case spv::OpMatrixTimesScalar:
|
|
|
|
|
+ case spv::OpVectorTimesMatrix:
|
|
|
|
|
+ case spv::OpMatrixTimesVector:
|
|
|
|
|
+ case spv::OpMatrixTimesMatrix:
|
|
|
|
|
+ case spv::OpOuterProduct:
|
|
|
|
|
+ case spv::OpDot:
|
|
|
|
|
+ case spv::OpIAddCarry:
|
|
|
|
|
+ case spv::OpISubBorrow:
|
|
|
|
|
+ case spv::OpUMulExtended:
|
|
|
|
|
+ case spv::OpSMulExtended:
|
|
|
|
|
+ case spv::OpShiftRightLogical:
|
|
|
|
|
+ case spv::OpShiftRightArithmetic:
|
|
|
|
|
+ case spv::OpShiftLeftLogical:
|
|
|
|
|
+ case spv::OpBitwiseOr:
|
|
|
|
|
+ case spv::OpBitwiseXor:
|
|
|
|
|
+ case spv::OpBitwiseAnd:
|
|
|
|
|
+ if ((_defs[op.args[2]]._flags & DF_constant_expression) != 0 &&
|
|
|
|
|
+ (_defs[op.args[3]]._flags & DF_constant_expression) != 0) {
|
|
|
|
|
+ _defs[op.args[1]]._flags |= DF_constant_expression;
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case spv::OpSelect:
|
|
|
|
|
+ // This can in theory operate on pointers, which is why we handle this
|
|
|
|
|
+ //mark_used(op.args[2]);
|
|
|
|
|
+ mark_used(op.args[3]);
|
|
|
|
|
+ mark_used(op.args[4]);
|
|
|
|
|
+
|
|
|
|
|
+ if ((_defs[op.args[2]]._flags & DF_constant_expression) != 0 &&
|
|
|
|
|
+ (_defs[op.args[3]]._flags & DF_constant_expression) != 0 &&
|
|
|
|
|
+ (_defs[op.args[4]]._flags & DF_constant_expression) != 0) {
|
|
|
|
|
+ _defs[op.args[1]]._flags |= DF_constant_expression;
|
|
|
|
|
+ }
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case spv::OpReturnValue:
|
|
case spv::OpReturnValue:
|
|
@@ -2985,6 +3101,7 @@ record_constant(uint32_t id, uint32_t type_id, const uint32_t *words, uint32_t n
|
|
|
def._type_id = type_id;
|
|
def._type_id = type_id;
|
|
|
def._type = (type_def._dtype == DT_type) ? type_def._type : nullptr;
|
|
def._type = (type_def._dtype == DT_type) ? type_def._type : nullptr;
|
|
|
def._constant = (nwords > 0) ? words[0] : 0;
|
|
def._constant = (nwords > 0) ? words[0] : 0;
|
|
|
|
|
+ def._flags |= DF_constant_expression;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -3051,6 +3168,7 @@ record_spec_constant(uint32_t id, uint32_t type_id) {
|
|
|
def._dtype = DT_spec_constant;
|
|
def._dtype = DT_spec_constant;
|
|
|
def._type_id = type_id;
|
|
def._type_id = type_id;
|
|
|
def._type = type_def._type;
|
|
def._type = type_def._type;
|
|
|
|
|
+ def._flags |= DF_constant_expression;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|