xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/draw/vktDrawShaderViewportIndexTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 #include "vkBuilderUtil.hpp"
42 #include "vkBufferWithMemory.hpp"
43 
44 #include "tcuTestLog.hpp"
45 #include "tcuVector.hpp"
46 #include "tcuImageCompare.hpp"
47 #include "tcuTextureUtil.hpp"
48 
49 #include "deUniquePtr.hpp"
50 #include "deMath.h"
51 
52 #include <vector>
53 #include <memory>
54 
55 namespace vkt
56 {
57 namespace Draw
58 {
59 using namespace vk;
60 using de::MovePtr;
61 using de::SharedPtr;
62 using de::UniquePtr;
63 using tcu::UVec2;
64 using tcu::UVec4;
65 using tcu::Vec2;
66 using tcu::Vec4;
67 
68 namespace
69 {
70 
71 enum Constants
72 {
73     MIN_MAX_VIEWPORTS = 16, //!< Minimum number of viewports for an implementation supporting multiViewport.
74 };
75 
76 struct TestParams
77 {
78     int numViewports;
79     bool writeFromVertex;
80     const SharedGroupParams groupParams;
81     bool useTessellationShader;
82 };
83 
84 template <typename T>
sizeInBytes(const std::vector<T> & vec)85 inline VkDeviceSize sizeInBytes(const std::vector<T> &vec)
86 {
87     return vec.size() * sizeof(vec[0]);
88 }
89 
makeImageCreateInfo(const VkFormat format,const UVec2 & size,VkImageUsageFlags usage)90 VkImageCreateInfo makeImageCreateInfo(const VkFormat format, const UVec2 &size, VkImageUsageFlags usage)
91 {
92     const VkImageCreateInfo imageParams = {
93         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
94         DE_NULL,                             // const void* pNext;
95         (VkImageCreateFlags)0,               // VkImageCreateFlags flags;
96         VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
97         format,                              // VkFormat format;
98         makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
99         1u,                                  // uint32_t mipLevels;
100         1u,                                  // uint32_t arrayLayers;
101         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
102         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
103         usage,                               // VkImageUsageFlags usage;
104         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
105         0u,                                  // uint32_t queueFamilyIndexCount;
106         DE_NULL,                             // const uint32_t* pQueueFamilyIndices;
107         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
108     };
109     return imageParams;
110 }
111 
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)112 Move<VkPipeline> makeGraphicsPipeline(const DeviceInterface &vk, const VkDevice device,
113                                       const VkPipelineLayout pipelineLayout, const VkRenderPass renderPass,
114                                       const VkShaderModule vertexModule, const VkShaderModule tessellationControlModule,
115                                       const VkShaderModule tessellationEvaluationModule,
116                                       const VkShaderModule fragmentModule, const UVec2 renderSize,
117                                       const int numViewports, const std::vector<UVec4> cells)
118 {
119     const VkVertexInputBindingDescription vertexInputBindingDescription = {
120         0u,                          // uint32_t binding;
121         sizeof(PositionColorVertex), // uint32_t stride;
122         VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
123     };
124 
125     const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = {
126         {
127             0u,                            // uint32_t location;
128             0u,                            // uint32_t binding;
129             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
130             0u,                            // uint32_t offset;
131         },
132         {
133             1u,                            // uint32_t location;
134             0u,                            // uint32_t binding;
135             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
136             sizeof(Vec4),                  // uint32_t offset;
137         },
138     };
139 
140     const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = {
141         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType                             sType;
142         DE_NULL,                                                   // const void*                                 pNext;
143         (VkPipelineVertexInputStateCreateFlags)0,                  // VkPipelineVertexInputStateCreateFlags       flags;
144         1u,                             // uint32_t                                    vertexBindingDescriptionCount;
145         &vertexInputBindingDescription, // const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
146         DE_LENGTH_OF_ARRAY(
147             vertexInputAttributeDescriptions), // uint32_t                                    vertexAttributeDescriptionCount;
148         vertexInputAttributeDescriptions, // const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
149     };
150 
151     const bool useTessellationShaders =
152         (tessellationControlModule != DE_NULL) && (tessellationEvaluationModule != DE_NULL);
153 
154     const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = {
155         VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType                             sType;
156         DE_NULL,                                    // const void*                                 pNext;
157         (VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags     flags;
158         useTessellationShaders ?
159             VK_PRIMITIVE_TOPOLOGY_PATCH_LIST :
160             VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // VkPrimitiveTopology                         topology;
161         VK_FALSE,                                // VkBool32                                    primitiveRestartEnable;
162     };
163 
164     DE_ASSERT(numViewports == static_cast<int>(cells.size()));
165 
166     std::vector<VkViewport> viewports;
167     viewports.reserve(numViewports);
168 
169     std::vector<VkRect2D> rectScissors;
170     rectScissors.reserve(numViewports);
171 
172     for (std::vector<UVec4>::const_iterator it = cells.begin(); it != cells.end(); ++it)
173     {
174         const VkViewport viewport =
175             makeViewport(float(it->x()), float(it->y()), float(it->z()), float(it->w()), 0.0f, 1.0f);
176         viewports.push_back(viewport);
177         const VkRect2D rect = makeRect2D(renderSize);
178         rectScissors.push_back(rect);
179     }
180 
181     const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = {
182         VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType                             sType;
183         DE_NULL,                                               // const void*                                 pNext;
184         (VkPipelineViewportStateCreateFlags)0,                 // VkPipelineViewportStateCreateFlags          flags;
185         static_cast<uint32_t>(numViewports), // uint32_t                                    viewportCount;
186         &viewports[0],                       // const VkViewport*                           pViewports;
187         static_cast<uint32_t>(numViewports), // uint32_t                                    scissorCount;
188         &rectScissors[0],                    // const VkRect2D*                             pScissors;
189     };
190 
191     const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = {
192         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType                          sType;
193         DE_NULL,                                                    // const void*                              pNext;
194         (VkPipelineRasterizationStateCreateFlags)0,                 // VkPipelineRasterizationStateCreateFlags  flags;
195         VK_FALSE,                        // VkBool32                                 depthClampEnable;
196         VK_FALSE,                        // VkBool32                                 rasterizerDiscardEnable;
197         VK_POLYGON_MODE_FILL,            // VkPolygonMode polygonMode;
198         VK_CULL_MODE_NONE,               // VkCullModeFlags cullMode;
199         VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
200         VK_FALSE,                        // VkBool32 depthBiasEnable;
201         0.0f,                            // float depthBiasConstantFactor;
202         0.0f,                            // float depthBiasClamp;
203         0.0f,                            // float depthBiasSlopeFactor;
204         1.0f,                            // float lineWidth;
205     };
206 
207     const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = {
208         VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
209         DE_NULL,                                                  // const void* pNext;
210         (VkPipelineMultisampleStateCreateFlags)0,                 // VkPipelineMultisampleStateCreateFlags flags;
211         VK_SAMPLE_COUNT_1_BIT,                                    // VkSampleCountFlagBits rasterizationSamples;
212         VK_FALSE,                                                 // VkBool32 sampleShadingEnable;
213         0.0f,                                                     // float minSampleShading;
214         DE_NULL,                                                  // const VkSampleMask* pSampleMask;
215         VK_FALSE,                                                 // VkBool32 alphaToCoverageEnable;
216         VK_FALSE                                                  // VkBool32 alphaToOneEnable;
217     };
218 
219     const VkStencilOpState stencilOpState = makeStencilOpState(VK_STENCIL_OP_KEEP,   // stencil fail
220                                                                VK_STENCIL_OP_KEEP,   // depth & stencil pass
221                                                                VK_STENCIL_OP_KEEP,   // depth only fail
222                                                                VK_COMPARE_OP_ALWAYS, // compare op
223                                                                0u,                   // compare mask
224                                                                0u,                   // write mask
225                                                                0u);                  // reference
226 
227     VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo = {
228         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
229         DE_NULL,                                                    // const void* pNext;
230         (VkPipelineDepthStencilStateCreateFlags)0,                  // VkPipelineDepthStencilStateCreateFlags flags;
231         VK_FALSE,                                                   // VkBool32 depthTestEnable;
232         VK_FALSE,                                                   // VkBool32 depthWriteEnable;
233         VK_COMPARE_OP_LESS,                                         // VkCompareOp depthCompareOp;
234         VK_FALSE,                                                   // VkBool32 depthBoundsTestEnable;
235         VK_FALSE,                                                   // VkBool32 stencilTestEnable;
236         stencilOpState,                                             // VkStencilOpState front;
237         stencilOpState,                                             // VkStencilOpState back;
238         0.0f,                                                       // float minDepthBounds;
239         1.0f,                                                       // float maxDepthBounds;
240     };
241 
242     const VkColorComponentFlags colorComponentsAll =
243         VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
244     const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {
245         VK_FALSE,             // VkBool32 blendEnable;
246         VK_BLEND_FACTOR_ONE,  // VkBlendFactor srcColorBlendFactor;
247         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
248         VK_BLEND_OP_ADD,      // VkBlendOp colorBlendOp;
249         VK_BLEND_FACTOR_ONE,  // VkBlendFactor srcAlphaBlendFactor;
250         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
251         VK_BLEND_OP_ADD,      // VkBlendOp alphaBlendOp;
252         colorComponentsAll,   // VkColorComponentFlags colorWriteMask;
253     };
254 
255     const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = {
256         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
257         DE_NULL,                                                  // const void* pNext;
258         (VkPipelineColorBlendStateCreateFlags)0,                  // VkPipelineColorBlendStateCreateFlags flags;
259         VK_FALSE,                                                 // VkBool32 logicOpEnable;
260         VK_LOGIC_OP_COPY,                                         // VkLogicOp logicOp;
261         1u,                                                       // uint32_t attachmentCount;
262         &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
263         {0.0f, 0.0f, 0.0f, 0.0f},           // float blendConstants[4];
264     };
265 
266     const VkPipelineShaderStageCreateInfo pShaderStages[] = {
267         {
268             VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
269             DE_NULL,                                             // const void* pNext;
270             (VkPipelineShaderStageCreateFlags)0,                 // VkPipelineShaderStageCreateFlags flags;
271             VK_SHADER_STAGE_VERTEX_BIT,                          // VkShaderStageFlagBits stage;
272             vertexModule,                                        // VkShaderModule module;
273             "main",                                              // const char* pName;
274             DE_NULL,                                             // const VkSpecializationInfo* pSpecializationInfo;
275         },
276         {
277             VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
278             DE_NULL,                                             // const void* pNext;
279             (VkPipelineShaderStageCreateFlags)0,                 // VkPipelineShaderStageCreateFlags flags;
280             VK_SHADER_STAGE_FRAGMENT_BIT,                        // VkShaderStageFlagBits stage;
281             fragmentModule,                                      // VkShaderModule module;
282             "main",                                              // const char* pName;
283             DE_NULL,                                             // const VkSpecializationInfo* pSpecializationInfo;
284         },
285         {
286             VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
287             DE_NULL,                                             // const void* pNext;
288             (VkPipelineShaderStageCreateFlags)0,                 // VkPipelineShaderStageCreateFlags flags;
289             VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,            // VkShaderStageFlagBits stage;
290             tessellationControlModule,                           // VkShaderModule module;
291             "main",                                              // const char* pName;
292             DE_NULL,                                             // const VkSpecializationInfo* pSpecializationInfo;
293         },
294         {
295             VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
296             DE_NULL,                                             // const void* pNext;
297             (VkPipelineShaderStageCreateFlags)0,                 // VkPipelineShaderStageCreateFlags flags;
298             VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,         // VkShaderStageFlagBits stage;
299             tessellationEvaluationModule,                        // VkShaderModule module;
300             "main",                                              // const char* pName;
301             DE_NULL,                                             // const VkSpecializationInfo* pSpecializationInfo;
302         },
303     };
304 
305     const VkPipelineTessellationStateCreateInfo pipelineTessellationStateInfo = {
306         VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType;
307         DE_NULL,                                                   // const void* pNext;
308         (VkPipelineTessellationStateCreateFlags)0,                 // VkPipelineTessellationStateCreateFlags flags;
309         3,                                                         // uint32_t patchControlPoints;
310     };
311 
312     VkGraphicsPipelineCreateInfo graphicsPipelineInfo{
313         VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,    // VkStructureType sType;
314         DE_NULL,                                            // const void* pNext;
315         (VkPipelineCreateFlags)0,                           // VkPipelineCreateFlags flags;
316         useTessellationShaders ? uint32_t(4) : uint32_t(2), // uint32_t stageCount;
317         pShaderStages,                                      // const VkPipelineShaderStageCreateInfo* pStages;
318         &vertexInputStateInfo,           // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
319         &pipelineInputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
320         useTessellationShaders ? &pipelineTessellationStateInfo :
321                                  DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
322         &pipelineViewportStateInfo,       // const VkPipelineViewportStateCreateInfo* pViewportState;
323         &pipelineRasterizationStateInfo,  // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
324         &pipelineMultisampleStateInfo,    // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
325         &pipelineDepthStencilStateInfo,   // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
326         &pipelineColorBlendStateInfo,     // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
327         DE_NULL,                          // const VkPipelineDynamicStateCreateInfo* pDynamicState;
328         pipelineLayout,                   // VkPipelineLayout layout;
329         renderPass,                       // VkRenderPass renderPass;
330         0u,                               // uint32_t subpass;
331         DE_NULL,                          // VkPipeline basePipelineHandle;
332         0,                                // int32_t basePipelineIndex;
333     };
334 
335 #ifndef CTS_USES_VULKANSC
336     VkFormat colorAttachmentFormat = VK_FORMAT_R8G8B8A8_UNORM;
337     VkPipelineRenderingCreateInfoKHR renderingCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
338                                                          DE_NULL,
339                                                          0u,
340                                                          1u,
341                                                          &colorAttachmentFormat,
342                                                          VK_FORMAT_UNDEFINED,
343                                                          VK_FORMAT_UNDEFINED};
344 
345     // when pipeline is created without render pass we are using dynamic rendering
346     if (renderPass == DE_NULL)
347         graphicsPipelineInfo.pNext = &renderingCreateInfo;
348 #endif // CTS_USES_VULKANSC
349 
350     return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
351 }
352 
generateGrid(const int numCells,const UVec2 & renderSize)353 std::vector<UVec4> generateGrid(const int numCells, const UVec2 &renderSize)
354 {
355     const int numCols    = deCeilFloatToInt32(deFloatSqrt(static_cast<float>(numCells)));
356     const int numRows    = deCeilFloatToInt32(static_cast<float>(numCells) / static_cast<float>(numCols));
357     const int rectWidth  = renderSize.x() / numCols;
358     const int rectHeight = renderSize.y() / numRows;
359 
360     std::vector<UVec4> cells;
361     cells.reserve(numCells);
362 
363     int x = 0;
364     int y = 0;
365 
366     for (int cellNdx = 0; cellNdx < numCells; ++cellNdx)
367     {
368         const bool nextRow = (cellNdx != 0) && (cellNdx % numCols == 0);
369         if (nextRow)
370         {
371             x = 0;
372             y += rectHeight;
373         }
374 
375         cells.push_back(UVec4(x, y, rectWidth, rectHeight));
376 
377         x += rectWidth;
378     }
379 
380     return cells;
381 }
382 
generateColors(const int numColors)383 std::vector<Vec4> generateColors(const int numColors)
384 {
385     const Vec4 colors[] = {
386         Vec4(0.18f, 0.42f, 0.17f, 1.0f), Vec4(0.29f, 0.62f, 0.28f, 1.0f), Vec4(0.59f, 0.84f, 0.44f, 1.0f),
387         Vec4(0.96f, 0.95f, 0.72f, 1.0f), Vec4(0.94f, 0.55f, 0.39f, 1.0f), Vec4(0.82f, 0.19f, 0.12f, 1.0f),
388         Vec4(0.46f, 0.15f, 0.26f, 1.0f), Vec4(0.24f, 0.14f, 0.24f, 1.0f), Vec4(0.49f, 0.31f, 0.26f, 1.0f),
389         Vec4(0.78f, 0.52f, 0.33f, 1.0f), Vec4(0.94f, 0.82f, 0.31f, 1.0f), Vec4(0.98f, 0.65f, 0.30f, 1.0f),
390         Vec4(0.22f, 0.65f, 0.53f, 1.0f), Vec4(0.67f, 0.81f, 0.91f, 1.0f), Vec4(0.43f, 0.44f, 0.75f, 1.0f),
391         Vec4(0.26f, 0.24f, 0.48f, 1.0f),
392     };
393 
394     DE_ASSERT(numColors <= DE_LENGTH_OF_ARRAY(colors));
395 
396     return std::vector<Vec4>(colors, colors + numColors);
397 }
398 
399 //! 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)400 tcu::TextureLevel generateReferenceImage(const tcu::TextureFormat format, const UVec2 &renderSize,
401                                          const Vec4 &clearColor, const std::vector<UVec4> &cells,
402                                          const std::vector<Vec4> &cellColors)
403 {
404     DE_ASSERT(cells.size() == cellColors.size());
405 
406     tcu::TextureLevel image(format, renderSize.x(), renderSize.y());
407     tcu::clear(image.getAccess(), clearColor);
408 
409     for (std::size_t i = 0; i < cells.size(); ++i)
410     {
411         const UVec4 &cell = cells[i];
412         tcu::clear(tcu::getSubregion(image.getAccess(), cell.x(), cell.y(), cell.z(), cell.w()), cellColors[i]);
413     }
414 
415     return image;
416 }
417 
initVertexTestPrograms(SourceCollections & programCollection,const TestParams)418 void initVertexTestPrograms(SourceCollections &programCollection, const TestParams)
419 {
420     // Vertex shader
421     {
422         std::ostringstream src;
423         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
424             << "#extension GL_ARB_shader_viewport_layer_array : require\n"
425             << "\n"
426             << "layout(location = 0) in  vec4 in_position;\n"
427             << "layout(location = 1) in  vec4 in_color;\n"
428             << "layout(location = 0) out vec4 out_color;\n"
429             << "\n"
430             << "void main(void)\n"
431             << "{\n"
432             << "    gl_ViewportIndex = gl_VertexIndex / 6;\n"
433             << "    gl_Position = in_position;\n"
434             << "    out_color = in_color;\n"
435             << "}\n";
436 
437         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
438         programCollection.glslSources.add("vert_1_2")
439             << glu::VertexSource(src.str())
440             << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_5, 0u, true);
441     }
442 
443     // Fragment shader
444     {
445         std::ostringstream src;
446         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
447             << "\n"
448             << "layout(location = 0) in  vec4 in_color;\n"
449             << "layout(location = 0) out vec4 out_color;\n"
450             << "\n"
451             << "void main(void)\n"
452             << "{\n"
453             << "    out_color = in_color;\n"
454             << "}\n";
455 
456         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
457     }
458 }
459 
initFragmentTestPrograms(SourceCollections & programCollection,const TestParams testParams)460 void initFragmentTestPrograms(SourceCollections &programCollection, const TestParams testParams)
461 {
462     // Vertex shader.
463     {
464         std::ostringstream src;
465         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
466             << "#extension GL_ARB_shader_viewport_layer_array : require\n"
467             << "\n"
468             << "layout(location = 0) in  vec4 in_position;\n"
469             << "layout(location = 1) in  vec4 in_color;\n"
470             << "layout(location = 0) out vec4 out_color;\n"
471             << "\n"
472             << "void main(void)\n"
473             << "{\n"
474             << (testParams.writeFromVertex ? "    gl_ViewportIndex = gl_VertexIndex / 6;\n" : "")
475             << "    gl_Position = in_position;\n"
476             << "    out_color = in_color;\n"
477             << "}\n";
478 
479         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
480         programCollection.glslSources.add("vert_1_2")
481             << glu::VertexSource(src.str())
482             << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_5, 0u, true);
483     }
484 
485     // Fragment shader
486     {
487         // Ignore input color and choose one using the viewport index.
488         std::ostringstream src;
489         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
490             << "\n"
491             << "layout(location = 0) in  vec4 in_color;\n"
492             << "layout(location = 0) out vec4 out_color;\n"
493             << "layout(set=0, binding=0) uniform Colors {\n"
494             << "    vec4 color[" << testParams.numViewports << "];\n"
495             << "};\n"
496             << "\n"
497             << "void main(void)\n"
498             << "{\n"
499             << "    out_color = color[gl_ViewportIndex];\n"
500             << "}\n";
501 
502         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
503     }
504 }
505 
initTessellationTestPrograms(SourceCollections & programCollection,const TestParams)506 void initTessellationTestPrograms(SourceCollections &programCollection, const TestParams)
507 {
508     // Vertex shader
509     {
510         std::ostringstream src;
511         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
512             << "\n"
513             << "layout(location = 0) in  vec4 in_position;\n"
514             << "layout(location = 1) in  vec4 in_color;\n"
515             << "layout(location = 0) out vec4 out_color;\n"
516             << "\n"
517             << "void main(void)\n"
518             << "{\n"
519             << "    gl_Position = in_position;\n"
520             << "    out_color = in_color;\n"
521             << "}\n";
522 
523         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
524         programCollection.glslSources.add("vert_1_2")
525             << glu::VertexSource(src.str())
526             << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_5, 0u, true);
527     }
528 
529     // Tessellation control shader
530     {
531         std::ostringstream src;
532         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
533             << "\n"
534             << "layout(vertices = 3) out;\n"
535             << "\n"
536             << "layout(location = 0) in  vec4 in_color[];\n"
537             << "layout(location = 0) out vec4 out_color[];\n"
538             << "\n"
539             << "void main(void)\n"
540             << "{\n"
541             << "    if (gl_InvocationID == 0) {\n"
542             << "        gl_TessLevelInner[0] = 1.0;\n"
543             << "        gl_TessLevelInner[1] = 1.0;\n"
544             << "        gl_TessLevelOuter[0] = 1.0;\n"
545             << "        gl_TessLevelOuter[1] = 1.0;\n"
546             << "        gl_TessLevelOuter[2] = 1.0;\n"
547             << "        gl_TessLevelOuter[3] = 1.0;\n"
548             << "    }\n"
549             << "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
550             << "    out_color[gl_InvocationID] = in_color[gl_InvocationID];\n"
551             << "}\n";
552 
553         programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
554     }
555 
556     // Tessellation evaluation shader
557     {
558         std::ostringstream src;
559         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
560             << "#extension GL_ARB_shader_viewport_layer_array : require\n"
561             << "\n"
562             << "layout(triangles, equal_spacing, cw) in;\n"
563             << "\n"
564             << "layout(location = 0) in  vec4 in_color[];\n"
565             << "layout(location = 0) out vec4 out_color;\n"
566             << "\n"
567             << "void main(void)\n"
568             << "{\n"
569             << "    gl_ViewportIndex = gl_PrimitiveID / 2;\n"
570             << "    gl_Position = gl_in[0].gl_Position * gl_TessCoord.x +\n"
571             << "                  gl_in[1].gl_Position * gl_TessCoord.y +\n"
572             << "                  gl_in[2].gl_Position * gl_TessCoord.z;\n"
573             << "\n"
574             << "    out_color = in_color[0] * gl_TessCoord.x +\n"
575             << "                in_color[1] * gl_TessCoord.y +\n"
576             << "                in_color[2] * gl_TessCoord.z;\n"
577             << "}\n";
578 
579         programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
580         programCollection.glslSources.add("tese_1_2")
581             << glu::TessellationEvaluationSource(src.str())
582             << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_5, 0u, true);
583     }
584 
585     // Fragment shader
586     {
587         std::ostringstream src;
588         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
589             << "\n"
590             << "layout(location = 0) in  vec4 in_color;\n"
591             << "layout(location = 0) out vec4 out_color;\n"
592             << "\n"
593             << "void main(void)\n"
594             << "{\n"
595             << "    out_color = in_color;\n"
596             << "}\n";
597 
598         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
599     }
600 }
601 
generateVertices(const std::vector<Vec4> & colors)602 std::vector<PositionColorVertex> generateVertices(const std::vector<Vec4> &colors)
603 {
604     // Two triangles for each color (viewport).
605     std::size_t total = colors.size() * 6;
606 
607     std::vector<PositionColorVertex> result;
608     result.reserve(total);
609 
610     for (std::size_t i = 0; i < total; ++i)
611     {
612         Vec4 pos;
613         pos.z() = 0.0;
614         pos.w() = 1.0;
615 
616         switch (i % 6)
617         {
618         case 0:
619             pos.xy() = Vec2(-1.0, 1.0);
620             break;
621         case 1:
622             pos.xy() = Vec2(1.0, 1.0);
623             break;
624         case 2:
625             pos.xy() = Vec2(-1.0, -1.0);
626             break;
627         case 3:
628             pos.xy() = Vec2(1.0, -1.0);
629             break;
630         case 4:
631             pos.xy() = Vec2(1.0, 1.0);
632             break;
633         case 5:
634             pos.xy() = Vec2(-1.0, -1.0);
635             break;
636         }
637 
638         result.push_back(PositionColorVertex(pos, colors[i / 6]));
639     }
640 
641     return result;
642 }
643 
644 // Renderer generates two triangles per viewport, each pair using a different color. The
645 // numViewports are positioned to form a grid.
646 class Renderer
647 {
648 public:
649     enum Shader
650     {
651         VERTEX,
652         TESSELLATION,
653         FRAGMENT,
654     };
655 
Renderer(Context & context,const UVec2 & renderSize,const TestParams & testParams,const std::vector<UVec4> & cells,const VkFormat colorFormat,const Vec4 & clearColor,const std::vector<Vec4> & colors,const Shader shader)656     Renderer(Context &context, const UVec2 &renderSize, const TestParams &testParams, const std::vector<UVec4> &cells,
657              const VkFormat colorFormat, const Vec4 &clearColor, const std::vector<Vec4> &colors, const Shader shader)
658         : m_groupParams(testParams.groupParams)
659         , m_renderSize(renderSize)
660         , m_colorFormat(colorFormat)
661         , m_colorSubresourceRange(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
662         , m_clearValue(makeClearValueColor(clearColor))
663         , m_numViewports(testParams.numViewports)
664         , m_colors(colors)
665         , m_vertices(generateVertices(colors))
666         , m_shader(shader)
667     {
668         const DeviceInterface &vk           = context.getDeviceInterface();
669         const VkDevice device               = context.getDevice();
670         const uint32_t queueFamilyIndex     = context.getUniversalQueueFamilyIndex();
671         Allocator &allocator                = context.getDefaultAllocator();
672         const VkDeviceSize vertexBufferSize = sizeInBytes(m_vertices);
673 
674         m_colorImage =
675             makeImage(vk, device,
676                       makeImageCreateInfo(m_colorFormat, m_renderSize,
677                                           VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
678         m_colorImageAlloc = bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
679         m_colorAttachment =
680             makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
681 
682         m_vertexBuffer = Buffer::createAndAlloc(
683             vk, device, makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), allocator,
684             MemoryRequirement::HostVisible);
685 
686         {
687             deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), &m_vertices[0],
688                      static_cast<std::size_t>(vertexBufferSize));
689             flushAlloc(vk, device, m_vertexBuffer->getBoundMemory());
690         }
691 
692         if (shader == TESSELLATION)
693         {
694             m_tessellationControlModule = createShaderModule(vk, device, context.getBinaryCollection().get("tesc"), 0u);
695             m_tessellationEvaluationModule = createShaderModule(
696                 vk, device,
697                 context.getBinaryCollection().get(context.contextSupports(VK_API_VERSION_1_2) ? "tese_1_2" : "tese"),
698                 0u);
699         }
700 
701         m_vertexModule = createShaderModule(
702             vk, device,
703             context.getBinaryCollection().get(context.contextSupports(VK_API_VERSION_1_2) ? "vert_1_2" : "vert"), 0u);
704         m_fragmentModule = createShaderModule(vk, device, context.getBinaryCollection().get("frag"), 0u);
705 
706         if (!m_groupParams->useDynamicRendering)
707         {
708             m_renderPass = makeRenderPass(vk, device, m_colorFormat);
709 
710             m_framebuffer =
711                 makeFramebuffer(vk, device, *m_renderPass, m_colorAttachment.get(),
712                                 static_cast<uint32_t>(m_renderSize.x()), static_cast<uint32_t>(m_renderSize.y()));
713         }
714 
715         if (shader == FRAGMENT)
716         {
717             vk::DescriptorSetLayoutBuilder builder;
718             builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_FRAGMENT_BIT);
719             m_descriptorSetLayout = builder.build(vk, device);
720         }
721 
722         m_pipelineLayout = makePipelineLayout(vk, device, (shader == FRAGMENT ? m_descriptorSetLayout.get() : DE_NULL));
723         m_pipeline       = makeGraphicsPipeline(vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule,
724                                                 *m_tessellationControlModule, *m_tessellationEvaluationModule,
725                                                 *m_fragmentModule, m_renderSize, m_numViewports, cells);
726         m_cmdPool   = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
727         m_cmdBuffer = allocateCommandBuffer(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
728         m_secCmdBuffer = allocateCommandBuffer(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
729     }
730 
draw(Context & context,const VkBuffer colorBuffer)731     void draw(Context &context, const VkBuffer colorBuffer)
732     {
733         const DeviceInterface &vk = context.getDeviceInterface();
734         const VkDevice device     = context.getDevice();
735         const VkQueue queue       = context.getUniversalQueue();
736         const VkRect2D renderArea{
737             makeOffset2D(0, 0),
738             makeExtent2D(m_renderSize.x(), m_renderSize.y()),
739         };
740 
741 #ifndef CTS_USES_VULKANSC
742         if (m_groupParams->useSecondaryCmdBuffer)
743         {
744             // record secondary command buffer
745             if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
746             {
747                 beginSecondaryCmdBuffer(context, *m_secCmdBuffer, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
748                 beginRendering(vk, *m_secCmdBuffer, *m_colorAttachment, renderArea, m_clearValue,
749                                VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR);
750             }
751             else
752                 beginSecondaryCmdBuffer(context, *m_secCmdBuffer);
753 
754             drawCommands(context, *m_secCmdBuffer);
755 
756             if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
757                 endRendering(vk, *m_secCmdBuffer);
758 
759             endCommandBuffer(vk, *m_secCmdBuffer);
760 
761             // record primary command buffer
762             beginCommandBuffer(vk, *m_cmdBuffer, 0u);
763 
764             preRenderCommands(context, *m_cmdBuffer);
765 
766             if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
767                 beginRendering(vk, *m_cmdBuffer, *m_colorAttachment, renderArea, m_clearValue,
768                                VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR,
769                                VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR);
770 
771             vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
772 
773             if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
774                 endRendering(vk, *m_cmdBuffer);
775 
776             postRenderCommands(context, colorBuffer);
777             endCommandBuffer(vk, *m_cmdBuffer);
778         }
779         else if (m_groupParams->useDynamicRendering)
780         {
781             beginCommandBuffer(vk, *m_cmdBuffer);
782 
783             preRenderCommands(context, *m_cmdBuffer);
784             beginRendering(vk, *m_cmdBuffer, *m_colorAttachment, renderArea, m_clearValue,
785                            VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_CLEAR);
786             drawCommands(context, *m_cmdBuffer);
787             endRendering(vk, *m_cmdBuffer);
788             postRenderCommands(context, colorBuffer);
789 
790             endCommandBuffer(vk, *m_cmdBuffer);
791         }
792 #endif // CTS_USES_VULKANSC
793 
794         if (!m_groupParams->useDynamicRendering)
795         {
796             beginCommandBuffer(vk, *m_cmdBuffer);
797 
798             preRenderCommands(context, *m_cmdBuffer);
799             beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, renderArea, m_clearValue);
800             drawCommands(context, *m_cmdBuffer);
801             endRenderPass(vk, *m_cmdBuffer);
802             postRenderCommands(context, colorBuffer);
803 
804             endCommandBuffer(vk, *m_cmdBuffer);
805         }
806 
807         submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
808     }
809 
810 protected:
811 #ifndef CTS_USES_VULKANSC
beginSecondaryCmdBuffer(Context & context,VkCommandBuffer cmdBuffer,VkRenderingFlagsKHR renderingFlags=0u) const812     void beginSecondaryCmdBuffer(Context &context, VkCommandBuffer cmdBuffer,
813                                  VkRenderingFlagsKHR renderingFlags = 0u) const
814     {
815         VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo{
816             VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
817             DE_NULL,                                                         // const void* pNext;
818             renderingFlags,                                                  // VkRenderingFlagsKHR flags;
819             0u,                                                              // uint32_t viewMask;
820             1u,                                                              // uint32_t colorAttachmentCount;
821             &m_colorFormat,                                                  // const VkFormat* pColorAttachmentFormats;
822             VK_FORMAT_UNDEFINED,                                             // VkFormat depthAttachmentFormat;
823             VK_FORMAT_UNDEFINED,                                             // VkFormat stencilAttachmentFormat;
824             VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
825         };
826         const VkCommandBufferInheritanceInfo bufferInheritanceInfo = initVulkanStructure(&inheritanceRenderingInfo);
827 
828         VkCommandBufferUsageFlags usageFlags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
829         if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
830             usageFlags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
831 
832         const VkCommandBufferBeginInfo commandBufBeginParams{
833             VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
834             DE_NULL,                                     // const void* pNext;
835             usageFlags,                                  // VkCommandBufferUsageFlags flags;
836             &bufferInheritanceInfo};
837 
838         const DeviceInterface &vk = context.getDeviceInterface();
839         VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &commandBufBeginParams));
840     }
841 #endif // CTS_USES_VULKANSC
842 
preRenderCommands(Context & context,VkCommandBuffer cmdBuffer) const843     void preRenderCommands(Context &context, VkCommandBuffer cmdBuffer) const
844     {
845         if (m_groupParams->useDynamicRendering)
846         {
847             const DeviceInterface &vk = context.getDeviceInterface();
848             initialTransitionColor2DImage(vk, cmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
849                                           VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
850         }
851     }
852 
postRenderCommands(Context & context,VkBuffer colorBuffer) const853     void postRenderCommands(Context &context, VkBuffer colorBuffer) const
854     {
855         const DeviceInterface &vk = context.getDeviceInterface();
856         copyImageToBuffer(vk, *m_cmdBuffer, *m_colorImage, colorBuffer, tcu::IVec2(m_renderSize.x(), m_renderSize.y()));
857     }
858 
drawCommands(Context & context,VkCommandBuffer cmdBuffer)859     void drawCommands(Context &context, VkCommandBuffer cmdBuffer)
860     {
861         const DeviceInterface &vk             = context.getDeviceInterface();
862         const VkDevice device                 = context.getDevice();
863         Allocator &allocator                  = context.getDefaultAllocator();
864         const VkBuffer vertexBuffer           = m_vertexBuffer->object();
865         const VkDeviceSize vertexBufferOffset = 0ull;
866 
867         vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
868         vk.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset);
869 
870         // Prepare colors buffer if needed.
871         if (m_shader == FRAGMENT)
872         {
873             // Create buffer.
874             const auto colorsBufferSize       = m_colors.size() * sizeof(decltype(m_colors)::value_type);
875             const auto colorsBufferCreateInfo = vk::makeBufferCreateInfo(static_cast<VkDeviceSize>(colorsBufferSize),
876                                                                          vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
877             m_colorsBuffer                    = SharedPtr<BufferWithMemory>(new vk::BufferWithMemory{
878                 vk, device, allocator, colorsBufferCreateInfo, MemoryRequirement::HostVisible});
879 
880             // Copy colors and flush allocation.
881             auto &colorsBufferAlloc = m_colorsBuffer->getAllocation();
882             deMemcpy(colorsBufferAlloc.getHostPtr(), m_colors.data(), colorsBufferSize);
883             vk::flushAlloc(vk, device, colorsBufferAlloc);
884 
885             // Descriptor pool.
886             DescriptorPoolBuilder poolBuilder;
887             poolBuilder.addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u);
888             m_descriptorPool = poolBuilder.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
889 
890             // Descriptor set.
891             m_descriptorSet = vk::makeDescriptorSet(vk, device, m_descriptorPool.get(), m_descriptorSetLayout.get());
892 
893             // Update and bind descriptor set.
894             const auto colorsBufferDescriptorInfo =
895                 vk::makeDescriptorBufferInfo(m_colorsBuffer->get(), 0ull, VK_WHOLE_SIZE);
896             vk::DescriptorSetUpdateBuilder updateBuilder;
897             updateBuilder.writeSingle(m_descriptorSet.get(), vk::DescriptorSetUpdateBuilder::Location::binding(0u),
898                                       vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &colorsBufferDescriptorInfo);
899             updateBuilder.update(vk, device);
900 
901             vk.cmdBindDescriptorSets(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout.get(), 0u, 1u,
902                                      &m_descriptorSet.get(), 0u, nullptr);
903         }
904 
905         vk.cmdDraw(cmdBuffer, static_cast<uint32_t>(m_numViewports * 6), 1u, 0u, 0u); // two triangles per viewport
906     }
907 
908 private:
909     const SharedGroupParams m_groupParams;
910     const UVec2 m_renderSize;
911     const VkFormat m_colorFormat;
912     const VkImageSubresourceRange m_colorSubresourceRange;
913     const VkClearValue m_clearValue;
914     const int m_numViewports;
915     const std::vector<Vec4> m_colors;
916     const std::vector<PositionColorVertex> m_vertices;
917     const Shader m_shader;
918 
919     Move<VkImage> m_colorImage;
920     MovePtr<Allocation> m_colorImageAlloc;
921     Move<VkImageView> m_colorAttachment;
922     SharedPtr<BufferWithMemory> m_colorsBuffer;
923     SharedPtr<Buffer> m_vertexBuffer;
924     Move<VkShaderModule> m_vertexModule;
925     Move<VkShaderModule> m_tessellationControlModule;
926     Move<VkShaderModule> m_tessellationEvaluationModule;
927     Move<VkShaderModule> m_fragmentModule;
928     Move<VkRenderPass> m_renderPass;
929     Move<VkFramebuffer> m_framebuffer;
930     Move<VkDescriptorPool> m_descriptorPool;
931     Move<VkDescriptorSet> m_descriptorSet;
932     Move<VkDescriptorSetLayout> m_descriptorSetLayout;
933     Move<VkPipelineLayout> m_pipelineLayout;
934     Move<VkPipeline> m_pipeline;
935     Move<VkCommandPool> m_cmdPool;
936     Move<VkCommandBuffer> m_cmdBuffer;
937     Move<VkCommandBuffer> m_secCmdBuffer;
938 
939     // "deleted"
940     Renderer(const Renderer &);
941     Renderer &operator=(const Renderer &);
942 };
943 
testVertexFragmentShader(Context & context,const TestParams & testParams,Renderer::Shader shader)944 tcu::TestStatus testVertexFragmentShader(Context &context, const TestParams &testParams, Renderer::Shader shader)
945 {
946     const DeviceInterface &vk = context.getDeviceInterface();
947     const VkDevice device     = context.getDevice();
948     Allocator &allocator      = context.getDefaultAllocator();
949 
950     const UVec2 renderSize(128, 128);
951     const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
952     const Vec4 clearColor(0.5f, 0.5f, 0.5f, 1.0f);
953     const std::vector<Vec4> colors = generateColors(testParams.numViewports);
954     const std::vector<UVec4> cells = generateGrid(testParams.numViewports, renderSize);
955 
956     const VkDeviceSize colorBufferSize = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
957 
958     const SharedPtr<Buffer> colorBuffer =
959         Buffer::createAndAlloc(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT),
960                                allocator, MemoryRequirement::HostVisible);
961 
962     // Zero buffer.
963     {
964         const Allocation alloc = colorBuffer->getBoundMemory();
965         deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
966         flushAlloc(vk, device, alloc);
967     }
968 
969     {
970         context.getTestContext().getLog()
971             << tcu::TestLog::Message << "Rendering a colorful grid of " << testParams.numViewports << " rectangle(s)."
972             << tcu::TestLog::EndMessage << tcu::TestLog::Message << "Not covered area will be filled with a gray color."
973             << tcu::TestLog::EndMessage;
974     }
975 
976     // Draw
977     {
978         Renderer renderer(context, renderSize, testParams, cells, colorFormat, clearColor, colors, shader);
979         renderer.draw(context, colorBuffer->object());
980     }
981 
982     // Log image
983     {
984         const Allocation alloc = colorBuffer->getBoundMemory();
985         invalidateAlloc(vk, device, alloc);
986 
987         const tcu::ConstPixelBufferAccess resultImage(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u,
988                                                       alloc.getHostPtr());
989         const tcu::TextureLevel referenceImage =
990             generateReferenceImage(mapVkFormat(colorFormat), renderSize, clearColor, cells, colors);
991 
992         // Images should now match.
993         if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare",
994                                         referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
995             TCU_FAIL("Rendered image is not correct");
996     }
997 
998     return tcu::TestStatus::pass("OK");
999 }
1000 
testVertexShader(Context & context,const TestParams testParams)1001 tcu::TestStatus testVertexShader(Context &context, const TestParams testParams)
1002 {
1003     return testVertexFragmentShader(context, testParams, Renderer::VERTEX);
1004 }
1005 
testFragmentShader(Context & context,const TestParams testParams)1006 tcu::TestStatus testFragmentShader(Context &context, const TestParams testParams)
1007 {
1008     return testVertexFragmentShader(context, testParams, Renderer::FRAGMENT);
1009 }
1010 
testTessellationShader(Context & context,const TestParams testParams)1011 tcu::TestStatus testTessellationShader(Context &context, const TestParams testParams)
1012 {
1013     const DeviceInterface &vk = context.getDeviceInterface();
1014     const VkDevice device     = context.getDevice();
1015     Allocator &allocator      = context.getDefaultAllocator();
1016 
1017     const UVec2 renderSize(128, 128);
1018     const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
1019     const Vec4 clearColor(0.5f, 0.5f, 0.5f, 1.0f);
1020     const std::vector<Vec4> colors = generateColors(testParams.numViewports);
1021     const std::vector<UVec4> cells = generateGrid(testParams.numViewports, renderSize);
1022 
1023     const VkDeviceSize colorBufferSize = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
1024 
1025     const SharedPtr<Buffer> colorBuffer =
1026         Buffer::createAndAlloc(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT),
1027                                allocator, MemoryRequirement::HostVisible);
1028 
1029     // Zero buffer.
1030     {
1031         const Allocation alloc = colorBuffer->getBoundMemory();
1032         deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
1033         flushAlloc(vk, device, alloc);
1034     }
1035 
1036     {
1037         context.getTestContext().getLog()
1038             << tcu::TestLog::Message << "Rendering a colorful grid of " << testParams.numViewports << " rectangle(s)."
1039             << tcu::TestLog::EndMessage << tcu::TestLog::Message << "Not covered area will be filled with a gray color."
1040             << tcu::TestLog::EndMessage;
1041     }
1042 
1043     // Draw
1044     {
1045         Renderer renderer(context, renderSize, testParams, cells, colorFormat, clearColor, colors,
1046                           Renderer::TESSELLATION);
1047         renderer.draw(context, colorBuffer->object());
1048     }
1049 
1050     // Log image
1051     {
1052         const Allocation alloc = colorBuffer->getBoundMemory();
1053         invalidateAlloc(vk, device, alloc);
1054 
1055         const tcu::ConstPixelBufferAccess resultImage(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u,
1056                                                       alloc.getHostPtr());
1057         const tcu::TextureLevel referenceImage =
1058             generateReferenceImage(mapVkFormat(colorFormat), renderSize, clearColor, cells, colors);
1059 
1060         // Images should now match.
1061         if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare",
1062                                         referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
1063             TCU_FAIL("Rendered image is not correct");
1064     }
1065 
1066     return tcu::TestStatus::pass("OK");
1067 }
1068 
checkSupport(Context & context,TestParams params)1069 void checkSupport(Context &context, TestParams params)
1070 {
1071     context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_MULTI_VIEWPORT);
1072     context.requireDeviceFunctionality("VK_EXT_shader_viewport_index_layer");
1073 
1074     if (context.getDeviceProperties().limits.maxViewports < MIN_MAX_VIEWPORTS)
1075         TCU_FAIL("multiViewport supported but maxViewports is less than the minimum required");
1076 
1077     if (params.useTessellationShader)
1078         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
1079 
1080     if (params.groupParams->useDynamicRendering)
1081         context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
1082 }
1083 
1084 } // namespace
1085 
createShaderViewportIndexTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)1086 tcu::TestCaseGroup *createShaderViewportIndexTests(tcu::TestContext &testCtx, const SharedGroupParams groupParams)
1087 {
1088     MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "shader_viewport_index"));
1089 
1090     TestParams testParams{
1091         1,           // int numViewports;
1092         false,       // bool writeFromVertex;
1093         groupParams, // SharedGroupParams groupParams;
1094         false        // bool useTessellationShader;
1095     };
1096 
1097     for (testParams.numViewports = 1; testParams.numViewports <= MIN_MAX_VIEWPORTS; ++testParams.numViewports)
1098         addFunctionCaseWithPrograms(group.get(), "vertex_shader_" + de::toString(testParams.numViewports), checkSupport,
1099                                     initVertexTestPrograms, testVertexShader, testParams);
1100 
1101     testParams.numViewports = 1;
1102     addFunctionCaseWithPrograms(group.get(), "fragment_shader_implicit", checkSupport, initFragmentTestPrograms,
1103                                 testFragmentShader, testParams);
1104     testParams.writeFromVertex = true;
1105     for (testParams.numViewports = 1; testParams.numViewports <= MIN_MAX_VIEWPORTS; ++testParams.numViewports)
1106         addFunctionCaseWithPrograms(group.get(), "fragment_shader_" + de::toString(testParams.numViewports),
1107                                     checkSupport, initFragmentTestPrograms, testFragmentShader, testParams);
1108     testParams.writeFromVertex = false;
1109 
1110     testParams.useTessellationShader = true;
1111     for (testParams.numViewports = 1; testParams.numViewports <= MIN_MAX_VIEWPORTS; ++testParams.numViewports)
1112         addFunctionCaseWithPrograms(group.get(), "tessellation_shader_" + de::toString(testParams.numViewports),
1113                                     checkSupport, initTessellationTestPrograms, testTessellationShader, testParams);
1114 
1115     return group.release();
1116 }
1117 
1118 } // namespace Draw
1119 } // namespace vkt
1120