blob: c8a23b9f19534fecac7852b47fd9f814864b4e07 [file] [log] [blame]
Tony-LunarG73719992020-01-15 10:20:28 -07001/* Copyright (c) 2015-2020 The Khronos Group Inc.
2 * Copyright (c) 2015-2020 Valve Corporation
3 * Copyright (c) 2015-2020 LunarG, Inc.
4 * Copyright (C) 2015-2020 Google Inc.
Tobias Hector6663c9b2020-11-05 10:18:02 +00005 * Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
Chris Forbes47567b72017-06-09 12:09:45 -07006 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * Author: Chris Forbes <chrisf@ijw.co.nz>
Dave Houlton51653902018-06-22 17:32:13 -060020 * Author: Dave Houlton <daveh@lunarg.com>
Tobias Hector6663c9b2020-11-05 10:18:02 +000021 * Author: Tobias Hector <tobias.hector@amd.com>
Chris Forbes47567b72017-06-09 12:09:45 -070022 */
23
Petr Kraus25810d02019-08-27 17:41:15 +020024#include "shader_validation.h"
25
Chris Forbes47567b72017-06-09 12:09:45 -070026#include <cassert>
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +020027#include <chrono>
Petr Kraus25810d02019-08-27 17:41:15 +020028#include <cinttypes>
Jeff Bolzf234bf82019-11-04 14:07:15 -060029#include <cmath>
Petr Kraus25810d02019-08-27 17:41:15 +020030#include <map>
Chris Forbes47567b72017-06-09 12:09:45 -070031#include <sstream>
Petr Kraus25810d02019-08-27 17:41:15 +020032#include <string>
33#include <unordered_map>
34#include <vector>
35
Mark Lobodzinski102687e2020-04-28 11:03:28 -060036#include <spirv/unified1/spirv.hpp>
Chris Forbes47567b72017-06-09 12:09:45 -070037#include "vk_loader_platform.h"
38#include "vk_enum_string_helper.h"
Chris Forbes47567b72017-06-09 12:09:45 -070039#include "vk_layer_data.h"
40#include "vk_layer_extension_utils.h"
41#include "vk_layer_utils.h"
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -070042#include "chassis.h"
Chris Forbes47567b72017-06-09 12:09:45 -070043#include "core_validation.h"
Petr Kraus25810d02019-08-27 17:41:15 +020044
Chris Forbes4ae55b32017-06-09 14:42:56 -070045#include "spirv-tools/libspirv.h"
Chris Forbes9a61e082017-07-24 15:35:29 -070046#include "xxhash.h"
Chris Forbes47567b72017-06-09 12:09:45 -070047
Chris Forbes8a6d8cb2019-02-14 14:33:08 -080048void decoration_set::add(uint32_t decoration, uint32_t value) {
49 switch (decoration) {
50 case spv::DecorationLocation:
51 flags |= location_bit;
52 location = value;
53 break;
54 case spv::DecorationPatch:
55 flags |= patch_bit;
56 break;
57 case spv::DecorationRelaxedPrecision:
58 flags |= relaxed_precision_bit;
59 break;
60 case spv::DecorationBlock:
61 flags |= block_bit;
62 break;
63 case spv::DecorationBufferBlock:
64 flags |= buffer_block_bit;
65 break;
66 case spv::DecorationComponent:
67 flags |= component_bit;
68 component = value;
69 break;
70 case spv::DecorationInputAttachmentIndex:
71 flags |= input_attachment_index_bit;
72 input_attachment_index = value;
73 break;
74 case spv::DecorationDescriptorSet:
75 flags |= descriptor_set_bit;
76 descriptor_set = value;
77 break;
78 case spv::DecorationBinding:
79 flags |= binding_bit;
80 binding = value;
81 break;
82 case spv::DecorationNonWritable:
83 flags |= nonwritable_bit;
84 break;
85 case spv::DecorationBuiltIn:
86 flags |= builtin_bit;
87 builtin = value;
88 break;
89 }
90}
91
Chris Forbes47567b72017-06-09 12:09:45 -070092enum FORMAT_TYPE {
93 FORMAT_TYPE_FLOAT = 1, // UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader
94 FORMAT_TYPE_SINT = 2,
95 FORMAT_TYPE_UINT = 4,
96};
97
98typedef std::pair<unsigned, unsigned> location_t;
99
Chris Forbes47567b72017-06-09 12:09:45 -0700100static shader_stage_attributes shader_stage_attribs[] = {
Ari Suonpaa696b3432019-03-11 14:02:57 +0200101 {"vertex shader", false, false, VK_SHADER_STAGE_VERTEX_BIT},
102 {"tessellation control shader", true, true, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT},
103 {"tessellation evaluation shader", true, false, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT},
104 {"geometry shader", true, false, VK_SHADER_STAGE_GEOMETRY_BIT},
105 {"fragment shader", false, false, VK_SHADER_STAGE_FRAGMENT_BIT},
Chris Forbes47567b72017-06-09 12:09:45 -0700106};
107
John Zulauf14c355b2019-06-27 16:09:37 -0600108unsigned ExecutionModelToShaderStageFlagBits(unsigned mode);
109
Chris Forbes47567b72017-06-09 12:09:45 -0700110// SPIRV utility functions
Mark Lobodzinski3c59d972019-04-25 11:28:14 -0600111void SHADER_MODULE_STATE::BuildDefIndex() {
locke-lunargde3f0fa2020-09-10 11:55:31 -0600112 function_set func_set = {};
113 EntryPoint *entry_point = nullptr;
114
Chris Forbes47567b72017-06-09 12:09:45 -0700115 for (auto insn : *this) {
locke-lunargde3f0fa2020-09-10 11:55:31 -0600116 // offset is not 0, it means it's updated and the offset is in a Function.
117 if (func_set.offset)
118 func_set.op_lists.insert({insn.opcode(), insn.offset()});
119 else if (entry_point) {
120 entry_point->decorate_list.insert({insn.opcode(), insn.offset()});
121 }
122
Chris Forbes47567b72017-06-09 12:09:45 -0700123 switch (insn.opcode()) {
124 // Types
125 case spv::OpTypeVoid:
126 case spv::OpTypeBool:
127 case spv::OpTypeInt:
128 case spv::OpTypeFloat:
129 case spv::OpTypeVector:
130 case spv::OpTypeMatrix:
131 case spv::OpTypeImage:
132 case spv::OpTypeSampler:
133 case spv::OpTypeSampledImage:
134 case spv::OpTypeArray:
135 case spv::OpTypeRuntimeArray:
136 case spv::OpTypeStruct:
137 case spv::OpTypeOpaque:
138 case spv::OpTypePointer:
139 case spv::OpTypeFunction:
140 case spv::OpTypeEvent:
141 case spv::OpTypeDeviceEvent:
142 case spv::OpTypeReserveId:
143 case spv::OpTypeQueue:
144 case spv::OpTypePipe:
Shannon McPherson0fa28232018-11-01 11:59:02 -0600145 case spv::OpTypeAccelerationStructureNV:
Jeff Bolze4356752019-03-07 11:23:46 -0600146 case spv::OpTypeCooperativeMatrixNV:
Chris Forbes47567b72017-06-09 12:09:45 -0700147 def_index[insn.word(1)] = insn.offset();
148 break;
149
150 // Fixed constants
151 case spv::OpConstantTrue:
152 case spv::OpConstantFalse:
153 case spv::OpConstant:
154 case spv::OpConstantComposite:
155 case spv::OpConstantSampler:
156 case spv::OpConstantNull:
157 def_index[insn.word(2)] = insn.offset();
158 break;
159
160 // Specialization constants
161 case spv::OpSpecConstantTrue:
162 case spv::OpSpecConstantFalse:
163 case spv::OpSpecConstant:
164 case spv::OpSpecConstantComposite:
165 case spv::OpSpecConstantOp:
166 def_index[insn.word(2)] = insn.offset();
167 break;
168
169 // Variables
170 case spv::OpVariable:
171 def_index[insn.word(2)] = insn.offset();
172 break;
173
174 // Functions
175 case spv::OpFunction:
176 def_index[insn.word(2)] = insn.offset();
locke-lunargde3f0fa2020-09-10 11:55:31 -0600177 func_set.id = insn.word(2);
178 func_set.offset = insn.offset();
179 func_set.op_lists.clear();
Chris Forbes47567b72017-06-09 12:09:45 -0700180 break;
181
Chris Forbes8a6d8cb2019-02-14 14:33:08 -0800182 // Decorations
183 case spv::OpDecorate: {
184 auto targetId = insn.word(1);
185 decorations[targetId].add(insn.word(2), insn.len() > 3u ? insn.word(3) : 0u);
186 } break;
187 case spv::OpGroupDecorate: {
188 auto const &src = decorations[insn.word(1)];
189 for (auto i = 2u; i < insn.len(); i++) decorations[insn.word(i)].merge(src);
190 } break;
191
John Zulauf14c355b2019-06-27 16:09:37 -0600192 // Entry points ... add to the entrypoint table
193 case spv::OpEntryPoint: {
194 // Entry points do not have an id (the id is the function id) and thus need their own table
195 auto entrypoint_name = (char const *)&insn.word(3);
196 auto execution_model = insn.word(1);
197 auto entrypoint_stage = ExecutionModelToShaderStageFlagBits(execution_model);
locke-lunargde3f0fa2020-09-10 11:55:31 -0600198 entry_points.emplace(entrypoint_name,
199 EntryPoint{insn.offset(), static_cast<VkShaderStageFlagBits>(entrypoint_stage)});
200
201 auto range = entry_points.equal_range(entrypoint_name);
202 for (auto it = range.first; it != range.second; ++it) {
203 if (it->second.offset == insn.offset()) {
204 entry_point = &(it->second);
205 break;
206 }
207 }
208 assert(entry_point != nullptr);
209 break;
210 }
211 case spv::OpFunctionEnd: {
212 assert(entry_point != nullptr);
213 func_set.length = insn.offset() - func_set.offset;
214 entry_point->function_set_list.emplace_back(func_set);
John Zulauf14c355b2019-06-27 16:09:37 -0600215 break;
216 }
Chris Forbes8a6d8cb2019-02-14 14:33:08 -0800217
Chris Forbes47567b72017-06-09 12:09:45 -0700218 default:
219 // We don't care about any other defs for now.
220 break;
221 }
222 }
223}
224
Jeff Bolz105d6492018-09-29 15:46:44 -0500225unsigned ExecutionModelToShaderStageFlagBits(unsigned mode) {
226 switch (mode) {
227 case spv::ExecutionModelVertex:
228 return VK_SHADER_STAGE_VERTEX_BIT;
229 case spv::ExecutionModelTessellationControl:
230 return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
231 case spv::ExecutionModelTessellationEvaluation:
232 return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
233 case spv::ExecutionModelGeometry:
234 return VK_SHADER_STAGE_GEOMETRY_BIT;
235 case spv::ExecutionModelFragment:
236 return VK_SHADER_STAGE_FRAGMENT_BIT;
237 case spv::ExecutionModelGLCompute:
238 return VK_SHADER_STAGE_COMPUTE_BIT;
Shannon McPherson0fa28232018-11-01 11:59:02 -0600239 case spv::ExecutionModelRayGenerationNV:
Eric Werness30127fd2018-10-31 21:01:03 -0700240 return VK_SHADER_STAGE_RAYGEN_BIT_NV;
Shannon McPherson0fa28232018-11-01 11:59:02 -0600241 case spv::ExecutionModelAnyHitNV:
Eric Werness30127fd2018-10-31 21:01:03 -0700242 return VK_SHADER_STAGE_ANY_HIT_BIT_NV;
Shannon McPherson0fa28232018-11-01 11:59:02 -0600243 case spv::ExecutionModelClosestHitNV:
Eric Werness30127fd2018-10-31 21:01:03 -0700244 return VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
Shannon McPherson0fa28232018-11-01 11:59:02 -0600245 case spv::ExecutionModelMissNV:
Eric Werness30127fd2018-10-31 21:01:03 -0700246 return VK_SHADER_STAGE_MISS_BIT_NV;
Shannon McPherson0fa28232018-11-01 11:59:02 -0600247 case spv::ExecutionModelIntersectionNV:
Eric Werness30127fd2018-10-31 21:01:03 -0700248 return VK_SHADER_STAGE_INTERSECTION_BIT_NV;
Shannon McPherson0fa28232018-11-01 11:59:02 -0600249 case spv::ExecutionModelCallableNV:
Eric Werness30127fd2018-10-31 21:01:03 -0700250 return VK_SHADER_STAGE_CALLABLE_BIT_NV;
Jeff Bolz105d6492018-09-29 15:46:44 -0500251 case spv::ExecutionModelTaskNV:
252 return VK_SHADER_STAGE_TASK_BIT_NV;
253 case spv::ExecutionModelMeshNV:
254 return VK_SHADER_STAGE_MESH_BIT_NV;
255 default:
256 return 0;
257 }
258}
259
locke-lunargde3f0fa2020-09-10 11:55:31 -0600260const SHADER_MODULE_STATE::EntryPoint *FindEntrypointStruct(SHADER_MODULE_STATE const *src, char const *name,
261 VkShaderStageFlagBits stageBits) {
262 auto range = src->entry_points.equal_range(name);
263 for (auto it = range.first; it != range.second; ++it) {
264 if (it->second.stage == stageBits) {
265 return &(it->second);
266 }
267 }
268 return nullptr;
269}
270
locke-lunargd9a069d2019-09-17 01:50:19 -0600271spirv_inst_iter FindEntrypoint(SHADER_MODULE_STATE const *src, char const *name, VkShaderStageFlagBits stageBits) {
John Zulauf14c355b2019-06-27 16:09:37 -0600272 auto range = src->entry_points.equal_range(name);
273 for (auto it = range.first; it != range.second; ++it) {
274 if (it->second.stage == stageBits) {
275 return src->at(it->second.offset);
Chris Forbes47567b72017-06-09 12:09:45 -0700276 }
277 }
Chris Forbes47567b72017-06-09 12:09:45 -0700278 return src->end();
279}
280
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600281static char const *StorageClassName(unsigned sc) {
Chris Forbes47567b72017-06-09 12:09:45 -0700282 switch (sc) {
283 case spv::StorageClassInput:
284 return "input";
285 case spv::StorageClassOutput:
286 return "output";
287 case spv::StorageClassUniformConstant:
288 return "const uniform";
289 case spv::StorageClassUniform:
290 return "uniform";
291 case spv::StorageClassWorkgroup:
292 return "workgroup local";
293 case spv::StorageClassCrossWorkgroup:
294 return "workgroup global";
295 case spv::StorageClassPrivate:
296 return "private global";
297 case spv::StorageClassFunction:
298 return "function";
299 case spv::StorageClassGeneric:
300 return "generic";
301 case spv::StorageClassAtomicCounter:
302 return "atomic counter";
303 case spv::StorageClassImage:
304 return "image";
305 case spv::StorageClassPushConstant:
306 return "push constant";
Chris Forbes9f89d752018-03-07 12:57:48 -0800307 case spv::StorageClassStorageBuffer:
308 return "storage buffer";
Chris Forbes47567b72017-06-09 12:09:45 -0700309 default:
310 return "unknown";
311 }
312}
313
314// Get the value of an integral constant
Mark Lobodzinski3c59d972019-04-25 11:28:14 -0600315unsigned GetConstantValue(SHADER_MODULE_STATE const *src, unsigned id) {
Chris Forbes47567b72017-06-09 12:09:45 -0700316 auto value = src->get_def(id);
317 assert(value != src->end());
318
319 if (value.opcode() != spv::OpConstant) {
320 // TODO: Either ensure that the specialization transform is already performed on a module we're
321 // considering here, OR -- specialize on the fly now.
322 return 1;
323 }
324
325 return value.word(3);
326}
327
Mark Lobodzinski3c59d972019-04-25 11:28:14 -0600328static void DescribeTypeInner(std::ostringstream &ss, SHADER_MODULE_STATE const *src, unsigned type) {
Chris Forbes47567b72017-06-09 12:09:45 -0700329 auto insn = src->get_def(type);
330 assert(insn != src->end());
331
332 switch (insn.opcode()) {
333 case spv::OpTypeBool:
334 ss << "bool";
335 break;
336 case spv::OpTypeInt:
337 ss << (insn.word(3) ? 's' : 'u') << "int" << insn.word(2);
338 break;
339 case spv::OpTypeFloat:
340 ss << "float" << insn.word(2);
341 break;
342 case spv::OpTypeVector:
343 ss << "vec" << insn.word(3) << " of ";
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600344 DescribeTypeInner(ss, src, insn.word(2));
Chris Forbes47567b72017-06-09 12:09:45 -0700345 break;
346 case spv::OpTypeMatrix:
347 ss << "mat" << insn.word(3) << " of ";
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600348 DescribeTypeInner(ss, src, insn.word(2));
Chris Forbes47567b72017-06-09 12:09:45 -0700349 break;
350 case spv::OpTypeArray:
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600351 ss << "arr[" << GetConstantValue(src, insn.word(3)) << "] of ";
352 DescribeTypeInner(ss, src, insn.word(2));
Chris Forbes47567b72017-06-09 12:09:45 -0700353 break;
Chris Forbes062f1222018-08-21 15:34:15 -0700354 case spv::OpTypeRuntimeArray:
355 ss << "runtime arr[] of ";
356 DescribeTypeInner(ss, src, insn.word(2));
357 break;
Chris Forbes47567b72017-06-09 12:09:45 -0700358 case spv::OpTypePointer:
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600359 ss << "ptr to " << StorageClassName(insn.word(2)) << " ";
360 DescribeTypeInner(ss, src, insn.word(3));
Chris Forbes47567b72017-06-09 12:09:45 -0700361 break;
362 case spv::OpTypeStruct: {
363 ss << "struct of (";
364 for (unsigned i = 2; i < insn.len(); i++) {
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600365 DescribeTypeInner(ss, src, insn.word(i));
Chris Forbes47567b72017-06-09 12:09:45 -0700366 if (i == insn.len() - 1) {
367 ss << ")";
368 } else {
369 ss << ", ";
370 }
371 }
372 break;
373 }
374 case spv::OpTypeSampler:
375 ss << "sampler";
376 break;
377 case spv::OpTypeSampledImage:
378 ss << "sampler+";
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600379 DescribeTypeInner(ss, src, insn.word(2));
Chris Forbes47567b72017-06-09 12:09:45 -0700380 break;
381 case spv::OpTypeImage:
382 ss << "image(dim=" << insn.word(3) << ", sampled=" << insn.word(7) << ")";
383 break;
Shannon McPherson0fa28232018-11-01 11:59:02 -0600384 case spv::OpTypeAccelerationStructureNV:
Jeff Bolz105d6492018-09-29 15:46:44 -0500385 ss << "accelerationStruture";
386 break;
Chris Forbes47567b72017-06-09 12:09:45 -0700387 default:
388 ss << "oddtype";
389 break;
390 }
391}
392
Mark Lobodzinski3c59d972019-04-25 11:28:14 -0600393static std::string DescribeType(SHADER_MODULE_STATE const *src, unsigned type) {
Chris Forbes47567b72017-06-09 12:09:45 -0700394 std::ostringstream ss;
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600395 DescribeTypeInner(ss, src, type);
Chris Forbes47567b72017-06-09 12:09:45 -0700396 return ss.str();
397}
398
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600399static bool IsNarrowNumericType(spirv_inst_iter type) {
Chris Forbes47567b72017-06-09 12:09:45 -0700400 if (type.opcode() != spv::OpTypeInt && type.opcode() != spv::OpTypeFloat) return false;
401 return type.word(2) < 64;
402}
403
Mark Lobodzinski3c59d972019-04-25 11:28:14 -0600404static bool TypesMatch(SHADER_MODULE_STATE const *a, SHADER_MODULE_STATE const *b, unsigned a_type, unsigned b_type, bool a_arrayed,
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600405 bool b_arrayed, bool relaxed) {
Chris Forbes47567b72017-06-09 12:09:45 -0700406 // Walk two type trees together, and complain about differences
407 auto a_insn = a->get_def(a_type);
408 auto b_insn = b->get_def(b_type);
409 assert(a_insn != a->end());
410 assert(b_insn != b->end());
411
Chris Forbes062f1222018-08-21 15:34:15 -0700412 // Ignore runtime-sized arrays-- they cannot appear in these interfaces.
413
Chris Forbes47567b72017-06-09 12:09:45 -0700414 if (a_arrayed && a_insn.opcode() == spv::OpTypeArray) {
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600415 return TypesMatch(a, b, a_insn.word(2), b_type, false, b_arrayed, relaxed);
Chris Forbes47567b72017-06-09 12:09:45 -0700416 }
417
418 if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) {
419 // We probably just found the extra level of arrayness in b_type: compare the type inside it to a_type
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600420 return TypesMatch(a, b, a_type, b_insn.word(2), a_arrayed, false, relaxed);
Chris Forbes47567b72017-06-09 12:09:45 -0700421 }
422
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600423 if (a_insn.opcode() == spv::OpTypeVector && relaxed && IsNarrowNumericType(b_insn)) {
424 return TypesMatch(a, b, a_insn.word(2), b_type, a_arrayed, b_arrayed, false);
Chris Forbes47567b72017-06-09 12:09:45 -0700425 }
426
427 if (a_insn.opcode() != b_insn.opcode()) {
428 return false;
429 }
430
431 if (a_insn.opcode() == spv::OpTypePointer) {
432 // Match on pointee type. storage class is expected to differ
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600433 return TypesMatch(a, b, a_insn.word(3), b_insn.word(3), a_arrayed, b_arrayed, relaxed);
Chris Forbes47567b72017-06-09 12:09:45 -0700434 }
435
436 if (a_arrayed || b_arrayed) {
437 // If we havent resolved array-of-verts by here, we're not going to.
438 return false;
439 }
440
441 switch (a_insn.opcode()) {
442 case spv::OpTypeBool:
443 return true;
444 case spv::OpTypeInt:
445 // Match on width, signedness
446 return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3);
447 case spv::OpTypeFloat:
448 // Match on width
449 return a_insn.word(2) == b_insn.word(2);
450 case spv::OpTypeVector:
451 // Match on element type, count.
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600452 if (!TypesMatch(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false)) return false;
453 if (relaxed && IsNarrowNumericType(a->get_def(a_insn.word(2)))) {
Chris Forbes47567b72017-06-09 12:09:45 -0700454 return a_insn.word(3) >= b_insn.word(3);
455 } else {
456 return a_insn.word(3) == b_insn.word(3);
457 }
458 case spv::OpTypeMatrix:
459 // Match on element type, count.
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600460 return TypesMatch(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
Dave Houltona9df0ce2018-02-07 10:51:23 -0700461 a_insn.word(3) == b_insn.word(3);
Chris Forbes47567b72017-06-09 12:09:45 -0700462 case spv::OpTypeArray:
463 // Match on element type, count. these all have the same layout. we don't get here if b_arrayed. This differs from
464 // vector & matrix types in that the array size is the id of a constant instruction, * not a literal within OpTypeArray
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600465 return TypesMatch(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
466 GetConstantValue(a, a_insn.word(3)) == GetConstantValue(b, b_insn.word(3));
Chris Forbes47567b72017-06-09 12:09:45 -0700467 case spv::OpTypeStruct:
468 // Match on all element types
Dave Houltona9df0ce2018-02-07 10:51:23 -0700469 {
470 if (a_insn.len() != b_insn.len()) {
471 return false; // Structs cannot match if member counts differ
Chris Forbes47567b72017-06-09 12:09:45 -0700472 }
Chris Forbes47567b72017-06-09 12:09:45 -0700473
Dave Houltona9df0ce2018-02-07 10:51:23 -0700474 for (unsigned i = 2; i < a_insn.len(); i++) {
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600475 if (!TypesMatch(a, b, a_insn.word(i), b_insn.word(i), a_arrayed, b_arrayed, false)) {
Dave Houltona9df0ce2018-02-07 10:51:23 -0700476 return false;
477 }
478 }
479
480 return true;
481 }
Chris Forbes47567b72017-06-09 12:09:45 -0700482 default:
483 // Remaining types are CLisms, or may not appear in the interfaces we are interested in. Just claim no match.
484 return false;
485 }
486}
487
Mark Lobodzinski3c59d972019-04-25 11:28:14 -0600488static unsigned GetLocationsConsumedByType(SHADER_MODULE_STATE const *src, unsigned type, bool strip_array_level) {
Chris Forbes47567b72017-06-09 12:09:45 -0700489 auto insn = src->get_def(type);
490 assert(insn != src->end());
491
492 switch (insn.opcode()) {
493 case spv::OpTypePointer:
494 // See through the ptr -- this is only ever at the toplevel for graphics shaders we're never actually passing
495 // pointers around.
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600496 return GetLocationsConsumedByType(src, insn.word(3), strip_array_level);
Chris Forbes47567b72017-06-09 12:09:45 -0700497 case spv::OpTypeArray:
498 if (strip_array_level) {
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600499 return GetLocationsConsumedByType(src, insn.word(2), false);
Chris Forbes47567b72017-06-09 12:09:45 -0700500 } else {
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600501 return GetConstantValue(src, insn.word(3)) * GetLocationsConsumedByType(src, insn.word(2), false);
Chris Forbes47567b72017-06-09 12:09:45 -0700502 }
503 case spv::OpTypeMatrix:
504 // Num locations is the dimension * element size
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600505 return insn.word(3) * GetLocationsConsumedByType(src, insn.word(2), false);
Chris Forbes47567b72017-06-09 12:09:45 -0700506 case spv::OpTypeVector: {
507 auto scalar_type = src->get_def(insn.word(2));
508 auto bit_width =
509 (scalar_type.opcode() == spv::OpTypeInt || scalar_type.opcode() == spv::OpTypeFloat) ? scalar_type.word(2) : 32;
510
511 // Locations are 128-bit wide; 3- and 4-component vectors of 64 bit types require two.
512 return (bit_width * insn.word(3) + 127) / 128;
513 }
514 default:
515 // Everything else is just 1.
516 return 1;
517
518 // TODO: extend to handle 64bit scalar types, whose vectors may need multiple locations.
519 }
520}
521
Mark Lobodzinski3c59d972019-04-25 11:28:14 -0600522static unsigned GetComponentsConsumedByType(SHADER_MODULE_STATE const *src, unsigned type, bool strip_array_level) {
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +0200523 auto insn = src->get_def(type);
524 assert(insn != src->end());
525
526 switch (insn.opcode()) {
527 case spv::OpTypePointer:
528 // See through the ptr -- this is only ever at the toplevel for graphics shaders we're never actually passing
529 // pointers around.
530 return GetComponentsConsumedByType(src, insn.word(3), strip_array_level);
531 case spv::OpTypeStruct: {
532 uint32_t sum = 0;
533 for (uint32_t i = 2; i < insn.len(); i++) { // i=2 to skip word(0) and word(1)=ID of struct
534 sum += GetComponentsConsumedByType(src, insn.word(i), false);
535 }
536 return sum;
537 }
Jeff Bolze9ee3d82019-05-29 13:45:13 -0500538 case spv::OpTypeArray:
539 if (strip_array_level) {
540 return GetComponentsConsumedByType(src, insn.word(2), false);
541 } else {
542 return GetConstantValue(src, insn.word(3)) * GetComponentsConsumedByType(src, insn.word(2), false);
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +0200543 }
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +0200544 case spv::OpTypeMatrix:
545 // Num locations is the dimension * element size
546 return insn.word(3) * GetComponentsConsumedByType(src, insn.word(2), false);
547 case spv::OpTypeVector: {
548 auto scalar_type = src->get_def(insn.word(2));
549 auto bit_width =
550 (scalar_type.opcode() == spv::OpTypeInt || scalar_type.opcode() == spv::OpTypeFloat) ? scalar_type.word(2) : 32;
551 // One component is 32-bit
552 return (bit_width * insn.word(3) + 31) / 32;
553 }
554 case spv::OpTypeFloat: {
555 auto bit_width = insn.word(2);
556 return (bit_width + 31) / 32;
557 }
558 case spv::OpTypeInt: {
559 auto bit_width = insn.word(2);
560 return (bit_width + 31) / 32;
561 }
562 case spv::OpConstant:
563 return GetComponentsConsumedByType(src, insn.word(1), false);
564 default:
565 return 0;
566 }
567}
568
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600569static unsigned GetLocationsConsumedByFormat(VkFormat format) {
Chris Forbes47567b72017-06-09 12:09:45 -0700570 switch (format) {
571 case VK_FORMAT_R64G64B64A64_SFLOAT:
572 case VK_FORMAT_R64G64B64A64_SINT:
573 case VK_FORMAT_R64G64B64A64_UINT:
574 case VK_FORMAT_R64G64B64_SFLOAT:
575 case VK_FORMAT_R64G64B64_SINT:
576 case VK_FORMAT_R64G64B64_UINT:
577 return 2;
578 default:
579 return 1;
580 }
581}
582
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600583static unsigned GetFormatType(VkFormat fmt) {
Dave Houltona9df0ce2018-02-07 10:51:23 -0700584 if (FormatIsSInt(fmt)) return FORMAT_TYPE_SINT;
585 if (FormatIsUInt(fmt)) return FORMAT_TYPE_UINT;
586 if (FormatIsDepthAndStencil(fmt)) return FORMAT_TYPE_FLOAT | FORMAT_TYPE_UINT;
587 if (fmt == VK_FORMAT_UNDEFINED) return 0;
Chris Forbes47567b72017-06-09 12:09:45 -0700588 // everything else -- UNORM/SNORM/FLOAT/USCALED/SSCALED is all float in the shader.
589 return FORMAT_TYPE_FLOAT;
590}
591
592// characterizes a SPIR-V type appearing in an interface to a FF stage, for comparison to a VkFormat's characterization above.
Chris Forbes062f1222018-08-21 15:34:15 -0700593// also used for input attachments, as we statically know their format.
Mark Lobodzinski3c59d972019-04-25 11:28:14 -0600594static unsigned GetFundamentalType(SHADER_MODULE_STATE const *src, unsigned type) {
Chris Forbes47567b72017-06-09 12:09:45 -0700595 auto insn = src->get_def(type);
596 assert(insn != src->end());
597
598 switch (insn.opcode()) {
599 case spv::OpTypeInt:
600 return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
601 case spv::OpTypeFloat:
602 return FORMAT_TYPE_FLOAT;
603 case spv::OpTypeVector:
Chris Forbes47567b72017-06-09 12:09:45 -0700604 case spv::OpTypeMatrix:
Chris Forbes47567b72017-06-09 12:09:45 -0700605 case spv::OpTypeArray:
Chris Forbes062f1222018-08-21 15:34:15 -0700606 case spv::OpTypeRuntimeArray:
607 case spv::OpTypeImage:
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600608 return GetFundamentalType(src, insn.word(2));
Chris Forbes47567b72017-06-09 12:09:45 -0700609 case spv::OpTypePointer:
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600610 return GetFundamentalType(src, insn.word(3));
Chris Forbes47567b72017-06-09 12:09:45 -0700611
612 default:
613 return 0;
614 }
615}
616
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600617static uint32_t GetShaderStageId(VkShaderStageFlagBits stage) {
Chris Forbes47567b72017-06-09 12:09:45 -0700618 uint32_t bit_pos = uint32_t(u_ffs(stage));
619 return bit_pos - 1;
620}
621
Mark Lobodzinski3c59d972019-04-25 11:28:14 -0600622static spirv_inst_iter GetStructType(SHADER_MODULE_STATE const *src, spirv_inst_iter def, bool is_array_of_verts) {
Chris Forbes47567b72017-06-09 12:09:45 -0700623 while (true) {
624 if (def.opcode() == spv::OpTypePointer) {
625 def = src->get_def(def.word(3));
626 } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) {
627 def = src->get_def(def.word(2));
628 is_array_of_verts = false;
629 } else if (def.opcode() == spv::OpTypeStruct) {
630 return def;
631 } else {
632 return src->end();
633 }
634 }
635}
636
Mark Lobodzinski3c59d972019-04-25 11:28:14 -0600637static bool CollectInterfaceBlockMembers(SHADER_MODULE_STATE const *src, std::map<location_t, interface_var> *out,
Chris Forbes8a6d8cb2019-02-14 14:33:08 -0800638 bool is_array_of_verts, uint32_t id, uint32_t type_id, bool is_patch,
639 int /*first_location*/) {
Chris Forbes47567b72017-06-09 12:09:45 -0700640 // Walk down the type_id presented, trying to determine whether it's actually an interface block.
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600641 auto type = GetStructType(src, src->get_def(type_id), is_array_of_verts && !is_patch);
Chris Forbes8a6d8cb2019-02-14 14:33:08 -0800642 if (type == src->end() || !(src->get_decorations(type.word(1)).flags & decoration_set::block_bit)) {
Chris Forbes47567b72017-06-09 12:09:45 -0700643 // This isn't an interface block.
Chris Forbesa313d772017-06-13 13:59:41 -0700644 return false;
Chris Forbes47567b72017-06-09 12:09:45 -0700645 }
646
647 std::unordered_map<unsigned, unsigned> member_components;
648 std::unordered_map<unsigned, unsigned> member_relaxed_precision;
Chris Forbesa313d772017-06-13 13:59:41 -0700649 std::unordered_map<unsigned, unsigned> member_patch;
Chris Forbes47567b72017-06-09 12:09:45 -0700650
651 // Walk all the OpMemberDecorate for type's result id -- first pass, collect components.
652 for (auto insn : *src) {
653 if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
654 unsigned member_index = insn.word(2);
655
656 if (insn.word(3) == spv::DecorationComponent) {
657 unsigned component = insn.word(4);
658 member_components[member_index] = component;
659 }
660
661 if (insn.word(3) == spv::DecorationRelaxedPrecision) {
662 member_relaxed_precision[member_index] = 1;
663 }
Chris Forbesa313d772017-06-13 13:59:41 -0700664
665 if (insn.word(3) == spv::DecorationPatch) {
666 member_patch[member_index] = 1;
667 }
Chris Forbes47567b72017-06-09 12:09:45 -0700668 }
669 }
670
Chris Forbesa313d772017-06-13 13:59:41 -0700671 // TODO: correctly handle location assignment from outside
672
Chris Forbes47567b72017-06-09 12:09:45 -0700673 // Second pass -- produce the output, from Location decorations
674 for (auto insn : *src) {
675 if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
676 unsigned member_index = insn.word(2);
677 unsigned member_type_id = type.word(2 + member_index);
678
679 if (insn.word(3) == spv::DecorationLocation) {
680 unsigned location = insn.word(4);
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600681 unsigned num_locations = GetLocationsConsumedByType(src, member_type_id, false);
Chris Forbes47567b72017-06-09 12:09:45 -0700682 auto component_it = member_components.find(member_index);
683 unsigned component = component_it == member_components.end() ? 0 : component_it->second;
684 bool is_relaxed_precision = member_relaxed_precision.find(member_index) != member_relaxed_precision.end();
Dave Houltona9df0ce2018-02-07 10:51:23 -0700685 bool member_is_patch = is_patch || member_patch.count(member_index) > 0;
Chris Forbes47567b72017-06-09 12:09:45 -0700686
687 for (unsigned int offset = 0; offset < num_locations; offset++) {
688 interface_var v = {};
689 v.id = id;
690 // TODO: member index in interface_var too?
691 v.type_id = member_type_id;
692 v.offset = offset;
Chris Forbesa313d772017-06-13 13:59:41 -0700693 v.is_patch = member_is_patch;
Chris Forbes47567b72017-06-09 12:09:45 -0700694 v.is_block_member = true;
695 v.is_relaxed_precision = is_relaxed_precision;
696 (*out)[std::make_pair(location + offset, component)] = v;
697 }
698 }
699 }
700 }
Chris Forbesa313d772017-06-13 13:59:41 -0700701
702 return true;
Chris Forbes47567b72017-06-09 12:09:45 -0700703}
704
Ari Suonpaa696b3432019-03-11 14:02:57 +0200705static std::vector<uint32_t> FindEntrypointInterfaces(spirv_inst_iter entrypoint) {
Chris Forbes8a6d8cb2019-02-14 14:33:08 -0800706 assert(entrypoint.opcode() == spv::OpEntryPoint);
707
Ari Suonpaa696b3432019-03-11 14:02:57 +0200708 std::vector<uint32_t> interfaces;
709 // Find the end of the entrypoint's name string. additional zero bytes follow the actual null terminator, to fill out the
710 // rest of the word - so we only need to look at the last byte in the word to determine which word contains the terminator.
711 uint32_t word = 3;
712 while (entrypoint.word(word) & 0xff000000u) {
713 ++word;
714 }
715 ++word;
716
717 for (; word < entrypoint.len(); word++) interfaces.push_back(entrypoint.word(word));
718
719 return interfaces;
720}
721
Mark Lobodzinski3c59d972019-04-25 11:28:14 -0600722static std::map<location_t, interface_var> CollectInterfaceByLocation(SHADER_MODULE_STATE const *src, spirv_inst_iter entrypoint,
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600723 spv::StorageClass sinterface, bool is_array_of_verts) {
Chris Forbes47567b72017-06-09 12:09:45 -0700724 // TODO: handle index=1 dual source outputs from FS -- two vars will have the same location, and we DON'T want to clobber.
725
Chris Forbes47567b72017-06-09 12:09:45 -0700726 std::map<location_t, interface_var> out;
727
Chris Forbes8a6d8cb2019-02-14 14:33:08 -0800728 for (uint32_t iid : FindEntrypointInterfaces(entrypoint)) {
729 auto insn = src->get_def(iid);
Chris Forbes47567b72017-06-09 12:09:45 -0700730 assert(insn != src->end());
731 assert(insn.opcode() == spv::OpVariable);
732
733 if (insn.word(3) == static_cast<uint32_t>(sinterface)) {
Chris Forbes8a6d8cb2019-02-14 14:33:08 -0800734 auto d = src->get_decorations(iid);
Chris Forbes47567b72017-06-09 12:09:45 -0700735 unsigned id = insn.word(2);
736 unsigned type = insn.word(1);
737
Chris Forbes8a6d8cb2019-02-14 14:33:08 -0800738 int location = d.location;
739 int builtin = d.builtin;
740 unsigned component = d.component;
741 bool is_patch = (d.flags & decoration_set::patch_bit) != 0;
742 bool is_relaxed_precision = (d.flags & decoration_set::relaxed_precision_bit) != 0;
Chris Forbes47567b72017-06-09 12:09:45 -0700743
Dave Houltona9df0ce2018-02-07 10:51:23 -0700744 if (builtin != -1)
745 continue;
Chris Forbes8a6d8cb2019-02-14 14:33:08 -0800746 else if (!CollectInterfaceBlockMembers(src, &out, is_array_of_verts, id, type, is_patch, location)) {
Chris Forbes47567b72017-06-09 12:09:45 -0700747 // A user-defined interface variable, with a location. Where a variable occupied multiple locations, emit
748 // one result for each.
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600749 unsigned num_locations = GetLocationsConsumedByType(src, type, is_array_of_verts && !is_patch);
Chris Forbes47567b72017-06-09 12:09:45 -0700750 for (unsigned int offset = 0; offset < num_locations; offset++) {
751 interface_var v = {};
752 v.id = id;
753 v.type_id = type;
754 v.offset = offset;
755 v.is_patch = is_patch;
756 v.is_relaxed_precision = is_relaxed_precision;
757 out[std::make_pair(location + offset, component)] = v;
758 }
Chris Forbes47567b72017-06-09 12:09:45 -0700759 }
760 }
761 }
762
763 return out;
764}
765
Mark Lobodzinski3c59d972019-04-25 11:28:14 -0600766static std::vector<uint32_t> CollectBuiltinBlockMembers(SHADER_MODULE_STATE const *src, spirv_inst_iter entrypoint,
Ari Suonpaa696b3432019-03-11 14:02:57 +0200767 uint32_t storageClass) {
768 std::vector<uint32_t> variables;
769 std::vector<uint32_t> builtinStructMembers;
770 std::vector<uint32_t> builtinDecorations;
771
772 for (auto insn : *src) {
773 switch (insn.opcode()) {
774 // Find all built-in member decorations
775 case spv::OpMemberDecorate:
776 if (insn.word(3) == spv::DecorationBuiltIn) {
777 builtinStructMembers.push_back(insn.word(1));
778 }
779 break;
780 // Find all built-in decorations
781 case spv::OpDecorate:
782 switch (insn.word(2)) {
783 case spv::DecorationBlock: {
784 uint32_t blockID = insn.word(1);
785 for (auto builtInBlockID : builtinStructMembers) {
786 // Check if one of the members of the block are built-in -> the block is built-in
787 if (blockID == builtInBlockID) {
788 builtinDecorations.push_back(blockID);
789 break;
790 }
791 }
792 break;
793 }
794 case spv::DecorationBuiltIn:
795 builtinDecorations.push_back(insn.word(1));
796 break;
797 default:
798 break;
799 }
800 break;
801 default:
802 break;
803 }
804 }
805
806 // Find all interface variables belonging to the entrypoint and matching the storage class
807 for (uint32_t id : FindEntrypointInterfaces(entrypoint)) {
808 auto def = src->get_def(id);
809 assert(def != src->end());
810 assert(def.opcode() == spv::OpVariable);
811
812 if (def.word(3) == storageClass) variables.push_back(def.word(1));
813 }
814
815 // Find all members belonging to the builtin block selected
816 std::vector<uint32_t> builtinBlockMembers;
817 for (auto &var : variables) {
818 auto def = src->get_def(src->get_def(var).word(3));
819
820 // It could be an array of IO blocks. The element type should be the struct defining the block contents
821 if (def.opcode() == spv::OpTypeArray) def = src->get_def(def.word(2));
822
823 // Now find all members belonging to the struct defining the IO block
824 if (def.opcode() == spv::OpTypeStruct) {
825 for (auto builtInID : builtinDecorations) {
826 if (builtInID == def.word(1)) {
827 for (int i = 2; i < (int)def.len(); i++)
828 builtinBlockMembers.push_back(spv::BuiltInMax); // Start with undefined builtin for each struct member.
829 // These shouldn't be left after replacing.
830 for (auto insn : *src) {
831 if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == builtInID &&
832 insn.word(3) == spv::DecorationBuiltIn) {
833 auto structIndex = insn.word(2);
834 assert(structIndex < builtinBlockMembers.size());
835 builtinBlockMembers[structIndex] = insn.word(4);
836 }
837 }
838 }
839 }
840 }
841 }
842
843 return builtinBlockMembers;
844}
845
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600846static std::vector<std::pair<uint32_t, interface_var>> CollectInterfaceByInputAttachmentIndex(
Mark Lobodzinski3c59d972019-04-25 11:28:14 -0600847 SHADER_MODULE_STATE const *src, std::unordered_set<uint32_t> const &accessible_ids) {
Chris Forbes47567b72017-06-09 12:09:45 -0700848 std::vector<std::pair<uint32_t, interface_var>> out;
849
850 for (auto insn : *src) {
851 if (insn.opcode() == spv::OpDecorate) {
852 if (insn.word(2) == spv::DecorationInputAttachmentIndex) {
853 auto attachment_index = insn.word(3);
854 auto id = insn.word(1);
855
856 if (accessible_ids.count(id)) {
857 auto def = src->get_def(id);
858 assert(def != src->end());
locke-lunarg9a16ebb2020-07-30 16:56:33 -0600859 if (def.opcode() == spv::OpVariable && def.word(3) == spv::StorageClassUniformConstant) {
Shannon McPhersonc06c33d2018-06-28 17:21:12 -0600860 auto num_locations = GetLocationsConsumedByType(src, def.word(1), false);
Chris Forbes47567b72017-06-09 12:09:45 -0700861 for (unsigned int offset = 0; offset < num_locations; offset++) {
862 interface_var v = {};
863 v.id = id;
864 v.type_id = def.word(1);
865 v.offset = offset;
866 out.emplace_back(attachment_index + offset, v);
867 }
868 }
869 }
870 }
871 }
872 }
873
874 return out;
875}
876
locke-lunarg25b6c352020-08-06 17:44:18 -0600877static bool AtomicOperation(uint32_t opcode) {
878 switch (opcode) {
879 case spv::OpAtomicLoad:
880 case spv::OpAtomicStore:
881 case spv::OpAtomicExchange:
882 case spv::OpAtomicCompareExchange:
883 case spv::OpAtomicCompareExchangeWeak:
884 case spv::OpAtomicIIncrement:
885 case spv::OpAtomicIDecrement:
886 case spv::OpAtomicIAdd:
887 case spv::OpAtomicISub:
888 case spv::OpAtomicSMin:
889 case spv::OpAtomicUMin:
890 case spv::OpAtomicSMax:
891 case spv::OpAtomicUMax:
892 case spv::OpAtomicAnd:
893 case spv::OpAtomicOr:
894 case spv::OpAtomicXor:
895 case spv::OpAtomicFAddEXT:
896 return true;
897 default:
898 return false;
899 }
900 return false;
901}
902
sfricke-samsung0065ce02020-12-03 22:46:37 -0800903// Only includes valid group operations used in Vulkan (for now thats only subgroup ops) and any non supported operation will be
904// covered with VUID 01090
905static bool GroupOperation(uint32_t opcode) {
906 switch (opcode) {
907 case spv::OpGroupNonUniformElect:
908 case spv::OpGroupNonUniformAll:
909 case spv::OpGroupNonUniformAny:
910 case spv::OpGroupNonUniformAllEqual:
911 case spv::OpGroupNonUniformBroadcast:
912 case spv::OpGroupNonUniformBroadcastFirst:
913 case spv::OpGroupNonUniformBallot:
914 case spv::OpGroupNonUniformInverseBallot:
915 case spv::OpGroupNonUniformBallotBitExtract:
916 case spv::OpGroupNonUniformBallotBitCount:
917 case spv::OpGroupNonUniformBallotFindLSB:
918 case spv::OpGroupNonUniformBallotFindMSB:
919 case spv::OpGroupNonUniformShuffle:
920 case spv::OpGroupNonUniformShuffleXor:
921 case spv::OpGroupNonUniformShuffleUp:
922 case spv::OpGroupNonUniformShuffleDown:
923 case spv::OpGroupNonUniformIAdd:
924 case spv::OpGroupNonUniformFAdd:
925 case spv::OpGroupNonUniformIMul:
926 case spv::OpGroupNonUniformFMul:
927 case spv::OpGroupNonUniformSMin:
928 case spv::OpGroupNonUniformUMin:
929 case spv::OpGroupNonUniformFMin:
930 case spv::OpGroupNonUniformSMax:
931 case spv::OpGroupNonUniformUMax:
932 case spv::OpGroupNonUniformFMax:
933 case spv::OpGroupNonUniformBitwiseAnd:
934 case spv::OpGroupNonUniformBitwiseOr:
935 case spv::OpGroupNonUniformBitwiseXor:
936 case spv::OpGroupNonUniformLogicalAnd:
937 case spv::OpGroupNonUniformLogicalOr:
938 case spv::OpGroupNonUniformLogicalXor:
939 case spv::OpGroupNonUniformQuadBroadcast:
940 case spv::OpGroupNonUniformQuadSwap:
941 case spv::OpGroupNonUniformPartitionNV:
942 return true;
943 default:
944 return false;
945 }
946 return false;
947}
948
locke-lunarg12d20992020-09-21 12:46:49 -0600949bool CheckObjectIDFromOpLoad(uint32_t object_id, const std::vector<unsigned> &operator_members,
950 const std::unordered_map<unsigned, unsigned> &load_members,
951 const std::unordered_map<unsigned, std::pair<unsigned, unsigned>> &accesschain_members) {
952 for (auto load_id : operator_members) {
locke-lunargd3da0422020-09-23 01:02:11 -0600953 if (object_id == load_id) return true;
locke-lunarg12d20992020-09-21 12:46:49 -0600954 auto load_it = load_members.find(load_id);
955 if (load_it == load_members.end()) {
956 continue;
957 }
958 if (load_it->second == object_id) {
959 return true;
960 }
961
962 auto accesschain_it = accesschain_members.find(load_it->second);
963 if (accesschain_it == accesschain_members.end()) {
964 continue;
965 }
966 if (accesschain_it->second.first == object_id) {
967 return true;
968 }
969 }
970 return false;
971}
972
locke-lunargae2a43c2020-09-22 17:21:57 -0600973bool CheckImageOperandsBiasOffset(uint32_t type) {
974 return type & (spv::ImageOperandsBiasMask | spv::ImageOperandsConstOffsetMask | spv::ImageOperandsOffsetMask |
975 spv::ImageOperandsConstOffsetsMask)
976 ? true
977 : false;
978}
979
locke-lunargd3da0422020-09-23 01:02:11 -0600980struct shader_module_used_operators {
981 bool updated;
982 std::vector<unsigned> imagwrite_members;
983 std::vector<unsigned> atomic_members;
984 std::vector<unsigned> store_members;
985 std::vector<unsigned> atomic_store_members;
986 std::vector<unsigned> sampler_implicitLod_dref_proj_members; // sampler Load id
987 std::vector<unsigned> sampler_bias_offset_members; // sampler Load id
988 std::vector<std::pair<unsigned, unsigned>> sampledImage_members;
989 std::unordered_map<unsigned, unsigned> load_members;
990 std::unordered_map<unsigned, std::pair<unsigned, unsigned>> accesschain_members;
991 std::unordered_map<unsigned, unsigned> image_texel_pointer_members;
992
993 shader_module_used_operators() : updated(false) {}
994
995 void update(SHADER_MODULE_STATE const *module) {
996 if (updated) return;
997 updated = true;
998
999 for (auto insn : *module) {
1000 switch (insn.opcode()) {
1001 case spv::OpImageSampleImplicitLod:
1002 case spv::OpImageSampleProjImplicitLod:
1003 case spv::OpImageSampleProjExplicitLod:
1004 case spv::OpImageSparseSampleImplicitLod:
1005 case spv::OpImageSparseSampleProjImplicitLod:
1006 case spv::OpImageSparseSampleProjExplicitLod: {
1007 sampler_implicitLod_dref_proj_members.emplace_back(insn.word(3)); // Load id
1008 // ImageOperands in index: 5
1009 if (insn.len() > 5 && CheckImageOperandsBiasOffset(insn.word(5))) {
1010 sampler_bias_offset_members.emplace_back(insn.word(3));
1011 }
1012 break;
1013 }
1014 case spv::OpImageSampleDrefImplicitLod:
1015 case spv::OpImageSampleDrefExplicitLod:
1016 case spv::OpImageSampleProjDrefImplicitLod:
1017 case spv::OpImageSampleProjDrefExplicitLod:
1018 case spv::OpImageSparseSampleDrefImplicitLod:
1019 case spv::OpImageSparseSampleDrefExplicitLod:
1020 case spv::OpImageSparseSampleProjDrefImplicitLod:
1021 case spv::OpImageSparseSampleProjDrefExplicitLod: {
1022 sampler_implicitLod_dref_proj_members.emplace_back(insn.word(3)); // Load id
1023 // ImageOperands in index: 6
1024 if (insn.len() > 6 && CheckImageOperandsBiasOffset(insn.word(6))) {
1025 sampler_bias_offset_members.emplace_back(insn.word(3));
1026 }
1027 break;
1028 }
1029 case spv::OpImageSampleExplicitLod:
1030 case spv::OpImageSparseSampleExplicitLod: {
1031 // ImageOperands in index: 5
1032 if (insn.len() > 5 && CheckImageOperandsBiasOffset(insn.word(5))) {
1033 sampler_bias_offset_members.emplace_back(insn.word(3));
1034 }
1035 break;
1036 }
1037 case spv::OpStore: {
1038 store_members.emplace_back(insn.word(1)); // object id or AccessChain id
1039 break;
1040 }
1041 case spv::OpImageWrite: {
1042 imagwrite_members.emplace_back(insn.word(1)); // Load id
1043 break;
1044 }
1045 case spv::OpSampledImage: {
1046 // 3: image load id, 4: sampler load id
1047 sampledImage_members.emplace_back(std::pair<unsigned, unsigned>(insn.word(3), insn.word(4)));
1048 break;
1049 }
1050 case spv::OpLoad: {
1051 // 2: Load id, 3: object id or AccessChain id
1052 load_members.insert(std::make_pair(insn.word(2), insn.word(3)));
1053 break;
1054 }
1055 case spv::OpAccessChain: {
locke-lunarg025daa72020-10-13 11:07:51 -06001056 if (insn.len() == 4) {
1057 // If it is for struct, the length is only 4.
1058 // 2: AccessChain id, 3: object id
1059 accesschain_members.insert(std::make_pair(insn.word(2), std::pair<unsigned, unsigned>(insn.word(3), 0)));
1060 } else {
1061 // 2: AccessChain id, 3: object id, 4: object id of array index
1062 accesschain_members.insert(
1063 std::make_pair(insn.word(2), std::pair<unsigned, unsigned>(insn.word(3), insn.word(4))));
1064 }
locke-lunargd3da0422020-09-23 01:02:11 -06001065 break;
1066 }
1067 case spv::OpImageTexelPointer: {
1068 // 2: ImageTexelPointer id, 3: object id
1069 image_texel_pointer_members.insert(std::make_pair(insn.word(2), insn.word(3)));
1070 break;
1071 }
1072 default: {
1073 if (AtomicOperation(insn.opcode())) {
1074 if (insn.opcode() == spv::OpAtomicStore) {
1075 atomic_store_members.emplace_back(insn.word(1)); // ImageTexelPointer id
1076 } else {
1077 atomic_members.emplace_back(insn.word(3)); // ImageTexelPointer id
1078 }
1079 }
1080 break;
1081 }
1082 }
1083 }
1084 }
1085};
1086
locke-lunarg25b6c352020-08-06 17:44:18 -06001087// Check writable, image atomic operation
1088static void IsSpecificDescriptorType(SHADER_MODULE_STATE const *module, const spirv_inst_iter &id_it, bool is_storage_buffer,
locke-lunargd3da0422020-09-23 01:02:11 -06001089 bool is_check_writable, interface_var &out_interface_var,
1090 shader_module_used_operators &used_operators) {
locke-lunarg6f760f12020-06-05 16:19:37 -06001091 uint32_t type_id = id_it.word(1);
locke-lunarg36045992020-08-20 16:54:37 -06001092 unsigned int id = id_it.word(2);
1093
Chris Forbes8af24522018-03-07 11:37:45 -08001094 auto type = module->get_def(type_id);
1095
1096 // Strip off any array or ptrs. Where we remove array levels, adjust the descriptor count for each dimension.
locke-lunarg12d20992020-09-21 12:46:49 -06001097 while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer || type.opcode() == spv::OpTypeRuntimeArray ||
1098 type.opcode() == spv::OpTypeSampledImage) {
1099 if (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypeRuntimeArray ||
1100 type.opcode() == spv::OpTypeSampledImage) {
Chris Forbes8d31e5d2018-10-08 17:19:15 -07001101 type = module->get_def(type.word(2)); // Element type
Chris Forbes8af24522018-03-07 11:37:45 -08001102 } else {
locke-lunarg36045992020-08-20 16:54:37 -06001103 type = module->get_def(type.word(3)); // Pointer type
Chris Forbes8af24522018-03-07 11:37:45 -08001104 }
1105 }
Chris Forbes8af24522018-03-07 11:37:45 -08001106 switch (type.opcode()) {
1107 case spv::OpTypeImage: {
1108 auto dim = type.word(3);
locke-lunarg36045992020-08-20 16:54:37 -06001109 if (dim != spv::DimSubpassData) {
locke-lunargd3da0422020-09-23 01:02:11 -06001110 used_operators.update(module);
locke-lunarg25b6c352020-08-06 17:44:18 -06001111
locke-lunargd3da0422020-09-23 01:02:11 -06001112 if (CheckObjectIDFromOpLoad(id, used_operators.imagwrite_members, used_operators.load_members,
1113 used_operators.accesschain_members)) {
locke-lunarg25b6c352020-08-06 17:44:18 -06001114 out_interface_var.is_writable = true;
locke-lunarg12d20992020-09-21 12:46:49 -06001115 }
1116 if (CheckObjectIDFromOpLoad(id, used_operators.sampler_implicitLod_dref_proj_members, used_operators.load_members,
1117 used_operators.accesschain_members)) {
1118 out_interface_var.is_sampler_implicitLod_dref_proj = true;
locke-lunarg25b6c352020-08-06 17:44:18 -06001119 }
locke-lunargd3da0422020-09-23 01:02:11 -06001120 if (CheckObjectIDFromOpLoad(id, used_operators.sampler_bias_offset_members, used_operators.load_members,
1121 used_operators.accesschain_members)) {
locke-lunargae2a43c2020-09-22 17:21:57 -06001122 out_interface_var.is_sampler_bias_offset = true;
1123 }
locke-lunargd3da0422020-09-23 01:02:11 -06001124 if (CheckObjectIDFromOpLoad(id, used_operators.atomic_members, used_operators.image_texel_pointer_members,
1125 used_operators.accesschain_members) ||
1126 CheckObjectIDFromOpLoad(id, used_operators.atomic_store_members, used_operators.image_texel_pointer_members,
1127 used_operators.accesschain_members)) {
1128 out_interface_var.is_atomic_operation = true;
1129 }
locke-lunarg25b6c352020-08-06 17:44:18 -06001130
locke-lunargd3da0422020-09-23 01:02:11 -06001131 for (auto &itp_id : used_operators.sampledImage_members) {
locke-lunarg36045992020-08-20 16:54:37 -06001132 // Find if image id match.
1133 uint32_t image_index = 0;
locke-lunargd3da0422020-09-23 01:02:11 -06001134 auto load_it = used_operators.load_members.find(itp_id.first);
1135 if (load_it == used_operators.load_members.end()) {
locke-lunarg36045992020-08-20 16:54:37 -06001136 continue;
1137 } else {
1138 if (load_it->second != id) {
locke-lunargd3da0422020-09-23 01:02:11 -06001139 auto accesschain_it = used_operators.accesschain_members.find(load_it->second);
1140 if (accesschain_it == used_operators.accesschain_members.end()) {
locke-lunarg36045992020-08-20 16:54:37 -06001141 continue;
1142 } else {
1143 if (accesschain_it->second.first != id) {
1144 continue;
1145 }
locke-lunarg025daa72020-10-13 11:07:51 -06001146 if (used_operators.load_members.end() !=
1147 used_operators.load_members.find(accesschain_it->second.second)) {
1148 // image_index isn't a constant, skip.
1149 break;
1150 }
locke-lunarg36045992020-08-20 16:54:37 -06001151 image_index = GetConstantValue(module, accesschain_it->second.second);
1152 }
1153 }
1154 }
1155 // Find sampler's set binding.
locke-lunargd3da0422020-09-23 01:02:11 -06001156 load_it = used_operators.load_members.find(itp_id.second);
1157 if (load_it == used_operators.load_members.end()) {
locke-lunarg36045992020-08-20 16:54:37 -06001158 continue;
1159 } else {
1160 uint32_t sampler_id = load_it->second;
1161 uint32_t sampler_index = 0;
locke-lunargd3da0422020-09-23 01:02:11 -06001162 auto accesschain_it = used_operators.accesschain_members.find(load_it->second);
1163 if (accesschain_it != used_operators.accesschain_members.end()) {
locke-lunarg025daa72020-10-13 11:07:51 -06001164 if (used_operators.load_members.end() !=
1165 used_operators.load_members.find(accesschain_it->second.second)) {
1166 // sampler_index isn't a constant, skip.
1167 break;
1168 }
locke-lunarg36045992020-08-20 16:54:37 -06001169 sampler_id = accesschain_it->second.first;
1170 sampler_index = GetConstantValue(module, accesschain_it->second.second);
1171 }
1172 auto sampler_dec = module->get_decorations(sampler_id);
locke-lunarg654a9052020-10-13 16:28:42 -06001173 if (image_index >= out_interface_var.samplers_used_by_image.size()) {
1174 out_interface_var.samplers_used_by_image.resize(image_index + 1);
1175 }
1176 out_interface_var.samplers_used_by_image[image_index].emplace(
1177 SamplerUsedByImage{descriptor_slot_t{sampler_dec.descriptor_set, sampler_dec.binding}, sampler_index});
locke-lunarg36045992020-08-20 16:54:37 -06001178 }
1179 }
locke-lunarg6f760f12020-06-05 16:19:37 -06001180 }
locke-lunarg25b6c352020-08-06 17:44:18 -06001181 return;
Chris Forbes8af24522018-03-07 11:37:45 -08001182 }
1183
Chris Forbes8d31e5d2018-10-08 17:19:15 -07001184 case spv::OpTypeStruct: {
1185 std::unordered_set<unsigned> nonwritable_members;
Chris Forbes8a6d8cb2019-02-14 14:33:08 -08001186 if (module->get_decorations(type.word(1)).flags & decoration_set::buffer_block_bit) is_storage_buffer = true;
Chris Forbes8af24522018-03-07 11:37:45 -08001187 for (auto insn : *module) {
Chris Forbes8a6d8cb2019-02-14 14:33:08 -08001188 if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1) &&
1189 insn.word(3) == spv::DecorationNonWritable) {
Chris Forbes8d31e5d2018-10-08 17:19:15 -07001190 nonwritable_members.insert(insn.word(2));
Chris Forbes8af24522018-03-07 11:37:45 -08001191 }
1192 }
Chris Forbes8d31e5d2018-10-08 17:19:15 -07001193
1194 // A buffer is writable if it's either flavor of storage buffer, and has any member not decorated
1195 // as nonwritable.
locke-lunarg6f760f12020-06-05 16:19:37 -06001196 if (is_storage_buffer && nonwritable_members.size() != type.len() - 2) {
locke-lunargd3da0422020-09-23 01:02:11 -06001197 used_operators.update(module);
locke-lunarg6f760f12020-06-05 16:19:37 -06001198
locke-lunargd3da0422020-09-23 01:02:11 -06001199 for (auto oid : used_operators.store_members) {
1200 if (id == oid) {
locke-lunarg25b6c352020-08-06 17:44:18 -06001201 out_interface_var.is_writable = true;
1202 return;
1203 }
locke-lunargd3da0422020-09-23 01:02:11 -06001204 auto accesschain_it = used_operators.accesschain_members.find(oid);
1205 if (accesschain_it == used_operators.accesschain_members.end()) {
locke-lunarg25b6c352020-08-06 17:44:18 -06001206 continue;
1207 }
locke-lunargd3da0422020-09-23 01:02:11 -06001208 if (accesschain_it->second.first == id) {
1209 out_interface_var.is_writable = true;
1210 return;
1211 }
1212 }
1213 if (CheckObjectIDFromOpLoad(id, used_operators.atomic_store_members, used_operators.image_texel_pointer_members,
1214 used_operators.accesschain_members)) {
locke-lunarg25b6c352020-08-06 17:44:18 -06001215 out_interface_var.is_writable = true;
1216 return;
locke-lunarg6f760f12020-06-05 16:19:37 -06001217 }
1218 }
Chris Forbes8d31e5d2018-10-08 17:19:15 -07001219 }
Chris Forbes8af24522018-03-07 11:37:45 -08001220 }
Chris Forbes8af24522018-03-07 11:37:45 -08001221}
1222
locke-lunargd9a069d2019-09-17 01:50:19 -06001223std::vector<std::pair<descriptor_slot_t, interface_var>> CollectInterfaceByDescriptorSlot(
locke-lunarg63e4daf2020-08-17 17:53:25 -06001224 SHADER_MODULE_STATE const *src, std::unordered_set<uint32_t> const &accessible_ids, bool *has_writable_descriptor,
1225 bool *has_atomic_descriptor) {
Chris Forbes47567b72017-06-09 12:09:45 -07001226 std::vector<std::pair<descriptor_slot_t, interface_var>> out;
locke-lunargd3da0422020-09-23 01:02:11 -06001227 shader_module_used_operators operators;
1228
Chris Forbes47567b72017-06-09 12:09:45 -07001229 for (auto id : accessible_ids) {
1230 auto insn = src->get_def(id);
1231 assert(insn != src->end());
1232
1233 if (insn.opcode() == spv::OpVariable &&
Chris Forbes9f89d752018-03-07 12:57:48 -08001234 (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant ||
1235 insn.word(3) == spv::StorageClassStorageBuffer)) {
Chris Forbes8a6d8cb2019-02-14 14:33:08 -08001236 auto d = src->get_decorations(insn.word(2));
1237 unsigned set = d.descriptor_set;
1238 unsigned binding = d.binding;
Chris Forbes47567b72017-06-09 12:09:45 -07001239
1240 interface_var v = {};
1241 v.id = insn.word(2);
1242 v.type_id = insn.word(1);
Chris Forbes8af24522018-03-07 11:37:45 -08001243
locke-lunarg25b6c352020-08-06 17:44:18 -06001244 IsSpecificDescriptorType(src, insn, insn.word(3) == spv::StorageClassStorageBuffer,
locke-lunargd3da0422020-09-23 01:02:11 -06001245 !(d.flags & decoration_set::nonwritable_bit), v, operators);
locke-lunarg63e4daf2020-08-17 17:53:25 -06001246 if (v.is_writable) *has_writable_descriptor = true;
1247 if (v.is_atomic_operation) *has_atomic_descriptor = true;
locke-lunarg654e3692020-06-04 17:19:15 -06001248 out.emplace_back(std::make_pair(set, binding), v);
Chris Forbes47567b72017-06-09 12:09:45 -07001249 }
1250 }
1251
1252 return out;
1253}
1254
locke-lunargde3f0fa2020-09-10 11:55:31 -06001255void DefineStructMember(const SHADER_MODULE_STATE &src, const spirv_inst_iter &it,
1256 const std::vector<uint32_t> &memberDecorate_offsets, shader_struct_member &data) {
1257 const auto struct_it = GetStructType(&src, it, false);
1258 assert(struct_it != src.end());
1259 data.size = 0;
1260
1261 shader_struct_member data1;
1262 uint32_t i = 2;
1263 uint32_t local_offset = 0;
1264 std::vector<uint32_t> offsets;
1265 offsets.resize(struct_it.len() - i);
1266
1267 // The members of struct in SPRIV_R aren't always sort, so we need to know their order.
1268 for (const auto offset : memberDecorate_offsets) {
1269 const auto member_decorate = src.at(offset);
1270 if (member_decorate.word(1) != struct_it.word(1)) {
1271 continue;
1272 }
1273
1274 offsets[member_decorate.word(2)] = member_decorate.word(4);
1275 }
1276
1277 for (const auto offset : offsets) {
1278 local_offset = offset;
1279 data1 = {};
1280 data1.root = data.root;
1281 data1.offset = local_offset;
1282 auto def_member = src.get_def(struct_it.word(i));
1283
1284 // Array could be multi-dimensional
1285 while (def_member.opcode() == spv::OpTypeArray) {
1286 const auto len_id = def_member.word(3);
1287 const auto def_len = src.get_def(len_id);
1288 data1.array_length_hierarchy.emplace_back(def_len.word(3)); // array length
1289 def_member = src.get_def(def_member.word(2));
1290 }
1291
1292 if (def_member.opcode() == spv::OpTypeStruct || def_member.opcode() == spv::OpTypePointer) {
1293 // If it's OpTypePointer. it means the member is a buffer, the type will be TypePointer, and then struct
1294 DefineStructMember(src, def_member, memberDecorate_offsets, data1);
1295 } else {
1296 if (def_member.opcode() == spv::OpTypeMatrix) {
1297 data1.array_length_hierarchy.emplace_back(def_member.word(3)); // matrix's columns. matrix's row is vector.
1298 def_member = src.get_def(def_member.word(2));
1299 }
1300
1301 if (def_member.opcode() == spv::OpTypeVector) {
1302 data1.array_length_hierarchy.emplace_back(def_member.word(3)); // vector length
1303 def_member = src.get_def(def_member.word(2));
1304 }
1305
1306 // Get scalar type size. The value in SPRV-R is bit. It needs to translate to byte.
1307 data1.size = (def_member.word(2) / 8);
1308 }
1309 const auto array_length_hierarchy_szie = data1.array_length_hierarchy.size();
1310 if (array_length_hierarchy_szie > 0) {
1311 data1.array_block_size.resize(array_length_hierarchy_szie, 1);
1312
1313 for (int i2 = static_cast<int>(array_length_hierarchy_szie - 1); i2 > 0; --i2) {
1314 data1.array_block_size[i2 - 1] = data1.array_length_hierarchy[i2] * data1.array_block_size[i2];
1315 }
1316 }
1317 data.struct_members.emplace_back(data1);
1318 ++i;
1319 }
1320 uint32_t total_array_length = 1;
1321 for (const auto length : data1.array_length_hierarchy) {
1322 total_array_length *= length;
1323 }
1324 data.size = local_offset + data1.size * total_array_length;
1325}
1326
1327uint32_t UpdateOffset(uint32_t offset, const std::vector<uint32_t> &array_indices, const shader_struct_member &data) {
1328 int array_indices_size = static_cast<int>(array_indices.size());
1329 if (array_indices_size) {
1330 uint32_t array_index = 0;
1331 uint32_t i = 0;
1332 for (const auto index : array_indices) {
1333 array_index += (data.array_block_size[i] * index);
1334 ++i;
1335 }
1336 offset += (array_index * data.size);
1337 }
1338 return offset;
1339}
1340
1341void SetUsedBytes(uint32_t offset, const std::vector<uint32_t> &array_indices, const shader_struct_member &data) {
1342 int array_indices_size = static_cast<int>(array_indices.size());
1343 uint32_t block_memory_size = data.size;
1344 for (uint32_t i = static_cast<int>(array_indices_size); i < data.array_length_hierarchy.size(); ++i) {
1345 block_memory_size *= data.array_length_hierarchy[i];
1346 }
1347
1348 offset = UpdateOffset(offset, array_indices, data);
1349
1350 uint32_t end = offset + block_memory_size;
1351 auto used_bytes = data.GetUsedbytes();
1352 if (used_bytes->size() < end) {
1353 used_bytes->resize(end, 0);
1354 }
1355 std::memset(used_bytes->data() + offset, true, static_cast<std::size_t>(block_memory_size));
1356}
1357
1358void RunUsedArray(const SHADER_MODULE_STATE &src, uint32_t offset, std::vector<uint32_t> array_indices,
1359 uint32_t access_chain_word_index, spirv_inst_iter &access_chain_it, const shader_struct_member &data) {
1360 if (access_chain_word_index < access_chain_it.len()) {
1361 if (data.array_length_hierarchy.size() > array_indices.size()) {
1362 auto def_it = src.get_def(access_chain_it.word(access_chain_word_index));
1363 ++access_chain_word_index;
1364
1365 if (def_it != src.end() && def_it.opcode() == spv::OpConstant) {
1366 array_indices.emplace_back(def_it.word(3));
1367 RunUsedArray(src, offset, array_indices, access_chain_word_index, access_chain_it, data);
1368 } else {
1369 // If it is a variable, set the all array is used.
1370 if (access_chain_word_index < access_chain_it.len()) {
1371 uint32_t array_length = data.array_length_hierarchy[array_indices.size()];
1372 for (uint32_t i = 0; i < array_length; ++i) {
1373 auto array_indices2 = array_indices;
1374 array_indices2.emplace_back(i);
1375 RunUsedArray(src, offset, array_indices2, access_chain_word_index, access_chain_it, data);
1376 }
1377 } else {
1378 SetUsedBytes(offset, array_indices, data);
1379 }
1380 }
1381 } else {
1382 offset = UpdateOffset(offset, array_indices, data);
1383 RunUsedStruct(src, offset, access_chain_word_index, access_chain_it, data);
1384 }
1385 } else {
1386 SetUsedBytes(offset, array_indices, data);
1387 }
1388}
1389
1390void RunUsedStruct(const SHADER_MODULE_STATE &src, uint32_t offset, uint32_t access_chain_word_index,
1391 spirv_inst_iter &access_chain_it, const shader_struct_member &data) {
1392 std::vector<uint32_t> array_indices_emptry;
1393
1394 if (access_chain_word_index < access_chain_it.len()) {
1395 auto strcut_member_index = GetConstantValue(&src, access_chain_it.word(access_chain_word_index));
1396 ++access_chain_word_index;
1397
1398 auto data1 = data.struct_members[strcut_member_index];
1399 RunUsedArray(src, offset + data1.offset, array_indices_emptry, access_chain_word_index, access_chain_it, data1);
1400 }
1401}
1402
1403void SetUsedStructMember(const SHADER_MODULE_STATE &src, const uint32_t variable_id,
1404 const std::vector<function_set> &function_set_list, const shader_struct_member &data) {
1405 for (const auto &func_set : function_set_list) {
1406 auto range = func_set.op_lists.equal_range(spv::OpAccessChain);
1407 for (auto it = range.first; it != range.second; ++it) {
1408 auto access_chain = src.at(it->second);
1409 if (access_chain.word(3) == variable_id) {
1410 RunUsedStruct(src, 0, 4, access_chain, data);
1411 }
1412 }
1413 }
1414}
1415
1416void SetPushConstantUsedInShader(SHADER_MODULE_STATE &src) {
1417 for (auto &entrypoint : src.entry_points) {
1418 auto range = entrypoint.second.decorate_list.equal_range(spv::OpVariable);
1419 for (auto it = range.first; it != range.second; ++it) {
1420 const auto def_insn = src.at(it->second);
1421
1422 if (def_insn.word(3) == spv::StorageClassPushConstant) {
1423 spirv_inst_iter type = src.get_def(def_insn.word(1));
1424 const auto range2 = entrypoint.second.decorate_list.equal_range(spv::OpMemberDecorate);
1425 std::vector<uint32_t> offsets;
1426
1427 for (auto it2 = range2.first; it2 != range2.second; ++it2) {
1428 auto member_decorate = src.at(it2->second);
1429 if (member_decorate.len() == 5 && member_decorate.word(3) == spv::DecorationOffset) {
1430 offsets.emplace_back(member_decorate.offset());
1431 }
1432 }
1433 entrypoint.second.push_constant_used_in_shader.root = &entrypoint.second.push_constant_used_in_shader;
1434 DefineStructMember(src, type, offsets, entrypoint.second.push_constant_used_in_shader);
1435 SetUsedStructMember(src, def_insn.word(2), entrypoint.second.function_set_list,
1436 entrypoint.second.push_constant_used_in_shader);
1437 }
1438 }
1439 }
1440}
1441
locke-lunarg96dc9632020-06-10 17:22:18 -06001442std::unordered_set<uint32_t> CollectWritableOutputLocationinFS(const SHADER_MODULE_STATE &module,
1443 const VkPipelineShaderStageCreateInfo &stage_info) {
1444 std::unordered_set<uint32_t> location_list;
1445 if (stage_info.stage != VK_SHADER_STAGE_FRAGMENT_BIT) return location_list;
1446 const auto entrypoint = FindEntrypoint(&module, stage_info.pName, stage_info.stage);
1447 const auto outputs = CollectInterfaceByLocation(&module, entrypoint, spv::StorageClassOutput, false);
1448 std::unordered_set<unsigned> store_members;
1449 std::unordered_map<unsigned, unsigned> accesschain_members;
1450
1451 for (auto insn : module) {
1452 switch (insn.opcode()) {
1453 case spv::OpStore:
1454 case spv::OpAtomicStore: {
1455 store_members.insert(insn.word(1)); // object id or AccessChain id
1456 break;
1457 }
1458 case spv::OpAccessChain: {
1459 // 2: AccessChain id, 3: object id
1460 if (insn.word(3)) accesschain_members.insert(std::make_pair(insn.word(2), insn.word(3)));
1461 break;
1462 }
1463 default:
1464 break;
1465 }
1466 }
1467 if (store_members.empty()) {
1468 return location_list;
1469 }
1470 for (auto output : outputs) {
1471 auto store_it = store_members.find(output.second.id);
1472 if (store_it != store_members.end()) {
1473 location_list.insert(output.first.first);
1474 store_members.erase(store_it);
1475 continue;
1476 }
1477 store_it = store_members.begin();
1478 while (store_it != store_members.end()) {
1479 auto accesschain_it = accesschain_members.find(*store_it);
1480 if (accesschain_it == accesschain_members.end()) {
1481 ++store_it;
1482 continue;
1483 }
1484 if (accesschain_it->second == output.second.id) {
1485 location_list.insert(output.first.first);
1486 store_members.erase(store_it);
1487 accesschain_members.erase(accesschain_it);
1488 break;
1489 }
1490 ++store_it;
1491 }
1492 }
1493 return location_list;
1494}
1495
Mark Lobodzinskid8d658e2020-01-30 15:05:51 -07001496bool CoreChecks::ValidateViConsistency(VkPipelineVertexInputStateCreateInfo const *vi) const {
Chris Forbes47567b72017-06-09 12:09:45 -07001497 // Walk the binding descriptions, which describe the step rate and stride of each vertex buffer. Each binding should
1498 // be specified only once.
1499 std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings;
1500 bool skip = false;
1501
1502 for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) {
1503 auto desc = &vi->pVertexBindingDescriptions[i];
1504 auto &binding = bindings[desc->binding];
1505 if (binding) {
Dave Houlton78d09922018-05-17 15:48:45 -06001506 // TODO: "VUID-VkGraphicsPipelineCreateInfo-pStages-00742" perhaps?
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07001507 skip |= LogError(device, kVUID_Core_Shader_InconsistentVi, "Duplicate vertex input binding descriptions for binding %d",
1508 desc->binding);
Chris Forbes47567b72017-06-09 12:09:45 -07001509 } else {
1510 binding = desc;
1511 }
1512 }
1513
1514 return skip;
1515}
1516
Mark Lobodzinskid8d658e2020-01-30 15:05:51 -07001517bool CoreChecks::ValidateViAgainstVsInputs(VkPipelineVertexInputStateCreateInfo const *vi, SHADER_MODULE_STATE const *vs,
1518 spirv_inst_iter entrypoint) const {
Chris Forbes47567b72017-06-09 12:09:45 -07001519 bool skip = false;
1520
Petr Kraus25810d02019-08-27 17:41:15 +02001521 const auto inputs = CollectInterfaceByLocation(vs, entrypoint, spv::StorageClassInput, false);
Chris Forbes47567b72017-06-09 12:09:45 -07001522
1523 // Build index by location
Petr Kraus25810d02019-08-27 17:41:15 +02001524 std::map<uint32_t, const VkVertexInputAttributeDescription *> attribs;
Chris Forbes47567b72017-06-09 12:09:45 -07001525 if (vi) {
Petr Kraus25810d02019-08-27 17:41:15 +02001526 for (uint32_t i = 0; i < vi->vertexAttributeDescriptionCount; ++i) {
1527 const auto num_locations = GetLocationsConsumedByFormat(vi->pVertexAttributeDescriptions[i].format);
1528 for (uint32_t j = 0; j < num_locations; ++j) {
Chris Forbes47567b72017-06-09 12:09:45 -07001529 attribs[vi->pVertexAttributeDescriptions[i].location + j] = &vi->pVertexAttributeDescriptions[i];
1530 }
1531 }
1532 }
1533
Petr Kraus25810d02019-08-27 17:41:15 +02001534 struct AttribInputPair {
1535 const VkVertexInputAttributeDescription *attrib = nullptr;
1536 const interface_var *input = nullptr;
1537 };
1538 std::map<uint32_t, AttribInputPair> location_map;
1539 for (const auto &attrib_it : attribs) location_map[attrib_it.first].attrib = attrib_it.second;
1540 for (const auto &input_it : inputs) location_map[input_it.first.first].input = &input_it.second;
Chris Forbes47567b72017-06-09 12:09:45 -07001541
Jamie Madillc1f7ca82020-03-16 17:08:26 -04001542 for (const auto &location_it : location_map) {
Petr Kraus25810d02019-08-27 17:41:15 +02001543 const auto location = location_it.first;
1544 const auto attrib = location_it.second.attrib;
1545 const auto input = location_it.second.input;
Mark Lobodzinski7caa39c2018-07-25 15:48:34 -06001546
Petr Kraus25810d02019-08-27 17:41:15 +02001547 if (attrib && !input) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07001548 skip |= LogPerformanceWarning(vs->vk_shader_module, kVUID_Core_Shader_OutputNotConsumed,
1549 "Vertex attribute at location %" PRIu32 " not consumed by vertex shader", location);
Petr Kraus25810d02019-08-27 17:41:15 +02001550 } else if (!attrib && input) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07001551 skip |= LogError(vs->vk_shader_module, kVUID_Core_Shader_InputNotProduced,
1552 "Vertex shader consumes input at location %" PRIu32 " but not provided", location);
Petr Kraus25810d02019-08-27 17:41:15 +02001553 } else if (attrib && input) {
1554 const auto attrib_type = GetFormatType(attrib->format);
1555 const auto input_type = GetFundamentalType(vs, input->type_id);
Chris Forbes47567b72017-06-09 12:09:45 -07001556
1557 // Type checking
1558 if (!(attrib_type & input_type)) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07001559 skip |= LogError(vs->vk_shader_module, kVUID_Core_Shader_InterfaceTypeMismatch,
1560 "Attribute type of `%s` at location %" PRIu32 " does not match vertex shader input type of `%s`",
1561 string_VkFormat(attrib->format), location, DescribeType(vs, input->type_id).c_str());
Chris Forbes47567b72017-06-09 12:09:45 -07001562 }
Petr Kraus25810d02019-08-27 17:41:15 +02001563 } else { // !attrib && !input
1564 assert(false); // at least one exists in the map
Chris Forbes47567b72017-06-09 12:09:45 -07001565 }
1566 }
1567
1568 return skip;
1569}
1570
Mark Lobodzinskid8d658e2020-01-30 15:05:51 -07001571bool CoreChecks::ValidateFsOutputsAgainstRenderPass(SHADER_MODULE_STATE const *fs, spirv_inst_iter entrypoint,
1572 PIPELINE_STATE const *pipeline, uint32_t subpass_index) const {
Petr Kraus25810d02019-08-27 17:41:15 +02001573 bool skip = false;
Chris Forbes8bca1652017-07-20 11:10:09 -07001574
Petr Kraus25810d02019-08-27 17:41:15 +02001575 const auto rpci = pipeline->rp_state->createInfo.ptr();
1576
Jeremy Hayes3699c7c2019-10-09 12:24:55 -06001577 struct Attachment {
1578 const VkAttachmentReference2KHR *reference = nullptr;
1579 const VkAttachmentDescription2KHR *attachment = nullptr;
1580 const interface_var *output = nullptr;
1581 };
1582 std::map<uint32_t, Attachment> location_map;
1583
Petr Kraus25810d02019-08-27 17:41:15 +02001584 const auto subpass = rpci->pSubpasses[subpass_index];
1585 for (uint32_t i = 0; i < subpass.colorAttachmentCount; ++i) {
Jeremy Hayes3699c7c2019-10-09 12:24:55 -06001586 auto const &reference = subpass.pColorAttachments[i];
1587 location_map[i].reference = &reference;
1588 if (reference.attachment != VK_ATTACHMENT_UNUSED &&
1589 rpci->pAttachments[reference.attachment].format != VK_FORMAT_UNDEFINED) {
1590 location_map[i].attachment = &rpci->pAttachments[reference.attachment];
Chris Forbes47567b72017-06-09 12:09:45 -07001591 }
1592 }
1593
Chris Forbes47567b72017-06-09 12:09:45 -07001594 // TODO: dual source blend index (spv::DecIndex, zero if not provided)
1595
Petr Kraus25810d02019-08-27 17:41:15 +02001596 const auto outputs = CollectInterfaceByLocation(fs, entrypoint, spv::StorageClassOutput, false);
Jeremy Hayes3699c7c2019-10-09 12:24:55 -06001597 for (const auto &output_it : outputs) {
1598 auto const location = output_it.first.first;
1599 location_map[location].output = &output_it.second;
1600 }
Chris Forbes47567b72017-06-09 12:09:45 -07001601
Petr Kraus25810d02019-08-27 17:41:15 +02001602 const bool alphaToCoverageEnabled = pipeline->graphicsPipelineCI.pMultisampleState != NULL &&
1603 pipeline->graphicsPipelineCI.pMultisampleState->alphaToCoverageEnable == VK_TRUE;
Chris Forbes47567b72017-06-09 12:09:45 -07001604
Jamie Madillc1f7ca82020-03-16 17:08:26 -04001605 for (const auto &location_it : location_map) {
Jeremy Hayes3699c7c2019-10-09 12:24:55 -06001606 const auto reference = location_it.second.reference;
1607 if (reference != nullptr && reference->attachment == VK_ATTACHMENT_UNUSED) {
1608 continue;
1609 }
1610
Petr Kraus25810d02019-08-27 17:41:15 +02001611 const auto location = location_it.first;
1612 const auto attachment = location_it.second.attachment;
1613 const auto output = location_it.second.output;
Petr Kraus25810d02019-08-27 17:41:15 +02001614 if (attachment && !output) {
1615 if (pipeline->attachments[location].colorWriteMask != 0) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07001616 skip |= LogWarning(fs->vk_shader_module, kVUID_Core_Shader_InputNotProduced,
1617 "Attachment %" PRIu32
1618 " not written by fragment shader; undefined values will be written to attachment",
1619 location);
Petr Kraus25810d02019-08-27 17:41:15 +02001620 }
1621 } else if (!attachment && output) {
1622 if (!(alphaToCoverageEnabled && location == 0)) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07001623 skip |= LogWarning(fs->vk_shader_module, kVUID_Core_Shader_OutputNotConsumed,
1624 "fragment shader writes to output location %" PRIu32 " with no matching attachment", location);
Ari Suonpaa412b23b2019-02-26 07:56:58 +02001625 }
Petr Kraus25810d02019-08-27 17:41:15 +02001626 } else if (attachment && output) {
1627 const auto attachment_type = GetFormatType(attachment->format);
1628 const auto output_type = GetFundamentalType(fs, output->type_id);
Chris Forbes47567b72017-06-09 12:09:45 -07001629
1630 // Type checking
Petr Kraus25810d02019-08-27 17:41:15 +02001631 if (!(output_type & attachment_type)) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07001632 skip |=
1633 LogWarning(fs->vk_shader_module, kVUID_Core_Shader_InterfaceTypeMismatch,
1634 "Attachment %" PRIu32
1635 " of type `%s` does not match fragment shader output type of `%s`; resulting values are undefined",
1636 location, string_VkFormat(attachment->format), DescribeType(fs, output->type_id).c_str());
Chris Forbes47567b72017-06-09 12:09:45 -07001637 }
Petr Kraus25810d02019-08-27 17:41:15 +02001638 } else { // !attachment && !output
1639 assert(false); // at least one exists in the map
Chris Forbes47567b72017-06-09 12:09:45 -07001640 }
1641 }
1642
Petr Kraus25810d02019-08-27 17:41:15 +02001643 const auto output_zero = location_map.count(0) ? location_map[0].output : nullptr;
1644 bool locationZeroHasAlpha = output_zero && fs->get_def(output_zero->type_id) != fs->end() &&
1645 GetComponentsConsumedByType(fs, output_zero->type_id, false) == 4;
Ari Suonpaa412b23b2019-02-26 07:56:58 +02001646 if (alphaToCoverageEnabled && !locationZeroHasAlpha) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07001647 skip |= LogError(fs->vk_shader_module, kVUID_Core_Shader_NoAlphaAtLocation0WithAlphaToCoverage,
1648 "fragment shader doesn't declare alpha output at location 0 even though alpha to coverage is enabled.");
Ari Suonpaa412b23b2019-02-26 07:56:58 +02001649 }
1650
Chris Forbes47567b72017-06-09 12:09:45 -07001651 return skip;
1652}
1653
Tobias Hector6663c9b2020-11-05 10:18:02 +00001654// For some built-in analysis we need to know if the variable decorated with as the built-in was actually written to.
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06001655// This function examines instructions in the static call tree for a write to this variable.
Tobias Hector6663c9b2020-11-05 10:18:02 +00001656static bool IsBuiltInWritten(SHADER_MODULE_STATE const *src, spirv_inst_iter builtin_instr, spirv_inst_iter entrypoint) {
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06001657 auto type = builtin_instr.opcode();
1658 uint32_t target_id = builtin_instr.word(1);
1659 bool init_complete = false;
1660
1661 if (type == spv::OpMemberDecorate) {
1662 // Built-in is part of a structure -- examine instructions up to first function body to get initial IDs
1663 auto insn = entrypoint;
1664 while (!init_complete && (insn.opcode() != spv::OpFunction)) {
1665 switch (insn.opcode()) {
1666 case spv::OpTypePointer:
1667 if ((insn.word(3) == target_id) && (insn.word(2) == spv::StorageClassOutput)) {
1668 target_id = insn.word(1);
1669 }
1670 break;
1671 case spv::OpVariable:
1672 if (insn.word(1) == target_id) {
1673 target_id = insn.word(2);
1674 init_complete = true;
1675 }
1676 break;
1677 }
1678 insn++;
1679 }
1680 }
1681
Mark Lobodzinskif84b0b42018-09-11 14:54:32 -06001682 if (!init_complete && (type == spv::OpMemberDecorate)) return false;
1683
1684 bool found_write = false;
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06001685 std::unordered_set<uint32_t> worklist;
1686 worklist.insert(entrypoint.word(2));
1687
1688 // Follow instructions in call graph looking for writes to target
1689 while (!worklist.empty() && !found_write) {
1690 auto id_iter = worklist.begin();
1691 auto id = *id_iter;
1692 worklist.erase(id_iter);
1693
1694 auto insn = src->get_def(id);
1695 if (insn == src->end()) {
1696 continue;
1697 }
1698
1699 if (insn.opcode() == spv::OpFunction) {
1700 // Scan body of function looking for other function calls or items in our ID chain
1701 while (++insn, insn.opcode() != spv::OpFunctionEnd) {
1702 switch (insn.opcode()) {
1703 case spv::OpAccessChain:
1704 if (insn.word(3) == target_id) {
1705 if (type == spv::OpMemberDecorate) {
1706 auto value = GetConstantValue(src, insn.word(4));
1707 if (value == builtin_instr.word(2)) {
1708 target_id = insn.word(2);
1709 }
1710 } else {
1711 target_id = insn.word(2);
1712 }
1713 }
1714 break;
1715 case spv::OpStore:
1716 if (insn.word(1) == target_id) {
1717 found_write = true;
1718 }
1719 break;
1720 case spv::OpFunctionCall:
1721 worklist.insert(insn.word(3));
1722 break;
1723 }
1724 }
1725 }
1726 }
1727 return found_write;
1728}
1729
Chris Forbes47567b72017-06-09 12:09:45 -07001730// For some analyses, we need to know about all ids referenced by the static call tree of a particular entrypoint. This is
1731// important for identifying the set of shader resources actually used by an entrypoint, for example.
1732// Note: we only explore parts of the image which might actually contain ids we care about for the above analyses.
1733// - NOT the shader input/output interfaces.
1734//
1735// TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth
1736// converting parts of this to be generated from the machine-readable spec instead.
locke-lunargd9a069d2019-09-17 01:50:19 -06001737std::unordered_set<uint32_t> MarkAccessibleIds(SHADER_MODULE_STATE const *src, spirv_inst_iter entrypoint) {
Chris Forbes47567b72017-06-09 12:09:45 -07001738 std::unordered_set<uint32_t> ids;
1739 std::unordered_set<uint32_t> worklist;
1740 worklist.insert(entrypoint.word(2));
1741
1742 while (!worklist.empty()) {
1743 auto id_iter = worklist.begin();
1744 auto id = *id_iter;
1745 worklist.erase(id_iter);
1746
1747 auto insn = src->get_def(id);
1748 if (insn == src->end()) {
Shannon McPhersonc06c33d2018-06-28 17:21:12 -06001749 // ID is something we didn't collect in BuildDefIndex. that's OK -- we'll stumble across all kinds of things here
Chris Forbes47567b72017-06-09 12:09:45 -07001750 // that we may not care about.
1751 continue;
1752 }
1753
1754 // Try to add to the output set
1755 if (!ids.insert(id).second) {
1756 continue; // If we already saw this id, we don't want to walk it again.
1757 }
1758
1759 switch (insn.opcode()) {
1760 case spv::OpFunction:
1761 // Scan whole body of the function, enlisting anything interesting
1762 while (++insn, insn.opcode() != spv::OpFunctionEnd) {
1763 switch (insn.opcode()) {
1764 case spv::OpLoad:
Chris Forbes47567b72017-06-09 12:09:45 -07001765 worklist.insert(insn.word(3)); // ptr
1766 break;
1767 case spv::OpStore:
Chris Forbes47567b72017-06-09 12:09:45 -07001768 worklist.insert(insn.word(1)); // ptr
1769 break;
1770 case spv::OpAccessChain:
1771 case spv::OpInBoundsAccessChain:
1772 worklist.insert(insn.word(3)); // base ptr
1773 break;
1774 case spv::OpSampledImage:
1775 case spv::OpImageSampleImplicitLod:
1776 case spv::OpImageSampleExplicitLod:
1777 case spv::OpImageSampleDrefImplicitLod:
1778 case spv::OpImageSampleDrefExplicitLod:
1779 case spv::OpImageSampleProjImplicitLod:
1780 case spv::OpImageSampleProjExplicitLod:
1781 case spv::OpImageSampleProjDrefImplicitLod:
1782 case spv::OpImageSampleProjDrefExplicitLod:
1783 case spv::OpImageFetch:
1784 case spv::OpImageGather:
1785 case spv::OpImageDrefGather:
1786 case spv::OpImageRead:
1787 case spv::OpImage:
1788 case spv::OpImageQueryFormat:
1789 case spv::OpImageQueryOrder:
1790 case spv::OpImageQuerySizeLod:
1791 case spv::OpImageQuerySize:
1792 case spv::OpImageQueryLod:
1793 case spv::OpImageQueryLevels:
1794 case spv::OpImageQuerySamples:
1795 case spv::OpImageSparseSampleImplicitLod:
1796 case spv::OpImageSparseSampleExplicitLod:
1797 case spv::OpImageSparseSampleDrefImplicitLod:
1798 case spv::OpImageSparseSampleDrefExplicitLod:
1799 case spv::OpImageSparseSampleProjImplicitLod:
1800 case spv::OpImageSparseSampleProjExplicitLod:
1801 case spv::OpImageSparseSampleProjDrefImplicitLod:
1802 case spv::OpImageSparseSampleProjDrefExplicitLod:
1803 case spv::OpImageSparseFetch:
1804 case spv::OpImageSparseGather:
1805 case spv::OpImageSparseDrefGather:
1806 case spv::OpImageTexelPointer:
1807 worklist.insert(insn.word(3)); // Image or sampled image
1808 break;
1809 case spv::OpImageWrite:
1810 worklist.insert(insn.word(1)); // Image -- different operand order to above
1811 break;
1812 case spv::OpFunctionCall:
1813 for (uint32_t i = 3; i < insn.len(); i++) {
1814 worklist.insert(insn.word(i)); // fn itself, and all args
1815 }
1816 break;
1817
1818 case spv::OpExtInst:
1819 for (uint32_t i = 5; i < insn.len(); i++) {
1820 worklist.insert(insn.word(i)); // Operands to ext inst
1821 }
1822 break;
locke-lunarg25b6c352020-08-06 17:44:18 -06001823
1824 default: {
1825 if (AtomicOperation(insn.opcode())) {
1826 if (insn.opcode() == spv::OpAtomicStore) {
1827 worklist.insert(insn.word(1)); // ptr
1828 } else {
1829 worklist.insert(insn.word(3)); // ptr
1830 }
1831 }
1832 break;
1833 }
Chris Forbes47567b72017-06-09 12:09:45 -07001834 }
1835 }
1836 break;
1837 }
1838 }
1839
1840 return ids;
1841}
1842
locke-lunarg3d8b8f32020-10-26 17:04:16 -06001843PushConstantByteState CoreChecks::ValidatePushConstantSetUpdate(const std::vector<uint8_t> &push_constant_data_update,
1844 const shader_struct_member &push_constant_used_in_shader,
1845 uint32_t &out_issue_index) const {
locke-lunargde3f0fa2020-09-10 11:55:31 -06001846 const auto *used_bytes = push_constant_used_in_shader.GetUsedbytes();
locke-lunarg3d8b8f32020-10-26 17:04:16 -06001847 const auto used_bytes_size = used_bytes->size();
1848 if (used_bytes_size == 0) return PC_Byte_Updated;
1849
1850 const auto push_constant_data_update_size = push_constant_data_update.size();
1851 const auto *data = push_constant_data_update.data();
1852 if ((*data == PC_Byte_Updated) && std::memcmp(data, data + 1, push_constant_data_update_size - 1) == 0) {
1853 if (used_bytes_size <= push_constant_data_update_size) {
1854 return PC_Byte_Updated;
1855 }
1856 const auto used_bytes_size1 = used_bytes_size - push_constant_data_update_size;
1857
1858 const auto *used_bytes_data1 = used_bytes->data() + push_constant_data_update_size;
1859 if ((*used_bytes_data1 == 0) && std::memcmp(used_bytes_data1, used_bytes_data1 + 1, used_bytes_size1 - 1) == 0) {
1860 return PC_Byte_Updated;
1861 }
locke-lunargde3f0fa2020-09-10 11:55:31 -06001862 }
locke-lunarg3d8b8f32020-10-26 17:04:16 -06001863
locke-lunargde3f0fa2020-09-10 11:55:31 -06001864 uint32_t i = 0;
1865 for (const auto used : *used_bytes) {
1866 if (used) {
locke-lunarg3d8b8f32020-10-26 17:04:16 -06001867 if (i >= push_constant_data_update.size() || push_constant_data_update[i] == PC_Byte_Not_Set) {
locke-lunargde3f0fa2020-09-10 11:55:31 -06001868 out_issue_index = i;
locke-lunarg3d8b8f32020-10-26 17:04:16 -06001869 return PC_Byte_Not_Set;
1870 } else if (push_constant_data_update[i] == PC_Byte_Not_Updated) {
locke-lunargde3f0fa2020-09-10 11:55:31 -06001871 out_issue_index = i;
locke-lunarg3d8b8f32020-10-26 17:04:16 -06001872 return PC_Byte_Not_Updated;
locke-lunargde3f0fa2020-09-10 11:55:31 -06001873 }
1874 }
1875 ++i;
1876 }
locke-lunarg3d8b8f32020-10-26 17:04:16 -06001877 return PC_Byte_Updated;
locke-lunargde3f0fa2020-09-10 11:55:31 -06001878}
1879
1880bool CoreChecks::ValidatePushConstantUsage(const PIPELINE_STATE &pipeline, SHADER_MODULE_STATE const *src,
1881 VkPipelineShaderStageCreateInfo const *pStage) const {
Chris Forbes47567b72017-06-09 12:09:45 -07001882 bool skip = false;
Chris Forbes47567b72017-06-09 12:09:45 -07001883 // Validate directly off the offsets. this isn't quite correct for arrays and matrices, but is a good first step.
locke-lunargde3f0fa2020-09-10 11:55:31 -06001884 const auto *entrypoint = FindEntrypointStruct(src, pStage->pName, pStage->stage);
1885 if (!entrypoint || !entrypoint->push_constant_used_in_shader.IsUsed()) {
1886 return skip;
1887 }
1888 std::vector<VkPushConstantRange> const *push_constant_ranges = pipeline.pipeline_layout->push_constant_ranges.get();
Chris Forbes47567b72017-06-09 12:09:45 -07001889
locke-lunargde3f0fa2020-09-10 11:55:31 -06001890 bool found_stage = false;
1891 for (auto const &range : *push_constant_ranges) {
1892 if (range.stageFlags & pStage->stage) {
1893 found_stage = true;
1894 std::string location_desc;
locke-lunarg3d8b8f32020-10-26 17:04:16 -06001895 std::vector<uint8_t> push_constant_bytes_set;
locke-lunargde3f0fa2020-09-10 11:55:31 -06001896 if (range.offset > 0) {
locke-lunarg3d8b8f32020-10-26 17:04:16 -06001897 push_constant_bytes_set.resize(range.offset, PC_Byte_Not_Set);
locke-lunargde3f0fa2020-09-10 11:55:31 -06001898 }
locke-lunarg3d8b8f32020-10-26 17:04:16 -06001899 push_constant_bytes_set.resize(range.offset + range.size, PC_Byte_Updated);
locke-lunargde3f0fa2020-09-10 11:55:31 -06001900 uint32_t issue_index = 0;
locke-lunarg3d8b8f32020-10-26 17:04:16 -06001901 const auto ret =
1902 ValidatePushConstantSetUpdate(push_constant_bytes_set, entrypoint->push_constant_used_in_shader, issue_index);
Chris Forbes47567b72017-06-09 12:09:45 -07001903
locke-lunarg3d8b8f32020-10-26 17:04:16 -06001904 if (ret == PC_Byte_Not_Set) {
locke-lunargde3f0fa2020-09-10 11:55:31 -06001905 const auto loc_descr = entrypoint->push_constant_used_in_shader.GetLocationDesc(issue_index);
1906 LogObjectList objlist(src->vk_shader_module);
1907 objlist.add(pipeline.pipeline_layout->layout);
1908 skip |= LogError(objlist, kVUID_Core_Shader_PushConstantOutOfRange,
1909 "Push-constant buffer:%s in %s is out of range in %s.", loc_descr.c_str(),
1910 string_VkShaderStageFlags(pStage->stage).c_str(),
1911 report_data->FormatHandle(pipeline.pipeline_layout->layout).c_str());
1912 break;
Chris Forbes47567b72017-06-09 12:09:45 -07001913 }
1914 }
1915 }
1916
locke-lunargde3f0fa2020-09-10 11:55:31 -06001917 if (!found_stage) {
1918 LogObjectList objlist(src->vk_shader_module);
1919 objlist.add(pipeline.pipeline_layout->layout);
1920 skip |= LogError(
1921 objlist, kVUID_Core_Shader_PushConstantOutOfRange, "Push constant is used in %s of %s. But %s doesn't set %s.",
1922 string_VkShaderStageFlags(pStage->stage).c_str(), report_data->FormatHandle(src->vk_shader_module).c_str(),
1923 report_data->FormatHandle(pipeline.pipeline_layout->layout).c_str(), string_VkShaderStageFlags(pStage->stage).c_str());
Chris Forbes47567b72017-06-09 12:09:45 -07001924 }
Chris Forbes47567b72017-06-09 12:09:45 -07001925 return skip;
1926}
1927
sfricke-samsungef2a68c2020-10-26 04:22:46 -07001928bool CoreChecks::ValidateBuiltinLimits(SHADER_MODULE_STATE const *src, const std::unordered_set<uint32_t> &accessible_ids,
1929 VkShaderStageFlagBits stage) const {
1930 bool skip = false;
1931
1932 // Currently all builtin tested are only found in fragment shaders
1933 if (stage != VK_SHADER_STAGE_FRAGMENT_BIT) {
1934 return skip;
1935 }
1936
1937 for (const auto id : accessible_ids) {
1938 auto insn = src->get_def(id);
1939 const decoration_set decorations = src->get_decorations(insn.word(2));
1940
1941 // Built-ins are obtained from OpVariable
1942 if (((decorations.flags & decoration_set::builtin_bit) != 0) && (insn.opcode() == spv::OpVariable)) {
1943 auto type_pointer = src->get_def(insn.word(1));
1944 assert(type_pointer.opcode() == spv::OpTypePointer);
1945
1946 auto type = src->get_def(type_pointer.word(3));
1947 if (type.opcode() == spv::OpTypeArray) {
1948 uint32_t length = static_cast<uint32_t>(GetConstantValue(src, type.word(3)));
1949
1950 switch (decorations.builtin) {
1951 case spv::BuiltInSampleMask:
1952 // Handles both the input and output sampleMask
1953 if (length > phys_dev_props.limits.maxSampleMaskWords) {
1954 skip |= LogError(device, "VUID-VkPipelineShaderStageCreateInfo-maxSampleMaskWords-00711",
1955 "vkCreateGraphicsPipelines(): The BuiltIns SampleMask array sizes is %u which exceeds "
1956 "maxSampleMaskWords of %u in %s.",
1957 length, phys_dev_props.limits.maxSampleMaskWords,
1958 report_data->FormatHandle(src->vk_shader_module).c_str());
1959 }
1960 break;
1961 }
1962 }
1963 }
1964 }
1965
1966 return skip;
1967}
1968
Chris Forbes47567b72017-06-09 12:09:45 -07001969// Validate that data for each specialization entry is fully contained within the buffer.
Mark Lobodzinskid8d658e2020-01-30 15:05:51 -07001970bool CoreChecks::ValidateSpecializationOffsets(VkPipelineShaderStageCreateInfo const *info) const {
Chris Forbes47567b72017-06-09 12:09:45 -07001971 bool skip = false;
1972
1973 VkSpecializationInfo const *spec = info->pSpecializationInfo;
1974
1975 if (spec) {
1976 for (auto i = 0u; i < spec->mapEntryCount; i++) {
Jeremy Hayes6c555c32019-09-09 17:14:09 -06001977 if (spec->pMapEntries[i].offset >= spec->dataSize) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07001978 skip |= LogError(device, "VUID-VkSpecializationInfo-offset-00773",
1979 "Specialization entry %u (for constant id %u) references memory outside provided specialization "
1980 "data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER " bytes provided)..",
1981 i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset,
1982 spec->pMapEntries[i].offset + spec->dataSize - 1, spec->dataSize);
Jeremy Hayes6c555c32019-09-09 17:14:09 -06001983
1984 continue;
1985 }
Chris Forbes47567b72017-06-09 12:09:45 -07001986 if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07001987 skip |= LogError(device, "VUID-VkSpecializationInfo-pMapEntries-00774",
1988 "Specialization entry %u (for constant id %u) references memory outside provided specialization "
1989 "data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER " bytes provided)..",
1990 i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset,
1991 spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize);
Chris Forbes47567b72017-06-09 12:09:45 -07001992 }
1993 }
1994 }
1995
1996 return skip;
1997}
1998
Jeff Bolz38b3ce72018-09-19 12:53:38 -05001999// TODO (jbolz): Can this return a const reference?
sourav parmarcd5fb182020-07-17 12:58:44 -07002000static std::set<uint32_t> TypeToDescriptorTypeSet(SHADER_MODULE_STATE const *module, uint32_t type_id, unsigned &descriptor_count,
2001 bool is_khr) {
Chris Forbes47567b72017-06-09 12:09:45 -07002002 auto type = module->get_def(type_id);
Chris Forbes9f89d752018-03-07 12:57:48 -08002003 bool is_storage_buffer = false;
Chris Forbes47567b72017-06-09 12:09:45 -07002004 descriptor_count = 1;
Jeff Bolze54ae892018-09-08 12:16:29 -05002005 std::set<uint32_t> ret;
Chris Forbes47567b72017-06-09 12:09:45 -07002006
2007 // Strip off any array or ptrs. Where we remove array levels, adjust the descriptor count for each dimension.
Jeff Bolzfdf96072018-04-10 14:32:18 -05002008 while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer || type.opcode() == spv::OpTypeRuntimeArray) {
2009 if (type.opcode() == spv::OpTypeRuntimeArray) {
2010 descriptor_count = 0;
2011 type = module->get_def(type.word(2));
2012 } else if (type.opcode() == spv::OpTypeArray) {
Shannon McPhersonc06c33d2018-06-28 17:21:12 -06002013 descriptor_count *= GetConstantValue(module, type.word(3));
Chris Forbes47567b72017-06-09 12:09:45 -07002014 type = module->get_def(type.word(2));
2015 } else {
Chris Forbes9f89d752018-03-07 12:57:48 -08002016 if (type.word(2) == spv::StorageClassStorageBuffer) {
2017 is_storage_buffer = true;
2018 }
Chris Forbes47567b72017-06-09 12:09:45 -07002019 type = module->get_def(type.word(3));
2020 }
2021 }
2022
2023 switch (type.opcode()) {
2024 case spv::OpTypeStruct: {
2025 for (auto insn : *module) {
2026 if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) {
2027 if (insn.word(2) == spv::DecorationBlock) {
Chris Forbes9f89d752018-03-07 12:57:48 -08002028 if (is_storage_buffer) {
Jeff Bolze54ae892018-09-08 12:16:29 -05002029 ret.insert(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
2030 ret.insert(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
2031 return ret;
Chris Forbes9f89d752018-03-07 12:57:48 -08002032 } else {
Jeff Bolze54ae892018-09-08 12:16:29 -05002033 ret.insert(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
2034 ret.insert(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC);
2035 ret.insert(VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT);
2036 return ret;
Chris Forbes9f89d752018-03-07 12:57:48 -08002037 }
Chris Forbes47567b72017-06-09 12:09:45 -07002038 } else if (insn.word(2) == spv::DecorationBufferBlock) {
Jeff Bolze54ae892018-09-08 12:16:29 -05002039 ret.insert(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
2040 ret.insert(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
2041 return ret;
Chris Forbes47567b72017-06-09 12:09:45 -07002042 }
2043 }
2044 }
2045
2046 // Invalid
Jeff Bolze54ae892018-09-08 12:16:29 -05002047 return ret;
Chris Forbes47567b72017-06-09 12:09:45 -07002048 }
2049
2050 case spv::OpTypeSampler:
Jeff Bolze54ae892018-09-08 12:16:29 -05002051 ret.insert(VK_DESCRIPTOR_TYPE_SAMPLER);
2052 ret.insert(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
2053 return ret;
Chris Forbes47567b72017-06-09 12:09:45 -07002054
Chris Forbes73c00bf2018-06-22 16:28:06 -07002055 case spv::OpTypeSampledImage: {
2056 // Slight relaxation for some GLSL historical madness: samplerBuffer doesn't really have a sampler, and a texel
2057 // buffer descriptor doesn't really provide one. Allow this slight mismatch.
2058 auto image_type = module->get_def(type.word(2));
2059 auto dim = image_type.word(3);
2060 auto sampled = image_type.word(7);
2061 if (dim == spv::DimBuffer && sampled == 1) {
Jeff Bolze54ae892018-09-08 12:16:29 -05002062 ret.insert(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER);
2063 return ret;
Chris Forbes47567b72017-06-09 12:09:45 -07002064 }
Chris Forbes73c00bf2018-06-22 16:28:06 -07002065 }
Jeff Bolze54ae892018-09-08 12:16:29 -05002066 ret.insert(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
2067 return ret;
Chris Forbes47567b72017-06-09 12:09:45 -07002068
2069 case spv::OpTypeImage: {
2070 // Many descriptor types backing image types-- depends on dimension and whether the image will be used with a sampler.
2071 // SPIRV for Vulkan requires that sampled be 1 or 2 -- leaving the decision to runtime is unacceptable.
2072 auto dim = type.word(3);
2073 auto sampled = type.word(7);
2074
2075 if (dim == spv::DimSubpassData) {
Jeff Bolze54ae892018-09-08 12:16:29 -05002076 ret.insert(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
2077 return ret;
Chris Forbes47567b72017-06-09 12:09:45 -07002078 } else if (dim == spv::DimBuffer) {
2079 if (sampled == 1) {
Jeff Bolze54ae892018-09-08 12:16:29 -05002080 ret.insert(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER);
2081 return ret;
Chris Forbes47567b72017-06-09 12:09:45 -07002082 } else {
Jeff Bolze54ae892018-09-08 12:16:29 -05002083 ret.insert(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER);
2084 return ret;
Chris Forbes47567b72017-06-09 12:09:45 -07002085 }
2086 } else if (sampled == 1) {
Jeff Bolze54ae892018-09-08 12:16:29 -05002087 ret.insert(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
2088 ret.insert(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
2089 return ret;
Chris Forbes47567b72017-06-09 12:09:45 -07002090 } else {
Jeff Bolze54ae892018-09-08 12:16:29 -05002091 ret.insert(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
2092 return ret;
Chris Forbes47567b72017-06-09 12:09:45 -07002093 }
2094 }
Shannon McPherson0fa28232018-11-01 11:59:02 -06002095 case spv::OpTypeAccelerationStructureNV:
sourav parmarcd5fb182020-07-17 12:58:44 -07002096 is_khr ? ret.insert(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
2097 : ret.insert(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV);
Jeff Bolz105d6492018-09-29 15:46:44 -05002098 return ret;
Chris Forbes47567b72017-06-09 12:09:45 -07002099
2100 // We shouldn't really see any other junk types -- but if we do, they're a mismatch.
2101 default:
Jeff Bolze54ae892018-09-08 12:16:29 -05002102 return ret; // Matches nothing
Chris Forbes47567b72017-06-09 12:09:45 -07002103 }
2104}
2105
Jeff Bolze54ae892018-09-08 12:16:29 -05002106static std::string string_descriptorTypes(const std::set<uint32_t> &descriptor_types) {
Chris Forbes73c00bf2018-06-22 16:28:06 -07002107 std::stringstream ss;
Jeff Bolze54ae892018-09-08 12:16:29 -05002108 for (auto it = descriptor_types.begin(); it != descriptor_types.end(); ++it) {
2109 if (ss.tellp()) ss << ", ";
2110 ss << string_VkDescriptorType(VkDescriptorType(*it));
Chris Forbes73c00bf2018-06-22 16:28:06 -07002111 }
2112 return ss.str();
2113}
2114
sfricke-samsung0065ce02020-12-03 22:46:37 -08002115bool CoreChecks::RequirePropertyFlag(VkBool32 check, char const *flag, char const *structure, const char *vuid) const {
Jeff Bolzee743412019-06-20 22:24:32 -05002116 if (!check) {
sfricke-samsung0065ce02020-12-03 22:46:37 -08002117 if (LogError(device, vuid, "Shader requires flag %s set in %s but it is not set on the device", flag, structure)) {
Jeff Bolzee743412019-06-20 22:24:32 -05002118 return true;
2119 }
2120 }
2121
2122 return false;
2123}
2124
sfricke-samsung0065ce02020-12-03 22:46:37 -08002125bool CoreChecks::RequireFeature(VkBool32 feature, char const *feature_name, const char *vuid) const {
Chris Forbes47567b72017-06-09 12:09:45 -07002126 if (!feature) {
sfricke-samsung0065ce02020-12-03 22:46:37 -08002127 if (LogError(device, vuid, "Shader requires %s but is not enabled on the device", feature_name)) {
Chris Forbes47567b72017-06-09 12:09:45 -07002128 return true;
2129 }
2130 }
2131
2132 return false;
2133}
2134
locke-lunarg63e4daf2020-08-17 17:53:25 -06002135bool CoreChecks::ValidateShaderStageWritableOrAtomicDescriptor(VkShaderStageFlagBits stage, bool has_writable_descriptor,
2136 bool has_atomic_descriptor) const {
Jeff Bolzee743412019-06-20 22:24:32 -05002137 bool skip = false;
2138
locke-lunarg63e4daf2020-08-17 17:53:25 -06002139 if (has_writable_descriptor || has_atomic_descriptor) {
Chris Forbes349b3132018-03-07 11:38:08 -08002140 switch (stage) {
2141 case VK_SHADER_STAGE_COMPUTE_BIT:
Jeff Bolz148d94e2018-12-13 21:25:56 -06002142 case VK_SHADER_STAGE_RAYGEN_BIT_NV:
2143 case VK_SHADER_STAGE_ANY_HIT_BIT_NV:
2144 case VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV:
2145 case VK_SHADER_STAGE_MISS_BIT_NV:
2146 case VK_SHADER_STAGE_INTERSECTION_BIT_NV:
2147 case VK_SHADER_STAGE_CALLABLE_BIT_NV:
2148 case VK_SHADER_STAGE_TASK_BIT_NV:
2149 case VK_SHADER_STAGE_MESH_BIT_NV:
Chris Forbes349b3132018-03-07 11:38:08 -08002150 /* No feature requirements for writes and atomics from compute
Jeff Bolz148d94e2018-12-13 21:25:56 -06002151 * raytracing, or mesh stages */
Chris Forbes349b3132018-03-07 11:38:08 -08002152 break;
2153 case VK_SHADER_STAGE_FRAGMENT_BIT:
sfricke-samsung0065ce02020-12-03 22:46:37 -08002154 skip |= RequireFeature(enabled_features.core.fragmentStoresAndAtomics, "fragmentStoresAndAtomics",
2155 kVUID_Core_Shader_FeatureNotEnabled);
Chris Forbes349b3132018-03-07 11:38:08 -08002156 break;
2157 default:
sfricke-samsung0065ce02020-12-03 22:46:37 -08002158 skip |= RequireFeature(enabled_features.core.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics",
2159 kVUID_Core_Shader_FeatureNotEnabled);
Chris Forbes349b3132018-03-07 11:38:08 -08002160 break;
2161 }
2162 }
2163
Chris Forbes47567b72017-06-09 12:09:45 -07002164 return skip;
2165}
2166
Jeff Bolz526f2d52019-09-18 13:18:08 -05002167bool CoreChecks::ValidateShaderStageGroupNonUniform(SHADER_MODULE_STATE const *module, VkShaderStageFlagBits stage) const {
Jeff Bolzee743412019-06-20 22:24:32 -05002168 bool skip = false;
2169
Piers Daniell41b8c5d2020-01-10 15:42:00 -07002170 auto const subgroup_props = phys_dev_props_core11;
sfricke-samsung0065ce02020-12-03 22:46:37 -08002171 const VkSubgroupFeatureFlags supportedStages = subgroup_props.subgroupSupportedStages;
Jeff Bolzee743412019-06-20 22:24:32 -05002172
Jeff Bolz526f2d52019-09-18 13:18:08 -05002173 for (auto inst : *module) {
sfricke-samsung0065ce02020-12-03 22:46:37 -08002174 // Check anything using a group operation (which currently is only OpGroupNonUnifrom* operations)
2175 if (GroupOperation(inst.opcode()) == true) {
2176 // Check the quad operations.
2177 if ((inst.opcode() == spv::OpGroupNonUniformQuadBroadcast) || (inst.opcode() == spv::OpGroupNonUniformQuadSwap)) {
Jeff Bolzee743412019-06-20 22:24:32 -05002178 if ((stage != VK_SHADER_STAGE_FRAGMENT_BIT) && (stage != VK_SHADER_STAGE_COMPUTE_BIT)) {
Mark Lobodzinskid8d658e2020-01-30 15:05:51 -07002179 skip |= RequireFeature(subgroup_props.subgroupQuadOperationsInAllStages,
sfricke-samsung0065ce02020-12-03 22:46:37 -08002180 "VkPhysicalDeviceSubgroupProperties::quadOperationsInAllStages",
2181 kVUID_Core_Shader_FeatureNotEnabled);
Jeff Bolzee743412019-06-20 22:24:32 -05002182 }
sfricke-samsung0065ce02020-12-03 22:46:37 -08002183 }
Jeff Bolz526f2d52019-09-18 13:18:08 -05002184
sfricke-samsung0065ce02020-12-03 22:46:37 -08002185 auto scope_id = module->get_def(inst.word(3));
2186 uint32_t scope_type = spv::ScopeMax;
2187 if ((scope_id.opcode() == spv::OpSpecConstant) || (scope_id.opcode() == spv::OpConstant)) {
2188 scope_type = scope_id.word(3);
2189 } else {
2190 // TODO - Look if this is check by spirv-val
2191 skip |= LogWarning(device, "UNASSIGNED-spirv-group-scopeId",
2192 "Expecting group operation (%u) scope id operand to point to a OpConstant or OpSpecConstant "
2193 "opcode but instead it is pointing to opcode (%u)",
2194 inst.opcode(), scope_id.opcode());
2195 }
2196
2197 if (scope_type == spv::ScopeSubgroup) {
2198 // "Group operations with subgroup scope" must have stage support
2199 skip |=
2200 RequirePropertyFlag(supportedStages & stage, string_VkShaderStageFlagBits(stage),
2201 "VkPhysicalDeviceSubgroupProperties::supportedStages", kVUID_Core_Shader_ExceedDeviceLimit);
2202 }
2203
2204 if (!enabled_features.core12.shaderSubgroupExtendedTypes) {
2205 auto type = module->get_def(inst.word(1));
2206
2207 if (type.opcode() == spv::OpTypeVector) {
2208 // Get the element type
2209 type = module->get_def(type.word(2));
2210 }
2211
2212 if (type.opcode() == spv::OpTypeBool) {
Jeff Bolz526f2d52019-09-18 13:18:08 -05002213 break;
sfricke-samsung0065ce02020-12-03 22:46:37 -08002214 }
Jeff Bolz526f2d52019-09-18 13:18:08 -05002215
sfricke-samsung0065ce02020-12-03 22:46:37 -08002216 // Both OpTypeInt and OpTypeFloat the width is in the 2nd word.
2217 const uint32_t width = type.word(2);
Jeff Bolz526f2d52019-09-18 13:18:08 -05002218
sfricke-samsung0065ce02020-12-03 22:46:37 -08002219 if ((type.opcode() == spv::OpTypeFloat && width == 16) ||
2220 (type.opcode() == spv::OpTypeInt && (width == 8 || width == 16 || width == 64))) {
2221 skip |= RequireFeature(enabled_features.core12.shaderSubgroupExtendedTypes,
2222 "VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures::shaderSubgroupExtendedTypes",
2223 kVUID_Core_Shader_FeatureNotEnabled);
Jeff Bolz526f2d52019-09-18 13:18:08 -05002224 }
2225 }
2226 }
Jeff Bolzee743412019-06-20 22:24:32 -05002227 }
2228
2229 return skip;
2230}
2231
Mark Lobodzinski3c59d972019-04-25 11:28:14 -06002232bool CoreChecks::ValidateShaderStageInputOutputLimits(SHADER_MODULE_STATE const *src, VkPipelineShaderStageCreateInfo const *pStage,
John Zulaufac4c6e12019-07-01 16:05:58 -06002233 const PIPELINE_STATE *pipeline, spirv_inst_iter entrypoint) const {
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002234 if (pStage->stage == VK_SHADER_STAGE_COMPUTE_BIT || pStage->stage == VK_SHADER_STAGE_ALL_GRAPHICS ||
2235 pStage->stage == VK_SHADER_STAGE_ALL) {
2236 return false;
2237 }
2238
2239 bool skip = false;
Mark Lobodzinski518eadc2019-03-09 12:07:30 -07002240 auto const &limits = phys_dev_props.limits;
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002241
Jeff Bolze9ee3d82019-05-29 13:45:13 -05002242 std::set<uint32_t> patchIDs;
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002243 struct Variable {
2244 uint32_t baseTypePtrID;
2245 uint32_t ID;
2246 uint32_t storageClass;
2247 };
2248 std::vector<Variable> variables;
2249
Jeff Bolze9ee3d82019-05-29 13:45:13 -05002250 uint32_t numVertices = 0;
2251
Jeff Bolzf234bf82019-11-04 14:07:15 -06002252 auto entrypointVariables = FindEntrypointInterfaces(entrypoint);
2253
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002254 for (auto insn : *src) {
2255 switch (insn.opcode()) {
Jeff Bolze9ee3d82019-05-29 13:45:13 -05002256 // Find all Patch decorations
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002257 case spv::OpDecorate:
2258 switch (insn.word(2)) {
Jeff Bolze9ee3d82019-05-29 13:45:13 -05002259 case spv::DecorationPatch: {
2260 patchIDs.insert(insn.word(1));
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002261 break;
2262 }
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002263 default:
2264 break;
2265 }
2266 break;
2267 // Find all input and output variables
2268 case spv::OpVariable: {
2269 Variable var = {};
2270 var.storageClass = insn.word(3);
Jeff Bolzf234bf82019-11-04 14:07:15 -06002271 if ((var.storageClass == spv::StorageClassInput || var.storageClass == spv::StorageClassOutput) &&
2272 // Only include variables in the entrypoint's interface
2273 find(entrypointVariables.begin(), entrypointVariables.end(), insn.word(2)) != entrypointVariables.end()) {
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002274 var.baseTypePtrID = insn.word(1);
2275 var.ID = insn.word(2);
2276 variables.push_back(var);
2277 }
2278 break;
2279 }
Jeff Bolze9ee3d82019-05-29 13:45:13 -05002280 case spv::OpExecutionMode:
2281 if (insn.word(1) == entrypoint.word(2)) {
2282 switch (insn.word(2)) {
2283 default:
2284 break;
2285 case spv::ExecutionModeOutputVertices:
2286 numVertices = insn.word(3);
2287 break;
2288 }
2289 }
2290 break;
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002291 default:
2292 break;
2293 }
2294 }
2295
Jeff Bolze9ee3d82019-05-29 13:45:13 -05002296 bool strip_output_array_level =
2297 (pStage->stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT || pStage->stage == VK_SHADER_STAGE_MESH_BIT_NV);
2298 bool strip_input_array_level =
2299 (pStage->stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
2300 pStage->stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT || pStage->stage == VK_SHADER_STAGE_GEOMETRY_BIT);
2301
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002302 uint32_t numCompIn = 0, numCompOut = 0;
Jeff Bolzf234bf82019-11-04 14:07:15 -06002303 int maxCompIn = 0, maxCompOut = 0;
2304
2305 auto inputs = CollectInterfaceByLocation(src, entrypoint, spv::StorageClassInput, strip_input_array_level);
2306 auto outputs = CollectInterfaceByLocation(src, entrypoint, spv::StorageClassOutput, strip_output_array_level);
2307
2308 // Find max component location used for input variables.
2309 for (auto &var : inputs) {
2310 int location = var.first.first;
2311 int component = var.first.second;
2312 interface_var &iv = var.second;
2313
2314 // Only need to look at the first location, since we use the type's whole size
2315 if (iv.offset != 0) {
2316 continue;
2317 }
2318
2319 if (iv.is_patch) {
2320 continue;
2321 }
2322
2323 int numComponents = GetComponentsConsumedByType(src, iv.type_id, strip_input_array_level);
2324 maxCompIn = std::max(maxCompIn, location * 4 + component + numComponents);
2325 }
2326
2327 // Find max component location used for output variables.
2328 for (auto &var : outputs) {
2329 int location = var.first.first;
2330 int component = var.first.second;
2331 interface_var &iv = var.second;
2332
2333 // Only need to look at the first location, since we use the type's whole size
2334 if (iv.offset != 0) {
2335 continue;
2336 }
2337
2338 if (iv.is_patch) {
2339 continue;
2340 }
2341
2342 int numComponents = GetComponentsConsumedByType(src, iv.type_id, strip_output_array_level);
2343 maxCompOut = std::max(maxCompOut, location * 4 + component + numComponents);
2344 }
2345
2346 // XXX TODO: Would be nice to rewrite this to use CollectInterfaceByLocation (or something similar),
2347 // but that doesn't include builtins.
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002348 for (auto &var : variables) {
Jeff Bolze9ee3d82019-05-29 13:45:13 -05002349 // Check if the variable is a patch. Patches can also be members of blocks,
2350 // but if they are then the top-level arrayness has already been stripped
2351 // by the time GetComponentsConsumedByType gets to it.
2352 bool isPatch = patchIDs.find(var.ID) != patchIDs.end();
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002353
2354 if (var.storageClass == spv::StorageClassInput) {
Jeff Bolze9ee3d82019-05-29 13:45:13 -05002355 numCompIn += GetComponentsConsumedByType(src, var.baseTypePtrID, strip_input_array_level && !isPatch);
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002356 } else { // var.storageClass == spv::StorageClassOutput
Jeff Bolze9ee3d82019-05-29 13:45:13 -05002357 numCompOut += GetComponentsConsumedByType(src, var.baseTypePtrID, strip_output_array_level && !isPatch);
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002358 }
2359 }
2360
2361 switch (pStage->stage) {
2362 case VK_SHADER_STAGE_VERTEX_BIT:
Mark Lobodzinski57a44272019-02-27 12:40:50 -07002363 if (numCompOut > limits.maxVertexOutputComponents) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002364 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2365 "Invalid Pipeline CreateInfo State: Vertex shader exceeds "
2366 "VkPhysicalDeviceLimits::maxVertexOutputComponents of %u "
2367 "components by %u components",
2368 limits.maxVertexOutputComponents, numCompOut - limits.maxVertexOutputComponents);
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002369 }
Jeff Bolzf234bf82019-11-04 14:07:15 -06002370 if (maxCompOut > (int)limits.maxVertexOutputComponents) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002371 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2372 "Invalid Pipeline CreateInfo State: Vertex shader output variable uses location that "
2373 "exceeds component limit VkPhysicalDeviceLimits::maxVertexOutputComponents (%u)",
2374 limits.maxVertexOutputComponents);
Jeff Bolzf234bf82019-11-04 14:07:15 -06002375 }
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002376 break;
2377
2378 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
Mark Lobodzinski57a44272019-02-27 12:40:50 -07002379 if (numCompIn > limits.maxTessellationControlPerVertexInputComponents) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002380 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2381 "Invalid Pipeline CreateInfo State: Tessellation control shader exceeds "
2382 "VkPhysicalDeviceLimits::maxTessellationControlPerVertexInputComponents of %u "
2383 "components by %u components",
2384 limits.maxTessellationControlPerVertexInputComponents,
2385 numCompIn - limits.maxTessellationControlPerVertexInputComponents);
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002386 }
Jeff Bolzf234bf82019-11-04 14:07:15 -06002387 if (maxCompIn > (int)limits.maxTessellationControlPerVertexInputComponents) {
2388 skip |=
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002389 LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2390 "Invalid Pipeline CreateInfo State: Tessellation control shader input variable uses location that "
2391 "exceeds component limit VkPhysicalDeviceLimits::maxTessellationControlPerVertexInputComponents (%u)",
2392 limits.maxTessellationControlPerVertexInputComponents);
Jeff Bolzf234bf82019-11-04 14:07:15 -06002393 }
Mark Lobodzinski57a44272019-02-27 12:40:50 -07002394 if (numCompOut > limits.maxTessellationControlPerVertexOutputComponents) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002395 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2396 "Invalid Pipeline CreateInfo State: Tessellation control shader exceeds "
2397 "VkPhysicalDeviceLimits::maxTessellationControlPerVertexOutputComponents of %u "
2398 "components by %u components",
2399 limits.maxTessellationControlPerVertexOutputComponents,
2400 numCompOut - limits.maxTessellationControlPerVertexOutputComponents);
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002401 }
Jeff Bolzf234bf82019-11-04 14:07:15 -06002402 if (maxCompOut > (int)limits.maxTessellationControlPerVertexOutputComponents) {
2403 skip |=
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002404 LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2405 "Invalid Pipeline CreateInfo State: Tessellation control shader output variable uses location that "
2406 "exceeds component limit VkPhysicalDeviceLimits::maxTessellationControlPerVertexOutputComponents (%u)",
2407 limits.maxTessellationControlPerVertexOutputComponents);
Jeff Bolzf234bf82019-11-04 14:07:15 -06002408 }
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002409 break;
2410
2411 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
Mark Lobodzinski57a44272019-02-27 12:40:50 -07002412 if (numCompIn > limits.maxTessellationEvaluationInputComponents) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002413 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2414 "Invalid Pipeline CreateInfo State: Tessellation evaluation shader exceeds "
2415 "VkPhysicalDeviceLimits::maxTessellationEvaluationInputComponents of %u "
2416 "components by %u components",
2417 limits.maxTessellationEvaluationInputComponents,
2418 numCompIn - limits.maxTessellationEvaluationInputComponents);
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002419 }
Jeff Bolzf234bf82019-11-04 14:07:15 -06002420 if (maxCompIn > (int)limits.maxTessellationEvaluationInputComponents) {
2421 skip |=
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002422 LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2423 "Invalid Pipeline CreateInfo State: Tessellation evaluation shader input variable uses location that "
2424 "exceeds component limit VkPhysicalDeviceLimits::maxTessellationEvaluationInputComponents (%u)",
2425 limits.maxTessellationEvaluationInputComponents);
Jeff Bolzf234bf82019-11-04 14:07:15 -06002426 }
Mark Lobodzinski57a44272019-02-27 12:40:50 -07002427 if (numCompOut > limits.maxTessellationEvaluationOutputComponents) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002428 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2429 "Invalid Pipeline CreateInfo State: Tessellation evaluation shader exceeds "
2430 "VkPhysicalDeviceLimits::maxTessellationEvaluationOutputComponents of %u "
2431 "components by %u components",
2432 limits.maxTessellationEvaluationOutputComponents,
2433 numCompOut - limits.maxTessellationEvaluationOutputComponents);
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002434 }
Jeff Bolzf234bf82019-11-04 14:07:15 -06002435 if (maxCompOut > (int)limits.maxTessellationEvaluationOutputComponents) {
2436 skip |=
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002437 LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2438 "Invalid Pipeline CreateInfo State: Tessellation evaluation shader output variable uses location that "
2439 "exceeds component limit VkPhysicalDeviceLimits::maxTessellationEvaluationOutputComponents (%u)",
2440 limits.maxTessellationEvaluationOutputComponents);
Jeff Bolzf234bf82019-11-04 14:07:15 -06002441 }
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002442 break;
2443
2444 case VK_SHADER_STAGE_GEOMETRY_BIT:
Mark Lobodzinski57a44272019-02-27 12:40:50 -07002445 if (numCompIn > limits.maxGeometryInputComponents) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002446 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2447 "Invalid Pipeline CreateInfo State: Geometry shader exceeds "
2448 "VkPhysicalDeviceLimits::maxGeometryInputComponents of %u "
2449 "components by %u components",
2450 limits.maxGeometryInputComponents, numCompIn - limits.maxGeometryInputComponents);
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002451 }
Jeff Bolzf234bf82019-11-04 14:07:15 -06002452 if (maxCompIn > (int)limits.maxGeometryInputComponents) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002453 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2454 "Invalid Pipeline CreateInfo State: Geometry shader input variable uses location that "
2455 "exceeds component limit VkPhysicalDeviceLimits::maxGeometryInputComponents (%u)",
2456 limits.maxGeometryInputComponents);
Jeff Bolzf234bf82019-11-04 14:07:15 -06002457 }
Mark Lobodzinski57a44272019-02-27 12:40:50 -07002458 if (numCompOut > limits.maxGeometryOutputComponents) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002459 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2460 "Invalid Pipeline CreateInfo State: Geometry shader exceeds "
2461 "VkPhysicalDeviceLimits::maxGeometryOutputComponents of %u "
2462 "components by %u components",
2463 limits.maxGeometryOutputComponents, numCompOut - limits.maxGeometryOutputComponents);
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002464 }
Jeff Bolzf234bf82019-11-04 14:07:15 -06002465 if (maxCompOut > (int)limits.maxGeometryOutputComponents) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002466 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2467 "Invalid Pipeline CreateInfo State: Geometry shader output variable uses location that "
2468 "exceeds component limit VkPhysicalDeviceLimits::maxGeometryOutputComponents (%u)",
2469 limits.maxGeometryOutputComponents);
Jeff Bolzf234bf82019-11-04 14:07:15 -06002470 }
Jeff Bolze9ee3d82019-05-29 13:45:13 -05002471 if (numCompOut * numVertices > limits.maxGeometryTotalOutputComponents) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002472 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2473 "Invalid Pipeline CreateInfo State: Geometry shader exceeds "
2474 "VkPhysicalDeviceLimits::maxGeometryTotalOutputComponents of %u "
2475 "components by %u components",
2476 limits.maxGeometryTotalOutputComponents,
2477 numCompOut * numVertices - limits.maxGeometryTotalOutputComponents);
Jeff Bolze9ee3d82019-05-29 13:45:13 -05002478 }
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002479 break;
2480
2481 case VK_SHADER_STAGE_FRAGMENT_BIT:
Mark Lobodzinski57a44272019-02-27 12:40:50 -07002482 if (numCompIn > limits.maxFragmentInputComponents) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002483 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2484 "Invalid Pipeline CreateInfo State: Fragment shader exceeds "
2485 "VkPhysicalDeviceLimits::maxFragmentInputComponents of %u "
2486 "components by %u components",
2487 limits.maxFragmentInputComponents, numCompIn - limits.maxFragmentInputComponents);
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002488 }
Jeff Bolzf234bf82019-11-04 14:07:15 -06002489 if (maxCompIn > (int)limits.maxFragmentInputComponents) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002490 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_ExceedDeviceLimit,
2491 "Invalid Pipeline CreateInfo State: Fragment shader input variable uses location that "
2492 "exceeds component limit VkPhysicalDeviceLimits::maxFragmentInputComponents (%u)",
2493 limits.maxFragmentInputComponents);
Jeff Bolzf234bf82019-11-04 14:07:15 -06002494 }
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002495 break;
2496
Jeff Bolz148d94e2018-12-13 21:25:56 -06002497 case VK_SHADER_STAGE_RAYGEN_BIT_NV:
2498 case VK_SHADER_STAGE_ANY_HIT_BIT_NV:
2499 case VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV:
2500 case VK_SHADER_STAGE_MISS_BIT_NV:
2501 case VK_SHADER_STAGE_INTERSECTION_BIT_NV:
2502 case VK_SHADER_STAGE_CALLABLE_BIT_NV:
2503 case VK_SHADER_STAGE_TASK_BIT_NV:
2504 case VK_SHADER_STAGE_MESH_BIT_NV:
2505 break;
2506
Daniel Fedai Larsenc939abc2018-08-07 10:01:58 +02002507 default:
2508 assert(false); // This should never happen
2509 }
2510 return skip;
2511}
2512
sfricke-samsungdc96f302020-03-18 20:42:10 -07002513bool CoreChecks::ValidateShaderStageMaxResources(VkShaderStageFlagBits stage, const PIPELINE_STATE *pipeline) const {
2514 bool skip = false;
2515 uint32_t total_resources = 0;
2516
2517 // Only currently testing for graphics and compute pipelines
2518 // TODO: Add check and support for Ray Tracing pipeline VUID 03428
2519 if ((stage & (VK_SHADER_STAGE_ALL_GRAPHICS | VK_SHADER_STAGE_COMPUTE_BIT)) == 0) {
2520 return false;
2521 }
2522
2523 if (stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
2524 // "For the fragment shader stage the framebuffer color attachments also count against this limit"
2525 total_resources += pipeline->rp_state->createInfo.pSubpasses[pipeline->graphicsPipelineCI.subpass].colorAttachmentCount;
2526 }
2527
2528 // TODO: This reuses a lot of GetDescriptorCountMaxPerStage but currently would need to make it agnostic in a way to handle
2529 // input from CreatePipeline and CreatePipelineLayout level
2530 for (auto set_layout : pipeline->pipeline_layout->set_layouts) {
2531 if ((set_layout->GetCreateFlags() & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT) != 0) {
2532 continue;
2533 }
2534
2535 for (uint32_t binding_idx = 0; binding_idx < set_layout->GetBindingCount(); binding_idx++) {
2536 const VkDescriptorSetLayoutBinding *binding = set_layout->GetDescriptorSetLayoutBindingPtrFromIndex(binding_idx);
2537 // Bindings with a descriptorCount of 0 are "reserved" and should be skipped
2538 if (((stage & binding->stageFlags) != 0) && (binding->descriptorCount > 0)) {
2539 // Check only descriptor types listed in maxPerStageResources description in spec
2540 switch (binding->descriptorType) {
2541 case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
2542 case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
2543 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
2544 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
2545 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
2546 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
2547 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
2548 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
2549 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
2550 case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
2551 total_resources += binding->descriptorCount;
2552 break;
2553 default:
2554 break;
2555 }
2556 }
2557 }
2558 }
2559
2560 if (total_resources > phys_dev_props.limits.maxPerStageResources) {
2561 const char *vuid = (stage == VK_SHADER_STAGE_COMPUTE_BIT) ? "VUID-VkComputePipelineCreateInfo-layout-01687"
2562 : "VUID-VkGraphicsPipelineCreateInfo-layout-01688";
2563 skip |= LogError(pipeline->pipeline, vuid,
2564 "Invalid Pipeline CreateInfo State: Shader Stage %s exceeds component limit "
2565 "VkPhysicalDeviceLimits::maxPerStageResources (%u)",
2566 string_VkShaderStageFlagBits(stage), phys_dev_props.limits.maxPerStageResources);
2567 }
2568
2569 return skip;
2570}
2571
Jeff Bolze4356752019-03-07 11:23:46 -06002572// copy the specialization constant value into buf, if it is present
2573void GetSpecConstantValue(VkPipelineShaderStageCreateInfo const *pStage, uint32_t spec_id, void *buf) {
2574 VkSpecializationInfo const *spec = pStage->pSpecializationInfo;
2575
2576 if (spec && spec_id < spec->mapEntryCount) {
2577 memcpy(buf, (uint8_t *)spec->pData + spec->pMapEntries[spec_id].offset, spec->pMapEntries[spec_id].size);
2578 }
2579}
2580
2581// Fill in value with the constant or specialization constant value, if available.
2582// Returns true if the value has been accurately filled out.
Mark Lobodzinski3c59d972019-04-25 11:28:14 -06002583static bool GetIntConstantValue(spirv_inst_iter insn, SHADER_MODULE_STATE const *src, VkPipelineShaderStageCreateInfo const *pStage,
Jeff Bolze4356752019-03-07 11:23:46 -06002584 const std::unordered_map<uint32_t, uint32_t> &id_to_spec_id, uint32_t *value) {
2585 auto type_id = src->get_def(insn.word(1));
2586 if (type_id.opcode() != spv::OpTypeInt || type_id.word(2) != 32) {
2587 return false;
2588 }
2589 switch (insn.opcode()) {
2590 case spv::OpSpecConstant:
2591 *value = insn.word(3);
2592 GetSpecConstantValue(pStage, id_to_spec_id.at(insn.word(2)), value);
2593 return true;
2594 case spv::OpConstant:
2595 *value = insn.word(3);
2596 return true;
2597 default:
2598 return false;
2599 }
2600}
2601
2602// Map SPIR-V type to VK_COMPONENT_TYPE enum
Mark Lobodzinski3c59d972019-04-25 11:28:14 -06002603VkComponentTypeNV GetComponentType(spirv_inst_iter insn, SHADER_MODULE_STATE const *src) {
Jeff Bolze4356752019-03-07 11:23:46 -06002604 switch (insn.opcode()) {
2605 case spv::OpTypeInt:
2606 switch (insn.word(2)) {
2607 case 8:
2608 return insn.word(3) != 0 ? VK_COMPONENT_TYPE_SINT8_NV : VK_COMPONENT_TYPE_UINT8_NV;
2609 case 16:
2610 return insn.word(3) != 0 ? VK_COMPONENT_TYPE_SINT16_NV : VK_COMPONENT_TYPE_UINT16_NV;
2611 case 32:
2612 return insn.word(3) != 0 ? VK_COMPONENT_TYPE_SINT32_NV : VK_COMPONENT_TYPE_UINT32_NV;
2613 case 64:
2614 return insn.word(3) != 0 ? VK_COMPONENT_TYPE_SINT64_NV : VK_COMPONENT_TYPE_UINT64_NV;
2615 default:
2616 return VK_COMPONENT_TYPE_MAX_ENUM_NV;
2617 }
2618 case spv::OpTypeFloat:
2619 switch (insn.word(2)) {
2620 case 16:
2621 return VK_COMPONENT_TYPE_FLOAT16_NV;
2622 case 32:
2623 return VK_COMPONENT_TYPE_FLOAT32_NV;
2624 case 64:
2625 return VK_COMPONENT_TYPE_FLOAT64_NV;
2626 default:
2627 return VK_COMPONENT_TYPE_MAX_ENUM_NV;
2628 }
2629 default:
2630 return VK_COMPONENT_TYPE_MAX_ENUM_NV;
2631 }
2632}
2633
2634// Validate SPV_NV_cooperative_matrix behavior that can't be statically validated
2635// in SPIRV-Tools (e.g. due to specialization constant usage).
Mark Lobodzinski3c59d972019-04-25 11:28:14 -06002636bool CoreChecks::ValidateCooperativeMatrix(SHADER_MODULE_STATE const *src, VkPipelineShaderStageCreateInfo const *pStage,
John Zulaufac4c6e12019-07-01 16:05:58 -06002637 const PIPELINE_STATE *pipeline) const {
Jeff Bolze4356752019-03-07 11:23:46 -06002638 bool skip = false;
2639
2640 // Map SPIR-V result ID to specialization constant id (SpecId decoration value)
2641 std::unordered_map<uint32_t, uint32_t> id_to_spec_id;
2642 // Map SPIR-V result ID to the ID of its type.
2643 std::unordered_map<uint32_t, uint32_t> id_to_type_id;
2644
2645 struct CoopMatType {
2646 uint32_t scope, rows, cols;
2647 VkComponentTypeNV component_type;
2648 bool all_constant;
2649
2650 CoopMatType() : scope(0), rows(0), cols(0), component_type(VK_COMPONENT_TYPE_MAX_ENUM_NV), all_constant(false) {}
2651
Mark Lobodzinski3c59d972019-04-25 11:28:14 -06002652 void Init(uint32_t id, SHADER_MODULE_STATE const *src, VkPipelineShaderStageCreateInfo const *pStage,
Jeff Bolze4356752019-03-07 11:23:46 -06002653 const std::unordered_map<uint32_t, uint32_t> &id_to_spec_id) {
2654 spirv_inst_iter insn = src->get_def(id);
2655 uint32_t component_type_id = insn.word(2);
2656 uint32_t scope_id = insn.word(3);
2657 uint32_t rows_id = insn.word(4);
2658 uint32_t cols_id = insn.word(5);
2659 auto component_type_iter = src->get_def(component_type_id);
2660 auto scope_iter = src->get_def(scope_id);
2661 auto rows_iter = src->get_def(rows_id);
2662 auto cols_iter = src->get_def(cols_id);
2663
2664 all_constant = true;
2665 if (!GetIntConstantValue(scope_iter, src, pStage, id_to_spec_id, &scope)) {
2666 all_constant = false;
2667 }
2668 if (!GetIntConstantValue(rows_iter, src, pStage, id_to_spec_id, &rows)) {
2669 all_constant = false;
2670 }
2671 if (!GetIntConstantValue(cols_iter, src, pStage, id_to_spec_id, &cols)) {
2672 all_constant = false;
2673 }
2674 component_type = GetComponentType(component_type_iter, src);
2675 }
2676 };
2677
2678 bool seen_coopmat_capability = false;
2679
2680 for (auto insn : *src) {
2681 // Whitelist instructions whose result can be a cooperative matrix type, and
2682 // keep track of their types. It would be nice if SPIRV-Headers generated code
2683 // to identify which instructions have a result type and result id. Lacking that,
2684 // this whitelist is based on the set of instructions that
2685 // SPV_NV_cooperative_matrix says can be used with cooperative matrix types.
2686 switch (insn.opcode()) {
2687 case spv::OpLoad:
2688 case spv::OpCooperativeMatrixLoadNV:
2689 case spv::OpCooperativeMatrixMulAddNV:
2690 case spv::OpSNegate:
2691 case spv::OpFNegate:
2692 case spv::OpIAdd:
2693 case spv::OpFAdd:
2694 case spv::OpISub:
2695 case spv::OpFSub:
2696 case spv::OpFDiv:
2697 case spv::OpSDiv:
2698 case spv::OpUDiv:
2699 case spv::OpMatrixTimesScalar:
2700 case spv::OpConstantComposite:
2701 case spv::OpCompositeConstruct:
2702 case spv::OpConvertFToU:
2703 case spv::OpConvertFToS:
2704 case spv::OpConvertSToF:
2705 case spv::OpConvertUToF:
2706 case spv::OpUConvert:
2707 case spv::OpSConvert:
2708 case spv::OpFConvert:
2709 id_to_type_id[insn.word(2)] = insn.word(1);
2710 break;
2711 default:
2712 break;
2713 }
2714
2715 switch (insn.opcode()) {
2716 case spv::OpDecorate:
2717 if (insn.word(2) == spv::DecorationSpecId) {
2718 id_to_spec_id[insn.word(1)] = insn.word(3);
2719 }
2720 break;
2721 case spv::OpCapability:
2722 if (insn.word(1) == spv::CapabilityCooperativeMatrixNV) {
2723 seen_coopmat_capability = true;
2724
2725 if (!(pStage->stage & phys_dev_ext_props.cooperative_matrix_props.cooperativeMatrixSupportedStages)) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002726 skip |= LogError(
2727 pipeline->pipeline, kVUID_Core_Shader_CooperativeMatrixSupportedStages,
2728 "OpTypeCooperativeMatrixNV used in shader stage not in cooperativeMatrixSupportedStages (= %u)",
2729 phys_dev_ext_props.cooperative_matrix_props.cooperativeMatrixSupportedStages);
Jeff Bolze4356752019-03-07 11:23:46 -06002730 }
2731 }
2732 break;
2733 case spv::OpMemoryModel:
2734 // If the capability isn't enabled, don't bother with the rest of this function.
2735 // OpMemoryModel is the first required instruction after all OpCapability instructions.
2736 if (!seen_coopmat_capability) {
2737 return skip;
2738 }
2739 break;
2740 case spv::OpTypeCooperativeMatrixNV: {
2741 CoopMatType M;
2742 M.Init(insn.word(1), src, pStage, id_to_spec_id);
2743
2744 if (M.all_constant) {
2745 // Validate that the type parameters are all supported for one of the
2746 // operands of a cooperative matrix property.
2747 bool valid = false;
2748 for (unsigned i = 0; i < cooperative_matrix_properties.size(); ++i) {
2749 if (cooperative_matrix_properties[i].AType == M.component_type &&
2750 cooperative_matrix_properties[i].MSize == M.rows && cooperative_matrix_properties[i].KSize == M.cols &&
2751 cooperative_matrix_properties[i].scope == M.scope) {
2752 valid = true;
2753 break;
2754 }
2755 if (cooperative_matrix_properties[i].BType == M.component_type &&
2756 cooperative_matrix_properties[i].KSize == M.rows && cooperative_matrix_properties[i].NSize == M.cols &&
2757 cooperative_matrix_properties[i].scope == M.scope) {
2758 valid = true;
2759 break;
2760 }
2761 if (cooperative_matrix_properties[i].CType == M.component_type &&
2762 cooperative_matrix_properties[i].MSize == M.rows && cooperative_matrix_properties[i].NSize == M.cols &&
2763 cooperative_matrix_properties[i].scope == M.scope) {
2764 valid = true;
2765 break;
2766 }
2767 if (cooperative_matrix_properties[i].DType == M.component_type &&
2768 cooperative_matrix_properties[i].MSize == M.rows && cooperative_matrix_properties[i].NSize == M.cols &&
2769 cooperative_matrix_properties[i].scope == M.scope) {
2770 valid = true;
2771 break;
2772 }
2773 }
2774 if (!valid) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002775 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_CooperativeMatrixType,
2776 "OpTypeCooperativeMatrixNV (result id = %u) operands don't match a supported matrix type",
2777 insn.word(1));
Jeff Bolze4356752019-03-07 11:23:46 -06002778 }
2779 }
2780 break;
2781 }
2782 case spv::OpCooperativeMatrixMulAddNV: {
2783 CoopMatType A, B, C, D;
2784 if (id_to_type_id.find(insn.word(2)) == id_to_type_id.end() ||
2785 id_to_type_id.find(insn.word(3)) == id_to_type_id.end() ||
2786 id_to_type_id.find(insn.word(4)) == id_to_type_id.end() ||
2787 id_to_type_id.find(insn.word(5)) == id_to_type_id.end()) {
Mike Schuchardte48dc142019-04-18 09:12:03 -07002788 // Couldn't find type of matrix
2789 assert(false);
Jeff Bolze4356752019-03-07 11:23:46 -06002790 break;
2791 }
2792 D.Init(id_to_type_id[insn.word(2)], src, pStage, id_to_spec_id);
2793 A.Init(id_to_type_id[insn.word(3)], src, pStage, id_to_spec_id);
2794 B.Init(id_to_type_id[insn.word(4)], src, pStage, id_to_spec_id);
2795 C.Init(id_to_type_id[insn.word(5)], src, pStage, id_to_spec_id);
2796
2797 if (A.all_constant && B.all_constant && C.all_constant && D.all_constant) {
2798 // Validate that the type parameters are all supported for the same
2799 // cooperative matrix property.
2800 bool valid = false;
2801 for (unsigned i = 0; i < cooperative_matrix_properties.size(); ++i) {
2802 if (cooperative_matrix_properties[i].AType == A.component_type &&
2803 cooperative_matrix_properties[i].MSize == A.rows && cooperative_matrix_properties[i].KSize == A.cols &&
2804 cooperative_matrix_properties[i].scope == A.scope &&
2805
2806 cooperative_matrix_properties[i].BType == B.component_type &&
2807 cooperative_matrix_properties[i].KSize == B.rows && cooperative_matrix_properties[i].NSize == B.cols &&
2808 cooperative_matrix_properties[i].scope == B.scope &&
2809
2810 cooperative_matrix_properties[i].CType == C.component_type &&
2811 cooperative_matrix_properties[i].MSize == C.rows && cooperative_matrix_properties[i].NSize == C.cols &&
2812 cooperative_matrix_properties[i].scope == C.scope &&
2813
2814 cooperative_matrix_properties[i].DType == D.component_type &&
2815 cooperative_matrix_properties[i].MSize == D.rows && cooperative_matrix_properties[i].NSize == D.cols &&
2816 cooperative_matrix_properties[i].scope == D.scope) {
2817 valid = true;
2818 break;
2819 }
2820 }
2821 if (!valid) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002822 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_CooperativeMatrixMulAdd,
2823 "OpCooperativeMatrixMulAddNV (result id = %u) operands don't match a supported matrix "
2824 "VkCooperativeMatrixPropertiesNV",
2825 insn.word(2));
Jeff Bolze4356752019-03-07 11:23:46 -06002826 }
2827 }
2828 break;
2829 }
2830 default:
2831 break;
2832 }
2833 }
2834
2835 return skip;
2836}
2837
John Zulaufac4c6e12019-07-01 16:05:58 -06002838bool CoreChecks::ValidateExecutionModes(SHADER_MODULE_STATE const *src, spirv_inst_iter entrypoint) const {
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00002839 auto entrypoint_id = entrypoint.word(2);
2840
Attilio Provenzanof6c0e852019-04-09 11:01:18 +01002841 // The first denorm execution mode encountered, along with its bit width.
2842 // Used to check if SeparateDenormSettings is respected.
2843 std::pair<spv::ExecutionMode, uint32_t> first_denorm_execution_mode = std::make_pair(spv::ExecutionModeMax, 0);
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00002844
Attilio Provenzanof6c0e852019-04-09 11:01:18 +01002845 // The first rounding mode encountered, along with its bit width.
2846 // Used to check if SeparateRoundingModeSettings is respected.
2847 std::pair<spv::ExecutionMode, uint32_t> first_rounding_mode = std::make_pair(spv::ExecutionModeMax, 0);
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00002848
2849 bool skip = false;
2850
Jeff Bolze9ee3d82019-05-29 13:45:13 -05002851 uint32_t verticesOut = 0;
2852 uint32_t invocations = 0;
2853
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00002854 for (auto insn : *src) {
2855 if (insn.opcode() == spv::OpExecutionMode && insn.word(1) == entrypoint_id) {
2856 auto mode = insn.word(2);
2857 switch (mode) {
2858 case spv::ExecutionModeSignedZeroInfNanPreserve: {
2859 auto bit_width = insn.word(3);
Piers Daniell41b8c5d2020-01-10 15:42:00 -07002860 if ((bit_width == 16 && !phys_dev_props_core12.shaderSignedZeroInfNanPreserveFloat16) ||
2861 (bit_width == 32 && !phys_dev_props_core12.shaderSignedZeroInfNanPreserveFloat32) ||
2862 (bit_width == 64 && !phys_dev_props_core12.shaderSignedZeroInfNanPreserveFloat64)) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002863 skip |= LogError(
2864 device, kVUID_Core_Shader_FeatureNotEnabled,
2865 "Shader requires SignedZeroInfNanPreserve for bit width %d but it is not enabled on the device",
2866 bit_width);
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00002867 }
2868 break;
2869 }
2870
2871 case spv::ExecutionModeDenormPreserve: {
2872 auto bit_width = insn.word(3);
Piers Daniell41b8c5d2020-01-10 15:42:00 -07002873 if ((bit_width == 16 && !phys_dev_props_core12.shaderDenormPreserveFloat16) ||
2874 (bit_width == 32 && !phys_dev_props_core12.shaderDenormPreserveFloat32) ||
2875 (bit_width == 64 && !phys_dev_props_core12.shaderDenormPreserveFloat64)) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002876 skip |= LogError(device, kVUID_Core_Shader_FeatureNotEnabled,
2877 "Shader requires DenormPreserve for bit width %d but it is not enabled on the device",
2878 bit_width);
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00002879 }
2880
Attilio Provenzanof6c0e852019-04-09 11:01:18 +01002881 if (first_denorm_execution_mode.first == spv::ExecutionModeMax) {
2882 // Register the first denorm execution mode found
2883 first_denorm_execution_mode = std::make_pair(static_cast<spv::ExecutionMode>(mode), bit_width);
Jason Ekstrande1e06de2019-08-05 11:43:43 -05002884 } else if (first_denorm_execution_mode.first != mode && first_denorm_execution_mode.second != bit_width) {
Piers Daniell41b8c5d2020-01-10 15:42:00 -07002885 switch (phys_dev_props_core12.denormBehaviorIndependence) {
Jason Ekstrande1e06de2019-08-05 11:43:43 -05002886 case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR:
2887 if (first_rounding_mode.second != 32 && bit_width != 32) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002888 skip |= LogError(device, kVUID_Core_Shader_FeatureNotEnabled,
2889 "Shader uses different denorm execution modes for 16 and 64-bit but "
2890 "denormBehaviorIndependence is "
2891 "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR on the device");
Jason Ekstrande1e06de2019-08-05 11:43:43 -05002892 }
2893 break;
2894
2895 case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR:
2896 break;
2897
2898 case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR:
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002899 skip |= LogError(device, kVUID_Core_Shader_FeatureNotEnabled,
2900 "Shader uses different denorm execution modes for different bit widths but "
2901 "denormBehaviorIndependence is "
2902 "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR on the device");
Jason Ekstrande1e06de2019-08-05 11:43:43 -05002903 break;
2904
2905 default:
2906 break;
2907 }
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00002908 }
2909 break;
2910 }
2911
2912 case spv::ExecutionModeDenormFlushToZero: {
2913 auto bit_width = insn.word(3);
Piers Daniell41b8c5d2020-01-10 15:42:00 -07002914 if ((bit_width == 16 && !phys_dev_props_core12.shaderDenormFlushToZeroFloat16) ||
2915 (bit_width == 32 && !phys_dev_props_core12.shaderDenormFlushToZeroFloat32) ||
2916 (bit_width == 64 && !phys_dev_props_core12.shaderDenormFlushToZeroFloat64)) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002917 skip |= LogError(device, kVUID_Core_Shader_FeatureNotEnabled,
2918 "Shader requires DenormFlushToZero for bit width %d but it is not enabled on the device",
2919 bit_width);
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00002920 }
2921
Attilio Provenzanof6c0e852019-04-09 11:01:18 +01002922 if (first_denorm_execution_mode.first == spv::ExecutionModeMax) {
2923 // Register the first denorm execution mode found
2924 first_denorm_execution_mode = std::make_pair(static_cast<spv::ExecutionMode>(mode), bit_width);
Jason Ekstrande1e06de2019-08-05 11:43:43 -05002925 } else if (first_denorm_execution_mode.first != mode && first_denorm_execution_mode.second != bit_width) {
Piers Daniell41b8c5d2020-01-10 15:42:00 -07002926 switch (phys_dev_props_core12.denormBehaviorIndependence) {
Jason Ekstrande1e06de2019-08-05 11:43:43 -05002927 case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR:
2928 if (first_rounding_mode.second != 32 && bit_width != 32) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002929 skip |= LogError(device, kVUID_Core_Shader_FeatureNotEnabled,
2930 "Shader uses different denorm execution modes for 16 and 64-bit but "
2931 "denormBehaviorIndependence is "
2932 "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR on the device");
Jason Ekstrande1e06de2019-08-05 11:43:43 -05002933 }
2934 break;
2935
2936 case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR:
2937 break;
2938
2939 case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR:
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002940 skip |= LogError(device, kVUID_Core_Shader_FeatureNotEnabled,
2941 "Shader uses different denorm execution modes for different bit widths but "
2942 "denormBehaviorIndependence is "
2943 "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR on the device");
Jason Ekstrande1e06de2019-08-05 11:43:43 -05002944 break;
2945
2946 default:
2947 break;
2948 }
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00002949 }
2950 break;
2951 }
2952
2953 case spv::ExecutionModeRoundingModeRTE: {
2954 auto bit_width = insn.word(3);
Piers Daniell41b8c5d2020-01-10 15:42:00 -07002955 if ((bit_width == 16 && !phys_dev_props_core12.shaderRoundingModeRTEFloat16) ||
2956 (bit_width == 32 && !phys_dev_props_core12.shaderRoundingModeRTEFloat32) ||
2957 (bit_width == 64 && !phys_dev_props_core12.shaderRoundingModeRTEFloat64)) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002958 skip |= LogError(device, kVUID_Core_Shader_FeatureNotEnabled,
2959 "Shader requires RoundingModeRTE for bit width %d but it is not enabled on the device",
2960 bit_width);
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00002961 }
2962
Attilio Provenzanof6c0e852019-04-09 11:01:18 +01002963 if (first_rounding_mode.first == spv::ExecutionModeMax) {
2964 // Register the first rounding mode found
2965 first_rounding_mode = std::make_pair(static_cast<spv::ExecutionMode>(mode), bit_width);
Jason Ekstrande1e06de2019-08-05 11:43:43 -05002966 } else if (first_rounding_mode.first != mode && first_rounding_mode.second != bit_width) {
Piers Daniell41b8c5d2020-01-10 15:42:00 -07002967 switch (phys_dev_props_core12.roundingModeIndependence) {
Jason Ekstrande1e06de2019-08-05 11:43:43 -05002968 case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR:
2969 if (first_rounding_mode.second != 32 && bit_width != 32) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002970 skip |= LogError(device, kVUID_Core_Shader_FeatureNotEnabled,
2971 "Shader uses different rounding modes for 16 and 64-bit but "
2972 "roundingModeIndependence is "
2973 "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR on the device");
Jason Ekstrande1e06de2019-08-05 11:43:43 -05002974 }
2975 break;
2976
2977 case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR:
2978 break;
2979
2980 case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR:
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002981 skip |= LogError(device, kVUID_Core_Shader_FeatureNotEnabled,
2982 "Shader uses different rounding modes for different bit widths but "
2983 "roundingModeIndependence is "
2984 "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR on the device");
Jason Ekstrande1e06de2019-08-05 11:43:43 -05002985 break;
2986
2987 default:
2988 break;
2989 }
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00002990 }
2991 break;
2992 }
2993
2994 case spv::ExecutionModeRoundingModeRTZ: {
2995 auto bit_width = insn.word(3);
Piers Daniell41b8c5d2020-01-10 15:42:00 -07002996 if ((bit_width == 16 && !phys_dev_props_core12.shaderRoundingModeRTZFloat16) ||
2997 (bit_width == 32 && !phys_dev_props_core12.shaderRoundingModeRTZFloat32) ||
2998 (bit_width == 64 && !phys_dev_props_core12.shaderRoundingModeRTZFloat64)) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07002999 skip |= LogError(device, kVUID_Core_Shader_FeatureNotEnabled,
3000 "Shader requires RoundingModeRTZ for bit width %d but it is not enabled on the device",
3001 bit_width);
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00003002 }
3003
Attilio Provenzanof6c0e852019-04-09 11:01:18 +01003004 if (first_rounding_mode.first == spv::ExecutionModeMax) {
3005 // Register the first rounding mode found
3006 first_rounding_mode = std::make_pair(static_cast<spv::ExecutionMode>(mode), bit_width);
Jason Ekstrande1e06de2019-08-05 11:43:43 -05003007 } else if (first_rounding_mode.first != mode && first_rounding_mode.second != bit_width) {
Piers Daniell41b8c5d2020-01-10 15:42:00 -07003008 switch (phys_dev_props_core12.roundingModeIndependence) {
Jason Ekstrande1e06de2019-08-05 11:43:43 -05003009 case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR:
3010 if (first_rounding_mode.second != 32 && bit_width != 32) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003011 skip |= LogError(device, kVUID_Core_Shader_FeatureNotEnabled,
3012 "Shader uses different rounding modes for 16 and 64-bit but "
3013 "roundingModeIndependence is "
3014 "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR on the device");
Jason Ekstrande1e06de2019-08-05 11:43:43 -05003015 }
3016 break;
3017
3018 case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR:
3019 break;
3020
3021 case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR:
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003022 skip |= LogError(device, kVUID_Core_Shader_FeatureNotEnabled,
3023 "Shader uses different rounding modes for different bit widths but "
3024 "roundingModeIndependence is "
3025 "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR on the device");
Jason Ekstrande1e06de2019-08-05 11:43:43 -05003026 break;
3027
3028 default:
3029 break;
3030 }
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00003031 }
3032 break;
3033 }
Jeff Bolze9ee3d82019-05-29 13:45:13 -05003034
3035 case spv::ExecutionModeOutputVertices: {
3036 verticesOut = insn.word(3);
3037 break;
3038 }
3039
3040 case spv::ExecutionModeInvocations: {
3041 invocations = insn.word(3);
3042 break;
3043 }
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00003044 }
3045 }
3046 }
3047
Jeff Bolze9ee3d82019-05-29 13:45:13 -05003048 if (entrypoint.word(1) == spv::ExecutionModelGeometry) {
3049 if (verticesOut == 0 || verticesOut > phys_dev_props.limits.maxGeometryOutputVertices) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003050 skip |= LogError(device, "VUID-VkPipelineShaderStageCreateInfo-stage-00714",
3051 "Geometry shader entry point must have an OpExecutionMode instruction that "
3052 "specifies a maximum output vertex count that is greater than 0 and less "
3053 "than or equal to maxGeometryOutputVertices. "
3054 "OutputVertices=%d, maxGeometryOutputVertices=%d",
3055 verticesOut, phys_dev_props.limits.maxGeometryOutputVertices);
Jeff Bolze9ee3d82019-05-29 13:45:13 -05003056 }
3057
3058 if (invocations == 0 || invocations > phys_dev_props.limits.maxGeometryShaderInvocations) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003059 skip |= LogError(device, "VUID-VkPipelineShaderStageCreateInfo-stage-00715",
3060 "Geometry shader entry point must have an OpExecutionMode instruction that "
3061 "specifies an invocation count that is greater than 0 and less "
3062 "than or equal to maxGeometryShaderInvocations. "
3063 "Invocations=%d, maxGeometryShaderInvocations=%d",
3064 invocations, phys_dev_props.limits.maxGeometryShaderInvocations);
Jeff Bolze9ee3d82019-05-29 13:45:13 -05003065 }
3066 }
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00003067 return skip;
3068}
3069
locke-lunargd9a069d2019-09-17 01:50:19 -06003070uint32_t DescriptorTypeToReqs(SHADER_MODULE_STATE const *module, uint32_t type_id) {
Chris Forbes47567b72017-06-09 12:09:45 -07003071 auto type = module->get_def(type_id);
3072
3073 while (true) {
3074 switch (type.opcode()) {
3075 case spv::OpTypeArray:
Chris Forbes062f1222018-08-21 15:34:15 -07003076 case spv::OpTypeRuntimeArray:
Chris Forbes47567b72017-06-09 12:09:45 -07003077 case spv::OpTypeSampledImage:
3078 type = module->get_def(type.word(2));
3079 break;
3080 case spv::OpTypePointer:
3081 type = module->get_def(type.word(3));
3082 break;
3083 case spv::OpTypeImage: {
3084 auto dim = type.word(3);
3085 auto arrayed = type.word(5);
3086 auto msaa = type.word(6);
3087
Chris Forbes74ba2232018-08-27 15:19:27 -07003088 uint32_t bits = 0;
3089 switch (GetFundamentalType(module, type.word(2))) {
3090 case FORMAT_TYPE_FLOAT:
3091 bits = DESCRIPTOR_REQ_COMPONENT_TYPE_FLOAT;
3092 break;
3093 case FORMAT_TYPE_UINT:
3094 bits = DESCRIPTOR_REQ_COMPONENT_TYPE_UINT;
3095 break;
3096 case FORMAT_TYPE_SINT:
3097 bits = DESCRIPTOR_REQ_COMPONENT_TYPE_SINT;
3098 break;
3099 default:
3100 break;
3101 }
3102
Chris Forbes47567b72017-06-09 12:09:45 -07003103 switch (dim) {
3104 case spv::Dim1D:
Chris Forbes74ba2232018-08-27 15:19:27 -07003105 bits |= arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_1D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_1D;
3106 return bits;
Chris Forbes47567b72017-06-09 12:09:45 -07003107 case spv::Dim2D:
Chris Forbes74ba2232018-08-27 15:19:27 -07003108 bits |= msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE;
3109 bits |= arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_2D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_2D;
3110 return bits;
Chris Forbes47567b72017-06-09 12:09:45 -07003111 case spv::Dim3D:
Chris Forbes74ba2232018-08-27 15:19:27 -07003112 bits |= DESCRIPTOR_REQ_VIEW_TYPE_3D;
3113 return bits;
Chris Forbes47567b72017-06-09 12:09:45 -07003114 case spv::DimCube:
Chris Forbes74ba2232018-08-27 15:19:27 -07003115 bits |= arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_CUBE_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_CUBE;
3116 return bits;
Chris Forbes47567b72017-06-09 12:09:45 -07003117 case spv::DimSubpassData:
Chris Forbes74ba2232018-08-27 15:19:27 -07003118 bits |= msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE;
3119 return bits;
Chris Forbes47567b72017-06-09 12:09:45 -07003120 default: // buffer, etc.
Chris Forbes74ba2232018-08-27 15:19:27 -07003121 return bits;
Chris Forbes47567b72017-06-09 12:09:45 -07003122 }
3123 }
3124 default:
3125 return 0;
3126 }
3127 }
3128}
3129
3130// For given pipelineLayout verify that the set_layout_node at slot.first
3131// has the requested binding at slot.second and return ptr to that binding
Mark Lobodzinskica6ebe32019-04-25 11:43:37 -06003132static VkDescriptorSetLayoutBinding const *GetDescriptorBinding(PIPELINE_LAYOUT_STATE const *pipelineLayout,
Shannon McPhersonc06c33d2018-06-28 17:21:12 -06003133 descriptor_slot_t slot) {
Chris Forbes47567b72017-06-09 12:09:45 -07003134 if (!pipelineLayout) return nullptr;
3135
3136 if (slot.first >= pipelineLayout->set_layouts.size()) return nullptr;
3137
3138 return pipelineLayout->set_layouts[slot.first]->GetDescriptorSetLayoutBindingPtrFromBinding(slot.second);
3139}
3140
Sam Wallsd7ab6db2020-06-19 20:41:54 +01003141int32_t GetShaderResourceDimensionality(const SHADER_MODULE_STATE *module, const interface_var &resource) {
3142 if (module == nullptr) return -1;
3143
3144 auto type = module->get_def(resource.type_id);
3145 while (true) {
3146 switch (type.opcode()) {
3147 case spv::OpTypeSampledImage:
3148 type = module->get_def(type.word(2));
3149 break;
3150 case spv::OpTypePointer:
3151 type = module->get_def(type.word(3));
3152 break;
3153 case spv::OpTypeImage:
3154 return type.word(3);
3155 default:
3156 return -1;
3157 }
3158 }
3159}
3160
3161bool FindLocalSize(SHADER_MODULE_STATE const *src, uint32_t &local_size_x, uint32_t &local_size_y, uint32_t &local_size_z) {
Locke1ec6d952019-04-02 11:57:21 -06003162 for (auto insn : *src) {
3163 if (insn.opcode() == spv::OpEntryPoint) {
3164 auto executionModel = insn.word(1);
3165 auto entrypointStageBits = ExecutionModelToShaderStageFlagBits(executionModel);
3166 if (entrypointStageBits == VK_SHADER_STAGE_COMPUTE_BIT) {
3167 auto entrypoint_id = insn.word(2);
3168 for (auto insn1 : *src) {
3169 if (insn1.opcode() == spv::OpExecutionMode && insn1.word(1) == entrypoint_id &&
3170 insn1.word(2) == spv::ExecutionModeLocalSize) {
3171 local_size_x = insn1.word(3);
3172 local_size_y = insn1.word(4);
3173 local_size_z = insn1.word(5);
3174 return true;
3175 }
3176 }
3177 }
3178 }
3179 }
3180 return false;
3181}
3182
locke-lunargd9a069d2019-09-17 01:50:19 -06003183void ProcessExecutionModes(SHADER_MODULE_STATE const *src, const spirv_inst_iter &entrypoint, PIPELINE_STATE *pipeline) {
Jeff Bolz105d6492018-09-29 15:46:44 -05003184 auto entrypoint_id = entrypoint.word(2);
Chris Forbes0771b672018-03-22 21:13:46 -07003185 bool is_point_mode = false;
3186
3187 for (auto insn : *src) {
3188 if (insn.opcode() == spv::OpExecutionMode && insn.word(1) == entrypoint_id) {
3189 switch (insn.word(2)) {
3190 case spv::ExecutionModePointMode:
3191 // In tessellation shaders, PointMode is separate and trumps the tessellation topology.
3192 is_point_mode = true;
3193 break;
3194
3195 case spv::ExecutionModeOutputPoints:
3196 pipeline->topology_at_rasterizer = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
3197 break;
3198
3199 case spv::ExecutionModeIsolines:
3200 case spv::ExecutionModeOutputLineStrip:
3201 pipeline->topology_at_rasterizer = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
3202 break;
3203
3204 case spv::ExecutionModeTriangles:
3205 case spv::ExecutionModeQuads:
3206 case spv::ExecutionModeOutputTriangleStrip:
3207 pipeline->topology_at_rasterizer = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
3208 break;
3209 }
3210 }
3211 }
3212
3213 if (is_point_mode) pipeline->topology_at_rasterizer = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
3214}
3215
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06003216// If PointList topology is specified in the pipeline, verify that a shader geometry stage writes PointSize
3217// o If there is only a vertex shader : gl_PointSize must be written when using points
3218// o If there is a geometry or tessellation shader:
3219// - If shaderTessellationAndGeometryPointSize feature is enabled:
3220// * gl_PointSize must be written in the final geometry stage
3221// - If shaderTessellationAndGeometryPointSize feature is disabled:
3222// * gl_PointSize must NOT be written and a default of 1.0 is assumed
Mark Lobodzinski3c59d972019-04-25 11:28:14 -06003223bool CoreChecks::ValidatePointListShaderState(const PIPELINE_STATE *pipeline, SHADER_MODULE_STATE const *src,
John Zulaufac4c6e12019-07-01 16:05:58 -06003224 spirv_inst_iter entrypoint, VkShaderStageFlagBits stage) const {
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06003225 if (pipeline->topology_at_rasterizer != VK_PRIMITIVE_TOPOLOGY_POINT_LIST) {
3226 return false;
3227 }
3228
3229 bool pointsize_written = false;
3230 bool skip = false;
3231
3232 // Search for PointSize built-in decorations
3233 std::vector<uint32_t> pointsize_builtin_offsets;
3234 spirv_inst_iter insn = entrypoint;
3235 while (!pointsize_written && (insn.opcode() != spv::OpFunction)) {
3236 if (insn.opcode() == spv::OpMemberDecorate) {
3237 if (insn.word(3) == spv::DecorationBuiltIn) {
3238 if (insn.word(4) == spv::BuiltInPointSize) {
Tobias Hector6663c9b2020-11-05 10:18:02 +00003239 pointsize_written = IsBuiltInWritten(src, insn, entrypoint);
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06003240 }
3241 }
3242 } else if (insn.opcode() == spv::OpDecorate) {
3243 if (insn.word(2) == spv::DecorationBuiltIn) {
3244 if (insn.word(3) == spv::BuiltInPointSize) {
Tobias Hector6663c9b2020-11-05 10:18:02 +00003245 pointsize_written = IsBuiltInWritten(src, insn, entrypoint);
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06003246 }
3247 }
3248 }
3249
3250 insn++;
3251 }
3252
3253 if ((stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT || stage == VK_SHADER_STAGE_GEOMETRY_BIT) &&
Mark Lobodzinskid7b03cc2019-04-19 14:23:10 -06003254 !enabled_features.core.shaderTessellationAndGeometryPointSize) {
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06003255 if (pointsize_written) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003256 skip |= LogError(pipeline->pipeline, kVUID_Core_Shader_PointSizeBuiltInOverSpecified,
3257 "Pipeline topology is set to POINT_LIST and geometry or tessellation shaders write PointSize which "
3258 "is prohibited when the shaderTessellationAndGeometryPointSize feature is not enabled.");
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06003259 }
3260 } else if (!pointsize_written) {
3261 skip |=
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003262 LogError(pipeline->pipeline, kVUID_Core_Shader_MissingPointSizeBuiltIn,
3263 "Pipeline topology is set to POINT_LIST, but PointSize is not written to in the shader corresponding to %s.",
3264 string_VkShaderStageFlagBits(stage));
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06003265 }
3266 return skip;
3267}
John Zulauf14c355b2019-06-27 16:09:37 -06003268
Tobias Hector6663c9b2020-11-05 10:18:02 +00003269bool CoreChecks::ValidatePrimitiveRateShaderState(const PIPELINE_STATE *pipeline, SHADER_MODULE_STATE const *src,
3270 spirv_inst_iter entrypoint, VkShaderStageFlagBits stage) const {
3271 bool primitiverate_written = false;
3272 bool viewportindex_written = false;
3273 bool viewportmask_written = false;
3274 bool skip = false;
3275
3276 // Check if the primitive shading rate is written
3277 spirv_inst_iter insn = entrypoint;
3278 while (!(primitiverate_written && viewportindex_written && viewportmask_written) && insn.opcode() != spv::OpFunction) {
3279 if (insn.opcode() == spv::OpMemberDecorate) {
3280 if (insn.word(3) == spv::DecorationBuiltIn) {
3281 if (insn.word(4) == spv::BuiltInPrimitiveShadingRateKHR) {
3282 primitiverate_written = IsBuiltInWritten(src, insn, entrypoint);
3283 } else if (insn.word(4) == spv::BuiltInViewportIndex) {
3284 viewportindex_written = IsBuiltInWritten(src, insn, entrypoint);
3285 } else if (insn.word(4) == spv::BuiltInViewportMaskNV) {
3286 viewportmask_written = IsBuiltInWritten(src, insn, entrypoint);
3287 }
3288 }
3289 } else if (insn.opcode() == spv::OpDecorate) {
3290 if (insn.word(2) == spv::DecorationBuiltIn) {
3291 if (insn.word(3) == spv::BuiltInPrimitiveShadingRateKHR) {
3292 primitiverate_written = IsBuiltInWritten(src, insn, entrypoint);
3293 } else if (insn.word(3) == spv::BuiltInViewportIndex) {
3294 viewportindex_written = IsBuiltInWritten(src, insn, entrypoint);
3295 } else if (insn.word(3) == spv::BuiltInViewportMaskNV) {
3296 viewportmask_written = IsBuiltInWritten(src, insn, entrypoint);
3297 }
3298 }
3299 }
3300
3301 insn++;
3302 }
3303
3304 if (!phys_dev_ext_props.fragment_shading_rate_props.primitiveFragmentShadingRateWithMultipleViewports) {
3305 if (!IsDynamic(pipeline, VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT) &&
3306 pipeline->graphicsPipelineCI.pViewportState->viewportCount > 1 && primitiverate_written) {
3307 skip |= LogError(
3308 pipeline->pipeline, "VUID-VkGraphicsPipelineCreateInfo-primitiveFragmentShadingRateWithMultipleViewports-04503",
3309 "vkCreateGraphicsPipelines: %s shader statically writes to PrimitiveShadingRateKHR built-in, but multiple viewports "
3310 "are used and the primitiveFragmentShadingRateWithMultipleViewports limit is not supported.",
3311 string_VkShaderStageFlagBits(stage));
3312 }
3313
3314 if (primitiverate_written && viewportindex_written) {
3315 skip |= LogError(pipeline->pipeline,
3316 "VUID-VkGraphicsPipelineCreateInfo-primitiveFragmentShadingRateWithMultipleViewports-04504",
3317 "vkCreateGraphicsPipelines: %s shader statically writes to both PrimitiveShadingRateKHR and "
3318 "ViewportIndex built-ins,"
3319 "but the primitiveFragmentShadingRateWithMultipleViewports limit is not supported.",
3320 string_VkShaderStageFlagBits(stage));
3321 }
3322
3323 if (primitiverate_written && viewportmask_written) {
3324 skip |= LogError(pipeline->pipeline,
3325 "VUID-VkGraphicsPipelineCreateInfo-primitiveFragmentShadingRateWithMultipleViewports-04505",
3326 "vkCreateGraphicsPipelines: %s shader statically writes to both PrimitiveShadingRateKHR and "
3327 "ViewportMaskNV built-ins,"
3328 "but the primitiveFragmentShadingRateWithMultipleViewports limit is not supported.",
3329 string_VkShaderStageFlagBits(stage));
3330 }
3331 }
3332 return skip;
3333}
3334
John Zulauf14c355b2019-06-27 16:09:37 -06003335bool CoreChecks::ValidatePipelineShaderStage(VkPipelineShaderStageCreateInfo const *pStage, const PIPELINE_STATE *pipeline,
3336 const PIPELINE_STATE::StageState &stage_state, const SHADER_MODULE_STATE *module,
John Zulaufac4c6e12019-07-01 16:05:58 -06003337 const spirv_inst_iter &entrypoint, bool check_point_size) const {
John Zulauf14c355b2019-06-27 16:09:37 -06003338 bool skip = false;
3339
3340 // Check the module
3341 if (!module->has_valid_spirv) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003342 skip |= LogError(device, "VUID-VkPipelineShaderStageCreateInfo-module-parameter",
3343 "%s does not contain valid spirv for stage %s.",
3344 report_data->FormatHandle(module->vk_shader_module).c_str(), string_VkShaderStageFlagBits(pStage->stage));
John Zulauf14c355b2019-06-27 16:09:37 -06003345 }
3346
Jeremy Hayesb3e4d532019-08-16 10:08:49 -06003347 // If specialization-constant values are given and specialization-constant instructions are present in the shader, the
3348 // specializations should be applied and validated.
3349 if (pStage->pSpecializationInfo != nullptr && pStage->pSpecializationInfo->mapEntryCount > 0 &&
3350 pStage->pSpecializationInfo->pMapEntries != nullptr && module->has_specialization_constants) {
3351 // Gather the specialization-constant values.
3352 auto const &specialization_info = pStage->pSpecializationInfo;
Jeremy Hayes521221d2020-01-15 16:48:49 -07003353 auto const &specialization_data = reinterpret_cast<uint8_t const *>(specialization_info->pData);
Jeremy Hayesb3e4d532019-08-16 10:08:49 -06003354 std::unordered_map<uint32_t, std::vector<uint32_t>> id_value_map;
3355 id_value_map.reserve(specialization_info->mapEntryCount);
3356 for (auto i = 0u; i < specialization_info->mapEntryCount; ++i) {
3357 auto const &map_entry = specialization_info->pMapEntries[i];
Jeremy Hayesb3e4d532019-08-16 10:08:49 -06003358
Jeremy Hayes521221d2020-01-15 16:48:49 -07003359 // Expect only scalar types.
3360 assert(map_entry.size == 1 || map_entry.size == 2 || map_entry.size == 4 || map_entry.size == 8);
3361 auto entry = id_value_map.emplace(map_entry.constantID, std::vector<uint32_t>(map_entry.size > 4 ? 2 : 1));
3362 memcpy(entry.first->second.data(), specialization_data + map_entry.offset, map_entry.size);
Jeremy Hayesb3e4d532019-08-16 10:08:49 -06003363 }
3364
3365 // Apply the specialization-constant values and revalidate the shader module.
Tony-LunarG8a51b7d2020-07-01 15:57:23 -06003366 spv_target_env spirv_environment = PickSpirvEnv(api_version, (device_extensions.vk_khr_spirv_1_4 != kNotEnabled));
Jeremy Hayesb3e4d532019-08-16 10:08:49 -06003367 spvtools::Optimizer optimizer(spirv_environment);
3368 spvtools::MessageConsumer consumer = [&skip, &module, &pStage, this](spv_message_level_t level, const char *source,
3369 const spv_position_t &position, const char *message) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003370 skip |= LogError(
3371 device, "VUID-VkPipelineShaderStageCreateInfo-module-parameter", "%s does not contain valid spirv for stage %s. %s",
Jeremy Hayesb3e4d532019-08-16 10:08:49 -06003372 report_data->FormatHandle(module->vk_shader_module).c_str(), string_VkShaderStageFlagBits(pStage->stage), message);
3373 };
3374 optimizer.SetMessageConsumer(consumer);
3375 optimizer.RegisterPass(spvtools::CreateSetSpecConstantDefaultValuePass(id_value_map));
3376 optimizer.RegisterPass(spvtools::CreateFreezeSpecConstantValuePass());
3377 std::vector<uint32_t> specialized_spirv;
3378 auto const optimized =
3379 optimizer.Run(module->words.data(), module->words.size(), &specialized_spirv, spvtools::ValidatorOptions(), true);
3380 assert(optimized == true);
3381
3382 if (optimized) {
3383 spv_context ctx = spvContextCreate(spirv_environment);
3384 spv_const_binary_t binary{specialized_spirv.data(), specialized_spirv.size()};
3385 spv_diagnostic diag = nullptr;
Tony-LunarG9fe69a42020-07-23 15:09:37 -06003386 spvtools::ValidatorOptions options;
3387 AdjustValidatorOptions(device_extensions, enabled_features, options);
Jeremy Hayesb3e4d532019-08-16 10:08:49 -06003388 auto const spv_valid = spvValidateWithOptions(ctx, options, &binary, &diag);
3389 if (spv_valid != SPV_SUCCESS) {
sfricke-samsungd3793802020-08-18 22:55:03 -07003390 skip |= LogError(device, "VUID-VkPipelineShaderStageCreateInfo-module-04145",
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003391 "After specialization was applied, %s does not contain valid spirv for stage %s.",
3392 report_data->FormatHandle(module->vk_shader_module).c_str(),
3393 string_VkShaderStageFlagBits(pStage->stage));
Jeremy Hayesb3e4d532019-08-16 10:08:49 -06003394 }
3395
Jeremy Hayesb3e4d532019-08-16 10:08:49 -06003396 spvDiagnosticDestroy(diag);
3397 spvContextDestroy(ctx);
3398 }
3399 }
3400
John Zulauf14c355b2019-06-27 16:09:37 -06003401 // Check the entrypoint
3402 if (entrypoint == module->end()) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003403 skip |=
3404 LogError(device, "VUID-VkPipelineShaderStageCreateInfo-pName-00707", "No entrypoint found named `%s` for stage %s..",
3405 pStage->pName, string_VkShaderStageFlagBits(pStage->stage));
John Zulauf14c355b2019-06-27 16:09:37 -06003406 }
3407 if (skip) return true; // no point continuing beyond here, any analysis is just going to be garbage.
3408
3409 // Mark accessible ids
3410 auto &accessible_ids = stage_state.accessible_ids;
3411
Chris Forbes47567b72017-06-09 12:09:45 -07003412 // Validate descriptor set layout against what the entrypoint actually uses
John Zulauf14c355b2019-06-27 16:09:37 -06003413 bool has_writable_descriptor = stage_state.has_writable_descriptor;
3414 auto &descriptor_uses = stage_state.descriptor_uses;
Chris Forbes47567b72017-06-09 12:09:45 -07003415
Chris Forbes349b3132018-03-07 11:38:08 -08003416 // Validate shader capabilities against enabled device features
sfricke-samsung0065ce02020-12-03 22:46:37 -08003417 skip |= ValidateShaderCapabilitiesAndExtensions(module);
locke-lunarg63e4daf2020-08-17 17:53:25 -06003418 skip |=
3419 ValidateShaderStageWritableOrAtomicDescriptor(pStage->stage, has_writable_descriptor, stage_state.has_atomic_descriptor);
Jeff Bolze9ee3d82019-05-29 13:45:13 -05003420 skip |= ValidateShaderStageInputOutputLimits(module, pStage, pipeline, entrypoint);
sfricke-samsungdc96f302020-03-18 20:42:10 -07003421 skip |= ValidateShaderStageMaxResources(pStage->stage, pipeline);
Jeff Bolz526f2d52019-09-18 13:18:08 -05003422 skip |= ValidateShaderStageGroupNonUniform(module, pStage->stage);
Attilio Provenzanoc5d50102019-03-25 17:40:37 +00003423 skip |= ValidateExecutionModes(module, entrypoint);
Mark Lobodzinskid8d658e2020-01-30 15:05:51 -07003424 skip |= ValidateSpecializationOffsets(pStage);
locke-lunargde3f0fa2020-09-10 11:55:31 -06003425 skip |= ValidatePushConstantUsage(*pipeline, module, pStage);
Jeff Bolze54ae892018-09-08 12:16:29 -05003426 if (check_point_size && !pipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable) {
Mark Lobodzinski518eadc2019-03-09 12:07:30 -07003427 skip |= ValidatePointListShaderState(pipeline, module, entrypoint, pStage->stage);
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06003428 }
sfricke-samsungef2a68c2020-10-26 04:22:46 -07003429 skip |= ValidateBuiltinLimits(module, accessible_ids, pStage->stage);
Jeff Bolze4356752019-03-07 11:23:46 -06003430 skip |= ValidateCooperativeMatrix(module, pStage, pipeline);
Tobias Hector6663c9b2020-11-05 10:18:02 +00003431 if (enabled_features.fragment_shading_rate_features.primitiveFragmentShadingRate) {
3432 skip |= ValidatePrimitiveRateShaderState(pipeline, module, entrypoint, pStage->stage);
3433 }
Chris Forbes47567b72017-06-09 12:09:45 -07003434
locke-lunarg9a16ebb2020-07-30 16:56:33 -06003435 std::string vuid_layout_mismatch;
3436 if (pipeline->graphicsPipelineCI.sType == VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO) {
3437 vuid_layout_mismatch = "VUID-VkGraphicsPipelineCreateInfo-layout-00756";
3438 } else if (pipeline->computePipelineCI.sType == VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO) {
3439 vuid_layout_mismatch = "VUID-VkComputePipelineCreateInfo-layout-00703";
3440 } else if (pipeline->raytracingPipelineCI.sType == VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR) {
3441 vuid_layout_mismatch = "VUID-VkRayTracingPipelineCreateInfoKHR-layout-03427";
3442 } else if (pipeline->raytracingPipelineCI.sType == VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV) {
3443 vuid_layout_mismatch = "VUID-VkRayTracingPipelineCreateInfoNV-layout-03427";
3444 }
3445
Chris Forbes47567b72017-06-09 12:09:45 -07003446 // Validate descriptor use
3447 for (auto use : descriptor_uses) {
Chris Forbes47567b72017-06-09 12:09:45 -07003448 // Verify given pipelineLayout has requested setLayout with requested binding
Jeff Bolze7fc67b2019-10-04 12:29:31 -05003449 const auto &binding = GetDescriptorBinding(pipeline->pipeline_layout.get(), use.first);
Chris Forbes47567b72017-06-09 12:09:45 -07003450 unsigned required_descriptor_count;
sourav parmarcd5fb182020-07-17 12:58:44 -07003451 bool is_khr = binding && binding->descriptorType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
3452 std::set<uint32_t> descriptor_types =
3453 TypeToDescriptorTypeSet(module, use.second.type_id, required_descriptor_count, is_khr);
Chris Forbes47567b72017-06-09 12:09:45 -07003454
3455 if (!binding) {
locke-lunarg9a16ebb2020-07-30 16:56:33 -06003456 skip |= LogError(device, vuid_layout_mismatch,
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003457 "Shader uses descriptor slot %u.%u (expected `%s`) but not declared in pipeline layout",
3458 use.first.first, use.first.second, string_descriptorTypes(descriptor_types).c_str());
Chris Forbes47567b72017-06-09 12:09:45 -07003459 } else if (~binding->stageFlags & pStage->stage) {
locke-lunarg9a16ebb2020-07-30 16:56:33 -06003460 skip |= LogError(device, vuid_layout_mismatch,
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003461 "Shader uses descriptor slot %u.%u but descriptor not accessible from stage %s", use.first.first,
3462 use.first.second, string_VkShaderStageFlagBits(pStage->stage));
Jeff Bolze54ae892018-09-08 12:16:29 -05003463 } else if (descriptor_types.find(binding->descriptorType) == descriptor_types.end()) {
locke-lunarg9a16ebb2020-07-30 16:56:33 -06003464 skip |= LogError(device, vuid_layout_mismatch,
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003465 "Type mismatch on descriptor slot %u.%u (expected `%s`) but descriptor of type %s", use.first.first,
3466 use.first.second, string_descriptorTypes(descriptor_types).c_str(),
3467 string_VkDescriptorType(binding->descriptorType));
Chris Forbes47567b72017-06-09 12:09:45 -07003468 } else if (binding->descriptorCount < required_descriptor_count) {
locke-lunarg9a16ebb2020-07-30 16:56:33 -06003469 skip |= LogError(device, vuid_layout_mismatch,
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003470 "Shader expects at least %u descriptors for binding %u.%u but only %u provided",
3471 required_descriptor_count, use.first.first, use.first.second, binding->descriptorCount);
Chris Forbes47567b72017-06-09 12:09:45 -07003472 }
3473 }
3474
3475 // Validate use of input attachments against subpass structure
3476 if (pStage->stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
Shannon McPhersonc06c33d2018-06-28 17:21:12 -06003477 auto input_attachment_uses = CollectInterfaceByInputAttachmentIndex(module, accessible_ids);
Chris Forbes47567b72017-06-09 12:09:45 -07003478
Petr Krause91f7a12017-12-14 20:57:36 +01003479 auto rpci = pipeline->rp_state->createInfo.ptr();
Chris Forbes47567b72017-06-09 12:09:45 -07003480 auto subpass = pipeline->graphicsPipelineCI.subpass;
3481
3482 for (auto use : input_attachment_uses) {
3483 auto input_attachments = rpci->pSubpasses[subpass].pInputAttachments;
3484 auto index = (input_attachments && use.first < rpci->pSubpasses[subpass].inputAttachmentCount)
Dave Houltona9df0ce2018-02-07 10:51:23 -07003485 ? input_attachments[use.first].attachment
3486 : VK_ATTACHMENT_UNUSED;
Chris Forbes47567b72017-06-09 12:09:45 -07003487
3488 if (index == VK_ATTACHMENT_UNUSED) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003489 skip |= LogError(device, kVUID_Core_Shader_MissingInputAttachment,
3490 "Shader consumes input attachment index %d but not provided in subpass", use.first);
Shannon McPhersonc06c33d2018-06-28 17:21:12 -06003491 } else if (!(GetFormatType(rpci->pAttachments[index].format) & GetFundamentalType(module, use.second.type_id))) {
Chris Forbes47567b72017-06-09 12:09:45 -07003492 skip |=
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003493 LogError(device, kVUID_Core_Shader_InputAttachmentTypeMismatch,
3494 "Subpass input attachment %u format of %s does not match type used in shader `%s`", use.first,
3495 string_VkFormat(rpci->pAttachments[index].format), DescribeType(module, use.second.type_id).c_str());
Chris Forbes47567b72017-06-09 12:09:45 -07003496 }
3497 }
3498 }
Lockeaa8fdc02019-04-02 11:59:20 -06003499 if (pStage->stage == VK_SHADER_STAGE_COMPUTE_BIT) {
3500 skip |= ValidateComputeWorkGroupSizes(module);
3501 }
Chris Forbes47567b72017-06-09 12:09:45 -07003502 return skip;
3503}
3504
Mark Lobodzinskid8d658e2020-01-30 15:05:51 -07003505bool CoreChecks::ValidateInterfaceBetweenStages(SHADER_MODULE_STATE const *producer, spirv_inst_iter producer_entrypoint,
3506 shader_stage_attributes const *producer_stage, SHADER_MODULE_STATE const *consumer,
3507 spirv_inst_iter consumer_entrypoint,
3508 shader_stage_attributes const *consumer_stage) const {
Chris Forbes47567b72017-06-09 12:09:45 -07003509 bool skip = false;
3510
3511 auto outputs =
Shannon McPhersonc06c33d2018-06-28 17:21:12 -06003512 CollectInterfaceByLocation(producer, producer_entrypoint, spv::StorageClassOutput, producer_stage->arrayed_output);
3513 auto inputs = CollectInterfaceByLocation(consumer, consumer_entrypoint, spv::StorageClassInput, consumer_stage->arrayed_input);
Chris Forbes47567b72017-06-09 12:09:45 -07003514
3515 auto a_it = outputs.begin();
3516 auto b_it = inputs.begin();
3517
3518 // Maps sorted by key (location); walk them together to find mismatches
3519 while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) {
3520 bool a_at_end = outputs.size() == 0 || a_it == outputs.end();
3521 bool b_at_end = inputs.size() == 0 || b_it == inputs.end();
3522 auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first;
3523 auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first;
3524
3525 if (b_at_end || ((!a_at_end) && (a_first < b_first))) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003526 skip |= LogPerformanceWarning(producer->vk_shader_module, kVUID_Core_Shader_OutputNotConsumed,
3527 "%s writes to output location %u.%u which is not consumed by %s", producer_stage->name,
3528 a_first.first, a_first.second, consumer_stage->name);
Chris Forbes47567b72017-06-09 12:09:45 -07003529 a_it++;
3530 } else if (a_at_end || a_first > b_first) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003531 skip |= LogError(consumer->vk_shader_module, kVUID_Core_Shader_InputNotProduced,
3532 "%s consumes input location %u.%u which is not written by %s", consumer_stage->name, b_first.first,
3533 b_first.second, producer_stage->name);
Chris Forbes47567b72017-06-09 12:09:45 -07003534 b_it++;
3535 } else {
3536 // subtleties of arrayed interfaces:
3537 // - if is_patch, then the member is not arrayed, even though the interface may be.
3538 // - if is_block_member, then the extra array level of an arrayed interface is not
3539 // expressed in the member type -- it's expressed in the block type.
Shannon McPhersonc06c33d2018-06-28 17:21:12 -06003540 if (!TypesMatch(producer, consumer, a_it->second.type_id, b_it->second.type_id,
3541 producer_stage->arrayed_output && !a_it->second.is_patch && !a_it->second.is_block_member,
3542 consumer_stage->arrayed_input && !b_it->second.is_patch && !b_it->second.is_block_member, true)) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003543 skip |= LogError(producer->vk_shader_module, kVUID_Core_Shader_InterfaceTypeMismatch,
3544 "Type mismatch on location %u.%u: '%s' vs '%s'", a_first.first, a_first.second,
3545 DescribeType(producer, a_it->second.type_id).c_str(),
3546 DescribeType(consumer, b_it->second.type_id).c_str());
Chris Forbes47567b72017-06-09 12:09:45 -07003547 }
3548 if (a_it->second.is_patch != b_it->second.is_patch) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003549 skip |= LogError(producer->vk_shader_module, kVUID_Core_Shader_InterfaceTypeMismatch,
3550 "Decoration mismatch on location %u.%u: is per-%s in %s stage but per-%s in %s stage",
3551 a_first.first, a_first.second, a_it->second.is_patch ? "patch" : "vertex", producer_stage->name,
3552 b_it->second.is_patch ? "patch" : "vertex", consumer_stage->name);
Chris Forbes47567b72017-06-09 12:09:45 -07003553 }
3554 if (a_it->second.is_relaxed_precision != b_it->second.is_relaxed_precision) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003555 skip |= LogError(producer->vk_shader_module, kVUID_Core_Shader_InterfaceTypeMismatch,
3556 "Decoration mismatch on location %u.%u: %s and %s stages differ in precision", a_first.first,
3557 a_first.second, producer_stage->name, consumer_stage->name);
Chris Forbes47567b72017-06-09 12:09:45 -07003558 }
3559 a_it++;
3560 b_it++;
3561 }
3562 }
3563
Ari Suonpaa696b3432019-03-11 14:02:57 +02003564 if (consumer_stage->stage != VK_SHADER_STAGE_FRAGMENT_BIT) {
3565 auto builtins_producer = CollectBuiltinBlockMembers(producer, producer_entrypoint, spv::StorageClassOutput);
3566 auto builtins_consumer = CollectBuiltinBlockMembers(consumer, consumer_entrypoint, spv::StorageClassInput);
3567
3568 if (!builtins_producer.empty() && !builtins_consumer.empty()) {
3569 if (builtins_producer.size() != builtins_consumer.size()) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003570 skip |= LogError(producer->vk_shader_module, kVUID_Core_Shader_InterfaceTypeMismatch,
3571 "Number of elements inside builtin block differ between stages (%s %d vs %s %d).",
3572 producer_stage->name, (int)builtins_producer.size(), consumer_stage->name,
3573 (int)builtins_consumer.size());
Ari Suonpaa696b3432019-03-11 14:02:57 +02003574 } else {
3575 auto it_producer = builtins_producer.begin();
3576 auto it_consumer = builtins_consumer.begin();
3577 while (it_producer != builtins_producer.end() && it_consumer != builtins_consumer.end()) {
3578 if (*it_producer != *it_consumer) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003579 skip |= LogError(producer->vk_shader_module, kVUID_Core_Shader_InterfaceTypeMismatch,
3580 "Builtin variable inside block doesn't match between %s and %s.", producer_stage->name,
3581 consumer_stage->name);
Ari Suonpaa696b3432019-03-11 14:02:57 +02003582 break;
3583 }
3584 it_producer++;
3585 it_consumer++;
3586 }
3587 }
3588 }
3589 }
3590
Chris Forbes47567b72017-06-09 12:09:45 -07003591 return skip;
3592}
3593
John Zulauf14c355b2019-06-27 16:09:37 -06003594static inline uint32_t DetermineFinalGeomStage(const PIPELINE_STATE *pipeline, const VkGraphicsPipelineCreateInfo *pCreateInfo) {
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06003595 uint32_t stage_mask = 0;
3596 if (pipeline->topology_at_rasterizer == VK_PRIMITIVE_TOPOLOGY_POINT_LIST) {
3597 for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
3598 stage_mask |= pCreateInfo->pStages[i].stage;
3599 }
3600 // Determine which shader in which PointSize should be written (the final geometry stage)
Jeff Bolz105d6492018-09-29 15:46:44 -05003601 if (stage_mask & VK_SHADER_STAGE_MESH_BIT_NV) {
3602 stage_mask = VK_SHADER_STAGE_MESH_BIT_NV;
3603 } else if (stage_mask & VK_SHADER_STAGE_GEOMETRY_BIT) {
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06003604 stage_mask = VK_SHADER_STAGE_GEOMETRY_BIT;
3605 } else if (stage_mask & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
3606 stage_mask = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
3607 } else if (stage_mask & VK_SHADER_STAGE_VERTEX_BIT) {
3608 stage_mask = VK_SHADER_STAGE_VERTEX_BIT;
Mark Lobodzinski2c984cc2018-07-31 09:57:46 -06003609 }
3610 }
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06003611 return stage_mask;
Mark Lobodzinski2c984cc2018-07-31 09:57:46 -06003612}
3613
Chris Forbes47567b72017-06-09 12:09:45 -07003614// Validate that the shaders used by the given pipeline and store the active_slots
3615// that are actually used by the pipeline into pPipeline->active_slots
John Zulaufac4c6e12019-07-01 16:05:58 -06003616bool CoreChecks::ValidateGraphicsPipelineShaderState(const PIPELINE_STATE *pipeline) const {
Chris Forbesa400a8a2017-07-20 13:10:24 -07003617 auto pCreateInfo = pipeline->graphicsPipelineCI.ptr();
Shannon McPhersonc06c33d2018-06-28 17:21:12 -06003618 int vertex_stage = GetShaderStageId(VK_SHADER_STAGE_VERTEX_BIT);
3619 int fragment_stage = GetShaderStageId(VK_SHADER_STAGE_FRAGMENT_BIT);
Chris Forbes47567b72017-06-09 12:09:45 -07003620
John Zulauf14c355b2019-06-27 16:09:37 -06003621 const SHADER_MODULE_STATE *shaders[32];
Chris Forbes47567b72017-06-09 12:09:45 -07003622 memset(shaders, 0, sizeof(shaders));
Jeff Bolz7e35c392018-09-04 15:30:41 -05003623 spirv_inst_iter entrypoints[32];
Chris Forbes47567b72017-06-09 12:09:45 -07003624 bool skip = false;
3625
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06003626 uint32_t pointlist_stage_mask = DetermineFinalGeomStage(pipeline, pCreateInfo);
3627
Chris Forbes47567b72017-06-09 12:09:45 -07003628 for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
3629 auto pStage = &pCreateInfo->pStages[i];
Shannon McPhersonc06c33d2018-06-28 17:21:12 -06003630 auto stage_id = GetShaderStageId(pStage->stage);
John Zulauf14c355b2019-06-27 16:09:37 -06003631 shaders[stage_id] = GetShaderModuleState(pStage->module);
3632 entrypoints[stage_id] = FindEntrypoint(shaders[stage_id], pStage->pName, pStage->stage);
3633 skip |= ValidatePipelineShaderStage(pStage, pipeline, pipeline->stage_state[i], shaders[stage_id], entrypoints[stage_id],
Mark Lobodzinski1b4a8ed2018-08-07 08:47:05 -06003634 (pointlist_stage_mask == pStage->stage));
Chris Forbes47567b72017-06-09 12:09:45 -07003635 }
3636
3637 // if the shader stages are no good individually, cross-stage validation is pointless.
3638 if (skip) return true;
3639
3640 auto vi = pCreateInfo->pVertexInputState;
3641
3642 if (vi) {
Mark Lobodzinskid8d658e2020-01-30 15:05:51 -07003643 skip |= ValidateViConsistency(vi);
Chris Forbes47567b72017-06-09 12:09:45 -07003644 }
3645
3646 if (shaders[vertex_stage] && shaders[vertex_stage]->has_valid_spirv) {
Mark Lobodzinskid8d658e2020-01-30 15:05:51 -07003647 skip |= ValidateViAgainstVsInputs(vi, shaders[vertex_stage], entrypoints[vertex_stage]);
Chris Forbes47567b72017-06-09 12:09:45 -07003648 }
3649
Shannon McPhersonc06c33d2018-06-28 17:21:12 -06003650 int producer = GetShaderStageId(VK_SHADER_STAGE_VERTEX_BIT);
3651 int consumer = GetShaderStageId(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
Chris Forbes47567b72017-06-09 12:09:45 -07003652
3653 while (!shaders[producer] && producer != fragment_stage) {
3654 producer++;
3655 consumer++;
3656 }
3657
3658 for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) {
3659 assert(shaders[producer]);
Chris Forbesdbb43fc2018-02-16 16:59:23 -08003660 if (shaders[consumer]) {
3661 if (shaders[consumer]->has_valid_spirv && shaders[producer]->has_valid_spirv) {
Mark Lobodzinskid8d658e2020-01-30 15:05:51 -07003662 skip |= ValidateInterfaceBetweenStages(shaders[producer], entrypoints[producer], &shader_stage_attribs[producer],
3663 shaders[consumer], entrypoints[consumer], &shader_stage_attribs[consumer]);
Chris Forbesdbb43fc2018-02-16 16:59:23 -08003664 }
Chris Forbes47567b72017-06-09 12:09:45 -07003665
3666 producer = consumer;
3667 }
3668 }
3669
3670 if (shaders[fragment_stage] && shaders[fragment_stage]->has_valid_spirv) {
Mark Lobodzinskid8d658e2020-01-30 15:05:51 -07003671 skip |= ValidateFsOutputsAgainstRenderPass(shaders[fragment_stage], entrypoints[fragment_stage], pipeline,
Shannon McPhersonc06c33d2018-06-28 17:21:12 -06003672 pCreateInfo->subpass);
Chris Forbes47567b72017-06-09 12:09:45 -07003673 }
3674
3675 return skip;
3676}
3677
Tobias Hector6663c9b2020-11-05 10:18:02 +00003678bool CoreChecks::ValidateGraphicsPipelineShaderDynamicState(const PIPELINE_STATE *pipeline, const CMD_BUFFER_STATE *pCB,
3679 const char *caller, const DrawDispatchVuid &vuid) const {
3680 auto pCreateInfo = pipeline->graphicsPipelineCI.ptr();
3681
3682 const SHADER_MODULE_STATE *shaders[32];
3683 memset(shaders, 0, sizeof(shaders));
3684 spirv_inst_iter entrypoints[32];
3685 memset(entrypoints, 0, sizeof(entrypoints));
3686 bool skip = false;
3687
3688 for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
3689 auto pStage = &pCreateInfo->pStages[i];
3690 auto stage_id = GetShaderStageId(pStage->stage);
3691 shaders[stage_id] = GetShaderModuleState(pStage->module);
3692 entrypoints[stage_id] = FindEntrypoint(shaders[stage_id], pStage->pName, pStage->stage);
3693
3694 if (pStage->stage == VK_SHADER_STAGE_VERTEX_BIT || pStage->stage == VK_SHADER_STAGE_GEOMETRY_BIT ||
3695 pStage->stage == VK_SHADER_STAGE_MESH_BIT_NV) {
3696 if (!phys_dev_ext_props.fragment_shading_rate_props.primitiveFragmentShadingRateWithMultipleViewports &&
3697 IsDynamic(pipeline, VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT) && pCB->viewportWithCountCount != 1) {
3698 spirv_inst_iter insn = entrypoints[stage_id];
3699 bool primitiverate_written = false;
3700
3701 while (!primitiverate_written && (insn.opcode() != spv::OpFunction)) {
3702 if (insn.opcode() == spv::OpMemberDecorate) {
3703 if (insn.word(3) == spv::DecorationBuiltIn) {
3704 if (insn.word(4) == spv::BuiltInPrimitiveShadingRateKHR) {
3705 primitiverate_written = IsBuiltInWritten(shaders[stage_id], insn, entrypoints[stage_id]);
3706 }
3707 }
3708 } else if (insn.opcode() == spv::OpDecorate) {
3709 if (insn.word(2) == spv::DecorationBuiltIn) {
3710 if (insn.word(3) == spv::BuiltInPrimitiveShadingRateKHR) {
3711 primitiverate_written = IsBuiltInWritten(shaders[stage_id], insn, entrypoints[stage_id]);
3712 }
3713 }
3714 }
3715
3716 insn++;
3717 }
3718
3719 if (primitiverate_written) {
3720 skip |=
3721 LogError(pipeline->pipeline, vuid.viewport_count_primitive_shading_rate,
3722 "%s: %s shader of currently bound pipeline statically writes to PrimitiveShadingRateKHR built-in"
3723 "but multiple viewports are set by the last call to vkCmdSetViewportWithCountEXT,"
3724 "and the primitiveFragmentShadingRateWithMultipleViewports limit is not supported.",
3725 caller, string_VkShaderStageFlagBits(pStage->stage));
3726 }
3727 }
3728 }
3729 }
3730
3731 return skip;
3732}
3733
sfricke-samsunge72a85e2020-02-29 21:48:37 -08003734bool CoreChecks::ValidateComputePipelineShaderState(PIPELINE_STATE *pipeline) const {
John Zulauf14c355b2019-06-27 16:09:37 -06003735 const auto &stage = *pipeline->computePipelineCI.stage.ptr();
Chris Forbes47567b72017-06-09 12:09:45 -07003736
John Zulauf14c355b2019-06-27 16:09:37 -06003737 const SHADER_MODULE_STATE *module = GetShaderModuleState(stage.module);
3738 const spirv_inst_iter entrypoint = FindEntrypoint(module, stage.pName, stage.stage);
Chris Forbes47567b72017-06-09 12:09:45 -07003739
John Zulauf14c355b2019-06-27 16:09:37 -06003740 return ValidatePipelineShaderStage(&stage, pipeline, pipeline->stage_state[0], module, entrypoint, false);
Chris Forbes47567b72017-06-09 12:09:45 -07003741}
Chris Forbes4ae55b32017-06-09 14:42:56 -07003742
Ricardo Garcia6f3477e2020-10-21 10:58:53 +02003743uint32_t CoreChecks::CalcShaderStageCount(const PIPELINE_STATE *pipeline, VkShaderStageFlagBits stageBit) const {
3744 uint32_t total = 0;
3745
3746 const auto *stages = pipeline->raytracingPipelineCI.ptr()->pStages;
3747 for (uint32_t stage_index = 0; stage_index < pipeline->raytracingPipelineCI.stageCount; stage_index++) {
3748 if (stages[stage_index].stage == stageBit) {
3749 total++;
3750 }
3751 }
3752
3753 if (pipeline->raytracingPipelineCI.pLibraryInfo) {
3754 for (uint32_t i = 0; i < pipeline->raytracingPipelineCI.pLibraryInfo->libraryCount; ++i) {
3755 const PIPELINE_STATE *library_pipeline = GetPipelineState(pipeline->raytracingPipelineCI.pLibraryInfo->pLibraries[i]);
3756 total += CalcShaderStageCount(library_pipeline, stageBit);
3757 }
3758 }
3759
3760 return total;
3761}
3762
sourav parmarcd5fb182020-07-17 12:58:44 -07003763bool CoreChecks::ValidateRayTracingPipeline(PIPELINE_STATE *pipeline, VkPipelineCreateFlags flags, bool isKHR) const {
John Zulaufe4474e72019-07-01 17:28:27 -06003764 bool skip = false;
Jason Macnak15f95e82019-08-21 21:52:02 -04003765
Jeff Bolz443c2ca2020-03-19 12:11:51 -05003766 if (isKHR) {
sourav parmarcd5fb182020-07-17 12:58:44 -07003767 if (pipeline->raytracingPipelineCI.maxPipelineRayRecursionDepth >
3768 phys_dev_ext_props.ray_tracing_propsKHR.maxRayRecursionDepth) {
3769 skip |= LogError(device, "VUID-VkRayTracingPipelineCreateInfoKHR-maxPipelineRayRecursionDepth-03589",
3770 "vkCreateRayTracingPipelinesKHR: maxPipelineRayRecursionDepth (%d ) must be less than or equal to "
3771 "VkPhysicalDeviceRayTracingPipelinePropertiesKHR::maxRayRecursionDepth %d",
3772 pipeline->raytracingPipelineCI.maxPipelineRayRecursionDepth,
3773 phys_dev_ext_props.ray_tracing_propsKHR.maxRayRecursionDepth);
Jeff Bolz443c2ca2020-03-19 12:11:51 -05003774 }
sourav parmarcd5fb182020-07-17 12:58:44 -07003775 if (pipeline->raytracingPipelineCI.pLibraryInfo) {
3776 for (uint32_t i = 0; i < pipeline->raytracingPipelineCI.pLibraryInfo->libraryCount; ++i) {
3777 const PIPELINE_STATE *pLibrary_pipelinestate =
3778 GetPipelineState(pipeline->raytracingPipelineCI.pLibraryInfo->pLibraries[i]);
3779 if (pLibrary_pipelinestate->raytracingPipelineCI.maxPipelineRayRecursionDepth !=
3780 pipeline->raytracingPipelineCI.maxPipelineRayRecursionDepth) {
3781 skip |= LogError(
3782 device, "VUID-VkRayTracingPipelineCreateInfoKHR-pLibraries-03591",
3783 "vkCreateRayTracingPipelinesKHR: Each element (%d) of the pLibraries member of libraries must have been"
3784 "created with the value of maxPipelineRayRecursionDepth (%d) equal to that in this pipeline (%d) .",
3785 i, pLibrary_pipelinestate->raytracingPipelineCI.maxPipelineRayRecursionDepth,
3786 pipeline->raytracingPipelineCI.maxPipelineRayRecursionDepth);
3787 }
3788 if (pLibrary_pipelinestate->raytracingPipelineCI.pLibraryInfo &&
3789 (pLibrary_pipelinestate->raytracingPipelineCI.pLibraryInterface->maxPipelineRayHitAttributeSize !=
3790 pipeline->raytracingPipelineCI.pLibraryInterface->maxPipelineRayHitAttributeSize ||
3791 pLibrary_pipelinestate->raytracingPipelineCI.pLibraryInterface->maxPipelineRayPayloadSize !=
3792 pipeline->raytracingPipelineCI.pLibraryInterface->maxPipelineRayPayloadSize)) {
3793 skip |= LogError(device, "VUID-VkRayTracingPipelineCreateInfoKHR-pLibraryInfo-03593",
3794 "vkCreateRayTracingPipelinesKHR: If pLibraryInfo is not NULL, each element of its pLibraries "
3795 "member must have been created with values of the maxPipelineRayPayloadSize and "
3796 "maxPipelineRayHitAttributeSize members of pLibraryInterface equal to those in this pipeline");
3797 }
3798 if ((flags & VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR) &&
3799 !(pLibrary_pipelinestate->raytracingPipelineCI.flags &
3800 VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR)) {
3801 skip |= LogError(device, "VUID-VkRayTracingPipelineCreateInfoKHR-flags-03594",
3802 "vkCreateRayTracingPipelinesKHR: If flags includes "
3803 "VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR, each element of "
3804 "the pLibraries member of libraries must have been created with the "
3805 "VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR bit set");
3806 }
sourav parmar83c31b12020-05-06 12:30:54 -07003807 }
3808 }
Jeff Bolz443c2ca2020-03-19 12:11:51 -05003809 } else {
3810 if (pipeline->raytracingPipelineCI.maxRecursionDepth > phys_dev_ext_props.ray_tracing_propsNV.maxRecursionDepth) {
sourav parmarcd5fb182020-07-17 12:58:44 -07003811 skip |= LogError(device, "VUID-VkRayTracingPipelineCreateInfoNV-maxRecursionDepth-03457",
3812 "vkCreateRayTracingPipelinesNV: maxRecursionDepth (%d) must be less than or equal to "
3813 "VkPhysicalDeviceRayTracingPropertiesNV::maxRecursionDepth (%d)",
Jeff Bolz443c2ca2020-03-19 12:11:51 -05003814 pipeline->raytracingPipelineCI.maxRecursionDepth,
3815 phys_dev_ext_props.ray_tracing_propsNV.maxRecursionDepth);
3816 }
Jason Macnak15f95e82019-08-21 21:52:02 -04003817 }
Jason Macnak15f95e82019-08-21 21:52:02 -04003818 const auto *stages = pipeline->raytracingPipelineCI.ptr()->pStages;
3819 const auto *groups = pipeline->raytracingPipelineCI.ptr()->pGroups;
3820
John Zulaufe4474e72019-07-01 17:28:27 -06003821 for (uint32_t stage_index = 0; stage_index < pipeline->raytracingPipelineCI.stageCount; stage_index++) {
Jason Macnak15f95e82019-08-21 21:52:02 -04003822 const auto &stage = stages[stage_index];
Jeff Bolzfbe51582018-09-13 10:01:35 -05003823
John Zulaufe4474e72019-07-01 17:28:27 -06003824 const SHADER_MODULE_STATE *module = GetShaderModuleState(stage.module);
3825 const spirv_inst_iter entrypoint = FindEntrypoint(module, stage.pName, stage.stage);
Jeff Bolzfbe51582018-09-13 10:01:35 -05003826
John Zulaufe4474e72019-07-01 17:28:27 -06003827 skip |= ValidatePipelineShaderStage(&stage, pipeline, pipeline->stage_state[stage_index], module, entrypoint, false);
Jason Macnak15f95e82019-08-21 21:52:02 -04003828 }
Ricardo Garcia6f3477e2020-10-21 10:58:53 +02003829
3830 if ((pipeline->raytracingPipelineCI.flags & VK_PIPELINE_CREATE_LIBRARY_BIT_KHR) == 0) {
3831 const uint32_t raygen_stages_count = CalcShaderStageCount(pipeline, VK_SHADER_STAGE_RAYGEN_BIT_KHR);
3832 if (raygen_stages_count == 0) {
3833 skip |= LogError(
3834 device,
3835 isKHR ? "VUID-VkRayTracingPipelineCreateInfoKHR-stage-03425" : "VUID-VkRayTracingPipelineCreateInfoNV-stage-03425",
3836 " : The stage member of at least one element of pStages must be VK_SHADER_STAGE_RAYGEN_BIT_KHR.");
3837 }
Jason Macnak15f95e82019-08-21 21:52:02 -04003838 }
3839
3840 for (uint32_t group_index = 0; group_index < pipeline->raytracingPipelineCI.groupCount; group_index++) {
3841 const auto &group = groups[group_index];
3842
3843 if (group.type == VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV) {
3844 if (group.generalShader >= pipeline->raytracingPipelineCI.stageCount ||
3845 (stages[group.generalShader].stage != VK_SHADER_STAGE_RAYGEN_BIT_NV &&
3846 stages[group.generalShader].stage != VK_SHADER_STAGE_MISS_BIT_NV &&
3847 stages[group.generalShader].stage != VK_SHADER_STAGE_CALLABLE_BIT_NV)) {
Jeff Bolz443c2ca2020-03-19 12:11:51 -05003848 skip |= LogError(device,
3849 isKHR ? "VUID-VkRayTracingShaderGroupCreateInfoKHR-type-03474"
3850 : "VUID-VkRayTracingShaderGroupCreateInfoNV-type-02413",
3851 ": pGroups[%d]", group_index);
Jason Macnak15f95e82019-08-21 21:52:02 -04003852 }
3853 if (group.anyHitShader != VK_SHADER_UNUSED_NV || group.closestHitShader != VK_SHADER_UNUSED_NV ||
3854 group.intersectionShader != VK_SHADER_UNUSED_NV) {
Jeff Bolz443c2ca2020-03-19 12:11:51 -05003855 skip |= LogError(device,
3856 isKHR ? "VUID-VkRayTracingShaderGroupCreateInfoKHR-type-03475"
3857 : "VUID-VkRayTracingShaderGroupCreateInfoNV-type-02414",
3858 ": pGroups[%d]", group_index);
Jason Macnak15f95e82019-08-21 21:52:02 -04003859 }
3860 } else if (group.type == VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV) {
3861 if (group.intersectionShader >= pipeline->raytracingPipelineCI.stageCount ||
3862 stages[group.intersectionShader].stage != VK_SHADER_STAGE_INTERSECTION_BIT_NV) {
Jeff Bolz443c2ca2020-03-19 12:11:51 -05003863 skip |= LogError(device,
3864 isKHR ? "VUID-VkRayTracingShaderGroupCreateInfoKHR-type-03476"
3865 : "VUID-VkRayTracingShaderGroupCreateInfoNV-type-02415",
3866 ": pGroups[%d]", group_index);
Jason Macnak15f95e82019-08-21 21:52:02 -04003867 }
3868 } else if (group.type == VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV) {
3869 if (group.intersectionShader != VK_SHADER_UNUSED_NV) {
Jeff Bolz443c2ca2020-03-19 12:11:51 -05003870 skip |= LogError(device,
3871 isKHR ? "VUID-VkRayTracingShaderGroupCreateInfoKHR-type-03477"
3872 : "VUID-VkRayTracingShaderGroupCreateInfoNV-type-02416",
3873 ": pGroups[%d]", group_index);
Jason Macnak15f95e82019-08-21 21:52:02 -04003874 }
3875 }
3876
3877 if (group.type == VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV ||
3878 group.type == VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV) {
3879 if (group.anyHitShader != VK_SHADER_UNUSED_NV && (group.anyHitShader >= pipeline->raytracingPipelineCI.stageCount ||
3880 stages[group.anyHitShader].stage != VK_SHADER_STAGE_ANY_HIT_BIT_NV)) {
Jeff Bolz443c2ca2020-03-19 12:11:51 -05003881 skip |= LogError(device,
3882 isKHR ? "VUID-VkRayTracingShaderGroupCreateInfoKHR-anyHitShader-03479"
3883 : "VUID-VkRayTracingShaderGroupCreateInfoNV-anyHitShader-02418",
3884 ": pGroups[%d]", group_index);
Jason Macnak15f95e82019-08-21 21:52:02 -04003885 }
3886 if (group.closestHitShader != VK_SHADER_UNUSED_NV &&
3887 (group.closestHitShader >= pipeline->raytracingPipelineCI.stageCount ||
3888 stages[group.closestHitShader].stage != VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV)) {
Jeff Bolz443c2ca2020-03-19 12:11:51 -05003889 skip |= LogError(device,
3890 isKHR ? "VUID-VkRayTracingShaderGroupCreateInfoKHR-closestHitShader-03478"
3891 : "VUID-VkRayTracingShaderGroupCreateInfoNV-closestHitShader-02417",
3892 ": pGroups[%d]", group_index);
Jason Macnak15f95e82019-08-21 21:52:02 -04003893 }
3894 }
John Zulaufe4474e72019-07-01 17:28:27 -06003895 }
3896 return skip;
Jeff Bolzfbe51582018-09-13 10:01:35 -05003897}
3898
Dave Houltona9df0ce2018-02-07 10:51:23 -07003899uint32_t ValidationCache::MakeShaderHash(VkShaderModuleCreateInfo const *smci) { return XXH32(smci->pCode, smci->codeSize, 0); }
Chris Forbes9a61e082017-07-24 15:35:29 -07003900
Dave Houltona9df0ce2018-02-07 10:51:23 -07003901static ValidationCache *GetValidationCacheInfo(VkShaderModuleCreateInfo const *pCreateInfo) {
John Zulauf25ea2432019-04-05 10:07:38 -06003902 const auto validation_cache_ci = lvl_find_in_chain<VkShaderModuleValidationCacheCreateInfoEXT>(pCreateInfo->pNext);
3903 if (validation_cache_ci) {
John Zulauf146ee802019-04-05 15:31:06 -06003904 return CastFromHandle<ValidationCache *>(validation_cache_ci->validationCache);
Chris Forbes9a61e082017-07-24 15:35:29 -07003905 }
Chris Forbes9a61e082017-07-24 15:35:29 -07003906 return nullptr;
3907}
3908
Mark Lobodzinskib56bbb92019-02-18 11:49:59 -07003909bool CoreChecks::PreCallValidateCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
Jeff Bolz5c801d12019-10-09 10:38:45 -05003910 const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) const {
Chris Forbes4ae55b32017-06-09 14:42:56 -07003911 bool skip = false;
3912 spv_result_t spv_valid = SPV_SUCCESS;
Chris Forbes4ae55b32017-06-09 14:42:56 -07003913
Mark Lobodzinski90eea5b2020-05-15 12:54:00 -06003914 if (disabled[shader_validation]) {
Chris Forbes4ae55b32017-06-09 14:42:56 -07003915 return false;
3916 }
3917
Mark Lobodzinskif45e45f2019-04-19 14:15:39 -06003918 auto have_glsl_shader = device_extensions.vk_nv_glsl_shader;
Chris Forbes4ae55b32017-06-09 14:42:56 -07003919
3920 if (!have_glsl_shader && (pCreateInfo->codeSize % 4)) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003921 skip |= LogError(device, "VUID-VkShaderModuleCreateInfo-pCode-01376",
3922 "SPIR-V module not valid: Codesize must be a multiple of 4 but is " PRINTF_SIZE_T_SPECIFIER ".",
3923 pCreateInfo->codeSize);
Chris Forbes4ae55b32017-06-09 14:42:56 -07003924 } else {
Chris Forbes9a61e082017-07-24 15:35:29 -07003925 auto cache = GetValidationCacheInfo(pCreateInfo);
3926 uint32_t hash = 0;
3927 if (cache) {
3928 hash = ValidationCache::MakeShaderHash(pCreateInfo);
Dave Houltona9df0ce2018-02-07 10:51:23 -07003929 if (cache->Contains(hash)) return false;
Chris Forbes9a61e082017-07-24 15:35:29 -07003930 }
3931
Jeremy Hayesb3e4d532019-08-16 10:08:49 -06003932 // Use SPIRV-Tools validator to try and catch any issues with the module itself. If specialization constants are present,
3933 // the default values will be used during validation.
Tony-LunarG8a51b7d2020-07-01 15:57:23 -06003934 spv_target_env spirv_environment = PickSpirvEnv(api_version, (device_extensions.vk_khr_spirv_1_4 != kNotEnabled));
Dave Houlton0ea2d012018-06-21 14:00:26 -06003935 spv_context ctx = spvContextCreate(spirv_environment);
Dave Houltona9df0ce2018-02-07 10:51:23 -07003936 spv_const_binary_t binary{pCreateInfo->pCode, pCreateInfo->codeSize / sizeof(uint32_t)};
Chris Forbes4ae55b32017-06-09 14:42:56 -07003937 spv_diagnostic diag = nullptr;
Tony-LunarG9fe69a42020-07-23 15:09:37 -06003938 spvtools::ValidatorOptions options;
3939 AdjustValidatorOptions(device_extensions, enabled_features, options);
Karl Schultzfda1b382018-08-08 18:56:11 -06003940 spv_valid = spvValidateWithOptions(ctx, options, &binary, &diag);
Chris Forbes4ae55b32017-06-09 14:42:56 -07003941 if (spv_valid != SPV_SUCCESS) {
3942 if (!have_glsl_shader || (pCreateInfo->pCode[0] == spv::MagicNumber)) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003943 if (spv_valid == SPV_WARNING) {
3944 skip |= LogWarning(device, kVUID_Core_Shader_InconsistentSpirv, "SPIR-V module not valid: %s",
3945 diag && diag->error ? diag->error : "(no error text)");
3946 } else {
3947 skip |= LogError(device, kVUID_Core_Shader_InconsistentSpirv, "SPIR-V module not valid: %s",
3948 diag && diag->error ? diag->error : "(no error text)");
3949 }
Chris Forbes4ae55b32017-06-09 14:42:56 -07003950 }
Chris Forbes9a61e082017-07-24 15:35:29 -07003951 } else {
3952 if (cache) {
3953 cache->Insert(hash);
3954 }
Chris Forbes4ae55b32017-06-09 14:42:56 -07003955 }
3956
3957 spvDiagnosticDestroy(diag);
3958 spvContextDestroy(ctx);
3959 }
3960
Chris Forbes4ae55b32017-06-09 14:42:56 -07003961 return skip;
Mark Lobodzinski01734072019-02-13 17:39:15 -07003962}
3963
John Zulaufac4c6e12019-07-01 16:05:58 -06003964bool CoreChecks::ValidateComputeWorkGroupSizes(const SHADER_MODULE_STATE *shader) const {
Lockeaa8fdc02019-04-02 11:59:20 -06003965 bool skip = false;
3966 uint32_t local_size_x = 0;
3967 uint32_t local_size_y = 0;
3968 uint32_t local_size_z = 0;
3969 if (FindLocalSize(shader, local_size_x, local_size_y, local_size_z)) {
3970 if (local_size_x > phys_dev_props.limits.maxComputeWorkGroupSize[0]) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003971 skip |= LogError(shader->vk_shader_module, "UNASSIGNED-features-limits-maxComputeWorkGroupSize",
3972 "%s local_size_x (%" PRIu32 ") exceeds device limit maxComputeWorkGroupSize[0] (%" PRIu32 ").",
3973 report_data->FormatHandle(shader->vk_shader_module).c_str(), local_size_x,
3974 phys_dev_props.limits.maxComputeWorkGroupSize[0]);
Lockeaa8fdc02019-04-02 11:59:20 -06003975 }
3976 if (local_size_y > phys_dev_props.limits.maxComputeWorkGroupSize[1]) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003977 skip |= LogError(shader->vk_shader_module, "UNASSIGNED-features-limits-maxComputeWorkGroupSize",
3978 "%s local_size_y (%" PRIu32 ") exceeds device limit maxComputeWorkGroupSize[1] (%" PRIu32 ").",
3979 report_data->FormatHandle(shader->vk_shader_module).c_str(), local_size_x,
3980 phys_dev_props.limits.maxComputeWorkGroupSize[1]);
Lockeaa8fdc02019-04-02 11:59:20 -06003981 }
3982 if (local_size_z > phys_dev_props.limits.maxComputeWorkGroupSize[2]) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07003983 skip |= LogError(shader->vk_shader_module, "UNASSIGNED-features-limits-maxComputeWorkGroupSize",
3984 "%s local_size_z (%" PRIu32 ") exceeds device limit maxComputeWorkGroupSize[2] (%" PRIu32 ").",
3985 report_data->FormatHandle(shader->vk_shader_module).c_str(), local_size_x,
3986 phys_dev_props.limits.maxComputeWorkGroupSize[2]);
Lockeaa8fdc02019-04-02 11:59:20 -06003987 }
3988
3989 uint32_t limit = phys_dev_props.limits.maxComputeWorkGroupInvocations;
3990 uint64_t invocations = local_size_x * local_size_y;
3991 // Prevent overflow.
3992 bool fail = false;
3993 if (invocations > UINT32_MAX || invocations > limit) {
3994 fail = true;
3995 }
3996 if (!fail) {
3997 invocations *= local_size_z;
3998 if (invocations > UINT32_MAX || invocations > limit) {
3999 fail = true;
4000 }
4001 }
4002 if (fail) {
Mark Lobodzinski12b9be92020-01-30 15:25:55 -07004003 skip |= LogError(shader->vk_shader_module, "UNASSIGNED-features-limits-maxComputeWorkGroupInvocations",
4004 "%s local_size (%" PRIu32 ", %" PRIu32 ", %" PRIu32
4005 ") exceeds device limit maxComputeWorkGroupInvocations (%" PRIu32 ").",
4006 report_data->FormatHandle(shader->vk_shader_module).c_str(), local_size_x, local_size_y, local_size_z,
4007 limit);
Lockeaa8fdc02019-04-02 11:59:20 -06004008 }
4009 }
4010 return skip;
4011}
Tony-LunarG8a51b7d2020-07-01 15:57:23 -06004012
4013spv_target_env PickSpirvEnv(uint32_t api_version, bool spirv_1_4) {
4014 if (api_version >= VK_API_VERSION_1_2) {
4015 return SPV_ENV_VULKAN_1_2;
4016 } else if (api_version >= VK_API_VERSION_1_1) {
4017 if (spirv_1_4) {
4018 return SPV_ENV_VULKAN_1_1_SPIRV_1_4;
4019 } else {
4020 return SPV_ENV_VULKAN_1_1;
4021 }
4022 }
4023 return SPV_ENV_VULKAN_1_0;
4024}
Tony-LunarG9fe69a42020-07-23 15:09:37 -06004025
4026void AdjustValidatorOptions(const DeviceExtensions device_extensions, const DeviceFeatures enabled_features,
4027 spvtools::ValidatorOptions &options) {
4028 if (device_extensions.vk_khr_relaxed_block_layout) {
4029 options.SetRelaxBlockLayout(true);
4030 }
4031 if (device_extensions.vk_khr_uniform_buffer_standard_layout && enabled_features.core12.uniformBufferStandardLayout == VK_TRUE) {
4032 options.SetUniformBufferStandardLayout(true);
4033 }
4034 if (device_extensions.vk_ext_scalar_block_layout && enabled_features.core12.scalarBlockLayout == VK_TRUE) {
4035 options.SetScalarBlockLayout(true);
4036 }
4037}