• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Imagination Technologies Ltd.
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Image sampling case
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktPipelineImageSamplingInstance.hpp"
28 #include "vktPipelineClearUtil.hpp"
29 #include "vktPipelineReferenceRenderer.hpp"
30 #include "vkBuilderUtil.hpp"
31 #include "vkImageUtil.hpp"
32 #include "vkPrograms.hpp"
33 #include "vkQueryUtil.hpp"
34 #include "vkRefUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkTypeUtil.hpp"
38 #include "vkObjUtil.hpp"
39 #include "tcuTexLookupVerifier.hpp"
40 #include "tcuTextureUtil.hpp"
41 #include "tcuTestLog.hpp"
42 #include "deSTLUtil.hpp"
43 
44 namespace vkt
45 {
46 namespace pipeline
47 {
48 
49 using namespace vk;
50 using de::MovePtr;
51 using de::UniquePtr;
52 
53 namespace
54 {
allocateBuffer(const InstanceInterface & vki,const DeviceInterface & vkd,const VkPhysicalDevice & physDevice,const VkDevice device,const VkBuffer & buffer,const MemoryRequirement requirement,Allocator & allocator,AllocationKind allocationKind)55 de::MovePtr<Allocation> allocateBuffer(const InstanceInterface &vki, const DeviceInterface &vkd,
56                                        const VkPhysicalDevice &physDevice, const VkDevice device,
57                                        const VkBuffer &buffer, const MemoryRequirement requirement,
58                                        Allocator &allocator, AllocationKind allocationKind)
59 {
60     switch (allocationKind)
61     {
62     case ALLOCATION_KIND_SUBALLOCATED:
63     {
64         const VkMemoryRequirements memoryRequirements = getBufferMemoryRequirements(vkd, device, buffer);
65 
66         return allocator.allocate(memoryRequirements, requirement);
67     }
68 
69     case ALLOCATION_KIND_DEDICATED:
70     {
71         return allocateDedicated(vki, vkd, physDevice, device, buffer, requirement);
72     }
73 
74     default:
75     {
76         TCU_THROW(InternalError, "Invalid allocation kind");
77     }
78     }
79 }
80 
allocateImage(const InstanceInterface & vki,const DeviceInterface & vkd,const VkPhysicalDevice & physDevice,const VkDevice device,const VkImage & image,const MemoryRequirement requirement,Allocator & allocator,AllocationKind allocationKind)81 de::MovePtr<Allocation> allocateImage(const InstanceInterface &vki, const DeviceInterface &vkd,
82                                       const VkPhysicalDevice &physDevice, const VkDevice device, const VkImage &image,
83                                       const MemoryRequirement requirement, Allocator &allocator,
84                                       AllocationKind allocationKind)
85 {
86     switch (allocationKind)
87     {
88     case ALLOCATION_KIND_SUBALLOCATED:
89     {
90         const VkMemoryRequirements memoryRequirements = getImageMemoryRequirements(vkd, device, image);
91 
92         return allocator.allocate(memoryRequirements, requirement);
93     }
94 
95     case ALLOCATION_KIND_DEDICATED:
96     {
97         return allocateDedicated(vki, vkd, physDevice, device, image, requirement);
98     }
99 
100     default:
101     {
102         TCU_THROW(InternalError, "Invalid allocation kind");
103     }
104     }
105 }
106 
getCompatibleImageType(VkImageViewType viewType)107 static VkImageType getCompatibleImageType(VkImageViewType viewType)
108 {
109     switch (viewType)
110     {
111     case VK_IMAGE_VIEW_TYPE_1D:
112         return VK_IMAGE_TYPE_1D;
113     case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
114         return VK_IMAGE_TYPE_1D;
115     case VK_IMAGE_VIEW_TYPE_2D:
116         return VK_IMAGE_TYPE_2D;
117     case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
118         return VK_IMAGE_TYPE_2D;
119     case VK_IMAGE_VIEW_TYPE_3D:
120         return VK_IMAGE_TYPE_3D;
121     case VK_IMAGE_VIEW_TYPE_CUBE:
122         return VK_IMAGE_TYPE_2D;
123     case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
124         return VK_IMAGE_TYPE_2D;
125     default:
126         break;
127     }
128 
129     DE_ASSERT(false);
130     return VK_IMAGE_TYPE_1D;
131 }
132 
133 template <typename TcuFormatType>
createTestTexture(const TcuFormatType format,VkImageViewType viewType,const tcu::IVec3 & size,int layerCount)134 static MovePtr<TestTexture> createTestTexture(const TcuFormatType format, VkImageViewType viewType,
135                                               const tcu::IVec3 &size, int layerCount)
136 {
137     MovePtr<TestTexture> texture;
138     const VkImageType imageType = getCompatibleImageType(viewType);
139 
140     switch (imageType)
141     {
142     case VK_IMAGE_TYPE_1D:
143         if (layerCount == 1)
144             texture = MovePtr<TestTexture>(new TestTexture1D(format, size.x()));
145         else
146             texture = MovePtr<TestTexture>(new TestTexture1DArray(format, size.x(), layerCount));
147 
148         break;
149 
150     case VK_IMAGE_TYPE_2D:
151         if (layerCount == 1)
152         {
153             texture = MovePtr<TestTexture>(new TestTexture2D(format, size.x(), size.y()));
154         }
155         else
156         {
157             if (viewType == VK_IMAGE_VIEW_TYPE_CUBE || viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
158             {
159                 if (layerCount == tcu::CUBEFACE_LAST && viewType == VK_IMAGE_VIEW_TYPE_CUBE)
160                 {
161                     texture = MovePtr<TestTexture>(new TestTextureCube(format, size.x()));
162                 }
163                 else
164                 {
165                     DE_ASSERT(layerCount % tcu::CUBEFACE_LAST == 0);
166 
167                     texture = MovePtr<TestTexture>(new TestTextureCubeArray(format, size.x(), layerCount));
168                 }
169             }
170             else
171             {
172                 texture = MovePtr<TestTexture>(new TestTexture2DArray(format, size.x(), size.y(), layerCount));
173             }
174         }
175 
176         break;
177 
178     case VK_IMAGE_TYPE_3D:
179         texture = MovePtr<TestTexture>(new TestTexture3D(format, size.x(), size.y(), size.z()));
180         break;
181 
182     default:
183         DE_ASSERT(false);
184     }
185 
186     return texture;
187 }
188 
189 } // namespace
190 
checkSupportImageSamplingInstance(Context & context,ImageSamplingInstanceParams params)191 void checkSupportImageSamplingInstance(Context &context, ImageSamplingInstanceParams params)
192 {
193 
194     const VkSamplerReductionModeCreateInfo *reductionModeInfo      = NULL;
195     const VkSamplerYcbcrConversionInfo *ycbcrInfo                  = NULL;
196     const VkSamplerCustomBorderColorCreateInfoEXT *borderColorInfo = NULL;
197 
198     for (const VkBaseInStructure *pNext = static_cast<const VkBaseInStructure *>(params.samplerParams.pNext);
199          pNext != NULL; pNext           = pNext->pNext)
200     {
201         switch (pNext->sType)
202         {
203         case VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO:
204             reductionModeInfo = reinterpret_cast<const VkSamplerReductionModeCreateInfo *>(pNext);
205             break;
206         case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO:
207             ycbcrInfo = reinterpret_cast<const VkSamplerYcbcrConversionInfo *>(pNext);
208             break;
209         case VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT:
210             borderColorInfo = reinterpret_cast<const VkSamplerCustomBorderColorCreateInfoEXT *>(pNext);
211             break;
212         default:
213             TCU_FAIL("Unrecognized sType in chained sampler create info");
214         }
215     }
216 
217     if (de::abs(params.samplerParams.mipLodBias) > context.getDeviceProperties().limits.maxSamplerLodBias)
218         TCU_THROW(NotSupportedError, "Unsupported sampler Lod bias value");
219 
220     if (!isSupportedSamplableFormat(context.getInstanceInterface(), context.getPhysicalDevice(), params.imageFormat))
221         throw tcu::NotSupportedError(std::string("Unsupported format for sampling: ") +
222                                      getFormatName(params.imageFormat));
223 
224     if ((uint32_t)params.imageCount > context.getDeviceProperties().limits.maxColorAttachments)
225         throw tcu::NotSupportedError(std::string("Unsupported render target count: ") +
226                                      de::toString(params.imageCount));
227 
228     if (params.samplerParams.minFilter == VK_FILTER_LINEAR || params.samplerParams.magFilter == VK_FILTER_LINEAR ||
229         params.samplerParams.mipmapMode == VK_SAMPLER_MIPMAP_MODE_LINEAR)
230     {
231         if (reductionModeInfo == NULL || reductionModeInfo->reductionMode == VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE)
232         {
233             if (!isLinearFilteringSupported(context.getInstanceInterface(), context.getPhysicalDevice(),
234                                             params.imageFormat, VK_IMAGE_TILING_OPTIMAL))
235                 throw tcu::NotSupportedError(std::string("Unsupported format for linear filtering: ") +
236                                              getFormatName(params.imageFormat));
237         }
238         else
239         {
240             if (!isMinMaxFilteringSupported(context.getInstanceInterface(), context.getPhysicalDevice(),
241                                             params.imageFormat, VK_IMAGE_TILING_OPTIMAL))
242                 throw tcu::NotSupportedError(std::string("Unsupported format for min/max filtering: ") +
243                                              getFormatName(params.imageFormat));
244         }
245     }
246 
247     if (params.separateStencilUsage)
248     {
249         context.requireDeviceFunctionality("VK_EXT_separate_stencil_usage");
250         context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
251 
252         const VkImageStencilUsageCreateInfo stencilUsage = {VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO, nullptr,
253                                                             VK_IMAGE_USAGE_TRANSFER_DST_BIT};
254 
255         const VkPhysicalDeviceImageFormatInfo2 formatInfo2 = {
256             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,        //    VkStructureType            sType
257             params.separateStencilUsage ? &stencilUsage : nullptr,        //    const void*                pNext
258             params.imageFormat,                                           //    VkFormat                format
259             getCompatibleImageType(params.imageViewType),                 //    VkImageType                type
260             VK_IMAGE_TILING_OPTIMAL,                                      //    VkImageTiling            tiling
261             VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, //    VkImageUsageFlags        usage
262             (VkImageCreateFlags)0u                                        //    VkImageCreateFlags        flags
263         };
264 
265         VkImageFormatProperties2 extProperties = {
266             VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
267             nullptr,
268             {
269                 {
270                     0, // width
271                     0, // height
272                     0, // depth
273                 },
274                 0u, // maxMipLevels
275                 0u, // maxArrayLayers
276                 0,  // sampleCounts
277                 0u, // maxResourceSize
278             },
279         };
280 
281         if ((context.getInstanceInterface().getPhysicalDeviceImageFormatProperties2(
282                  context.getPhysicalDevice(), &formatInfo2, &extProperties) == VK_ERROR_FORMAT_NOT_SUPPORTED) ||
283             extProperties.imageFormatProperties.maxExtent.width < (uint32_t)params.imageSize.x() ||
284             extProperties.imageFormatProperties.maxExtent.height < (uint32_t)params.imageSize.y())
285         {
286             TCU_THROW(NotSupportedError, "Image format not supported");
287         }
288     }
289 
290     if (reductionModeInfo != NULL)
291         context.requireDeviceFunctionality("VK_EXT_sampler_filter_minmax");
292 
293     if (ycbcrInfo != NULL)
294         context.requireDeviceFunctionality("VK_KHR_sampler_ycbcr_conversion");
295 
296     if (borderColorInfo != NULL)
297         if (!context.getCustomBorderColorFeaturesEXT().customBorderColors)
298             throw tcu::NotSupportedError("customBorderColors feature is not supported");
299 
300     if (params.samplerParams.addressModeU == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE ||
301         params.samplerParams.addressModeV == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE ||
302         params.samplerParams.addressModeW == VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE)
303     {
304         context.requireDeviceFunctionality("VK_KHR_sampler_mirror_clamp_to_edge");
305     }
306 
307     if ((isCompressedFormat(params.imageFormat) || isDepthStencilFormat(params.imageFormat)) &&
308         params.imageViewType == VK_IMAGE_VIEW_TYPE_3D)
309     {
310         // \todo [2016-01-22 pyry] Mandate VK_ERROR_FORMAT_NOT_SUPPORTED
311         try
312         {
313             const VkImageFormatProperties formatProperties = getPhysicalDeviceImageFormatProperties(
314                 context.getInstanceInterface(), context.getPhysicalDevice(), params.imageFormat, VK_IMAGE_TYPE_3D,
315                 VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT, (VkImageCreateFlags)0);
316 
317             if (formatProperties.maxExtent.width == 0 && formatProperties.maxExtent.height == 0 &&
318                 formatProperties.maxExtent.depth == 0)
319                 TCU_THROW(NotSupportedError, "3D compressed or depth format not supported");
320         }
321         catch (const Error &)
322         {
323             TCU_THROW(NotSupportedError, "3D compressed or depth format not supported");
324         }
325     }
326 
327     if (params.imageViewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
328         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_IMAGE_CUBE_ARRAY);
329 
330     if (params.allocationKind == ALLOCATION_KIND_DEDICATED)
331         context.requireDeviceFunctionality("VK_KHR_dedicated_allocation");
332 
333 #ifndef CTS_USES_VULKANSC
334     if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset"))
335     {
336         const auto portabilitySubsetFeatures = context.getPortabilitySubsetFeatures();
337         const auto componentMapping          = params.componentMapping;
338         if (!portabilitySubsetFeatures.imageViewFormatSwizzle &&
339             ((componentMapping.r != VK_COMPONENT_SWIZZLE_IDENTITY) ||
340              (componentMapping.g != VK_COMPONENT_SWIZZLE_IDENTITY) ||
341              (componentMapping.b != VK_COMPONENT_SWIZZLE_IDENTITY) ||
342              (componentMapping.a != VK_COMPONENT_SWIZZLE_IDENTITY)))
343         {
344             TCU_THROW(NotSupportedError,
345                       "VK_KHR_portability_subset: Implementation does not support remapping format components");
346         }
347     }
348 
349     bool formatRgba10x6WithoutYCbCrSampler = context.getRGBA10X6FormatsFeaturesEXT().formatRgba10x6WithoutYCbCrSampler;
350 #else
351     bool formatRgba10x6WithoutYCbCrSampler = VK_FALSE;
352 #endif // CTS_USES_VULKANSC
353 
354     if ((params.imageFormat == VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16) &&
355         (params.subresourceRange.levelCount > 1) && (formatRgba10x6WithoutYCbCrSampler == VK_FALSE))
356     {
357         TCU_THROW(NotSupportedError, "formatRgba10x6WithoutYCbCrSampler not supported");
358     }
359 }
360 
ImageSamplingInstance(Context & context,ImageSamplingInstanceParams params)361 ImageSamplingInstance::ImageSamplingInstance(Context &context, ImageSamplingInstanceParams params)
362     : vkt::TestInstance(context)
363     , m_allocationKind(params.allocationKind)
364     , m_samplingType(params.samplingType)
365     , m_imageViewType(params.imageViewType)
366     , m_imageFormat(params.imageFormat)
367     , m_imageSize(params.imageSize)
368     , m_layerCount(params.layerCount)
369     , m_imageCount(params.imageCount)
370     , m_componentMapping(params.componentMapping)
371     , m_componentMask(true)
372     , m_subresourceRange(params.subresourceRange)
373     , m_samplerParams(params.samplerParams)
374     , m_samplerLod(params.samplerLod)
375     , m_renderSize(params.renderSize)
376     , m_colorFormat(VK_FORMAT_R8G8B8A8_UNORM)
377     , m_vertices(params.vertices)
378     , m_graphicsPipeline(context.getInstanceInterface(), context.getDeviceInterface(), context.getPhysicalDevice(),
379                          context.getDevice(), m_context.getDeviceExtensions(), params.pipelineConstructionType,
380                          params.pipelineCreateFlags)
381     , m_pipelineConstructionType(params.pipelineConstructionType)
382     , m_imageLayout(params.imageLayout)
383 {
384 }
385 
setup()386 void ImageSamplingInstance::setup()
387 {
388     const InstanceInterface &vki      = m_context.getInstanceInterface();
389     const DeviceInterface &vk         = m_context.getDeviceInterface();
390     const VkPhysicalDevice physDevice = m_context.getPhysicalDevice();
391     const VkDevice vkDevice           = m_context.getDevice();
392     const VkQueue queue               = m_context.getUniversalQueue();
393     const uint32_t queueFamilyIndex   = m_context.getUniversalQueueFamilyIndex();
394     SimpleAllocator memAlloc(
395         vk, vkDevice,
396         getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
397     const VkComponentMapping componentMappingRGBA = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
398                                                      VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A};
399 
400     void const *pNext = m_samplerParams.pNext;
401     while (pNext != nullptr)
402     {
403         const VkStructureType nextType = *reinterpret_cast<const VkStructureType *>(pNext);
404         switch (nextType)
405         {
406         case VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO:
407         {
408             VkPhysicalDeviceSamplerFilterMinmaxProperties physicalDeviceSamplerMinMaxProperties = {
409                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES, nullptr, false, false};
410             VkPhysicalDeviceProperties2 physicalDeviceProperties;
411             physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
412             physicalDeviceProperties.pNext = &physicalDeviceSamplerMinMaxProperties;
413 
414             vki.getPhysicalDeviceProperties2(m_context.getPhysicalDevice(), &physicalDeviceProperties);
415 
416             if (physicalDeviceSamplerMinMaxProperties.filterMinmaxImageComponentMapping != VK_TRUE)
417             {
418                 // If filterMinmaxImageComponentMapping is VK_FALSE the component mapping of the image
419                 // view used with min/max filtering must have been created with the r component set to
420                 // VK_COMPONENT_SWIZZLE_IDENTITY. Only the r component of the sampled image value is
421                 // defined and the other component values are undefined
422 
423                 m_componentMask = tcu::BVec4(true, false, false, false);
424 
425                 if (m_componentMapping.r != VK_COMPONENT_SWIZZLE_IDENTITY &&
426                     m_componentMapping.r != VK_COMPONENT_SWIZZLE_R)
427                 {
428                     TCU_THROW(NotSupportedError,
429                               "filterMinmaxImageComponentMapping is not supported (R mapping is not IDENTITY)");
430                 }
431             }
432             pNext = reinterpret_cast<const VkSamplerReductionModeCreateInfo *>(pNext)->pNext;
433         }
434         break;
435         case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO:
436             pNext = reinterpret_cast<const VkSamplerYcbcrConversionInfo *>(pNext)->pNext;
437             break;
438         case VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT:
439         {
440             const VkSamplerCustomBorderColorCreateInfoEXT customBorderColorCreateInfo =
441                 *reinterpret_cast<const VkSamplerCustomBorderColorCreateInfoEXT *>(pNext);
442 
443             VkPhysicalDeviceCustomBorderColorFeaturesEXT physicalDeviceCustomBorderColorFeatures = {
444                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT, nullptr, false, false};
445             VkPhysicalDeviceFeatures2 physicalDeviceFeatures;
446             physicalDeviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
447             physicalDeviceFeatures.pNext = &physicalDeviceCustomBorderColorFeatures;
448 
449             vki.getPhysicalDeviceFeatures2(m_context.getPhysicalDevice(), &physicalDeviceFeatures);
450 
451             if (physicalDeviceCustomBorderColorFeatures.customBorderColors != VK_TRUE)
452             {
453                 TCU_THROW(NotSupportedError, "customBorderColors are not supported");
454             }
455 
456             if (physicalDeviceCustomBorderColorFeatures.customBorderColorWithoutFormat != VK_TRUE &&
457                 customBorderColorCreateInfo.format == VK_FORMAT_UNDEFINED)
458             {
459                 TCU_THROW(NotSupportedError, "customBorderColorWithoutFormat is not supported");
460             }
461 
462             pNext = reinterpret_cast<const VkSamplerCustomBorderColorCreateInfoEXT *>(pNext)->pNext;
463         }
464         break;
465         default:
466             TCU_FAIL("Unrecognized sType in chained sampler create info");
467         }
468     }
469 
470     // Create texture images, views and samplers
471     {
472         VkImageCreateFlags imageFlags = 0u;
473 
474         if (m_imageViewType == VK_IMAGE_VIEW_TYPE_CUBE || m_imageViewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
475             imageFlags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
476 
477         // Initialize texture data
478         if (isCompressedFormat(m_imageFormat))
479             m_texture =
480                 createTestTexture(mapVkCompressedFormat(m_imageFormat), m_imageViewType, m_imageSize, m_layerCount);
481         else
482             m_texture = createTestTexture(mapVkFormat(m_imageFormat), m_imageViewType, m_imageSize, m_layerCount);
483 
484         const VkImageCreateInfo imageParams = {
485             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,     // VkStructureType sType;
486             nullptr,                                 // const void* pNext;
487             imageFlags,                              // VkImageCreateFlags flags;
488             getCompatibleImageType(m_imageViewType), // VkImageType imageType;
489             m_imageFormat,                           // VkFormat format;
490             {                                        // VkExtent3D extent;
491              (uint32_t)m_imageSize.x(), (uint32_t)m_imageSize.y(), (uint32_t)m_imageSize.z()},
492             (uint32_t)m_texture->getNumLevels(),                          // uint32_t mipLevels;
493             (uint32_t)m_layerCount,                                       // uint32_t arrayLayers;
494             VK_SAMPLE_COUNT_1_BIT,                                        // VkSampleCountFlagBits samples;
495             VK_IMAGE_TILING_OPTIMAL,                                      // VkImageTiling tiling;
496             VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage;
497             VK_SHARING_MODE_EXCLUSIVE,                                    // VkSharingMode sharingMode;
498             1u,                                                           // uint32_t queueFamilyIndexCount;
499             &queueFamilyIndex,                                            // const uint32_t* pQueueFamilyIndices;
500             VK_IMAGE_LAYOUT_UNDEFINED                                     // VkImageLayout initialLayout;
501         };
502 
503         m_images.resize(m_imageCount);
504         m_imageAllocs.resize(m_imageCount);
505         m_imageViews.resize(m_imageCount);
506 
507         for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
508         {
509             m_images[imgNdx] = SharedImagePtr(new UniqueImage(createImage(vk, vkDevice, &imageParams)));
510             m_imageAllocs[imgNdx] =
511                 SharedAllocPtr(new UniqueAlloc(allocateImage(vki, vk, physDevice, vkDevice, **m_images[imgNdx],
512                                                              MemoryRequirement::Any, memAlloc, m_allocationKind)));
513             VK_CHECK(vk.bindImageMemory(vkDevice, **m_images[imgNdx], (*m_imageAllocs[imgNdx])->getMemory(),
514                                         (*m_imageAllocs[imgNdx])->getOffset()));
515 
516             // Upload texture data
517             uploadTestTexture(vk, vkDevice, queue, queueFamilyIndex, memAlloc, *m_texture, **m_images[imgNdx]);
518 
519             // Create image view and sampler
520             const VkImageViewCreateInfo imageViewParams = {
521                 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
522                 nullptr,                                  // const void* pNext;
523                 0u,                                       // VkImageViewCreateFlags flags;
524                 **m_images[imgNdx],                       // VkImage image;
525                 m_imageViewType,                          // VkImageViewType viewType;
526                 m_imageFormat,                            // VkFormat format;
527                 m_componentMapping,                       // VkComponentMapping components;
528                 m_subresourceRange,                       // VkImageSubresourceRange subresourceRange;
529             };
530 
531             m_imageViews[imgNdx] =
532                 SharedImageViewPtr(new UniqueImageView(createImageView(vk, vkDevice, &imageViewParams)));
533         }
534 
535         m_sampler = createSampler(vk, vkDevice, &m_samplerParams);
536     }
537 
538     // Create descriptor set for image and sampler
539     {
540         DescriptorPoolBuilder descriptorPoolBuilder;
541         if (m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
542             descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLER, 1u);
543         descriptorPoolBuilder.addType(m_samplingType, m_imageCount);
544         m_descriptorPool = descriptorPoolBuilder.build(
545             vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
546             m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ? m_imageCount + 1u : m_imageCount);
547 
548         DescriptorSetLayoutBuilder setLayoutBuilder;
549         if (m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
550             setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT);
551         setLayoutBuilder.addArrayBinding(m_samplingType, m_imageCount, VK_SHADER_STAGE_FRAGMENT_BIT);
552         m_descriptorSetLayout = setLayoutBuilder.build(vk, vkDevice);
553 
554         const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {
555             VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
556             nullptr,                                        // const void* pNext;
557             *m_descriptorPool,                              // VkDescriptorPool descriptorPool;
558             1u,                                             // uint32_t setLayoutCount;
559             &m_descriptorSetLayout.get()                    // const VkDescriptorSetLayout* pSetLayouts;
560         };
561 
562         m_descriptorSet = allocateDescriptorSet(vk, vkDevice, &descriptorSetAllocateInfo);
563 
564         const VkSampler sampler = m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ? VK_NULL_HANDLE : *m_sampler;
565         std::vector<VkDescriptorImageInfo> descriptorImageInfo(m_imageCount);
566         for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
567         {
568             descriptorImageInfo[imgNdx].sampler   = sampler;                // VkSampler sampler;
569             descriptorImageInfo[imgNdx].imageView = **m_imageViews[imgNdx]; // VkImageView imageView;
570             descriptorImageInfo[imgNdx].imageLayout =
571                 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; // VkImageLayout imageLayout;
572         }
573 
574         DescriptorSetUpdateBuilder setUpdateBuilder;
575         if (m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
576         {
577             const VkDescriptorImageInfo descriptorSamplerInfo = {
578                 *m_sampler,                              // VkSampler sampler;
579                 VK_NULL_HANDLE,                          // VkImageView imageView;
580                 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout imageLayout;
581             };
582             setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0),
583                                          VK_DESCRIPTOR_TYPE_SAMPLER, &descriptorSamplerInfo);
584         }
585 
586         const uint32_t binding = m_samplingType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ? 1u : 0u;
587         setUpdateBuilder.writeArray(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(binding),
588                                     m_samplingType, m_imageCount, descriptorImageInfo.data());
589         setUpdateBuilder.update(vk, vkDevice);
590     }
591 
592     // Create color images and views
593     {
594         const VkImageCreateInfo colorImageParams = {
595             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                   // VkStructureType sType;
596             nullptr,                                                               // const void* pNext;
597             0u,                                                                    // VkImageCreateFlags flags;
598             VK_IMAGE_TYPE_2D,                                                      // VkImageType imageType;
599             m_colorFormat,                                                         // VkFormat format;
600             {(uint32_t)m_renderSize.x(), (uint32_t)m_renderSize.y(), 1u},          // VkExtent3D extent;
601             1u,                                                                    // uint32_t mipLevels;
602             1u,                                                                    // uint32_t arrayLayers;
603             VK_SAMPLE_COUNT_1_BIT,                                                 // VkSampleCountFlagBits samples;
604             VK_IMAGE_TILING_OPTIMAL,                                               // VkImageTiling tiling;
605             VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
606             VK_SHARING_MODE_EXCLUSIVE,                                             // VkSharingMode sharingMode;
607             1u,                                                                    // uint32_t queueFamilyIndexCount;
608             &queueFamilyIndex,        // const uint32_t* pQueueFamilyIndices;
609             VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
610         };
611 
612         m_colorImages.resize(m_imageCount);
613         m_colorImageAllocs.resize(m_imageCount);
614         m_colorAttachmentViews.resize(m_imageCount);
615 
616         for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
617         {
618             m_colorImages[imgNdx] = SharedImagePtr(new UniqueImage(createImage(vk, vkDevice, &colorImageParams)));
619             m_colorImageAllocs[imgNdx] =
620                 SharedAllocPtr(new UniqueAlloc(allocateImage(vki, vk, physDevice, vkDevice, **m_colorImages[imgNdx],
621                                                              MemoryRequirement::Any, memAlloc, m_allocationKind)));
622             VK_CHECK(vk.bindImageMemory(vkDevice, **m_colorImages[imgNdx], (*m_colorImageAllocs[imgNdx])->getMemory(),
623                                         (*m_colorImageAllocs[imgNdx])->getOffset()));
624 
625             const VkImageViewCreateInfo colorAttachmentViewParams = {
626                 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,   // VkStructureType sType;
627                 nullptr,                                    // const void* pNext;
628                 0u,                                         // VkImageViewCreateFlags flags;
629                 **m_colorImages[imgNdx],                    // VkImage image;
630                 VK_IMAGE_VIEW_TYPE_2D,                      // VkImageViewType viewType;
631                 m_colorFormat,                              // VkFormat format;
632                 componentMappingRGBA,                       // VkComponentMapping components;
633                 {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u} // VkImageSubresourceRange subresourceRange;
634             };
635 
636             m_colorAttachmentViews[imgNdx] =
637                 SharedImageViewPtr(new UniqueImageView(createImageView(vk, vkDevice, &colorAttachmentViewParams)));
638         }
639     }
640 
641     // Create render pass
642     {
643         std::vector<VkAttachmentDescription> colorAttachmentDescriptions(m_imageCount);
644         std::vector<VkAttachmentReference> colorAttachmentReferences(m_imageCount);
645 
646         for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
647         {
648             colorAttachmentDescriptions[imgNdx].flags   = 0u;                    // VkAttachmentDescriptionFlags flags;
649             colorAttachmentDescriptions[imgNdx].format  = m_colorFormat;         // VkFormat format;
650             colorAttachmentDescriptions[imgNdx].samples = VK_SAMPLE_COUNT_1_BIT; // VkSampleCountFlagBits samples;
651             colorAttachmentDescriptions[imgNdx].loadOp  = VK_ATTACHMENT_LOAD_OP_CLEAR;  // VkAttachmentLoadOp loadOp;
652             colorAttachmentDescriptions[imgNdx].storeOp = VK_ATTACHMENT_STORE_OP_STORE; // VkAttachmentStoreOp storeOp;
653             colorAttachmentDescriptions[imgNdx].stencilLoadOp =
654                 VK_ATTACHMENT_LOAD_OP_DONT_CARE; // VkAttachmentLoadOp stencilLoadOp;
655             colorAttachmentDescriptions[imgNdx].stencilStoreOp =
656                 VK_ATTACHMENT_STORE_OP_DONT_CARE; // VkAttachmentStoreOp stencilStoreOp;
657             colorAttachmentDescriptions[imgNdx].initialLayout =
658                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VkImageLayout initialLayout;
659             colorAttachmentDescriptions[imgNdx].finalLayout =
660                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VkImageLayout finalLayout;
661 
662             colorAttachmentReferences[imgNdx].attachment = (uint32_t)imgNdx; // uint32_t attachment;
663             colorAttachmentReferences[imgNdx].layout =
664                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VkImageLayout layout;
665         }
666 
667         const VkSubpassDescription subpassDescription = {
668             0u,                              // VkSubpassDescriptionFlags flags;
669             VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
670             0u,                              // uint32_t inputAttachmentCount;
671             nullptr,                         // const VkAttachmentReference* pInputAttachments;
672             (uint32_t)m_imageCount,          // uint32_t colorAttachmentCount;
673             &colorAttachmentReferences[0],   // const VkAttachmentReference* pColorAttachments;
674             nullptr,                         // const VkAttachmentReference* pResolveAttachments;
675             nullptr,                         // const VkAttachmentReference* pDepthStencilAttachment;
676             0u,                              // uint32_t preserveAttachmentCount;
677             nullptr                          // const VkAttachmentReference* pPreserveAttachments;
678         };
679 
680         const VkRenderPassCreateInfo renderPassParams = {
681             VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
682             nullptr,                                   // const void* pNext;
683             0u,                                        // VkRenderPassCreateFlags flags;
684             (uint32_t)m_imageCount,                    // uint32_t attachmentCount;
685             &colorAttachmentDescriptions[0],           // const VkAttachmentDescription* pAttachments;
686             1u,                                        // uint32_t subpassCount;
687             &subpassDescription,                       // const VkSubpassDescription* pSubpasses;
688             0u,                                        // uint32_t dependencyCount;
689             nullptr                                    // const VkSubpassDependency* pDependencies;
690         };
691 
692         m_renderPass = RenderPassWrapper(m_pipelineConstructionType, vk, vkDevice, &renderPassParams);
693     }
694 
695     // Create framebuffer
696     {
697         std::vector<VkImage> images(m_imageCount);
698         std::vector<VkImageView> pAttachments(m_imageCount);
699         for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
700         {
701             images[imgNdx]       = m_colorImages[imgNdx]->get();
702             pAttachments[imgNdx] = m_colorAttachmentViews[imgNdx]->get();
703         }
704 
705         const VkFramebufferCreateInfo framebufferParams = {
706             VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
707             nullptr,                                   // const void* pNext;
708             0u,                                        // VkFramebufferCreateFlags flags;
709             *m_renderPass,                             // VkRenderPass renderPass;
710             (uint32_t)m_imageCount,                    // uint32_t attachmentCount;
711             &pAttachments[0],                          // const VkImageView* pAttachments;
712             (uint32_t)m_renderSize.x(),                // uint32_t width;
713             (uint32_t)m_renderSize.y(),                // uint32_t height;
714             1u                                         // uint32_t layers;
715         };
716 
717         m_renderPass.createFramebuffer(vk, vkDevice, &framebufferParams, images);
718     }
719 
720     // Create pipeline layout
721     {
722 #ifndef CTS_USES_VULKANSC
723         VkPipelineLayoutCreateFlags pipelineLayoutFlags =
724             (!isConstructionTypeLibrary(m_pipelineConstructionType)) ?
725                 0u :
726                 uint32_t(VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT);
727 #else
728         VkPipelineLayoutCreateFlags pipelineLayoutFlags = 0u;
729 #endif // CTS_USES_VULKANSC
730         VkPipelineLayoutCreateInfo pipelineLayoutParams{
731             VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
732             nullptr,                                       // const void* pNext;
733             pipelineLayoutFlags,                           // VkPipelineLayoutCreateFlags flags;
734             0u,                                            // uint32_t setLayoutCount;
735             nullptr,                                       // const VkDescriptorSetLayout* pSetLayouts;
736             0u,                                            // uint32_t pushConstantRangeCount;
737             nullptr                                        // const VkPushConstantRange* pPushConstantRanges;
738         };
739 
740         m_preRasterizationStatePipelineLayout =
741             PipelineLayoutWrapper(m_pipelineConstructionType, vk, vkDevice, &pipelineLayoutParams);
742         pipelineLayoutParams.setLayoutCount = 1u;
743         pipelineLayoutParams.pSetLayouts    = &m_descriptorSetLayout.get();
744         m_fragmentStatePipelineLayout =
745             PipelineLayoutWrapper(m_pipelineConstructionType, vk, vkDevice, &pipelineLayoutParams);
746     }
747 
748     m_vertexShaderModule   = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("tex_vert"), 0);
749     m_fragmentShaderModule = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("tex_frag"), 0);
750 
751     // Create pipeline
752     {
753         const VkVertexInputBindingDescription vertexInputBindingDescription = {
754             0u,                         // uint32_t binding;
755             sizeof(Vertex4Tex4),        // uint32_t strideInBytes;
756             VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate inputRate;
757         };
758 
759         const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] = {
760             {
761                 0u,                            // uint32_t location;
762                 0u,                            // uint32_t binding;
763                 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
764                 0u                             // uint32_t offset;
765             },
766             {
767                 1u,                              // uint32_t location;
768                 0u,                              // uint32_t binding;
769                 VK_FORMAT_R32G32B32A32_SFLOAT,   // VkFormat format;
770                 offsetof(Vertex4Tex4, texCoord), // uint32_t offset;
771             }};
772 
773         const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = {
774             VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
775             nullptr,                                                   // const void* pNext;
776             0u,                                                        // VkPipelineVertexInputStateCreateFlags flags;
777             1u,                                                        // uint32_t vertexBindingDescriptionCount;
778             &vertexInputBindingDescription,  // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
779             2u,                              // uint32_t vertexAttributeDescriptionCount;
780             vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
781         };
782 
783         const std::vector<VkViewport> viewports{makeViewport(m_renderSize)};
784         const std::vector<VkRect2D> scissors{makeRect2D(m_renderSize)};
785 
786         std::vector<VkPipelineColorBlendAttachmentState> colorBlendAttachmentStates(m_imageCount);
787 
788         for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
789         {
790             colorBlendAttachmentStates[imgNdx].blendEnable = false; // VkBool32 blendEnable;
791             colorBlendAttachmentStates[imgNdx].srcColorBlendFactor =
792                 VK_BLEND_FACTOR_ONE; // VkBlendFactor srcColorBlendFactor;
793             colorBlendAttachmentStates[imgNdx].dstColorBlendFactor =
794                 VK_BLEND_FACTOR_ZERO;                                          // VkBlendFactor dstColorBlendFactor;
795             colorBlendAttachmentStates[imgNdx].colorBlendOp = VK_BLEND_OP_ADD; // VkBlendOp colorBlendOp;
796             colorBlendAttachmentStates[imgNdx].srcAlphaBlendFactor =
797                 VK_BLEND_FACTOR_ONE; // VkBlendFactor srcAlphaBlendFactor;
798             colorBlendAttachmentStates[imgNdx].dstAlphaBlendFactor =
799                 VK_BLEND_FACTOR_ZERO;                                          // VkBlendFactor dstAlphaBlendFactor;
800             colorBlendAttachmentStates[imgNdx].alphaBlendOp = VK_BLEND_OP_ADD; // VkBlendOp alphaBlendOp;
801             colorBlendAttachmentStates[imgNdx].colorWriteMask =
802                 VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | // VkColorComponentFlags colorWriteMask;
803                 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
804         }
805 
806         const VkPipelineColorBlendStateCreateInfo colorBlendStateParams = {
807             VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
808             nullptr,                                                  // const void* pNext;
809             0u,                                                       // VkPipelineColorBlendStateCreateFlags flags;
810             false,                                                    // VkBool32 logicOpEnable;
811             VK_LOGIC_OP_COPY,                                         // VkLogicOp logicOp;
812             (uint32_t)m_imageCount,                                   // uint32_t attachmentCount;
813             &colorBlendAttachmentStates[0], // const VkPipelineColorBlendAttachmentState* pAttachments;
814             {0.0f, 0.0f, 0.0f, 0.0f}        // float blendConstants[4];
815         };
816 
817         m_graphicsPipeline.setMonolithicPipelineLayout(m_fragmentStatePipelineLayout)
818             .setDefaultDepthStencilState()
819             .setDefaultRasterizationState()
820             .setDefaultMultisampleState()
821             .setupVertexInputState(&vertexInputStateParams)
822             .setupPreRasterizationShaderState(viewports, scissors, m_preRasterizationStatePipelineLayout, *m_renderPass,
823                                               0u, m_vertexShaderModule)
824             .setupFragmentShaderState(m_fragmentStatePipelineLayout, *m_renderPass, 0u, m_fragmentShaderModule)
825             .setupFragmentOutputState(*m_renderPass, 0u, &colorBlendStateParams)
826             .buildPipeline();
827     }
828 
829     // Create vertex buffer
830     {
831         const VkDeviceSize vertexBufferSize         = (VkDeviceSize)(m_vertices.size() * sizeof(Vertex4Tex4));
832         const VkBufferCreateInfo vertexBufferParams = {
833             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
834             nullptr,                              // const void* pNext;
835             0u,                                   // VkBufferCreateFlags flags;
836             vertexBufferSize,                     // VkDeviceSize size;
837             VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,    // VkBufferUsageFlags usage;
838             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
839             1u,                                   // uint32_t queueFamilyIndexCount;
840             &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
841         };
842 
843         DE_ASSERT(vertexBufferSize > 0);
844 
845         m_vertexBuffer      = createBuffer(vk, vkDevice, &vertexBufferParams);
846         m_vertexBufferAlloc = allocateBuffer(vki, vk, physDevice, vkDevice, *m_vertexBuffer,
847                                              MemoryRequirement::HostVisible, memAlloc, m_allocationKind);
848         VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(),
849                                      m_vertexBufferAlloc->getOffset()));
850 
851         // Load vertices into vertex buffer
852         deMemcpy(m_vertexBufferAlloc->getHostPtr(), &m_vertices[0], (size_t)vertexBufferSize);
853         flushAlloc(vk, vkDevice, *m_vertexBufferAlloc);
854     }
855 
856     // Create command pool
857     m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
858 
859     // Create command buffer
860     {
861         const std::vector<VkClearValue> attachmentClearValues(m_imageCount, defaultClearValue(m_colorFormat));
862 
863         std::vector<VkImageMemoryBarrier> preAttachmentBarriers(m_imageCount);
864 
865         for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
866         {
867             preAttachmentBarriers[imgNdx].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; // VkStructureType sType;
868             preAttachmentBarriers[imgNdx].pNext = nullptr;                                // const void* pNext;
869             preAttachmentBarriers[imgNdx].srcAccessMask = 0u; // VkAccessFlags srcAccessMask;
870             preAttachmentBarriers[imgNdx].dstAccessMask =
871                 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;                            // VkAccessFlags dstAccessMask;
872             preAttachmentBarriers[imgNdx].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; // VkImageLayout oldLayout;
873             preAttachmentBarriers[imgNdx].newLayout =
874                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VkImageLayout newLayout;
875             preAttachmentBarriers[imgNdx].srcQueueFamilyIndex =
876                 VK_QUEUE_FAMILY_IGNORED; // uint32_t srcQueueFamilyIndex;
877             preAttachmentBarriers[imgNdx].dstQueueFamilyIndex =
878                 VK_QUEUE_FAMILY_IGNORED;                                   // uint32_t dstQueueFamilyIndex;
879             preAttachmentBarriers[imgNdx].image = **m_colorImages[imgNdx]; // VkImage image;
880             preAttachmentBarriers[imgNdx].subresourceRange.aspectMask =
881                 VK_IMAGE_ASPECT_COLOR_BIT; // VkImageSubresourceRange subresourceRange;
882             preAttachmentBarriers[imgNdx].subresourceRange.baseMipLevel   = 0u;
883             preAttachmentBarriers[imgNdx].subresourceRange.levelCount     = 1u;
884             preAttachmentBarriers[imgNdx].subresourceRange.baseArrayLayer = 0u;
885             preAttachmentBarriers[imgNdx].subresourceRange.layerCount     = 1u;
886         }
887 
888         m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
889 
890         beginCommandBuffer(vk, *m_cmdBuffer, 0u);
891 
892         vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
893                               VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, (VkDependencyFlags)0, 0u, nullptr, 0u,
894                               nullptr, (uint32_t)m_imageCount, &preAttachmentBarriers[0]);
895 
896         m_renderPass.begin(vk, *m_cmdBuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()),
897                            (uint32_t)attachmentClearValues.size(), &attachmentClearValues[0]);
898 
899         m_graphicsPipeline.bind(*m_cmdBuffer);
900 
901         m_fragmentStatePipelineLayout.bindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 1,
902                                                          &m_descriptorSet.get(), 0, nullptr);
903 
904         const VkDeviceSize vertexBufferOffset = 0;
905         vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
906         vk.cmdDraw(*m_cmdBuffer, (uint32_t)m_vertices.size(), 1, 0, 0);
907 
908         m_renderPass.end(vk, *m_cmdBuffer);
909         endCommandBuffer(vk, *m_cmdBuffer);
910     }
911 }
912 
~ImageSamplingInstance(void)913 ImageSamplingInstance::~ImageSamplingInstance(void)
914 {
915 }
916 
iterate(void)917 tcu::TestStatus ImageSamplingInstance::iterate(void)
918 {
919     const DeviceInterface &vk = m_context.getDeviceInterface();
920     const VkDevice vkDevice   = m_context.getDevice();
921     const VkQueue queue       = m_context.getUniversalQueue();
922 
923     setup();
924 
925     submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
926 
927     return verifyImage();
928 }
929 
930 namespace
931 {
932 
isLookupResultValid(const tcu::Texture1DView & texture,const tcu::Sampler & sampler,const tcu::LookupPrecision & precision,const tcu::Vec4 & coords,const tcu::Vec2 & lodBounds,const tcu::Vec4 & result)933 bool isLookupResultValid(const tcu::Texture1DView &texture, const tcu::Sampler &sampler,
934                          const tcu::LookupPrecision &precision, const tcu::Vec4 &coords, const tcu::Vec2 &lodBounds,
935                          const tcu::Vec4 &result)
936 {
937     return tcu::isLookupResultValid(texture, sampler, precision, coords.x(), lodBounds, result);
938 }
939 
isLookupResultValid(const tcu::Texture1DArrayView & texture,const tcu::Sampler & sampler,const tcu::LookupPrecision & precision,const tcu::Vec4 & coords,const tcu::Vec2 & lodBounds,const tcu::Vec4 & result)940 bool isLookupResultValid(const tcu::Texture1DArrayView &texture, const tcu::Sampler &sampler,
941                          const tcu::LookupPrecision &precision, const tcu::Vec4 &coords, const tcu::Vec2 &lodBounds,
942                          const tcu::Vec4 &result)
943 {
944     return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0, 1), lodBounds, result);
945 }
946 
isLookupResultValid(const tcu::Texture2DView & texture,const tcu::Sampler & sampler,const tcu::LookupPrecision & precision,const tcu::Vec4 & coords,const tcu::Vec2 & lodBounds,const tcu::Vec4 & result)947 bool isLookupResultValid(const tcu::Texture2DView &texture, const tcu::Sampler &sampler,
948                          const tcu::LookupPrecision &precision, const tcu::Vec4 &coords, const tcu::Vec2 &lodBounds,
949                          const tcu::Vec4 &result)
950 {
951     return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0, 1), lodBounds, result);
952 }
953 
isLookupResultValid(const tcu::Texture2DArrayView & texture,const tcu::Sampler & sampler,const tcu::LookupPrecision & precision,const tcu::Vec4 & coords,const tcu::Vec2 & lodBounds,const tcu::Vec4 & result)954 bool isLookupResultValid(const tcu::Texture2DArrayView &texture, const tcu::Sampler &sampler,
955                          const tcu::LookupPrecision &precision, const tcu::Vec4 &coords, const tcu::Vec2 &lodBounds,
956                          const tcu::Vec4 &result)
957 {
958     return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0, 1, 2), lodBounds, result);
959 }
960 
isLookupResultValid(const tcu::TextureCubeView & texture,const tcu::Sampler & sampler,const tcu::LookupPrecision & precision,const tcu::Vec4 & coords,const tcu::Vec2 & lodBounds,const tcu::Vec4 & result)961 bool isLookupResultValid(const tcu::TextureCubeView &texture, const tcu::Sampler &sampler,
962                          const tcu::LookupPrecision &precision, const tcu::Vec4 &coords, const tcu::Vec2 &lodBounds,
963                          const tcu::Vec4 &result)
964 {
965     return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0, 1, 2), lodBounds, result);
966 }
967 
isLookupResultValid(const tcu::TextureCubeArrayView & texture,const tcu::Sampler & sampler,const tcu::LookupPrecision & precision,const tcu::Vec4 & coords,const tcu::Vec2 & lodBounds,const tcu::Vec4 & result)968 bool isLookupResultValid(const tcu::TextureCubeArrayView &texture, const tcu::Sampler &sampler,
969                          const tcu::LookupPrecision &precision, const tcu::Vec4 &coords, const tcu::Vec2 &lodBounds,
970                          const tcu::Vec4 &result)
971 {
972     return tcu::isLookupResultValid(texture, sampler, precision, tcu::IVec4(precision.coordBits.x()), coords, lodBounds,
973                                     result);
974 }
975 
isLookupResultValid(const tcu::Texture3DView & texture,const tcu::Sampler & sampler,const tcu::LookupPrecision & precision,const tcu::Vec4 & coords,const tcu::Vec2 & lodBounds,const tcu::Vec4 & result)976 bool isLookupResultValid(const tcu::Texture3DView &texture, const tcu::Sampler &sampler,
977                          const tcu::LookupPrecision &precision, const tcu::Vec4 &coords, const tcu::Vec2 &lodBounds,
978                          const tcu::Vec4 &result)
979 {
980     return tcu::isLookupResultValid(texture, sampler, precision, coords.swizzle(0, 1, 2), lodBounds, result);
981 }
982 
983 template <typename TextureViewType>
validateResultImage(const TextureViewType & texture,const tcu::Sampler & sampler,const tcu::ConstPixelBufferAccess & texCoords,const tcu::Vec2 & lodBounds,const tcu::LookupPrecision & lookupPrecision,const tcu::Vec4 & lookupScale,const tcu::Vec4 & lookupBias,const tcu::ConstPixelBufferAccess & result,const tcu::PixelBufferAccess & errorMask)984 bool validateResultImage(const TextureViewType &texture, const tcu::Sampler &sampler,
985                          const tcu::ConstPixelBufferAccess &texCoords, const tcu::Vec2 &lodBounds,
986                          const tcu::LookupPrecision &lookupPrecision, const tcu::Vec4 &lookupScale,
987                          const tcu::Vec4 &lookupBias, const tcu::ConstPixelBufferAccess &result,
988                          const tcu::PixelBufferAccess &errorMask)
989 {
990     const int w = result.getWidth();
991     const int h = result.getHeight();
992     bool allOk  = true;
993 
994     for (int y = 0; y < h; ++y)
995     {
996         for (int x = 0; x < w; ++x)
997         {
998             const tcu::Vec4 resultPixel = result.getPixel(x, y);
999             const tcu::Vec4 resultColor = (resultPixel - lookupBias) / lookupScale;
1000             const tcu::Vec4 texCoord    = texCoords.getPixel(x, y);
1001             const bool pixelOk =
1002                 isLookupResultValid(texture, sampler, lookupPrecision, texCoord, lodBounds, resultColor);
1003 
1004             errorMask.setPixel(tcu::Vec4(pixelOk ? 0.0f : 1.0f, pixelOk ? 1.0f : 0.0f, 0.0f, 1.0f), x, y);
1005 
1006             if (!pixelOk)
1007                 allOk = false;
1008         }
1009     }
1010 
1011     return allOk;
1012 }
1013 
1014 template <typename ScalarType>
getSwizzledComp(const tcu::Vector<ScalarType,4> & vec,vk::VkComponentSwizzle comp,int identityNdx)1015 ScalarType getSwizzledComp(const tcu::Vector<ScalarType, 4> &vec, vk::VkComponentSwizzle comp, int identityNdx)
1016 {
1017     if (comp == vk::VK_COMPONENT_SWIZZLE_IDENTITY)
1018         return vec[identityNdx];
1019     else if (comp == vk::VK_COMPONENT_SWIZZLE_ZERO)
1020         return ScalarType(0);
1021     else if (comp == vk::VK_COMPONENT_SWIZZLE_ONE)
1022         return ScalarType(1);
1023     else
1024         return vec[comp - vk::VK_COMPONENT_SWIZZLE_R];
1025 }
1026 
1027 template <typename ScalarType>
swizzle(const tcu::Vector<ScalarType,4> & vec,const vk::VkComponentMapping & swz)1028 tcu::Vector<ScalarType, 4> swizzle(const tcu::Vector<ScalarType, 4> &vec, const vk::VkComponentMapping &swz)
1029 {
1030     return tcu::Vector<ScalarType, 4>(getSwizzledComp(vec, swz.r, 0), getSwizzledComp(vec, swz.g, 1),
1031                                       getSwizzledComp(vec, swz.b, 2), getSwizzledComp(vec, swz.a, 3));
1032 }
1033 
1034 /*--------------------------------------------------------------------*//*!
1035 * \brief Swizzle scale or bias vector by given mapping
1036 *
1037 * \param vec scale or bias vector
1038 * \param swz swizzle component mapping, may include ZERO, ONE, or IDENTITY
1039 * \param zeroOrOneValue vector value for component swizzled as ZERO or ONE
1040 * \return swizzled vector
1041 *//*--------------------------------------------------------------------*/
swizzleScaleBias(const tcu::Vec4 & vec,const vk::VkComponentMapping & swz,float zeroOrOneValue)1042 tcu::Vec4 swizzleScaleBias(const tcu::Vec4 &vec, const vk::VkComponentMapping &swz, float zeroOrOneValue)
1043 {
1044 
1045     // Remove VK_COMPONENT_SWIZZLE_IDENTITY to avoid addressing channelValues[0]
1046     const vk::VkComponentMapping nonIdentitySwz = {
1047         swz.r == VK_COMPONENT_SWIZZLE_IDENTITY ? VK_COMPONENT_SWIZZLE_R : swz.r,
1048         swz.g == VK_COMPONENT_SWIZZLE_IDENTITY ? VK_COMPONENT_SWIZZLE_G : swz.g,
1049         swz.b == VK_COMPONENT_SWIZZLE_IDENTITY ? VK_COMPONENT_SWIZZLE_B : swz.b,
1050         swz.a == VK_COMPONENT_SWIZZLE_IDENTITY ? VK_COMPONENT_SWIZZLE_A : swz.a};
1051 
1052     const float channelValues[] = {
1053         -1.0f,          // impossible
1054         zeroOrOneValue, // SWIZZLE_ZERO
1055         zeroOrOneValue, // SWIZZLE_ONE
1056         vec.x(),        vec.y(), vec.z(), vec.w(),
1057     };
1058 
1059     return tcu::Vec4(channelValues[nonIdentitySwz.r], channelValues[nonIdentitySwz.g], channelValues[nonIdentitySwz.b],
1060                      channelValues[nonIdentitySwz.a]);
1061 }
1062 
1063 template <typename ScalarType>
swizzleT(const tcu::ConstPixelBufferAccess & src,const tcu::PixelBufferAccess & dst,const vk::VkComponentMapping & swz)1064 void swizzleT(const tcu::ConstPixelBufferAccess &src, const tcu::PixelBufferAccess &dst,
1065               const vk::VkComponentMapping &swz)
1066 {
1067     for (int z = 0; z < dst.getDepth(); ++z)
1068         for (int y = 0; y < dst.getHeight(); ++y)
1069             for (int x = 0; x < dst.getWidth(); ++x)
1070                 dst.setPixel(swizzle(src.getPixelT<ScalarType>(x, y, z), swz), x, y, z);
1071 }
1072 
swizzleFromSRGB(const tcu::ConstPixelBufferAccess & src,const tcu::PixelBufferAccess & dst,const vk::VkComponentMapping & swz)1073 void swizzleFromSRGB(const tcu::ConstPixelBufferAccess &src, const tcu::PixelBufferAccess &dst,
1074                      const vk::VkComponentMapping &swz)
1075 {
1076     for (int z = 0; z < dst.getDepth(); ++z)
1077         for (int y = 0; y < dst.getHeight(); ++y)
1078             for (int x = 0; x < dst.getWidth(); ++x)
1079                 dst.setPixel(swizzle(tcu::sRGBToLinear(src.getPixelT<float>(x, y, z)), swz), x, y, z);
1080 }
1081 
swizzle(const tcu::ConstPixelBufferAccess & src,const tcu::PixelBufferAccess & dst,const vk::VkComponentMapping & swz)1082 void swizzle(const tcu::ConstPixelBufferAccess &src, const tcu::PixelBufferAccess &dst,
1083              const vk::VkComponentMapping &swz)
1084 {
1085     const tcu::TextureChannelClass chnClass = tcu::getTextureChannelClass(dst.getFormat().type);
1086 
1087     DE_ASSERT(src.getWidth() == dst.getWidth() && src.getHeight() == dst.getHeight() &&
1088               src.getDepth() == dst.getDepth());
1089 
1090     if (chnClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
1091         swizzleT<int32_t>(src, dst, swz);
1092     else if (chnClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
1093         swizzleT<uint32_t>(src, dst, swz);
1094     else if (tcu::isSRGB(src.getFormat()) && !tcu::isSRGB(dst.getFormat()))
1095         swizzleFromSRGB(src, dst, swz);
1096     else
1097         swizzleT<float>(src, dst, swz);
1098 }
1099 
isIdentitySwizzle(const vk::VkComponentMapping & swz)1100 bool isIdentitySwizzle(const vk::VkComponentMapping &swz)
1101 {
1102     return (swz.r == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.r == vk::VK_COMPONENT_SWIZZLE_R) &&
1103            (swz.g == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.g == vk::VK_COMPONENT_SWIZZLE_G) &&
1104            (swz.b == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.b == vk::VK_COMPONENT_SWIZZLE_B) &&
1105            (swz.a == vk::VK_COMPONENT_SWIZZLE_IDENTITY || swz.a == vk::VK_COMPONENT_SWIZZLE_A);
1106 }
1107 
1108 template <typename TextureViewType>
1109 struct TexViewTraits;
1110 
1111 template <>
1112 struct TexViewTraits<tcu::Texture1DView>
1113 {
1114     typedef tcu::Texture1D TextureType;
1115 };
1116 template <>
1117 struct TexViewTraits<tcu::Texture1DArrayView>
1118 {
1119     typedef tcu::Texture1DArray TextureType;
1120 };
1121 template <>
1122 struct TexViewTraits<tcu::Texture2DView>
1123 {
1124     typedef tcu::Texture2D TextureType;
1125 };
1126 template <>
1127 struct TexViewTraits<tcu::Texture2DArrayView>
1128 {
1129     typedef tcu::Texture2DArray TextureType;
1130 };
1131 template <>
1132 struct TexViewTraits<tcu::TextureCubeView>
1133 {
1134     typedef tcu::TextureCube TextureType;
1135 };
1136 template <>
1137 struct TexViewTraits<tcu::TextureCubeArrayView>
1138 {
1139     typedef tcu::TextureCubeArray TextureType;
1140 };
1141 template <>
1142 struct TexViewTraits<tcu::Texture3DView>
1143 {
1144     typedef tcu::Texture3D TextureType;
1145 };
1146 
1147 template <typename TextureViewType>
1148 typename TexViewTraits<TextureViewType>::TextureType *createSkeletonClone(tcu::TextureFormat format,
1149                                                                           const tcu::ConstPixelBufferAccess &level0);
1150 
getSwizzleTargetFormat(tcu::TextureFormat format)1151 tcu::TextureFormat getSwizzleTargetFormat(tcu::TextureFormat format)
1152 {
1153     // Swizzled texture needs to hold all four channels
1154     // \todo [2016-09-21 pyry] We could save some memory by using smaller formats
1155     //                           when possible (for example U8).
1156 
1157     const tcu::TextureChannelClass chnClass = tcu::getTextureChannelClass(format.type);
1158 
1159     if (chnClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
1160         return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
1161     else if (chnClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
1162         return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
1163     else
1164         return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
1165 }
1166 
1167 template <>
createSkeletonClone(tcu::TextureFormat format,const tcu::ConstPixelBufferAccess & level0)1168 tcu::Texture1D *createSkeletonClone<tcu::Texture1DView>(tcu::TextureFormat format,
1169                                                         const tcu::ConstPixelBufferAccess &level0)
1170 {
1171     return new tcu::Texture1D(format, level0.getWidth());
1172 }
1173 
1174 template <>
createSkeletonClone(tcu::TextureFormat format,const tcu::ConstPixelBufferAccess & level0)1175 tcu::Texture1DArray *createSkeletonClone<tcu::Texture1DArrayView>(tcu::TextureFormat format,
1176                                                                   const tcu::ConstPixelBufferAccess &level0)
1177 {
1178     return new tcu::Texture1DArray(format, level0.getWidth(), level0.getHeight());
1179 }
1180 
1181 template <>
createSkeletonClone(tcu::TextureFormat format,const tcu::ConstPixelBufferAccess & level0)1182 tcu::Texture2D *createSkeletonClone<tcu::Texture2DView>(tcu::TextureFormat format,
1183                                                         const tcu::ConstPixelBufferAccess &level0)
1184 {
1185     return new tcu::Texture2D(format, level0.getWidth(), level0.getHeight());
1186 }
1187 
1188 template <>
createSkeletonClone(tcu::TextureFormat format,const tcu::ConstPixelBufferAccess & level0)1189 tcu::Texture2DArray *createSkeletonClone<tcu::Texture2DArrayView>(tcu::TextureFormat format,
1190                                                                   const tcu::ConstPixelBufferAccess &level0)
1191 {
1192     return new tcu::Texture2DArray(format, level0.getWidth(), level0.getHeight(), level0.getDepth());
1193 }
1194 
1195 template <>
createSkeletonClone(tcu::TextureFormat format,const tcu::ConstPixelBufferAccess & level0)1196 tcu::Texture3D *createSkeletonClone<tcu::Texture3DView>(tcu::TextureFormat format,
1197                                                         const tcu::ConstPixelBufferAccess &level0)
1198 {
1199     return new tcu::Texture3D(format, level0.getWidth(), level0.getHeight(), level0.getDepth());
1200 }
1201 
1202 template <>
createSkeletonClone(tcu::TextureFormat format,const tcu::ConstPixelBufferAccess & level0)1203 tcu::TextureCubeArray *createSkeletonClone<tcu::TextureCubeArrayView>(tcu::TextureFormat format,
1204                                                                       const tcu::ConstPixelBufferAccess &level0)
1205 {
1206     return new tcu::TextureCubeArray(format, level0.getWidth(), level0.getDepth());
1207 }
1208 
1209 template <typename TextureViewType>
createSwizzledCopy(const TextureViewType & texture,const vk::VkComponentMapping & swz)1210 MovePtr<typename TexViewTraits<TextureViewType>::TextureType> createSwizzledCopy(const TextureViewType &texture,
1211                                                                                  const vk::VkComponentMapping &swz)
1212 {
1213     MovePtr<typename TexViewTraits<TextureViewType>::TextureType> copy(createSkeletonClone<TextureViewType>(
1214         getSwizzleTargetFormat(texture.getLevel(0).getFormat()), texture.getLevel(0)));
1215 
1216     for (int levelNdx = 0; levelNdx < texture.getNumLevels(); ++levelNdx)
1217     {
1218         copy->allocLevel(levelNdx);
1219         swizzle(texture.getLevel(levelNdx), copy->getLevel(levelNdx), swz);
1220     }
1221 
1222     return copy;
1223 }
1224 
1225 template <>
createSwizzledCopy(const tcu::TextureCubeView & texture,const vk::VkComponentMapping & swz)1226 MovePtr<tcu::TextureCube> createSwizzledCopy(const tcu::TextureCubeView &texture, const vk::VkComponentMapping &swz)
1227 {
1228     MovePtr<tcu::TextureCube> copy(new tcu::TextureCube(
1229         getSwizzleTargetFormat(texture.getLevelFace(0, tcu::CUBEFACE_NEGATIVE_X).getFormat()), texture.getSize()));
1230 
1231     for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
1232     {
1233         for (int levelNdx = 0; levelNdx < texture.getNumLevels(); ++levelNdx)
1234         {
1235             copy->allocLevel((tcu::CubeFace)faceNdx, levelNdx);
1236             swizzle(texture.getLevelFace(levelNdx, (tcu::CubeFace)faceNdx),
1237                     copy->getLevelFace(levelNdx, (tcu::CubeFace)faceNdx), swz);
1238         }
1239     }
1240 
1241     return copy;
1242 }
1243 
1244 template <typename TextureViewType>
validateResultImage(const TextureViewType & texture,const tcu::Sampler & sampler,const vk::VkComponentMapping & swz,const tcu::ConstPixelBufferAccess & texCoords,const tcu::Vec2 & lodBounds,const tcu::LookupPrecision & lookupPrecision,const tcu::Vec4 & lookupScale,const tcu::Vec4 & lookupBias,const tcu::ConstPixelBufferAccess & result,const tcu::PixelBufferAccess & errorMask)1245 bool validateResultImage(const TextureViewType &texture, const tcu::Sampler &sampler, const vk::VkComponentMapping &swz,
1246                          const tcu::ConstPixelBufferAccess &texCoords, const tcu::Vec2 &lodBounds,
1247                          const tcu::LookupPrecision &lookupPrecision, const tcu::Vec4 &lookupScale,
1248                          const tcu::Vec4 &lookupBias, const tcu::ConstPixelBufferAccess &result,
1249                          const tcu::PixelBufferAccess &errorMask)
1250 {
1251     if (isIdentitySwizzle(swz))
1252         return validateResultImage(texture, sampler, texCoords, lodBounds, lookupPrecision, lookupScale, lookupBias,
1253                                    result, errorMask);
1254     else
1255     {
1256         // There is (currently) no way to handle swizzling inside validation loop
1257         // and thus we need to pre-swizzle the texture.
1258         UniquePtr<typename TexViewTraits<TextureViewType>::TextureType> swizzledTex(createSwizzledCopy(texture, swz));
1259 
1260         return validateResultImage(*swizzledTex, sampler, texCoords, lodBounds, lookupPrecision,
1261                                    swizzleScaleBias(lookupScale, swz, 1.0f), swizzleScaleBias(lookupBias, swz, 0.0f),
1262                                    result, errorMask);
1263     }
1264 }
1265 
resolveSubresourceRange(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource)1266 vk::VkImageSubresourceRange resolveSubresourceRange(const TestTexture &testTexture,
1267                                                     const vk::VkImageSubresourceRange &subresource)
1268 {
1269     vk::VkImageSubresourceRange resolved = subresource;
1270 
1271     if (subresource.levelCount == VK_REMAINING_MIP_LEVELS)
1272         resolved.levelCount = testTexture.getNumLevels() - subresource.baseMipLevel;
1273 
1274     if (subresource.layerCount == VK_REMAINING_ARRAY_LAYERS)
1275         resolved.layerCount = testTexture.getArraySize() - subresource.baseArrayLayer;
1276 
1277     return resolved;
1278 }
1279 
getTexture1DView(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource,std::vector<tcu::ConstPixelBufferAccess> & levels)1280 MovePtr<tcu::Texture1DView> getTexture1DView(const TestTexture &testTexture,
1281                                              const vk::VkImageSubresourceRange &subresource,
1282                                              std::vector<tcu::ConstPixelBufferAccess> &levels)
1283 {
1284     DE_ASSERT(subresource.layerCount == 1);
1285 
1286     levels.resize(subresource.levelCount);
1287 
1288     for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
1289     {
1290         const tcu::ConstPixelBufferAccess &srcLevel =
1291             testTexture.getLevel((int)subresource.baseMipLevel + levelNdx, subresource.baseArrayLayer);
1292 
1293         levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, 0, srcLevel.getWidth(), 1, 1);
1294     }
1295 
1296     return MovePtr<tcu::Texture1DView>(new tcu::Texture1DView((int)levels.size(), &levels[0]));
1297 }
1298 
getTexture1DArrayView(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource,std::vector<tcu::ConstPixelBufferAccess> & levels)1299 MovePtr<tcu::Texture1DArrayView> getTexture1DArrayView(const TestTexture &testTexture,
1300                                                        const vk::VkImageSubresourceRange &subresource,
1301                                                        std::vector<tcu::ConstPixelBufferAccess> &levels)
1302 {
1303     const TestTexture1D *tex1D           = dynamic_cast<const TestTexture1D *>(&testTexture);
1304     const TestTexture1DArray *tex1DArray = dynamic_cast<const TestTexture1DArray *>(&testTexture);
1305 
1306     DE_ASSERT(!!tex1D != !!tex1DArray);
1307     DE_ASSERT(tex1DArray || subresource.baseArrayLayer == 0);
1308 
1309     levels.resize(subresource.levelCount);
1310 
1311     for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
1312     {
1313         const tcu::ConstPixelBufferAccess &srcLevel =
1314             tex1D ? tex1D->getTexture().getLevel((int)subresource.baseMipLevel + levelNdx) :
1315                     tex1DArray->getTexture().getLevel((int)subresource.baseMipLevel + levelNdx);
1316 
1317         levels[levelNdx] = tcu::getSubregion(srcLevel, 0, (int)subresource.baseArrayLayer, 0, srcLevel.getWidth(),
1318                                              (int)subresource.layerCount, 1);
1319     }
1320 
1321     return MovePtr<tcu::Texture1DArrayView>(new tcu::Texture1DArrayView((int)levels.size(), &levels[0]));
1322 }
1323 
getTexture2DView(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource,std::vector<tcu::ConstPixelBufferAccess> & levels)1324 MovePtr<tcu::Texture2DView> getTexture2DView(const TestTexture &testTexture,
1325                                              const vk::VkImageSubresourceRange &subresource,
1326                                              std::vector<tcu::ConstPixelBufferAccess> &levels)
1327 {
1328     const TestTexture2D *tex2D           = dynamic_cast<const TestTexture2D *>(&testTexture);
1329     const TestTexture2DArray *tex2DArray = dynamic_cast<const TestTexture2DArray *>(&testTexture);
1330 
1331     DE_ASSERT(subresource.layerCount == 1);
1332     DE_ASSERT(!!tex2D != !!tex2DArray);
1333     DE_ASSERT(tex2DArray || subresource.baseArrayLayer == 0);
1334 
1335     levels.resize(subresource.levelCount);
1336 
1337     for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
1338     {
1339         const tcu::ConstPixelBufferAccess &srcLevel =
1340             tex2D ? tex2D->getTexture().getLevel((int)subresource.baseMipLevel + levelNdx) :
1341                     tex2DArray->getTexture().getLevel((int)subresource.baseMipLevel + levelNdx);
1342 
1343         levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer, srcLevel.getWidth(),
1344                                              srcLevel.getHeight(), 1);
1345     }
1346 
1347     return MovePtr<tcu::Texture2DView>(new tcu::Texture2DView((int)levels.size(), &levels[0]));
1348 }
1349 
getTexture2DArrayView(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource,std::vector<tcu::ConstPixelBufferAccess> & levels)1350 MovePtr<tcu::Texture2DArrayView> getTexture2DArrayView(const TestTexture &testTexture,
1351                                                        const vk::VkImageSubresourceRange &subresource,
1352                                                        std::vector<tcu::ConstPixelBufferAccess> &levels)
1353 {
1354     const TestTexture2D *tex2D           = dynamic_cast<const TestTexture2D *>(&testTexture);
1355     const TestTexture2DArray *tex2DArray = dynamic_cast<const TestTexture2DArray *>(&testTexture);
1356 
1357     DE_ASSERT(!!tex2D != !!tex2DArray);
1358     DE_ASSERT(tex2DArray || subresource.baseArrayLayer == 0);
1359 
1360     levels.resize(subresource.levelCount);
1361 
1362     for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
1363     {
1364         const tcu::ConstPixelBufferAccess &srcLevel =
1365             tex2D ? tex2D->getTexture().getLevel((int)subresource.baseMipLevel + levelNdx) :
1366                     tex2DArray->getTexture().getLevel((int)subresource.baseMipLevel + levelNdx);
1367 
1368         levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer, srcLevel.getWidth(),
1369                                              srcLevel.getHeight(), (int)subresource.layerCount);
1370     }
1371 
1372     return MovePtr<tcu::Texture2DArrayView>(new tcu::Texture2DArrayView((int)levels.size(), &levels[0]));
1373 }
1374 
getTextureCubeView(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource,std::vector<tcu::ConstPixelBufferAccess> & levels)1375 MovePtr<tcu::TextureCubeView> getTextureCubeView(const TestTexture &testTexture,
1376                                                  const vk::VkImageSubresourceRange &subresource,
1377                                                  std::vector<tcu::ConstPixelBufferAccess> &levels)
1378 {
1379     const static tcu::CubeFace s_faceMap[tcu::CUBEFACE_LAST] = {tcu::CUBEFACE_POSITIVE_X, tcu::CUBEFACE_NEGATIVE_X,
1380                                                                 tcu::CUBEFACE_POSITIVE_Y, tcu::CUBEFACE_NEGATIVE_Y,
1381                                                                 tcu::CUBEFACE_POSITIVE_Z, tcu::CUBEFACE_NEGATIVE_Z};
1382 
1383     const TestTextureCube *texCube           = dynamic_cast<const TestTextureCube *>(&testTexture);
1384     const TestTextureCubeArray *texCubeArray = dynamic_cast<const TestTextureCubeArray *>(&testTexture);
1385 
1386     DE_ASSERT(!!texCube != !!texCubeArray);
1387     DE_ASSERT(subresource.layerCount == 6);
1388     DE_ASSERT(texCubeArray || subresource.baseArrayLayer == 0);
1389 
1390     levels.resize(subresource.levelCount * tcu::CUBEFACE_LAST);
1391 
1392     for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
1393     {
1394         for (int levelNdx = 0; levelNdx < (int)subresource.levelCount; ++levelNdx)
1395         {
1396             const tcu::ConstPixelBufferAccess &srcLevel =
1397                 texCubeArray ? texCubeArray->getTexture().getLevel((int)subresource.baseMipLevel + levelNdx) :
1398                                texCube->getTexture().getLevelFace(levelNdx, s_faceMap[faceNdx]);
1399 
1400             levels[faceNdx * subresource.levelCount + levelNdx] =
1401                 tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer + (texCubeArray ? faceNdx : 0),
1402                                   srcLevel.getWidth(), srcLevel.getHeight(), 1);
1403         }
1404     }
1405 
1406     {
1407         const tcu::ConstPixelBufferAccess *reordered[tcu::CUBEFACE_LAST];
1408 
1409         for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; ++faceNdx)
1410             reordered[s_faceMap[faceNdx]] = &levels[faceNdx * subresource.levelCount];
1411 
1412         return MovePtr<tcu::TextureCubeView>(new tcu::TextureCubeView((int)subresource.levelCount, reordered));
1413     }
1414 }
1415 
getTextureCubeArrayView(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource,std::vector<tcu::ConstPixelBufferAccess> & levels)1416 MovePtr<tcu::TextureCubeArrayView> getTextureCubeArrayView(const TestTexture &testTexture,
1417                                                            const vk::VkImageSubresourceRange &subresource,
1418                                                            std::vector<tcu::ConstPixelBufferAccess> &levels)
1419 {
1420     const TestTextureCubeArray *texCubeArray = dynamic_cast<const TestTextureCubeArray *>(&testTexture);
1421 
1422     DE_ASSERT(texCubeArray);
1423     DE_ASSERT(subresource.layerCount % 6 == 0);
1424 
1425     levels.resize(subresource.levelCount);
1426 
1427     for (int levelNdx = 0; levelNdx < (int)subresource.levelCount; ++levelNdx)
1428     {
1429         const tcu::ConstPixelBufferAccess &srcLevel =
1430             texCubeArray->getTexture().getLevel((int)subresource.baseMipLevel + levelNdx);
1431 
1432         levels[levelNdx] = tcu::getSubregion(srcLevel, 0, 0, (int)subresource.baseArrayLayer, srcLevel.getWidth(),
1433                                              srcLevel.getHeight(), (int)subresource.layerCount);
1434     }
1435 
1436     return MovePtr<tcu::TextureCubeArrayView>(new tcu::TextureCubeArrayView((int)levels.size(), &levels[0]));
1437 }
1438 
getTexture3DView(const TestTexture & testTexture,const vk::VkImageSubresourceRange & subresource,std::vector<tcu::ConstPixelBufferAccess> & levels)1439 MovePtr<tcu::Texture3DView> getTexture3DView(const TestTexture &testTexture,
1440                                              const vk::VkImageSubresourceRange &subresource,
1441                                              std::vector<tcu::ConstPixelBufferAccess> &levels)
1442 {
1443     DE_ASSERT(subresource.baseArrayLayer == 0 && subresource.layerCount == 1);
1444 
1445     levels.resize(subresource.levelCount);
1446 
1447     for (int levelNdx = 0; levelNdx < (int)levels.size(); ++levelNdx)
1448         levels[levelNdx] = testTexture.getLevel((int)subresource.baseMipLevel + levelNdx, subresource.baseArrayLayer);
1449 
1450     return MovePtr<tcu::Texture3DView>(new tcu::Texture3DView((int)levels.size(), &levels[0]));
1451 }
1452 
validateResultImage(const TestTexture & texture,const VkImageViewType imageViewType,const VkImageSubresourceRange & subresource,const tcu::Sampler & sampler,const vk::VkComponentMapping & componentMapping,const tcu::ConstPixelBufferAccess & coordAccess,const tcu::Vec2 & lodBounds,const tcu::LookupPrecision & lookupPrecision,const tcu::Vec4 & lookupScale,const tcu::Vec4 & lookupBias,const tcu::ConstPixelBufferAccess & resultAccess,const tcu::PixelBufferAccess & errorAccess)1453 bool validateResultImage(const TestTexture &texture, const VkImageViewType imageViewType,
1454                          const VkImageSubresourceRange &subresource, const tcu::Sampler &sampler,
1455                          const vk::VkComponentMapping &componentMapping, const tcu::ConstPixelBufferAccess &coordAccess,
1456                          const tcu::Vec2 &lodBounds, const tcu::LookupPrecision &lookupPrecision,
1457                          const tcu::Vec4 &lookupScale, const tcu::Vec4 &lookupBias,
1458                          const tcu::ConstPixelBufferAccess &resultAccess, const tcu::PixelBufferAccess &errorAccess)
1459 {
1460     std::vector<tcu::ConstPixelBufferAccess> levels;
1461 
1462     switch (imageViewType)
1463     {
1464     case VK_IMAGE_VIEW_TYPE_1D:
1465     {
1466         UniquePtr<tcu::Texture1DView> texView(getTexture1DView(texture, subresource, levels));
1467 
1468         return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision,
1469                                    lookupScale, lookupBias, resultAccess, errorAccess);
1470     }
1471 
1472     case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
1473     {
1474         UniquePtr<tcu::Texture1DArrayView> texView(getTexture1DArrayView(texture, subresource, levels));
1475 
1476         return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision,
1477                                    lookupScale, lookupBias, resultAccess, errorAccess);
1478     }
1479 
1480     case VK_IMAGE_VIEW_TYPE_2D:
1481     {
1482         UniquePtr<tcu::Texture2DView> texView(getTexture2DView(texture, subresource, levels));
1483 
1484         return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision,
1485                                    lookupScale, lookupBias, resultAccess, errorAccess);
1486     }
1487 
1488     case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
1489     {
1490         UniquePtr<tcu::Texture2DArrayView> texView(getTexture2DArrayView(texture, subresource, levels));
1491 
1492         return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision,
1493                                    lookupScale, lookupBias, resultAccess, errorAccess);
1494     }
1495 
1496     case VK_IMAGE_VIEW_TYPE_CUBE:
1497     {
1498         UniquePtr<tcu::TextureCubeView> texView(getTextureCubeView(texture, subresource, levels));
1499 
1500         return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision,
1501                                    lookupScale, lookupBias, resultAccess, errorAccess);
1502     }
1503 
1504     case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
1505     {
1506         UniquePtr<tcu::TextureCubeArrayView> texView(getTextureCubeArrayView(texture, subresource, levels));
1507 
1508         return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision,
1509                                    lookupScale, lookupBias, resultAccess, errorAccess);
1510     }
1511 
1512     case VK_IMAGE_VIEW_TYPE_3D:
1513     {
1514         UniquePtr<tcu::Texture3DView> texView(getTexture3DView(texture, subresource, levels));
1515 
1516         return validateResultImage(*texView, sampler, componentMapping, coordAccess, lodBounds, lookupPrecision,
1517                                    lookupScale, lookupBias, resultAccess, errorAccess);
1518     }
1519 
1520     default:
1521         DE_ASSERT(false);
1522         return false;
1523     }
1524 }
1525 
1526 } // namespace
1527 
verifyImage(void)1528 tcu::TestStatus ImageSamplingInstance::verifyImage(void)
1529 {
1530     const VkPhysicalDeviceLimits &limits = m_context.getDeviceProperties().limits;
1531     // \note Color buffer is used to capture coordinates - not sampled texture values
1532     const tcu::TextureFormat colorFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
1533     const tcu::TextureFormat depthStencilFormat; // Undefined depth/stencil format.
1534     const CoordinateCaptureProgram coordCaptureProgram;
1535     const rr::Program rrProgram = coordCaptureProgram.getReferenceProgram();
1536     ReferenceRenderer refRenderer(m_renderSize.x(), m_renderSize.y(), 1, colorFormat, depthStencilFormat, &rrProgram);
1537     const bool useStencilAspect = (m_subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT);
1538 
1539     bool compareOkAll = true;
1540 
1541     tcu::Vec4 lookupScale(1.0f);
1542     tcu::Vec4 lookupBias(0.0f);
1543 
1544     getLookupScaleBias(m_imageFormat, lookupScale, lookupBias, useStencilAspect);
1545 
1546     // Render out coordinates
1547     {
1548         const rr::RenderState renderState(refRenderer.getViewportState(),
1549                                           m_context.getDeviceProperties().limits.subPixelPrecisionBits);
1550         refRenderer.draw(renderState, rr::PRIMITIVETYPE_TRIANGLES, m_vertices);
1551     }
1552 
1553     // Verify results
1554     {
1555         const tcu::Sampler sampler = mapVkSampler(m_samplerParams);
1556         const float referenceLod =
1557             de::clamp(m_samplerParams.mipLodBias + m_samplerLod, m_samplerParams.minLod, m_samplerParams.maxLod);
1558         const float lodError = 1.0f / static_cast<float>((1u << limits.mipmapPrecisionBits) - 1u);
1559         const tcu::Vec2 lodBounds(referenceLod - lodError, referenceLod + lodError);
1560         const vk::VkImageSubresourceRange subresource = resolveSubresourceRange(*m_texture, m_subresourceRange);
1561 
1562         const tcu::ConstPixelBufferAccess coordAccess = refRenderer.getAccess();
1563         tcu::TextureLevel errorMask(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8),
1564                                     (int)m_renderSize.x(), (int)m_renderSize.y());
1565         const tcu::PixelBufferAccess errorAccess = errorMask.getAccess();
1566 
1567         const bool isNearestOnly =
1568             (m_samplerParams.minFilter == VK_FILTER_NEAREST && m_samplerParams.magFilter == VK_FILTER_NEAREST);
1569 
1570         tcu::LookupPrecision lookupPrecision;
1571 
1572         // Set precision requirements - very low for these tests as
1573         // the point of the test is not to validate accuracy.
1574         lookupPrecision.coordBits = tcu::IVec3(17, 17, 17);
1575         lookupPrecision.uvwBits   = tcu::IVec3(5, 5, 5);
1576         lookupPrecision.colorMask = m_componentMask;
1577         lookupPrecision.colorThreshold =
1578             tcu::computeFixedPointThreshold(max((tcu::IVec4(8, 8, 8, 8) - (isNearestOnly ? 1 : 2)), tcu::IVec4(0))) /
1579             swizzleScaleBias(lookupScale, m_componentMapping, 1.0f);
1580 
1581         if (m_imageFormat == VK_FORMAT_BC5_UNORM_BLOCK || m_imageFormat == VK_FORMAT_BC5_SNORM_BLOCK)
1582             lookupPrecision.colorThreshold = tcu::Vec4(0.06f, 0.06f, 0.06f, 0.06f);
1583         if (tcu::isSRGB(m_texture->getTextureFormat()))
1584             lookupPrecision.colorThreshold += tcu::Vec4(4.f / 255.f);
1585 
1586         de::MovePtr<TestTexture> textureCopy;
1587         TestTexture *texture = nullptr;
1588 
1589         if (isCombinedDepthStencilType(m_texture->getTextureFormat().type))
1590         {
1591             // Verification loop does not support reading from combined depth stencil texture levels.
1592             // Get rid of stencil component.
1593 
1594             tcu::TextureFormat::ChannelOrder channelOrder = tcu::TextureFormat::CHANNELORDER_LAST;
1595             tcu::TextureFormat::ChannelType channelType   = tcu::TextureFormat::CHANNELTYPE_LAST;
1596 
1597             if (subresource.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT)
1598             {
1599                 channelOrder = tcu::TextureFormat::S;
1600                 channelType  = tcu::TextureFormat::UNSIGNED_INT8;
1601             }
1602             else
1603             {
1604                 channelOrder = tcu::TextureFormat::D;
1605 
1606                 switch (m_texture->getTextureFormat().type)
1607                 {
1608                 case tcu::TextureFormat::UNSIGNED_INT_16_8_8:
1609                     channelType = tcu::TextureFormat::UNORM_INT16;
1610                     break;
1611                 case tcu::TextureFormat::UNSIGNED_INT_24_8:
1612                 case tcu::TextureFormat::UNSIGNED_INT_24_8_REV:
1613                     channelType = tcu::TextureFormat::UNORM_INT24;
1614                     break;
1615                 case tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
1616                     channelType = tcu::TextureFormat::FLOAT;
1617                     break;
1618                 default:
1619                     DE_FATAL("Unhandled texture format type in switch");
1620                 }
1621             }
1622 
1623             textureCopy = m_texture->copy(tcu::TextureFormat(channelOrder, channelType));
1624             texture     = textureCopy.get();
1625         }
1626         else
1627         {
1628             texture = m_texture.get();
1629         }
1630 
1631         for (int imgNdx = 0; imgNdx < m_imageCount; ++imgNdx)
1632         {
1633             // Read back result image
1634             UniquePtr<tcu::TextureLevel> result(readColorAttachment(
1635                 m_context.getDeviceInterface(), m_context.getDevice(), m_context.getUniversalQueue(),
1636                 m_context.getUniversalQueueFamilyIndex(), m_context.getDefaultAllocator(), **m_colorImages[imgNdx],
1637                 m_colorFormat, m_renderSize));
1638             const tcu::ConstPixelBufferAccess resultAccess = result->getAccess();
1639             bool compareOk =
1640                 validateResultImage(*texture, m_imageViewType, subresource, sampler, m_componentMapping, coordAccess,
1641                                     lodBounds, lookupPrecision, lookupScale, lookupBias, resultAccess, errorAccess);
1642             if (!compareOk)
1643                 m_context.getTestContext().getLog() << tcu::TestLog::Image("Result", "Result Image", resultAccess)
1644                                                     << tcu::TestLog::Image("ErrorMask", "Error Mask", errorAccess);
1645 
1646             compareOkAll = compareOkAll && compareOk;
1647         }
1648     }
1649 
1650     if (compareOkAll)
1651         return tcu::TestStatus::pass("Result image matches reference");
1652     else
1653         return tcu::TestStatus::fail("Image mismatch");
1654 }
1655 
1656 } // namespace pipeline
1657 } // namespace vkt
1658