1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2015 Mobica Ltd.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and/or associated documentation files (the
9 * "Materials"), to deal in the Materials without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Materials, and to
12 * permit persons to whom the Materials are furnished to do so, subject to
13 * the following conditions:
15 * The above copyright notice(s) and this permission notice shall be included
16 * in all copies or substantial portions of the Materials.
18 * The Materials are Confidential Information as defined by the
19 * Khronos Membership Agreement until designated non-confidential by Khronos,
20 * at which point this condition clause shall be removed.
22 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
26 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
32 * \brief Image size Tests
33 *//*--------------------------------------------------------------------*/
35 #include "vktImageSizeTests.hpp"
36 #include "vktTestCaseUtil.hpp"
37 #include "vktImageTestsUtil.hpp"
38 #include "vktImageTexture.hpp"
42 #include "vkRefUtil.hpp"
43 #include "vkPlatform.hpp"
44 #include "vkPrograms.hpp"
45 #include "vkMemUtil.hpp"
46 #include "vkBuilderUtil.hpp"
47 #include "vkImageUtil.hpp"
49 #include "deUniquePtr.hpp"
50 #include "deStringUtil.hpp"
63 //! Get a texture based on image type and suggested size.
64 Texture getTexture (const ImageType imageType, const tcu::IVec3& size)
69 case IMAGE_TYPE_BUFFER:
70 return Texture(imageType, tcu::IVec3(size.x(), 1, 1), 1);
72 case IMAGE_TYPE_1D_ARRAY:
73 return Texture(imageType, tcu::IVec3(size.x(), 1, 1), size.y());
76 return Texture(imageType, tcu::IVec3(size.x(), size.y(), 1), 1);
78 case IMAGE_TYPE_2D_ARRAY:
79 return Texture(imageType, tcu::IVec3(size.x(), size.y(), 1), size.z());
82 return Texture(imageType, tcu::IVec3(size.x(), size.x(), 1), 6);
84 case IMAGE_TYPE_CUBE_ARRAY:
85 return Texture(imageType, tcu::IVec3(size.x(), size.x(), 1), 2*6);
88 return Texture(imageType, size, 1);
91 DE_FATAL("Internal error");
92 return Texture(IMAGE_TYPE_LAST, tcu::IVec3(), 0);
96 inline VkImageCreateInfo makeImageCreateInfo (const Texture& texture, const VkFormat format)
98 const VkImageCreateInfo imageParams =
100 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
101 DE_NULL, // const void* pNext;
102 (isCube(texture) ? (VkImageCreateFlags)VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0u), // VkImageCreateFlags flags;
103 mapImageType(texture.type()), // VkImageType imageType;
104 format, // VkFormat format;
105 makeExtent3D(texture.layerSize()), // VkExtent3D extent;
106 1u, // deUint32 mipLevels;
107 (deUint32)texture.numLayers(), // deUint32 arrayLayers;
108 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
109 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
110 VK_IMAGE_USAGE_STORAGE_BIT, // VkImageUsageFlags usage;
111 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
112 0u, // deUint32 queueFamilyIndexCount;
113 DE_NULL, // const deUint32* pQueueFamilyIndices;
114 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
119 //! Interpret the memory as IVec3
120 inline tcu::IVec3 readIVec3 (const void* const data)
122 const int* const p = reinterpret_cast<const int* const>(data);
123 return tcu::IVec3(p[0], p[1], p[2]);
126 tcu::IVec3 getExpectedImageSizeResult (const Texture& texture)
128 // GLSL imageSize() function returns:
130 // z = N for cube arrays, where N is the number of cubes
131 // y or z = L where L is the number of layers for other array types (e.g. 1D array, 2D array)
132 // z = D where D is the depth of 3d image
134 const tcu::IVec3 size = texture.size();
135 const int numCubeFaces = 6;
137 switch (texture.type())
140 case IMAGE_TYPE_BUFFER:
141 return tcu::IVec3(size.x(), 0, 0);
143 case IMAGE_TYPE_1D_ARRAY:
145 case IMAGE_TYPE_CUBE:
146 return tcu::IVec3(size.x(), size.y(), 0);
148 case IMAGE_TYPE_2D_ARRAY:
152 case IMAGE_TYPE_CUBE_ARRAY:
153 return tcu::IVec3(size.x(), size.y(), size.z() / numCubeFaces);
156 DE_FATAL("Internal error");
161 class SizeTest : public TestCase
166 FLAG_READONLY_IMAGE = 1u << 0,
167 FLAG_WRITEONLY_IMAGE = 1u << 1,
170 SizeTest (tcu::TestContext& testCtx,
171 const std::string& name,
172 const std::string& description,
173 const Texture& texture,
174 const VkFormat format,
175 const deUint32 flags = 0);
177 void initPrograms (SourceCollections& programCollection) const;
178 TestInstance* createInstance (Context& context) const;
181 const Texture m_texture;
182 const VkFormat m_format;
183 const bool m_useReadonly;
184 const bool m_useWriteonly;
187 SizeTest::SizeTest (tcu::TestContext& testCtx,
188 const std::string& name,
189 const std::string& description,
190 const Texture& texture,
191 const VkFormat format,
192 const deUint32 flags)
193 : TestCase (testCtx, name, description)
194 , m_texture (texture)
196 , m_useReadonly ((flags & FLAG_READONLY_IMAGE) != 0)
197 , m_useWriteonly ((flags & FLAG_WRITEONLY_IMAGE) != 0)
199 // We expect at least one flag to be set.
200 DE_ASSERT(m_useReadonly || m_useWriteonly);
203 void SizeTest::initPrograms (SourceCollections& programCollection) const
205 const std::string formatQualifierStr = getShaderImageFormatQualifier(mapVkFormat(m_format));
206 const std::string imageTypeStr = getShaderImageType(mapVkFormat(m_format), m_texture.type());
207 const int dimension = m_texture.dimension();
209 std::ostringstream accessQualifier;
211 accessQualifier << " readonly";
213 accessQualifier << " writeonly";
215 std::ostringstream src;
216 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
218 << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
219 << "layout (binding = 0, " << formatQualifierStr << ")" << accessQualifier.str() << " uniform highp " << imageTypeStr << " u_image;\n"
220 << "layout (binding = 1) writeonly buffer Output {\n"
224 << "void main (void)\n"
227 " sb_out.size = ivec3(imageSize(u_image), 0, 0);\n"
228 : dimension == 2 || m_texture.type() == IMAGE_TYPE_CUBE ? // cubes return ivec2
229 " sb_out.size = ivec3(imageSize(u_image), 0);\n"
230 : dimension == 3 ? // cube arrays return ivec3
231 " sb_out.size = imageSize(u_image);\n"
235 programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
238 //! Build a case name, e.g. "readonly_writeonly_32x32"
239 std::string getCaseName (const Texture& texture, const deUint32 flags)
241 std::ostringstream str;
242 str << ((flags & SizeTest::FLAG_READONLY_IMAGE) != 0 ? "readonly_" : "")
243 << ((flags & SizeTest::FLAG_WRITEONLY_IMAGE) != 0 ? "writeonly_" : "");
245 const int numComponents = texture.dimension();
246 for (int i = 0; i < numComponents; ++i)
247 str << (i == 0 ? "" : "x") << texture.size()[i];
252 //! Base test instance for image and buffer tests
253 class SizeTestInstance : public TestInstance
256 SizeTestInstance (Context& context,
257 const Texture& texture,
258 const VkFormat format);
260 tcu::TestStatus iterate (void);
262 virtual ~SizeTestInstance (void) {}
265 virtual VkDescriptorSetLayout prepareDescriptors (void) = 0;
266 virtual VkDescriptorSet getDescriptorSet (void) const = 0;
267 virtual void commandBeforeCompute (const VkCommandBuffer cmdBuffer) = 0;
269 const Texture m_texture;
270 const VkFormat m_format;
271 const VkDeviceSize m_resultBufferSizeBytes;
272 de::MovePtr<Buffer> m_resultBuffer; //!< Shader writes the output here.
275 SizeTestInstance::SizeTestInstance (Context& context, const Texture& texture, const VkFormat format)
276 : TestInstance (context)
277 , m_texture (texture)
279 , m_resultBufferSizeBytes (3 * sizeof(deUint32)) // ivec3 in shader
281 const DeviceInterface& vk = m_context.getDeviceInterface();
282 const VkDevice device = m_context.getDevice();
283 Allocator& allocator = m_context.getDefaultAllocator();
285 // Create an SSBO for shader output.
287 m_resultBuffer = de::MovePtr<Buffer>(new Buffer(
288 vk, device, allocator,
289 makeBufferCreateInfo(m_resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),
290 MemoryRequirement::HostVisible));
293 tcu::TestStatus SizeTestInstance::iterate (void)
295 const DeviceInterface& vk = m_context.getDeviceInterface();
296 const VkDevice device = m_context.getDevice();
297 const VkQueue queue = m_context.getUniversalQueue();
298 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
300 // Create memory barriers.
302 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
303 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
304 m_resultBuffer->get(), 0ull, m_resultBufferSizeBytes);
306 // Create the pipeline.
308 const Unique<VkShaderModule> shaderModule(createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0));
310 const VkDescriptorSetLayout descriptorSetLayout = prepareDescriptors();
311 const VkDescriptorSet descriptorSet = getDescriptorSet();
313 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, descriptorSetLayout));
314 const Unique<VkPipeline> pipeline(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
316 const Unique<VkCommandPool> cmdPool(makeCommandPool(vk, device, queueFamilyIndex));
317 const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
319 beginCommandBuffer(vk, *cmdBuffer);
321 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
322 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL);
324 commandBeforeCompute(*cmdBuffer);
325 vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
326 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &shaderWriteBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
328 endCommandBuffer(vk, *cmdBuffer);
330 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
332 // Compare the result.
334 const Allocation& bufferAlloc = m_resultBuffer->getAllocation();
335 invalidateMappedMemoryRange(vk, device, bufferAlloc.getMemory(), bufferAlloc.getOffset(), m_resultBufferSizeBytes);
337 const tcu::IVec3 resultSize = readIVec3(bufferAlloc.getHostPtr());
338 const tcu::IVec3 expectedSize = getExpectedImageSizeResult(m_texture);
340 if (resultSize != expectedSize)
341 return tcu::TestStatus::fail("Incorrect imageSize(): expected " + de::toString(expectedSize) + " but got " + de::toString(resultSize));
343 return tcu::TestStatus::pass("Passed");
346 class ImageSizeTestInstance : public SizeTestInstance
349 ImageSizeTestInstance (Context& context,
350 const Texture& texture,
351 const VkFormat format);
354 VkDescriptorSetLayout prepareDescriptors (void);
355 void commandBeforeCompute (const VkCommandBuffer cmdBuffer);
357 VkDescriptorSet getDescriptorSet (void) const { return *m_descriptorSet; }
359 de::MovePtr<Image> m_image;
360 Move<VkImageView> m_imageView;
361 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
362 Move<VkDescriptorPool> m_descriptorPool;
363 Move<VkDescriptorSet> m_descriptorSet;
366 ImageSizeTestInstance::ImageSizeTestInstance (Context& context, const Texture& texture, const VkFormat format)
367 : SizeTestInstance (context, texture, format)
369 const DeviceInterface& vk = m_context.getDeviceInterface();
370 const VkDevice device = m_context.getDevice();
371 Allocator& allocator = m_context.getDefaultAllocator();
373 // Create an image. Its data be uninitialized, as we're not reading from it.
375 m_image = de::MovePtr<Image>(new Image(vk, device, allocator, makeImageCreateInfo(m_texture, m_format), MemoryRequirement::Any));
377 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_texture.numLayers());
378 m_imageView = makeImageView(vk, device, m_image->get(), mapImageViewType(m_texture.type()), m_format, subresourceRange);
381 VkDescriptorSetLayout ImageSizeTestInstance::prepareDescriptors (void)
383 const DeviceInterface& vk = m_context.getDeviceInterface();
384 const VkDevice device = m_context.getDevice();
386 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
387 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
388 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
391 m_descriptorPool = DescriptorPoolBuilder()
392 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
393 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
394 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
396 m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
398 const VkDescriptorImageInfo descriptorImageInfo = makeDescriptorImageInfo(DE_NULL, *m_imageView, VK_IMAGE_LAYOUT_GENERAL);
399 const VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(m_resultBuffer->get(), 0ull, m_resultBufferSizeBytes);
401 DescriptorSetUpdateBuilder()
402 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
403 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
406 return *m_descriptorSetLayout;
409 void ImageSizeTestInstance::commandBeforeCompute (const VkCommandBuffer cmdBuffer)
411 const DeviceInterface& vk = m_context.getDeviceInterface();
413 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_texture.numLayers());
414 const VkImageMemoryBarrier barrierSetImageLayout = makeImageMemoryBarrier(
416 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
417 m_image->get(), subresourceRange);
419 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &barrierSetImageLayout);
422 class BufferSizeTestInstance : public SizeTestInstance
425 BufferSizeTestInstance (Context& context,
426 const Texture& texture,
427 const VkFormat format);
430 VkDescriptorSetLayout prepareDescriptors (void);
432 void commandBeforeCompute (const VkCommandBuffer) {}
433 VkDescriptorSet getDescriptorSet (void) const { return *m_descriptorSet; }
435 de::MovePtr<Buffer> m_imageBuffer;
436 Move<VkBufferView> m_bufferView;
437 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
438 Move<VkDescriptorPool> m_descriptorPool;
439 Move<VkDescriptorSet> m_descriptorSet;
442 BufferSizeTestInstance::BufferSizeTestInstance (Context& context, const Texture& texture, const VkFormat format)
443 : SizeTestInstance (context, texture, format)
445 const DeviceInterface& vk = m_context.getDeviceInterface();
446 const VkDevice device = m_context.getDevice();
447 Allocator& allocator = m_context.getDefaultAllocator();
449 // Create a texel storage buffer. Its data be uninitialized, as we're not reading from it.
451 const VkDeviceSize imageSizeBytes = getImageSizeBytes(m_texture.size(), m_format);
452 m_imageBuffer = de::MovePtr<Buffer>(new Buffer(vk, device, allocator,
453 makeBufferCreateInfo(imageSizeBytes, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT), MemoryRequirement::Any));
455 m_bufferView = makeBufferView(vk, device, m_imageBuffer->get(), m_format, 0ull, imageSizeBytes);
458 VkDescriptorSetLayout BufferSizeTestInstance::prepareDescriptors (void)
460 const DeviceInterface& vk = m_context.getDeviceInterface();
461 const VkDevice device = m_context.getDevice();
463 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
464 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
465 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
468 m_descriptorPool = DescriptorPoolBuilder()
469 .addType(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
470 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
471 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
473 m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
475 const VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(m_resultBuffer->get(), 0ull, m_resultBufferSizeBytes);
477 DescriptorSetUpdateBuilder()
478 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, &m_bufferView.get())
479 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
482 return *m_descriptorSetLayout;
485 TestInstance* SizeTest::createInstance (Context& context) const
487 if (m_texture.type() == IMAGE_TYPE_BUFFER)
488 return new BufferSizeTestInstance(context, m_texture, m_format);
490 return new ImageSizeTestInstance(context, m_texture, m_format);
493 static const ImageType s_imageTypes[] =
501 IMAGE_TYPE_CUBE_ARRAY,
505 //! Base sizes used to generate actual image/buffer sizes in the test.
506 static const tcu::IVec3 s_baseImageSizes[] =
508 tcu::IVec3(32, 32, 32),
509 tcu::IVec3(12, 34, 56),
514 static const deUint32 s_flags[] =
516 SizeTest::FLAG_READONLY_IMAGE,
517 SizeTest::FLAG_WRITEONLY_IMAGE,
518 SizeTest::FLAG_READONLY_IMAGE | SizeTest::FLAG_WRITEONLY_IMAGE,
523 tcu::TestCaseGroup* createImageSizeTests (tcu::TestContext& testCtx)
525 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "image_size", "imageSize() cases"));
527 const VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT;
529 for (int imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(s_imageTypes); ++imageTypeNdx)
531 de::MovePtr<tcu::TestCaseGroup> imageGroup(new tcu::TestCaseGroup(testCtx, getImageTypeName(s_imageTypes[imageTypeNdx]).c_str(), ""));
533 for (int flagNdx = 0; flagNdx < DE_LENGTH_OF_ARRAY(s_flags); ++flagNdx)
534 for (int imageSizeNdx = 0; imageSizeNdx < DE_LENGTH_OF_ARRAY(s_baseImageSizes); ++imageSizeNdx)
536 const Texture texture = getTexture(s_imageTypes[imageTypeNdx], s_baseImageSizes[imageSizeNdx]);
537 imageGroup->addChild(new SizeTest(testCtx, getCaseName(texture, s_flags[flagNdx]), "", texture, format, s_flags[flagNdx]));
540 testGroup->addChild(imageGroup.release());
542 return testGroup.release();