1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2018 The Khronos Group Inc.
6 * Copyright (c) 2018 The Android Open Source Project
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Use of gl_ViewportIndex in Vertex and Tessellation Shaders
23 * (part of VK_EXT_ShaderViewportIndexLayer)
24 *//*--------------------------------------------------------------------*/
25
26 #include "vktDrawShaderViewportIndexTests.hpp"
27
28 #include "vktDrawBaseClass.hpp"
29 #include "vktTestCaseUtil.hpp"
30
31 #include "vkDefs.hpp"
32 #include "vkRef.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkPrograms.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkObjUtil.hpp"
41
42 #include "tcuTestLog.hpp"
43 #include "tcuVector.hpp"
44 #include "tcuImageCompare.hpp"
45 #include "tcuTextureUtil.hpp"
46
47 #include "deUniquePtr.hpp"
48 #include "deMath.h"
49
50 #include <vector>
51
52 namespace vkt
53 {
54 namespace Draw
55 {
56 using namespace vk;
57 using de::UniquePtr;
58 using de::MovePtr;
59 using de::SharedPtr;
60 using tcu::Vec4;
61 using tcu::Vec2;
62 using tcu::UVec2;
63 using tcu::UVec4;
64
65 namespace
66 {
67
68 enum Constants
69 {
70 MIN_MAX_VIEWPORTS = 16, //!< Minimum number of viewports for an implementation supporting multiViewport.
71 };
72
73 template<typename T>
sizeInBytes(const std::vector<T> & vec)74 inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
75 {
76 return vec.size() * sizeof(vec[0]);
77 }
78
makeBufferCreateInfo(const VkDeviceSize bufferSize,const VkBufferUsageFlags usage)79 VkBufferCreateInfo makeBufferCreateInfo (const VkDeviceSize bufferSize,
80 const VkBufferUsageFlags usage)
81 {
82 const VkBufferCreateInfo bufferCreateInfo =
83 {
84 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
85 DE_NULL, // const void* pNext;
86 (VkBufferCreateFlags)0, // VkBufferCreateFlags flags;
87 bufferSize, // VkDeviceSize size;
88 usage, // VkBufferUsageFlags usage;
89 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
90 0u, // deUint32 queueFamilyIndexCount;
91 DE_NULL, // const deUint32* pQueueFamilyIndices;
92 };
93 return bufferCreateInfo;
94 }
95
makePipelineLayout(const DeviceInterface & vk,const VkDevice device)96 Move<VkPipelineLayout> makePipelineLayout (const DeviceInterface& vk,
97 const VkDevice device)
98 {
99 const VkPipelineLayoutCreateInfo info =
100 {
101 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
102 DE_NULL, // const void* pNext;
103 (VkPipelineLayoutCreateFlags)0, // VkPipelineLayoutCreateFlags flags;
104 0u, // deUint32 setLayoutCount;
105 DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
106 0u, // deUint32 pushConstantRangeCount;
107 DE_NULL, // const VkPushConstantRange* pPushConstantRanges;
108 };
109 return createPipelineLayout(vk, device, &info);
110 }
111
makeImageView(const DeviceInterface & vk,const VkDevice vkDevice,const VkImage image,const VkImageViewType viewType,const VkFormat format,const VkImageSubresourceRange subresourceRange)112 Move<VkImageView> makeImageView (const DeviceInterface& vk,
113 const VkDevice vkDevice,
114 const VkImage image,
115 const VkImageViewType viewType,
116 const VkFormat format,
117 const VkImageSubresourceRange subresourceRange)
118 {
119 const VkImageViewCreateInfo imageViewParams =
120 {
121 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
122 DE_NULL, // const void* pNext;
123 (VkImageViewCreateFlags)0, // VkImageViewCreateFlags flags;
124 image, // VkImage image;
125 viewType, // VkImageViewType viewType;
126 format, // VkFormat format;
127 makeComponentMappingRGBA(), // VkComponentMapping components;
128 subresourceRange, // VkImageSubresourceRange subresourceRange;
129 };
130 return createImageView(vk, vkDevice, &imageViewParams);
131 }
132
makeFramebuffer(const DeviceInterface & vk,const VkDevice device,const VkRenderPass renderPass,const deUint32 attachmentCount,const VkImageView * pAttachments,const deUint32 width,const deUint32 height,const deUint32 layers=1u)133 Move<VkFramebuffer> makeFramebuffer (const DeviceInterface& vk,
134 const VkDevice device,
135 const VkRenderPass renderPass,
136 const deUint32 attachmentCount,
137 const VkImageView* pAttachments,
138 const deUint32 width,
139 const deUint32 height,
140 const deUint32 layers = 1u)
141 {
142 const VkFramebufferCreateInfo framebufferInfo = {
143 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
144 DE_NULL, // const void* pNext;
145 (VkFramebufferCreateFlags)0, // VkFramebufferCreateFlags flags;
146 renderPass, // VkRenderPass renderPass;
147 attachmentCount, // uint32_t attachmentCount;
148 pAttachments, // const VkImageView* pAttachments;
149 width, // uint32_t width;
150 height, // uint32_t height;
151 layers, // uint32_t layers;
152 };
153
154 return createFramebuffer(vk, device, &framebufferInfo);
155 }
156
bindImage(const DeviceInterface & vk,const VkDevice device,Allocator & allocator,const VkImage image,const MemoryRequirement requirement)157 MovePtr<Allocation> bindImage (const DeviceInterface& vk, const VkDevice device, Allocator& allocator, const VkImage image, const MemoryRequirement requirement)
158 {
159 MovePtr<Allocation> alloc = allocator.allocate(getImageMemoryRequirements(vk, device, image), requirement);
160 VK_CHECK(vk.bindImageMemory(device, image, alloc->getMemory(), alloc->getOffset()));
161 return alloc;
162 }
163
makeImage(const vk::DeviceInterface & vk,const vk::VkDevice device,const vk::VkImageCreateInfo & createInfo)164 inline vk::Move<vk::VkImage> makeImage (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkImageCreateInfo& createInfo)
165 {
166 return createImage(vk, device, &createInfo);
167 }
168
makeImageCreateInfo(const VkFormat format,const UVec2 & size,VkImageUsageFlags usage)169 VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const UVec2& size, VkImageUsageFlags usage)
170 {
171 const VkImageCreateInfo imageParams =
172 {
173 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
174 DE_NULL, // const void* pNext;
175 (VkImageCreateFlags)0, // VkImageCreateFlags flags;
176 VK_IMAGE_TYPE_2D, // VkImageType imageType;
177 format, // VkFormat format;
178 makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
179 1u, // deUint32 mipLevels;
180 1u, // deUint32 arrayLayers;
181 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
182 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
183 usage, // VkImageUsageFlags usage;
184 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
185 0u, // deUint32 queueFamilyIndexCount;
186 DE_NULL, // const deUint32* pQueueFamilyIndices;
187 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
188 };
189 return imageParams;
190 }
191
makeGraphicsPipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule tessellationControlModule,const VkShaderModule tessellationEvaluationModule,const VkShaderModule fragmentModule,const UVec2 renderSize,const int numViewports,const std::vector<UVec4> cells)192 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface& vk,
193 const VkDevice device,
194 const VkPipelineLayout pipelineLayout,
195 const VkRenderPass renderPass,
196 const VkShaderModule vertexModule,
197 const VkShaderModule tessellationControlModule,
198 const VkShaderModule tessellationEvaluationModule,
199 const VkShaderModule fragmentModule,
200 const UVec2 renderSize,
201 const int numViewports,
202 const std::vector<UVec4> cells)
203 {
204 const VkVertexInputBindingDescription vertexInputBindingDescription =
205 {
206 0u, // uint32_t binding;
207 sizeof(PositionColorVertex), // uint32_t stride;
208 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
209 };
210
211 const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
212 {
213 {
214 0u, // uint32_t location;
215 0u, // uint32_t binding;
216 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
217 0u, // uint32_t offset;
218 },
219 {
220 1u, // uint32_t location;
221 0u, // uint32_t binding;
222 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
223 sizeof(Vec4), // uint32_t offset;
224 },
225 };
226
227 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
228 {
229 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
230 DE_NULL, // const void* pNext;
231 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags;
232 1u, // uint32_t vertexBindingDescriptionCount;
233 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
234 DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions), // uint32_t vertexAttributeDescriptionCount;
235 vertexInputAttributeDescriptions, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
236 };
237
238 const bool useTessellationShaders = (tessellationControlModule != DE_NULL) && (tessellationEvaluationModule != DE_NULL);
239
240 const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
241 {
242 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
243 DE_NULL, // const void* pNext;
244 (VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags flags;
245 useTessellationShaders ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // VkPrimitiveTopology topology;
246 VK_FALSE, // VkBool32 primitiveRestartEnable;
247 };
248
249 DE_ASSERT(numViewports == static_cast<int>(cells.size()));
250
251 std::vector<VkViewport> viewports;
252 viewports.reserve(numViewports);
253
254 std::vector<VkRect2D> rectScissors;
255 rectScissors.reserve(numViewports);
256
257 for (std::vector<UVec4>::const_iterator it = cells.begin(); it != cells.end(); ++it) {
258 const VkViewport viewport = makeViewport(float(it->x()), float(it->y()), float(it->z()), float(it->w()), 0.0f, 1.0f);
259 viewports.push_back(viewport);
260 const VkRect2D rect = makeRect2D(renderSize);
261 rectScissors.push_back(rect);
262 }
263
264 const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
265 {
266 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
267 DE_NULL, // const void* pNext;
268 (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags;
269 static_cast<deUint32>(numViewports), // uint32_t viewportCount;
270 &viewports[0], // const VkViewport* pViewports;
271 static_cast<deUint32>(numViewports), // uint32_t scissorCount;
272 &rectScissors[0], // const VkRect2D* pScissors;
273 };
274
275 const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
276 {
277 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
278 DE_NULL, // const void* pNext;
279 (VkPipelineRasterizationStateCreateFlags)0, // VkPipelineRasterizationStateCreateFlags flags;
280 VK_FALSE, // VkBool32 depthClampEnable;
281 VK_FALSE, // VkBool32 rasterizerDiscardEnable;
282 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
283 VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
284 VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
285 VK_FALSE, // VkBool32 depthBiasEnable;
286 0.0f, // float depthBiasConstantFactor;
287 0.0f, // float depthBiasClamp;
288 0.0f, // float depthBiasSlopeFactor;
289 1.0f, // float lineWidth;
290 };
291
292 const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
293 {
294 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
295 DE_NULL, // const void* pNext;
296 (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags;
297 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
298 VK_FALSE, // VkBool32 sampleShadingEnable;
299 0.0f, // float minSampleShading;
300 DE_NULL, // const VkSampleMask* pSampleMask;
301 VK_FALSE, // VkBool32 alphaToCoverageEnable;
302 VK_FALSE // VkBool32 alphaToOneEnable;
303 };
304
305 const VkStencilOpState stencilOpState = makeStencilOpState(
306 VK_STENCIL_OP_KEEP, // stencil fail
307 VK_STENCIL_OP_KEEP, // depth & stencil pass
308 VK_STENCIL_OP_KEEP, // depth only fail
309 VK_COMPARE_OP_ALWAYS, // compare op
310 0u, // compare mask
311 0u, // write mask
312 0u); // reference
313
314 VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
315 {
316 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
317 DE_NULL, // const void* pNext;
318 (VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags;
319 VK_FALSE, // VkBool32 depthTestEnable;
320 VK_FALSE, // VkBool32 depthWriteEnable;
321 VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
322 VK_FALSE, // VkBool32 depthBoundsTestEnable;
323 VK_FALSE, // VkBool32 stencilTestEnable;
324 stencilOpState, // VkStencilOpState front;
325 stencilOpState, // VkStencilOpState back;
326 0.0f, // float minDepthBounds;
327 1.0f, // float maxDepthBounds;
328 };
329
330 const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
331 const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState =
332 {
333 VK_FALSE, // VkBool32 blendEnable;
334 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
335 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
336 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
337 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
338 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
339 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
340 colorComponentsAll, // VkColorComponentFlags colorWriteMask;
341 };
342
343 const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
344 {
345 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
346 DE_NULL, // const void* pNext;
347 (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags;
348 VK_FALSE, // VkBool32 logicOpEnable;
349 VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
350 1u, // deUint32 attachmentCount;
351 &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
352 { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4];
353 };
354
355 const VkPipelineShaderStageCreateInfo pShaderStages[] =
356 {
357 {
358 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
359 DE_NULL, // const void* pNext;
360 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
361 VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
362 vertexModule, // VkShaderModule module;
363 "main", // const char* pName;
364 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
365 },
366 {
367 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
368 DE_NULL, // const void* pNext;
369 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
370 VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
371 fragmentModule, // VkShaderModule module;
372 "main", // const char* pName;
373 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
374 },
375 {
376 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
377 DE_NULL, // const void* pNext;
378 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
379 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, // VkShaderStageFlagBits stage;
380 tessellationControlModule, // VkShaderModule module;
381 "main", // const char* pName;
382 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
383 },
384 {
385 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
386 DE_NULL, // const void* pNext;
387 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
388 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, // VkShaderStageFlagBits stage;
389 tessellationEvaluationModule, // VkShaderModule module;
390 "main", // const char* pName;
391 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
392 },
393 };
394
395 const VkPipelineTessellationStateCreateInfo pipelineTessellationStateInfo =
396 {
397 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType;
398 DE_NULL, // const void* pNext;
399 (VkPipelineTessellationStateCreateFlags)0, // VkPipelineTessellationStateCreateFlags flags;
400 3, // uint32_t patchControlPoints;
401 };
402
403 const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
404 {
405 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
406 DE_NULL, // const void* pNext;
407 (VkPipelineCreateFlags)0, // VkPipelineCreateFlags flags;
408 useTessellationShaders ? deUint32(4) : deUint32(2), // deUint32 stageCount;
409 pShaderStages, // const VkPipelineShaderStageCreateInfo* pStages;
410 &vertexInputStateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
411 &pipelineInputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
412 useTessellationShaders ? &pipelineTessellationStateInfo : DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
413 &pipelineViewportStateInfo, // const VkPipelineViewportStateCreateInfo* pViewportState;
414 &pipelineRasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
415 &pipelineMultisampleStateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
416 &pipelineDepthStencilStateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
417 &pipelineColorBlendStateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
418 DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
419 pipelineLayout, // VkPipelineLayout layout;
420 renderPass, // VkRenderPass renderPass;
421 0u, // deUint32 subpass;
422 DE_NULL, // VkPipeline basePipelineHandle;
423 0, // deInt32 basePipelineIndex;
424 };
425
426 return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
427 }
428
generateGrid(const int numCells,const UVec2 & renderSize)429 std::vector<UVec4> generateGrid (const int numCells, const UVec2& renderSize)
430 {
431 const int numCols = deCeilFloatToInt32(deFloatSqrt(static_cast<float>(numCells)));
432 const int numRows = deCeilFloatToInt32(static_cast<float>(numCells) / static_cast<float>(numCols));
433 const int rectWidth = renderSize.x() / numCols;
434 const int rectHeight = renderSize.y() / numRows;
435
436 std::vector<UVec4> cells;
437 cells.reserve(numCells);
438
439 int x = 0;
440 int y = 0;
441
442 for (int cellNdx = 0; cellNdx < numCells; ++cellNdx)
443 {
444 const bool nextRow = (cellNdx != 0) && (cellNdx % numCols == 0);
445 if (nextRow)
446 {
447 x = 0;
448 y += rectHeight;
449 }
450
451 cells.push_back(UVec4(x, y, rectWidth, rectHeight));
452
453 x += rectWidth;
454 }
455
456 return cells;
457 }
458
generateColors(const int numColors)459 std::vector<Vec4> generateColors (const int numColors)
460 {
461 const Vec4 colors[] =
462 {
463 Vec4(0.18f, 0.42f, 0.17f, 1.0f),
464 Vec4(0.29f, 0.62f, 0.28f, 1.0f),
465 Vec4(0.59f, 0.84f, 0.44f, 1.0f),
466 Vec4(0.96f, 0.95f, 0.72f, 1.0f),
467 Vec4(0.94f, 0.55f, 0.39f, 1.0f),
468 Vec4(0.82f, 0.19f, 0.12f, 1.0f),
469 Vec4(0.46f, 0.15f, 0.26f, 1.0f),
470 Vec4(0.24f, 0.14f, 0.24f, 1.0f),
471 Vec4(0.49f, 0.31f, 0.26f, 1.0f),
472 Vec4(0.78f, 0.52f, 0.33f, 1.0f),
473 Vec4(0.94f, 0.82f, 0.31f, 1.0f),
474 Vec4(0.98f, 0.65f, 0.30f, 1.0f),
475 Vec4(0.22f, 0.65f, 0.53f, 1.0f),
476 Vec4(0.67f, 0.81f, 0.91f, 1.0f),
477 Vec4(0.43f, 0.44f, 0.75f, 1.0f),
478 Vec4(0.26f, 0.24f, 0.48f, 1.0f),
479 };
480
481 DE_ASSERT(numColors <= DE_LENGTH_OF_ARRAY(colors));
482
483 return std::vector<Vec4>(colors, colors + numColors);
484 }
485
486 //! Renders a colorful grid of rectangles.
generateReferenceImage(const tcu::TextureFormat format,const UVec2 & renderSize,const Vec4 & clearColor,const std::vector<UVec4> & cells,const std::vector<Vec4> & cellColors)487 tcu::TextureLevel generateReferenceImage (const tcu::TextureFormat format,
488 const UVec2& renderSize,
489 const Vec4& clearColor,
490 const std::vector<UVec4>& cells,
491 const std::vector<Vec4>& cellColors)
492 {
493 DE_ASSERT(cells.size() == cellColors.size());
494
495 tcu::TextureLevel image(format, renderSize.x(), renderSize.y());
496 tcu::clear(image.getAccess(), clearColor);
497
498 for (std::size_t i = 0; i < cells.size(); ++i)
499 {
500 const UVec4& cell = cells[i];
501 tcu::clear(
502 tcu::getSubregion(image.getAccess(), cell.x(), cell.y(), cell.z(), cell.w()),
503 cellColors[i]);
504 }
505
506 return image;
507 }
508
initVertexTestPrograms(SourceCollections & programCollection,const int numViewports)509 void initVertexTestPrograms (SourceCollections& programCollection, const int numViewports)
510 {
511 DE_UNREF(numViewports);
512
513 // Vertex shader
514 {
515 std::ostringstream src;
516 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
517 << "#extension GL_ARB_shader_viewport_layer_array : require\n"
518 << "\n"
519 << "layout(location = 0) in vec4 in_position;\n"
520 << "layout(location = 1) in vec4 in_color;\n"
521 << "layout(location = 0) out vec4 out_color;\n"
522 << "\n"
523 << "void main(void)\n"
524 << "{\n"
525 << " gl_ViewportIndex = gl_VertexIndex / 6;\n"
526 << " gl_Position = in_position;\n"
527 << " out_color = in_color;\n"
528 << "}\n";
529
530 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
531 }
532
533 // Fragment shader
534 {
535 std::ostringstream src;
536 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
537 << "\n"
538 << "layout(location = 0) in vec4 in_color;\n"
539 << "layout(location = 0) out vec4 out_color;\n"
540 << "\n"
541 << "void main(void)\n"
542 << "{\n"
543 << " out_color = in_color;\n"
544 << "}\n";
545
546 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
547 }
548 }
549
initTessellationTestPrograms(SourceCollections & programCollection,const int numViewports)550 void initTessellationTestPrograms (SourceCollections& programCollection, const int numViewports)
551 {
552 DE_UNREF(numViewports);
553
554 // Vertex shader
555 {
556 std::ostringstream src;
557 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
558 << "\n"
559 << "layout(location = 0) in vec4 in_position;\n"
560 << "layout(location = 1) in vec4 in_color;\n"
561 << "layout(location = 0) out vec4 out_color;\n"
562 << "\n"
563 << "void main(void)\n"
564 << "{\n"
565 << " gl_Position = in_position;\n"
566 << " out_color = in_color;\n"
567 << "}\n";
568
569 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
570 }
571
572 // Tessellation control shader
573 {
574 std::ostringstream src;
575 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
576 << "\n"
577 << "layout(vertices = 3) out;\n"
578 << "\n"
579 << "layout(location = 0) in vec4 in_color[];\n"
580 << "layout(location = 0) out vec4 out_color[];\n"
581 << "\n"
582 << "void main(void)\n"
583 << "{\n"
584 << " if (gl_InvocationID == 0) {\n"
585 << " gl_TessLevelInner[0] = 1.0;\n"
586 << " gl_TessLevelInner[1] = 1.0;\n"
587 << " gl_TessLevelOuter[0] = 1.0;\n"
588 << " gl_TessLevelOuter[1] = 1.0;\n"
589 << " gl_TessLevelOuter[2] = 1.0;\n"
590 << " gl_TessLevelOuter[3] = 1.0;\n"
591 << " }\n"
592 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
593 << " out_color[gl_InvocationID] = in_color[gl_InvocationID];\n"
594 << "}\n";
595
596 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
597 }
598
599 // Tessellation evaluation shader
600 {
601 std::ostringstream src;
602 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
603 << "#extension GL_ARB_shader_viewport_layer_array : require\n"
604 << "\n"
605 << "layout(triangles, equal_spacing, cw) in;\n"
606 << "\n"
607 << "layout(location = 0) in vec4 in_color[];\n"
608 << "layout(location = 0) out vec4 out_color;\n"
609 << "\n"
610 << "void main(void)\n"
611 << "{\n"
612 << " gl_ViewportIndex = gl_PrimitiveID / 2;\n"
613 << " gl_Position = gl_in[0].gl_Position * gl_TessCoord.x +\n"
614 << " gl_in[1].gl_Position * gl_TessCoord.y +\n"
615 << " gl_in[2].gl_Position * gl_TessCoord.z;\n"
616 << "\n"
617 << " out_color = in_color[0] * gl_TessCoord.x +\n"
618 << " in_color[1] * gl_TessCoord.y +\n"
619 << " in_color[2] * gl_TessCoord.z;\n"
620 << "}\n";
621
622 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
623 }
624
625 // Fragment shader
626 {
627 std::ostringstream src;
628 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
629 << "\n"
630 << "layout(location = 0) in vec4 in_color;\n"
631 << "layout(location = 0) out vec4 out_color;\n"
632 << "\n"
633 << "void main(void)\n"
634 << "{\n"
635 << " out_color = in_color;\n"
636 << "}\n";
637
638 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
639 }
640 }
641
generateVertices(const std::vector<Vec4> & colors)642 std::vector<PositionColorVertex> generateVertices (const std::vector<Vec4>& colors)
643 {
644 // Two triangles for each color (viewport).
645 std::size_t total = colors.size() * 6;
646
647 std::vector<PositionColorVertex> result;
648 result.reserve(total);
649
650 for (std::size_t i = 0; i < total; ++i)
651 {
652 Vec4 pos;
653 pos.z() = 0.0;
654 pos.w() = 1.0;
655
656 switch (i % 6) {
657 case 0: pos.xy() = Vec2(-1.0, 1.0); break;
658 case 1: pos.xy() = Vec2( 1.0, 1.0); break;
659 case 2: pos.xy() = Vec2(-1.0, -1.0); break;
660 case 3: pos.xy() = Vec2( 1.0, -1.0); break;
661 case 4: pos.xy() = Vec2( 1.0, 1.0); break;
662 case 5: pos.xy() = Vec2(-1.0, -1.0); break;
663 }
664
665 result.push_back(PositionColorVertex(pos, colors[i/6]));
666 }
667
668 return result;
669 }
670
671 // Renderer generates two triangles per viewport, each pair using a different color. The
672 // numViewports are positioned to form a grid.
673 class Renderer
674 {
675 public:
676 enum Shader {
677 VERTEX,
678 TESSELLATION,
679 };
680
Renderer(Context & context,const UVec2 & renderSize,const int numViewports,const std::vector<UVec4> & cells,const VkFormat colorFormat,const Vec4 & clearColor,const std::vector<Vec4> & colors,const Shader shader)681 Renderer (Context& context,
682 const UVec2& renderSize,
683 const int numViewports,
684 const std::vector<UVec4>& cells,
685 const VkFormat colorFormat,
686 const Vec4& clearColor,
687 const std::vector<Vec4>& colors,
688 const Shader shader)
689 : m_renderSize (renderSize)
690 , m_colorFormat (colorFormat)
691 , m_colorSubresourceRange (makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
692 , m_clearColor (clearColor)
693 , m_numViewports (numViewports)
694 , m_vertices (generateVertices(colors))
695 {
696 const DeviceInterface& vk = context.getDeviceInterface();
697 const VkDevice device = context.getDevice();
698 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
699 Allocator& allocator = context.getDefaultAllocator();
700 const VkDeviceSize vertexBufferSize = sizeInBytes(m_vertices);
701
702 m_colorImage = makeImage (vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
703 m_colorImageAlloc = bindImage (vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
704 m_colorAttachment = makeImageView (vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
705
706 m_vertexBuffer = Buffer::createAndAlloc (vk, device, makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), allocator, MemoryRequirement::HostVisible);
707
708 {
709 deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), &m_vertices[0], static_cast<std::size_t>(vertexBufferSize));
710 flushAlloc(vk, device, m_vertexBuffer->getBoundMemory());
711 }
712
713 if (shader == TESSELLATION)
714 {
715 m_tessellationControlModule = createShaderModule (vk, device, context.getBinaryCollection().get("tesc"), 0u);
716 m_tessellationEvaluationModule = createShaderModule (vk, device, context.getBinaryCollection().get("tese"), 0u);
717 }
718
719 m_vertexModule = createShaderModule (vk, device, context.getBinaryCollection().get("vert"), 0u);
720 m_fragmentModule = createShaderModule (vk, device, context.getBinaryCollection().get("frag"), 0u);
721 m_renderPass = makeRenderPass (vk, device, m_colorFormat);
722 m_framebuffer = makeFramebuffer (vk, device, *m_renderPass, 1u, &m_colorAttachment.get(),
723 static_cast<deUint32>(m_renderSize.x()), static_cast<deUint32>(m_renderSize.y()));
724 m_pipelineLayout = makePipelineLayout (vk, device);
725 m_pipeline = makeGraphicsPipeline (vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_tessellationControlModule,
726 *m_tessellationEvaluationModule, *m_fragmentModule, m_renderSize, m_numViewports, cells);
727 m_cmdPool = createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
728 m_cmdBuffer = allocateCommandBuffer (vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
729 }
730
draw(Context & context,const VkBuffer colorBuffer) const731 void draw (Context& context, const VkBuffer colorBuffer) const
732 {
733 const DeviceInterface& vk = context.getDeviceInterface();
734 const VkDevice device = context.getDevice();
735 const VkQueue queue = context.getUniversalQueue();
736
737 beginCommandBuffer(vk, *m_cmdBuffer);
738
739 beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), m_clearColor);
740
741 vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
742 {
743 const VkBuffer vertexBuffer = m_vertexBuffer->object();
744 const VkDeviceSize vertexBufferOffset = 0ull;
745 vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset);
746 }
747 vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_numViewports * 6), 1u, 0u, 0u); // two triangles per viewport
748 endRenderPass(vk, *m_cmdBuffer);
749
750 copyImageToBuffer(vk, *m_cmdBuffer, *m_colorImage, colorBuffer, tcu::IVec2(m_renderSize.x(), m_renderSize.y()));
751
752 VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
753 submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
754 }
755
756 private:
757 const UVec2 m_renderSize;
758 const VkFormat m_colorFormat;
759 const VkImageSubresourceRange m_colorSubresourceRange;
760 const Vec4 m_clearColor;
761 const int m_numViewports;
762 const std::vector<PositionColorVertex> m_vertices;
763
764 Move<VkImage> m_colorImage;
765 MovePtr<Allocation> m_colorImageAlloc;
766 Move<VkImageView> m_colorAttachment;
767 SharedPtr<Buffer> m_vertexBuffer;
768 Move<VkShaderModule> m_vertexModule;
769 Move<VkShaderModule> m_tessellationControlModule;
770 Move<VkShaderModule> m_tessellationEvaluationModule;
771 Move<VkShaderModule> m_fragmentModule;
772 Move<VkRenderPass> m_renderPass;
773 Move<VkFramebuffer> m_framebuffer;
774 Move<VkPipelineLayout> m_pipelineLayout;
775 Move<VkPipeline> m_pipeline;
776 Move<VkCommandPool> m_cmdPool;
777 Move<VkCommandBuffer> m_cmdBuffer;
778
779 // "deleted"
780 Renderer (const Renderer&);
781 Renderer& operator= (const Renderer&);
782 };
783
requireShaderViewportIndexLayer(const Context & context)784 void requireShaderViewportIndexLayer (const Context& context)
785 {
786 const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(context.getInstanceInterface(), context.getPhysicalDevice());
787 const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(context.getInstanceInterface(), context.getPhysicalDevice()).limits;
788
789 if (!features.multiViewport)
790 TCU_THROW(NotSupportedError, "Required feature is not supported: multiViewport");
791
792 if (limits.maxViewports < MIN_MAX_VIEWPORTS)
793 TCU_FAIL("multiViewport supported but maxViewports is less than the minimum required");
794
795 const std::vector<std::string>& extensions = context.getDeviceExtensions();
796 if (!isDeviceExtensionSupported(context.getUsedApiVersion(), extensions, "VK_EXT_shader_viewport_index_layer"))
797 TCU_THROW(NotSupportedError, "Extension VK_EXT_shader_viewport_index_layer not supported");
798
799 }
800
testVertexShader(Context & context,const int numViewports)801 tcu::TestStatus testVertexShader (Context& context, const int numViewports)
802 {
803 requireShaderViewportIndexLayer(context);
804
805 const DeviceInterface& vk = context.getDeviceInterface();
806 const VkDevice device = context.getDevice();
807 Allocator& allocator = context.getDefaultAllocator();
808
809 const UVec2 renderSize (128, 128);
810 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
811 const Vec4 clearColor (0.5f, 0.5f, 0.5f, 1.0f);
812 const std::vector<Vec4> colors = generateColors(numViewports);
813 const std::vector<UVec4> cells = generateGrid(numViewports, renderSize);
814
815 const VkDeviceSize colorBufferSize = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
816
817 const SharedPtr<Buffer> colorBuffer = Buffer::createAndAlloc(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), allocator, MemoryRequirement::HostVisible);
818
819 // Zero buffer.
820 {
821 const Allocation alloc = colorBuffer->getBoundMemory();
822 deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
823 flushAlloc(vk, device, alloc);
824 }
825
826 {
827 context.getTestContext().getLog()
828 << tcu::TestLog::Message << "Rendering a colorful grid of " << numViewports << " rectangle(s)." << tcu::TestLog::EndMessage
829 << tcu::TestLog::Message << "Not covered area will be filled with a gray color." << tcu::TestLog::EndMessage;
830 }
831
832 // Draw
833 {
834 const Renderer renderer (context, renderSize, numViewports, cells, colorFormat, clearColor, colors, Renderer::VERTEX);
835 renderer.draw(context, colorBuffer->object());
836 }
837
838 // Log image
839 {
840 const Allocation alloc = colorBuffer->getBoundMemory();
841 invalidateMappedMemoryRange(vk, device, alloc.getMemory(), 0ull, colorBufferSize);
842
843 const tcu::ConstPixelBufferAccess resultImage (mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, alloc.getHostPtr());
844 const tcu::TextureLevel referenceImage = generateReferenceImage(mapVkFormat(colorFormat), renderSize, clearColor, cells, colors);
845
846 // Images should now match.
847 if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
848 TCU_FAIL("Rendered image is not correct");
849 }
850
851 return tcu::TestStatus::pass("OK");
852 }
853
testTessellationShader(Context & context,const int numViewports)854 tcu::TestStatus testTessellationShader (Context& context, const int numViewports)
855 {
856 requireShaderViewportIndexLayer(context);
857
858 const VkPhysicalDeviceFeatures& features = context.getDeviceFeatures();
859 if (!features.tessellationShader)
860 TCU_THROW(NotSupportedError, "Required feature is not supported: tessellationShader");
861
862 const DeviceInterface& vk = context.getDeviceInterface();
863 const VkDevice device = context.getDevice();
864 Allocator& allocator = context.getDefaultAllocator();
865
866 const UVec2 renderSize (128, 128);
867 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
868 const Vec4 clearColor (0.5f, 0.5f, 0.5f, 1.0f);
869 const std::vector<Vec4> colors = generateColors(numViewports);
870 const std::vector<UVec4> cells = generateGrid(numViewports, renderSize);
871
872 const VkDeviceSize colorBufferSize = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
873
874 const SharedPtr<Buffer> colorBuffer = Buffer::createAndAlloc(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), allocator, MemoryRequirement::HostVisible);
875
876 // Zero buffer.
877 {
878 const Allocation alloc = colorBuffer->getBoundMemory();
879 deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
880 flushAlloc(vk, device, alloc);
881 }
882
883 {
884 context.getTestContext().getLog()
885 << tcu::TestLog::Message << "Rendering a colorful grid of " << numViewports << " rectangle(s)." << tcu::TestLog::EndMessage
886 << tcu::TestLog::Message << "Not covered area will be filled with a gray color." << tcu::TestLog::EndMessage;
887 }
888
889 // Draw
890 {
891 const Renderer renderer (context, renderSize, numViewports, cells, colorFormat, clearColor, colors, Renderer::TESSELLATION);
892 renderer.draw(context, colorBuffer->object());
893 }
894
895 // Log image
896 {
897 const Allocation alloc = colorBuffer->getBoundMemory();
898 invalidateMappedMemoryRange(vk, device, alloc.getMemory(), 0ull, colorBufferSize);
899
900 const tcu::ConstPixelBufferAccess resultImage (mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, alloc.getHostPtr());
901 const tcu::TextureLevel referenceImage = generateReferenceImage(mapVkFormat(colorFormat), renderSize, clearColor, cells, colors);
902
903 // Images should now match.
904 if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
905 TCU_FAIL("Rendered image is not correct");
906 }
907
908 return tcu::TestStatus::pass("OK");
909 }
910
911
912 } // anonymous
913
createShaderViewportIndexTests(tcu::TestContext & testCtx)914 tcu::TestCaseGroup* createShaderViewportIndexTests (tcu::TestContext& testCtx)
915 {
916 MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "shader_viewport_index", ""));
917
918 for (int numViewports = 1; numViewports <= MIN_MAX_VIEWPORTS; ++numViewports)
919 addFunctionCaseWithPrograms(group.get(), "vertex_shader_" + de::toString(numViewports), "", initVertexTestPrograms, testVertexShader, numViewports);
920
921 for (int numViewports = 1; numViewports <= MIN_MAX_VIEWPORTS; ++numViewports)
922 addFunctionCaseWithPrograms(group.get(), "tessellation_shader_" + de::toString(numViewports), "", initTessellationTestPrograms, testTessellationShader, numViewports);
923
924 return group.release();
925 }
926
927 } // Draw
928 } // vkt
929