1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2016 The Khronos Group Inc.
6 * Copyright (c) 2016 The Android Open Source Project
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 Image size Tests
23 *//*--------------------------------------------------------------------*/
25 #include "vktImageSizeTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktImageTestsUtil.hpp"
28 #include "vktImageTexture.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vkPlatform.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkImageUtil.hpp"
39 #include "deUniquePtr.hpp"
40 #include "deStringUtil.hpp"
53 //! Get a texture based on image type and suggested size.
54 Texture getTexture (const ImageType imageType, const tcu::IVec3& size)
59 case IMAGE_TYPE_BUFFER:
60 return Texture(imageType, tcu::IVec3(size.x(), 1, 1), 1);
62 case IMAGE_TYPE_1D_ARRAY:
63 return Texture(imageType, tcu::IVec3(size.x(), 1, 1), size.y());
66 return Texture(imageType, tcu::IVec3(size.x(), size.y(), 1), 1);
68 case IMAGE_TYPE_2D_ARRAY:
69 return Texture(imageType, tcu::IVec3(size.x(), size.y(), 1), size.z());
72 return Texture(imageType, tcu::IVec3(size.x(), size.x(), 1), 6);
74 case IMAGE_TYPE_CUBE_ARRAY:
75 return Texture(imageType, tcu::IVec3(size.x(), size.x(), 1), 2*6);
78 return Texture(imageType, size, 1);
81 DE_FATAL("Internal error");
82 return Texture(IMAGE_TYPE_LAST, tcu::IVec3(), 0);
86 inline VkImageCreateInfo makeImageCreateInfo (const Texture& texture, const VkFormat format)
88 const VkImageCreateInfo imageParams =
90 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
91 DE_NULL, // const void* pNext;
92 (isCube(texture) ? (VkImageCreateFlags)VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0u), // VkImageCreateFlags flags;
93 mapImageType(texture.type()), // VkImageType imageType;
94 format, // VkFormat format;
95 makeExtent3D(texture.layerSize()), // VkExtent3D extent;
96 1u, // deUint32 mipLevels;
97 (deUint32)texture.numLayers(), // deUint32 arrayLayers;
98 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
99 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
100 VK_IMAGE_USAGE_STORAGE_BIT, // VkImageUsageFlags usage;
101 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
102 0u, // deUint32 queueFamilyIndexCount;
103 DE_NULL, // const deUint32* pQueueFamilyIndices;
104 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
109 //! Interpret the memory as IVec3
110 inline tcu::IVec3 readIVec3 (const void* const data)
112 const int* const p = reinterpret_cast<const int* const>(data);
113 return tcu::IVec3(p[0], p[1], p[2]);
116 tcu::IVec3 getExpectedImageSizeResult (const Texture& texture)
118 // GLSL imageSize() function returns:
120 // z = N for cube arrays, where N is the number of cubes
121 // y or z = L where L is the number of layers for other array types (e.g. 1D array, 2D array)
122 // z = D where D is the depth of 3d image
124 const tcu::IVec3 size = texture.size();
125 const int numCubeFaces = 6;
127 switch (texture.type())
130 case IMAGE_TYPE_BUFFER:
131 return tcu::IVec3(size.x(), 0, 0);
133 case IMAGE_TYPE_1D_ARRAY:
135 case IMAGE_TYPE_CUBE:
136 return tcu::IVec3(size.x(), size.y(), 0);
138 case IMAGE_TYPE_2D_ARRAY:
142 case IMAGE_TYPE_CUBE_ARRAY:
143 return tcu::IVec3(size.x(), size.y(), size.z() / numCubeFaces);
146 DE_FATAL("Internal error");
151 class SizeTest : public TestCase
156 FLAG_READONLY_IMAGE = 1u << 0,
157 FLAG_WRITEONLY_IMAGE = 1u << 1,
160 SizeTest (tcu::TestContext& testCtx,
161 const std::string& name,
162 const std::string& description,
163 const Texture& texture,
164 const VkFormat format,
165 const deUint32 flags = 0);
167 void initPrograms (SourceCollections& programCollection) const;
168 TestInstance* createInstance (Context& context) const;
171 const Texture m_texture;
172 const VkFormat m_format;
173 const bool m_useReadonly;
174 const bool m_useWriteonly;
177 SizeTest::SizeTest (tcu::TestContext& testCtx,
178 const std::string& name,
179 const std::string& description,
180 const Texture& texture,
181 const VkFormat format,
182 const deUint32 flags)
183 : TestCase (testCtx, name, description)
184 , m_texture (texture)
186 , m_useReadonly ((flags & FLAG_READONLY_IMAGE) != 0)
187 , m_useWriteonly ((flags & FLAG_WRITEONLY_IMAGE) != 0)
189 // We expect at least one flag to be set.
190 DE_ASSERT(m_useReadonly || m_useWriteonly);
193 void SizeTest::initPrograms (SourceCollections& programCollection) const
195 const std::string formatQualifierStr = getShaderImageFormatQualifier(mapVkFormat(m_format));
196 const std::string imageTypeStr = getShaderImageType(mapVkFormat(m_format), m_texture.type());
197 const int dimension = m_texture.dimension();
199 std::ostringstream accessQualifier;
201 accessQualifier << " readonly";
203 accessQualifier << " writeonly";
205 std::ostringstream src;
206 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
208 << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
209 << "layout (binding = 0, " << formatQualifierStr << ")" << accessQualifier.str() << " uniform highp " << imageTypeStr << " u_image;\n"
210 << "layout (binding = 1) writeonly buffer Output {\n"
214 << "void main (void)\n"
217 " sb_out.size = ivec3(imageSize(u_image), 0, 0);\n"
218 : dimension == 2 || m_texture.type() == IMAGE_TYPE_CUBE ? // cubes return ivec2
219 " sb_out.size = ivec3(imageSize(u_image), 0);\n"
220 : dimension == 3 ? // cube arrays return ivec3
221 " sb_out.size = imageSize(u_image);\n"
225 programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
228 //! Build a case name, e.g. "readonly_writeonly_32x32"
229 std::string getCaseName (const Texture& texture, const deUint32 flags)
231 std::ostringstream str;
232 str << ((flags & SizeTest::FLAG_READONLY_IMAGE) != 0 ? "readonly_" : "")
233 << ((flags & SizeTest::FLAG_WRITEONLY_IMAGE) != 0 ? "writeonly_" : "");
235 const int numComponents = texture.dimension();
236 for (int i = 0; i < numComponents; ++i)
237 str << (i == 0 ? "" : "x") << texture.size()[i];
242 //! Base test instance for image and buffer tests
243 class SizeTestInstance : public TestInstance
246 SizeTestInstance (Context& context,
247 const Texture& texture,
248 const VkFormat format);
250 tcu::TestStatus iterate (void);
252 virtual ~SizeTestInstance (void) {}
255 virtual VkDescriptorSetLayout prepareDescriptors (void) = 0;
256 virtual VkDescriptorSet getDescriptorSet (void) const = 0;
257 virtual void commandBeforeCompute (const VkCommandBuffer cmdBuffer) = 0;
259 const Texture m_texture;
260 const VkFormat m_format;
261 const VkDeviceSize m_resultBufferSizeBytes;
262 de::MovePtr<Buffer> m_resultBuffer; //!< Shader writes the output here.
265 SizeTestInstance::SizeTestInstance (Context& context, const Texture& texture, const VkFormat format)
266 : TestInstance (context)
267 , m_texture (texture)
269 , m_resultBufferSizeBytes (3 * sizeof(deUint32)) // ivec3 in shader
271 const DeviceInterface& vk = m_context.getDeviceInterface();
272 const VkDevice device = m_context.getDevice();
273 Allocator& allocator = m_context.getDefaultAllocator();
275 // Create an SSBO for shader output.
277 m_resultBuffer = de::MovePtr<Buffer>(new Buffer(
278 vk, device, allocator,
279 makeBufferCreateInfo(m_resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),
280 MemoryRequirement::HostVisible));
283 tcu::TestStatus SizeTestInstance::iterate (void)
285 const DeviceInterface& vk = m_context.getDeviceInterface();
286 const VkDevice device = m_context.getDevice();
287 const VkQueue queue = m_context.getUniversalQueue();
288 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
290 // Create memory barriers.
292 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
293 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
294 m_resultBuffer->get(), 0ull, m_resultBufferSizeBytes);
296 // Create the pipeline.
298 const Unique<VkShaderModule> shaderModule(createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0));
300 const VkDescriptorSetLayout descriptorSetLayout = prepareDescriptors();
301 const VkDescriptorSet descriptorSet = getDescriptorSet();
303 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, descriptorSetLayout));
304 const Unique<VkPipeline> pipeline(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
306 const Unique<VkCommandPool> cmdPool(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
307 const Unique<VkCommandBuffer> cmdBuffer(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
309 beginCommandBuffer(vk, *cmdBuffer);
311 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
312 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL);
314 commandBeforeCompute(*cmdBuffer);
315 vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
316 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);
318 endCommandBuffer(vk, *cmdBuffer);
320 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
322 // Compare the result.
324 const Allocation& bufferAlloc = m_resultBuffer->getAllocation();
325 invalidateMappedMemoryRange(vk, device, bufferAlloc.getMemory(), bufferAlloc.getOffset(), m_resultBufferSizeBytes);
327 const tcu::IVec3 resultSize = readIVec3(bufferAlloc.getHostPtr());
328 const tcu::IVec3 expectedSize = getExpectedImageSizeResult(m_texture);
330 if (resultSize != expectedSize)
331 return tcu::TestStatus::fail("Incorrect imageSize(): expected " + de::toString(expectedSize) + " but got " + de::toString(resultSize));
333 return tcu::TestStatus::pass("Passed");
336 class ImageSizeTestInstance : public SizeTestInstance
339 ImageSizeTestInstance (Context& context,
340 const Texture& texture,
341 const VkFormat format);
344 VkDescriptorSetLayout prepareDescriptors (void);
345 void commandBeforeCompute (const VkCommandBuffer cmdBuffer);
347 VkDescriptorSet getDescriptorSet (void) const { return *m_descriptorSet; }
349 de::MovePtr<Image> m_image;
350 Move<VkImageView> m_imageView;
351 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
352 Move<VkDescriptorPool> m_descriptorPool;
353 Move<VkDescriptorSet> m_descriptorSet;
356 ImageSizeTestInstance::ImageSizeTestInstance (Context& context, const Texture& texture, const VkFormat format)
357 : SizeTestInstance (context, texture, format)
359 const DeviceInterface& vk = m_context.getDeviceInterface();
360 const VkDevice device = m_context.getDevice();
361 Allocator& allocator = m_context.getDefaultAllocator();
363 // Create an image. Its data be uninitialized, as we're not reading from it.
365 m_image = de::MovePtr<Image>(new Image(vk, device, allocator, makeImageCreateInfo(m_texture, m_format), MemoryRequirement::Any));
367 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_texture.numLayers());
368 m_imageView = makeImageView(vk, device, m_image->get(), mapImageViewType(m_texture.type()), m_format, subresourceRange);
371 VkDescriptorSetLayout ImageSizeTestInstance::prepareDescriptors (void)
373 const DeviceInterface& vk = m_context.getDeviceInterface();
374 const VkDevice device = m_context.getDevice();
376 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
377 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
378 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
381 m_descriptorPool = DescriptorPoolBuilder()
382 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
383 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
384 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
386 m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
388 const VkDescriptorImageInfo descriptorImageInfo = makeDescriptorImageInfo(DE_NULL, *m_imageView, VK_IMAGE_LAYOUT_GENERAL);
389 const VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(m_resultBuffer->get(), 0ull, m_resultBufferSizeBytes);
391 DescriptorSetUpdateBuilder()
392 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
393 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
396 return *m_descriptorSetLayout;
399 void ImageSizeTestInstance::commandBeforeCompute (const VkCommandBuffer cmdBuffer)
401 const DeviceInterface& vk = m_context.getDeviceInterface();
403 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_texture.numLayers());
404 const VkImageMemoryBarrier barrierSetImageLayout = makeImageMemoryBarrier(
406 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
407 m_image->get(), subresourceRange);
409 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);
412 class BufferSizeTestInstance : public SizeTestInstance
415 BufferSizeTestInstance (Context& context,
416 const Texture& texture,
417 const VkFormat format);
420 VkDescriptorSetLayout prepareDescriptors (void);
422 void commandBeforeCompute (const VkCommandBuffer) {}
423 VkDescriptorSet getDescriptorSet (void) const { return *m_descriptorSet; }
425 de::MovePtr<Buffer> m_imageBuffer;
426 Move<VkBufferView> m_bufferView;
427 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
428 Move<VkDescriptorPool> m_descriptorPool;
429 Move<VkDescriptorSet> m_descriptorSet;
432 BufferSizeTestInstance::BufferSizeTestInstance (Context& context, const Texture& texture, const VkFormat format)
433 : SizeTestInstance (context, texture, format)
435 const DeviceInterface& vk = m_context.getDeviceInterface();
436 const VkDevice device = m_context.getDevice();
437 Allocator& allocator = m_context.getDefaultAllocator();
439 // Create a texel storage buffer. Its data be uninitialized, as we're not reading from it.
441 const VkDeviceSize imageSizeBytes = getImageSizeBytes(m_texture.size(), m_format);
442 m_imageBuffer = de::MovePtr<Buffer>(new Buffer(vk, device, allocator,
443 makeBufferCreateInfo(imageSizeBytes, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT), MemoryRequirement::Any));
445 m_bufferView = makeBufferView(vk, device, m_imageBuffer->get(), m_format, 0ull, imageSizeBytes);
448 VkDescriptorSetLayout BufferSizeTestInstance::prepareDescriptors (void)
450 const DeviceInterface& vk = m_context.getDeviceInterface();
451 const VkDevice device = m_context.getDevice();
453 m_descriptorSetLayout = DescriptorSetLayoutBuilder()
454 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
455 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
458 m_descriptorPool = DescriptorPoolBuilder()
459 .addType(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
460 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
461 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
463 m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
465 const VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(m_resultBuffer->get(), 0ull, m_resultBufferSizeBytes);
467 DescriptorSetUpdateBuilder()
468 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, &m_bufferView.get())
469 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
472 return *m_descriptorSetLayout;
475 TestInstance* SizeTest::createInstance (Context& context) const
477 if (m_texture.type() == IMAGE_TYPE_BUFFER)
478 return new BufferSizeTestInstance(context, m_texture, m_format);
480 return new ImageSizeTestInstance(context, m_texture, m_format);
483 static const ImageType s_imageTypes[] =
491 IMAGE_TYPE_CUBE_ARRAY,
495 //! Base sizes used to generate actual image/buffer sizes in the test.
496 static const tcu::IVec3 s_baseImageSizes[] =
498 tcu::IVec3(32, 32, 32),
499 tcu::IVec3(12, 34, 56),
504 static const deUint32 s_flags[] =
506 SizeTest::FLAG_READONLY_IMAGE,
507 SizeTest::FLAG_WRITEONLY_IMAGE,
508 SizeTest::FLAG_READONLY_IMAGE | SizeTest::FLAG_WRITEONLY_IMAGE,
513 tcu::TestCaseGroup* createImageSizeTests (tcu::TestContext& testCtx)
515 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "image_size", "imageSize() cases"));
517 const VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT;
519 for (int imageTypeNdx = 0; imageTypeNdx < DE_LENGTH_OF_ARRAY(s_imageTypes); ++imageTypeNdx)
521 de::MovePtr<tcu::TestCaseGroup> imageGroup(new tcu::TestCaseGroup(testCtx, getImageTypeName(s_imageTypes[imageTypeNdx]).c_str(), ""));
523 for (int flagNdx = 0; flagNdx < DE_LENGTH_OF_ARRAY(s_flags); ++flagNdx)
524 for (int imageSizeNdx = 0; imageSizeNdx < DE_LENGTH_OF_ARRAY(s_baseImageSizes); ++imageSizeNdx)
526 const Texture texture = getTexture(s_imageTypes[imageTypeNdx], s_baseImageSizes[imageSizeNdx]);
527 imageGroup->addChild(new SizeTest(testCtx, getCaseName(texture, s_flags[flagNdx]), "", texture, format, s_flags[flagNdx]));
530 testGroup->addChild(imageGroup.release());
532 return testGroup.release();