Skip to content

Commit da0ec29

Browse files
authored
Revert array location validation (KhronosGroup#6187)
* Revert "Fix calculation of locations for matrices (KhronosGroup#6062)" This reverts commit ada1771. * Revert "Update location/component conflict validation (KhronosGroup#5993)" This reverts commit ba1359d.
1 parent 3f76afc commit da0ec29

File tree

3 files changed

+88
-159
lines changed

3 files changed

+88
-159
lines changed

source/val/validate_interfaces.cpp

Lines changed: 84 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -166,20 +166,17 @@ spv_result_t NumConsumedLocations(ValidationState_t& _, const Instruction* type,
166166
}
167167
break;
168168
case spv::Op::OpTypeMatrix:
169-
// Matrices consume locations equivalent to arrays.
170-
if (auto error = NumConsumedLocations(
171-
_, _.FindDef(type->GetOperandAs<uint32_t>(1)), num_locations)) {
172-
return error;
173-
}
169+
// Matrices consume locations equal to the underlying vector type for
170+
// each column.
171+
NumConsumedLocations(_, _.FindDef(type->GetOperandAs<uint32_t>(1)),
172+
num_locations);
174173
*num_locations *= type->GetOperandAs<uint32_t>(2);
175174
break;
176175
case spv::Op::OpTypeArray: {
177176
// Arrays consume locations equal to the underlying type times the number
178177
// of elements in the vector.
179-
if (auto error = NumConsumedLocations(
180-
_, _.FindDef(type->GetOperandAs<uint32_t>(1)), num_locations)) {
181-
return error;
182-
}
178+
NumConsumedLocations(_, _.FindDef(type->GetOperandAs<uint32_t>(1)),
179+
num_locations);
183180
bool is_int = false;
184181
bool is_const = false;
185182
uint32_t value = 0;
@@ -249,31 +246,10 @@ uint32_t NumConsumedComponents(ValidationState_t& _, const Instruction* type) {
249246
NumConsumedComponents(_, _.FindDef(type->GetOperandAs<uint32_t>(1)));
250247
num_components *= type->GetOperandAs<uint32_t>(2);
251248
break;
252-
case spv::Op::OpTypeMatrix:
253-
// Matrices consume all components of the location.
254-
// Round up to next multiple of 4.
255-
num_components =
256-
NumConsumedComponents(_, _.FindDef(type->GetOperandAs<uint32_t>(1)));
257-
num_components *= type->GetOperandAs<uint32_t>(2);
258-
num_components = ((num_components + 3) / 4) * 4;
259-
break;
260-
case spv::Op::OpTypeArray: {
261-
// Arrays consume all components of the location.
262-
// Round up to next multiple of 4.
263-
num_components =
264-
NumConsumedComponents(_, _.FindDef(type->GetOperandAs<uint32_t>(1)));
265-
266-
bool is_int = false;
267-
bool is_const = false;
268-
uint32_t value = 0;
269-
// Attempt to evaluate the number of array elements.
270-
std::tie(is_int, is_const, value) =
271-
_.EvalInt32IfConst(type->GetOperandAs<uint32_t>(2));
272-
if (is_int && is_const) num_components *= value;
273-
274-
num_components = ((num_components + 3) / 4) * 4;
275-
return num_components;
276-
}
249+
case spv::Op::OpTypeArray:
250+
// Skip the array.
251+
return NumConsumedComponents(_,
252+
_.FindDef(type->GetOperandAs<uint32_t>(1)));
277253
case spv::Op::OpTypePointer:
278254
if (_.addressing_model() ==
279255
spv::AddressingModel::PhysicalStorageBuffer64 &&
@@ -356,10 +332,9 @@ spv_result_t GetLocationsForVariable(
356332
}
357333
}
358334

359-
// Vulkan 15.1.3 (Interface Matching): Tessellation control and mesh
360-
// per-vertex outputs and tessellation control, evaluation and geometry
361-
// per-vertex inputs have a layer of arraying that is not included in
362-
// interface matching.
335+
// Vulkan 14.1.3: Tessellation control and mesh per-vertex outputs and
336+
// tessellation control, evaluation and geometry per-vertex inputs have a
337+
// layer of arraying that is not included in interface matching.
363338
bool is_arrayed = false;
364339
switch (entry_point->GetOperandAs<spv::ExecutionModel>(0)) {
365340
case spv::ExecutionModel::TessellationControl:
@@ -413,33 +388,51 @@ spv_result_t GetLocationsForVariable(
413388

414389
const std::string storage_class = is_output ? "output" : "input";
415390
if (has_location) {
391+
auto sub_type = type;
392+
bool is_int = false;
393+
bool is_const = false;
394+
uint32_t array_size = 1;
395+
// If the variable is still arrayed, mark the locations/components per
396+
// index.
397+
if (type->opcode() == spv::Op::OpTypeArray) {
398+
// Determine the array size if possible and get the element type.
399+
std::tie(is_int, is_const, array_size) =
400+
_.EvalInt32IfConst(type->GetOperandAs<uint32_t>(2));
401+
if (!is_int || !is_const) array_size = 1;
402+
auto sub_type_id = type->GetOperandAs<uint32_t>(1);
403+
sub_type = _.FindDef(sub_type_id);
404+
}
405+
416406
uint32_t num_locations = 0;
417-
if (auto error = NumConsumedLocations(_, type, &num_locations))
407+
if (auto error = NumConsumedLocations(_, sub_type, &num_locations))
418408
return error;
419-
uint32_t num_components = NumConsumedComponents(_, type);
409+
uint32_t num_components = NumConsumedComponents(_, sub_type);
420410

421-
uint32_t start = location * 4;
422-
uint32_t end = (location + num_locations) * 4;
423-
if (num_components % 4 != 0) {
424-
start += component;
425-
end = start + num_components;
426-
}
411+
for (uint32_t array_idx = 0; array_idx < array_size; ++array_idx) {
412+
uint32_t array_location = location + (num_locations * array_idx);
413+
uint32_t start = array_location * 4;
414+
if (kMaxLocations <= start) {
415+
// Too many locations, give up.
416+
break;
417+
}
427418

428-
if (kMaxLocations <= start) {
429-
// Too many locations, give up.
430-
return SPV_SUCCESS;
431-
}
419+
uint32_t end = (array_location + num_locations) * 4;
420+
if (num_components != 0) {
421+
start += component;
422+
end = array_location * 4 + component + num_components;
423+
}
432424

433-
auto locs = locations;
434-
if (has_index && index == 1) locs = output_index1_locations;
425+
auto locs = locations;
426+
if (has_index && index == 1) locs = output_index1_locations;
435427

436-
for (uint32_t i = start; i < end; ++i) {
437-
if (!locs->insert(i).second) {
438-
return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
439-
<< (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
440-
<< "Entry-point has conflicting " << storage_class
441-
<< " location assignment at location " << i / 4 << ", component "
442-
<< i % 4;
428+
for (uint32_t i = start; i < end; ++i) {
429+
if (!locs->insert(i).second) {
430+
return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
431+
<< (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
432+
<< "Entry-point has conflicting " << storage_class
433+
<< " location assignment at location " << i / 4
434+
<< ", component " << i % 4;
435+
}
443436
}
444437
}
445438
} else {
@@ -498,19 +491,38 @@ spv_result_t GetLocationsForVariable(
498491
continue;
499492
}
500493

501-
uint32_t end = (location + num_locations) * 4;
502-
if (num_components % 4 != 0) {
503-
start += component;
504-
end = location * 4 + component + num_components;
505-
}
506-
507-
for (uint32_t l = start; l < end; ++l) {
508-
if (!locations->insert(l).second) {
509-
return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
510-
<< (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
511-
<< "Entry-point has conflicting " << storage_class
512-
<< " location assignment at location " << l / 4
513-
<< ", component " << l % 4;
494+
if (member->opcode() == spv::Op::OpTypeArray && num_components >= 1 &&
495+
num_components < 4) {
496+
// When an array has an element that takes less than a location in
497+
// size, calculate the used locations in a strided manner.
498+
for (uint32_t l = location; l < num_locations + location; ++l) {
499+
for (uint32_t c = component; c < component + num_components; ++c) {
500+
uint32_t check = 4 * l + c;
501+
if (!locations->insert(check).second) {
502+
return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
503+
<< (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
504+
<< "Entry-point has conflicting " << storage_class
505+
<< " location assignment at location " << l
506+
<< ", component " << c;
507+
}
508+
}
509+
}
510+
} else {
511+
// TODO: There is a hole here is the member is an array of 3- or
512+
// 4-element vectors of 64-bit types.
513+
uint32_t end = (location + num_locations) * 4;
514+
if (num_components != 0) {
515+
start += component;
516+
end = location * 4 + component + num_components;
517+
}
518+
for (uint32_t l = start; l < end; ++l) {
519+
if (!locations->insert(l).second) {
520+
return _.diag(SPV_ERROR_INVALID_DATA, entry_point)
521+
<< (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721))
522+
<< "Entry-point has conflicting " << storage_class
523+
<< " location assignment at location " << l / 4
524+
<< ", component " << l % 4;
525+
}
514526
}
515527
}
516528
}

test/val/val_decoration_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10394,7 +10394,7 @@ TEST_F(ValidateDecorations, ComponentMultipleArrays) {
1039410394
OpDecorate %gl_PerVertex Block
1039510395
OpDecorate %FOO Component 2
1039610396
OpDecorate %FOO Location 1
10397-
OpDecorate %FOO0 Location 4
10397+
OpDecorate %FOO0 Location 1
1039810398
OpDecorate %FOO0 Component 0
1039910399
%void = OpTypeVoid
1040010400
%3 = OpTypeFunction %void

test/val/val_interfaces_test.cpp

Lines changed: 3 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,12 +1415,7 @@ OpFunctionEnd
14151415
)";
14161416

14171417
CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1418-
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1419-
EXPECT_THAT(getDiagnosticString(),
1420-
AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08722"));
1421-
EXPECT_THAT(getDiagnosticString(),
1422-
HasSubstr("Entry-point has conflicting output location "
1423-
"assignment at location 0, component 0"));
1418+
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
14241419
}
14251420

14261421
TEST_F(ValidateInterfacesTest, VulkanLocationsArrayWithComponentBad) {
@@ -1433,7 +1428,7 @@ OpDecorate %11 Location 0
14331428
OpDecorate %18 Component 0
14341429
OpDecorate %18 Location 0
14351430
OpDecorate %28 Component 1
1436-
OpDecorate %28 Location 1
1431+
OpDecorate %28 Location 0
14371432
OpDecorate %36 Location 1
14381433
OpDecorate %40 Component 1
14391434
OpDecorate %40 Location 1
@@ -1548,12 +1543,7 @@ OpFunctionEnd
15481543
)";
15491544

15501545
CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1551-
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1552-
EXPECT_THAT(getDiagnosticString(),
1553-
AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
1554-
EXPECT_THAT(getDiagnosticString(),
1555-
HasSubstr("Entry-point has conflicting input location "
1556-
"assignment at location 0, component 0"));
1546+
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
15571547
}
15581548

15591549
TEST_F(ValidateInterfacesTest, VulkanLocationArrayWithComponent2) {
@@ -1582,85 +1572,12 @@ OpMemberDecorate %struct 1 Component 2
15821572
%entry = OpLabel
15831573
OpReturn
15841574
OpFunctionEnd
1585-
)";
1586-
1587-
CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1588-
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1589-
EXPECT_THAT(getDiagnosticString(),
1590-
AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
1591-
EXPECT_THAT(getDiagnosticString(),
1592-
HasSubstr("Entry-point has conflicting input location "
1593-
"assignment at location 0, component 0"));
1594-
}
1595-
1596-
TEST_F(ValidateInterfacesTest, VulkanLocationMatrix2x2DoubleGood) {
1597-
const std::string text = R"(
1598-
OpCapability Shader
1599-
OpCapability Float64
1600-
OpMemoryModel Logical GLSL450
1601-
OpEntryPoint Fragment %main "main" %in
1602-
OpExecutionMode %main OriginUpperLeft
1603-
OpDecorate %struct Block
1604-
OpMemberDecorate %struct 0 Location 0
1605-
OpMemberDecorate %struct 1 Location 2
1606-
%void = OpTypeVoid
1607-
%void_fn = OpTypeFunction %void
1608-
%float = OpTypeFloat 32
1609-
%double = OpTypeFloat 64
1610-
%int = OpTypeInt 32 0
1611-
%int_2 = OpConstant %int 2
1612-
%double2 = OpTypeVector %double 2
1613-
%mat2x2_double = OpTypeMatrix %double2 2
1614-
%struct = OpTypeStruct %mat2x2_double %int
1615-
%ptr = OpTypePointer Input %struct
1616-
%in = OpVariable %ptr Input
1617-
%main = OpFunction %void None %void_fn
1618-
%entry = OpLabel
1619-
OpReturn
1620-
OpFunctionEnd
16211575
)";
16221576

16231577
CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
16241578
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
16251579
}
16261580

1627-
TEST_F(ValidateInterfacesTest, VulkanLocationMatrix2x2DoubleBad) {
1628-
const std::string text = R"(
1629-
OpCapability Shader
1630-
OpCapability Float64
1631-
OpMemoryModel Logical GLSL450
1632-
OpEntryPoint Fragment %main "main" %in
1633-
OpExecutionMode %main OriginUpperLeft
1634-
OpDecorate %struct Block
1635-
OpMemberDecorate %struct 0 Location 0
1636-
OpMemberDecorate %struct 1 Location 1
1637-
OpMemberDecorate %struct 1 Component 3
1638-
%void = OpTypeVoid
1639-
%void_fn = OpTypeFunction %void
1640-
%float = OpTypeFloat 32
1641-
%double = OpTypeFloat 64
1642-
%int = OpTypeInt 32 0
1643-
%int_2 = OpConstant %int 2
1644-
%double2 = OpTypeVector %double 2
1645-
%mat2x2_double = OpTypeMatrix %double2 2
1646-
%struct = OpTypeStruct %mat2x2_double %int
1647-
%ptr = OpTypePointer Input %struct
1648-
%in = OpVariable %ptr Input
1649-
%main = OpFunction %void None %void_fn
1650-
%entry = OpLabel
1651-
OpReturn
1652-
OpFunctionEnd
1653-
)";
1654-
1655-
CompileSuccessfully(text, SPV_ENV_VULKAN_1_0);
1656-
EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
1657-
EXPECT_THAT(getDiagnosticString(),
1658-
AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721"));
1659-
EXPECT_THAT(getDiagnosticString(),
1660-
HasSubstr("Entry-point has conflicting input location "
1661-
"assignment at location 1, component 3"));
1662-
}
1663-
16641581
TEST_F(ValidateInterfacesTest, DuplicateInterfaceVariableSuccess) {
16651582
const std::string text = R"(
16661583
OpCapability Shader

0 commit comments

Comments
 (0)