1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2020 NVIDIA Corporation
6 * Copyright (c) 2023 LunarG, Inc.
7 * Copyright (c) 2023 Nintendo
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*!
22 * \file
23 * \brief VK_NV_inherited_viewport_scissor Tests
24 *
25 * Simple test cases for secondary command buffers inheriting dynamic
26 * viewport and scissor state from the calling primary command buffer
27 * or an earlier secondary command buffer. Tests draw a bunch of color
28 * rectangles using a trivial geometry pipeline (no vertex
29 * transformation except for fixed-function viewport transform,
30 * geometry shader selects viewport/scissor index). The depth test is
31 * enabled to check for incorrect depth transformation.
32 *//*--------------------------------------------------------------------*/
33 #include "vktDynamicStateInheritanceTests.hpp"
34
35 #include <math.h>
36 #include <sstream>
37 #include <vector>
38
39 #include "vkBufferWithMemory.hpp"
40 #include "vkImageWithMemory.hpp"
41
42 using namespace vk;
43 using tcu::Vec2;
44 using tcu::Vec3;
45
46 namespace vkt
47 {
48 namespace DynamicState
49 {
50 namespace
51 {
52 // Size of test framebuffer, power of 2 to avoid rounding errors.
53 static const int32_t kWidth = 256, kHeight = 128;
54
55 // Maximum viewport/scissors, and maximum rectangles, for any test case.
56 static const uint32_t kMaxViewports = 16, kMaxRectangles = 1024;
57
58 // Color format of framebuffer image, this seems universally supported.
59 static const VkFormat kFormat = VK_FORMAT_B8G8R8A8_UNORM;
60
61 // Texel data matching kFormat, and functions for converting to/from
62 // packed 32-bit color. alpha is unused.
63 struct Texel
64 {
65 uint8_t blue, green, red, alpha;
66 };
67
texelFrom_r8g8b8(int32_t r8g8b8)68 inline Texel texelFrom_r8g8b8(int32_t r8g8b8)
69 {
70 return {uint8_t(r8g8b8 & 255), uint8_t((r8g8b8 >> 8) & 255), uint8_t((r8g8b8 >> 16) & 255), 0u};
71 }
72
73 // Parameters of axis-aligned rectangle to rasterize. No mvp matrix
74 // or anything, only testing fixed-function viewport transformation.
75 struct Rectangle
76 {
77 Vec3 xyz; // Before viewport transformation
78 int32_t r8g8b8; // (8-bit) red << 16 | green << 8 | blue
79 Vec2 widthHeight; // positive; before viewport transformation
80 int32_t viewportIndex;
81 };
82
83 // Determines where the secondary command buffer's inherited viewport/scissor state comes from (if inherited at all).
84 enum InheritanceMode
85 {
86 kInheritanceDisabled, // Disable extension, use non-dynamic viewport/scissor count
87 kInheritFromPrimary, // Inherit from calling primary cmd buffer
88 kInheritFromSecondary, // Inherit from earlier secondary cmd buffer
89 kInheritFromSecondaryNested, // Inherit from earlier secondary cmd buffer nested within another secondary buffer
90 kSplitInheritance, // Split viewport/scissor array in two, inherit
91 // some from primary and rest from secondary
92
93 // Inherit state-with-count-EXT from calling primary cmd buffer
94 kInheritFromPrimaryWithCount,
95 // Inherit state-with-count-EXT from earlier secondary cmd buffer
96 kInheritFromSecondaryWithCount,
97 // Inherit state-with-count-EXT from earlier secondary cmd buffer nested within another secondary buffer
98 kInheritFromSecondaryNestedWithCount,
99 };
100
101 // Input test geometry.
102 struct TestGeometry
103 {
104 // Color and depth to clear the framebuffer to.
105 Vec3 clearColor;
106 float clearDepth;
107
108 // List of rectangles to rasterize, in order.
109 std::vector<Rectangle> rectangles;
110
111 // List of viewports and scissors to use, both vectors must have
112 // same length and have length at least 1.
113 std::vector<VkViewport> viewports;
114 std::vector<VkRect2D> scissors;
115 InheritanceMode inheritanceMode;
116 };
117
118 // Whether the test was a success, and both the device-rasterized image
119 // and the CPU-computed expected image.
120 struct TestResults
121 {
122 bool passed;
123
124 // Index with [y][x]
125 Texel deviceResult[kHeight][kWidth];
126 Texel expectedResult[kHeight][kWidth];
127 };
128
129 class InheritanceTestInstance : public TestInstance
130 {
131 const vk::InstanceInterface &m_in;
132 const vk::DeviceInterface &m_vk;
133 InheritanceMode m_inheritanceMode;
134
135 PipelineConstructionType m_pipelineConstructionType;
136
137 // Vertex buffer storing rectangle list, and its mapping and
138 // backing memory. kMaxRectangles is its capacity (in Rectangles).
139 BufferWithMemory m_rectangleBuffer;
140
141 // Buffer for downloading rendered image from device
142 BufferWithMemory m_downloadBuffer;
143
144 // Image attachments and views.
145 // Create info for depth buffer set at runtime due to depth format search.
146 VkImageCreateInfo m_depthImageInfo;
147 ImageWithMemory m_colorImage, m_depthImage;
148 VkImageViewCreateInfo m_colorViewInfo, m_depthViewInfo;
149 Unique<VkImageView> m_colorView, m_depthView;
150
151 // Simple render pass and framebuffer.
152 RenderPassWrapper m_renderPass;
153
154 // Shader modules for graphics pipelines.
155 ShaderWrapper m_vertModule, m_geomModule, m_fragModule;
156
157 // Geometry shader pipeline, converts points into rasterized
158 // struct Rectangles using geometry shader, which also selects the
159 // viewport to use. Pipeline array maps viewport/scissor count to
160 // the pipeline to use (special value 0 indicates that
161 // viewport/scissor count is dynamic state).
162 PipelineLayoutWrapper m_rectanglePipelineLayout;
163 std::vector<GraphicsPipelineWrapper> m_rectanglePipelines;
164
165 // Command pool
166 Move<VkCommandPool> m_cmdPool;
167
168 // Primary command buffer, re-used for every test
169 Move<VkCommandBuffer> m_primaryCmdBuffer;
170
171 // Secondary command buffers, first for specifying
172 // viewport/scissor state, second for subpass contents.
173 // Both re-used to check for stale state.
174 Move<VkCommandBuffer> m_setStateCmdBuffer, m_subpassCmdBuffer;
175
176 // Secondary command buffer for nested command buffer tests
177 Move<VkCommandBuffer> m_nestedCmdBuffer;
178
179 // "depth buffer" used for CPU rasterization of expected image.
180 float m_cpuDepthBuffer[kHeight][kWidth];
181
182 public:
183 InheritanceTestInstance(Context &context, PipelineConstructionType pipelineConstructionType,
184 InheritanceMode inheritanceMode);
185 tcu::TestStatus iterate(void);
186
187 private:
188 void startRenderCmds(const TestGeometry &geometry);
189 void rasterizeExpectedResults(const TestGeometry &geometry, Texel (&output)[kHeight][kWidth]);
190 };
191
192 // Most state for graphics pipeline
193 namespace pipelinestate
194 {
195
196 // Vertex shader, just pass through Rectangle data.
197 const char vert_glsl[] = "#version 460\n"
198 "\n"
199 "layout(location=0) in vec3 xyz;\n"
200 "layout(location=1) in int r8g8b8;\n"
201 "layout(location=2) in vec2 widthHeight;\n"
202 "layout(location=3) in int viewportIndex;\n"
203 "\n"
204 "layout(location=0) flat out int o_r8g8b8;\n"
205 "layout(location=1) flat out vec2 o_widthHeight;\n"
206 "layout(location=2) flat out int o_viewportIndex;\n"
207 "\n"
208 "void main()\n"
209 "{\n"
210 " gl_Position = vec4(xyz, 1.0);\n"
211 " o_r8g8b8 = r8g8b8;\n"
212 " o_widthHeight = widthHeight;\n"
213 " o_viewportIndex = viewportIndex;\n"
214 "}\n";
215
216 // Geometry shader, convert points to rectangles and select correct viewport.
217 const char geom_glsl[] = "#version 460\n"
218 "\n"
219 "layout(points) in;\n"
220 "layout(triangle_strip, max_vertices=4) out;\n"
221 "\n"
222 "layout(location=0) flat in int r8g8b8[];\n"
223 "layout(location=1) flat in vec2 widthHeight[];\n"
224 "layout(location=2) flat in int viewportIndex[];\n"
225 "\n"
226 "layout(location=0) flat out vec4 o_color;\n"
227 "\n"
228 "void main()\n"
229 "{\n"
230 " int redBits = (r8g8b8[0] >> 16) & 255;\n"
231 " int greenBits = (r8g8b8[0] >> 8) & 255;\n"
232 " int blueBits = r8g8b8[0] & 255;\n"
233 " float n = 1.0 / 255.0;\n"
234 " vec4 color = vec4(redBits * n, greenBits * n, blueBits * n, 1.0);\n"
235 "\n"
236 " gl_ViewportIndex = viewportIndex[0];\n"
237 " gl_Position = gl_in[0].gl_Position;\n"
238 " o_color = color;\n"
239 " EmitVertex();\n"
240 "\n"
241 " gl_ViewportIndex = viewportIndex[0];\n"
242 " gl_Position = gl_in[0].gl_Position + vec4(0.0, widthHeight[0].y, 0.0, 0.0);\n"
243 " o_color = color;\n"
244 " EmitVertex();\n"
245 "\n"
246 " gl_ViewportIndex = viewportIndex[0];\n"
247 " gl_Position = gl_in[0].gl_Position + vec4(widthHeight[0].x, 0.0, 0.0, 0.0);\n"
248 " o_color = color;\n"
249 " EmitVertex();\n"
250 "\n"
251 " gl_ViewportIndex = viewportIndex[0];\n"
252 " gl_Position = gl_in[0].gl_Position + vec4(widthHeight[0].xy, 0.0, 0.0);\n"
253 " o_color = color;\n"
254 " EmitVertex();\n"
255 "\n"
256 " EndPrimitive();\n"
257 "}\n";
258
259 // Pass through fragment shader
260 const char frag_glsl[] = "#version 460\n"
261 "layout(location=0) flat in vec4 color;\n"
262 "layout(location=0) out vec4 o_color;\n"
263 "\n"
264 "void main()\n"
265 "{\n"
266 " o_color = color;\n"
267 "}\n";
268
269 static const VkVertexInputBindingDescription binding = {0, sizeof(Rectangle), VK_VERTEX_INPUT_RATE_VERTEX};
270
271 static const VkVertexInputAttributeDescription attributes[4] = {
272 {0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Rectangle, xyz)},
273 {1, 0, VK_FORMAT_R32_SINT, offsetof(Rectangle, r8g8b8)},
274 {2, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(Rectangle, widthHeight)},
275 {3, 0, VK_FORMAT_R32_SINT, offsetof(Rectangle, viewportIndex)}};
276
277 static const VkPipelineVertexInputStateCreateInfo vertexInput = {
278 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, NULL, 0, 1, &binding, 4, attributes};
279
280 static const VkPipelineRasterizationStateCreateInfo rasterization = {
281 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
282 NULL,
283 0,
284 VK_FALSE,
285 VK_FALSE,
286 VK_POLYGON_MODE_FILL,
287 VK_CULL_MODE_BACK_BIT,
288 VK_FRONT_FACE_COUNTER_CLOCKWISE,
289 VK_FALSE,
290 0.0f,
291 0.0f,
292 0.0f,
293 1.0f};
294
295 static const VkPipelineDepthStencilStateCreateInfo depthStencil = {
296 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
297 NULL,
298 0,
299 VK_TRUE,
300 VK_TRUE,
301 VK_COMPARE_OP_LESS,
302 0,
303 0,
304 {},
305 {},
306 0,
307 0};
308
309 static const VkPipelineColorBlendAttachmentState blendAttachment{
310 VK_FALSE,
311 VK_BLEND_FACTOR_ZERO,
312 VK_BLEND_FACTOR_ZERO,
313 VK_BLEND_OP_ADD,
314 VK_BLEND_FACTOR_ZERO,
315 VK_BLEND_FACTOR_ZERO,
316 VK_BLEND_OP_ADD,
317 VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
318
319 static const VkPipelineColorBlendStateCreateInfo blend = {VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
320 NULL,
321 0,
322 VK_FALSE,
323 VK_LOGIC_OP_CLEAR,
324 1,
325 &blendAttachment,
326 {}};
327
328 static const VkDynamicState dynamicStateData[2] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
329 static const VkDynamicState dynamicStateWithCountData[2] = {VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT,
330 VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT};
331
332 static const VkPipelineDynamicStateCreateInfo dynamicState = {VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
333 NULL, 0, 2, dynamicStateData};
334
335 static const VkPipelineDynamicStateCreateInfo dynamicStateWithCount = {
336 VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, NULL, 0, 2, dynamicStateWithCountData};
337
338 } // end namespace pipelinestate
339
340 const VkBufferCreateInfo rectangleBufferInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
341 NULL,
342 0,
343 kMaxRectangles * sizeof(Rectangle),
344 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
345 VK_SHARING_MODE_EXCLUSIVE,
346 0,
347 NULL};
348
349 const VkBufferCreateInfo downloadBufferInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
350 NULL,
351 0,
352 kWidth *kHeight * sizeof(Texel),
353 VK_BUFFER_USAGE_TRANSFER_DST_BIT,
354 VK_SHARING_MODE_EXCLUSIVE,
355 0,
356 NULL};
357
358 const VkImageCreateInfo colorImageInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
359 NULL,
360 0,
361 VK_IMAGE_TYPE_2D,
362 kFormat,
363 {kWidth, kHeight, 1},
364 1,
365 1,
366 VK_SAMPLE_COUNT_1_BIT,
367 VK_IMAGE_TILING_OPTIMAL,
368 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
369 VK_SHARING_MODE_EXCLUSIVE,
370 0,
371 NULL,
372 VK_IMAGE_LAYOUT_UNDEFINED};
373
makeDepthImageInfo(Context & context)374 VkImageCreateInfo makeDepthImageInfo(Context &context)
375 {
376 VkImageCreateInfo info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
377 NULL,
378 0,
379 VK_IMAGE_TYPE_2D,
380 VK_FORMAT_UNDEFINED, // To be filled in.
381 {kWidth, kHeight, 1},
382 1,
383 1,
384 VK_SAMPLE_COUNT_1_BIT,
385 VK_IMAGE_TILING_OPTIMAL,
386 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
387 VK_SHARING_MODE_EXCLUSIVE,
388 0,
389 NULL,
390 VK_IMAGE_LAYOUT_UNDEFINED};
391
392 VkFormat depthFormats[4] = {VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT,
393 VK_FORMAT_D32_SFLOAT_S8_UINT};
394 for (int i = 0; i < 4; ++i)
395 {
396 VkFormatProperties properties;
397 context.getInstanceInterface().getPhysicalDeviceFormatProperties(context.getPhysicalDevice(), depthFormats[i],
398 &properties);
399 if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
400 {
401 info.format = depthFormats[i];
402 return info;
403 }
404 }
405 throw std::runtime_error("Did not find suitable depth attachment format.");
406 }
407
408 // Initialize the Vulkan state for the tests.
InheritanceTestInstance(Context & context,PipelineConstructionType pipelineConstructionType,InheritanceMode inheritanceMode)409 InheritanceTestInstance::InheritanceTestInstance(Context &context, PipelineConstructionType pipelineConstructionType,
410 InheritanceMode inheritanceMode)
411 : TestInstance(context)
412 , m_in(context.getInstanceInterface())
413 , m_vk(context.getDeviceInterface())
414 , m_inheritanceMode(inheritanceMode)
415 , m_pipelineConstructionType(pipelineConstructionType)
416 , m_rectangleBuffer(m_vk, m_context.getDevice(), m_context.getDefaultAllocator(), rectangleBufferInfo,
417 MemoryRequirement::HostVisible | MemoryRequirement::Coherent)
418 , m_downloadBuffer(m_vk, m_context.getDevice(), m_context.getDefaultAllocator(), downloadBufferInfo,
419 MemoryRequirement::HostVisible | MemoryRequirement::Coherent)
420 , m_depthImageInfo(makeDepthImageInfo(context))
421 , m_colorImage(m_vk, m_context.getDevice(), m_context.getDefaultAllocator(), colorImageInfo,
422 MemoryRequirement::Local)
423 , m_depthImage(m_vk, m_context.getDevice(), m_context.getDefaultAllocator(), m_depthImageInfo,
424 MemoryRequirement::Local)
425 , m_colorViewInfo{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
426 NULL,
427 0,
428 m_colorImage.get(),
429 VK_IMAGE_VIEW_TYPE_2D,
430 kFormat,
431 {},
432 {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}
433 , m_depthViewInfo{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
434 NULL,
435 0,
436 m_depthImage.get(),
437 VK_IMAGE_VIEW_TYPE_2D,
438 m_depthImageInfo.format,
439 {},
440 {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1}}
441 , m_colorView(createImageView(m_vk, m_context.getDevice(), &m_colorViewInfo, NULL))
442 , m_depthView(createImageView(m_vk, m_context.getDevice(), &m_depthViewInfo, NULL))
443 {
444 VkDevice dev = m_context.getDevice();
445
446 // Render pass, adapted from Alexander Overvoorde's
447 // vulkan-tutorial.com (CC0 1.0 Universal)
448 VkAttachmentDescription colorAttachment{};
449 colorAttachment.format = kFormat;
450 colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
451 colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
452 colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
453 colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
454 colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
455 colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
456 colorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
457
458 VkAttachmentDescription depthAttachment{};
459 depthAttachment.format = m_depthImageInfo.format;
460 depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
461 depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
462 depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
463 depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
464 depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
465 depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
466 depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
467
468 VkAttachmentReference colorAttachmentRef{};
469 colorAttachmentRef.attachment = 0;
470 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
471
472 VkAttachmentReference depthAttachmentRef{};
473 depthAttachmentRef.attachment = 1;
474 depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
475
476 VkSubpassDescription subpass{};
477 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
478 subpass.colorAttachmentCount = 1;
479 subpass.pColorAttachments = &colorAttachmentRef;
480 subpass.pDepthStencilAttachment = &depthAttachmentRef;
481
482 VkSubpassDependency dependency{};
483 dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
484 dependency.dstSubpass = 0;
485 dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
486 dependency.srcAccessMask = 0;
487 dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
488 dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
489
490 VkAttachmentDescription attachments[2] = {colorAttachment, depthAttachment};
491 VkRenderPassCreateInfo renderPassInfo{};
492 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
493 renderPassInfo.attachmentCount = 2;
494 renderPassInfo.pAttachments = attachments;
495 renderPassInfo.subpassCount = 1;
496 renderPassInfo.pSubpasses = &subpass;
497 renderPassInfo.dependencyCount = 1;
498 renderPassInfo.pDependencies = &dependency;
499
500 m_renderPass = RenderPassWrapper(pipelineConstructionType, m_vk, dev, &renderPassInfo);
501
502 // Set up framebuffer
503 VkImageView attachmentViews[2] = {m_colorView.get(), m_depthView.get()};
504 VkFramebufferCreateInfo framebufferInfo{
505 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, NULL, 0, m_renderPass.get(), 2, attachmentViews, kWidth, kHeight, 1};
506 m_renderPass.createFramebuffer(m_vk, dev, &framebufferInfo, {*m_colorImage, *m_depthImage});
507
508 // Compile graphics pipeline stages.
509 m_vertModule = vk::ShaderWrapper(m_vk, dev, m_context.getBinaryCollection().get("vert"), 0u);
510 m_geomModule = vk::ShaderWrapper(m_vk, dev, m_context.getBinaryCollection().get("geom"), 0u);
511 m_fragModule = vk::ShaderWrapper(m_vk, dev, m_context.getBinaryCollection().get("frag"), 0u);
512
513 // Set up pipeline layout (empty)
514 VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
515 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
516 m_rectanglePipelineLayout = PipelineLayoutWrapper(pipelineConstructionType, m_vk, dev, &pipelineLayoutInfo, NULL);
517
518 // Graphics pipelines are created on-the-fly later.
519 uint32_t size = kMaxViewports + 1;
520 m_rectanglePipelines.reserve(size);
521 for (uint32_t i = 0; i < size; ++i)
522 m_rectanglePipelines.emplace_back(m_context.getInstanceInterface(), m_vk, m_context.getPhysicalDevice(),
523 m_context.getDevice(), m_context.getDeviceExtensions(),
524 pipelineConstructionType);
525
526 // Command pool and command buffers.
527 VkCommandPoolCreateInfo poolInfo{VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, NULL,
528 VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
529 m_context.getUniversalQueueFamilyIndex()};
530 m_cmdPool = createCommandPool(m_vk, dev, &poolInfo, NULL);
531
532 VkCommandBufferAllocateInfo cmdBufferInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, NULL, m_cmdPool.get(),
533 VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1};
534 m_primaryCmdBuffer = allocateCommandBuffer(m_vk, dev, &cmdBufferInfo);
535 cmdBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
536 m_setStateCmdBuffer = allocateCommandBuffer(m_vk, dev, &cmdBufferInfo);
537 m_subpassCmdBuffer = allocateCommandBuffer(m_vk, dev, &cmdBufferInfo);
538 m_nestedCmdBuffer = allocateCommandBuffer(m_vk, dev, &cmdBufferInfo);
539 }
540
u8_from_unorm(float x)541 static uint8_t u8_from_unorm(float x)
542 {
543 return uint8_t(roundf(de::clamp(x, 0.0f, 1.0f) * 255.0f));
544 }
545
546 // Start work (on the univeral queue) for filling m_downloadBuffer with the image
547 // resulting from rendering the test case. Must vkQueueWaitIdle before
548 // accessing the data, or calling this function again.
startRenderCmds(const TestGeometry & geometry)549 void InheritanceTestInstance::startRenderCmds(const TestGeometry &geometry)
550 {
551 DE_ASSERT(geometry.viewports.size() > 0);
552 DE_ASSERT(geometry.viewports.size() <= kMaxViewports);
553 DE_ASSERT(geometry.viewports.size() == geometry.scissors.size());
554
555 // Fill vertex buffer
556 DE_ASSERT(kMaxRectangles >= geometry.rectangles.size());
557 Rectangle *pRectangles = static_cast<Rectangle *>(m_rectangleBuffer.getAllocation().getHostPtr());
558 for (size_t i = 0; i < geometry.rectangles.size(); ++i)
559 {
560 pRectangles[i] = geometry.rectangles[i];
561 }
562
563 VkCommandBufferInheritanceInfo inheritanceInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
564 NULL,
565 m_renderPass.get(),
566 0,
567 m_renderPass.getFramebuffer(),
568 0,
569 0,
570 0};
571
572 VkCommandBufferBeginInfo cmdBeginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL,
573 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inheritanceInfo};
574
575 #ifndef CTS_USES_VULKANSC
576 vk::VkCommandBufferInheritanceRenderingInfo inheritanceRenderingInfo = vk::initVulkanStructure();
577 inheritanceRenderingInfo.flags = (VkRenderingFlags)0u;
578 inheritanceRenderingInfo.viewMask = 0x0;
579 inheritanceRenderingInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
580 std::vector<vk::VkFormat> colorFormats;
581 if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
582 {
583 m_renderPass.fillInheritanceRenderingInfo(0U, &colorFormats, &inheritanceRenderingInfo);
584 inheritanceInfo.pNext = &inheritanceRenderingInfo;
585 }
586 #endif
587
588 // ************************************************************************
589 // Record state-setting secondary command buffer.
590 // ************************************************************************
591 VK_CHECK(m_vk.beginCommandBuffer(m_setStateCmdBuffer.get(), &cmdBeginInfo));
592 switch (m_inheritanceMode)
593 {
594 case kInheritanceDisabled:
595 case kInheritFromPrimary:
596 case kInheritFromPrimaryWithCount:
597 break;
598 case kInheritFromSecondary:
599 case kInheritFromSecondaryNested:
600 // Set all viewport/scissor state.
601 if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
602 {
603 #ifndef CTS_USES_VULKANSC
604 m_vk.cmdSetViewportWithCount(m_setStateCmdBuffer.get(), uint32_t(geometry.viewports.size()),
605 &geometry.viewports[0]);
606 m_vk.cmdSetScissorWithCount(m_setStateCmdBuffer.get(), uint32_t(geometry.scissors.size()),
607 &geometry.scissors[0]);
608 #else
609 m_vk.cmdSetViewportWithCountEXT(m_setStateCmdBuffer.get(), uint32_t(geometry.viewports.size()),
610 &geometry.viewports[0]);
611 m_vk.cmdSetScissorWithCountEXT(m_setStateCmdBuffer.get(), uint32_t(geometry.scissors.size()),
612 &geometry.scissors[0]);
613 #endif
614 }
615 else
616 {
617 m_vk.cmdSetViewport(m_setStateCmdBuffer.get(), 0, uint32_t(geometry.viewports.size()),
618 &geometry.viewports[0]);
619 m_vk.cmdSetScissor(m_setStateCmdBuffer.get(), 0, uint32_t(geometry.scissors.size()), &geometry.scissors[0]);
620 }
621 break;
622 case kSplitInheritance:
623 // Set just the first viewport / scissor, rest are set in
624 // primary command buffer. Checks that extension properly
625 // muxes state from different sources.
626 if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
627 {
628 #ifndef CTS_USES_VULKANSC
629 m_vk.cmdSetViewportWithCount(m_setStateCmdBuffer.get(), 1, &geometry.viewports[0]);
630 m_vk.cmdSetScissorWithCount(m_setStateCmdBuffer.get(), 1, &geometry.scissors[0]);
631 #else
632 m_vk.cmdSetViewportWithCountEXT(m_setStateCmdBuffer.get(), 1, &geometry.viewports[0]);
633 m_vk.cmdSetScissorWithCountEXT(m_setStateCmdBuffer.get(), 1, &geometry.scissors[0]);
634 #endif
635 }
636 else
637 {
638 m_vk.cmdSetViewport(m_setStateCmdBuffer.get(), 0, 1, &geometry.viewports[0]);
639 m_vk.cmdSetScissor(m_setStateCmdBuffer.get(), 0, 1, &geometry.scissors[0]);
640 }
641 break;
642 case kInheritFromSecondaryWithCount:
643 case kInheritFromSecondaryNestedWithCount:
644 #ifndef CTS_USES_VULKANSC
645 m_vk.cmdSetViewportWithCount(m_setStateCmdBuffer.get(), uint32_t(geometry.viewports.size()),
646 &geometry.viewports[0]);
647 m_vk.cmdSetScissorWithCount(m_setStateCmdBuffer.get(), uint32_t(geometry.scissors.size()),
648 &geometry.scissors[0]);
649 #else
650 m_vk.cmdSetViewportWithCountEXT(m_setStateCmdBuffer.get(), uint32_t(geometry.viewports.size()),
651 &geometry.viewports[0]);
652 m_vk.cmdSetScissorWithCountEXT(m_setStateCmdBuffer.get(), uint32_t(geometry.scissors.size()),
653 &geometry.scissors[0]);
654 #endif // CTS_USES_VULKANSC
655 break;
656 }
657 VK_CHECK(m_vk.endCommandBuffer(m_setStateCmdBuffer.get()));
658
659 // ************************************************************************
660 // Record subpass command buffer, bind vertex buffer and pipeline,
661 // then draw rectangles.
662 // ************************************************************************
663 if (m_inheritanceMode != kInheritanceDisabled)
664 {
665 #ifndef CTS_USES_VULKANSC
666 // Enable viewport/scissor inheritance struct.
667 VkCommandBufferInheritanceViewportScissorInfoNV inheritViewportInfo{
668 VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV, inheritanceInfo.pNext, VK_TRUE,
669 uint32_t(geometry.viewports.size()), &geometry.viewports[0]};
670 inheritanceInfo.pNext = &inheritViewportInfo;
671 VK_CHECK(m_vk.beginCommandBuffer(m_subpassCmdBuffer.get(), &cmdBeginInfo));
672 inheritanceInfo.pNext = inheritViewportInfo.pNext;
673 #endif // CTS_USES_VULKANSC
674 }
675 else
676 {
677 VK_CHECK(m_vk.beginCommandBuffer(m_subpassCmdBuffer.get(), &cmdBeginInfo));
678 }
679 // Set viewport/scissor state only when not inherited.
680 if (m_inheritanceMode == kInheritanceDisabled)
681 {
682 if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
683 {
684 #ifndef CTS_USES_VULKANSC
685 m_vk.cmdSetViewportWithCount(m_subpassCmdBuffer.get(), uint32_t(geometry.viewports.size()),
686 &geometry.viewports[0]);
687 m_vk.cmdSetScissorWithCount(m_subpassCmdBuffer.get(), uint32_t(geometry.scissors.size()),
688 &geometry.scissors[0]);
689 #else
690 m_vk.cmdSetViewportWithCountEXT(m_subpassCmdBuffer.get(), uint32_t(geometry.viewports.size()),
691 &geometry.viewports[0]);
692 m_vk.cmdSetScissorWithCountEXT(m_subpassCmdBuffer.get(), uint32_t(geometry.scissors.size()),
693 &geometry.scissors[0]);
694 #endif
695 }
696 else
697 {
698 m_vk.cmdSetViewport(m_subpassCmdBuffer.get(), 0, uint32_t(geometry.viewports.size()),
699 &geometry.viewports[0]);
700 m_vk.cmdSetScissor(m_subpassCmdBuffer.get(), 0, uint32_t(geometry.scissors.size()), &geometry.scissors[0]);
701 }
702 }
703 // Get the graphics pipeline, creating it if needed (encountered
704 // new static viewport/scissor count). 0 = dynamic count.
705 uint32_t staticViewportCount = 0;
706 switch (m_inheritanceMode)
707 {
708 case kInheritanceDisabled:
709 case kInheritFromPrimary:
710 case kInheritFromSecondary:
711 case kInheritFromSecondaryNested:
712 case kSplitInheritance:
713 staticViewportCount = uint32_t(geometry.viewports.size());
714 break;
715 case kInheritFromPrimaryWithCount:
716 case kInheritFromSecondaryWithCount:
717 case kInheritFromSecondaryNestedWithCount:
718 staticViewportCount = 0;
719 break;
720 }
721 DE_ASSERT(staticViewportCount < m_rectanglePipelines.size());
722 if (!m_rectanglePipelines[staticViewportCount].wasPipelineOrShaderObjectBuild())
723 {
724 const std::vector<VkViewport> viewports;
725 const std::vector<VkRect2D> scissors;
726
727 m_rectanglePipelines[staticViewportCount]
728 .setDynamicState((staticViewportCount == 0) ? &pipelinestate::dynamicStateWithCount :
729 &pipelinestate::dynamicState)
730 .setDefaultTopology(VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
731 .setDefaultViewportsCount(staticViewportCount)
732 .setDefaultScissorsCount(staticViewportCount)
733 .setDefaultMultisampleState()
734 .setDefaultColorBlendState()
735 .setupVertexInputState(&pipelinestate::vertexInput)
736 .setupPreRasterizationShaderState(viewports, scissors, m_rectanglePipelineLayout, *m_renderPass, 0u,
737 m_vertModule, &pipelinestate::rasterization, vk::ShaderWrapper(),
738 vk::ShaderWrapper(), m_geomModule)
739 .setupFragmentShaderState(m_rectanglePipelineLayout, *m_renderPass, 0u, m_fragModule,
740 &pipelinestate::depthStencil)
741 .setupFragmentOutputState(*m_renderPass, 0u, &pipelinestate::blend)
742 .setMonolithicPipelineLayout(m_rectanglePipelineLayout)
743 .buildPipeline();
744 }
745 m_rectanglePipelines[staticViewportCount].bind(m_subpassCmdBuffer.get());
746
747 // Bind vertex buffer and draw.
748 VkDeviceSize offset = 0;
749 VkBuffer vertexBuffer = m_rectangleBuffer.get();
750 m_vk.cmdBindVertexBuffers(m_subpassCmdBuffer.get(), 0, 1, &vertexBuffer, &offset);
751 m_vk.cmdDraw(m_subpassCmdBuffer.get(), uint32_t(geometry.rectangles.size()), 1, 0, 0);
752 VK_CHECK(m_vk.endCommandBuffer(m_subpassCmdBuffer.get()));
753
754 VkCommandBuffer secondaryCmdBuffers[2] = {m_setStateCmdBuffer.get(), m_subpassCmdBuffer.get()};
755
756 if (m_inheritanceMode == kInheritFromSecondaryNested || m_inheritanceMode == kInheritFromSecondaryNestedWithCount)
757 {
758 VK_CHECK(m_vk.beginCommandBuffer(m_nestedCmdBuffer.get(), &cmdBeginInfo));
759 m_vk.cmdExecuteCommands(m_nestedCmdBuffer.get(), 2, secondaryCmdBuffers);
760 VK_CHECK(m_vk.endCommandBuffer(m_nestedCmdBuffer.get()));
761 }
762
763 // ************************************************************************
764 // Primary command buffer commands, start render pass and execute
765 // the secondary command buffers, then copy rendered image to
766 // download buffer.
767 // ************************************************************************
768 VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, 0, NULL};
769 VK_CHECK(m_vk.beginCommandBuffer(m_primaryCmdBuffer.get(), &beginInfo));
770
771 VkClearValue clearValues[2];
772 clearValues[0].color.float32[0] = geometry.clearColor.x();
773 clearValues[0].color.float32[1] = geometry.clearColor.y();
774 clearValues[0].color.float32[2] = geometry.clearColor.z();
775 clearValues[0].color.float32[3] = 1.0f;
776 clearValues[1].depthStencil = {geometry.clearDepth, 0};
777
778 VkRenderPassBeginInfo renderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
779 NULL,
780 m_renderPass.get(),
781 m_renderPass.getFramebuffer(),
782 {{0, 0}, {kWidth, kHeight}},
783 2,
784 clearValues};
785
786 switch (m_inheritanceMode)
787 {
788 case kInheritFromPrimary:
789 // Specify all viewport/scissor state only when we expect to.
790 // inherit ALL viewport/scissor state from primary command buffer.
791 if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
792 {
793 #ifndef CTS_USES_VULKANSC
794 m_vk.cmdSetViewportWithCount(m_primaryCmdBuffer.get(), uint32_t(geometry.viewports.size()),
795 &geometry.viewports[0]);
796 m_vk.cmdSetScissorWithCount(m_primaryCmdBuffer.get(), uint32_t(geometry.scissors.size()),
797 &geometry.scissors[0]);
798 #else
799 m_vk.cmdSetViewportWithCountEXT(m_primaryCmdBuffer.get(), uint32_t(geometry.viewports.size()),
800 &geometry.viewports[0]);
801 m_vk.cmdSetScissorWithCountEXT(m_primaryCmdBuffer.get(), uint32_t(geometry.scissors.size()),
802 &geometry.scissors[0]);
803 #endif
804 }
805 else
806 {
807 m_vk.cmdSetViewport(m_primaryCmdBuffer.get(), 0, uint32_t(geometry.viewports.size()),
808 &geometry.viewports[0]);
809 m_vk.cmdSetScissor(m_primaryCmdBuffer.get(), 0, uint32_t(geometry.scissors.size()), &geometry.scissors[0]);
810 }
811 break;
812 case kInheritFromPrimaryWithCount:
813 // Same but with count inherited.
814 #ifndef CTS_USES_VULKANSC
815 m_vk.cmdSetViewportWithCount(m_primaryCmdBuffer.get(), uint32_t(geometry.viewports.size()),
816 &geometry.viewports[0]);
817 m_vk.cmdSetScissorWithCount(m_primaryCmdBuffer.get(), uint32_t(geometry.scissors.size()),
818 &geometry.scissors[0]);
819 #else
820 m_vk.cmdSetViewportWithCountEXT(m_primaryCmdBuffer.get(), uint32_t(geometry.viewports.size()),
821 &geometry.viewports[0]);
822 m_vk.cmdSetScissorWithCountEXT(m_primaryCmdBuffer.get(), uint32_t(geometry.scissors.size()),
823 &geometry.scissors[0]);
824 #endif // CTS_USES_VULKANSC
825 break;
826 case kSplitInheritance:
827 // Specify the remaining viewport, scissors not set by the
828 // setStateCmdBuffer in this test mode.
829 if (geometry.viewports.size() > 1)
830 {
831 if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
832 {
833 #ifndef CTS_USES_VULKANSC
834 m_vk.cmdSetViewportWithCount(m_primaryCmdBuffer.get(), uint32_t(geometry.viewports.size()),
835 &geometry.viewports[0]);
836 m_vk.cmdSetScissorWithCount(m_primaryCmdBuffer.get(), uint32_t(geometry.scissors.size()),
837 &geometry.scissors[0]);
838 #else
839 m_vk.cmdSetViewportWithCountEXT(m_primaryCmdBuffer.get(), uint32_t(geometry.viewports.size()),
840 &geometry.viewports[0]);
841 m_vk.cmdSetScissorWithCountEXT(m_primaryCmdBuffer.get(), uint32_t(geometry.scissors.size()),
842 &geometry.scissors[0]);
843 #endif
844 }
845
846 m_vk.cmdSetViewport(m_primaryCmdBuffer.get(), 1, uint32_t(geometry.viewports.size() - 1),
847 &geometry.viewports[1]);
848 m_vk.cmdSetScissor(m_primaryCmdBuffer.get(), 1, uint32_t(geometry.scissors.size() - 1),
849 &geometry.scissors[1]);
850 }
851 /* FALLTHROUGH */
852 case kInheritanceDisabled:
853 case kInheritFromSecondary:
854 case kInheritFromSecondaryWithCount:
855 case kInheritFromSecondaryNested:
856 case kInheritFromSecondaryNestedWithCount:
857 // Specify some bogus state, ensure correctly overwritten later.
858 VkViewport bogusViewport{0.f, 0.f, 8.f, 8.f, 0.f, 0.1f};
859 VkRect2D bogusScissors{{2, 0}, {100, 100}};
860 if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
861 {
862 #ifndef CTS_USES_VULKANSC
863 m_vk.cmdSetViewportWithCount(m_primaryCmdBuffer.get(), 1, &bogusViewport);
864 m_vk.cmdSetScissorWithCount(m_primaryCmdBuffer.get(), 1, &bogusScissors);
865 #else
866 m_vk.cmdSetViewportWithCountEXT(m_primaryCmdBuffer.get(), 1, &bogusViewport);
867 m_vk.cmdSetScissorWithCountEXT(m_primaryCmdBuffer.get(), 1, &bogusScissors);
868 #endif
869 }
870 else
871 {
872 m_vk.cmdSetViewport(m_primaryCmdBuffer.get(), 0, 1, &bogusViewport);
873 m_vk.cmdSetScissor(m_primaryCmdBuffer.get(), 0, 1, &bogusScissors);
874 }
875 break;
876 }
877
878 m_renderPass.begin(m_vk, m_primaryCmdBuffer.get(), renderPassBeginInfo.renderArea,
879 renderPassBeginInfo.clearValueCount, renderPassBeginInfo.pClearValues,
880 VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
881
882 switch (m_inheritanceMode)
883 {
884 case kInheritanceDisabled:
885 case kInheritFromPrimary:
886 case kInheritFromSecondary:
887 case kSplitInheritance:
888 case kInheritFromPrimaryWithCount:
889 case kInheritFromSecondaryWithCount:
890 m_vk.cmdExecuteCommands(m_primaryCmdBuffer.get(), 2, secondaryCmdBuffers);
891 break;
892 case kInheritFromSecondaryNested:
893 case kInheritFromSecondaryNestedWithCount:
894 m_vk.cmdExecuteCommands(m_primaryCmdBuffer.get(), 1, &m_nestedCmdBuffer.get());
895 break;
896 }
897
898 m_renderPass.end(m_vk, m_primaryCmdBuffer.get());
899
900 // Barrier, then copy rendered image to download buffer.
901 VkImageMemoryBarrier imageBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
902 NULL,
903 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
904 VK_ACCESS_TRANSFER_READ_BIT,
905 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
906 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
907 0,
908 0,
909 m_colorImage.get(),
910 {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};
911 m_vk.cmdPipelineBarrier(m_primaryCmdBuffer.get(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
912 VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &imageBarrier);
913 VkBufferImageCopy bufferImageCopy{0, 0, 0, {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, {0, 0, 0}, {kWidth, kHeight, 1}};
914 m_vk.cmdCopyImageToBuffer(m_primaryCmdBuffer.get(), m_colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
915 m_downloadBuffer.get(), 1, &bufferImageCopy);
916
917 // Barrier, make buffer visible to host.
918 VkBufferMemoryBarrier bufferBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
919 NULL,
920 VK_ACCESS_TRANSFER_WRITE_BIT,
921 VK_ACCESS_HOST_READ_BIT,
922 0,
923 0,
924 m_downloadBuffer.get(),
925 0,
926 VK_WHOLE_SIZE};
927 m_vk.cmdPipelineBarrier(m_primaryCmdBuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, 0,
928 NULL, 1, &bufferBarrier, 0, NULL);
929
930 // End and submit primary command buffer.
931 VK_CHECK(m_vk.endCommandBuffer(m_primaryCmdBuffer.get()));
932 VkCommandBuffer primaryCmd = m_primaryCmdBuffer.get();
933 VkSubmitInfo submitInfo{VK_STRUCTURE_TYPE_SUBMIT_INFO, NULL, 0, NULL, NULL, 1, &primaryCmd, 0, NULL};
934 m_vk.queueSubmit(m_context.getUniversalQueue(), 1, &submitInfo, 0);
935 }
936
rasterizeExpectedResults(const TestGeometry & geometry,Texel (& output)[kHeight][kWidth])937 void InheritanceTestInstance::rasterizeExpectedResults(const TestGeometry &geometry, Texel (&output)[kHeight][kWidth])
938 {
939 // Clear color and depth buffers.
940 Texel clearColorTexel{u8_from_unorm(geometry.clearColor.z()), u8_from_unorm(geometry.clearColor.y()),
941 u8_from_unorm(geometry.clearColor.x()), 0u};
942 for (size_t y = 0; y < kHeight; ++y)
943 {
944 for (size_t x = 0; x < kWidth; ++x)
945 {
946 m_cpuDepthBuffer[y][x] = geometry.clearDepth;
947 output[y][x] = clearColorTexel;
948 }
949 }
950
951 // Rasterize each rectangle. Pixels have half-integer centers.
952 for (size_t i = 0; i < geometry.rectangles.size(); ++i)
953 {
954 Rectangle r = geometry.rectangles[i];
955
956 // Select correct viewport and scissor.
957 VkViewport viewport = geometry.viewports.at(r.viewportIndex);
958 VkRect2D scissor = geometry.scissors.at(r.viewportIndex);
959
960 // Transform xyz and width/height with selected viewport.
961 float ox = viewport.x + viewport.width * 0.5f;
962 float oy = viewport.y + viewport.height * 0.5f;
963 float oz = viewport.minDepth;
964
965 float px = viewport.width;
966 float py = viewport.height;
967 float pz = viewport.maxDepth - viewport.minDepth;
968
969 float xLow = de::clamp(r.xyz.x(), -1.0f, 1.0f);
970 float xHigh = de::clamp(r.xyz.x() + r.widthHeight.x(), -1.0f, 1.0f);
971 float yLow = de::clamp(r.xyz.y(), -1.0f, 1.0f);
972 float yHigh = de::clamp(r.xyz.y() + r.widthHeight.y(), -1.0f, 1.0f);
973
974 float xf[2];
975 xf[0] = px * 0.5f * xLow + ox;
976 xf[1] = px * 0.5f * xHigh + ox;
977 float yf[2];
978 yf[0] = py * 0.5f * yLow + oy;
979 yf[1] = py * 0.5f * yHigh + oy;
980 float zf = pz * r.xyz.z() + oz;
981
982 int32_t xBegin = int32_t(floorf(xf[0] + 0.5f));
983 int32_t xEnd = int32_t(floorf(xf[1] + 0.5f));
984 int32_t yBegin = int32_t(floorf(yf[0] + 0.5f));
985 int32_t yEnd = int32_t(floorf(yf[1] + 0.5f));
986
987 // Scissor test, only correct when drawn rectangle has
988 // positive width/height.
989 int32_t xsLow = scissor.offset.x;
990 int32_t xsHigh = xsLow + int32_t(scissor.extent.width);
991 xBegin = de::clamp(xBegin, xsLow, xsHigh);
992 xEnd = de::clamp(xEnd, xsLow, xsHigh);
993 int32_t ysLow = scissor.offset.y;
994 int32_t ysHigh = ysLow + int32_t(scissor.extent.height);
995 yBegin = de::clamp(yBegin, ysLow, ysHigh);
996 yEnd = de::clamp(yEnd, ysLow, ysHigh);
997
998 // Clamp to framebuffer size
999 xBegin = de::clamp(xBegin, 0, kWidth);
1000 xEnd = de::clamp(xEnd, 0, kWidth);
1001 yBegin = de::clamp(yBegin, 0, kHeight);
1002 yEnd = de::clamp(yEnd, 0, kHeight);
1003
1004 // Rasterize.
1005 Texel rectTexel = texelFrom_r8g8b8(r.r8g8b8);
1006 for (int32_t x = xBegin; x < xEnd; ++x)
1007 {
1008 for (int32_t y = yBegin; y < yEnd; ++y)
1009 {
1010 // Depth test
1011 float oldDepth = m_cpuDepthBuffer[y][x];
1012 if (!(zf < oldDepth))
1013 continue;
1014
1015 output[y][x] = rectTexel;
1016 m_cpuDepthBuffer[y][x] = zf;
1017 }
1018 }
1019 }
1020 }
1021
makeGeometry()1022 std::vector<TestGeometry> makeGeometry()
1023 {
1024 std::vector<TestGeometry> cases;
1025
1026 TestGeometry geometry;
1027 geometry.clearColor = Vec3(1.0f, 1.0f, 1.0f);
1028 geometry.clearDepth = 1.0f;
1029
1030 // Simple test case, three squares, the last one should go in
1031 // between the first two in depth due to viewport 1 halving the
1032 // actual depth value.
1033 geometry.rectangles.push_back(Rectangle{Vec3(-0.5f, -1.0f, 0.2f), 0xFF0000, Vec2(0.5f, 1.0f), 0});
1034 geometry.rectangles.push_back(Rectangle{Vec3(0.0f, 0.0f, 0.6f), 0x0000FF, Vec2(0.5f, 1.0f), 0});
1035 geometry.rectangles.push_back(Rectangle{Vec3(-0.25f, -0.5f, 0.8f), // becomes 0.4f depth
1036 0x008000, Vec2(0.5f, 1.0f), 1});
1037 geometry.viewports.push_back({0, 0, kWidth, kHeight, 0.0f, 1.0f});
1038 geometry.viewports.push_back({0, 0, kWidth, kHeight, 0.0f, 0.5f});
1039 geometry.scissors.push_back({{0, 0}, {kWidth, kHeight}});
1040 geometry.scissors.push_back({{0, 0}, {kWidth, kHeight}});
1041
1042 cases.push_back(geometry);
1043
1044 // Apply scissor rectangle to red and blue squares.
1045 geometry.scissors[0].extent.width = kWidth / 2 + 1;
1046 cases.push_back(geometry);
1047
1048 // Squash down and offset green rectangle's viewport.
1049 geometry.viewports[1].y = kHeight * 0.25f;
1050 geometry.viewports[1].height = kHeight * 0.75f;
1051 cases.push_back(geometry);
1052
1053 // Add another viewport and scissor.
1054 geometry.viewports.push_back({kWidth / 2 - 4, 0, kWidth / 2, kHeight - 8, 0.5f, 1.0f});
1055 geometry.scissors.push_back({{kWidth / 2 - 2, 10}, {kWidth / 2, kHeight}});
1056 geometry.rectangles.push_back(Rectangle{Vec3(-1.0f, -1.0f, 0.5f), // Becomes 0.75f depth
1057 0x000000, Vec2(1.75f, 1.75f), 2});
1058 cases.push_back(geometry);
1059
1060 // Add a few more rectangles.
1061 geometry.rectangles.push_back(Rectangle{Vec3(-0.25f, -0.25f, 0.1f), 0xFF00FF, Vec2(0.375f, 0.375f), 0});
1062 geometry.rectangles.push_back(Rectangle{Vec3(-1.0f, -1.0f, 0.8f), // Becomes 0.9f depth
1063 0x00FFFF, Vec2(2.0f, 2.0f), 2});
1064 geometry.rectangles.push_back(Rectangle{Vec3(-1.0f, -1.0f, 0.7f), 0x808000, Vec2(2.0f, 2.0f), 0});
1065 cases.push_back(geometry);
1066
1067 // Change clear depth and color.
1068 geometry.clearDepth = 0.85f;
1069 geometry.clearColor = Vec3(1.0f, 1.0f, 0.0f);
1070 cases.push_back(geometry);
1071
1072 // Alter viewport/scissor 2.
1073 geometry.viewports[2] = VkViewport{0, 0, kWidth, kHeight, 0.51f, 0.53f};
1074 geometry.scissors[2] = VkRect2D{{20, 0}, {kWidth, kHeight}};
1075 cases.push_back(geometry);
1076
1077 // Change clear depth and color again.
1078 geometry.clearDepth = 0.5f;
1079 geometry.clearColor = Vec3(0.0f, 1.0f, 0.0f);
1080 cases.push_back(geometry);
1081
1082 return cases;
1083 }
1084
iterate(void)1085 tcu::TestStatus InheritanceTestInstance::iterate(void)
1086 {
1087 std::vector<TestGeometry> testGeometries = makeGeometry();
1088 uint32_t failBits = 0;
1089 DE_ASSERT(testGeometries.size() < 32);
1090
1091 for (size_t i = 0; i != testGeometries.size(); ++i)
1092 {
1093 const TestGeometry &geometry = testGeometries[i];
1094 TestResults results;
1095
1096 // Start drawing commands.
1097 startRenderCmds(geometry);
1098
1099 // Work on CPU-side expected results while waiting for device.
1100 rasterizeExpectedResults(geometry, results.expectedResult);
1101
1102 // Wait for commands to finish and copy back results.
1103 m_vk.queueWaitIdle(m_context.getUniversalQueue());
1104 memcpy(results.deviceResult, m_downloadBuffer.getAllocation().getHostPtr(), kWidth * kHeight * sizeof(Texel));
1105
1106 // Compare results. The test cases should be simple enough not to
1107 // require fuzzy matching (power of 2 framebuffer, no nearby depth
1108 // values, etc.)
1109 bool passed = true;
1110 for (size_t y = 0; y < kHeight; ++y)
1111 {
1112 for (size_t x = 0; x < kWidth; ++x)
1113 {
1114 passed &= results.expectedResult[y][x].red == results.deviceResult[y][x].red;
1115 passed &= results.expectedResult[y][x].green == results.deviceResult[y][x].green;
1116 passed &= results.expectedResult[y][x].blue == results.deviceResult[y][x].blue;
1117 }
1118 }
1119 results.passed = passed; // Log results?
1120
1121 failBits |= uint32_t(!passed) << i;
1122 }
1123
1124 if (failBits != 0)
1125 {
1126 std::stringstream stream;
1127 stream << "Failed for test geometry";
1128 for (int i = 0; i < 32; ++i)
1129 {
1130 if (1 & (failBits >> i))
1131 {
1132 stream << ' ' << i;
1133 }
1134 }
1135 return tcu::TestStatus::fail(stream.str());
1136 }
1137 else
1138 {
1139 return tcu::TestStatus::pass("pass");
1140 }
1141 }
1142
1143 class InheritanceTestCase : public TestCase
1144 {
1145 public:
InheritanceTestCase(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType,InheritanceMode inheritanceMode,const char * name)1146 InheritanceTestCase(tcu::TestContext &testCtx, vk::PipelineConstructionType pipelineConstructionType,
1147 InheritanceMode inheritanceMode, const char *name)
1148 : TestCase(testCtx, name)
1149 , m_pipelineConstructionType(pipelineConstructionType)
1150 , m_inheritanceMode(inheritanceMode)
1151 {
1152 }
1153
createInstance(Context & context) const1154 TestInstance *createInstance(Context &context) const
1155 {
1156 return new InheritanceTestInstance(context, m_pipelineConstructionType, m_inheritanceMode);
1157 }
1158
checkSupport(Context & context) const1159 virtual void checkSupport(Context &context) const
1160 {
1161 context.requireDeviceFunctionality("VK_NV_inherited_viewport_scissor");
1162 if (m_inheritanceMode == kInheritFromPrimaryWithCount || m_inheritanceMode == kInheritFromSecondaryWithCount)
1163 {
1164 context.requireDeviceFunctionality("VK_EXT_extended_dynamic_state");
1165 }
1166 if (m_inheritanceMode == kInheritFromSecondaryNested ||
1167 m_inheritanceMode == kInheritFromSecondaryNestedWithCount)
1168 {
1169 context.requireDeviceFunctionality("VK_EXT_nested_command_buffer");
1170 #ifndef CTS_USES_VULKANSC
1171 const auto &features =
1172 *findStructure<VkPhysicalDeviceNestedCommandBufferFeaturesEXT>(&context.getDeviceFeatures2());
1173 if (!features.nestedCommandBuffer)
1174 #endif // CTS_USES_VULKANSC
1175 TCU_THROW(NotSupportedError, "nestedCommandBuffer is not supported");
1176 #ifndef CTS_USES_VULKANSC
1177 if (!features.nestedCommandBufferRendering)
1178 #endif // CTS_USES_VULKANSC
1179 TCU_THROW(NotSupportedError, "nestedCommandBufferRendering is not supported");
1180 }
1181 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1182 m_pipelineConstructionType);
1183 }
1184
initPrograms(vk::SourceCollections & programCollection) const1185 virtual void initPrograms(vk::SourceCollections &programCollection) const
1186 {
1187 programCollection.glslSources.add("vert") << glu::VertexSource(pipelinestate::vert_glsl);
1188 programCollection.glslSources.add("geom") << glu::GeometrySource(pipelinestate::geom_glsl);
1189 programCollection.glslSources.add("frag") << glu::FragmentSource(pipelinestate::frag_glsl);
1190 }
1191
1192 private:
1193 vk::PipelineConstructionType m_pipelineConstructionType;
1194 InheritanceMode m_inheritanceMode;
1195 };
1196
1197 } // anonymous namespace
1198
1199 // Tests for inherited viewport/scissor state
DynamicStateInheritanceTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)1200 DynamicStateInheritanceTests::DynamicStateInheritanceTests(tcu::TestContext &testCtx,
1201 vk::PipelineConstructionType pipelineConstructionType)
1202 : TestCaseGroup(testCtx, "inheritance")
1203 , m_pipelineConstructionType(pipelineConstructionType)
1204 {
1205 }
1206
init(void)1207 void DynamicStateInheritanceTests::init(void)
1208 {
1209 // Baseline, no viewport/scissor inheritance
1210 addChild(new InheritanceTestCase(m_testCtx, m_pipelineConstructionType, kInheritanceDisabled, "baseline"));
1211 #ifndef CTS_USES_VULKANSC
1212 // Inherit viewport/scissor from calling primary command buffer
1213 addChild(new InheritanceTestCase(m_testCtx, m_pipelineConstructionType, kInheritFromPrimary, "primary"));
1214 // Inherit viewport/scissor from another secondary command buffer
1215 addChild(new InheritanceTestCase(m_testCtx, m_pipelineConstructionType, kInheritFromSecondary, "secondary"));
1216 // Inherit viewport/scissor from another secondary command buffer
1217 addChild(new InheritanceTestCase(m_testCtx, m_pipelineConstructionType, kInheritFromSecondaryNested, "nested"));
1218 // Inherit some viewports/scissors from primary, some from secondary
1219 addChild(new InheritanceTestCase(m_testCtx, m_pipelineConstructionType, kSplitInheritance, "split"));
1220 // Inherit viewport/scissor with count from calling primary command buffer
1221 addChild(new InheritanceTestCase(m_testCtx, m_pipelineConstructionType, kInheritFromPrimaryWithCount,
1222 "primary_with_count"));
1223 // Inherit viewport/scissor with count from another secondary command buffer
1224 addChild(new InheritanceTestCase(m_testCtx, m_pipelineConstructionType, kInheritFromSecondaryWithCount,
1225 "secondary_with_count"));
1226 // Inherit viewport/scissor with count from another secondary command buffer within a secondary buffer
1227 addChild(new InheritanceTestCase(m_testCtx, m_pipelineConstructionType, kInheritFromSecondaryNestedWithCount,
1228 "nested_with_count"));
1229 #endif // CTS_USES_VULKANSC
1230 }
1231
1232 } // namespace DynamicState
1233 } // namespace vkt
1234