1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2021-2022 Google LLC.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * \brief Tests that images using a block-compressed format are sampled
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 *//*--------------------------------------------------------------------*/
32 #include "deUniquePtr.hpp"
33 #include "deStringUtil.hpp"
35 #include "tcuCompressedTexture.hpp"
36 #include "tcuVectorType.hpp"
37 #include "tcuTextureUtil.hpp"
38 #include "tcuImageCompare.hpp"
39 #include "tcuTexture.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"
55 #include "vktTestCaseUtil.hpp"
56 #include "tcuTestLog.hpp"
73 using tcu::TextureLevel;
74 using tcu::PixelBufferAccess;
75 using tcu::ConstPixelBufferAccess;
77 const VkDeviceSize BUFFERSIZE = 100u * 1024;
79 const int HEIGHT = 80;
82 inline VkImageCreateInfo makeImageCreateInfo (const IVec3& size, const VkFormat& format, bool storageImage, bool cubemap)
84 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
85 | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
86 VkImageCreateFlags createFlags = cubemap ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : DE_NULL;
87 const deUint32 layerCount = cubemap ? 6u : 1u;
91 usageFlags = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT
92 | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
93 createFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT
94 | VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT;
97 const VkImageCreateInfo imageParams =
99 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
100 DE_NULL, // const void* pNext;
101 createFlags, // VkImageCreateFlags flags;
102 VK_IMAGE_TYPE_2D, // VkImageType imageType;
103 format, // VkFormat format;
104 makeExtent3D(size.x(), size.y(), 1u), // VkExtent3D extent;
105 1u, // deUint32 mipLevels;
106 layerCount, // deUint32 arrayLayers;
107 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
108 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
109 usageFlags, // VkImageUsageFlags usage;
110 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
111 0u, // deUint32 queueFamilyIndexCount;
112 DE_NULL, // const deUint32* pQueueFamilyIndices;
113 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
119 Move<VkBuffer> makeVertexBuffer (const DeviceInterface& vk, const VkDevice device, const deUint32 queueFamilyIndex)
121 const VkBufferCreateInfo vertexBufferParams =
123 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
124 DE_NULL, // const void* pNext;
125 0u, // VkBufferCreateFlags flags;
126 BUFFERSIZE, // VkDeviceSize size;
127 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
128 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
129 1u, // deUint32 queueFamilyIndexCount;
130 &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
133 Move<VkBuffer> vertexBuffer = createBuffer(vk, device, &vertexBufferParams);
137 class SampleDrawnTextureTestInstance : public TestInstance
140 SampleDrawnTextureTestInstance (Context& context,
141 const VkFormat imageFormat,
142 const VkFormat imageViewFormat,
143 const bool twoSamplers,
146 tcu::TestStatus iterate (void);
149 const VkFormat m_imageFormat;
150 const VkFormat m_imageViewFormat;
151 const bool m_twoSamplers;
152 const bool m_cubemap;
155 SampleDrawnTextureTestInstance::SampleDrawnTextureTestInstance (Context& context, const VkFormat imageFormat, const VkFormat imageViewFormat,
156 const bool twoSamplers, const bool cubemap)
157 : TestInstance (context)
158 , m_imageFormat (imageFormat)
159 , m_imageViewFormat (imageViewFormat)
160 , m_twoSamplers (twoSamplers)
161 , m_cubemap (cubemap)
166 inline size_t sizeInBytes (const vector<T>& vec)
168 return vec.size() * sizeof(vec[0]);
171 Move<VkSampler> makeSampler (const DeviceInterface& vk, const VkDevice& device)
173 const VkSamplerCreateInfo samplerParams =
175 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType;
176 DE_NULL, // const void* pNext;
177 (VkSamplerCreateFlags)0, // VkSamplerCreateFlags flags;
178 VK_FILTER_NEAREST, // VkFilter magFilter;
179 VK_FILTER_NEAREST, // VkFilter minFilter;
180 VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode;
181 VK_SAMPLER_ADDRESS_MODE_REPEAT, // VkSamplerAddressMode addressModeU;
182 VK_SAMPLER_ADDRESS_MODE_REPEAT, // VkSamplerAddressMode addressModeV;
183 VK_SAMPLER_ADDRESS_MODE_REPEAT, // VkSamplerAddressMode addressModeW;
184 0.0f, // float mipLodBias;
185 VK_FALSE, // VkBool32 anisotropyEnable;
186 1.0f, // float maxAnisotropy;
187 VK_FALSE, // VkBool32 compareEnable;
188 VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp;
189 0.0f, // float minLod;
190 0.0f, // float maxLod;
191 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor;
192 VK_FALSE, // VkBool32 unnormalizedCoordinates;
195 return createSampler(vk, device, &samplerParams);
200 Vertex(Vec4 position_, Vec2 uv_) : position(position_), uv(uv_) {}
204 static VkVertexInputBindingDescription getBindingDescription (void);
205 static vector<VkVertexInputAttributeDescription> getAttributeDescriptions (void);
208 VkVertexInputBindingDescription Vertex::getBindingDescription (void)
210 static const VkVertexInputBindingDescription desc =
212 0u, // deUint32 binding;
213 static_cast<deUint32>(sizeof(Vertex)), // deUint32 stride;
214 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
220 vector<VkVertexInputAttributeDescription> Vertex::getAttributeDescriptions (void)
222 static const vector<VkVertexInputAttributeDescription> desc =
225 0u, // deUint32 location;
226 0u, // deUint32 binding;
227 vk::VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
228 static_cast<deUint32>(offsetof(Vertex, position)), // deUint32 offset;
231 1u, // deUint32 location;
232 0u, // deUint32 binding;
233 vk::VK_FORMAT_R32G32_SFLOAT, // VkFormat format;
234 static_cast<deUint32>(offsetof(Vertex, uv)), // deUint32 offset;
241 // Generates the vertices of a full quad and texture coordinates of each vertex.
242 vector<Vertex> generateVertices (void)
244 vector<Vertex> vertices;
245 vertices.push_back(Vertex(Vec4(-1.0f, -1.0f, 0.0f, 1.0f), Vec2(0.0f, 0.0f)));
246 vertices.push_back(Vertex(Vec4( 1.0f, -1.0f, 0.0f, 1.0f), Vec2(1.0f, 0.0f)));
247 vertices.push_back(Vertex(Vec4(-1.0f, 1.0f, 0.0f, 1.0f), Vec2(0.0f, 1.0f)));
248 vertices.push_back(Vertex(Vec4( 1.0f, -1.0f, 0.0f, 1.0f), Vec2(1.0f, 0.0f)));
249 vertices.push_back(Vertex(Vec4( 1.0f, 1.0f, 0.0f, 1.0f), Vec2(1.0f, 1.0f)));
250 vertices.push_back(Vertex(Vec4(-1.0f, 1.0f, 0.0f, 1.0f), Vec2(0.0f, 1.0f)));
255 // Generates a reference image filled with pure blue.
256 TextureLevel makeReferenceImage (const VkFormat format, int width, int height)
258 TextureLevel referenceImage(mapVkFormat(format), width, height, 1);
259 for (int y = 0; y < height; y++)
260 for (int x = 0; x < width; x++)
261 referenceImage.getAccess().setPixel(tcu::IVec4(0, 0, 255, 255), x, y, 0);
263 return referenceImage;
266 tcu::TestStatus SampleDrawnTextureTestInstance::iterate (void)
268 DE_ASSERT(m_imageFormat == VK_FORMAT_BC1_RGB_UNORM_BLOCK || m_imageFormat == VK_FORMAT_BC3_UNORM_BLOCK);
270 const DeviceInterface& vk = m_context.getDeviceInterface();
271 const VkDevice device = m_context.getDevice();
272 Allocator& allocator = m_context.getDefaultAllocator();
273 const VkQueue queue = m_context.getUniversalQueue();
274 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
276 const IVec3 imageSize = {static_cast<int>(WIDTH), HEIGHT, 1};
277 const VkExtent2D renderSize = {deUint32(WIDTH), deUint32(HEIGHT)};
278 const VkRect2D renderArea = makeRect2D(makeExtent3D(WIDTH, HEIGHT, 1u));
279 const vector<VkRect2D> scissors (1u, renderArea);
280 const vector<VkViewport> viewports (1u, makeViewport(makeExtent3D(WIDTH, HEIGHT, 1u)));
282 const Move<VkCommandPool> cmdPool = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
283 const Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
285 const Unique<VkDescriptorPool> descriptorPool (DescriptorPoolBuilder()
286 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 6)
287 .addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 12)
288 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 21u));
290 const VkFormat renderedImageFormat = VK_FORMAT_R8G8B8A8_UNORM;
291 tcu::CompressedTexFormat compressedFormat (mapVkCompressedFormat(m_imageFormat));
292 IVec3 blockSize = tcu::getBlockPixelSize(compressedFormat);
294 DE_ASSERT(blockSize.z() == 1);
296 IVec3 storageImageViewSize = imageSize / blockSize;
298 // Create a storage image. The first pipeline fills it and the second pipeline
299 // uses it as a sampling source.
300 const VkImageCreateInfo imageCreateInfo = makeImageCreateInfo(imageSize, m_imageFormat, true, m_cubemap);
301 const VkImageSubresourceRange imageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1, 0, 1);
302 const ImageWithMemory storageImage (vk, device, m_context.getDefaultAllocator(), imageCreateInfo, MemoryRequirement::Any);
304 // Create image views and descriptor sets for the first pipeline
305 Move<VkDescriptorSetLayout> descriptorSetLayout = DescriptorSetLayoutBuilder()
306 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
309 Move<VkImageView> storageImageImageView;
310 VkDescriptorImageInfo storageImageDscrInfo;
311 Move<VkDescriptorSet> storageImageDescriptorSet;
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;
321 DescriptorSetUpdateBuilder updateBuilder;
322 for (int i = 0; i < FACES; i++)
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, m_imageViewFormat, cubeSubresourceRanges[i]));
326 cubeStorageDscrImageInfos.emplace_back(makeDescriptorImageInfo(DE_NULL, *cubeStorageImageViews[i], VK_IMAGE_LAYOUT_GENERAL));
327 cubeStorageDscrSets.emplace_back(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
328 updateBuilder.writeSingle(*cubeStorageDscrSets[i], DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &cubeStorageDscrImageInfos[i]);
330 updateBuilder.update(vk, device);
334 storageImageImageView = makeImageView(vk, device, *storageImage, VK_IMAGE_VIEW_TYPE_2D, m_imageViewFormat, imageSubresourceRange);
335 storageImageDscrInfo = makeDescriptorImageInfo(DE_NULL, *storageImageImageView, VK_IMAGE_LAYOUT_GENERAL);
336 storageImageDescriptorSet = makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout);
338 DescriptorSetUpdateBuilder()
339 .writeSingle(*storageImageDescriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &storageImageDscrInfo)
343 // Create a compute pipeline.
344 Move<VkShaderModule> computeShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0u);
345 const VkPushConstantRange pushConstantRange =
347 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlags stageFlags;
348 0u, // uint32_t offset;
349 (deUint32)sizeof(deUint32), // uint32_t size;
352 const Move<VkPipelineLayout> computePipelineLayout = makePipelineLayout(vk, device, 1, &(*descriptorSetLayout), 1, &pushConstantRange);
353 Move<VkPipeline> computePipeline = makeComputePipeline(vk, device, *computePipelineLayout, *computeShader);
356 // Create a graphics pipeline and all the necessary components for sampling the storage image
358 // The first sampler uses an uncompressed format.
359 const Unique<VkSampler> sampler (makeSampler(vk, device));
361 // The second sampler uses the same format as the image.
362 const Unique<VkSampler> sampler2 (makeSampler(vk, device));
364 // Image views implicitly derive the usage flags from the image. Drop the storage image flag since it's incompatible
365 // with the compressed format and unnecessary in sampling.
366 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
367 VkImageViewUsageCreateInfo imageViewUsageInfo =
369 VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, //VkStructureType sType;
370 DE_NULL, //const void* pNext;
371 usageFlags, //VkImageUsageFlags usage;
374 Move<VkImageView> sampledImageView;
375 Move<VkImageView> sampledImageView2;
376 VkDescriptorImageInfo samplerDscrImageInfo;
377 VkDescriptorImageInfo samplerDscrImageInfo2;
378 Move<VkDescriptorSet> graphicsDescriptorSet;
380 // Cubemap tests use separate image views for each side of a cubemap.
381 vector<Move<VkImageView>> cubeSamplerImageViews;
382 vector<Move<VkImageView>> cubeSampler2ImageViews;
383 vector<VkDescriptorImageInfo> cubeSamplerDscrImageInfos;
384 vector<VkDescriptorImageInfo> cubeSampler2DscrImageInfos;
385 vector<Move<VkDescriptorSet>> cubeSamplerDescriptorSets;
387 const auto graphicsDscrSetLayout (DescriptorSetLayoutBuilder()
388 .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, &sampler2.get())
389 .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, &sampler.get())
394 DescriptorSetUpdateBuilder updateBuilder;
395 for (int i = 0; i < FACES; i++)
397 cubeSamplerImageViews.emplace_back(makeImageView(vk, device, *storageImage, VK_IMAGE_VIEW_TYPE_2D, m_imageFormat, cubeSubresourceRanges[i], &imageViewUsageInfo));
398 cubeSamplerDscrImageInfos.emplace_back(makeDescriptorImageInfo(sampler2.get(), *cubeSamplerImageViews[i], VK_IMAGE_LAYOUT_GENERAL));
399 cubeSamplerDescriptorSets.emplace_back(makeDescriptorSet(vk, device, *descriptorPool, *graphicsDscrSetLayout));
400 updateBuilder.writeSingle(*cubeSamplerDescriptorSets[i], DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &cubeSamplerDscrImageInfos[i]);
405 for (int i = 0; i < FACES; i++)
407 cubeSampler2ImageViews.emplace_back(makeImageView(vk, device, *storageImage, VK_IMAGE_VIEW_TYPE_2D, m_imageViewFormat, cubeSubresourceRanges[i]));
408 cubeSampler2DscrImageInfos.emplace_back(makeDescriptorImageInfo(sampler.get(), *cubeSampler2ImageViews[i], VK_IMAGE_LAYOUT_GENERAL));
409 updateBuilder.writeSingle(*cubeSamplerDescriptorSets[i], DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &cubeSampler2DscrImageInfos[i]);
412 updateBuilder.update(vk, device);
416 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1, 0, 1);
417 DescriptorSetUpdateBuilder updateBuilder;
419 sampledImageView2 = makeImageView(vk, device, *storageImage, VK_IMAGE_VIEW_TYPE_2D, m_imageFormat, subresourceRange, &imageViewUsageInfo);
420 samplerDscrImageInfo2 = makeDescriptorImageInfo(sampler2.get(), *sampledImageView2, VK_IMAGE_LAYOUT_GENERAL);
421 graphicsDescriptorSet = makeDescriptorSet(vk, device, *descriptorPool, *graphicsDscrSetLayout);
425 sampledImageView = makeImageView(vk, device, *storageImage, VK_IMAGE_VIEW_TYPE_2D, m_imageViewFormat, subresourceRange);
426 samplerDscrImageInfo = makeDescriptorImageInfo(sampler.get(), *sampledImageView, VK_IMAGE_LAYOUT_GENERAL);
429 updateBuilder.writeSingle(*graphicsDescriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &samplerDscrImageInfo2);
431 updateBuilder.writeSingle(*graphicsDescriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &samplerDscrImageInfo);
433 updateBuilder.update(vk, device);
436 // Sampled values will be rendered on this image.
437 const VkImageSubresourceRange targetSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1, 0, 1);
438 const VkImageCreateInfo targetImageCreateInfo = makeImageCreateInfo(imageSize, renderedImageFormat, false, false);
440 const ImageWithMemory targetImage (vk, device, m_context.getDefaultAllocator(), targetImageCreateInfo, MemoryRequirement::Any);
441 Move<VkImageView> targetImageView = makeImageView(vk, device, *targetImage, VK_IMAGE_VIEW_TYPE_2D, renderedImageFormat, targetSubresourceRange);
443 // Clear the render target image as black and do a layout transition.
444 clearColorImage(vk, device, m_context.getUniversalQueue(), m_context.getUniversalQueueFamilyIndex(), targetImage.get(),
445 Vec4(0, 0, 0, 0), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
447 const VkPushConstantRange pushConstantRange2 =
449 VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags stageFlags;
450 0u, // uint32_t offset;
451 (deUint32)sizeof(deUint32), // uint32_t size;
454 const Move<VkPipelineLayout> graphicsPipelineLayout = makePipelineLayout(vk, device, 1, &(*graphicsDscrSetLayout), 1, &pushConstantRange2);
456 // Vertices for a full quad and texture coordinates for each vertex.
457 const vector<Vertex> vertices = generateVertices();
458 Move<VkBuffer> vertexBuffer = makeVertexBuffer(vk, device, queueFamilyIndex);
459 de::MovePtr<Allocation> vertexBufferAlloc = bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible);
460 const VkDeviceSize vertexBufferOffset = 0ull;
461 deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], sizeInBytes(vertices));
462 flushAlloc(vk, device, *vertexBufferAlloc);
464 const auto vtxBindingDescription = Vertex::getBindingDescription();
465 const auto vtxAttrDescriptions = Vertex::getAttributeDescriptions();
467 const VkPipelineVertexInputStateCreateInfo vtxInputInfo =
469 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType
470 nullptr, // const void* pNext
471 0u, // VkPipelineVertexInputStateCreateFlags flags
472 1u, // deUint32 vertexBindingDescriptionCount
473 &vtxBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions
474 static_cast<deUint32>(vtxAttrDescriptions.size()), // deUint32 vertexAttributeDescriptionCount
475 vtxAttrDescriptions.data(), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions
478 Move<VkShaderModule> vertexShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
479 Move<VkShaderModule> fragmentShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u);
481 // Create a render pass, a framebuffer, and the second pipeline.
482 Move<VkRenderPass> renderPass = makeRenderPass(vk, device, renderedImageFormat, VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD,
483 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
484 Move<VkFramebuffer> framebuffer = makeFramebuffer(vk, device, *renderPass, targetImageView.get(), renderSize.width, renderSize.height);
485 const Move<VkPipeline> graphicsPipeline = makeGraphicsPipeline(vk, device, graphicsPipelineLayout.get(), vertexShader.get(), DE_NULL,
486 DE_NULL, DE_NULL, fragmentShader.get(), renderPass.get(), viewports, scissors,
487 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u, &vtxInputInfo);
489 // Create a result buffer.
490 const VkBufferCreateInfo resultBufferCreateInfo = makeBufferCreateInfo(BUFFERSIZE, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
491 Move<VkBuffer> resultBuffer = createBuffer(vk, device, &resultBufferCreateInfo);
492 MovePtr<Allocation> resultBufferMemory = allocator.allocate(getBufferMemoryRequirements(vk, device, *resultBuffer), MemoryRequirement::HostVisible);
493 TextureLevel resultImage (mapVkFormat(renderedImageFormat), renderSize.width, renderSize.height, 1);
494 VK_CHECK(vk.bindBufferMemory(device, *resultBuffer, resultBufferMemory->getMemory(), resultBufferMemory->getOffset()));
496 // Generate a reference image.
497 TextureLevel expectedImage = makeReferenceImage(renderedImageFormat, WIDTH, HEIGHT);
499 beginCommandBuffer(vk, *cmdBuffer);
501 // Do a layout transition for the storage image.
502 const VkImageSubresourceRange imageSubresourceRange2 = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1, 0, m_cubemap ? 6 : 1);
503 const auto barrier1 = makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT,
504 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
505 storageImage.get(), imageSubresourceRange2);
506 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, DE_NULL, 0, DE_NULL, 1u, &barrier1);
508 // Bind the vertices and the descriptors used in the graphics pipeline.
509 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
511 // Fill the storage image and sample it twice.
512 for (int pass = 0; pass < 2; pass++)
514 // If both samplers are enabled, it's not necessary to run the compute shader twice since it already writes
515 // the expected values on the first pass. The first sampler uses an uncompressed image format so the result
516 // image will contain garbage if the second sampler doesn't work properly.
517 if (!m_twoSamplers || pass == 0)
519 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline);
520 vk.cmdPushConstants(*cmdBuffer, *computePipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(deInt32), &pass);
522 // If cubemaps are enabled, loop over six times and bind the next face of the cubemap image on each iteration.
525 for (int face = 0; face < FACES; face++)
527 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipelineLayout, 0u, 1u, &(cubeStorageDscrSets[face].get()), 0u, DE_NULL);
528 vk.cmdDispatch(*cmdBuffer, storageImageViewSize.x(), storageImageViewSize.y(), 1u);
533 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipelineLayout, 0u, 1u, &storageImageDescriptorSet.get(), 0u, DE_NULL);
534 vk.cmdDispatch(*cmdBuffer, storageImageViewSize.x(), storageImageViewSize.y(), 1u);
537 const auto barrier2 = makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL,
538 VK_IMAGE_LAYOUT_GENERAL, storageImage.get(), imageSubresourceRange);
539 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, DE_NULL, 0, DE_NULL, 1u, &barrier2);
542 vk.cmdPushConstants(*cmdBuffer, *graphicsPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(deInt32), &pass);
544 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
546 // If cubemaps are enabled, loop over six times and bind the next face of the cubemap image on each iteration.
549 for (int face = 0; face < FACES; face++)
551 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipelineLayout, 0u, 1u, &(cubeSamplerDescriptorSets[face].get()), 0u, DE_NULL);
553 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, imageSize.x(), imageSize.y()),0u, DE_NULL);
554 vk.cmdDraw(*cmdBuffer, 6u, 1u, 0u, 0u);
555 endRenderPass(vk, *cmdBuffer);
559 const auto barrier4 = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
560 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
561 targetImage.get(), targetSubresourceRange);
562 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
563 0, 0, DE_NULL, 0, DE_NULL, 1u, &barrier4);
569 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipelineLayout, 0u, 1u, &(graphicsDescriptorSet.get()), 0u, DE_NULL);
571 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, imageSize.x(), imageSize.y()),0u, DE_NULL);
572 vk.cmdDraw(*cmdBuffer, 6u, 1u, 0u, 0u);
573 endRenderPass(vk, *cmdBuffer);
578 const auto barrier3 = makeImageMemoryBarrier(VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL,
579 VK_IMAGE_LAYOUT_GENERAL, storageImage.get(), imageSubresourceRange);
580 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, DE_NULL, 0, DE_NULL, 1u, &barrier3);
582 const auto barrier4 = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
583 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
584 targetImage.get(), targetSubresourceRange);
585 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, DE_NULL, 0, DE_NULL, 1u, &barrier4);
589 // Copy the sampled values from the target image into the result image.
590 copyImageToBuffer(vk, *cmdBuffer, *targetImage, *resultBuffer, tcu::IVec2(WIDTH, HEIGHT), VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
592 endCommandBuffer(vk, *cmdBuffer);
593 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
595 invalidateAlloc(vk, device, *resultBufferMemory);
597 clear(resultImage.getAccess(), tcu::IVec4(0));
598 copy(resultImage.getAccess(), ConstPixelBufferAccess(resultImage.getFormat(), resultImage.getSize(), resultBufferMemory->getHostPtr()));
604 // The first pass draws pure red on the faces and the second pass redraws them with pure blue.
605 // Sampling anywhere should produce colors with a 0.0 red component and > 0.0 blue and alpha components.
606 for (deUint32 y = 0; y < renderSize.height; y++)
608 for (deUint32 x = 0; x < renderSize.width; x++)
610 const deUint8* ptr = static_cast<const deUint8 *>(resultImage.getAccess().getPixelPtr(x, y, 0));
611 const tcu::IVec4 val = tcu::IVec4(ptr[0], ptr[1], ptr[2], ptr[3]);
612 if (!(val[0] == 0 && val[2] > 0 && val[3] > 0))
617 // Log attachment contents.
618 m_context.getTestContext().getLog() << tcu::TestLog::ImageSet("Attachment ", "")
619 << tcu::TestLog::Image("Rendered image", "Rendered image", resultImage.getAccess())
620 << tcu::TestLog::EndImageSet;
624 // Each test case should render pure blue as the result.
625 result = tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Image Comparison", "",
626 expectedImage.getAccess(), resultImage.getAccess(),
627 tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
631 return tcu::TestStatus::pass("pass");
633 return tcu::TestStatus::fail("fail");
636 class SampleDrawnTextureTest : public TestCase
639 SampleDrawnTextureTest (tcu::TestContext& testCtx,
640 const std::string& name,
641 const std::string& description,
642 const VkFormat imageFormat,
643 const VkFormat imageViewFormat,
644 const bool twoSamplers,
647 void initPrograms (SourceCollections& programCollection) const;
648 TestInstance* createInstance (Context& context) const;
649 virtual void checkSupport (Context& context) const;
652 const VkFormat m_imageFormat;
653 const VkFormat m_imageViewFormat;
654 const bool m_twoSamplers;
655 const bool m_cubemap;
658 SampleDrawnTextureTest::SampleDrawnTextureTest (tcu::TestContext& testCtx,
659 const std::string& name,
660 const std::string& description,
661 const VkFormat imageFormat,
662 const VkFormat imageViewFormat,
663 const bool twoSamplers,
665 : TestCase (testCtx, name, description)
666 , m_imageFormat (imageFormat)
667 , m_imageViewFormat (imageViewFormat)
668 , m_twoSamplers (twoSamplers)
669 , m_cubemap (cubemap)
673 void SampleDrawnTextureTest::checkSupport(Context& context) const
675 const auto& vki = context.getInstanceInterface();
676 const auto usageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT
677 | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
678 auto creationFlags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT
679 | VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT;
681 creationFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
684 // - VkImageViewUsageCreateInfo can be used to override implicit usage flags derived from the image.
685 // - A compressed image can be created with usage flags that are not supported for the format but are
686 // supported by an image view that is using uncompressed format where each texel corresponds to
687 // a compressed texel block of the image.
689 if (!context.isDeviceFunctionalitySupported("VK_KHR_maintenance2"))
690 TCU_THROW(NotSupportedError, "Device does not support extended image usage flags nor overriding implicit usage flags");
692 VkImageFormatProperties imageFormatProperties;
694 if (vki.getPhysicalDeviceImageFormatProperties(context.getPhysicalDevice(), m_imageFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
695 usageFlags, creationFlags, &imageFormatProperties) == VK_ERROR_FORMAT_NOT_SUPPORTED)
697 std::string algorithmName = (m_imageFormat == vk::VK_FORMAT_BC3_UNORM_BLOCK) ? "BC3" : "BC1";
698 std::string errorMsg = algorithmName;
700 errorMsg += m_cubemap ? " compressed cubemap images" : " compressed images";
701 errorMsg += " created with VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, VK_IMAGE_CREATE_EXTENDED_USAGE_BIT";
702 errorMsg += " and VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT flags not supported.";
703 TCU_THROW(NotSupportedError, errorMsg);
707 void SampleDrawnTextureTest::initPrograms (SourceCollections& programCollection) const
709 // Pure red, green, and blue compressed with the BC1 and BC3 algorithms.
710 std::string bc1_red = "uvec4(4160813056u, 0u, 4160813056u, 0u);\n";
711 std::string bc1_blue = "uvec4(2031647, 0u, 2031647, 0u);\n";
712 std::string bc3_red = "uvec4(4294967295u, 4294967295u, 4160813056u, 0u);\n";
713 std::string bc3_blue = "uvec4(4294967295u, 4294967295u, 2031647, 0u);\n";
715 std::string red = (m_imageFormat == VK_FORMAT_BC1_RGB_UNORM_BLOCK) ? bc1_red : bc3_red;
716 std::string blue = (m_imageFormat == VK_FORMAT_BC1_RGB_UNORM_BLOCK) ? bc1_blue : bc3_blue;
718 std::ostringstream computeSrc;
720 // Generate the compute shader.
721 computeSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n";
722 computeSrc << "layout(set = 0, binding = 0, rgba32ui) uniform highp uimage2D img;\n";
723 computeSrc << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n";
728 << "layout(push_constant) uniform constants {\n"
733 computeSrc << "void main() {\n";
736 computeSrc << " uvec4 color = " << blue;
739 computeSrc << " uvec4 color = " << red;
740 computeSrc << " if (pc.pass == 1)\n";
741 computeSrc << " color = " << blue;
745 << " imageStore(img, ivec2(gl_GlobalInvocationID.xy), color);\n"
748 // Generate the vertex shader.
749 std::ostringstream vertexSrc;
751 << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
752 << "layout(location = 0) in highp vec4 a_position;\n"
753 << "layout(location = 1) in vec2 inTexCoord;\n"
754 << "layout(location = 1) out vec2 fragTexCoord;\n"
755 << "void main (void) {\n"
756 << " gl_Position = a_position;\n"
757 << " fragTexCoord = inTexCoord;\n"
760 // Generate the fragment shader.
761 std::ostringstream fragmentSrc;
763 << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
764 << "layout(location = 0) out vec4 outColor;\n"
765 << "layout(location = 1) in vec2 fragTexCoord;\n";
767 fragmentSrc << "layout(binding = 0) uniform sampler2D compTexSampler;\n";
772 << "layout(binding = 1) uniform usampler2D texSampler;\n"
773 << "layout(push_constant) uniform constants {\n"
777 << " if (pc.pass == 1)\n"
778 << " outColor = texture(compTexSampler, fragTexCoord);\n"
780 << " outColor = texture(texSampler, fragTexCoord);\n";
786 << " outColor = texture(compTexSampler, fragTexCoord);\n";
789 fragmentSrc << "}\n";
791 programCollection.glslSources.add("comp") << glu::ComputeSource(computeSrc.str());
792 programCollection.glslSources.add("vert") << glu::VertexSource(vertexSrc.str());
793 programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSrc.str());
796 TestInstance* SampleDrawnTextureTest::createInstance (Context& context) const
798 return new SampleDrawnTextureTestInstance(context, m_imageFormat, m_imageViewFormat, m_twoSamplers, m_cubemap);
803 tcu::TestCaseGroup* createImageSampleDrawnTextureTests (tcu::TestContext& testCtx)
805 /* If both samplers are enabled, the test works as follows:
808 * - Compute shader fills a storage image with values that are pure blue compressed with
809 * either the BC1 or BC3 algorithm.
810 * - Fragment shader samples the image and draws the values on a target image.
811 * - As the sampled values are accessed through an image view using an uncompressed
812 * format, they remain compressed and the drawn image ends up being garbage.
814 * - Fragment shader samples the image. On this pass, the image view uses
815 * a block-compressed format and correctly interprets the sampled values.
816 * - As the values are uncompressed now, the target image is filled
817 * with pure blue and the test passes.
819 * Only one sampler enabled:
821 * - Compute shader fills a storage image with values that are pure red compressed
822 * with either the BC1 or BC3 algorithm.
823 * - Fragment shader samples the image through an image view which interprets the values
824 * correctly. The values are drawn on a target image. The test doesn't pass yet
825 * since the image is red.
827 * - Compute shader fills the storage image with values that are pure blue compressed
828 * with the same algorithm as on the previous pass.
829 * - Fragment shader samples the image through an image view which interprets the values
830 * correctly. The values are drawn on the target image and the test passes.
832 * If cubemaps are enabled:
834 * - If both samplers are enabled, draw compressed pure blue on the faces. Otherwise pure red.
835 * - Sample the image through an image view with or without compressed format as in the cases
838 * - If only one sampler is enabled, redraw the faces with pure blue
839 * - Sample the image. Sampling should produce colors with a 0.0 red component and with > 0.0
840 * blue and alpha components.
843 const bool twoSamplers = true;
844 const bool cubemap = true;
846 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "sample_texture", "Sample texture that has been rendered to tests"));
848 testGroup->addChild(new SampleDrawnTextureTest(testCtx, "128_bit_compressed_format_cubemap", "", VK_FORMAT_BC3_UNORM_BLOCK, VK_FORMAT_R32G32B32A32_UINT, !twoSamplers, cubemap));
849 testGroup->addChild(new SampleDrawnTextureTest(testCtx, "64_bit_compressed_format_cubemap", "", VK_FORMAT_BC1_RGB_UNORM_BLOCK, VK_FORMAT_R32G32_UINT, !twoSamplers, cubemap));
850 testGroup->addChild(new SampleDrawnTextureTest(testCtx, "64_bit_compressed_format_two_samplers_cubemap", "", VK_FORMAT_BC1_RGB_UNORM_BLOCK, VK_FORMAT_R32G32_UINT, twoSamplers, cubemap));
851 testGroup->addChild(new SampleDrawnTextureTest(testCtx, "128_bit_compressed_format_two_samplers_cubemap", "", VK_FORMAT_BC3_UNORM_BLOCK, VK_FORMAT_R32G32B32A32_UINT, twoSamplers, cubemap));
853 testGroup->addChild(new SampleDrawnTextureTest(testCtx, "64_bit_compressed_format", "", VK_FORMAT_BC1_RGB_UNORM_BLOCK, VK_FORMAT_R32G32_UINT, !twoSamplers, false));
854 testGroup->addChild(new SampleDrawnTextureTest(testCtx, "64_bit_compressed_format_two_samplers", "", VK_FORMAT_BC1_RGB_UNORM_BLOCK, VK_FORMAT_R32G32_UINT, twoSamplers, false));
855 testGroup->addChild(new SampleDrawnTextureTest(testCtx, "128_bit_compressed_format", "", VK_FORMAT_BC3_UNORM_BLOCK, VK_FORMAT_R32G32B32A32_UINT, !twoSamplers, false));
856 testGroup->addChild(new SampleDrawnTextureTest(testCtx, "128_bit_compressed_format_two_samplers", "", VK_FORMAT_BC3_UNORM_BLOCK, VK_FORMAT_R32G32B32A32_UINT, twoSamplers, false));
858 return testGroup.release();