1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Tests for mutable images
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktImageMutableTests.hpp"
25 #include "vktImageLoadStoreUtil.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktImageTexture.hpp"
28 #include "vktCustomInstancesDevices.hpp"
29
30 #include "vkBuilderUtil.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkImageUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "vkObjUtil.hpp"
35 #include "vkRef.hpp"
36 #include "vkDefs.hpp"
37 #include "vkPlatform.hpp"
38 #include "vkWsiUtil.hpp"
39 #include "vkDeviceUtil.hpp"
40 #include "vkSafetyCriticalUtil.hpp"
41
42 #include "deUniquePtr.hpp"
43 #include "deSharedPtr.hpp"
44
45 #include "tcuImageCompare.hpp"
46 #include "tcuTestLog.hpp"
47 #include "tcuTextureUtil.hpp"
48 #include "tcuPlatform.hpp"
49 #include "tcuCommandLine.hpp"
50
51 #include <string>
52 #include <vector>
53
54 using namespace vk;
55 using namespace tcu;
56 using namespace vk::wsi;
57
58 using de::MovePtr;
59 using de::SharedPtr;
60 using de::UniquePtr;
61 using std::string;
62 using std::vector;
63
64 namespace vkt
65 {
66 namespace image
67 {
68
69 typedef SharedPtr<Unique<VkPipeline>> SharedPtrVkPipeline;
70 typedef SharedPtr<Unique<VkImageView>> SharedPtrVkImageView;
71
72 template <typename T>
makeSharedPtr(Move<T> move)73 inline SharedPtr<Unique<T>> makeSharedPtr(Move<T> move)
74 {
75 return SharedPtr<Unique<T>>(new Unique<T>(move));
76 }
77
78 enum Upload
79 {
80 UPLOAD_CLEAR = 0,
81 UPLOAD_COPY,
82 UPLOAD_STORE,
83 UPLOAD_DRAW,
84 UPLOAD_LAST
85 };
86
87 enum Download
88 {
89 DOWNLOAD_COPY = 0,
90 DOWNLOAD_LOAD,
91 DOWNLOAD_TEXTURE,
92 DOWNLOAD_LAST
93 };
94
getUploadString(const int upload)95 std::string getUploadString(const int upload)
96 {
97 const char *strs[] = {"clear", "copy", "store", "draw"};
98 return strs[upload];
99 }
100
getDownloadString(const int download)101 std::string getDownloadString(const int download)
102 {
103 const char *strs[] = {"copy", "load", "texture"};
104 return strs[download];
105 }
106
107 struct CaseDef
108 {
109 ImageType imageType;
110 IVec3 size;
111 uint32_t numLayers;
112 VkFormat imageFormat;
113 VkFormat viewFormat;
114 enum Upload upload;
115 enum Download download;
116 bool isFormatListTest;
117 bool isSwapchainImageTest;
118 Type wsiType;
119 };
120
121 static const uint32_t COLOR_TABLE_SIZE = 4;
122
123 // Reference color values for float color rendering. Values have been chosen
124 // so that when the bit patterns are reinterpreted as a 16-bit float, we do not
125 // run into NaN / inf / denorm values.
126 static const Vec4 COLOR_TABLE_FLOAT[COLOR_TABLE_SIZE] = {
127 Vec4(0.00f, 0.40f, 0.80f, 0.10f),
128 Vec4(0.50f, 0.10f, 0.90f, 0.20f),
129 Vec4(0.20f, 0.60f, 1.00f, 0.30f),
130 Vec4(0.30f, 0.70f, 0.00f, 0.40f),
131 };
132
133 // Reference color values for integer color rendering. We avoid negative
134 // values (even for SINT formats) to avoid the situation where sign extension
135 // leads to NaN / inf values when they are reinterpreted with a float
136 // format.
137 static const IVec4 COLOR_TABLE_INT[COLOR_TABLE_SIZE] = {
138 IVec4(0x70707070, 0x3C3C3C3C, 0x65656565, 0x29292929),
139 IVec4(0x3C3C3C3C, 0x65656565, 0x29292929, 0x70707070),
140 IVec4(0x29292929, 0x70707070, 0x3C3C3C3C, 0x65656565),
141 IVec4(0x65656565, 0x29292929, 0x70707070, 0x3C3C3C3C),
142 };
143
144 // Reference clear colors created from the color table values
145 static const VkClearValue REFERENCE_CLEAR_COLOR_FLOAT[COLOR_TABLE_SIZE] = {
146 makeClearValueColorF32(COLOR_TABLE_FLOAT[0].x(), COLOR_TABLE_FLOAT[0].y(), COLOR_TABLE_FLOAT[0].z(),
147 COLOR_TABLE_FLOAT[0].w()),
148 makeClearValueColorF32(COLOR_TABLE_FLOAT[1].x(), COLOR_TABLE_FLOAT[1].y(), COLOR_TABLE_FLOAT[1].z(),
149 COLOR_TABLE_FLOAT[1].w()),
150 makeClearValueColorF32(COLOR_TABLE_FLOAT[2].x(), COLOR_TABLE_FLOAT[2].y(), COLOR_TABLE_FLOAT[2].z(),
151 COLOR_TABLE_FLOAT[2].w()),
152 makeClearValueColorF32(COLOR_TABLE_FLOAT[3].x(), COLOR_TABLE_FLOAT[3].y(), COLOR_TABLE_FLOAT[3].z(),
153 COLOR_TABLE_FLOAT[3].w()),
154 };
155
156 static const Texture s_textures[] = {
157 Texture(IMAGE_TYPE_2D, tcu::IVec3(32, 32, 1), 1),
158 Texture(IMAGE_TYPE_2D_ARRAY, tcu::IVec3(32, 32, 1), 4),
159 };
160
getClearValueInt(const CaseDef & caseDef,uint32_t colorTableIndex)161 static VkClearValue getClearValueInt(const CaseDef &caseDef, uint32_t colorTableIndex)
162 {
163 VkClearValue clearValue;
164 uint32_t channelMask = 0;
165
166 if (caseDef.upload == UPLOAD_DRAW)
167 {
168 // We use this mask to get small color values in the vertex buffer and
169 // avoid possible round off errors from int-to-float conversions.
170 channelMask = 0xFFu;
171 }
172 else
173 {
174 VkFormat format;
175 tcu::TextureFormat tcuFormat;
176
177 // Select a mask such that no integer-based color values end up
178 // reinterpreted as NaN/Inf/denorm values.
179 if (caseDef.upload == UPLOAD_CLEAR || caseDef.upload == UPLOAD_COPY)
180 format = caseDef.imageFormat;
181 else
182 format = caseDef.viewFormat;
183
184 tcuFormat = mapVkFormat(format);
185
186 switch (getChannelSize(tcuFormat.type))
187 {
188 case 1: // 8-bit
189 channelMask = 0xFFu;
190 break;
191 case 2: // 16-bit
192 channelMask = 0xFFFFu;
193 break;
194 case 4: // 32-bit
195 channelMask = 0xFFFFFFFFu;
196 break;
197 default:
198 DE_ASSERT(0);
199 }
200 }
201
202 clearValue.color.int32[0] = COLOR_TABLE_INT[colorTableIndex].x() & channelMask;
203 clearValue.color.int32[1] = COLOR_TABLE_INT[colorTableIndex].y() & channelMask;
204 clearValue.color.int32[2] = COLOR_TABLE_INT[colorTableIndex].z() & channelMask;
205 clearValue.color.int32[3] = COLOR_TABLE_INT[colorTableIndex].w() & channelMask;
206
207 return clearValue;
208 }
209
getImageType(const ImageType textureImageType)210 VkImageType getImageType(const ImageType textureImageType)
211 {
212 switch (textureImageType)
213 {
214 case IMAGE_TYPE_2D:
215 case IMAGE_TYPE_2D_ARRAY:
216 return VK_IMAGE_TYPE_2D;
217
218 default:
219 DE_ASSERT(0);
220 return VK_IMAGE_TYPE_LAST;
221 }
222 }
223
getImageViewType(const ImageType textureImageType)224 VkImageViewType getImageViewType(const ImageType textureImageType)
225 {
226 switch (textureImageType)
227 {
228 case IMAGE_TYPE_2D:
229 return VK_IMAGE_VIEW_TYPE_2D;
230 case IMAGE_TYPE_2D_ARRAY:
231 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
232
233 default:
234 DE_ASSERT(0);
235 return VK_IMAGE_VIEW_TYPE_LAST;
236 }
237 }
238
239 static const VkFormat s_formats[] = {
240 VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R32G32_SFLOAT,
241 VK_FORMAT_R16G16_SFLOAT, VK_FORMAT_R32_SFLOAT,
242
243 VK_FORMAT_R32G32B32A32_UINT, VK_FORMAT_R16G16B16A16_UINT, VK_FORMAT_R8G8B8A8_UINT,
244 VK_FORMAT_R32G32_UINT, VK_FORMAT_R16G16_UINT, VK_FORMAT_R32_UINT,
245
246 VK_FORMAT_R32G32B32A32_SINT, VK_FORMAT_R16G16B16A16_SINT, VK_FORMAT_R8G8B8A8_SINT,
247 VK_FORMAT_R32G32_SINT, VK_FORMAT_R16G16_SINT, VK_FORMAT_R32_SINT,
248
249 VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_SNORM, VK_FORMAT_R8G8B8A8_SRGB,
250 VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SNORM, VK_FORMAT_B8G8R8A8_SRGB,
251 };
252
253 static const VkFormat s_swapchainFormats[] = {
254 VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_SNORM, VK_FORMAT_R8G8B8A8_SRGB,
255 VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SNORM, VK_FORMAT_B8G8R8A8_SRGB,
256 };
257
isSRGBConversionRequired(const CaseDef & caseDef)258 bool isSRGBConversionRequired(const CaseDef &caseDef)
259 {
260 bool required = false;
261
262 if (isSRGB(mapVkFormat(caseDef.imageFormat)))
263 {
264 if (caseDef.upload == UPLOAD_CLEAR)
265 {
266 required = true;
267 }
268 }
269
270 if (isSRGB(mapVkFormat(caseDef.viewFormat)))
271 {
272 if (caseDef.upload == UPLOAD_DRAW || caseDef.upload == UPLOAD_STORE)
273 {
274 required = true;
275 }
276 }
277
278 return required;
279 }
280
formatsAreCompatible(const VkFormat format0,const VkFormat format1)281 inline bool formatsAreCompatible(const VkFormat format0, const VkFormat format1)
282 {
283 return format0 == format1 || mapVkFormat(format0).getPixelSize() == mapVkFormat(format1).getPixelSize();
284 }
285
getColorFormatStr(const int numComponents,const bool isUint,const bool isSint)286 std::string getColorFormatStr(const int numComponents, const bool isUint, const bool isSint)
287 {
288 std::ostringstream str;
289 if (numComponents == 1)
290 str << (isUint ? "uint" : isSint ? "int" : "float");
291 else
292 str << (isUint ? "u" : isSint ? "i" : "") << "vec" << numComponents;
293
294 return str.str();
295 }
296
getShaderSamplerType(const tcu::TextureFormat & format,VkImageViewType type)297 std::string getShaderSamplerType(const tcu::TextureFormat &format, VkImageViewType type)
298 {
299 std::ostringstream samplerType;
300
301 if (tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
302 samplerType << "u";
303 else if (tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
304 samplerType << "i";
305
306 switch (type)
307 {
308 case VK_IMAGE_VIEW_TYPE_2D:
309 samplerType << "sampler2D";
310 break;
311
312 case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
313 samplerType << "sampler2DArray";
314 break;
315
316 default:
317 DE_FATAL("Ivalid image view type");
318 break;
319 }
320
321 return samplerType.str();
322 }
323
initPrograms(SourceCollections & programCollection,const CaseDef caseDef)324 void initPrograms(SourceCollections &programCollection, const CaseDef caseDef)
325 {
326 if (caseDef.upload == UPLOAD_DRAW)
327 {
328 {
329 std::ostringstream src;
330 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
331 << "\n"
332 << "layout(location = 0) in vec4 in_position;\n"
333 << "layout(location = 1) in vec4 in_color;\n"
334 << "layout(location = 0) out vec4 out_color;\n"
335 << "\n"
336 << "out gl_PerVertex {\n"
337 << " vec4 gl_Position;\n"
338 << "};\n"
339 << "\n"
340 << "void main(void)\n"
341 << "{\n"
342 << " gl_Position = in_position;\n"
343 << " out_color = in_color;\n"
344 << "}\n";
345
346 programCollection.glslSources.add("uploadDrawVert") << glu::VertexSource(src.str());
347 }
348
349 {
350 const int numComponents = getNumUsedChannels(mapVkFormat(caseDef.viewFormat).order);
351 const bool isUint = isUintFormat(caseDef.viewFormat);
352 const bool isSint = isIntFormat(caseDef.viewFormat);
353 const std::string colorFormat = getColorFormatStr(numComponents, isUint, isSint);
354
355 std::ostringstream src;
356 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
357 << "\n"
358 << "layout(location = 0) in vec4 in_color;\n"
359 << "layout(location = 0) out " << colorFormat << " out_color;\n"
360 << "\n"
361 << "void main(void)\n"
362 << "{\n"
363 << " out_color = " << colorFormat << "("
364 << (numComponents == 1 ? "in_color.r" :
365 numComponents == 2 ? "in_color.rg" :
366 numComponents == 3 ? "in_color.rgb" :
367 "in_color")
368 << ");\n"
369 << "}\n";
370
371 programCollection.glslSources.add("uploadDrawFrag") << glu::FragmentSource(src.str());
372 }
373 }
374
375 if (caseDef.upload == UPLOAD_STORE)
376 {
377 const TextureFormat tcuFormat = mapVkFormat(caseDef.viewFormat);
378 const std::string imageFormatStr = getShaderImageFormatQualifier(tcuFormat);
379 const std::string imageTypeStr = getShaderImageType(tcuFormat, caseDef.imageType);
380 const std::string colorTypeStr = isUintFormat(caseDef.viewFormat) ? "uvec4" :
381 isIntFormat(caseDef.viewFormat) ? "ivec4" :
382 "vec4";
383 const bool isIntegerFormat = isUintFormat(caseDef.viewFormat) || isIntFormat(caseDef.viewFormat);
384
385 std::ostringstream src;
386 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
387 << "\n"
388 << "layout (local_size_x = 1) in;\n"
389 << "\n"
390 << "layout(binding=0, " << imageFormatStr << ") writeonly uniform " << imageTypeStr << " u_image;\n"
391 << "\n"
392 << "const " << colorTypeStr << " colorTable[] = " << colorTypeStr << "[](\n";
393 for (uint32_t idx = 0; idx < COLOR_TABLE_SIZE; idx++)
394 {
395 if (isIntegerFormat)
396 {
397 const VkClearValue clearValue = getClearValueInt(caseDef, idx);
398
399 src << " " << colorTypeStr << "(" << clearValue.color.int32[0] << ", " << clearValue.color.int32[1]
400 << ", " << clearValue.color.int32[2] << ", " << clearValue.color.int32[3] << ")";
401 }
402 else
403 src << " " << colorTypeStr << "(" << COLOR_TABLE_FLOAT[idx].x() << ", "
404 << COLOR_TABLE_FLOAT[idx].y() << ", " << COLOR_TABLE_FLOAT[idx].z() << ", "
405 << COLOR_TABLE_FLOAT[idx].w() << ")";
406 if (idx < COLOR_TABLE_SIZE - 1)
407 src << ",";
408 src << "\n";
409 }
410 src << ");\n"
411 << "\n"
412 << "void main(void)\n"
413 << "{\n";
414 if (caseDef.imageType == IMAGE_TYPE_2D)
415 {
416 src << " ivec2 pos = ivec2(gl_GlobalInvocationID.xy);\n";
417 }
418 else
419 {
420 DE_ASSERT(caseDef.imageType == IMAGE_TYPE_2D_ARRAY);
421 src << " ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);\n";
422 }
423 src << " " << colorTypeStr << " color = colorTable[gl_GlobalInvocationID.z];\n"
424 << " imageStore(u_image, pos, color);\n"
425 << "}\n";
426
427 programCollection.glslSources.add("uploadStoreComp") << glu::ComputeSource(src.str());
428 }
429
430 if (caseDef.download == DOWNLOAD_LOAD)
431 {
432 const TextureFormat tcuFormat = mapVkFormat(caseDef.viewFormat);
433 const std::string imageFormatStr = getShaderImageFormatQualifier(tcuFormat);
434 const std::string imageTypeStr = getShaderImageType(tcuFormat, caseDef.imageType);
435 const std::string colorTypeStr = isUintFormat(caseDef.viewFormat) ? "uvec4" :
436 isIntFormat(caseDef.viewFormat) ? "ivec4" :
437 "vec4";
438
439 std::ostringstream src;
440 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
441 << "\n"
442 << "layout (local_size_x = 1) in;\n"
443 << "\n"
444 << "layout(binding=0, " << imageFormatStr << ") readonly uniform " << imageTypeStr << " in_image;\n"
445 << "layout(binding=1, " << imageFormatStr << ") writeonly uniform " << imageTypeStr << " out_image;\n"
446 << "\n"
447 << "void main(void)\n"
448 << "{\n";
449 if (caseDef.imageType == IMAGE_TYPE_2D)
450 {
451 src << " ivec2 pos = ivec2(gl_GlobalInvocationID.xy);\n";
452 }
453 else
454 {
455 DE_ASSERT(caseDef.imageType == IMAGE_TYPE_2D_ARRAY);
456 src << " ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);\n";
457 }
458 src << " imageStore(out_image, pos, imageLoad(in_image, pos));\n"
459 << "}\n";
460
461 programCollection.glslSources.add("downloadLoadComp") << glu::ComputeSource(src.str());
462 }
463
464 if (caseDef.download == DOWNLOAD_TEXTURE)
465 {
466 const TextureFormat tcuFormat = mapVkFormat(caseDef.viewFormat);
467 const VkImageViewType viewType = getImageViewType(caseDef.imageType);
468 const std::string samplerTypeStr = getShaderSamplerType(tcuFormat, viewType);
469 const std::string imageFormatStr = getShaderImageFormatQualifier(tcuFormat);
470 const std::string imageTypeStr = getShaderImageType(tcuFormat, caseDef.imageType);
471 const std::string colorTypeStr = isUintFormat(caseDef.viewFormat) ? "uvec4" :
472 isIntFormat(caseDef.viewFormat) ? "ivec4" :
473 "vec4";
474
475 std::ostringstream src;
476 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
477 << "\n"
478 << "layout (local_size_x = 1) in;\n"
479 << "\n"
480 << "layout(binding=0) uniform " << samplerTypeStr << " u_tex;\n"
481 << "layout(binding=1, " << imageFormatStr << ") writeonly uniform " << imageTypeStr << " out_image;\n"
482 << "\n"
483 << "void main(void)\n"
484 << "{\n";
485 if (caseDef.imageType == IMAGE_TYPE_2D)
486 {
487 src << " ivec2 pos = ivec2(gl_GlobalInvocationID.xy);\n";
488 }
489 else
490 {
491 DE_ASSERT(caseDef.imageType == IMAGE_TYPE_2D_ARRAY);
492 src << " ivec3 pos = ivec3(gl_GlobalInvocationID.xyz);\n";
493 }
494 src << " imageStore(out_image, pos, texelFetch(u_tex, pos, 0));\n"
495 << "}\n";
496
497 programCollection.glslSources.add("downloadTextureComp") << glu::ComputeSource(src.str());
498 }
499 }
500
makeImage(const DeviceInterface & vk,const VkDevice device,VkImageCreateFlags flags,VkImageType imageType,const VkFormat format,const VkFormat viewFormat,const bool useImageFormatList,const IVec3 & size,const uint32_t numMipLevels,const uint32_t numLayers,const VkImageUsageFlags usage)501 Move<VkImage> makeImage(const DeviceInterface &vk, const VkDevice device, VkImageCreateFlags flags,
502 VkImageType imageType, const VkFormat format, const VkFormat viewFormat,
503 const bool useImageFormatList, const IVec3 &size, const uint32_t numMipLevels,
504 const uint32_t numLayers, const VkImageUsageFlags usage)
505 {
506 const VkFormat formatList[2] = {format, viewFormat};
507
508 const VkImageFormatListCreateInfo formatListInfo = {
509 VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO, // VkStructureType sType;
510 DE_NULL, // const void* pNext;
511 2u, // uint32_t viewFormatCount
512 formatList // const VkFormat* pViewFormats
513 };
514
515 const VkImageCreateInfo imageParams = {
516 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
517 useImageFormatList ? &formatListInfo : DE_NULL, // const void* pNext;
518 flags, // VkImageCreateFlags flags;
519 imageType, // VkImageType imageType;
520 format, // VkFormat format;
521 makeExtent3D(size), // VkExtent3D extent;
522 numMipLevels, // uint32_t mipLevels;
523 numLayers, // uint32_t arrayLayers;
524 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
525 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
526 usage, // VkImageUsageFlags usage;
527 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
528 0u, // uint32_t queueFamilyIndexCount;
529 DE_NULL, // const uint32_t* pQueueFamilyIndices;
530 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
531 };
532 return createImage(vk, device, &imageParams);
533 }
534
makeColorSubresourceRange(const int baseArrayLayer,const int layerCount)535 inline VkImageSubresourceRange makeColorSubresourceRange(const int baseArrayLayer, const int layerCount)
536 {
537 return makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, static_cast<uint32_t>(baseArrayLayer),
538 static_cast<uint32_t>(layerCount));
539 }
540
makeSampler(const DeviceInterface & vk,const VkDevice device)541 Move<VkSampler> makeSampler(const DeviceInterface &vk, const VkDevice device)
542 {
543 const VkSamplerCreateInfo samplerParams = {
544 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType;
545 DE_NULL, // const void* pNext;
546 (VkSamplerCreateFlags)0, // VkSamplerCreateFlags flags;
547 VK_FILTER_NEAREST, // VkFilter magFilter;
548 VK_FILTER_NEAREST, // VkFilter minFilter;
549 VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode;
550 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeU;
551 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeV;
552 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW;
553 0.0f, // float mipLodBias;
554 VK_FALSE, // VkBool32 anisotropyEnable;
555 1.0f, // float maxAnisotropy;
556 VK_FALSE, // VkBool32 compareEnable;
557 VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp;
558 0.0f, // float minLod;
559 0.0f, // float maxLod;
560 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor;
561 VK_FALSE, // VkBool32 unnormalizedCoordinates;
562 };
563
564 return createSampler(vk, device, &samplerParams);
565 }
566
makeGraphicsPipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule fragmentModule,const IVec2 & renderSize,const VkPrimitiveTopology topology,const uint32_t subpass)567 Move<VkPipeline> makeGraphicsPipeline(const DeviceInterface &vk, const VkDevice device,
568 const VkPipelineLayout pipelineLayout, const VkRenderPass renderPass,
569 const VkShaderModule vertexModule, const VkShaderModule fragmentModule,
570 const IVec2 &renderSize, const VkPrimitiveTopology topology,
571 const uint32_t subpass)
572 {
573 const std::vector<VkViewport> viewports(1, makeViewport(renderSize));
574 const std::vector<VkRect2D> scissors(1, makeRect2D(renderSize));
575
576 const VkVertexInputBindingDescription vertexInputBindingDescription = {
577 0u, // uint32_t binding;
578 (uint32_t)(2 * sizeof(Vec4)), // uint32_t stride;
579 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
580 };
581
582 const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = {
583 {
584 0u, // uint32_t location;
585 0u, // uint32_t binding;
586 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
587 0u, // uint32_t offset;
588 },
589 {
590 1u, // uint32_t location;
591 0u, // uint32_t binding;
592 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
593 (uint32_t)sizeof(Vec4), // uint32_t offset;
594 }};
595
596 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
597 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
598 DE_NULL, // const void* pNext;
599 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags;
600 1u, // uint32_t vertexBindingDescriptionCount;
601 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
602 2u, // uint32_t vertexAttributeDescriptionCount;
603 vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
604 };
605
606 return vk::makeGraphicsPipeline(
607 vk, // const DeviceInterface& vk
608 device, // const VkDevice device
609 pipelineLayout, // const VkPipelineLayout pipelineLayout
610 vertexModule, // const VkShaderModule vertexShaderModule
611 DE_NULL, // const VkShaderModule tessellationControlModule
612 DE_NULL, // const VkShaderModule tessellationEvalModule
613 DE_NULL, // const VkShaderModule geometryShaderModule
614 fragmentModule, // const VkShaderModule fragmentShaderModule
615 renderPass, // const VkRenderPass renderPass
616 viewports, // const std::vector<VkViewport>& viewports
617 scissors, // const std::vector<VkRect2D>& scissors
618 topology, // const VkPrimitiveTopology topology
619 subpass, // const uint32_t subpass
620 0u, // const uint32_t patchControlPoints
621 &vertexInputStateCreateInfo); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
622 }
623
makeRenderPass(const DeviceInterface & vk,const VkDevice device,const VkFormat colorFormat,const uint32_t numLayers)624 Move<VkRenderPass> makeRenderPass(const DeviceInterface &vk, const VkDevice device, const VkFormat colorFormat,
625 const uint32_t numLayers)
626 {
627 const VkAttachmentDescription colorAttachmentDescription = {
628 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
629 colorFormat, // VkFormat format;
630 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
631 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
632 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
633 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
634 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
635 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
636 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
637 };
638 vector<VkAttachmentDescription> attachmentDescriptions(numLayers, colorAttachmentDescription);
639
640 // Create a subpass for each attachment (each attachement is a layer of an arrayed image).
641 vector<VkAttachmentReference> colorAttachmentReferences(numLayers);
642 vector<VkSubpassDescription> subpasses;
643
644 // Ordering here must match the framebuffer attachments
645 for (uint32_t i = 0; i < numLayers; ++i)
646 {
647 const VkAttachmentReference attachmentRef = {
648 i, // uint32_t attachment;
649 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
650 };
651
652 colorAttachmentReferences[i] = attachmentRef;
653
654 const VkSubpassDescription subpassDescription = {
655 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
656 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
657 0u, // uint32_t inputAttachmentCount;
658 DE_NULL, // const VkAttachmentReference* pInputAttachments;
659 1u, // uint32_t colorAttachmentCount;
660 &colorAttachmentReferences[i], // const VkAttachmentReference* pColorAttachments;
661 DE_NULL, // const VkAttachmentReference* pResolveAttachments;
662 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
663 0u, // uint32_t preserveAttachmentCount;
664 DE_NULL // const uint32_t* pPreserveAttachments;
665 };
666 subpasses.push_back(subpassDescription);
667 }
668
669 const VkRenderPassCreateInfo renderPassInfo = {
670 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
671 DE_NULL, // const void* pNext;
672 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
673 static_cast<uint32_t>(attachmentDescriptions.size()), // uint32_t attachmentCount;
674 &attachmentDescriptions[0], // const VkAttachmentDescription* pAttachments;
675 static_cast<uint32_t>(subpasses.size()), // uint32_t subpassCount;
676 &subpasses[0], // const VkSubpassDescription* pSubpasses;
677 0u, // uint32_t dependencyCount;
678 DE_NULL // const VkSubpassDependency* pDependencies;
679 };
680
681 return createRenderPass(vk, device, &renderPassInfo);
682 }
683
makeCommandBuffer(const DeviceInterface & vk,const VkDevice device,const VkCommandPool commandPool)684 Move<VkCommandBuffer> makeCommandBuffer(const DeviceInterface &vk, const VkDevice device,
685 const VkCommandPool commandPool)
686 {
687 return allocateCommandBuffer(vk, device, commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
688 }
689
genVertexData(const CaseDef & caseDef)690 vector<Vec4> genVertexData(const CaseDef &caseDef)
691 {
692 vector<Vec4> vectorData;
693 const bool isIntegerFormat = isUintFormat(caseDef.viewFormat) || isIntFormat(caseDef.viewFormat);
694
695 for (uint32_t z = 0; z < caseDef.numLayers; z++)
696 {
697 const uint32_t colorIdx = z % COLOR_TABLE_SIZE;
698 Vec4 color;
699
700 if (isIntegerFormat)
701 {
702 const VkClearValue clearValue = getClearValueInt(caseDef, colorIdx);
703 const IVec4 colorInt(clearValue.color.int32[0], clearValue.color.int32[1], clearValue.color.int32[2],
704 clearValue.color.int32[3]);
705
706 color = colorInt.cast<float>();
707 }
708 else
709 {
710 color = COLOR_TABLE_FLOAT[colorIdx];
711 }
712
713 vectorData.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
714 vectorData.push_back(color);
715 vectorData.push_back(Vec4(-1.0f, 1.0f, 0.0f, 1.0f));
716 vectorData.push_back(color);
717 vectorData.push_back(Vec4(1.0f, -1.0f, 0.0f, 1.0f));
718 vectorData.push_back(color);
719 vectorData.push_back(Vec4(1.0f, 1.0f, 0.0f, 1.0f));
720 vectorData.push_back(color);
721 }
722
723 return vectorData;
724 }
725
generateExpectedImage(const tcu::PixelBufferAccess & image,const CaseDef & caseDef)726 void generateExpectedImage(const tcu::PixelBufferAccess &image, const CaseDef &caseDef)
727 {
728 const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(image.getFormat().type);
729 const bool isIntegerFormat = channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER ||
730 channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
731 const IVec2 size = caseDef.size.swizzle(0, 1);
732
733 for (int z = 0; z < static_cast<int>(caseDef.numLayers); z++)
734 {
735 const uint32_t colorIdx = z % COLOR_TABLE_SIZE;
736 for (int y = 0; y < size.y(); y++)
737 for (int x = 0; x < size.x(); x++)
738 {
739 if (isIntegerFormat)
740 {
741 const VkClearValue clearValue = getClearValueInt(caseDef, colorIdx);
742 const IVec4 colorInt(clearValue.color.int32[0], clearValue.color.int32[1],
743 clearValue.color.int32[2], clearValue.color.int32[3]);
744
745 image.setPixel(colorInt, x, y, z);
746 }
747 else if (isSRGBConversionRequired(caseDef))
748 image.setPixel(tcu::linearToSRGB(COLOR_TABLE_FLOAT[colorIdx]), x, y, z);
749 else
750 image.setPixel(COLOR_TABLE_FLOAT[colorIdx], x, y, z);
751 }
752 }
753 }
754
getImageUsageForTestCase(const CaseDef & caseDef)755 VkImageUsageFlags getImageUsageForTestCase(const CaseDef &caseDef)
756 {
757 VkImageUsageFlags flags = 0u;
758
759 switch (caseDef.upload)
760 {
761 case UPLOAD_CLEAR:
762 flags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
763 break;
764 case UPLOAD_DRAW:
765 flags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
766 break;
767 case UPLOAD_STORE:
768 flags |= VK_IMAGE_USAGE_STORAGE_BIT;
769 break;
770 case UPLOAD_COPY:
771 flags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
772 break;
773 default:
774 DE_FATAL("Invalid upload method");
775 break;
776 }
777
778 switch (caseDef.download)
779 {
780 case DOWNLOAD_TEXTURE:
781 flags |= VK_IMAGE_USAGE_SAMPLED_BIT;
782 break;
783 case DOWNLOAD_LOAD:
784 flags |= VK_IMAGE_USAGE_STORAGE_BIT;
785 break;
786 case DOWNLOAD_COPY:
787 flags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
788 break;
789 default:
790 DE_FATAL("Invalid download method");
791 break;
792 }
793
794 // We can only create a view for the image if it is going to be used for any of these usages,
795 // so let's make sure that we have at least one of them.
796 VkImageUsageFlags viewRequiredFlags =
797 VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
798 if (!(flags & viewRequiredFlags))
799 flags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
800
801 return flags;
802 }
803
804 // Executes a combination of upload/download methods
805 class UploadDownloadExecutor
806 {
807 public:
UploadDownloadExecutor(Context & context,bool haveMaintenance2,const DeviceInterface & deviceInterface,VkDevice device,VkQueue queue,uint32_t queueFamilyIndex,const CaseDef & caseSpec)808 UploadDownloadExecutor(Context &context, bool haveMaintenance2, const DeviceInterface &deviceInterface,
809 VkDevice device, VkQueue queue, uint32_t queueFamilyIndex, const CaseDef &caseSpec)
810 : m_caseDef(caseSpec)
811 , m_haveMaintenance2(haveMaintenance2)
812 , m_vk(deviceInterface)
813 , m_device(device)
814 , m_queue(queue)
815 , m_queueFamilyIndex(queueFamilyIndex)
816 , m_allocator(m_vk, device,
817 getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()))
818 {
819 }
820
821 void runSwapchain(Context &context, VkBuffer buffer, VkImage image);
822
823 void run(Context &context, VkBuffer buffer);
824
825 private:
826 void uploadClear(Context &context);
827 void uploadStore(Context &context);
828 void uploadCopy(Context &context);
829 void uploadDraw(Context &context);
830 void downloadCopy(Context &context, VkBuffer buffer);
831 void downloadTexture(Context &context, VkBuffer buffer);
832 void downloadLoad(Context &context, VkBuffer buffer);
833
834 void copyImageToBuffer(VkImage image, VkBuffer buffer, const IVec3 size, const VkAccessFlags srcAccessMask,
835 const VkImageLayout oldLayout, const uint32_t numLayers);
836
837 const CaseDef &m_caseDef;
838
839 bool m_haveMaintenance2;
840
841 const DeviceInterface &m_vk;
842 const VkDevice m_device;
843 const VkQueue m_queue;
844 const uint32_t m_queueFamilyIndex;
845 SimpleAllocator m_allocator;
846
847 Move<VkCommandPool> m_cmdPool;
848 Move<VkCommandBuffer> m_cmdBuffer;
849
850 bool m_imageIsIntegerFormat;
851 bool m_viewIsIntegerFormat;
852
853 // Target image for upload paths
854 VkImage m_image;
855 Move<VkImage> m_imageHolder;
856 MovePtr<Allocation> m_imageAlloc;
857
858 // Upload copy
859 struct
860 {
861 Move<VkBuffer> colorBuffer;
862 VkDeviceSize colorBufferSize;
863 MovePtr<Allocation> colorBufferAlloc;
864 } m_uCopy;
865
866 // Upload draw
867 struct
868 {
869 Move<VkBuffer> vertexBuffer;
870 MovePtr<Allocation> vertexBufferAlloc;
871 Move<VkPipelineLayout> pipelineLayout;
872 Move<VkRenderPass> renderPass;
873 Move<VkShaderModule> vertexModule;
874 Move<VkShaderModule> fragmentModule;
875 vector<SharedPtrVkImageView> attachments;
876 vector<VkImageView> attachmentHandles;
877 vector<SharedPtrVkPipeline> pipelines;
878 Move<VkFramebuffer> framebuffer;
879 } m_uDraw;
880
881 // Upload store
882 struct
883 {
884 Move<VkDescriptorPool> descriptorPool;
885 Move<VkPipelineLayout> pipelineLayout;
886 Move<VkDescriptorSetLayout> descriptorSetLayout;
887 Move<VkDescriptorSet> descriptorSet;
888 VkDescriptorImageInfo imageDescriptorInfo;
889 Move<VkShaderModule> computeModule;
890 Move<VkPipeline> computePipeline;
891 Move<VkImageView> imageView;
892 } m_uStore;
893
894 // Download load
895 struct
896 {
897 Move<VkDescriptorPool> descriptorPool;
898 Move<VkPipelineLayout> pipelineLayout;
899 Move<VkDescriptorSetLayout> descriptorSetLayout;
900 Move<VkDescriptorSet> descriptorSet;
901 Move<VkShaderModule> computeModule;
902 Move<VkPipeline> computePipeline;
903 Move<VkImageView> inImageView;
904 VkDescriptorImageInfo inImageDescriptorInfo;
905 Move<VkImage> outImage;
906 Move<VkImageView> outImageView;
907 MovePtr<Allocation> outImageAlloc;
908 VkDescriptorImageInfo outImageDescriptorInfo;
909 } m_dLoad;
910
911 // Download texture
912 struct
913 {
914 Move<VkDescriptorPool> descriptorPool;
915 Move<VkPipelineLayout> pipelineLayout;
916 Move<VkDescriptorSetLayout> descriptorSetLayout;
917 Move<VkDescriptorSet> descriptorSet;
918 Move<VkShaderModule> computeModule;
919 Move<VkPipeline> computePipeline;
920 Move<VkImageView> inImageView;
921 VkDescriptorImageInfo inImageDescriptorInfo;
922 Move<VkSampler> sampler;
923 Move<VkImage> outImage;
924 Move<VkImageView> outImageView;
925 MovePtr<Allocation> outImageAlloc;
926 VkDescriptorImageInfo outImageDescriptorInfo;
927 } m_dTex;
928
929 VkImageLayout m_imageLayoutAfterUpload;
930 VkAccessFlagBits m_imageUploadAccessMask;
931 };
932
runSwapchain(Context & context,VkBuffer buffer,VkImage image)933 void UploadDownloadExecutor::runSwapchain(Context &context, VkBuffer buffer, VkImage image)
934 {
935 m_imageIsIntegerFormat = isUintFormat(m_caseDef.imageFormat) || isIntFormat(m_caseDef.imageFormat);
936 m_viewIsIntegerFormat = isUintFormat(m_caseDef.viewFormat) || isIntFormat(m_caseDef.viewFormat);
937
938 m_cmdPool = createCommandPool(m_vk, m_device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_queueFamilyIndex);
939 m_cmdBuffer = makeCommandBuffer(m_vk, m_device, *m_cmdPool);
940 beginCommandBuffer(m_vk, *m_cmdBuffer);
941
942 m_image = image;
943
944 switch (m_caseDef.upload)
945 {
946 case UPLOAD_DRAW:
947 uploadDraw(context);
948 break;
949 case UPLOAD_STORE:
950 uploadStore(context);
951 break;
952 case UPLOAD_CLEAR:
953 uploadClear(context);
954 break;
955 case UPLOAD_COPY:
956 uploadCopy(context);
957 break;
958 default:
959 DE_FATAL("Unsupported upload method");
960 }
961
962 switch (m_caseDef.download)
963 {
964 case DOWNLOAD_COPY:
965 downloadCopy(context, buffer);
966 break;
967 case DOWNLOAD_LOAD:
968 downloadLoad(context, buffer);
969 break;
970 case DOWNLOAD_TEXTURE:
971 downloadTexture(context, buffer);
972 break;
973 default:
974 DE_FATAL("Unsupported download method");
975 }
976
977 endCommandBuffer(m_vk, *m_cmdBuffer);
978 submitCommandsAndWait(m_vk, m_device, m_queue, *m_cmdBuffer);
979 }
980
run(Context & context,VkBuffer buffer)981 void UploadDownloadExecutor::run(Context &context, VkBuffer buffer)
982 {
983 m_imageIsIntegerFormat = isUintFormat(m_caseDef.imageFormat) || isIntFormat(m_caseDef.imageFormat);
984 m_viewIsIntegerFormat = isUintFormat(m_caseDef.viewFormat) || isIntFormat(m_caseDef.viewFormat);
985
986 m_cmdPool = createCommandPool(m_vk, m_device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_queueFamilyIndex);
987 m_cmdBuffer = makeCommandBuffer(m_vk, m_device, *m_cmdPool);
988 beginCommandBuffer(m_vk, *m_cmdBuffer);
989
990 const VkImageUsageFlags imageUsage = getImageUsageForTestCase(m_caseDef);
991 const VkImageCreateFlags imageFlags =
992 VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | (m_haveMaintenance2 ? VK_IMAGE_CREATE_EXTENDED_USAGE_BIT : 0);
993
994 VkImageFormatProperties properties;
995 if ((context.getInstanceInterface().getPhysicalDeviceImageFormatProperties(
996 context.getPhysicalDevice(), m_caseDef.imageFormat, getImageType(m_caseDef.imageType),
997 VK_IMAGE_TILING_OPTIMAL, imageUsage, imageFlags, &properties) == VK_ERROR_FORMAT_NOT_SUPPORTED))
998 {
999 TCU_THROW(NotSupportedError, "Format not supported");
1000 }
1001
1002 m_imageHolder = makeImage(m_vk, m_device, imageFlags, getImageType(m_caseDef.imageType), m_caseDef.imageFormat,
1003 m_caseDef.viewFormat, m_caseDef.isFormatListTest, m_caseDef.size, 1u, m_caseDef.numLayers,
1004 imageUsage);
1005 m_image = *m_imageHolder;
1006 m_imageAlloc = bindImage(m_vk, m_device, m_allocator, m_image, MemoryRequirement::Any);
1007
1008 switch (m_caseDef.upload)
1009 {
1010 case UPLOAD_DRAW:
1011 uploadDraw(context);
1012 break;
1013 case UPLOAD_STORE:
1014 uploadStore(context);
1015 break;
1016 case UPLOAD_CLEAR:
1017 uploadClear(context);
1018 break;
1019 case UPLOAD_COPY:
1020 uploadCopy(context);
1021 break;
1022 default:
1023 DE_FATAL("Unsupported upload method");
1024 }
1025
1026 switch (m_caseDef.download)
1027 {
1028 case DOWNLOAD_COPY:
1029 downloadCopy(context, buffer);
1030 break;
1031 case DOWNLOAD_LOAD:
1032 downloadLoad(context, buffer);
1033 break;
1034 case DOWNLOAD_TEXTURE:
1035 downloadTexture(context, buffer);
1036 break;
1037 default:
1038 DE_FATAL("Unsupported download method");
1039 }
1040
1041 endCommandBuffer(m_vk, *m_cmdBuffer);
1042 submitCommandsAndWait(m_vk, m_device, m_queue, *m_cmdBuffer);
1043 }
1044
uploadClear(Context & context)1045 void UploadDownloadExecutor::uploadClear(Context &context)
1046 {
1047 (void)context;
1048
1049 VkImageLayout requiredImageLayout = VK_IMAGE_LAYOUT_GENERAL;
1050
1051 const VkImageSubresourceRange subresourceRange = makeColorSubresourceRange(0, m_caseDef.numLayers);
1052 const VkImageMemoryBarrier imageInitBarrier = {
1053 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1054 DE_NULL, // const void* pNext;
1055 0u, // VkAccessFlags srcAccessMask;
1056 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAcessMask;
1057 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
1058 requiredImageLayout, // VkImageLayout newLayout;
1059 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1060 VK_QUEUE_FAMILY_IGNORED, // uint32_t destQueueFamilyIndex;
1061 m_image, // VkImage image;
1062 subresourceRange // VkImageSubresourceRange subresourceRange;
1063 };
1064
1065 m_vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u,
1066 DE_NULL, 0u, DE_NULL, 1u, &imageInitBarrier);
1067
1068 for (uint32_t layer = 0; layer < m_caseDef.numLayers; layer++)
1069 {
1070 const VkImageSubresourceRange layerSubresourceRange = makeColorSubresourceRange(layer, 1u);
1071 const uint32_t colorIdx = layer % COLOR_TABLE_SIZE;
1072 const VkClearColorValue clearColor = m_imageIsIntegerFormat ? getClearValueInt(m_caseDef, colorIdx).color :
1073 REFERENCE_CLEAR_COLOR_FLOAT[colorIdx].color;
1074 m_vk.cmdClearColorImage(*m_cmdBuffer, m_image, requiredImageLayout, &clearColor, 1u, &layerSubresourceRange);
1075 }
1076
1077 m_imageLayoutAfterUpload = requiredImageLayout;
1078 m_imageUploadAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
1079 }
1080
uploadStore(Context & context)1081 void UploadDownloadExecutor::uploadStore(Context &context)
1082 {
1083 const vk::VkImageViewUsageCreateInfo viewUsageCreateInfo = {
1084 VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, // VkStructureType sType
1085 DE_NULL, // const void* pNext
1086 VK_IMAGE_USAGE_STORAGE_BIT, // VkImageUsageFlags usage;
1087 };
1088 m_uStore.imageView = makeImageView(m_vk, m_device, m_image, getImageViewType(m_caseDef.imageType),
1089 m_caseDef.viewFormat, makeColorSubresourceRange(0, m_caseDef.numLayers),
1090 m_haveMaintenance2 ? &viewUsageCreateInfo : DE_NULL);
1091
1092 // Setup compute pipeline
1093 m_uStore.descriptorPool = DescriptorPoolBuilder()
1094 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
1095 .build(m_vk, m_device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1096
1097 m_uStore.descriptorSetLayout = DescriptorSetLayoutBuilder()
1098 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
1099 .build(m_vk, m_device);
1100
1101 m_uStore.pipelineLayout = makePipelineLayout(m_vk, m_device, *m_uStore.descriptorSetLayout);
1102 m_uStore.descriptorSet = makeDescriptorSet(m_vk, m_device, *m_uStore.descriptorPool, *m_uStore.descriptorSetLayout);
1103 m_uStore.imageDescriptorInfo = makeDescriptorImageInfo(DE_NULL, *m_uStore.imageView, VK_IMAGE_LAYOUT_GENERAL);
1104 m_uStore.computeModule =
1105 createShaderModule(m_vk, m_device, context.getBinaryCollection().get("uploadStoreComp"), 0);
1106 m_uStore.computePipeline = makeComputePipeline(m_vk, m_device, *m_uStore.pipelineLayout, *m_uStore.computeModule);
1107
1108 DescriptorSetUpdateBuilder()
1109 .writeSingle(*m_uStore.descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
1110 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &m_uStore.imageDescriptorInfo)
1111 .update(m_vk, m_device);
1112
1113 // Transition storage image for shader access (imageStore)
1114 VkImageLayout requiredImageLayout = VK_IMAGE_LAYOUT_GENERAL;
1115 const VkImageMemoryBarrier imageBarrier = {
1116 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1117 DE_NULL, // const void* pNext;
1118 (VkAccessFlags)0, // VkAccessFlags srcAccessMask;
1119 (VkAccessFlags)VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags dstAccessMask;
1120 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
1121 requiredImageLayout, // VkImageLayout newLayout;
1122 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1123 VK_QUEUE_FAMILY_IGNORED, // uint32_t destQueueFamilyIndex;
1124 m_image, // VkImage image;
1125 makeColorSubresourceRange(0, m_caseDef.numLayers), // VkImageSubresourceRange subresourceRange;
1126 };
1127
1128 m_vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u,
1129 DE_NULL, 0u, DE_NULL, 1u, &imageBarrier);
1130
1131 // Dispatch
1132 m_vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_uStore.computePipeline);
1133 m_vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_uStore.pipelineLayout, 0u, 1u,
1134 &m_uStore.descriptorSet.get(), 0u, DE_NULL);
1135 m_vk.cmdDispatch(*m_cmdBuffer, m_caseDef.size.x(), m_caseDef.size.y(), m_caseDef.numLayers);
1136
1137 m_imageLayoutAfterUpload = requiredImageLayout;
1138 m_imageUploadAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
1139 }
1140
uploadCopy(Context & context)1141 void UploadDownloadExecutor::uploadCopy(Context &context)
1142 {
1143 (void)context;
1144
1145 // Create a host-mappable buffer with the color data to upload
1146 const VkDeviceSize pixelSize = tcu::getPixelSize(mapVkFormat(m_caseDef.imageFormat));
1147 const VkDeviceSize layerSize = m_caseDef.size.x() * m_caseDef.size.y() * m_caseDef.size.z() * pixelSize;
1148
1149 m_uCopy.colorBufferSize = layerSize * m_caseDef.numLayers;
1150 m_uCopy.colorBuffer = makeBuffer(m_vk, m_device, m_uCopy.colorBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
1151 m_uCopy.colorBufferAlloc =
1152 bindBuffer(m_vk, m_device, m_allocator, *m_uCopy.colorBuffer, MemoryRequirement::HostVisible);
1153
1154 // Fill color buffer
1155 const tcu::TextureFormat tcuFormat = mapVkFormat(m_caseDef.imageFormat);
1156 VkDeviceSize layerOffset = 0ull;
1157 for (uint32_t layer = 0; layer < m_caseDef.numLayers; layer++)
1158 {
1159 tcu::PixelBufferAccess imageAccess =
1160 tcu::PixelBufferAccess(tcuFormat, m_caseDef.size.x(), m_caseDef.size.y(), 1u,
1161 (uint8_t *)m_uCopy.colorBufferAlloc->getHostPtr() + layerOffset);
1162 const uint32_t colorIdx = layer % COLOR_TABLE_SIZE;
1163 if (m_imageIsIntegerFormat)
1164 {
1165 const VkClearValue clearValue = getClearValueInt(m_caseDef, colorIdx);
1166 const IVec4 colorInt(clearValue.color.int32[0], clearValue.color.int32[1], clearValue.color.int32[2],
1167 clearValue.color.int32[3]);
1168
1169 tcu::clear(imageAccess, colorInt);
1170 }
1171 else
1172 tcu::clear(imageAccess, COLOR_TABLE_FLOAT[colorIdx]);
1173 layerOffset += layerSize;
1174 }
1175
1176 flushAlloc(m_vk, m_device, *(m_uCopy.colorBufferAlloc));
1177
1178 // Prepare buffer and image for copy
1179 const VkBufferMemoryBarrier bufferInitBarrier = {
1180 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
1181 DE_NULL, // const void* pNext;
1182 VK_ACCESS_HOST_WRITE_BIT, // VkAccessFlags srcAccessMask;
1183 VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
1184 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1185 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1186 *m_uCopy.colorBuffer, // VkBuffer buffer;
1187 0ull, // VkDeviceSize offset;
1188 VK_WHOLE_SIZE, // VkDeviceSize size;
1189 };
1190
1191 const VkImageMemoryBarrier imageInitBarrier = {
1192 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1193 DE_NULL, // const void* pNext;
1194 0u, // VkAccessFlags srcAccessMask;
1195 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask;
1196 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
1197 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout;
1198 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1199 VK_QUEUE_FAMILY_IGNORED, // uint32_t destQueueFamilyIndex;
1200 m_image, // VkImage image;
1201 makeColorSubresourceRange(0, m_caseDef.numLayers) // VkImageSubresourceRange subresourceRange;
1202 };
1203
1204 m_vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL,
1205 1u, &bufferInitBarrier, 1u, &imageInitBarrier);
1206
1207 // Copy buffer to image
1208 const VkImageSubresourceLayers subresource = {
1209 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
1210 0u, // uint32_t mipLevel;
1211 0u, // uint32_t baseArrayLayer;
1212 m_caseDef.numLayers, // uint32_t layerCount;
1213 };
1214
1215 const VkBufferImageCopy region = {
1216 0ull, // VkDeviceSize bufferOffset;
1217 0u, // uint32_t bufferRowLength;
1218 0u, // uint32_t bufferImageHeight;
1219 subresource, // VkImageSubresourceLayers imageSubresource;
1220 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
1221 makeExtent3D(m_caseDef.size), // VkExtent3D imageExtent;
1222 };
1223
1224 m_vk.cmdCopyBufferToImage(*m_cmdBuffer, *m_uCopy.colorBuffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u,
1225 ®ion);
1226
1227 const VkImageMemoryBarrier imagePostInitBarrier = {
1228 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1229 DE_NULL, // const void* pNext;
1230 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
1231 VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
1232 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout;
1233 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout;
1234 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1235 VK_QUEUE_FAMILY_IGNORED, // uint32_t destQueueFamilyIndex;
1236 m_image, // VkImage image;
1237 makeColorSubresourceRange(0, m_caseDef.numLayers) // VkImageSubresourceRange subresourceRange;
1238 };
1239
1240 m_vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u,
1241 DE_NULL, 0u, DE_NULL, 1u, &imagePostInitBarrier);
1242
1243 m_imageLayoutAfterUpload = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1244 m_imageUploadAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
1245 }
1246
uploadDraw(Context & context)1247 void UploadDownloadExecutor::uploadDraw(Context &context)
1248 {
1249 // Create vertex buffer
1250 {
1251 const vector<Vec4> vertices = genVertexData(m_caseDef);
1252 const VkDeviceSize vertexBufferSize = vertices.size() * sizeof(Vec4);
1253
1254 m_uDraw.vertexBuffer = makeBuffer(m_vk, m_device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1255 m_uDraw.vertexBufferAlloc =
1256 bindBuffer(m_vk, m_device, m_allocator, *m_uDraw.vertexBuffer, MemoryRequirement::HostVisible);
1257 deMemcpy(m_uDraw.vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
1258 flushAlloc(m_vk, m_device, *(m_uDraw.vertexBufferAlloc));
1259 }
1260
1261 // Create attachments and pipelines for each image layer
1262 m_uDraw.pipelineLayout = makePipelineLayout(m_vk, m_device);
1263 m_uDraw.renderPass = makeRenderPass(m_vk, m_device, m_caseDef.viewFormat, m_caseDef.numLayers);
1264 m_uDraw.vertexModule = createShaderModule(m_vk, m_device, context.getBinaryCollection().get("uploadDrawVert"), 0u);
1265 m_uDraw.fragmentModule =
1266 createShaderModule(m_vk, m_device, context.getBinaryCollection().get("uploadDrawFrag"), 0u);
1267
1268 for (uint32_t subpassNdx = 0; subpassNdx < m_caseDef.numLayers; ++subpassNdx)
1269 {
1270 const vk::VkImageViewUsageCreateInfo viewUsageCreateInfo = {
1271 VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, // VkStructureType sType
1272 DE_NULL, // const void* pNext
1273 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, // VkImageUsageFlags usage;
1274 };
1275 Move<VkImageView> imageView = makeImageView(m_vk, m_device, m_image, getImageViewType(m_caseDef.imageType),
1276 m_caseDef.viewFormat, makeColorSubresourceRange(subpassNdx, 1),
1277 m_haveMaintenance2 ? &viewUsageCreateInfo : DE_NULL);
1278 m_uDraw.attachmentHandles.push_back(*imageView);
1279 m_uDraw.attachments.push_back(makeSharedPtr(imageView));
1280 m_uDraw.pipelines.push_back(makeSharedPtr(makeGraphicsPipeline(
1281 m_vk, m_device, *m_uDraw.pipelineLayout, *m_uDraw.renderPass, *m_uDraw.vertexModule,
1282 *m_uDraw.fragmentModule, m_caseDef.size.swizzle(0, 1), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, subpassNdx)));
1283 }
1284
1285 // Create framebuffer
1286 {
1287 const IVec2 size = m_caseDef.size.swizzle(0, 1);
1288
1289 m_uDraw.framebuffer = makeFramebuffer(
1290 m_vk, m_device, *m_uDraw.renderPass, static_cast<uint32_t>(m_uDraw.attachmentHandles.size()),
1291 &m_uDraw.attachmentHandles[0], static_cast<uint32_t>(size.x()), static_cast<uint32_t>(size.y()));
1292 }
1293
1294 // Create command buffer
1295 {
1296 {
1297 vector<VkClearValue> clearValues(m_caseDef.numLayers, m_viewIsIntegerFormat ?
1298 getClearValueInt(m_caseDef, 0) :
1299 REFERENCE_CLEAR_COLOR_FLOAT[0]);
1300
1301 beginRenderPass(m_vk, *m_cmdBuffer, *m_uDraw.renderPass, *m_uDraw.framebuffer,
1302 makeRect2D(0, 0, m_caseDef.size.x(), m_caseDef.size.y()), (uint32_t)clearValues.size(),
1303 &clearValues[0]);
1304 }
1305
1306 // Render
1307 const VkDeviceSize vertexDataPerDraw = 4 * 2 * sizeof(Vec4);
1308 VkDeviceSize vertexBufferOffset = 0ull;
1309 for (uint32_t subpassNdx = 0; subpassNdx < m_caseDef.numLayers; ++subpassNdx)
1310 {
1311 if (subpassNdx != 0)
1312 m_vk.cmdNextSubpass(*m_cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
1313
1314 m_vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **m_uDraw.pipelines[subpassNdx]);
1315
1316 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_uDraw.vertexBuffer.get(), &vertexBufferOffset);
1317 m_vk.cmdDraw(*m_cmdBuffer, 4u, 1u, 0u, 0u);
1318 vertexBufferOffset += vertexDataPerDraw;
1319 }
1320
1321 endRenderPass(m_vk, *m_cmdBuffer);
1322 }
1323
1324 m_imageLayoutAfterUpload = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1325 m_imageUploadAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1326 }
1327
downloadCopy(Context & context,VkBuffer buffer)1328 void UploadDownloadExecutor::downloadCopy(Context &context, VkBuffer buffer)
1329 {
1330 (void)context;
1331
1332 copyImageToBuffer(m_image, buffer, m_caseDef.size, m_imageUploadAccessMask, m_imageLayoutAfterUpload,
1333 m_caseDef.numLayers);
1334 }
1335
downloadTexture(Context & context,VkBuffer buffer)1336 void UploadDownloadExecutor::downloadTexture(Context &context, VkBuffer buffer)
1337 {
1338 // Create output image with download result
1339 const VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1340 m_dTex.outImage = makeImage(m_vk, m_device, 0u, VK_IMAGE_TYPE_2D, m_caseDef.viewFormat, m_caseDef.viewFormat, false,
1341 m_caseDef.size, 1u, m_caseDef.numLayers, usageFlags);
1342 m_dTex.outImageAlloc = bindImage(m_vk, m_device, m_allocator, *m_dTex.outImage, MemoryRequirement::Any);
1343 m_dTex.outImageView = makeImageView(m_vk, m_device, *m_dTex.outImage, getImageViewType(m_caseDef.imageType),
1344 m_caseDef.viewFormat, makeColorSubresourceRange(0, m_caseDef.numLayers));
1345
1346 const vk::VkImageViewUsageCreateInfo viewUsageCreateInfo = {
1347 VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, // VkStructureType sType
1348 DE_NULL, // const void* pNext
1349 VK_IMAGE_USAGE_SAMPLED_BIT, // VkImageUsageFlags usage;
1350 };
1351 m_dTex.inImageView = makeImageView(m_vk, m_device, m_image, getImageViewType(m_caseDef.imageType),
1352 m_caseDef.viewFormat, makeColorSubresourceRange(0, m_caseDef.numLayers),
1353 m_haveMaintenance2 ? &viewUsageCreateInfo : DE_NULL);
1354 m_dTex.sampler = makeSampler(m_vk, m_device);
1355
1356 // Setup compute pipeline
1357 m_dTex.descriptorPool = DescriptorPoolBuilder()
1358 .addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
1359 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
1360 .build(m_vk, m_device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1361
1362 m_dTex.descriptorSetLayout = DescriptorSetLayoutBuilder()
1363 .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1364 VK_SHADER_STAGE_COMPUTE_BIT, &m_dTex.sampler.get())
1365 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
1366 .build(m_vk, m_device);
1367
1368 m_dTex.pipelineLayout = makePipelineLayout(m_vk, m_device, *m_dTex.descriptorSetLayout);
1369 m_dTex.descriptorSet = makeDescriptorSet(m_vk, m_device, *m_dTex.descriptorPool, *m_dTex.descriptorSetLayout);
1370 m_dTex.inImageDescriptorInfo =
1371 makeDescriptorImageInfo(DE_NULL, *m_dTex.inImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
1372 m_dTex.outImageDescriptorInfo = makeDescriptorImageInfo(DE_NULL, *m_dTex.outImageView, VK_IMAGE_LAYOUT_GENERAL);
1373 m_dTex.computeModule =
1374 createShaderModule(m_vk, m_device, context.getBinaryCollection().get("downloadTextureComp"), 0);
1375 m_dTex.computePipeline = makeComputePipeline(m_vk, m_device, *m_dTex.pipelineLayout, *m_dTex.computeModule);
1376
1377 DescriptorSetUpdateBuilder()
1378 .writeSingle(*m_dTex.descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
1379 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &m_dTex.inImageDescriptorInfo)
1380 .writeSingle(*m_dTex.descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
1381 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &m_dTex.outImageDescriptorInfo)
1382 .update(m_vk, m_device);
1383
1384 // Transition images for shader access (texture / imageStore)
1385 const VkImageMemoryBarrier imageBarriers[] = {
1386 {
1387 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1388 DE_NULL, // const void* pNext;
1389 (VkAccessFlags)m_imageUploadAccessMask, // VkAccessFlags srcAccessMask;
1390 (VkAccessFlags)VK_ACCESS_SHADER_READ_BIT, // VkAccessFlags dstAccessMask;
1391 m_imageLayoutAfterUpload, // VkImageLayout oldLayout;
1392 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // VkImageLayout newLayout;
1393 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1394 VK_QUEUE_FAMILY_IGNORED, // uint32_t destQueueFamilyIndex;
1395 m_image, // VkImage image;
1396 makeColorSubresourceRange(0, m_caseDef.numLayers), // VkImageSubresourceRange subresourceRange;
1397 },
1398 {
1399 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1400 DE_NULL, // const void* pNext;
1401 (VkAccessFlags)0, // VkAccessFlags srcAccessMask;
1402 (VkAccessFlags)VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags dstAccessMask;
1403 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
1404 VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout;
1405 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1406 VK_QUEUE_FAMILY_IGNORED, // uint32_t destQueueFamilyIndex;
1407 *m_dTex.outImage, // VkImage image;
1408 makeColorSubresourceRange(0, m_caseDef.numLayers), // VkImageSubresourceRange subresourceRange;
1409 }};
1410
1411 m_vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u,
1412 0u, DE_NULL, 0u, DE_NULL, 2u, imageBarriers);
1413
1414 // Dispatch
1415 m_vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_dTex.computePipeline);
1416 m_vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_dTex.pipelineLayout, 0u, 1u,
1417 &m_dTex.descriptorSet.get(), 0u, DE_NULL);
1418 m_vk.cmdDispatch(*m_cmdBuffer, m_caseDef.size.x(), m_caseDef.size.y(), m_caseDef.numLayers);
1419
1420 // Copy output image to color buffer
1421 copyImageToBuffer(*m_dTex.outImage, buffer, m_caseDef.size, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL,
1422 m_caseDef.numLayers);
1423 }
1424
downloadLoad(Context & context,VkBuffer buffer)1425 void UploadDownloadExecutor::downloadLoad(Context &context, VkBuffer buffer)
1426 {
1427 // Create output image with download result
1428 const VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1429 m_dLoad.outImage = makeImage(m_vk, m_device, 0u, VK_IMAGE_TYPE_2D, m_caseDef.viewFormat, m_caseDef.viewFormat,
1430 false, m_caseDef.size, 1u, m_caseDef.numLayers, usageFlags);
1431 m_dLoad.outImageAlloc = bindImage(m_vk, m_device, m_allocator, *m_dLoad.outImage, MemoryRequirement::Any);
1432 m_dLoad.outImageView = makeImageView(m_vk, m_device, *m_dLoad.outImage, getImageViewType(m_caseDef.imageType),
1433 m_caseDef.viewFormat, makeColorSubresourceRange(0, m_caseDef.numLayers));
1434
1435 const vk::VkImageViewUsageCreateInfo viewUsageCreateInfo = {
1436 VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, // VkStructureType sType
1437 DE_NULL, // const void* pNext
1438 VK_IMAGE_USAGE_STORAGE_BIT, // VkImageUsageFlags usage;
1439 };
1440 m_dLoad.inImageView = makeImageView(m_vk, m_device, m_image, getImageViewType(m_caseDef.imageType),
1441 m_caseDef.viewFormat, makeColorSubresourceRange(0, m_caseDef.numLayers),
1442 m_haveMaintenance2 ? &viewUsageCreateInfo : DE_NULL);
1443
1444 // Setup compute pipeline
1445 m_dLoad.descriptorPool = DescriptorPoolBuilder()
1446 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 2u)
1447 .build(m_vk, m_device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1448
1449 m_dLoad.descriptorSetLayout = DescriptorSetLayoutBuilder()
1450 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
1451 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
1452 .build(m_vk, m_device);
1453
1454 m_dLoad.pipelineLayout = makePipelineLayout(m_vk, m_device, *m_dLoad.descriptorSetLayout);
1455 m_dLoad.descriptorSet = makeDescriptorSet(m_vk, m_device, *m_dLoad.descriptorPool, *m_dLoad.descriptorSetLayout);
1456 m_dLoad.inImageDescriptorInfo = makeDescriptorImageInfo(DE_NULL, *m_dLoad.inImageView, VK_IMAGE_LAYOUT_GENERAL);
1457 m_dLoad.outImageDescriptorInfo = makeDescriptorImageInfo(DE_NULL, *m_dLoad.outImageView, VK_IMAGE_LAYOUT_GENERAL);
1458 m_dLoad.computeModule =
1459 createShaderModule(m_vk, m_device, context.getBinaryCollection().get("downloadLoadComp"), 0);
1460 m_dLoad.computePipeline = makeComputePipeline(m_vk, m_device, *m_dLoad.pipelineLayout, *m_dLoad.computeModule);
1461
1462 DescriptorSetUpdateBuilder()
1463 .writeSingle(*m_dLoad.descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
1464 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &m_dLoad.inImageDescriptorInfo)
1465 .writeSingle(*m_dLoad.descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
1466 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &m_dLoad.outImageDescriptorInfo)
1467 .update(m_vk, m_device);
1468
1469 // Transition storage images for shader access (imageLoad/Store)
1470 VkImageLayout requiredImageLayout = VK_IMAGE_LAYOUT_GENERAL;
1471 const VkImageMemoryBarrier imageBarriers[] = {
1472 {
1473 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1474 DE_NULL, // const void* pNext;
1475 (VkAccessFlags)m_imageUploadAccessMask, // VkAccessFlags srcAccessMask;
1476 (VkAccessFlags)VK_ACCESS_SHADER_READ_BIT, // VkAccessFlags dstAccessMask;
1477 m_imageLayoutAfterUpload, // VkImageLayout oldLayout;
1478 requiredImageLayout, // VkImageLayout newLayout;
1479 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1480 VK_QUEUE_FAMILY_IGNORED, // uint32_t destQueueFamilyIndex;
1481 m_image, // VkImage image;
1482 makeColorSubresourceRange(0, m_caseDef.numLayers), // VkImageSubresourceRange subresourceRange;
1483 },
1484 {
1485 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1486 DE_NULL, // const void* pNext;
1487 (VkAccessFlags)0, // VkAccessFlags srcAccessMask;
1488 (VkAccessFlags)VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags dstAccessMask;
1489 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
1490 requiredImageLayout, // VkImageLayout newLayout;
1491 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1492 VK_QUEUE_FAMILY_IGNORED, // uint32_t destQueueFamilyIndex;
1493 *m_dLoad.outImage, // VkImage image;
1494 makeColorSubresourceRange(0, m_caseDef.numLayers), // VkImageSubresourceRange subresourceRange;
1495 }};
1496
1497 m_vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u,
1498 0u, DE_NULL, 0u, DE_NULL, 2u, imageBarriers);
1499
1500 // Dispatch
1501 m_vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_dLoad.computePipeline);
1502 m_vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_dLoad.pipelineLayout, 0u, 1u,
1503 &m_dLoad.descriptorSet.get(), 0u, DE_NULL);
1504 m_vk.cmdDispatch(*m_cmdBuffer, m_caseDef.size.x(), m_caseDef.size.y(), m_caseDef.numLayers);
1505
1506 // Copy output image to color buffer
1507 copyImageToBuffer(*m_dLoad.outImage, buffer, m_caseDef.size, VK_ACCESS_SHADER_WRITE_BIT, requiredImageLayout,
1508 m_caseDef.numLayers);
1509 }
1510
copyImageToBuffer(VkImage sourceImage,VkBuffer buffer,const IVec3 size,const VkAccessFlags srcAccessMask,const VkImageLayout oldLayout,const uint32_t numLayers)1511 void UploadDownloadExecutor::copyImageToBuffer(VkImage sourceImage, VkBuffer buffer, const IVec3 size,
1512 const VkAccessFlags srcAccessMask, const VkImageLayout oldLayout,
1513 const uint32_t numLayers)
1514 {
1515 // Copy result to host visible buffer for inspection
1516 const VkImageMemoryBarrier imageBarrier = {
1517 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1518 DE_NULL, // const void* pNext;
1519 srcAccessMask, // VkAccessFlags srcAccessMask;
1520 VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
1521 oldLayout, // VkImageLayout oldLayout;
1522 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout;
1523 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1524 VK_QUEUE_FAMILY_IGNORED, // uint32_t destQueueFamilyIndex;
1525 sourceImage, // VkImage image;
1526 makeColorSubresourceRange(0, numLayers) // VkImageSubresourceRange subresourceRange;
1527 };
1528
1529 m_vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u,
1530 DE_NULL, 0u, DE_NULL, 1u, &imageBarrier);
1531
1532 const VkImageSubresourceLayers subresource = {
1533 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
1534 0u, // uint32_t mipLevel;
1535 0u, // uint32_t baseArrayLayer;
1536 numLayers, // uint32_t layerCount;
1537 };
1538
1539 const VkBufferImageCopy region = {
1540 0ull, // VkDeviceSize bufferOffset;
1541 0u, // uint32_t bufferRowLength;
1542 0u, // uint32_t bufferImageHeight;
1543 subresource, // VkImageSubresourceLayers imageSubresource;
1544 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
1545 makeExtent3D(size), // VkExtent3D imageExtent;
1546 };
1547
1548 m_vk.cmdCopyImageToBuffer(*m_cmdBuffer, sourceImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, 1u, ®ion);
1549
1550 const VkBufferMemoryBarrier bufferBarrier = {
1551 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
1552 DE_NULL, // const void* pNext;
1553 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
1554 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
1555 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1556 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1557 buffer, // VkBuffer buffer;
1558 0ull, // VkDeviceSize offset;
1559 VK_WHOLE_SIZE, // VkDeviceSize size;
1560 };
1561
1562 m_vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL,
1563 1u, &bufferBarrier, 0u, DE_NULL);
1564 }
1565
testMutable(Context & context,const CaseDef caseDef)1566 tcu::TestStatus testMutable(Context &context, const CaseDef caseDef)
1567 {
1568 const DeviceInterface &vk = context.getDeviceInterface();
1569 const VkDevice device = context.getDevice();
1570 Allocator &allocator = context.getDefaultAllocator();
1571
1572 // Create a color buffer for host-inspection of results
1573 // For the Copy download method, this is the target of the download, for other
1574 // download methods, pixel data will be copied to this buffer from the download
1575 // target
1576 const VkDeviceSize colorBufferSize = caseDef.size.x() * caseDef.size.y() * caseDef.size.z() * caseDef.numLayers *
1577 tcu::getPixelSize(mapVkFormat(caseDef.imageFormat));
1578 const Unique<VkBuffer> colorBuffer(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1579 const UniquePtr<Allocation> colorBufferAlloc(
1580 bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
1581 deMemset(colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
1582 flushAlloc(vk, device, *colorBufferAlloc);
1583
1584 // Execute the test
1585 UploadDownloadExecutor executor(context, context.isDeviceFunctionalitySupported("VK_KHR_maintenance2"),
1586 context.getDeviceInterface(), device, context.getUniversalQueue(),
1587 context.getUniversalQueueFamilyIndex(), caseDef);
1588 executor.run(context, *colorBuffer);
1589
1590 // Verify results
1591 {
1592 invalidateAlloc(vk, device, *colorBufferAlloc);
1593
1594 // For verification purposes, we use the format of the upload to generate the expected image
1595 const VkFormat format =
1596 caseDef.upload == UPLOAD_CLEAR || caseDef.upload == UPLOAD_COPY ? caseDef.imageFormat : caseDef.viewFormat;
1597 const tcu::TextureFormat tcuFormat = mapVkFormat(format);
1598 const bool isIntegerFormat = isUintFormat(format) || isIntFormat(format);
1599 const tcu::ConstPixelBufferAccess resultImage(tcuFormat, caseDef.size.x(), caseDef.size.y(), caseDef.numLayers,
1600 colorBufferAlloc->getHostPtr());
1601 tcu::TextureLevel textureLevel(tcuFormat, caseDef.size.x(), caseDef.size.y(), caseDef.numLayers);
1602 const tcu::PixelBufferAccess expectedImage = textureLevel.getAccess();
1603 generateExpectedImage(expectedImage, caseDef);
1604
1605 bool ok;
1606 if (isIntegerFormat)
1607 ok = tcu::intThresholdCompare(context.getTestContext().getLog(), "Image comparison", "", expectedImage,
1608 resultImage, tcu::UVec4(1), tcu::COMPARE_LOG_RESULT);
1609 else
1610 ok = tcu::floatThresholdCompare(context.getTestContext().getLog(), "Image comparison", "", expectedImage,
1611 resultImage, tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
1612 return ok ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
1613 }
1614 }
1615
checkSupport(Context & context,const CaseDef caseDef)1616 void checkSupport(Context &context, const CaseDef caseDef)
1617 {
1618 const InstanceInterface &vki = context.getInstanceInterface();
1619 const VkPhysicalDevice physDevice = context.getPhysicalDevice();
1620
1621 // If this is a VK_KHR_image_format_list test, check that the extension is supported
1622 if (caseDef.isFormatListTest)
1623 context.requireDeviceFunctionality("VK_KHR_image_format_list");
1624
1625 // Check required features on the format for the required upload/download methods
1626 VkFormatProperties imageFormatProps, viewFormatProps;
1627 vki.getPhysicalDeviceFormatProperties(physDevice, caseDef.imageFormat, &imageFormatProps);
1628 vki.getPhysicalDeviceFormatProperties(physDevice, caseDef.viewFormat, &viewFormatProps);
1629
1630 VkFormatFeatureFlags viewFormatFeatureFlags = 0u;
1631 switch (caseDef.upload)
1632 {
1633 case UPLOAD_DRAW:
1634 viewFormatFeatureFlags |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
1635 break;
1636 case UPLOAD_STORE:
1637 viewFormatFeatureFlags |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
1638 break;
1639 case UPLOAD_CLEAR:
1640 viewFormatFeatureFlags |= VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
1641 break;
1642 case UPLOAD_COPY:
1643 viewFormatFeatureFlags |= VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
1644 break;
1645 default:
1646 DE_FATAL("Invalid upload method");
1647 break;
1648 }
1649 switch (caseDef.download)
1650 {
1651 case DOWNLOAD_TEXTURE:
1652 viewFormatFeatureFlags |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
1653 // For the texture case we write the samples read to a separate output image with the same view format
1654 // so we need to check that we can also use the view format for storage
1655 viewFormatFeatureFlags |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
1656 break;
1657 case DOWNLOAD_LOAD:
1658 viewFormatFeatureFlags |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
1659 break;
1660 case DOWNLOAD_COPY:
1661 viewFormatFeatureFlags |= VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
1662 break;
1663 default:
1664 DE_FATAL("Invalid download method");
1665 break;
1666 }
1667
1668 if ((viewFormatProps.optimalTilingFeatures & viewFormatFeatureFlags) != viewFormatFeatureFlags)
1669 TCU_THROW(NotSupportedError, "View format doesn't support upload/download method");
1670
1671 const bool haveMaintenance2 = context.isDeviceFunctionalitySupported("VK_KHR_maintenance2");
1672
1673 // We don't use the base image for anything other than transfer
1674 // operations so there are no features to check. However, The Vulkan
1675 // 1.0 spec does not allow us to create an image view with usage that
1676 // is not supported by the main format. With VK_KHR_maintenance2, we
1677 // can do this via VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR.
1678 if ((imageFormatProps.optimalTilingFeatures & viewFormatFeatureFlags) != viewFormatFeatureFlags &&
1679 !haveMaintenance2)
1680 {
1681 TCU_THROW(NotSupportedError, "Image format doesn't support upload/download method");
1682 }
1683
1684 // If no format feature flags are supported, the format itself is not supported,
1685 // and images of that format cannot be created.
1686 if (imageFormatProps.optimalTilingFeatures == 0)
1687 {
1688 TCU_THROW(NotSupportedError, "Base image format is not supported");
1689 }
1690 }
1691
createImageMutableTests(TestContext & testCtx)1692 tcu::TestCaseGroup *createImageMutableTests(TestContext &testCtx)
1693 {
1694 de::MovePtr<TestCaseGroup> testGroup(new TestCaseGroup(testCtx, "mutable"));
1695 for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(s_textures); ++textureNdx)
1696 {
1697 const Texture &texture = s_textures[textureNdx];
1698 de::MovePtr<tcu::TestCaseGroup> groupByImageViewType(
1699 new tcu::TestCaseGroup(testCtx, getImageTypeName(texture.type()).c_str()));
1700
1701 for (int imageFormatNdx = 0; imageFormatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++imageFormatNdx)
1702 for (int viewFormatNdx = 0; viewFormatNdx < DE_LENGTH_OF_ARRAY(s_formats); ++viewFormatNdx)
1703 {
1704 if (imageFormatNdx != viewFormatNdx &&
1705 formatsAreCompatible(s_formats[imageFormatNdx], s_formats[viewFormatNdx]))
1706 {
1707 for (int upload = 0; upload < UPLOAD_LAST; upload++)
1708 {
1709 if (upload == UPLOAD_STORE && !isFormatImageLoadStoreCapable(s_formats[viewFormatNdx]))
1710 continue;
1711
1712 for (int download = 0; download < DOWNLOAD_LAST; download++)
1713 {
1714 if ((download == DOWNLOAD_LOAD || download == DOWNLOAD_TEXTURE) &&
1715 !isFormatImageLoadStoreCapable(s_formats[viewFormatNdx]))
1716 continue;
1717
1718 CaseDef caseDef = {
1719 texture.type(),
1720 texture.layerSize(),
1721 static_cast<uint32_t>(texture.numLayers()),
1722 s_formats[imageFormatNdx],
1723 s_formats[viewFormatNdx],
1724 static_cast<enum Upload>(upload),
1725 static_cast<enum Download>(download),
1726 false, // isFormatListTest;
1727 false, // isSwapchainImageTest
1728 vk::wsi::TYPE_LAST // wsiType
1729 };
1730
1731 std::string caseName = getFormatShortString(s_formats[imageFormatNdx]) + "_" +
1732 getFormatShortString(s_formats[viewFormatNdx]) + "_" +
1733 getUploadString(upload) + "_" + getDownloadString(download);
1734 addFunctionCaseWithPrograms(groupByImageViewType.get(), caseName, checkSupport,
1735 initPrograms, testMutable, caseDef);
1736
1737 caseDef.isFormatListTest = true;
1738 caseName += "_format_list";
1739 addFunctionCaseWithPrograms(groupByImageViewType.get(), caseName, checkSupport,
1740 initPrograms, testMutable, caseDef);
1741 }
1742 }
1743 }
1744 }
1745
1746 testGroup->addChild(groupByImageViewType.release());
1747 }
1748
1749 return testGroup.release();
1750 }
1751
1752 typedef vector<VkExtensionProperties> Extensions;
1753
checkAllSupported(const Extensions & supportedExtensions,const vector<string> & requiredExtensions)1754 void checkAllSupported(const Extensions &supportedExtensions, const vector<string> &requiredExtensions)
1755 {
1756 for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
1757 requiredExtName != requiredExtensions.end(); ++requiredExtName)
1758 {
1759 if (!isExtensionStructSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
1760 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
1761 }
1762 }
1763
createInstanceWithWsi(Context & context,const Extensions & supportedExtensions,Type wsiType,const VkAllocationCallbacks * pAllocator=DE_NULL)1764 CustomInstance createInstanceWithWsi(Context &context, const Extensions &supportedExtensions, Type wsiType,
1765 const VkAllocationCallbacks *pAllocator = DE_NULL)
1766 {
1767 vector<string> extensions;
1768
1769 extensions.push_back("VK_KHR_surface");
1770 extensions.push_back(getExtensionName(wsiType));
1771 if (isDisplaySurface(wsiType))
1772 extensions.push_back("VK_KHR_display");
1773
1774 // VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
1775 // the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
1776 // but using them without enabling the extension is not allowed. Thus we have
1777 // two options:
1778 //
1779 // 1) Filter out non-core formats to stay within valid usage.
1780 //
1781 // 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
1782 //
1783 // We opt for (2) as it provides basic coverage for the extension as a bonus.
1784 if (isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_EXT_swapchain_colorspace")))
1785 extensions.push_back("VK_EXT_swapchain_colorspace");
1786
1787 checkAllSupported(supportedExtensions, extensions);
1788
1789 return createCustomInstanceWithExtensions(context, extensions, pAllocator);
1790 }
1791
createDeviceWithWsi(const PlatformInterface & vkp,VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const uint32_t queueFamilyIndex,const VkAllocationCallbacks * pAllocator,de::SharedPtr<vk::ResourceInterface> resourceInterface,const tcu::CommandLine & cmdLine)1792 Move<VkDevice> createDeviceWithWsi(const PlatformInterface &vkp, VkInstance instance, const InstanceInterface &vki,
1793 VkPhysicalDevice physicalDevice, const Extensions &supportedExtensions,
1794 const uint32_t queueFamilyIndex, const VkAllocationCallbacks *pAllocator,
1795 #ifdef CTS_USES_VULKANSC
1796 de::SharedPtr<vk::ResourceInterface> resourceInterface,
1797 #endif // CTS_USES_VULKANSC
1798 const tcu::CommandLine &cmdLine)
1799 {
1800 const float queuePriorities[] = {1.0f};
1801 const VkDeviceQueueCreateInfo queueInfos[] = {{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, DE_NULL,
1802 (VkDeviceQueueCreateFlags)0, queueFamilyIndex,
1803 DE_LENGTH_OF_ARRAY(queuePriorities), &queuePriorities[0]}};
1804 VkPhysicalDeviceFeatures features;
1805 deMemset(&features, 0x0, sizeof(features));
1806
1807 const char *const extensions[] = {"VK_KHR_swapchain", "VK_KHR_swapchain_mutable_format"};
1808
1809 void *pNext = DE_NULL;
1810 #ifdef CTS_USES_VULKANSC
1811 VkDeviceObjectReservationCreateInfo memReservationInfo =
1812 cmdLine.isSubProcess() ? resourceInterface->getStatMax() : resetDeviceObjectReservationCreateInfo();
1813 memReservationInfo.pNext = pNext;
1814 pNext = &memReservationInfo;
1815
1816 VkPhysicalDeviceVulkanSC10Features sc10Features = createDefaultSC10Features();
1817 sc10Features.pNext = pNext;
1818 pNext = &sc10Features;
1819
1820 VkPipelineCacheCreateInfo pcCI;
1821 std::vector<VkPipelinePoolSize> poolSizes;
1822 if (cmdLine.isSubProcess())
1823 {
1824 if (resourceInterface->getCacheDataSize() > 0)
1825 {
1826 pcCI = {
1827 VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType;
1828 DE_NULL, // const void* pNext;
1829 VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
1830 VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT, // VkPipelineCacheCreateFlags flags;
1831 resourceInterface->getCacheDataSize(), // uintptr_t initialDataSize;
1832 resourceInterface->getCacheData() // const void* pInitialData;
1833 };
1834 memReservationInfo.pipelineCacheCreateInfoCount = 1;
1835 memReservationInfo.pPipelineCacheCreateInfos = &pcCI;
1836 }
1837
1838 poolSizes = resourceInterface->getPipelinePoolSizes();
1839 if (!poolSizes.empty())
1840 {
1841 memReservationInfo.pipelinePoolSizeCount = uint32_t(poolSizes.size());
1842 memReservationInfo.pPipelinePoolSizes = poolSizes.data();
1843 }
1844 }
1845 #endif // CTS_USES_VULKANSC
1846
1847 const VkDeviceCreateInfo deviceParams = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
1848 pNext,
1849 (VkDeviceCreateFlags)0,
1850 DE_LENGTH_OF_ARRAY(queueInfos),
1851 &queueInfos[0],
1852 0u, // enabledLayerCount
1853 DE_NULL, // ppEnabledLayerNames
1854 DE_LENGTH_OF_ARRAY(extensions), // enabledExtensionCount
1855 DE_ARRAY_BEGIN(extensions), // ppEnabledExtensionNames
1856 &features};
1857
1858 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx)
1859 {
1860 if (!isExtensionStructSupported(supportedExtensions, RequiredExtension(extensions[ndx])))
1861 TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
1862 }
1863
1864 return createCustomDevice(cmdLine.isValidationEnabled(), vkp, instance, vki, physicalDevice, &deviceParams,
1865 pAllocator);
1866 }
1867
1868 struct InstanceHelper
1869 {
1870 const vector<VkExtensionProperties> supportedExtensions;
1871 const CustomInstance instance;
1872 const InstanceDriver &vki;
1873
InstanceHelpervkt::image::InstanceHelper1874 InstanceHelper(Context &context, Type wsiType, const VkAllocationCallbacks *pAllocator = DE_NULL)
1875 : supportedExtensions(enumerateInstanceExtensionProperties(context.getPlatformInterface(), DE_NULL))
1876 , instance(createInstanceWithWsi(context, supportedExtensions, wsiType, pAllocator))
1877 , vki(instance.getDriver())
1878 {
1879 }
1880 };
1881
1882 struct DeviceHelper
1883 {
1884 const VkPhysicalDevice physicalDevice;
1885 const uint32_t queueFamilyIndex;
1886 const Unique<VkDevice> device;
1887 const DeviceDriver vkd;
1888 const VkQueue queue;
1889
DeviceHelpervkt::image::DeviceHelper1890 DeviceHelper(Context &context, const InstanceInterface &vki, VkInstance instance, VkSurfaceKHR surface,
1891 const VkAllocationCallbacks *pAllocator = DE_NULL)
1892 : physicalDevice(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
1893 , queueFamilyIndex(chooseQueueFamilyIndex(vki, physicalDevice, surface))
1894 , device(createDeviceWithWsi(context.getPlatformInterface(), context.getInstance(), vki, physicalDevice,
1895 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL), queueFamilyIndex,
1896 pAllocator,
1897 #ifdef CTS_USES_VULKANSC
1898 context.getResourceInterface(),
1899 #endif // CTS_USES_VULKANSC
1900 context.getTestContext().getCommandLine()))
1901 , vkd(context.getPlatformInterface(), context.getInstance(), *device, context.getUsedApiVersion(),
1902 context.getTestContext().getCommandLine())
1903 , queue(getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
1904 {
1905 }
1906 };
1907
createDisplay(const vk::Platform & platform,const Extensions & supportedExtensions,Type wsiType)1908 MovePtr<Display> createDisplay(const vk::Platform &platform, const Extensions &supportedExtensions, Type wsiType)
1909 {
1910 try
1911 {
1912 return MovePtr<Display>(platform.createWsiDisplay(wsiType));
1913 }
1914 catch (const tcu::NotSupportedError &e)
1915 {
1916 if (isExtensionStructSupported(supportedExtensions, RequiredExtension(getExtensionName(wsiType))) &&
1917 platform.hasDisplay(wsiType))
1918 {
1919 // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
1920 // must support creating native display & window for that WSI type.
1921 throw tcu::TestError(e.getMessage());
1922 }
1923 else
1924 throw;
1925 }
1926 }
1927
createWindow(const Display & display,const Maybe<UVec2> & initialSize)1928 MovePtr<Window> createWindow(const Display &display, const Maybe<UVec2> &initialSize)
1929 {
1930 try
1931 {
1932 return MovePtr<Window>(display.createWindow(initialSize));
1933 }
1934 catch (const tcu::NotSupportedError &e)
1935 {
1936 // See createDisplay - assuming that wsi::Display was supported platform port
1937 // should also support creating a window.
1938 throw tcu::TestError(e.getMessage());
1939 }
1940 }
1941
1942 struct NativeObjects
1943 {
1944 const UniquePtr<Display> display;
1945 const UniquePtr<Window> window;
1946
NativeObjectsvkt::image::NativeObjects1947 NativeObjects(Context &context, const Extensions &supportedExtensions, Type wsiType,
1948 const Maybe<UVec2> &initialWindowSize = tcu::Nothing)
1949 : display(
1950 createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
1951 , window(createWindow(*display, initialWindowSize))
1952 {
1953 }
1954 };
1955
makeSwapchain(const DeviceInterface & vk,const VkDevice device,const vk::wsi::Type wsiType,const VkSurfaceKHR surface,const VkSurfaceCapabilitiesKHR capabilities,const VkSurfaceFormatKHR surfaceFormat,const VkFormat viewFormat,const uint32_t numLayers,const VkImageUsageFlags usage,const tcu::UVec2 & desiredSize,uint32_t desiredImageCount)1956 Move<VkSwapchainKHR> makeSwapchain(const DeviceInterface &vk, const VkDevice device, const vk::wsi::Type wsiType,
1957 const VkSurfaceKHR surface, const VkSurfaceCapabilitiesKHR capabilities,
1958 const VkSurfaceFormatKHR surfaceFormat, const VkFormat viewFormat,
1959 const uint32_t numLayers, const VkImageUsageFlags usage,
1960 const tcu::UVec2 &desiredSize, uint32_t desiredImageCount)
1961 {
1962 const VkFormat formatList[2] = {surfaceFormat.format, viewFormat};
1963
1964 const VkImageFormatListCreateInfo formatListInfo = {
1965 VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO, // VkStructureType sType;
1966 DE_NULL, // const void* pNext;
1967 2u, // uint32_t viewFormatCount
1968 formatList // const VkFormat* pViewFormats
1969 };
1970
1971 const VkSurfaceTransformFlagBitsKHR transform =
1972 (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ?
1973 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
1974 capabilities.currentTransform;
1975 const PlatformProperties &platformProperties = getPlatformProperties(wsiType);
1976
1977 const VkSwapchainCreateInfoKHR swapchainInfo = {
1978 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, // VkStructureType sType;
1979 &formatListInfo, // const void* pNext;
1980 VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR, // VkSwapchainCreateFlagsKHR flags;
1981 surface, // VkSurfaceKHR surface;
1982 de::clamp(desiredImageCount, capabilities.minImageCount,
1983 capabilities.maxImageCount > 0 ?
1984 capabilities.maxImageCount :
1985 capabilities.minImageCount + desiredImageCount), // uint32_t minImageCount;
1986 surfaceFormat.format, // VkFormat imageFormat;
1987 surfaceFormat.colorSpace, // VkColorSpaceKHR imageColorSpace;
1988 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE ?
1989 capabilities.currentExtent :
1990 vk::makeExtent2D(desiredSize.x(), desiredSize.y())), // VkExtent2D imageExtent;
1991 numLayers, // uint32_t imageArrayLayers;
1992 usage, // VkImageUsageFlags imageUsage;
1993 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode imageSharingMode;
1994 0u, // uint32_t queueFamilyIndexCount;
1995 (const uint32_t *)DE_NULL, // const uint32_t* pQueueFamilyIndices;
1996 transform, // VkSurfaceTransformFlagBitsKHR preTransform;
1997 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, // VkCompositeAlphaFlagBitsKHR compositeAlpha;
1998 VK_PRESENT_MODE_FIFO_KHR, // VkPresentModeKHR presentMode;
1999 VK_FALSE, // VkBool32 clipped;
2000 (VkSwapchainKHR)0 // VkSwapchainKHR oldSwapchain;
2001 };
2002
2003 return createSwapchainKHR(vk, device, &swapchainInfo);
2004 }
2005
testSwapchainMutable(Context & context,CaseDef caseDef)2006 tcu::TestStatus testSwapchainMutable(Context &context, CaseDef caseDef)
2007 {
2008 const Type wsiType(caseDef.wsiType);
2009 const tcu::UVec2 desiredSize(256, 256);
2010 const InstanceHelper instHelper(context, wsiType);
2011 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
2012 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display,
2013 *native.window, context.getTestContext().getCommandLine()));
2014 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2015 const DeviceInterface &vk = devHelper.vkd;
2016 const InstanceDriver &vki = instHelper.vki;
2017 const VkDevice device = *devHelper.device;
2018 const VkPhysicalDevice physDevice = devHelper.physicalDevice;
2019 SimpleAllocator allocator(vk, device, getPhysicalDeviceMemoryProperties(vki, context.getPhysicalDevice()));
2020
2021 const VkImageUsageFlags imageUsage = getImageUsageForTestCase(caseDef);
2022
2023 {
2024 VkImageFormatProperties properties;
2025 VkResult result;
2026
2027 result =
2028 vki.getPhysicalDeviceImageFormatProperties(physDevice, caseDef.imageFormat, getImageType(caseDef.imageType),
2029 VK_IMAGE_TILING_OPTIMAL, imageUsage, 0, &properties);
2030
2031 if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
2032 {
2033 TCU_THROW(NotSupportedError, "Image format is not supported for required usage");
2034 }
2035
2036 result =
2037 vki.getPhysicalDeviceImageFormatProperties(physDevice, caseDef.viewFormat, getImageType(caseDef.imageType),
2038 VK_IMAGE_TILING_OPTIMAL, imageUsage, 0, &properties);
2039
2040 if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
2041 {
2042 TCU_THROW(NotSupportedError, "Image view format is not supported for required usage");
2043 }
2044 }
2045
2046 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(vki, physDevice, *surface);
2047
2048 if (caseDef.numLayers > capabilities.maxImageArrayLayers)
2049 caseDef.numLayers = capabilities.maxImageArrayLayers;
2050
2051 // Check support for requested formats by swapchain surface
2052 const vector<VkSurfaceFormatKHR> surfaceFormats = getPhysicalDeviceSurfaceFormats(vki, physDevice, *surface);
2053
2054 const VkSurfaceFormatKHR *surfaceFormat = DE_NULL;
2055 const VkFormat *viewFormat = DE_NULL;
2056
2057 for (vector<VkSurfaceFormatKHR>::size_type i = 0; i < surfaceFormats.size(); i++)
2058 {
2059 if (surfaceFormats[i].format == caseDef.imageFormat)
2060 surfaceFormat = &surfaceFormats[i];
2061
2062 if (surfaceFormats[i].format == caseDef.viewFormat)
2063 viewFormat = &surfaceFormats[i].format;
2064 }
2065
2066 if (surfaceFormat == DE_NULL)
2067 TCU_THROW(NotSupportedError, "Image format is not supported by swapchain.");
2068
2069 if (viewFormat == DE_NULL)
2070 TCU_THROW(NotSupportedError, "Image view format is not supported by swapchain.");
2071
2072 if ((capabilities.supportedUsageFlags & imageUsage) != imageUsage)
2073 TCU_THROW(NotSupportedError, "Image usage request not supported by swapchain.");
2074
2075 const Unique<VkSwapchainKHR> swapchain(makeSwapchain(vk, device, caseDef.wsiType, *surface, capabilities,
2076 *surfaceFormat, caseDef.viewFormat, caseDef.numLayers,
2077 imageUsage, desiredSize, 2));
2078 const vector<VkImage> swapchainImages = getSwapchainImages(vk, device, *swapchain);
2079
2080 // Create a color buffer for host-inspection of results
2081 // For the Copy download method, this is the target of the download, for other
2082 // download methods, pixel data will be copied to this buffer from the download
2083 // target
2084 const VkDeviceSize colorBufferSize = caseDef.size.x() * caseDef.size.y() * caseDef.size.z() * caseDef.numLayers *
2085 tcu::getPixelSize(mapVkFormat(caseDef.imageFormat));
2086 const Unique<VkBuffer> colorBuffer(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
2087 const UniquePtr<Allocation> colorBufferAlloc(
2088 bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
2089 deMemset(colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
2090 flushAlloc(vk, device, *colorBufferAlloc);
2091
2092 // Execute the test
2093 UploadDownloadExecutor executor(context, false, vk, device, devHelper.queue, devHelper.queueFamilyIndex, caseDef);
2094
2095 executor.runSwapchain(context, *colorBuffer, swapchainImages[0]);
2096
2097 // Verify results
2098 {
2099 invalidateAlloc(vk, device, *colorBufferAlloc);
2100
2101 // For verification purposes, we use the format of the upload to generate the expected image
2102 const VkFormat format =
2103 caseDef.upload == UPLOAD_CLEAR || caseDef.upload == UPLOAD_COPY ? caseDef.imageFormat : caseDef.viewFormat;
2104 const tcu::TextureFormat tcuFormat = mapVkFormat(format);
2105 const bool isIntegerFormat = isUintFormat(format) || isIntFormat(format);
2106 const tcu::ConstPixelBufferAccess resultImage(tcuFormat, caseDef.size.x(), caseDef.size.y(), caseDef.numLayers,
2107 colorBufferAlloc->getHostPtr());
2108 tcu::TextureLevel textureLevel(tcuFormat, caseDef.size.x(), caseDef.size.y(), caseDef.numLayers);
2109 const tcu::PixelBufferAccess expectedImage = textureLevel.getAccess();
2110 generateExpectedImage(expectedImage, caseDef);
2111
2112 bool ok;
2113 if (isIntegerFormat)
2114 ok = tcu::intThresholdCompare(context.getTestContext().getLog(), "Image comparison", "", expectedImage,
2115 resultImage, tcu::UVec4(1), tcu::COMPARE_LOG_RESULT);
2116 else
2117 ok = tcu::floatThresholdCompare(context.getTestContext().getLog(), "Image comparison", "", expectedImage,
2118 resultImage, tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
2119 return ok ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
2120 }
2121 }
2122
createSwapchainImageMutableTests(TestContext & testCtx)2123 tcu::TestCaseGroup *createSwapchainImageMutableTests(TestContext &testCtx)
2124 {
2125 de::MovePtr<TestCaseGroup> testGroup(new TestCaseGroup(testCtx, "swapchain_mutable"));
2126
2127 for (int typeNdx = 0; typeNdx < vk::wsi::TYPE_LAST; ++typeNdx)
2128 {
2129 const vk::wsi::Type wsiType = (vk::wsi::Type)typeNdx;
2130
2131 de::MovePtr<TestCaseGroup> testGroupWsi(new TestCaseGroup(testCtx, getName(wsiType)));
2132
2133 for (int textureNdx = 0; textureNdx < DE_LENGTH_OF_ARRAY(s_textures); ++textureNdx)
2134 {
2135 const Texture &texture = s_textures[textureNdx];
2136 de::MovePtr<tcu::TestCaseGroup> groupByImageViewType(
2137 new tcu::TestCaseGroup(testCtx, getImageTypeName(texture.type()).c_str()));
2138
2139 for (int imageFormatNdx = 0; imageFormatNdx < DE_LENGTH_OF_ARRAY(s_swapchainFormats); ++imageFormatNdx)
2140 for (int viewFormatNdx = 0; viewFormatNdx < DE_LENGTH_OF_ARRAY(s_swapchainFormats); ++viewFormatNdx)
2141 {
2142 if (imageFormatNdx != viewFormatNdx &&
2143 formatsAreCompatible(s_swapchainFormats[imageFormatNdx], s_swapchainFormats[viewFormatNdx]))
2144 {
2145 for (int upload = 0; upload < UPLOAD_LAST; upload++)
2146 {
2147 if (upload == UPLOAD_STORE &&
2148 !isFormatImageLoadStoreCapable(s_swapchainFormats[viewFormatNdx]))
2149 continue;
2150
2151 for (int download = 0; download < DOWNLOAD_LAST; download++)
2152 {
2153 if ((download == DOWNLOAD_LOAD || download == DOWNLOAD_TEXTURE) &&
2154 !isFormatImageLoadStoreCapable(s_swapchainFormats[viewFormatNdx]))
2155 continue;
2156
2157 CaseDef caseDef = {texture.type(),
2158 texture.layerSize(),
2159 static_cast<uint32_t>(texture.numLayers()),
2160 s_swapchainFormats[imageFormatNdx],
2161 s_swapchainFormats[viewFormatNdx],
2162 static_cast<enum Upload>(upload),
2163 static_cast<enum Download>(download),
2164 true, // isFormatListTest;
2165 true, // isSwapchainImageTest
2166 wsiType};
2167
2168 std::string caseName = getFormatShortString(s_swapchainFormats[imageFormatNdx]) + "_" +
2169 getFormatShortString(s_swapchainFormats[viewFormatNdx]) + "_" +
2170 getUploadString(upload) + "_" + getDownloadString(download) +
2171 "_format_list";
2172
2173 addFunctionCaseWithPrograms(groupByImageViewType.get(), caseName, checkSupport,
2174 initPrograms, testSwapchainMutable, caseDef);
2175 }
2176 }
2177 }
2178 }
2179
2180 testGroupWsi->addChild(groupByImageViewType.release());
2181 }
2182
2183 testGroup->addChild(testGroupWsi.release());
2184 }
2185 return testGroup.release();
2186 }
2187
2188 } // namespace image
2189 } // namespace vkt
2190