1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 The Khronos Group Inc.
6 * Copyright (c) 2023 LunarG, Inc.
7 * Copyright (c) 2023 Nintendo
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*!
22 * \file vktPipelineRenderToImageTests.cpp
23 * \brief Render to image tests
24 *//*--------------------------------------------------------------------*/
25
26 #include "vktPipelineRenderToImageTests.hpp"
27 #include "vktPipelineMakeUtil.hpp"
28 #include "vktTestCase.hpp"
29 #include "vktTestCaseUtil.hpp"
30 #include "vktPipelineVertexUtil.hpp"
31 #include "vktTestGroupUtil.hpp"
32 #include "vkObjUtil.hpp"
33
34 #include "vkMemUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkTypeUtil.hpp"
37 #include "vkRefUtil.hpp"
38 #include "vkBuilderUtil.hpp"
39 #include "vkPrograms.hpp"
40 #include "vkImageUtil.hpp"
41 #include "vkCmdUtil.hpp"
42
43 #include "tcuTextureUtil.hpp"
44 #include "tcuImageCompare.hpp"
45 #include "tcuTestLog.hpp"
46 #include "tcuPlatform.hpp"
47 #include "vkPlatform.hpp"
48
49 #include "deUniquePtr.hpp"
50 #include "deSharedPtr.hpp"
51
52 #include <string>
53 #include <vector>
54 #include <set>
55 #include <algorithm>
56
57 namespace vkt
58 {
59 namespace pipeline
60 {
61 namespace
62 {
63 using namespace vk;
64 using de::MovePtr;
65 using de::SharedPtr;
66 using de::UniquePtr;
67 using std::vector;
68 using tcu::BVec4;
69 using tcu::IVec2;
70 using tcu::IVec3;
71 using tcu::IVec4;
72 using tcu::UVec4;
73 using tcu::Vec4;
74
75 typedef SharedPtr<Unique<VkImageView>> SharedPtrVkImageView;
76
77 enum Constants
78 {
79 NUM_CUBE_FACES = 6,
80 REFERENCE_COLOR_VALUE = 125,
81 REFERENCE_STENCIL_VALUE = 42,
82 MAX_SIZE = -1, //!< Should be queried at runtime and replaced with max possible value
83 MAX_VERIFICATION_REGION_SIZE = 32, //!< Limit the checked area to a small size, especially for huge images
84 MAX_VERIFICATION_REGION_DEPTH = 8,
85
86 MASK_W = (1 | 0 | 0 | 0),
87 MASK_W_LAYERS = (1 | 0 | 0 | 8),
88 MASK_WH = (1 | 2 | 0 | 0),
89 MASK_WH_LAYERS = (1 | 2 | 0 | 8),
90 MASK_WHD = (1 | 2 | 4 | 0),
91 };
92
93 enum AllocationKind
94 {
95 ALLOCATION_KIND_SUBALLOCATED = 0,
96 ALLOCATION_KIND_DEDICATED,
97 };
98
99 static const float REFERENCE_DEPTH_VALUE = 1.0f;
100 static const Vec4 COLOR_TABLE[] = {
101 Vec4(0.9f, 0.0f, 0.0f, 1.0f), Vec4(0.6f, 1.0f, 0.0f, 1.0f), Vec4(0.3f, 0.0f, 1.0f, 1.0f),
102 Vec4(0.1f, 1.0f, 1.0f, 1.0f), Vec4(0.8f, 1.0f, 0.0f, 1.0f), Vec4(0.5f, 0.0f, 1.0f, 1.0f),
103 Vec4(0.2f, 0.0f, 0.0f, 1.0f), Vec4(1.0f, 1.0f, 0.0f, 1.0f),
104 };
105
106 struct CaseDef
107 {
108 PipelineConstructionType pipelineConstructionType;
109 VkImageViewType viewType;
110 IVec4 imageSizeHint; //!< (w, h, d, layers), a component may have a symbolic value MAX_SIZE
111 VkFormat colorFormat;
112 VkFormat depthStencilFormat; //! A depth/stencil format, or UNDEFINED if not used
113 AllocationKind allocationKind;
114 };
115
116 template <typename T>
makeSharedPtr(Move<T> move)117 inline SharedPtr<Unique<T>> makeSharedPtr(Move<T> move)
118 {
119 return SharedPtr<Unique<T>>(new Unique<T>(move));
120 }
121
122 template <typename T>
sizeInBytes(const vector<T> & vec)123 inline VkDeviceSize sizeInBytes(const vector<T> &vec)
124 {
125 return vec.size() * sizeof(vec[0]);
126 }
127
isCube(const VkImageViewType viewType)128 inline bool isCube(const VkImageViewType viewType)
129 {
130 return (viewType == VK_IMAGE_VIEW_TYPE_CUBE || viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY);
131 }
132
product(const IVec4 & v)133 inline VkDeviceSize product(const IVec4 &v)
134 {
135 return ((static_cast<VkDeviceSize>(v.x()) * v.y()) * v.z()) * v.w();
136 }
137
138 template <typename T>
sum(const vector<T> & v)139 inline T sum(const vector<T> &v)
140 {
141 T total = static_cast<T>(0);
142 for (typename vector<T>::const_iterator it = v.begin(); it != v.end(); ++it)
143 total += *it;
144 return total;
145 }
146
147 template <typename T, int Size>
findIndexOfMaxComponent(const tcu::Vector<T,Size> & vec)148 int findIndexOfMaxComponent(const tcu::Vector<T, Size> &vec)
149 {
150 int index = 0;
151 T value = vec[0];
152
153 for (int i = 1; i < Size; ++i)
154 {
155 if (vec[i] > value)
156 {
157 index = i;
158 value = vec[i];
159 }
160 }
161
162 return index;
163 }
164
maxLayersOrDepth(const IVec4 & size)165 inline int maxLayersOrDepth(const IVec4 &size)
166 {
167 // This is safe because 3D images must have layers (w) = 1
168 return deMax32(size.z(), size.w());
169 }
170
bindBuffer(const InstanceInterface & vki,const DeviceInterface & vkd,const VkPhysicalDevice & physDevice,const VkDevice device,const VkBuffer & buffer,const MemoryRequirement requirement,Allocator & allocator,AllocationKind allocationKind)171 de::MovePtr<Allocation> bindBuffer(const InstanceInterface &vki, const DeviceInterface &vkd,
172 const VkPhysicalDevice &physDevice, const VkDevice device, const VkBuffer &buffer,
173 const MemoryRequirement requirement, Allocator &allocator,
174 AllocationKind allocationKind)
175 {
176 switch (allocationKind)
177 {
178 case ALLOCATION_KIND_SUBALLOCATED:
179 {
180 return vk::bindBuffer(vkd, device, allocator, buffer, requirement);
181 }
182
183 case ALLOCATION_KIND_DEDICATED:
184 {
185 return bindBufferDedicated(vki, vkd, physDevice, device, buffer, requirement);
186 }
187
188 default:
189 {
190 TCU_THROW(InternalError, "Invalid allocation kind");
191 }
192 }
193 }
194
bindImage(const InstanceInterface & vki,const DeviceInterface & vkd,const VkPhysicalDevice & physDevice,const VkDevice device,const VkImage & image,const MemoryRequirement requirement,Allocator & allocator,AllocationKind allocationKind)195 de::MovePtr<Allocation> bindImage(const InstanceInterface &vki, const DeviceInterface &vkd,
196 const VkPhysicalDevice &physDevice, const VkDevice device, const VkImage &image,
197 const MemoryRequirement requirement, Allocator &allocator,
198 AllocationKind allocationKind)
199 {
200 switch (allocationKind)
201 {
202 case ALLOCATION_KIND_SUBALLOCATED:
203 {
204 return vk::bindImage(vkd, device, allocator, image, requirement);
205 }
206
207 case ALLOCATION_KIND_DEDICATED:
208 {
209 return bindImageDedicated(vki, vkd, physDevice, device, image, requirement);
210 }
211
212 default:
213 {
214 TCU_THROW(InternalError, "Invalid allocation kind");
215 }
216 }
217 }
218
219 // This is very test specific, so be careful if you want to reuse this code.
preparePipelineWrapper(GraphicsPipelineWrapper & gpw,const VkPipeline basePipeline,const PipelineLayoutWrapper & pipelineLayout,const VkRenderPass renderPass,const ShaderWrapper vertexModule,const ShaderWrapper fragmentModule,const IVec2 & renderSize,const VkPrimitiveTopology topology,const uint32_t subpass,const bool useDepth,const bool useStencil)220 void preparePipelineWrapper(GraphicsPipelineWrapper &gpw,
221 const VkPipeline basePipeline, // for derivatives
222 const PipelineLayoutWrapper &pipelineLayout, const VkRenderPass renderPass,
223 const ShaderWrapper vertexModule, const ShaderWrapper fragmentModule,
224 const IVec2 &renderSize, const VkPrimitiveTopology topology, const uint32_t subpass,
225 const bool useDepth, const bool useStencil)
226 {
227 const VkVertexInputBindingDescription vertexInputBindingDescription = {
228 0u, // uint32_t binding;
229 sizeof(Vertex4RGBA), // uint32_t stride;
230 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
231 };
232
233 const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = {
234 {
235 0u, // uint32_t location;
236 0u, // uint32_t binding;
237 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
238 0u, // uint32_t offset;
239 },
240 {
241 1u, // uint32_t location;
242 0u, // uint32_t binding;
243 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
244 sizeof(Vec4), // uint32_t offset;
245 }};
246
247 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = {
248 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
249 DE_NULL, // const void* pNext;
250 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags;
251 1u, // uint32_t vertexBindingDescriptionCount;
252 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
253 DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions), // uint32_t vertexAttributeDescriptionCount;
254 vertexInputAttributeDescriptions, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
255 };
256
257 const std::vector<VkViewport> viewport{makeViewport(renderSize)};
258 const std::vector<VkRect2D> scissor{makeRect2D(renderSize)};
259
260 const VkStencilOpState stencilOpState =
261 makeStencilOpState(VK_STENCIL_OP_KEEP, // stencil fail
262 VK_STENCIL_OP_KEEP, // depth & stencil pass
263 VK_STENCIL_OP_KEEP, // depth only fail
264 VK_COMPARE_OP_EQUAL, // compare op
265 ~0u, // compare mask
266 ~0u, // write mask
267 static_cast<uint32_t>(REFERENCE_STENCIL_VALUE)); // reference
268
269 VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo = {
270 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
271 DE_NULL, // const void* pNext;
272 (VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags;
273 useDepth, // VkBool32 depthTestEnable;
274 VK_FALSE, // VkBool32 depthWriteEnable;
275 VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
276 VK_FALSE, // VkBool32 depthBoundsTestEnable;
277 useStencil, // VkBool32 stencilTestEnable;
278 stencilOpState, // VkStencilOpState front;
279 stencilOpState, // VkStencilOpState back;
280 0.0f, // float minDepthBounds;
281 1.0f, // float maxDepthBounds;
282 };
283
284 const VkColorComponentFlags colorComponentsAll =
285 VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
286 // Number of blend attachments must equal the number of color attachments during any subpass.
287 const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {
288 VK_FALSE, // VkBool32 blendEnable;
289 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
290 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
291 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
292 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
293 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
294 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
295 colorComponentsAll, // VkColorComponentFlags colorWriteMask;
296 };
297
298 const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = {
299 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
300 DE_NULL, // const void* pNext;
301 (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags;
302 VK_FALSE, // VkBool32 logicOpEnable;
303 VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
304 1u, // uint32_t attachmentCount;
305 &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
306 {0.0f, 0.0f, 0.0f, 0.0f}, // float blendConstants[4];
307 };
308
309 gpw.setDefaultTopology(topology)
310 .setDefaultRasterizationState()
311 .setDefaultMultisampleState()
312 .setupVertexInputState(&vertexInputStateInfo)
313 .setupPreRasterizationShaderState(viewport, scissor, pipelineLayout, renderPass, subpass, vertexModule)
314 .setupFragmentShaderState(pipelineLayout, renderPass, subpass, fragmentModule, &pipelineDepthStencilStateInfo)
315 .setupFragmentOutputState(renderPass, subpass, &pipelineColorBlendStateInfo)
316 .setMonolithicPipelineLayout(pipelineLayout)
317 .buildPipeline(DE_NULL, basePipeline, -1);
318 }
319
320 //! Make a render pass with one subpass per color attachment and depth/stencil attachment (if used).
makeRenderPass(const DeviceInterface & vk,const VkDevice device,const PipelineConstructionType pipelineConstructionType,const VkFormat colorFormat,const VkFormat depthStencilFormat,const uint32_t numLayers,const VkImageLayout initialColorImageLayout=VK_IMAGE_LAYOUT_UNDEFINED,const VkImageLayout initialDepthStencilImageLayout=VK_IMAGE_LAYOUT_UNDEFINED)321 RenderPassWrapper makeRenderPass(const DeviceInterface &vk, const VkDevice device,
322 const PipelineConstructionType pipelineConstructionType, const VkFormat colorFormat,
323 const VkFormat depthStencilFormat, const uint32_t numLayers,
324 const VkImageLayout initialColorImageLayout = VK_IMAGE_LAYOUT_UNDEFINED,
325 const VkImageLayout initialDepthStencilImageLayout = VK_IMAGE_LAYOUT_UNDEFINED)
326 {
327 const VkAttachmentDescription colorAttachmentDescription = {
328 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
329 colorFormat, // VkFormat format;
330 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
331 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
332 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
333 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
334 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
335 initialColorImageLayout, // VkImageLayout initialLayout;
336 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
337 };
338 vector<VkAttachmentDescription> attachmentDescriptions(numLayers, colorAttachmentDescription);
339
340 const VkAttachmentDescription depthStencilAttachmentDescription = {
341 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
342 depthStencilFormat, // VkFormat format;
343 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
344 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
345 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp;
346 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp;
347 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
348 initialDepthStencilImageLayout, // VkImageLayout initialLayout;
349 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
350 };
351
352 if (depthStencilFormat != VK_FORMAT_UNDEFINED)
353 attachmentDescriptions.insert(attachmentDescriptions.end(), numLayers, depthStencilAttachmentDescription);
354
355 // Create a subpass for each attachment (each attachement is a layer of an arrayed image).
356 vector<VkAttachmentReference> colorAttachmentReferences(numLayers);
357 vector<VkAttachmentReference> depthStencilAttachmentReferences(numLayers);
358 vector<VkSubpassDescription> subpasses;
359
360 // Ordering here must match the framebuffer attachments
361 for (uint32_t i = 0; i < numLayers; ++i)
362 {
363 const VkAttachmentReference attachmentRef = {
364 i, // uint32_t attachment;
365 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
366 };
367 const VkAttachmentReference depthStencilAttachmentRef = {
368 i + numLayers, // uint32_t attachment;
369 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout layout;
370 };
371
372 colorAttachmentReferences[i] = attachmentRef;
373 depthStencilAttachmentReferences[i] = depthStencilAttachmentRef;
374
375 const VkAttachmentReference *pDepthStencilAttachment =
376 (depthStencilFormat != VK_FORMAT_UNDEFINED ? &depthStencilAttachmentReferences[i] : DE_NULL);
377 const VkSubpassDescription subpassDescription = {
378 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
379 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
380 0u, // uint32_t inputAttachmentCount;
381 DE_NULL, // const VkAttachmentReference* pInputAttachments;
382 1u, // uint32_t colorAttachmentCount;
383 &colorAttachmentReferences[i], // const VkAttachmentReference* pColorAttachments;
384 DE_NULL, // const VkAttachmentReference* pResolveAttachments;
385 pDepthStencilAttachment, // const VkAttachmentReference* pDepthStencilAttachment;
386 0u, // uint32_t preserveAttachmentCount;
387 DE_NULL // const uint32_t* pPreserveAttachments;
388 };
389 subpasses.push_back(subpassDescription);
390 }
391
392 const VkRenderPassCreateInfo renderPassInfo = {
393 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
394 DE_NULL, // const void* pNext;
395 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
396 static_cast<uint32_t>(attachmentDescriptions.size()), // uint32_t attachmentCount;
397 &attachmentDescriptions[0], // const VkAttachmentDescription* pAttachments;
398 static_cast<uint32_t>(subpasses.size()), // uint32_t subpassCount;
399 &subpasses[0], // const VkSubpassDescription* pSubpasses;
400 0u, // uint32_t dependencyCount;
401 DE_NULL // const VkSubpassDependency* pDependencies;
402 };
403
404 return RenderPassWrapper(pipelineConstructionType, vk, device, &renderPassInfo);
405 }
406
makeImage(const DeviceInterface & vk,const VkDevice device,VkImageCreateFlags flags,VkImageType imageType,const VkFormat format,const IVec3 & size,const uint32_t numMipLevels,const uint32_t numLayers,const VkImageUsageFlags usage)407 Move<VkImage> makeImage(const DeviceInterface &vk, const VkDevice device, VkImageCreateFlags flags,
408 VkImageType imageType, const VkFormat format, const IVec3 &size, const uint32_t numMipLevels,
409 const uint32_t numLayers, const VkImageUsageFlags usage)
410 {
411 const VkImageCreateInfo imageParams = {
412 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
413 DE_NULL, // const void* pNext;
414 flags, // VkImageCreateFlags flags;
415 imageType, // VkImageType imageType;
416 format, // VkFormat format;
417 makeExtent3D(size), // VkExtent3D extent;
418 numMipLevels, // uint32_t mipLevels;
419 numLayers, // uint32_t arrayLayers;
420 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
421 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
422 usage, // VkImageUsageFlags usage;
423 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
424 0u, // uint32_t queueFamilyIndexCount;
425 DE_NULL, // const uint32_t* pQueueFamilyIndices;
426 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
427 };
428 return createImage(vk, device, &imageParams);
429 }
430
makeColorSubresourceRange(const int baseArrayLayer,const int layerCount)431 inline VkImageSubresourceRange makeColorSubresourceRange(const int baseArrayLayer, const int layerCount)
432 {
433 return makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, static_cast<uint32_t>(baseArrayLayer),
434 static_cast<uint32_t>(layerCount));
435 }
436
437 //! Get a reference clear value based on color format.
getClearValue(const VkFormat format)438 VkClearValue getClearValue(const VkFormat format)
439 {
440 if (isUintFormat(format) || isIntFormat(format))
441 return makeClearValueColorU32(REFERENCE_COLOR_VALUE, REFERENCE_COLOR_VALUE, REFERENCE_COLOR_VALUE,
442 REFERENCE_COLOR_VALUE);
443 else
444 return makeClearValueColorF32(1.0f, 1.0f, 1.0f, 1.0f);
445 }
446
getColorFormatStr(const int numComponents,const bool isUint,const bool isSint)447 std::string getColorFormatStr(const int numComponents, const bool isUint, const bool isSint)
448 {
449 std::ostringstream str;
450 if (numComponents == 1)
451 str << (isUint ? "uint" : isSint ? "int" : "float");
452 else
453 str << (isUint ? "u" : isSint ? "i" : "") << "vec" << numComponents;
454
455 return str.str();
456 }
457
458 //! A half-viewport quad. Use with TRIANGLE_STRIP topology.
genFullQuadVertices(const int subpassCount)459 vector<Vertex4RGBA> genFullQuadVertices(const int subpassCount)
460 {
461 vector<Vertex4RGBA> vectorData;
462 for (int subpassNdx = 0; subpassNdx < subpassCount; ++subpassNdx)
463 {
464 Vertex4RGBA data = {
465 Vec4(0.0f, -1.0f, 0.0f, 1.0f),
466 COLOR_TABLE[subpassNdx % DE_LENGTH_OF_ARRAY(COLOR_TABLE)],
467 };
468 vectorData.push_back(data);
469 data.position = Vec4(0.0f, 1.0f, 0.0f, 1.0f);
470 vectorData.push_back(data);
471 data.position = Vec4(1.0f, -1.0f, 0.0f, 1.0f);
472 vectorData.push_back(data);
473 data.position = Vec4(1.0f, 1.0f, 0.0f, 1.0f);
474 vectorData.push_back(data);
475 }
476 return vectorData;
477 }
478
getImageType(const VkImageViewType viewType)479 VkImageType getImageType(const VkImageViewType viewType)
480 {
481 switch (viewType)
482 {
483 case VK_IMAGE_VIEW_TYPE_1D:
484 case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
485 return VK_IMAGE_TYPE_1D;
486
487 case VK_IMAGE_VIEW_TYPE_2D:
488 case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
489 case VK_IMAGE_VIEW_TYPE_CUBE:
490 case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
491 return VK_IMAGE_TYPE_2D;
492
493 case VK_IMAGE_VIEW_TYPE_3D:
494 return VK_IMAGE_TYPE_3D;
495
496 default:
497 DE_ASSERT(0);
498 return VK_IMAGE_TYPE_LAST;
499 }
500 }
501
502 //! ImageViewType for accessing a single layer/slice of an image
getImageViewSliceType(const VkImageViewType viewType)503 VkImageViewType getImageViewSliceType(const VkImageViewType viewType)
504 {
505 switch (viewType)
506 {
507 case VK_IMAGE_VIEW_TYPE_1D:
508 case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
509 return VK_IMAGE_VIEW_TYPE_1D;
510
511 case VK_IMAGE_VIEW_TYPE_2D:
512 case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
513 case VK_IMAGE_VIEW_TYPE_CUBE:
514 case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
515 case VK_IMAGE_VIEW_TYPE_3D:
516 return VK_IMAGE_VIEW_TYPE_2D;
517
518 default:
519 DE_ASSERT(0);
520 return VK_IMAGE_VIEW_TYPE_LAST;
521 }
522 }
523
getImageCreateFlags(const VkImageViewType viewType)524 VkImageCreateFlags getImageCreateFlags(const VkImageViewType viewType)
525 {
526 VkImageCreateFlags flags = (VkImageCreateFlags)0;
527
528 if (viewType == VK_IMAGE_VIEW_TYPE_3D)
529 flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
530 if (isCube(viewType))
531 flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
532
533 return flags;
534 }
535
generateExpectedImage(const tcu::PixelBufferAccess & outputImage,const IVec2 & renderSize,const int colorDepthOffset)536 void generateExpectedImage(const tcu::PixelBufferAccess &outputImage, const IVec2 &renderSize,
537 const int colorDepthOffset)
538 {
539 const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(outputImage.getFormat().type);
540 const bool isInt = (channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER ||
541 channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
542 const VkClearValue clearValue = getClearValue(mapTextureFormat(outputImage.getFormat()));
543
544 if (isInt)
545 tcu::clear(outputImage, IVec4(clearValue.color.int32));
546 else
547 tcu::clear(outputImage, Vec4(clearValue.color.float32));
548
549 for (int z = 0; z < outputImage.getDepth(); ++z)
550 {
551 const Vec4 &setColor = COLOR_TABLE[(z + colorDepthOffset) % DE_LENGTH_OF_ARRAY(COLOR_TABLE)];
552 const IVec4 setColorInt = (static_cast<float>(REFERENCE_COLOR_VALUE) * setColor).cast<int32_t>();
553
554 for (int y = 0; y < renderSize.y(); ++y)
555 for (int x = renderSize.x() / 2; x < renderSize.x(); ++x)
556 {
557 if (isInt)
558 outputImage.setPixel(setColorInt, x, y, z);
559 else
560 outputImage.setPixel(setColor, x, y, z);
561 }
562 }
563 }
564
getMaxImageSize(const VkImageViewType viewType,const IVec4 & sizeHint)565 IVec4 getMaxImageSize(const VkImageViewType viewType, const IVec4 &sizeHint)
566 {
567 //Limits have been taken from the vulkan specification
568 IVec4 size = IVec4(sizeHint.x() != MAX_SIZE ? sizeHint.x() : 4096, sizeHint.y() != MAX_SIZE ? sizeHint.y() : 4096,
569 sizeHint.z() != MAX_SIZE ? sizeHint.z() : 256, sizeHint.w() != MAX_SIZE ? sizeHint.w() : 256);
570
571 switch (viewType)
572 {
573 case VK_IMAGE_VIEW_TYPE_1D:
574 case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
575 size.x() = deMin32(4096, size.x());
576 break;
577
578 case VK_IMAGE_VIEW_TYPE_2D:
579 case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
580 size.x() = deMin32(4096, size.x());
581 size.y() = deMin32(4096, size.y());
582 break;
583
584 case VK_IMAGE_VIEW_TYPE_3D:
585 size.x() = deMin32(256, size.x());
586 size.y() = deMin32(256, size.y());
587 break;
588
589 case VK_IMAGE_VIEW_TYPE_CUBE:
590 case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
591 size.x() = deMin32(4096, size.x());
592 size.y() = deMin32(4096, size.y());
593 size.w() = deMin32(252, size.w());
594 size.w() = NUM_CUBE_FACES * (size.w() / NUM_CUBE_FACES); // round down to 6 faces
595 break;
596
597 default:
598 DE_ASSERT(0);
599 return IVec4();
600 }
601
602 return size;
603 }
604
605 //! Get a smaller image size. Returns a vector of zeroes, if it can't reduce more.
getReducedImageSize(const CaseDef & caseDef,IVec4 size)606 IVec4 getReducedImageSize(const CaseDef &caseDef, IVec4 size)
607 {
608 const int maxIndex = findIndexOfMaxComponent(size);
609 const int reducedSize = size[maxIndex] >> 1;
610
611 switch (caseDef.viewType)
612 {
613 case VK_IMAGE_VIEW_TYPE_CUBE:
614 case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
615 if (maxIndex < 2)
616 size.x() = size.y() = reducedSize;
617 else if (maxIndex == 3 && reducedSize >= NUM_CUBE_FACES)
618 size.w() = NUM_CUBE_FACES * (reducedSize / NUM_CUBE_FACES); // round down to a multiple of 6
619 else
620 size = IVec4(0);
621 break;
622
623 default:
624 size[maxIndex] = reducedSize;
625 break;
626 }
627
628 if (reducedSize == 0)
629 size = IVec4(0);
630
631 return size;
632 }
633
634 //! Get the image memory requirements for the image size under test, expecting potential image
635 //! creation failure if the required size is larger than the device's maxResourceSize, returning
636 //! false if creation failed.
getSupportedImageMemoryRequirements(Context & context,const CaseDef & caseDef,const VkFormat format,const IVec4 size,const VkImageUsageFlags usage,VkMemoryRequirements & imageMemoryRequiements)637 bool getSupportedImageMemoryRequirements(Context &context, const CaseDef &caseDef, const VkFormat format,
638 const IVec4 size, const VkImageUsageFlags usage,
639 VkMemoryRequirements &imageMemoryRequiements)
640 {
641 const DeviceInterface &vk = context.getDeviceInterface();
642 const VkDevice device = context.getDevice();
643 bool imageCreationPossible = true;
644
645 try
646 {
647 Move<VkImage> image =
648 makeImage(vk, device, getImageCreateFlags(caseDef.viewType), getImageType(caseDef.viewType), format,
649 size.swizzle(0, 1, 2), 1u, size.w(), usage);
650
651 vk.getImageMemoryRequirements(device, *image, &imageMemoryRequiements);
652 }
653 // vkCreateImage is allowed to return VK_ERROR_OUT_OF_HOST_MEMORY if the image's
654 // memory requirements will exceed maxResourceSize.
655 catch (const vk::OutOfMemoryError &)
656 {
657 imageCreationPossible = false;
658 }
659
660 return imageCreationPossible;
661 }
662
isDepthStencilFormatSupported(const InstanceInterface & vki,const VkPhysicalDevice physDevice,const VkFormat format)663 bool isDepthStencilFormatSupported(const InstanceInterface &vki, const VkPhysicalDevice physDevice,
664 const VkFormat format)
665 {
666 const VkFormatProperties properties = getPhysicalDeviceFormatProperties(vki, physDevice, format);
667 return (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0;
668 }
669
getFormatAspectFlags(const VkFormat format)670 VkImageAspectFlags getFormatAspectFlags(const VkFormat format)
671 {
672 if (format == VK_FORMAT_UNDEFINED)
673 return 0;
674
675 const tcu::TextureFormat::ChannelOrder order = mapVkFormat(format).order;
676
677 switch (order)
678 {
679 case tcu::TextureFormat::DS:
680 return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
681 case tcu::TextureFormat::D:
682 return VK_IMAGE_ASPECT_DEPTH_BIT;
683 case tcu::TextureFormat::S:
684 return VK_IMAGE_ASPECT_STENCIL_BIT;
685 default:
686 return VK_IMAGE_ASPECT_COLOR_BIT;
687 }
688 }
689
initPrograms(SourceCollections & programCollection,const CaseDef caseDef)690 void initPrograms(SourceCollections &programCollection, const CaseDef caseDef)
691 {
692 const int numComponents = getNumUsedChannels(mapVkFormat(caseDef.colorFormat).order);
693 const bool isUint = isUintFormat(caseDef.colorFormat);
694 const bool isSint = isIntFormat(caseDef.colorFormat);
695
696 // Vertex shader
697 {
698 std::ostringstream src;
699 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
700 << "\n"
701 << "layout(location = 0) in vec4 in_position;\n"
702 << "layout(location = 1) in vec4 in_color;\n"
703 << "layout(location = 0) out vec4 out_color;\n"
704 << "\n"
705 << "out gl_PerVertex {\n"
706 << " vec4 gl_Position;\n"
707 << "};\n"
708 << "\n"
709 << "void main(void)\n"
710 << "{\n"
711 << " gl_Position = in_position;\n"
712 << " out_color = in_color;\n"
713 << "}\n";
714
715 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
716 }
717
718 // Fragment shader
719 {
720 std::ostringstream colorValue;
721 colorValue << REFERENCE_COLOR_VALUE;
722 const std::string colorFormat = getColorFormatStr(numComponents, isUint, isSint);
723 const std::string colorInteger = (isUint || isSint ? " * " + colorFormat + "(" + colorValue.str() + ")" : "");
724
725 std::ostringstream src;
726 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
727 << "\n"
728 << "layout(location = 0) in vec4 in_color;\n"
729 << "layout(location = 0) out " << colorFormat << " o_color;\n"
730 << "\n"
731 << "void main(void)\n"
732 << "{\n"
733 << " o_color = " << colorFormat << "("
734 << (numComponents == 1 ? "in_color.r" :
735 numComponents == 2 ? "in_color.rg" :
736 numComponents == 3 ? "in_color.rgb" :
737 "in_color")
738 << colorInteger << ");\n"
739 << "}\n";
740
741 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
742 }
743 }
744
745 //! See testAttachmentSize() description
testWithSizeReduction(Context & context,const CaseDef & caseDef)746 tcu::TestStatus testWithSizeReduction(Context &context, const CaseDef &caseDef)
747 {
748 const DeviceInterface &vk = context.getDeviceInterface();
749 const InstanceInterface &vki = context.getInstanceInterface();
750 const VkDevice device = context.getDevice();
751 const VkPhysicalDevice physDevice = context.getPhysicalDevice();
752 const VkQueue queue = context.getUniversalQueue();
753 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
754 Allocator &allocator = context.getDefaultAllocator();
755
756 IVec4 imageSize = getMaxImageSize(caseDef.viewType, caseDef.imageSizeHint);
757
758 const VkImageUsageFlags colorImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
759 const VkImageUsageFlags depthStencilImageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
760 const bool useDepthStencil = (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED);
761
762 {
763 VkImageFormatProperties colorImageFormatProperties;
764 const auto result = vki.getPhysicalDeviceImageFormatProperties(
765 physDevice, caseDef.colorFormat, getImageType(caseDef.viewType), VK_IMAGE_TILING_OPTIMAL, colorImageUsage,
766 getImageCreateFlags(caseDef.viewType), &colorImageFormatProperties);
767
768 VK_CHECK(result);
769
770 imageSize.x() = std::min(static_cast<uint32_t>(imageSize.x()), colorImageFormatProperties.maxExtent.width);
771 imageSize.y() = std::min(static_cast<uint32_t>(imageSize.y()), colorImageFormatProperties.maxExtent.height);
772 imageSize.z() = std::min(static_cast<uint32_t>(imageSize.z()), colorImageFormatProperties.maxExtent.depth);
773 imageSize.w() = std::min(static_cast<uint32_t>(imageSize.w()), colorImageFormatProperties.maxArrayLayers);
774 }
775
776 if (useDepthStencil)
777 {
778 VkImageFormatProperties depthStencilImageFormatProperties;
779 const auto result = vki.getPhysicalDeviceImageFormatProperties(
780 physDevice, caseDef.depthStencilFormat, getImageType(caseDef.viewType), VK_IMAGE_TILING_OPTIMAL,
781 depthStencilImageUsage, getImageCreateFlags(caseDef.viewType), &depthStencilImageFormatProperties);
782
783 VK_CHECK(result);
784
785 imageSize.x() =
786 std::min(static_cast<uint32_t>(imageSize.x()), depthStencilImageFormatProperties.maxExtent.width);
787 imageSize.y() =
788 std::min(static_cast<uint32_t>(imageSize.y()), depthStencilImageFormatProperties.maxExtent.height);
789 imageSize.z() =
790 std::min(static_cast<uint32_t>(imageSize.z()), depthStencilImageFormatProperties.maxExtent.depth);
791 imageSize.w() =
792 std::min(static_cast<uint32_t>(imageSize.w()), depthStencilImageFormatProperties.maxArrayLayers);
793 }
794
795 bool allocationPossible = false;
796 while (!allocationPossible)
797 {
798 // Get the image memory requirements
799 VkMemoryRequirements colorImageMemReqs;
800 VkDeviceSize neededMemory = 0;
801 uint32_t memoryTypeNdx = 0;
802
803 if (!getSupportedImageMemoryRequirements(context, caseDef, caseDef.colorFormat, imageSize, colorImageUsage,
804 colorImageMemReqs))
805 {
806 // Try again with reduced image size
807 imageSize = getReducedImageSize(caseDef, imageSize);
808 if (imageSize == IVec4())
809 return tcu::TestStatus::fail("Couldn't create an image with required size");
810 else
811 continue;
812 }
813
814 neededMemory = colorImageMemReqs.size;
815
816 if (useDepthStencil)
817 {
818 VkMemoryRequirements depthStencilImageMemReqs;
819
820 if (!getSupportedImageMemoryRequirements(context, caseDef, caseDef.depthStencilFormat, imageSize,
821 depthStencilImageUsage, depthStencilImageMemReqs))
822 {
823 // Try again with reduced image size
824 imageSize = getReducedImageSize(caseDef, imageSize);
825 if (imageSize == IVec4())
826 return tcu::TestStatus::fail("Couldn't create an image with required size");
827 else
828 continue;
829 }
830
831 neededMemory += depthStencilImageMemReqs.size;
832 }
833
834 // Reserve an additional 15% device memory, plus the 512KB for checking results
835 {
836 const VkDeviceSize reserveForChecking = 500ull * 1024ull;
837 const float additionalMemory = 1.15f;
838 neededMemory =
839 static_cast<VkDeviceSize>(static_cast<float>(neededMemory) * additionalMemory) + reserveForChecking;
840 }
841
842 // Query the available memory in the corresponding memory heap
843 {
844 const VkPhysicalDeviceMemoryProperties memoryProperties =
845 getPhysicalDeviceMemoryProperties(vki, physDevice);
846 // Use the color image memory requirements, assume depth stencil uses the same memory type
847 memoryTypeNdx =
848 selectMatchingMemoryType(memoryProperties, colorImageMemReqs.memoryTypeBits, MemoryRequirement::Any);
849 tcu::PlatformMemoryLimits memoryLimits;
850 context.getTestContext().getPlatform().getMemoryLimits(memoryLimits);
851 VkDeviceSize maxMemory =
852 std::min(memoryProperties.memoryHeaps[memoryProperties.memoryTypes[memoryTypeNdx].heapIndex].size,
853 VkDeviceSize(memoryLimits.totalSystemMemory));
854
855 if (neededMemory > maxMemory)
856 {
857 // Try again with reduced image size
858 imageSize = getReducedImageSize(caseDef, imageSize);
859 if (imageSize == IVec4())
860 return tcu::TestStatus::fail("Couldn't create an image with required size");
861 else
862 continue;
863 }
864 }
865
866 // Attempt a memory allocation
867 {
868 VkDeviceMemory object = 0;
869 const VkMemoryAllocateInfo allocateInfo = {
870 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, //VkStructureType sType;
871 DE_NULL, //const void* pNext;
872 neededMemory, //VkDeviceSize allocationSize;
873 memoryTypeNdx //uint32_t memoryTypeIndex;
874 };
875
876 const VkResult result = vk.allocateMemory(device, &allocateInfo, DE_NULL, &object);
877
878 if (VK_ERROR_OUT_OF_DEVICE_MEMORY == result || VK_ERROR_OUT_OF_HOST_MEMORY == result)
879 {
880 // Try again with reduced image size
881 imageSize = getReducedImageSize(caseDef, imageSize);
882 if (imageSize == IVec4())
883 return tcu::TestStatus::fail("Couldn't create an image with required size");
884 }
885 else if (VK_SUCCESS != result)
886 {
887 return tcu::TestStatus::fail("Couldn't allocate memory");
888 }
889 else
890 {
891 //free memory using Move pointer
892 Move<VkDeviceMemory> memoryAllocated(check<VkDeviceMemory>(object),
893 Deleter<VkDeviceMemory>(vk, device, DE_NULL));
894 allocationPossible = true;
895 }
896 }
897 }
898
899 context.getTestContext().getLog() << tcu::TestLog::Message
900 << "Using an image with size (width, height, depth, layers) = " << imageSize
901 << tcu::TestLog::EndMessage;
902
903 // "Slices" is either the depth of a 3D image, or the number of layers of an arrayed image
904 const int32_t numSlices = maxLayersOrDepth(imageSize);
905
906 // Determine the verification bounds. The checked region will be in the center of the rendered image
907 const IVec4 checkSize = tcu::min(imageSize, IVec4(MAX_VERIFICATION_REGION_SIZE, MAX_VERIFICATION_REGION_SIZE,
908 MAX_VERIFICATION_REGION_DEPTH, MAX_VERIFICATION_REGION_DEPTH));
909 const IVec4 checkOffset = (imageSize - checkSize) / 2;
910
911 // Only make enough space for the check region
912 const VkDeviceSize colorBufferSize = product(checkSize) * tcu::getPixelSize(mapVkFormat(caseDef.colorFormat));
913 const Unique<VkBuffer> colorBuffer(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
914 const UniquePtr<Allocation> colorBufferAlloc(bindBuffer(
915 vki, vk, physDevice, device, *colorBuffer, MemoryRequirement::HostVisible, allocator, caseDef.allocationKind));
916
917 {
918 deMemset(colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
919 flushAlloc(vk, device, *colorBufferAlloc);
920 }
921
922 const ShaderWrapper vertexModule(ShaderWrapper(vk, device, context.getBinaryCollection().get("vert"), 0u));
923 const ShaderWrapper fragmentModule(ShaderWrapper(vk, device, context.getBinaryCollection().get("frag"), 0u));
924 RenderPassWrapper renderPass(makeRenderPass(vk, device, caseDef.pipelineConstructionType, caseDef.colorFormat,
925 caseDef.depthStencilFormat, static_cast<uint32_t>(numSlices),
926 (caseDef.viewType == VK_IMAGE_VIEW_TYPE_3D) ?
927 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL :
928 VK_IMAGE_LAYOUT_UNDEFINED));
929 const PipelineLayoutWrapper pipelineLayout(caseDef.pipelineConstructionType, vk, device);
930 vector<GraphicsPipelineWrapper> pipelines;
931
932 Move<VkImage> colorImage;
933 MovePtr<Allocation> colorImageAlloc;
934 vector<SharedPtrVkImageView> colorAttachments;
935 Move<VkImage> depthStencilImage;
936 MovePtr<Allocation> depthStencilImageAlloc;
937 vector<SharedPtrVkImageView> depthStencilAttachments;
938 vector<VkImage> images;
939 vector<VkImageView> attachmentHandles; // all attachments (color and d/s)
940 Move<VkBuffer> vertexBuffer;
941 MovePtr<Allocation> vertexBufferAlloc;
942
943 // Create a color image
944 {
945 colorImage = makeImage(vk, device, getImageCreateFlags(caseDef.viewType), getImageType(caseDef.viewType),
946 caseDef.colorFormat, imageSize.swizzle(0, 1, 2), 1u, imageSize.w(), colorImageUsage);
947 colorImageAlloc = bindImage(vki, vk, physDevice, device, *colorImage, MemoryRequirement::Any, allocator,
948 caseDef.allocationKind);
949 }
950
951 // Create a depth/stencil image (always a 2D image, optionally layered)
952 if (useDepthStencil)
953 {
954 depthStencilImage = makeImage(vk, device, (VkImageCreateFlags)0, VK_IMAGE_TYPE_2D, caseDef.depthStencilFormat,
955 IVec3(imageSize.x(), imageSize.y(), 1), 1u, numSlices, depthStencilImageUsage);
956 depthStencilImageAlloc = bindImage(vki, vk, physDevice, device, *depthStencilImage, MemoryRequirement::Any,
957 allocator, caseDef.allocationKind);
958 }
959
960 // Create a vertex buffer
961 {
962 const vector<Vertex4RGBA> vertices = genFullQuadVertices(numSlices);
963 const VkDeviceSize vertexBufferSize = sizeInBytes(vertices);
964
965 vertexBuffer = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
966 vertexBufferAlloc = bindBuffer(vki, vk, physDevice, device, *vertexBuffer, MemoryRequirement::HostVisible,
967 allocator, caseDef.allocationKind);
968
969 deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
970 flushAlloc(vk, device, *vertexBufferAlloc);
971 }
972
973 // Prepare color image upfront for rendering to individual slices. 3D slices aren't separate subresources, so they shouldn't be transitioned
974 // during each subpass like array layers.
975 if (caseDef.viewType == VK_IMAGE_VIEW_TYPE_3D)
976 {
977 const Unique<VkCommandPool> cmdPool(
978 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
979 const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
980
981 beginCommandBuffer(vk, *cmdBuffer);
982
983 const VkImageMemoryBarrier imageBarrier = {
984 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
985 DE_NULL, // const void* pNext;
986 (VkAccessFlags)0, // VkAccessFlags srcAccessMask;
987 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask;
988 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
989 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout;
990 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
991 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
992 *colorImage, // VkImage image;
993 {
994 // VkImageSubresourceRange subresourceRange;
995 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
996 0u, // uint32_t baseMipLevel;
997 1u, // uint32_t levelCount;
998 0u, // uint32_t baseArrayLayer;
999 static_cast<uint32_t>(imageSize.w()), // uint32_t layerCount;
1000 }};
1001
1002 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1003 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u,
1004 &imageBarrier);
1005
1006 endCommandBuffer(vk, *cmdBuffer);
1007 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1008 }
1009
1010 // For each image layer or slice (3D), create an attachment and a pipeline
1011 {
1012 const VkImageAspectFlags depthStencilAspect = getFormatAspectFlags(caseDef.depthStencilFormat);
1013 const bool useDepth = (depthStencilAspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
1014 const bool useStencil = (depthStencilAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
1015 VkPipeline basePipeline = DE_NULL;
1016
1017 // Color attachments are first in the framebuffer
1018 pipelines.reserve(numSlices);
1019 for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
1020 {
1021 colorAttachments.push_back(
1022 makeSharedPtr(makeImageView(vk, device, *colorImage, getImageViewSliceType(caseDef.viewType),
1023 caseDef.colorFormat, makeColorSubresourceRange(subpassNdx, 1))));
1024 images.push_back(*colorImage);
1025 attachmentHandles.push_back(**colorAttachments.back());
1026
1027 #ifndef CTS_USES_VULKANSC // Pipeline derivatives are forbidden in Vulkan SC
1028 // We also have to create pipelines for each subpass
1029 pipelines.emplace_back(vki, vk, physDevice, device, context.getDeviceExtensions(),
1030 caseDef.pipelineConstructionType,
1031 (basePipeline == DE_NULL ? VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT :
1032 VK_PIPELINE_CREATE_DERIVATIVE_BIT));
1033 #else
1034 pipelines.emplace_back(vki, vk, physDevice, device, context.getDeviceExtensions(),
1035 caseDef.pipelineConstructionType, 0u);
1036 #endif // CTS_USES_VULKANSC
1037 preparePipelineWrapper(pipelines.back(), basePipeline, pipelineLayout, *renderPass, vertexModule,
1038 fragmentModule, imageSize.swizzle(0, 1), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
1039 static_cast<uint32_t>(subpassNdx), useDepth, useStencil);
1040
1041 if (pipelines.front().wasBuild())
1042 basePipeline = pipelines.front().getPipeline();
1043 }
1044
1045 // Then D/S attachments, if any
1046 if (useDepthStencil)
1047 for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
1048 {
1049 depthStencilAttachments.push_back(makeSharedPtr(
1050 makeImageView(vk, device, *depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, caseDef.depthStencilFormat,
1051 makeImageSubresourceRange(depthStencilAspect, 0u, 1u, subpassNdx, 1u))));
1052 images.push_back(*depthStencilImage);
1053 attachmentHandles.push_back(**depthStencilAttachments.back());
1054 }
1055 }
1056
1057 renderPass.createFramebuffer(vk, device, static_cast<uint32_t>(attachmentHandles.size()), &images[0],
1058 &attachmentHandles[0], static_cast<uint32_t>(imageSize.x()),
1059 static_cast<uint32_t>(imageSize.y()));
1060
1061 {
1062 const Unique<VkCommandPool> cmdPool(
1063 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1064 const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
1065
1066 beginCommandBuffer(vk, *cmdBuffer);
1067 {
1068 vector<VkClearValue> clearValues(numSlices, getClearValue(caseDef.colorFormat));
1069
1070 if (useDepthStencil)
1071 clearValues.insert(clearValues.end(), numSlices,
1072 makeClearValueDepthStencil(REFERENCE_DEPTH_VALUE, REFERENCE_STENCIL_VALUE));
1073
1074 const VkDeviceSize vertexBufferOffset = 0ull;
1075
1076 renderPass.begin(vk, *cmdBuffer, makeRect2D(0, 0, imageSize.x(), imageSize.y()),
1077 (uint32_t)clearValues.size(), &clearValues[0]);
1078 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
1079 }
1080
1081 // Draw
1082 for (uint32_t subpassNdx = 0; subpassNdx < static_cast<uint32_t>(numSlices); ++subpassNdx)
1083 {
1084 if (subpassNdx != 0)
1085 renderPass.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
1086
1087 pipelines[subpassNdx].bind(*cmdBuffer);
1088 vk.cmdDraw(*cmdBuffer, 4u, 1u, subpassNdx * 4u, 0u);
1089 }
1090
1091 renderPass.end(vk, *cmdBuffer);
1092
1093 // Copy colorImage -> host visible colorBuffer
1094 {
1095 const VkImageMemoryBarrier imageBarriers[] = {{
1096 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1097 DE_NULL, // const void* pNext;
1098 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags outputMask;
1099 VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags inputMask;
1100 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout;
1101 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout;
1102 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1103 VK_QUEUE_FAMILY_IGNORED, // uint32_t destQueueFamilyIndex;
1104 *colorImage, // VkImage image;
1105 makeColorSubresourceRange(0, imageSize.w()) // VkImageSubresourceRange subresourceRange;
1106 }};
1107
1108 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1109 VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL,
1110 DE_LENGTH_OF_ARRAY(imageBarriers), imageBarriers);
1111
1112 // Copy the checked region rather than the whole image
1113 const VkImageSubresourceLayers subresource = {
1114 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
1115 0u, // uint32_t mipLevel;
1116 static_cast<uint32_t>(checkOffset.w()), // uint32_t baseArrayLayer;
1117 static_cast<uint32_t>(checkSize.w()), // uint32_t layerCount;
1118 };
1119
1120 const VkBufferImageCopy region = {
1121 0ull, // VkDeviceSize bufferOffset;
1122 0u, // uint32_t bufferRowLength;
1123 0u, // uint32_t bufferImageHeight;
1124 subresource, // VkImageSubresourceLayers imageSubresource;
1125 makeOffset3D(checkOffset.x(), checkOffset.y(),
1126 checkOffset.z()), // VkOffset3D imageOffset;
1127 makeExtent3D(checkSize.swizzle(0, 1, 2)), // VkExtent3D imageExtent;
1128 };
1129
1130 vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u,
1131 ®ion);
1132
1133 const VkBufferMemoryBarrier bufferBarriers[] = {
1134 {
1135 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
1136 DE_NULL, // const void* pNext;
1137 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
1138 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
1139 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1140 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1141 *colorBuffer, // VkBuffer buffer;
1142 0ull, // VkDeviceSize offset;
1143 VK_WHOLE_SIZE, // VkDeviceSize size;
1144 },
1145 };
1146
1147 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u,
1148 DE_NULL, DE_LENGTH_OF_ARRAY(bufferBarriers), bufferBarriers, 0u, DE_NULL);
1149 }
1150
1151 endCommandBuffer(vk, *cmdBuffer);
1152 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1153 }
1154
1155 // Verify results
1156 {
1157 invalidateAlloc(vk, device, *colorBufferAlloc);
1158
1159 const tcu::TextureFormat format = mapVkFormat(caseDef.colorFormat);
1160 const int checkDepth = maxLayersOrDepth(checkSize);
1161 const int depthOffset = maxLayersOrDepth(checkOffset);
1162 const tcu::ConstPixelBufferAccess resultImage(format, checkSize.x(), checkSize.y(), checkDepth,
1163 colorBufferAlloc->getHostPtr());
1164 tcu::TextureLevel textureLevel(format, checkSize.x(), checkSize.y(), checkDepth);
1165 const tcu::PixelBufferAccess expectedImage = textureLevel.getAccess();
1166 bool ok = false;
1167
1168 generateExpectedImage(expectedImage, checkSize.swizzle(0, 1), depthOffset);
1169
1170 if (isFloatFormat(caseDef.colorFormat))
1171 ok = tcu::floatThresholdCompare(context.getTestContext().getLog(), "Image Comparison", "", expectedImage,
1172 resultImage, tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
1173 else
1174 ok = tcu::intThresholdCompare(context.getTestContext().getLog(), "Image Comparison", "", expectedImage,
1175 resultImage, tcu::UVec4(2), tcu::COMPARE_LOG_RESULT);
1176
1177 return ok ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
1178 }
1179 }
1180
checkImageViewTypeRequirements(Context & context,const VkImageViewType viewType)1181 void checkImageViewTypeRequirements(Context &context, const VkImageViewType viewType)
1182 {
1183 #ifndef CTS_USES_VULKANSC
1184 if (viewType == VK_IMAGE_VIEW_TYPE_3D)
1185 {
1186 if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
1187 !context.getPortabilitySubsetFeatures().imageView2DOn3DImage)
1188 {
1189 TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Implementation does not support 2D or 2D array "
1190 "image view to be created on a 3D VkImage");
1191 }
1192
1193 context.requireDeviceFunctionality("VK_KHR_maintenance1");
1194 }
1195 #endif // CTS_USES_VULKANSC
1196
1197 if (viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
1198 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_IMAGE_CUBE_ARRAY);
1199 }
1200
checkSupportAttachmentSize(Context & context,const CaseDef caseDef)1201 void checkSupportAttachmentSize(Context &context, const CaseDef caseDef)
1202 {
1203 const InstanceInterface &vki = context.getInstanceInterface();
1204 const VkPhysicalDevice physDevice = context.getPhysicalDevice();
1205
1206 checkImageViewTypeRequirements(context, caseDef.viewType);
1207
1208 if (caseDef.allocationKind == ALLOCATION_KIND_DEDICATED)
1209 context.requireDeviceFunctionality("VK_KHR_dedicated_allocation");
1210
1211 {
1212 VkImageFormatProperties colorImageFormatProperties;
1213 const auto result = vki.getPhysicalDeviceImageFormatProperties(
1214 physDevice, caseDef.colorFormat, getImageType(caseDef.viewType), VK_IMAGE_TILING_OPTIMAL,
1215 (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT),
1216 getImageCreateFlags(caseDef.viewType), &colorImageFormatProperties);
1217
1218 if (result != VK_SUCCESS)
1219 {
1220 TCU_THROW(NotSupportedError, "Unsupported color attachment format");
1221 }
1222 }
1223
1224 if (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED)
1225 {
1226
1227 VkImageFormatProperties depthStencilImageFormatProperties;
1228 const auto result = vki.getPhysicalDeviceImageFormatProperties(
1229 physDevice, caseDef.depthStencilFormat, getImageType(caseDef.viewType), VK_IMAGE_TILING_OPTIMAL,
1230 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, getImageCreateFlags(caseDef.viewType),
1231 &depthStencilImageFormatProperties);
1232
1233 if (result != VK_SUCCESS)
1234 {
1235 TCU_THROW(NotSupportedError, "Unsupported depth/stencil attachment format");
1236 }
1237 }
1238
1239 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1240 caseDef.pipelineConstructionType);
1241 }
1242
1243 //! A test that can exercise very big color and depth/stencil attachment sizes.
1244 //! If the total memory consumed by images is too large, or if the implementation returns OUT_OF_MEMORY error somewhere,
1245 //! the test can be retried with a next increment of size reduction index, making the attachments smaller.
testAttachmentSize(Context & context,const CaseDef caseDef)1246 tcu::TestStatus testAttachmentSize(Context &context, const CaseDef caseDef)
1247 {
1248 return testWithSizeReduction(context, caseDef);
1249 // Never reached
1250 }
1251
getMipLevelSizes(IVec4 baseSize)1252 vector<IVec4> getMipLevelSizes(IVec4 baseSize)
1253 {
1254 vector<IVec4> levels;
1255 levels.push_back(baseSize);
1256
1257 while (baseSize.x() != 1 || baseSize.y() != 1 || baseSize.z() != 1)
1258 {
1259 baseSize.x() = deMax32(baseSize.x() >> 1, 1);
1260 baseSize.y() = deMax32(baseSize.y() >> 1, 1);
1261 baseSize.z() = deMax32(baseSize.z() >> 1, 1);
1262 levels.push_back(baseSize);
1263 }
1264
1265 return levels;
1266 }
1267
1268 //! Compute memory consumed by each mip level, including all layers. Sizes include a padding for alignment.
getPerMipLevelStorageSize(const vector<IVec4> & mipLevelSizes,const VkDeviceSize pixelSize)1269 vector<VkDeviceSize> getPerMipLevelStorageSize(const vector<IVec4> &mipLevelSizes, const VkDeviceSize pixelSize)
1270 {
1271 const int64_t levelAlignment = 16;
1272 vector<VkDeviceSize> storageSizes;
1273
1274 for (vector<IVec4>::const_iterator it = mipLevelSizes.begin(); it != mipLevelSizes.end(); ++it)
1275 storageSizes.push_back(deAlign64(pixelSize * product(*it), levelAlignment));
1276
1277 return storageSizes;
1278 }
1279
drawToMipLevel(const Context & context,const CaseDef & caseDef,const int mipLevel,const IVec4 & mipSize,const int numSlices,const VkImage colorImage,const VkImage depthStencilImage,const VkBuffer vertexBuffer,const PipelineLayoutWrapper & pipelineLayout,const ShaderWrapper vertexModule,const ShaderWrapper fragmentModule)1280 void drawToMipLevel(const Context &context, const CaseDef &caseDef, const int mipLevel, const IVec4 &mipSize,
1281 const int numSlices, const VkImage colorImage, const VkImage depthStencilImage,
1282 const VkBuffer vertexBuffer, const PipelineLayoutWrapper &pipelineLayout,
1283 const ShaderWrapper vertexModule, const ShaderWrapper fragmentModule)
1284 {
1285 const InstanceInterface &vki = context.getInstanceInterface();
1286 const DeviceInterface &vk = context.getDeviceInterface();
1287 const VkPhysicalDevice physDevice = context.getPhysicalDevice();
1288 const VkDevice device = context.getDevice();
1289 const VkQueue queue = context.getUniversalQueue();
1290 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
1291 const VkImageAspectFlags depthStencilAspect = getFormatAspectFlags(caseDef.depthStencilFormat);
1292 const bool useDepth = (depthStencilAspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
1293 const bool useStencil = (depthStencilAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
1294 RenderPassWrapper renderPass(makeRenderPass(vk, device, caseDef.pipelineConstructionType, caseDef.colorFormat,
1295 caseDef.depthStencilFormat, static_cast<uint32_t>(numSlices),
1296 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1297 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));
1298 vector<GraphicsPipelineWrapper> pipelines;
1299 vector<SharedPtrVkImageView> colorAttachments;
1300 vector<SharedPtrVkImageView> depthStencilAttachments;
1301 vector<VkImage> images;
1302 vector<VkImageView> attachmentHandles; // all attachments (color and d/s)
1303
1304 // For each image layer or slice (3D), create an attachment and a pipeline
1305 {
1306 VkPipeline basePipeline = DE_NULL;
1307
1308 // Color attachments are first in the framebuffer
1309 pipelines.reserve(numSlices);
1310 for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
1311 {
1312 colorAttachments.push_back(makeSharedPtr(
1313 makeImageView(vk, device, colorImage, getImageViewSliceType(caseDef.viewType), caseDef.colorFormat,
1314 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 1u, subpassNdx, 1u))));
1315 images.push_back(colorImage);
1316 attachmentHandles.push_back(**colorAttachments.back());
1317
1318 // We also have to create pipelines for each subpass
1319 #ifndef CTS_USES_VULKANSC // Pipeline derivatives are forbidden in Vulkan SC
1320 pipelines.emplace_back(vki, vk, physDevice, device, context.getDeviceExtensions(),
1321 caseDef.pipelineConstructionType,
1322 (basePipeline == DE_NULL ? VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT :
1323 VK_PIPELINE_CREATE_DERIVATIVE_BIT));
1324 #else
1325 pipelines.emplace_back(vki, vk, physDevice, device, context.getDeviceExtensions(),
1326 caseDef.pipelineConstructionType, 0u);
1327 #endif // CTS_USES_VULKANSC
1328 preparePipelineWrapper(pipelines.back(), basePipeline, pipelineLayout, *renderPass, vertexModule,
1329 fragmentModule, mipSize.swizzle(0, 1), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
1330 static_cast<uint32_t>(subpassNdx), useDepth, useStencil);
1331
1332 if (pipelines.front().wasBuild())
1333 basePipeline = pipelines.front().getPipeline();
1334 }
1335
1336 // Then D/S attachments, if any
1337 if (useDepth || useStencil)
1338 for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
1339 {
1340 depthStencilAttachments.push_back(makeSharedPtr(
1341 makeImageView(vk, device, depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, caseDef.depthStencilFormat,
1342 makeImageSubresourceRange(depthStencilAspect, mipLevel, 1u, subpassNdx, 1u))));
1343 images.push_back(depthStencilImage);
1344 attachmentHandles.push_back(**depthStencilAttachments.back());
1345 }
1346 }
1347
1348 renderPass.createFramebuffer(vk, device, static_cast<uint32_t>(attachmentHandles.size()), &images[0],
1349 &attachmentHandles[0], static_cast<uint32_t>(mipSize.x()),
1350 static_cast<uint32_t>(mipSize.y()));
1351
1352 {
1353 const Unique<VkCommandPool> cmdPool(
1354 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1355 const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
1356
1357 beginCommandBuffer(vk, *cmdBuffer);
1358 {
1359 vector<VkClearValue> clearValues(numSlices, getClearValue(caseDef.colorFormat));
1360
1361 if (useDepth || useStencil)
1362 clearValues.insert(clearValues.end(), numSlices,
1363 makeClearValueDepthStencil(REFERENCE_DEPTH_VALUE, REFERENCE_STENCIL_VALUE));
1364
1365 const VkDeviceSize vertexBufferOffset = 0ull;
1366
1367 renderPass.begin(vk, *cmdBuffer, makeRect2D(0, 0, mipSize.x(), mipSize.y()), (uint32_t)clearValues.size(),
1368 &clearValues[0]);
1369 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset);
1370 }
1371
1372 // Draw
1373 for (uint32_t subpassNdx = 0; subpassNdx < static_cast<uint32_t>(numSlices); ++subpassNdx)
1374 {
1375 if (subpassNdx != 0)
1376 renderPass.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
1377
1378 pipelines[subpassNdx].bind(*cmdBuffer);
1379 vk.cmdDraw(*cmdBuffer, 4u, 1u, subpassNdx * 4u, 0u);
1380 }
1381
1382 renderPass.end(vk, *cmdBuffer);
1383
1384 endCommandBuffer(vk, *cmdBuffer);
1385 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1386 }
1387 }
1388
checkSupportRenderToMipMaps(Context & context,const CaseDef caseDef)1389 void checkSupportRenderToMipMaps(Context &context, const CaseDef caseDef)
1390 {
1391 checkImageViewTypeRequirements(context, caseDef.viewType);
1392
1393 if (caseDef.allocationKind == ALLOCATION_KIND_DEDICATED)
1394 context.requireDeviceFunctionality("VK_KHR_dedicated_allocation");
1395
1396 if (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED &&
1397 !isDepthStencilFormatSupported(context.getInstanceInterface(), context.getPhysicalDevice(),
1398 caseDef.depthStencilFormat))
1399 TCU_THROW(NotSupportedError, "Unsupported depth/stencil format");
1400
1401 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1402 caseDef.pipelineConstructionType);
1403 }
1404
1405 //! Use image mip levels as attachments
testRenderToMipMaps(Context & context,const CaseDef caseDef)1406 tcu::TestStatus testRenderToMipMaps(Context &context, const CaseDef caseDef)
1407 {
1408 const DeviceInterface &vk = context.getDeviceInterface();
1409 const InstanceInterface &vki = context.getInstanceInterface();
1410 const VkDevice device = context.getDevice();
1411 const VkPhysicalDevice physDevice = context.getPhysicalDevice();
1412 const VkQueue queue = context.getUniversalQueue();
1413 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
1414 Allocator &allocator = context.getDefaultAllocator();
1415
1416 const IVec4 imageSize = caseDef.imageSizeHint; // MAX_SIZE is not used in this test
1417 const int32_t numSlices = maxLayersOrDepth(imageSize);
1418 const vector<IVec4> mipLevelSizes = getMipLevelSizes(imageSize);
1419 const vector<VkDeviceSize> mipLevelStorageSizes =
1420 getPerMipLevelStorageSize(mipLevelSizes, tcu::getPixelSize(mapVkFormat(caseDef.colorFormat)));
1421 const int numMipLevels = static_cast<int>(mipLevelSizes.size());
1422 const bool useDepthStencil = (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED);
1423
1424 // Create a color buffer big enough to hold all layers and mip levels
1425 const VkDeviceSize colorBufferSize = sum(mipLevelStorageSizes);
1426 const Unique<VkBuffer> colorBuffer(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1427 const UniquePtr<Allocation> colorBufferAlloc(bindBuffer(
1428 vki, vk, physDevice, device, *colorBuffer, MemoryRequirement::HostVisible, allocator, caseDef.allocationKind));
1429
1430 {
1431 deMemset(colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
1432 flushAlloc(vk, device, *colorBufferAlloc);
1433 }
1434
1435 const ShaderWrapper vertexModule(ShaderWrapper(vk, device, context.getBinaryCollection().get("vert"), 0u));
1436 const ShaderWrapper fragmentModule(ShaderWrapper(vk, device, context.getBinaryCollection().get("frag"), 0u));
1437 const PipelineLayoutWrapper pipelineLayout(caseDef.pipelineConstructionType, vk, device);
1438
1439 Move<VkImage> colorImage;
1440 MovePtr<Allocation> colorImageAlloc;
1441 Move<VkImage> depthStencilImage;
1442 MovePtr<Allocation> depthStencilImageAlloc;
1443 Move<VkBuffer> vertexBuffer;
1444 MovePtr<Allocation> vertexBufferAlloc;
1445
1446 // Create a color image
1447 {
1448 const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1449
1450 colorImage =
1451 makeImage(vk, device, getImageCreateFlags(caseDef.viewType), getImageType(caseDef.viewType),
1452 caseDef.colorFormat, imageSize.swizzle(0, 1, 2), numMipLevels, imageSize.w(), imageUsage);
1453 colorImageAlloc = bindImage(vki, vk, physDevice, device, *colorImage, MemoryRequirement::Any, allocator,
1454 caseDef.allocationKind);
1455 }
1456
1457 // Create a depth/stencil image (always a 2D image, optionally layered)
1458 if (useDepthStencil)
1459 {
1460 const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1461
1462 depthStencilImage = makeImage(vk, device, (VkImageCreateFlags)0, VK_IMAGE_TYPE_2D, caseDef.depthStencilFormat,
1463 IVec3(imageSize.x(), imageSize.y(), 1), numMipLevels, numSlices, imageUsage);
1464 depthStencilImageAlloc = bindImage(vki, vk, physDevice, device, *depthStencilImage, MemoryRequirement::Any,
1465 allocator, caseDef.allocationKind);
1466 }
1467
1468 // Create a vertex buffer
1469 {
1470 const vector<Vertex4RGBA> vertices = genFullQuadVertices(numSlices);
1471 const VkDeviceSize vertexBufferSize = sizeInBytes(vertices);
1472
1473 vertexBuffer = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1474 vertexBufferAlloc = bindBuffer(vki, vk, physDevice, device, *vertexBuffer, MemoryRequirement::HostVisible,
1475 allocator, caseDef.allocationKind);
1476
1477 deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
1478 flushAlloc(vk, device, *vertexBufferAlloc);
1479 }
1480
1481 // Prepare images
1482 {
1483 const Unique<VkCommandPool> cmdPool(
1484 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1485 const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
1486
1487 beginCommandBuffer(vk, *cmdBuffer);
1488
1489 const VkImageMemoryBarrier imageBarriers[] = {
1490 {
1491 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1492 DE_NULL, // const void* pNext;
1493 (VkAccessFlags)0, // VkAccessFlags srcAccessMask;
1494 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask;
1495 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
1496 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout;
1497 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1498 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1499 *colorImage, // VkImage image;
1500 {
1501 // VkImageSubresourceRange subresourceRange;
1502 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
1503 0u, // uint32_t baseMipLevel;
1504 static_cast<uint32_t>(numMipLevels), // uint32_t levelCount;
1505 0u, // uint32_t baseArrayLayer;
1506 static_cast<uint32_t>(imageSize.w()), // uint32_t layerCount;
1507 },
1508 },
1509 {
1510 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1511 DE_NULL, // const void* pNext;
1512 (VkAccessFlags)0, // VkAccessFlags srcAccessMask;
1513 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask;
1514 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
1515 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout;
1516 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1517 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1518 *depthStencilImage, // VkImage image;
1519 {
1520 // VkImageSubresourceRange subresourceRange;
1521 getFormatAspectFlags(caseDef.depthStencilFormat), // VkImageAspectFlags aspectMask;
1522 0u, // uint32_t baseMipLevel;
1523 static_cast<uint32_t>(numMipLevels), // uint32_t levelCount;
1524 0u, // uint32_t baseArrayLayer;
1525 static_cast<uint32_t>(numSlices), // uint32_t layerCount;
1526 },
1527 }};
1528
1529 const uint32_t numImageBarriers =
1530 static_cast<uint32_t>(DE_LENGTH_OF_ARRAY(imageBarriers) - (useDepthStencil ? 0 : 1));
1531
1532 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1533 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
1534 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
1535 0u, 0u, DE_NULL, 0u, DE_NULL, numImageBarriers, imageBarriers);
1536
1537 endCommandBuffer(vk, *cmdBuffer);
1538 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1539 }
1540
1541 // Draw
1542 for (int mipLevel = 0; mipLevel < numMipLevels; ++mipLevel)
1543 {
1544 const IVec4 &mipSize = mipLevelSizes[mipLevel];
1545 const int levelSlices = maxLayersOrDepth(mipSize);
1546
1547 drawToMipLevel(context, caseDef, mipLevel, mipSize, levelSlices, *colorImage, *depthStencilImage, *vertexBuffer,
1548 pipelineLayout, vertexModule, fragmentModule);
1549 }
1550
1551 // Copy results: colorImage -> host visible colorBuffer
1552 {
1553 const Unique<VkCommandPool> cmdPool(
1554 createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1555 const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
1556
1557 beginCommandBuffer(vk, *cmdBuffer);
1558
1559 {
1560 const VkImageMemoryBarrier imageBarriers[] = {{
1561 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1562 DE_NULL, // const void* pNext;
1563 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask;
1564 VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
1565 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout;
1566 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout;
1567 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1568 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1569 *colorImage, // VkImage image;
1570 {
1571 // VkImageSubresourceRange subresourceRange;
1572 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
1573 0u, // uint32_t baseMipLevel;
1574 static_cast<uint32_t>(numMipLevels), // uint32_t levelCount;
1575 0u, // uint32_t baseArrayLayer;
1576 static_cast<uint32_t>(imageSize.w()), // uint32_t layerCount;
1577 },
1578 }};
1579
1580 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1581 VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL,
1582 DE_LENGTH_OF_ARRAY(imageBarriers), imageBarriers);
1583 }
1584 {
1585 vector<VkBufferImageCopy> regions;
1586 VkDeviceSize levelOffset = 0ull;
1587 VkBufferImageCopy workRegion = {
1588 0ull, // VkDeviceSize bufferOffset;
1589 0u, // uint32_t bufferRowLength;
1590 0u, // uint32_t bufferImageHeight;
1591 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u,
1592 imageSize.w()), // VkImageSubresourceLayers imageSubresource;
1593 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
1594 makeExtent3D(0, 0, 0), // VkExtent3D imageExtent;
1595 };
1596
1597 for (int mipLevel = 0; mipLevel < numMipLevels; ++mipLevel)
1598 {
1599 workRegion.bufferOffset = levelOffset;
1600 workRegion.imageSubresource.mipLevel = static_cast<uint32_t>(mipLevel);
1601 workRegion.imageExtent = makeExtent3D(mipLevelSizes[mipLevel].swizzle(0, 1, 2));
1602
1603 regions.push_back(workRegion);
1604
1605 levelOffset += mipLevelStorageSizes[mipLevel];
1606 }
1607
1608 vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer,
1609 static_cast<uint32_t>(regions.size()), ®ions[0]);
1610 }
1611 {
1612 const VkBufferMemoryBarrier bufferBarriers[] = {
1613 {
1614 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
1615 DE_NULL, // const void* pNext;
1616 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
1617 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
1618 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1619 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1620 *colorBuffer, // VkBuffer buffer;
1621 0ull, // VkDeviceSize offset;
1622 VK_WHOLE_SIZE, // VkDeviceSize size;
1623 },
1624 };
1625
1626 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u,
1627 DE_NULL, DE_LENGTH_OF_ARRAY(bufferBarriers), bufferBarriers, 0u, DE_NULL);
1628 }
1629
1630 endCommandBuffer(vk, *cmdBuffer);
1631 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1632 }
1633
1634 // Verify results (per mip level)
1635 {
1636 invalidateAlloc(vk, device, *colorBufferAlloc);
1637
1638 const tcu::TextureFormat format = mapVkFormat(caseDef.colorFormat);
1639
1640 VkDeviceSize levelOffset = 0ull;
1641 bool allOk = true;
1642
1643 for (int mipLevel = 0; mipLevel < numMipLevels; ++mipLevel)
1644 {
1645 const IVec4 &mipSize = mipLevelSizes[mipLevel];
1646 const void *const pLevelData = static_cast<const uint8_t *>(colorBufferAlloc->getHostPtr()) + levelOffset;
1647 const int levelDepth = maxLayersOrDepth(mipSize);
1648 const tcu::ConstPixelBufferAccess resultImage(format, mipSize.x(), mipSize.y(), levelDepth, pLevelData);
1649 tcu::TextureLevel textureLevel(format, mipSize.x(), mipSize.y(), levelDepth);
1650 const tcu::PixelBufferAccess expectedImage = textureLevel.getAccess();
1651 const std::string comparisonName = "Mip level " + de::toString(mipLevel);
1652 bool ok = false;
1653
1654 generateExpectedImage(expectedImage, mipSize.swizzle(0, 1), 0);
1655
1656 if (isFloatFormat(caseDef.colorFormat))
1657 ok = tcu::floatThresholdCompare(context.getTestContext().getLog(), "Image Comparison",
1658 comparisonName.c_str(), expectedImage, resultImage, tcu::Vec4(0.01f),
1659 tcu::COMPARE_LOG_RESULT);
1660 else
1661 ok = tcu::intThresholdCompare(context.getTestContext().getLog(), "Image Comparison",
1662 comparisonName.c_str(), expectedImage, resultImage, tcu::UVec4(2),
1663 tcu::COMPARE_LOG_RESULT);
1664
1665 allOk = allOk && ok; // keep testing all levels, even if we know it's a fail overall
1666 levelOffset += mipLevelStorageSizes[mipLevel];
1667 }
1668
1669 return allOk ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
1670 }
1671 }
1672
getSizeDescription(const IVec4 & size)1673 std::string getSizeDescription(const IVec4 &size)
1674 {
1675 std::ostringstream str;
1676
1677 const char *const description[4] = {"width", "height", "depth", "layers"};
1678
1679 int numMaxComponents = 0;
1680
1681 for (int i = 0; i < 4; ++i)
1682 {
1683 if (size[i] == MAX_SIZE)
1684 {
1685 if (numMaxComponents > 0)
1686 str << "_";
1687
1688 str << description[i];
1689 ++numMaxComponents;
1690 }
1691 }
1692
1693 if (numMaxComponents == 0)
1694 str << "small";
1695
1696 return str.str();
1697 }
1698
getFormatString(const VkFormat format)1699 inline std::string getFormatString(const VkFormat format)
1700 {
1701 std::string name(getFormatName(format));
1702 return de::toLower(name.substr(10));
1703 }
1704
getFormatString(const VkFormat colorFormat,const VkFormat depthStencilFormat)1705 std::string getFormatString(const VkFormat colorFormat, const VkFormat depthStencilFormat)
1706 {
1707 std::ostringstream str;
1708 str << getFormatString(colorFormat);
1709 if (depthStencilFormat != VK_FORMAT_UNDEFINED)
1710 str << "_" << getFormatString(depthStencilFormat);
1711 return str.str();
1712 }
1713
getShortImageViewTypeName(const VkImageViewType imageViewType)1714 std::string getShortImageViewTypeName(const VkImageViewType imageViewType)
1715 {
1716 std::string s(getImageViewTypeName(imageViewType));
1717 return de::toLower(s.substr(19));
1718 }
1719
bvecFromMask(uint32_t mask)1720 inline BVec4 bvecFromMask(uint32_t mask)
1721 {
1722 return BVec4((mask >> 0) & 1, (mask >> 1) & 1, (mask >> 2) & 1, (mask >> 3) & 1);
1723 }
1724
genSizeCombinations(const IVec4 & baselineSize,const uint32_t sizeMask,const VkImageViewType imageViewType)1725 vector<IVec4> genSizeCombinations(const IVec4 &baselineSize, const uint32_t sizeMask,
1726 const VkImageViewType imageViewType)
1727 {
1728 vector<IVec4> sizes;
1729 std::set<uint32_t> masks;
1730
1731 for (uint32_t i = 0; i < (1u << 4); ++i)
1732 {
1733 // Cube images have square faces
1734 if (isCube(imageViewType) && ((i & MASK_WH) != 0))
1735 i |= MASK_WH;
1736
1737 masks.insert(i & sizeMask);
1738 }
1739
1740 for (std::set<uint32_t>::const_iterator it = masks.begin(); it != masks.end(); ++it)
1741 sizes.push_back(tcu::select(IVec4(MAX_SIZE), baselineSize, bvecFromMask(*it)));
1742
1743 return sizes;
1744 }
1745
addTestCasesWithFunctions(tcu::TestCaseGroup * group,PipelineConstructionType pipelineConstructionType,AllocationKind allocationKind)1746 void addTestCasesWithFunctions(tcu::TestCaseGroup *group, PipelineConstructionType pipelineConstructionType,
1747 AllocationKind allocationKind)
1748 {
1749 const struct
1750 {
1751 VkImageViewType viewType;
1752 IVec4 baselineSize; //!< image size: (dimX, dimY, dimZ, arraySize)
1753 uint32_t sizeMask; //!< if a dimension is masked, generate a huge size case for it
1754 } testCase[] = {
1755 {VK_IMAGE_VIEW_TYPE_1D, IVec4(54, 1, 1, 1), MASK_W},
1756 {VK_IMAGE_VIEW_TYPE_1D_ARRAY, IVec4(54, 1, 1, 4), MASK_W_LAYERS},
1757 {VK_IMAGE_VIEW_TYPE_2D, IVec4(44, 23, 1, 1), MASK_WH},
1758 {VK_IMAGE_VIEW_TYPE_2D_ARRAY, IVec4(44, 23, 1, 4), MASK_WH_LAYERS},
1759 {VK_IMAGE_VIEW_TYPE_3D, IVec4(22, 31, 7, 1), MASK_WHD},
1760 {VK_IMAGE_VIEW_TYPE_CUBE, IVec4(35, 35, 1, 6), MASK_WH},
1761 {VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, IVec4(35, 35, 1, 2 * 6), MASK_WH_LAYERS},
1762 };
1763
1764 const VkFormat format[] = {VK_FORMAT_R8G8B8A8_UNORM,
1765 VK_FORMAT_R32_UINT,
1766 VK_FORMAT_R16G16_SINT,
1767 VK_FORMAT_R32G32B32A32_SFLOAT,
1768 VK_FORMAT_A1R5G5B5_UNORM_PACK16,
1769 VK_FORMAT_R5G6B5_UNORM_PACK16,
1770 VK_FORMAT_A2B10G10R10_UINT_PACK32,
1771 VK_FORMAT_A2B10G10R10_UNORM_PACK32};
1772
1773 const VkFormat depthStencilFormat[] = {
1774 VK_FORMAT_UNDEFINED, // don't use a depth/stencil attachment
1775 VK_FORMAT_D16_UNORM, VK_FORMAT_S8_UINT,
1776 VK_FORMAT_D24_UNORM_S8_UINT, // one of the following mixed formats must be supported
1777 VK_FORMAT_D32_SFLOAT_S8_UINT,
1778 };
1779
1780 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(testCase); ++caseNdx)
1781 {
1782 MovePtr<tcu::TestCaseGroup> imageGroup(new tcu::TestCaseGroup(
1783 group->getTestContext(), getShortImageViewTypeName(testCase[caseNdx].viewType).c_str()));
1784
1785 // Generate attachment size cases
1786 {
1787 vector<IVec4> sizes = genSizeCombinations(testCase[caseNdx].baselineSize, testCase[caseNdx].sizeMask,
1788 testCase[caseNdx].viewType);
1789
1790 #ifdef CTS_USES_VULKANSC
1791 // filter out sizes in which width and height is equal to maximimum values
1792 sizes.erase(std::remove_if(begin(sizes), end(sizes),
1793 [&](const IVec4 &v) { return v.x() == MAX_SIZE && v.y() == MAX_SIZE; }),
1794 end(sizes));
1795 #endif // CTS_USES_VULKANSC
1796
1797 MovePtr<tcu::TestCaseGroup> smallGroup(new tcu::TestCaseGroup(group->getTestContext(), "small"));
1798 MovePtr<tcu::TestCaseGroup> hugeGroup(new tcu::TestCaseGroup(group->getTestContext(), "huge"));
1799
1800 imageGroup->addChild(smallGroup.get());
1801 imageGroup->addChild(hugeGroup.get());
1802
1803 for (vector<IVec4>::const_iterator sizeIter = sizes.begin(); sizeIter != sizes.end(); ++sizeIter)
1804 {
1805 // The first size is the baseline size, put it in a dedicated group
1806 if (sizeIter == sizes.begin())
1807 {
1808 for (int dsFormatNdx = 0; dsFormatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormat); ++dsFormatNdx)
1809 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(format); ++formatNdx)
1810 {
1811 const CaseDef caseDef{
1812 pipelineConstructionType, // PipelineConstructionType pipelineConstructionType;
1813 testCase[caseNdx].viewType, // VkImageViewType imageType;
1814 *sizeIter, // IVec4 imageSizeHint;
1815 format[formatNdx], // VkFormat colorFormat;
1816 depthStencilFormat[dsFormatNdx], // VkFormat depthStencilFormat;
1817 allocationKind // AllocationKind allocationKind;
1818 };
1819 addFunctionCaseWithPrograms(
1820 smallGroup.get(), getFormatString(format[formatNdx], depthStencilFormat[dsFormatNdx]),
1821 checkSupportAttachmentSize, initPrograms, testAttachmentSize, caseDef);
1822 }
1823 }
1824 else // All huge cases go into a separate group
1825 {
1826 if (allocationKind != ALLOCATION_KIND_DEDICATED)
1827 {
1828 MovePtr<tcu::TestCaseGroup> sizeGroup(
1829 new tcu::TestCaseGroup(group->getTestContext(), getSizeDescription(*sizeIter).c_str()));
1830 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
1831
1832 // Use the same color format for all cases, to reduce the number of permutations
1833 for (int dsFormatNdx = 0; dsFormatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormat); ++dsFormatNdx)
1834 {
1835 const CaseDef caseDef{
1836 pipelineConstructionType, // PipelineConstructionType pipelineConstructionType;
1837 testCase[caseNdx].viewType, // VkImageViewType viewType;
1838 *sizeIter, // IVec4 imageSizeHint;
1839 colorFormat, // VkFormat colorFormat;
1840 depthStencilFormat[dsFormatNdx], // VkFormat depthStencilFormat;
1841 allocationKind // AllocationKind allocationKind;
1842 };
1843 addFunctionCaseWithPrograms(
1844 sizeGroup.get(), getFormatString(colorFormat, depthStencilFormat[dsFormatNdx]),
1845 checkSupportAttachmentSize, initPrograms, testAttachmentSize, caseDef);
1846 }
1847 hugeGroup->addChild(sizeGroup.release());
1848 }
1849 }
1850 }
1851 smallGroup.release();
1852 hugeGroup.release();
1853 }
1854
1855 // Generate mip map cases
1856 {
1857 MovePtr<tcu::TestCaseGroup> mipmapGroup(new tcu::TestCaseGroup(group->getTestContext(), "mipmap"));
1858
1859 for (int dsFormatNdx = 0; dsFormatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormat); ++dsFormatNdx)
1860 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(format); ++formatNdx)
1861 {
1862 const CaseDef caseDef{
1863 pipelineConstructionType, // PipelineConstructionType pipelineConstructionType;
1864 testCase[caseNdx].viewType, // VkImageViewType imageType;
1865 testCase[caseNdx].baselineSize, // IVec4 imageSizeHint;
1866 format[formatNdx], // VkFormat colorFormat;
1867 depthStencilFormat[dsFormatNdx], // VkFormat depthStencilFormat;
1868 allocationKind // AllocationKind allocationKind;
1869 };
1870 addFunctionCaseWithPrograms(
1871 mipmapGroup.get(), getFormatString(format[formatNdx], depthStencilFormat[dsFormatNdx]),
1872 checkSupportRenderToMipMaps, initPrograms, testRenderToMipMaps, caseDef);
1873 }
1874 imageGroup->addChild(mipmapGroup.release());
1875 }
1876
1877 group->addChild(imageGroup.release());
1878 }
1879 }
1880
addCoreRenderToImageTests(tcu::TestCaseGroup * group,PipelineConstructionType pipelineConstructionType)1881 void addCoreRenderToImageTests(tcu::TestCaseGroup *group, PipelineConstructionType pipelineConstructionType)
1882 {
1883 addTestCasesWithFunctions(group, pipelineConstructionType, ALLOCATION_KIND_SUBALLOCATED);
1884 }
1885
addDedicatedAllocationRenderToImageTests(tcu::TestCaseGroup * group,PipelineConstructionType pipelineConstructionType)1886 void addDedicatedAllocationRenderToImageTests(tcu::TestCaseGroup *group,
1887 PipelineConstructionType pipelineConstructionType)
1888 {
1889 addTestCasesWithFunctions(group, pipelineConstructionType, ALLOCATION_KIND_DEDICATED);
1890 }
1891
1892 } // namespace
1893
createRenderToImageTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)1894 tcu::TestCaseGroup *createRenderToImageTests(tcu::TestContext &testCtx,
1895 PipelineConstructionType pipelineConstructionType)
1896 {
1897 de::MovePtr<tcu::TestCaseGroup> renderToImageTests(new tcu::TestCaseGroup(testCtx, "render_to_image"));
1898
1899 // Core render to image tests
1900 renderToImageTests->addChild(createTestGroup(testCtx, "core", addCoreRenderToImageTests, pipelineConstructionType));
1901 // Render to image tests for dedicated memory allocation
1902 renderToImageTests->addChild(createTestGroup(testCtx, "dedicated_allocation",
1903 addDedicatedAllocationRenderToImageTests, pipelineConstructionType));
1904
1905 return renderToImageTests.release();
1906 }
1907
1908 } // namespace pipeline
1909 } // namespace vkt
1910