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