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