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