1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021-2022 Google LLC.
6  *
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Tests that images using a block-compressed format are sampled
23  * correctly
24  *
25  * These tests create a storage image using a 128-bit or a 64-bit
26  * block-compressed image format and an ImageView using an uncompressed
27  * format. Each test case then fills the storage image with compressed
28  * color values in a compute shader and samples the storage image. If the
29  * sampled values are pure blue, the test passes.
30  *//*--------------------------------------------------------------------*/
31 
32 #include "deUniquePtr.hpp"
33 #include "deStringUtil.hpp"
34 
35 #include "tcuCompressedTexture.hpp"
36 #include "tcuVectorType.hpp"
37 #include "tcuTextureUtil.hpp"
38 #include "tcuImageCompare.hpp"
39 #include "tcuTexture.hpp"
40 
41 #include "vkDefs.hpp"
42 #include "vkRef.hpp"
43 #include "vkRefUtil.hpp"
44 #include "vkPrograms.hpp"
45 #include "vkMemUtil.hpp"
46 #include "vkBuilderUtil.hpp"
47 #include "vkImageUtil.hpp"
48 #include "vkCmdUtil.hpp"
49 #include "vkObjUtil.hpp"
50 #include "vkTypeUtil.hpp"
51 #include "vkImageWithMemory.hpp"
52 #include "vktImageTestsUtil.hpp"
53 #include "vkBarrierUtil.hpp"
54 
55 #include "vktTestCaseUtil.hpp"
56 #include "tcuTestLog.hpp"
57 
58 #include <string>
59 
60 using namespace vk;
61 
62 namespace vkt
63 {
64 namespace image
65 {
66 namespace
67 {
68 using de::MovePtr;
69 using std::vector;
70 using tcu::ConstPixelBufferAccess;
71 using tcu::IVec3;
72 using tcu::TextureLevel;
73 using tcu::Vec2;
74 using tcu::Vec4;
75 
76 const VkDeviceSize BUFFERSIZE = 100u * 1024;
77 const int WIDTH               = 80;
78 const int HEIGHT              = 80;
79 const int FACES               = 6;
80 
getLayerCount(const bool cubemap)81 uint32_t getLayerCount(const bool cubemap)
82 {
83     return (cubemap ? static_cast<uint32_t>(FACES) : 1u);
84 }
85 
makeImageCreateInfo(const IVec3 & size,const VkFormat & format,bool storageImage,bool cubemap)86 inline VkImageCreateInfo makeImageCreateInfo(const IVec3 &size, const VkFormat &format, bool storageImage, bool cubemap)
87 {
88     VkImageUsageFlags usageFlags =
89         VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
90     VkImageCreateFlags createFlags = cubemap ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : DE_NULL;
91     const uint32_t layerCount      = getLayerCount(cubemap);
92 
93     if (storageImage)
94     {
95         usageFlags = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
96                      VK_IMAGE_USAGE_SAMPLED_BIT;
97         createFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT |
98                        VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT;
99     }
100 
101     const VkImageCreateInfo imageParams = {
102         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,  //  VkStructureType         sType;
103         DE_NULL,                              //  const void*             pNext;
104         createFlags,                          //  VkImageCreateFlags      flags;
105         VK_IMAGE_TYPE_2D,                     //  VkImageType             imageType;
106         format,                               //  VkFormat                format;
107         makeExtent3D(size.x(), size.y(), 1u), //  VkExtent3D              extent;
108         1u,                                   //  uint32_t                mipLevels;
109         layerCount,                           //  uint32_t                arrayLayers;
110         VK_SAMPLE_COUNT_1_BIT,                //  VkSampleCountFlagBits   samples;
111         VK_IMAGE_TILING_OPTIMAL,              //  VkImageTiling           tiling;
112         usageFlags,                           //  VkImageUsageFlags       usage;
113         VK_SHARING_MODE_EXCLUSIVE,            //  VkSharingMode           sharingMode;
114         0u,                                   //  uint32_t                queueFamilyIndexCount;
115         DE_NULL,                              //  const uint32_t*         pQueueFamilyIndices;
116         VK_IMAGE_LAYOUT_UNDEFINED,            //  VkImageLayout           initialLayout;
117     };
118 
119     return imageParams;
120 }
121 
makeVertexBuffer(const DeviceInterface & vk,const VkDevice device,const uint32_t queueFamilyIndex)122 Move<VkBuffer> makeVertexBuffer(const DeviceInterface &vk, const VkDevice device, const uint32_t queueFamilyIndex)
123 {
124     const VkBufferCreateInfo vertexBufferParams = {
125         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType      sType;
126         DE_NULL,                              // const void*          pNext;
127         0u,                                   // VkBufferCreateFlags  flags;
128         BUFFERSIZE,                           // VkDeviceSize         size;
129         VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,    // VkBufferUsageFlags   usage;
130         VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode        sharingMode;
131         1u,                                   // uint32_t             queueFamilyIndexCount;
132         &queueFamilyIndex                     // const uint32_t*      pQueueFamilyIndices;
133     };
134 
135     Move<VkBuffer> vertexBuffer = createBuffer(vk, device, &vertexBufferParams);
136     return vertexBuffer;
137 }
138 
139 class SampleDrawnTextureTestInstance : public TestInstance
140 {
141 public:
142     SampleDrawnTextureTestInstance(Context &context, const VkFormat imageFormat, const VkFormat imageViewFormat,
143                                    const bool twoSamplers, const bool cubemap);
144 
145     tcu::TestStatus iterate(void);
146 
147 private:
148     const VkFormat m_imageFormat;
149     const VkFormat m_imageViewFormat;
150     const bool m_twoSamplers;
151     const bool m_cubemap;
152 };
153 
SampleDrawnTextureTestInstance(Context & context,const VkFormat imageFormat,const VkFormat imageViewFormat,const bool twoSamplers,const bool cubemap)154 SampleDrawnTextureTestInstance::SampleDrawnTextureTestInstance(Context &context, const VkFormat imageFormat,
155                                                                const VkFormat imageViewFormat, const bool twoSamplers,
156                                                                const bool cubemap)
157     : TestInstance(context)
158     , m_imageFormat(imageFormat)
159     , m_imageViewFormat(imageViewFormat)
160     , m_twoSamplers(twoSamplers)
161     , m_cubemap(cubemap)
162 {
163 }
164 
makeSampler(const DeviceInterface & vk,const VkDevice & device)165 Move<VkSampler> makeSampler(const DeviceInterface &vk, const VkDevice &device)
166 {
167     const VkSamplerCreateInfo samplerParams = {
168         VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,   // VkStructureType          sType;
169         DE_NULL,                                 // const void*              pNext;
170         (VkSamplerCreateFlags)0,                 // VkSamplerCreateFlags     flags;
171         VK_FILTER_NEAREST,                       // VkFilter                 magFilter;
172         VK_FILTER_NEAREST,                       // VkFilter                 minFilter;
173         VK_SAMPLER_MIPMAP_MODE_NEAREST,          // VkSamplerMipmapMode      mipmapMode;
174         VK_SAMPLER_ADDRESS_MODE_REPEAT,          // VkSamplerAddressMode     addressModeU;
175         VK_SAMPLER_ADDRESS_MODE_REPEAT,          // VkSamplerAddressMode     addressModeV;
176         VK_SAMPLER_ADDRESS_MODE_REPEAT,          // VkSamplerAddressMode     addressModeW;
177         0.0f,                                    // float                    mipLodBias;
178         VK_FALSE,                                // VkBool32                 anisotropyEnable;
179         1.0f,                                    // float                    maxAnisotropy;
180         VK_FALSE,                                // VkBool32                 compareEnable;
181         VK_COMPARE_OP_ALWAYS,                    // VkCompareOp              compareOp;
182         0.0f,                                    // float                    minLod;
183         0.0f,                                    // float                    maxLod;
184         VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor            borderColor;
185         VK_FALSE,                                // VkBool32                 unnormalizedCoordinates;
186     };
187 
188     return createSampler(vk, device, &samplerParams);
189 }
190 
191 struct Vertex
192 {
Vertexvkt::image::__anonbe945fba0111::Vertex193     Vertex(Vec4 position_, Vec2 uv_) : position(position_), uv(uv_)
194     {
195     }
196     Vec4 position;
197     Vec2 uv;
198 
199     static VkVertexInputBindingDescription getBindingDescription(void);
200     static vector<VkVertexInputAttributeDescription> getAttributeDescriptions(void);
201 };
202 
getBindingDescription(void)203 VkVertexInputBindingDescription Vertex::getBindingDescription(void)
204 {
205     static const VkVertexInputBindingDescription desc = {
206         0u,                                    // uint32_t             binding;
207         static_cast<uint32_t>(sizeof(Vertex)), // uint32_t             stride;
208         VK_VERTEX_INPUT_RATE_VERTEX,           // VkVertexInputRate    inputRate;
209     };
210 
211     return desc;
212 }
213 
getAttributeDescriptions(void)214 vector<VkVertexInputAttributeDescription> Vertex::getAttributeDescriptions(void)
215 {
216     static const vector<VkVertexInputAttributeDescription> desc = {
217         {
218             0u,                                                // uint32_t    location;
219             0u,                                                // uint32_t    binding;
220             vk::VK_FORMAT_R32G32B32A32_SFLOAT,                 // VkFormat    format;
221             static_cast<uint32_t>(offsetof(Vertex, position)), // uint32_t    offset;
222         },
223         {
224             1u,                                          // uint32_t    location;
225             0u,                                          // uint32_t    binding;
226             vk::VK_FORMAT_R32G32_SFLOAT,                 // VkFormat    format;
227             static_cast<uint32_t>(offsetof(Vertex, uv)), // uint32_t    offset;
228         },
229     };
230 
231     return desc;
232 }
233 
234 // Generates the vertices of a full quad and texture coordinates of each vertex.
generateVertices(void)235 vector<Vertex> generateVertices(void)
236 {
237     vector<Vertex> vertices;
238     vertices.push_back(Vertex(Vec4(-1.0f, -1.0f, 0.0f, 1.0f), Vec2(0.0f, 0.0f)));
239     vertices.push_back(Vertex(Vec4(1.0f, -1.0f, 0.0f, 1.0f), Vec2(1.0f, 0.0f)));
240     vertices.push_back(Vertex(Vec4(-1.0f, 1.0f, 0.0f, 1.0f), Vec2(0.0f, 1.0f)));
241     vertices.push_back(Vertex(Vec4(1.0f, -1.0f, 0.0f, 1.0f), Vec2(1.0f, 0.0f)));
242     vertices.push_back(Vertex(Vec4(1.0f, 1.0f, 0.0f, 1.0f), Vec2(1.0f, 1.0f)));
243     vertices.push_back(Vertex(Vec4(-1.0f, 1.0f, 0.0f, 1.0f), Vec2(0.0f, 1.0f)));
244 
245     return vertices;
246 }
247 
248 // Generates a reference image filled with pure blue.
makeReferenceImage(const VkFormat format,int width,int height)249 TextureLevel makeReferenceImage(const VkFormat format, int width, int height)
250 {
251     TextureLevel referenceImage(mapVkFormat(format), width, height, 1);
252     for (int y = 0; y < height; y++)
253         for (int x = 0; x < width; x++)
254             referenceImage.getAccess().setPixel(tcu::IVec4(0, 0, 255, 255), x, y, 0);
255 
256     return referenceImage;
257 }
258 
iterate(void)259 tcu::TestStatus SampleDrawnTextureTestInstance::iterate(void)
260 {
261     DE_ASSERT(m_imageFormat == VK_FORMAT_BC1_RGB_UNORM_BLOCK || m_imageFormat == VK_FORMAT_BC3_UNORM_BLOCK);
262 
263     const DeviceInterface &vk       = m_context.getDeviceInterface();
264     const VkDevice device           = m_context.getDevice();
265     Allocator &allocator            = m_context.getDefaultAllocator();
266     const VkQueue queue             = m_context.getUniversalQueue();
267     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
268 
269     const IVec3 imageSize       = {static_cast<int>(WIDTH), HEIGHT, 1};
270     const VkExtent2D renderSize = {uint32_t(WIDTH), uint32_t(HEIGHT)};
271     const VkRect2D renderArea   = makeRect2D(makeExtent3D(WIDTH, HEIGHT, 1u));
272     const vector<VkRect2D> scissors(1u, renderArea);
273     const vector<VkViewport> viewports(1u, makeViewport(makeExtent3D(WIDTH, HEIGHT, 1u)));
274 
275     const Move<VkCommandPool> cmdPool =
276         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
277     const Move<VkCommandBuffer> cmdBuffer =
278         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
279 
280     const Unique<VkDescriptorPool> descriptorPool(
281         DescriptorPoolBuilder()
282             .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 6)
283             .addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 12)
284             .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 21u));
285 
286     const VkFormat renderedImageFormat = VK_FORMAT_R8G8B8A8_UNORM;
287     tcu::CompressedTexFormat compressedFormat(mapVkCompressedFormat(m_imageFormat));
288     IVec3 blockSize = tcu::getBlockPixelSize(compressedFormat);
289 
290     DE_ASSERT(blockSize.z() == 1);
291 
292     IVec3 storageImageViewSize = imageSize / blockSize;
293 
294     // Create a storage image. The first pipeline fills it and the second pipeline
295     // uses it as a sampling source.
296     const VkImageCreateInfo imageCreateInfo = makeImageCreateInfo(imageSize, m_imageFormat, true, m_cubemap);
297     const auto layerCount                   = getLayerCount(m_cubemap);
298     const VkImageSubresourceRange imageSubresourceRange =
299         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1, 0, layerCount);
300     const ImageWithMemory storageImage(vk, device, m_context.getDefaultAllocator(), imageCreateInfo,
301                                        MemoryRequirement::Any);
302 
303     // Create image views and descriptor sets for the first pipeline
304     Move<VkDescriptorSetLayout> descriptorSetLayout =
305         DescriptorSetLayoutBuilder()
306             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
307             .build(vk, device);
308 
309     Move<VkImageView> storageImageImageView;
310     VkDescriptorImageInfo storageImageDscrInfo;
311     Move<VkDescriptorSet> storageImageDescriptorSet;
312 
313     // Cubemap tests use separate image views for each side of a cubemap.
314     vector<VkImageSubresourceRange> cubeSubresourceRanges;
315     vector<Move<VkImageView>> cubeStorageImageViews;
316     vector<VkDescriptorImageInfo> cubeStorageDscrImageInfos;
317     vector<Move<VkDescriptorSet>> cubeStorageDscrSets;
318 
319     if (m_cubemap)
320     {
321         DescriptorSetUpdateBuilder updateBuilder;
322         for (int i = 0; i < FACES; i++)
323         {
324             cubeSubresourceRanges.emplace_back(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1, i, 1));
325             cubeStorageImageViews.emplace_back(makeImageView(vk, device, *storageImage, VK_IMAGE_VIEW_TYPE_2D,
326                                                              m_imageViewFormat, cubeSubresourceRanges[i]));
327             cubeStorageDscrImageInfos.emplace_back(
328                 makeDescriptorImageInfo(DE_NULL, *cubeStorageImageViews[i], VK_IMAGE_LAYOUT_GENERAL));
329             cubeStorageDscrSets.emplace_back(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
330             updateBuilder.writeSingle(*cubeStorageDscrSets[i], DescriptorSetUpdateBuilder::Location::binding(0u),
331                                       VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &cubeStorageDscrImageInfos[i]);
332         }
333         updateBuilder.update(vk, device);
334     }
335     else
336     {
337         storageImageImageView =
338             makeImageView(vk, device, *storageImage, VK_IMAGE_VIEW_TYPE_2D, m_imageViewFormat, imageSubresourceRange);
339         storageImageDscrInfo      = makeDescriptorImageInfo(DE_NULL, *storageImageImageView, VK_IMAGE_LAYOUT_GENERAL);
340         storageImageDescriptorSet = makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout);
341 
342         DescriptorSetUpdateBuilder()
343             .writeSingle(*storageImageDescriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
344                          VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &storageImageDscrInfo)
345             .update(vk, device);
346     }
347 
348     // Create a compute pipeline.
349     Move<VkShaderModule> computeShader =
350         createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0u);
351     const VkPushConstantRange pushConstantRange = {
352         VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlags    stageFlags;
353         0u,                          // uint32_t              offset;
354         (uint32_t)sizeof(uint32_t),  // uint32_t              size;
355     };
356 
357     const Move<VkPipelineLayout> computePipelineLayout =
358         makePipelineLayout(vk, device, 1, &(*descriptorSetLayout), 1, &pushConstantRange);
359     Move<VkPipeline> computePipeline = makeComputePipeline(vk, device, *computePipelineLayout, *computeShader);
360 
361     // Create a graphics pipeline and all the necessary components for sampling the storage image
362 
363     // The first sampler uses an uncompressed format.
364     const Unique<VkSampler> sampler(makeSampler(vk, device));
365 
366     // The second sampler uses the same format as the image.
367     const Unique<VkSampler> sampler2(makeSampler(vk, device));
368 
369     // Image views implicitly derive the usage flags from the image. Drop the storage image flag since it's incompatible
370     // with the compressed format and unnecessary in sampling.
371     VkImageUsageFlags usageFlags                  = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
372     VkImageViewUsageCreateInfo imageViewUsageInfo = {
373         VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, //VkStructureType sType;
374         DE_NULL,                                        //const void* pNext;
375         usageFlags,                                     //VkImageUsageFlags usage;
376     };
377 
378     Move<VkImageView> sampledImageView;
379     Move<VkImageView> sampledImageView2;
380     VkDescriptorImageInfo samplerDscrImageInfo;
381     VkDescriptorImageInfo samplerDscrImageInfo2;
382     Move<VkDescriptorSet> graphicsDescriptorSet;
383 
384     // Cubemap tests use separate image views for each side of a cubemap.
385     vector<Move<VkImageView>> cubeSamplerImageViews;
386     vector<Move<VkImageView>> cubeSampler2ImageViews;
387     vector<VkDescriptorImageInfo> cubeSamplerDscrImageInfos;
388     vector<VkDescriptorImageInfo> cubeSampler2DscrImageInfos;
389     vector<Move<VkDescriptorSet>> cubeSamplerDescriptorSets;
390 
391     const auto graphicsDscrSetLayout(DescriptorSetLayoutBuilder()
392                                          .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
393                                                                   VK_SHADER_STAGE_FRAGMENT_BIT, &sampler2.get())
394                                          .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
395                                                                   VK_SHADER_STAGE_FRAGMENT_BIT, &sampler.get())
396                                          .build(vk, device));
397 
398     if (m_cubemap)
399     {
400         DescriptorSetUpdateBuilder updateBuilder;
401         for (int i = 0; i < FACES; i++)
402         {
403             cubeSamplerImageViews.emplace_back(makeImageView(vk, device, *storageImage, VK_IMAGE_VIEW_TYPE_2D,
404                                                              m_imageFormat, cubeSubresourceRanges[i],
405                                                              &imageViewUsageInfo));
406             cubeSamplerDscrImageInfos.emplace_back(
407                 makeDescriptorImageInfo(sampler2.get(), *cubeSamplerImageViews[i], VK_IMAGE_LAYOUT_GENERAL));
408             cubeSamplerDescriptorSets.emplace_back(
409                 makeDescriptorSet(vk, device, *descriptorPool, *graphicsDscrSetLayout));
410             updateBuilder.writeSingle(*cubeSamplerDescriptorSets[i], DescriptorSetUpdateBuilder::Location::binding(0u),
411                                       VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &cubeSamplerDscrImageInfos[i]);
412         }
413 
414         if (m_twoSamplers)
415         {
416             for (int i = 0; i < FACES; i++)
417             {
418                 cubeSampler2ImageViews.emplace_back(makeImageView(vk, device, *storageImage, VK_IMAGE_VIEW_TYPE_2D,
419                                                                   m_imageViewFormat, cubeSubresourceRanges[i]));
420                 cubeSampler2DscrImageInfos.emplace_back(
421                     makeDescriptorImageInfo(sampler.get(), *cubeSampler2ImageViews[i], VK_IMAGE_LAYOUT_GENERAL));
422                 updateBuilder.writeSingle(*cubeSamplerDescriptorSets[i],
423                                           DescriptorSetUpdateBuilder::Location::binding(1u),
424                                           VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &cubeSampler2DscrImageInfos[i]);
425             }
426         }
427         updateBuilder.update(vk, device);
428     }
429     else
430     {
431         const VkImageSubresourceRange subresourceRange =
432             makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1, 0, 1);
433         DescriptorSetUpdateBuilder updateBuilder;
434 
435         sampledImageView2     = makeImageView(vk, device, *storageImage, VK_IMAGE_VIEW_TYPE_2D, m_imageFormat,
436                                               subresourceRange, &imageViewUsageInfo);
437         samplerDscrImageInfo2 = makeDescriptorImageInfo(sampler2.get(), *sampledImageView2, VK_IMAGE_LAYOUT_GENERAL);
438         graphicsDescriptorSet = makeDescriptorSet(vk, device, *descriptorPool, *graphicsDscrSetLayout);
439 
440         if (m_twoSamplers)
441         {
442             sampledImageView =
443                 makeImageView(vk, device, *storageImage, VK_IMAGE_VIEW_TYPE_2D, m_imageViewFormat, subresourceRange);
444             samplerDscrImageInfo = makeDescriptorImageInfo(sampler.get(), *sampledImageView, VK_IMAGE_LAYOUT_GENERAL);
445         }
446 
447         updateBuilder.writeSingle(*graphicsDescriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
448                                   VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &samplerDscrImageInfo2);
449         if (m_twoSamplers)
450             updateBuilder.writeSingle(*graphicsDescriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
451                                       VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &samplerDscrImageInfo);
452 
453         updateBuilder.update(vk, device);
454     }
455 
456     // Sampled values will be rendered on this image.
457     const VkImageSubresourceRange targetSubresourceRange =
458         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1, 0, 1);
459     const VkImageCreateInfo targetImageCreateInfo = makeImageCreateInfo(imageSize, renderedImageFormat, false, false);
460 
461     const ImageWithMemory targetImage(vk, device, m_context.getDefaultAllocator(), targetImageCreateInfo,
462                                       MemoryRequirement::Any);
463     Move<VkImageView> targetImageView =
464         makeImageView(vk, device, *targetImage, VK_IMAGE_VIEW_TYPE_2D, renderedImageFormat, targetSubresourceRange);
465 
466     // Clear the render target image as black and do a layout transition.
467     const auto clearColor = makeClearValueColor(Vec4(0.0f, 0.0f, 0.0f, 0.0f)).color;
468     clearColorImage(vk, device, m_context.getUniversalQueue(), m_context.getUniversalQueueFamilyIndex(),
469                     targetImage.get(), clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
470                     (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
471                     VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
472 
473     const VkPushConstantRange pushConstantRange2 = {
474         VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags    stageFlags;
475         0u,                           // uint32_t              offset;
476         (uint32_t)sizeof(uint32_t),   // uint32_t              size;
477     };
478 
479     const Move<VkPipelineLayout> graphicsPipelineLayout =
480         makePipelineLayout(vk, device, 1, &(*graphicsDscrSetLayout), 1, &pushConstantRange2);
481 
482     // Vertices for a full quad and texture coordinates for each vertex.
483     const vector<Vertex> vertices = generateVertices();
484     const uint32_t vertexCount    = static_cast<uint32_t>(vertices.size());
485     Move<VkBuffer> vertexBuffer   = makeVertexBuffer(vk, device, queueFamilyIndex);
486     de::MovePtr<Allocation> vertexBufferAlloc =
487         bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible);
488     const VkDeviceSize vertexBufferOffset = 0ull;
489     deMemcpy(vertexBufferAlloc->getHostPtr(), de::dataOrNull(vertices), de::dataSize(vertices));
490     flushAlloc(vk, device, *vertexBufferAlloc);
491 
492     const auto vtxBindingDescription = Vertex::getBindingDescription();
493     const auto vtxAttrDescriptions   = Vertex::getAttributeDescriptions();
494 
495     const VkPipelineVertexInputStateCreateInfo vtxInputInfo = {
496         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType                             sType
497         nullptr,                                                   // const void*                                 pNext
498         0u,                                                        // VkPipelineVertexInputStateCreateFlags       flags
499         1u,                     // uint32_t                                    vertexBindingDescriptionCount
500         &vtxBindingDescription, // const VkVertexInputBindingDescription*      pVertexBindingDescriptions
501         static_cast<uint32_t>(
502             vtxAttrDescriptions.size()), // uint32_t                                    vertexAttributeDescriptionCount
503         vtxAttrDescriptions.data(),      // const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions
504     };
505 
506     Move<VkShaderModule> vertexShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
507     Move<VkShaderModule> fragmentShader =
508         createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u);
509 
510     // Create a render pass, a framebuffer, and the second pipeline.
511     Move<VkRenderPass> renderPass = makeRenderPass(vk, device, renderedImageFormat, VK_FORMAT_UNDEFINED,
512                                                    VK_ATTACHMENT_LOAD_OP_LOAD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
513     Move<VkFramebuffer> framebuffer =
514         makeFramebuffer(vk, device, *renderPass, targetImageView.get(), renderSize.width, renderSize.height);
515     const Move<VkPipeline> graphicsPipeline = makeGraphicsPipeline(
516         vk, device, graphicsPipelineLayout.get(), vertexShader.get(), DE_NULL, DE_NULL, DE_NULL, fragmentShader.get(),
517         renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u, &vtxInputInfo);
518 
519     // Create a result buffer.
520     const VkBufferCreateInfo resultBufferCreateInfo =
521         makeBufferCreateInfo(BUFFERSIZE, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
522     Move<VkBuffer> resultBuffer = createBuffer(vk, device, &resultBufferCreateInfo);
523     MovePtr<Allocation> resultBufferMemory =
524         allocator.allocate(getBufferMemoryRequirements(vk, device, *resultBuffer), MemoryRequirement::HostVisible);
525     TextureLevel resultImage(mapVkFormat(renderedImageFormat), renderSize.width, renderSize.height, 1);
526     VK_CHECK(
527         vk.bindBufferMemory(device, *resultBuffer, resultBufferMemory->getMemory(), resultBufferMemory->getOffset()));
528 
529     // Generate a reference image.
530     TextureLevel expectedImage = makeReferenceImage(renderedImageFormat, WIDTH, HEIGHT);
531 
532     beginCommandBuffer(vk, *cmdBuffer);
533 
534     // Do a layout transition for the storage image.
535     const auto barrier1 = makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
536                                                  VK_IMAGE_LAYOUT_GENERAL, storageImage.get(), imageSubresourceRange);
537     vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0,
538                           DE_NULL, 0, DE_NULL, 1u, &barrier1);
539 
540     // Bind the vertices and the descriptors used in the graphics pipeline.
541     vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
542 
543     // Fill the storage image and sample it twice.
544     for (int pass = 0; pass < 2; pass++)
545     {
546         // If both samplers are enabled, it's not necessary to run the compute shader twice since it already writes
547         // the expected values on the first pass. The first sampler uses an uncompressed image format so the result
548         // image will contain garbage if the second sampler doesn't work properly.
549         if (!m_twoSamplers || pass == 0)
550         {
551             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline);
552             vk.cmdPushConstants(*cmdBuffer, *computePipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(int32_t),
553                                 &pass);
554 
555             // If cubemaps are enabled, loop over six times and bind the next face of the cubemap image on each iteration.
556             if (m_cubemap)
557             {
558                 for (int face = 0; face < FACES; face++)
559                 {
560                     vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipelineLayout, 0u, 1u,
561                                              &(cubeStorageDscrSets[face].get()), 0u, DE_NULL);
562                     vk.cmdDispatch(*cmdBuffer, storageImageViewSize.x(), storageImageViewSize.y(), 1u);
563                 }
564             }
565             else
566             {
567                 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipelineLayout, 0u, 1u,
568                                          &storageImageDescriptorSet.get(), 0u, DE_NULL);
569                 vk.cmdDispatch(*cmdBuffer, storageImageViewSize.x(), storageImageViewSize.y(), 1u);
570             }
571 
572             const auto barrier2 =
573                 makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL,
574                                        VK_IMAGE_LAYOUT_GENERAL, storageImage.get(), imageSubresourceRange);
575             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
576                                   VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, DE_NULL, 0, DE_NULL, 1u, &barrier2);
577         }
578 
579         vk.cmdPushConstants(*cmdBuffer, *graphicsPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(int32_t),
580                             &pass);
581 
582         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
583 
584         // If cubemaps are enabled, loop over six times and bind the next face of the cubemap image on each iteration.
585         if (m_cubemap)
586         {
587             for (int face = 0; face < FACES; face++)
588             {
589                 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipelineLayout, 0u, 1u,
590                                          &(cubeSamplerDescriptorSets[face].get()), 0u, DE_NULL);
591 
592                 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer,
593                                 makeRect2D(0, 0, imageSize.x(), imageSize.y()), 0u, DE_NULL);
594                 vk.cmdDraw(*cmdBuffer, vertexCount, 1u, 0u, 0u);
595                 endRenderPass(vk, *cmdBuffer);
596 
597                 if (face < FACES - 1)
598                 {
599                     const auto barrier4 = makeImageMemoryBarrier(
600                         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
601                         (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT),
602                         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
603                         targetImage.get(), targetSubresourceRange);
604                     vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
605                                           VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, DE_NULL, 0, DE_NULL, 1u,
606                                           &barrier4);
607                 }
608             }
609         }
610         else
611         {
612             vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipelineLayout, 0u, 1u,
613                                      &(graphicsDescriptorSet.get()), 0u, DE_NULL);
614 
615             beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, imageSize.x(), imageSize.y()),
616                             0u, DE_NULL);
617             vk.cmdDraw(*cmdBuffer, vertexCount, 1u, 0u, 0u);
618             endRenderPass(vk, *cmdBuffer);
619         }
620 
621         if (pass == 0)
622         {
623             const auto barrier3 =
624                 makeImageMemoryBarrier(VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL,
625                                        VK_IMAGE_LAYOUT_GENERAL, storageImage.get(), imageSubresourceRange);
626             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
627                                   VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, DE_NULL, 0, DE_NULL, 1u, &barrier3);
628 
629             const auto barrier4 =
630                 makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
631                                        (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT),
632                                        VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
633                                        targetImage.get(), targetSubresourceRange);
634             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
635                                   VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, DE_NULL, 0, DE_NULL, 1u,
636                                   &barrier4);
637         }
638     }
639 
640     // Copy the sampled values from the target image into the result image.
641     copyImageToBuffer(vk, *cmdBuffer, *targetImage, *resultBuffer, tcu::IVec2(WIDTH, HEIGHT),
642                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
643 
644     endCommandBuffer(vk, *cmdBuffer);
645     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
646 
647     invalidateAlloc(vk, device, *resultBufferMemory);
648 
649     clear(resultImage.getAccess(), tcu::IVec4(0));
650     copy(resultImage.getAccess(),
651          ConstPixelBufferAccess(resultImage.getFormat(), resultImage.getSize(), resultBufferMemory->getHostPtr()));
652 
653     bool result = true;
654 
655     if (m_cubemap)
656     {
657         // The first pass draws pure red on the faces and the second pass redraws them with pure blue.
658         // Sampling anywhere should produce colors with a 0.0 red component and > 0.0 blue and alpha components.
659         for (uint32_t y = 0; y < renderSize.height; y++)
660         {
661             for (uint32_t x = 0; x < renderSize.width; x++)
662             {
663                 const uint8_t *ptr   = static_cast<const uint8_t *>(resultImage.getAccess().getPixelPtr(x, y, 0));
664                 const tcu::IVec4 val = tcu::IVec4(ptr[0], ptr[1], ptr[2], ptr[3]);
665                 if (!(val[0] == 0 && val[2] > 0 && val[3] > 0))
666                     result = false;
667             }
668         }
669 
670         // Log attachment contents.
671         m_context.getTestContext().getLog()
672             << tcu::TestLog::ImageSet("Attachment ", "")
673             << tcu::TestLog::Image("Rendered image", "Rendered image", resultImage.getAccess())
674             << tcu::TestLog::EndImageSet;
675     }
676     else
677     {
678         // Each test case should render pure blue as the result.
679         result = tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Image Comparison", "",
680                                             expectedImage.getAccess(), resultImage.getAccess(), tcu::Vec4(0.01f),
681                                             tcu::COMPARE_LOG_RESULT);
682     }
683 
684     if (result)
685         return tcu::TestStatus::pass("pass");
686     else
687         return tcu::TestStatus::fail("fail");
688 }
689 
690 class SampleDrawnTextureTest : public TestCase
691 {
692 public:
693     SampleDrawnTextureTest(tcu::TestContext &testCtx, const std::string &name, const VkFormat imageFormat,
694                            const VkFormat imageViewFormat, const bool twoSamplers, const bool cubemap);
695 
696     void initPrograms(SourceCollections &programCollection) const;
697     TestInstance *createInstance(Context &context) const;
698     virtual void checkSupport(Context &context) const;
699 
700 private:
701     const VkFormat m_imageFormat;
702     const VkFormat m_imageViewFormat;
703     const bool m_twoSamplers;
704     const bool m_cubemap;
705 };
706 
SampleDrawnTextureTest(tcu::TestContext & testCtx,const std::string & name,const VkFormat imageFormat,const VkFormat imageViewFormat,const bool twoSamplers,const bool cubemap)707 SampleDrawnTextureTest::SampleDrawnTextureTest(tcu::TestContext &testCtx, const std::string &name,
708                                                const VkFormat imageFormat, const VkFormat imageViewFormat,
709                                                const bool twoSamplers, const bool cubemap)
710     : TestCase(testCtx, name)
711     , m_imageFormat(imageFormat)
712     , m_imageViewFormat(imageViewFormat)
713     , m_twoSamplers(twoSamplers)
714     , m_cubemap(cubemap)
715 {
716 }
717 
checkSupport(Context & context) const718 void SampleDrawnTextureTest::checkSupport(Context &context) const
719 {
720     const auto &vki       = context.getInstanceInterface();
721     const auto usageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
722                             VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
723     auto creationFlags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT |
724                          VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT;
725     if (m_cubemap)
726         creationFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
727 
728     // Check that:
729     // - VkImageViewUsageCreateInfo can be used to override implicit usage flags derived from the image.
730     // - A compressed image can be created with usage flags that are not supported for the format but are
731     //   supported by an image view that is using uncompressed format where each texel corresponds to
732     //   a compressed texel block of the image.
733 
734     if (!context.isDeviceFunctionalitySupported("VK_KHR_maintenance2"))
735         TCU_THROW(NotSupportedError,
736                   "Device does not support extended image usage flags nor overriding implicit usage flags");
737 
738     VkImageFormatProperties imageFormatProperties;
739 
740     if (vki.getPhysicalDeviceImageFormatProperties(context.getPhysicalDevice(), m_imageFormat, VK_IMAGE_TYPE_2D,
741                                                    VK_IMAGE_TILING_OPTIMAL, usageFlags, creationFlags,
742                                                    &imageFormatProperties) == VK_ERROR_FORMAT_NOT_SUPPORTED)
743     {
744         std::string algorithmName = (m_imageFormat == vk::VK_FORMAT_BC3_UNORM_BLOCK) ? "BC3" : "BC1";
745         std::string errorMsg      = algorithmName;
746 
747         errorMsg += m_cubemap ? " compressed cubemap images" : " compressed images";
748         errorMsg += " created with VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, VK_IMAGE_CREATE_EXTENDED_USAGE_BIT";
749         errorMsg += " and VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT flags not supported.";
750         TCU_THROW(NotSupportedError, errorMsg);
751     }
752 }
753 
initPrograms(SourceCollections & programCollection) const754 void SampleDrawnTextureTest::initPrograms(SourceCollections &programCollection) const
755 {
756     // Pure red, green, and blue compressed with the BC1 and BC3 algorithms.
757     std::string bc1_red  = "uvec4(4160813056u, 0u, 4160813056u, 0u);\n";
758     std::string bc1_blue = "uvec4(2031647, 0u, 2031647, 0u);\n";
759     std::string bc3_red  = "uvec4(4294967295u, 4294967295u, 4160813056u, 0u);\n";
760     std::string bc3_blue = "uvec4(4294967295u, 4294967295u, 2031647, 0u);\n";
761 
762     std::string red  = (m_imageFormat == VK_FORMAT_BC1_RGB_UNORM_BLOCK) ? bc1_red : bc3_red;
763     std::string blue = (m_imageFormat == VK_FORMAT_BC1_RGB_UNORM_BLOCK) ? bc1_blue : bc3_blue;
764 
765     std::ostringstream computeSrc;
766 
767     // Generate the compute shader.
768     computeSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n";
769     computeSrc << "layout(set = 0, binding = 0, rgba32ui) uniform highp uimage2D img;\n";
770     computeSrc << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n";
771 
772     if (!m_twoSamplers)
773     {
774         computeSrc << "layout(push_constant) uniform constants {\n"
775                    << "    int pass;\n"
776                    << "} pc;\n";
777     }
778 
779     computeSrc << "void main() {\n";
780 
781     if (m_twoSamplers)
782         computeSrc << "    uvec4 color = " << blue;
783     else
784     {
785         computeSrc << "    uvec4 color = " << red;
786         computeSrc << "    if (pc.pass == 1)\n";
787         computeSrc << "        color = " << blue;
788     }
789 
790     computeSrc << "    imageStore(img, ivec2(gl_GlobalInvocationID.xy), color);\n"
791                << "}\n";
792 
793     // Generate the vertex shader.
794     std::ostringstream vertexSrc;
795     vertexSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
796               << "layout(location = 0) in highp vec4 a_position;\n"
797               << "layout(location = 1) in vec2 inTexCoord;\n"
798               << "layout(location = 1) out vec2 fragTexCoord;\n"
799               << "void main (void) {\n"
800               << "    gl_Position = a_position;\n"
801               << "    fragTexCoord = inTexCoord;\n"
802               << "}\n";
803 
804     // Generate the fragment shader.
805     std::ostringstream fragmentSrc;
806     fragmentSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
807                 << "layout(location = 0) out vec4 outColor;\n"
808                 << "layout(location = 1) in vec2 fragTexCoord;\n";
809 
810     fragmentSrc << "layout(binding = 0) uniform sampler2D compTexSampler;\n";
811 
812     if (m_twoSamplers)
813     {
814         fragmentSrc << "layout(binding = 1) uniform usampler2D texSampler;\n"
815                     << "layout(push_constant) uniform constants {\n"
816                     << "    int pass;\n"
817                     << "} pc;\n"
818                     << "void main() {\n"
819                     << "    if (pc.pass == 1)\n"
820                     << "        outColor = texture(compTexSampler, fragTexCoord);\n"
821                     << "    else"
822                     << "        outColor = texture(texSampler, fragTexCoord);\n";
823     }
824     else
825     {
826         fragmentSrc << "void main() {\n"
827                     << "    outColor = texture(compTexSampler, fragTexCoord);\n";
828     }
829 
830     fragmentSrc << "}\n";
831 
832     programCollection.glslSources.add("comp") << glu::ComputeSource(computeSrc.str());
833     programCollection.glslSources.add("vert") << glu::VertexSource(vertexSrc.str());
834     programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSrc.str());
835 }
836 
createInstance(Context & context) const837 TestInstance *SampleDrawnTextureTest::createInstance(Context &context) const
838 {
839     return new SampleDrawnTextureTestInstance(context, m_imageFormat, m_imageViewFormat, m_twoSamplers, m_cubemap);
840 }
841 
842 } // namespace
843 
createImageSampleDrawnTextureTests(tcu::TestContext & testCtx)844 tcu::TestCaseGroup *createImageSampleDrawnTextureTests(tcu::TestContext &testCtx)
845 {
846     /* If both samplers are enabled, the test works as follows:
847      *
848      * Pass 0:
849      * - Compute shader fills a storage image with values that are pure blue compressed with
850      *   either the BC1 or BC3 algorithm.
851      * - Fragment shader samples the image and draws the values on a target image.
852      * - As the sampled values are accessed through an image view using an uncompressed
853      *   format, they remain compressed and the drawn image ends up being garbage.
854      * Pass 1:
855      * - Fragment shader samples the image. On this pass, the image view uses
856      *   a block-compressed format and correctly interprets the sampled values.
857      * - As the values are uncompressed now, the target image is filled
858      *   with pure blue and the test passes.
859 
860      * Only one sampler enabled:
861      * Pass 0:
862      * - Compute shader fills a storage image with values that are pure red compressed
863      *   with either the BC1 or BC3 algorithm.
864      * - Fragment shader samples the image through an image view which interprets the values
865      *   correctly. The values are drawn on a target image. The test doesn't pass yet
866      *   since the image is red.
867      * Pass 1:
868      * - Compute shader fills the storage image with values that are pure blue compressed
869      *   with the same algorithm as on the previous pass.
870      * - Fragment shader samples the image through an image view which interprets the values
871      *   correctly. The values are drawn on the target image and the test passes.
872      *
873      * If cubemaps are enabled:
874      * Pass 0:
875      * - If both samplers are enabled, draw compressed pure blue on the faces. Otherwise pure red.
876      * - Sample the image through an image view with or without compressed format as in the cases
877      *   without cubemaps.
878      * Pass 1:
879      * - If only one sampler is enabled, redraw the faces with pure blue
880      * - Sample the image. Sampling should produce colors with a 0.0 red component and with > 0.0
881      *   blue and alpha components.
882      */
883 
884     const bool twoSamplers = true;
885     const bool cubemap     = true;
886 
887     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "sample_texture"));
888 
889     testGroup->addChild(new SampleDrawnTextureTest(testCtx, "128_bit_compressed_format_cubemap",
890                                                    VK_FORMAT_BC3_UNORM_BLOCK, VK_FORMAT_R32G32B32A32_UINT, !twoSamplers,
891                                                    cubemap));
892     testGroup->addChild(new SampleDrawnTextureTest(testCtx, "64_bit_compressed_format_cubemap",
893                                                    VK_FORMAT_BC1_RGB_UNORM_BLOCK, VK_FORMAT_R32G32_UINT, !twoSamplers,
894                                                    cubemap));
895     testGroup->addChild(new SampleDrawnTextureTest(testCtx, "64_bit_compressed_format_two_samplers_cubemap",
896                                                    VK_FORMAT_BC1_RGB_UNORM_BLOCK, VK_FORMAT_R32G32_UINT, twoSamplers,
897                                                    cubemap));
898     testGroup->addChild(new SampleDrawnTextureTest(testCtx, "128_bit_compressed_format_two_samplers_cubemap",
899                                                    VK_FORMAT_BC3_UNORM_BLOCK, VK_FORMAT_R32G32B32A32_UINT, twoSamplers,
900                                                    cubemap));
901 
902     testGroup->addChild(new SampleDrawnTextureTest(testCtx, "64_bit_compressed_format", VK_FORMAT_BC1_RGB_UNORM_BLOCK,
903                                                    VK_FORMAT_R32G32_UINT, !twoSamplers, false));
904     testGroup->addChild(new SampleDrawnTextureTest(testCtx, "64_bit_compressed_format_two_samplers",
905                                                    VK_FORMAT_BC1_RGB_UNORM_BLOCK, VK_FORMAT_R32G32_UINT, twoSamplers,
906                                                    false));
907     testGroup->addChild(new SampleDrawnTextureTest(testCtx, "128_bit_compressed_format", VK_FORMAT_BC3_UNORM_BLOCK,
908                                                    VK_FORMAT_R32G32B32A32_UINT, !twoSamplers, false));
909     testGroup->addChild(new SampleDrawnTextureTest(testCtx, "128_bit_compressed_format_two_samplers",
910                                                    VK_FORMAT_BC3_UNORM_BLOCK, VK_FORMAT_R32G32B32A32_UINT, twoSamplers,
911                                                    false));
912 
913     return testGroup.release();
914 }
915 
916 } // namespace image
917 } // namespace vkt
918