1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 The Khronos Group Inc.
6 * Copyright (c) 2019 The Android Open Source Project
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 Cube image with misaligned baseArrayLayer tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktImageMisalignedCubeTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktImageTestsUtil.hpp"
28 #include "vktImageTexture.hpp"
29
30 #include "vkDefs.hpp"
31 #include "vkRef.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vkPlatform.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkBarrierUtil.hpp"
37 #include "vkBuilderUtil.hpp"
38 #include "vkImageUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkObjUtil.hpp"
41 #include "vkTypeUtil.hpp"
42 #include "vkBufferWithMemory.hpp"
43
44 #include "deUniquePtr.hpp"
45 #include "deStringUtil.hpp"
46 #include "deMath.h"
47
48 #include <string>
49
50 using namespace vk;
51
52 namespace vkt
53 {
54 namespace image
55 {
56 namespace
57 {
58
makeImageCreateInfo(const tcu::IVec3 & size,const VkFormat format)59 inline VkImageCreateInfo makeImageCreateInfo (const tcu::IVec3& size, const VkFormat format)
60 {
61 const VkImageUsageFlags usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
62 const VkImageCreateInfo imageParams =
63 {
64 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
65 DE_NULL, // const void* pNext;
66 VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT, // VkImageCreateFlags flags;
67 VK_IMAGE_TYPE_2D, // VkImageType imageType;
68 format, // VkFormat format;
69 makeExtent3D(size.x(), size.y(), 1u), // VkExtent3D extent;
70 1u, // deUint32 mipLevels;
71 (deUint32)size.z(), // deUint32 arrayLayers;
72 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
73 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
74 usage, // VkImageUsageFlags usage;
75 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
76 0u, // deUint32 queueFamilyIndexCount;
77 DE_NULL, // const deUint32* pQueueFamilyIndices;
78 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
79 };
80
81 return imageParams;
82 }
83
fillBuffer(const DeviceInterface & vk,const VkDevice device,const Allocation & alloc,const VkDeviceSize offset,const VkDeviceSize size,const VkFormat format,const tcu::Vec4 & color)84 void fillBuffer (const DeviceInterface& vk, const VkDevice device, const Allocation& alloc, const VkDeviceSize offset, const VkDeviceSize size, const VkFormat format, const tcu::Vec4& color)
85 {
86 const tcu::TextureFormat textureFormat = mapVkFormat(format);
87 const deUint32 colorPixelSize = static_cast<deUint32>(tcu::getPixelSize(textureFormat));
88 tcu::TextureLevel colorPixelBuffer (textureFormat, 1, 1);
89 tcu::PixelBufferAccess colorPixel (colorPixelBuffer);
90
91 colorPixel.setPixel(color, 0, 0);
92
93 const deUint8* src = static_cast<deUint8*>(colorPixel.getDataPtr());
94 deUint8* dstBase = static_cast<deUint8*>(alloc.getHostPtr());
95 deUint8* dst = &dstBase[offset];
96
97 for (deUint32 pixelPos = 0; pixelPos < size; pixelPos += colorPixelSize)
98 deMemcpy(&dst[pixelPos], src, colorPixelSize);
99
100 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset() + offset, size);
101 }
102
makeBufferImageCopy(const vk::VkDeviceSize & bufferOffset,const vk::VkImageSubresourceLayers & imageSubresource,const vk::VkOffset3D & imageOffset,const vk::VkExtent3D & imageExtent)103 VkBufferImageCopy makeBufferImageCopy (const vk::VkDeviceSize& bufferOffset,
104 const vk::VkImageSubresourceLayers& imageSubresource,
105 const vk::VkOffset3D& imageOffset,
106 const vk::VkExtent3D& imageExtent)
107 {
108 const VkBufferImageCopy copyParams =
109 {
110 bufferOffset, // VkDeviceSize bufferOffset;
111 0u, // deUint32 bufferRowLength;
112 0u, // deUint32 bufferImageHeight;
113 imageSubresource, // VkImageSubresourceLayers imageSubresource;
114 imageOffset, // VkOffset3D imageOffset;
115 imageExtent, // VkExtent3D imageExtent;
116 };
117 return copyParams;
118 }
119
120 //! Interpret the memory as IVec4
readVec4(const void * const data,const deUint32 ndx)121 inline tcu::Vec4 readVec4 (const void* const data, const deUint32 ndx)
122 {
123 const float* const p = reinterpret_cast<const float*>(data);
124 const deUint32 ofs = 4 * ndx;
125
126 return tcu::Vec4(p[ofs+0], p[ofs+1], p[ofs+2], p[ofs+3]);
127 }
128
129 class MisalignedCubeTestInstance : public TestInstance
130 {
131 public:
132 MisalignedCubeTestInstance (Context& context,
133 const tcu::IVec3& size,
134 const VkFormat format);
135 tcu::TestStatus iterate (void);
136
137 private:
138 const tcu::IVec3& m_size;
139 const VkFormat m_format;
140 };
141
MisalignedCubeTestInstance(Context & context,const tcu::IVec3 & size,const VkFormat format)142 MisalignedCubeTestInstance::MisalignedCubeTestInstance (Context& context, const tcu::IVec3& size, const VkFormat format)
143 : TestInstance (context)
144 , m_size (size)
145 , m_format (format)
146 {
147 }
148
iterate(void)149 tcu::TestStatus MisalignedCubeTestInstance::iterate (void)
150 {
151 DE_ASSERT(de::inRange(m_size.z(), 6, 16));
152 DE_ASSERT(m_format == VK_FORMAT_R8G8B8A8_UNORM);
153
154 const DeviceInterface& vk = m_context.getDeviceInterface();
155 const VkDevice device = m_context.getDevice();
156 Allocator& allocator = m_context.getDefaultAllocator();
157 const VkQueue queue = m_context.getUniversalQueue();
158 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
159 const deUint32 numLayers = m_size.z();
160 const deUint32 cube0LayerStart = 0;
161 const deUint32 cube1LayerStart = numLayers - 6u;
162 const VkDeviceSize resultBufferSizeBytes = 2 * 6 * 4 * sizeof(float); // vec4[6] in shader
163 const VkExtent3D imageExtent = makeExtent3D(m_size.x(), m_size.y(), 1u);
164 const deUint32 pixelSize = static_cast<deUint32>(tcu::getPixelSize(mapVkFormat(m_format)));
165 const deUint32 layerSize = imageExtent.width * imageExtent.height * pixelSize;
166 const float eps = 1.0f / float(2 * 256);
167
168 const VkBufferCreateInfo resultBufferCreateInfo = makeBufferCreateInfo(resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
169 de::MovePtr<BufferWithMemory> resultBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vk, device, allocator, resultBufferCreateInfo, MemoryRequirement::HostVisible));
170 const Allocation& resultBufferAlloc = resultBuffer->getAllocation();
171 const VkImageCreateInfo imageCreateInfo = makeImageCreateInfo(m_size, m_format);
172 de::MovePtr<Image> image = de::MovePtr<Image>(new Image(vk, device, allocator, imageCreateInfo, MemoryRequirement::Any));
173 const VkImageSubresourceRange imageSubresourceRange0 = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, cube0LayerStart, 6u);
174 Move<VkImageView> imageView0 = makeImageView(vk, device, image->get(), VK_IMAGE_VIEW_TYPE_CUBE, m_format, imageSubresourceRange0);
175 const VkImageSubresourceRange imageSubresourceRange1 = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, cube1LayerStart, 6u);
176 Move<VkImageView> imageView1 = makeImageView(vk, device, image->get(), VK_IMAGE_VIEW_TYPE_CUBE, m_format, imageSubresourceRange1);
177
178 Move<VkDescriptorSetLayout> descriptorSetLayout = DescriptorSetLayoutBuilder()
179 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
180 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
181 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
182 .build(vk, device);
183 Move<VkDescriptorPool> descriptorPool = DescriptorPoolBuilder()
184 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
185 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
186 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
187 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
188 Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout);
189 const VkDescriptorImageInfo descriptorImageInfo0 = makeDescriptorImageInfo(DE_NULL, *imageView0, VK_IMAGE_LAYOUT_GENERAL);
190 const VkDescriptorImageInfo descriptorImageInfo1 = makeDescriptorImageInfo(DE_NULL, *imageView1, VK_IMAGE_LAYOUT_GENERAL);
191 const VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(resultBuffer->get(), 0ull, resultBufferSizeBytes);
192
193 const Move<VkShaderModule> shaderModule = createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0);
194 const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vk, device, *descriptorSetLayout);
195 const Move<VkPipeline> pipeline = makeComputePipeline(vk, device, *pipelineLayout, *shaderModule);
196 const Move<VkCommandPool> cmdPool = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
197 const Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
198
199 const VkDeviceSize clearBufferSize = layerSize * numLayers;
200 const Move<VkBuffer> clearBuffer = makeBuffer(vk, device, clearBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
201 const de::MovePtr<Allocation> clearBufferAlloc = bindBuffer(vk, device, allocator, *clearBuffer, MemoryRequirement::HostVisible);
202 const VkImageSubresourceRange clearSubresRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, numLayers);
203 const VkImageMemoryBarrier clearBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT,
204 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
205 image->get(), clearSubresRange);
206 const VkImageMemoryBarrier preShaderImageBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
207 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
208 image->get(), clearSubresRange);
209 const VkBufferMemoryBarrier postShaderBarrier = makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
210 resultBuffer->get(), 0ull, VK_WHOLE_SIZE);
211 bool result = true;
212
213 DescriptorSetUpdateBuilder()
214 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo0)
215 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo1)
216 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
217 .update(vk, device);
218
219 beginCommandBuffer(vk, *cmdBuffer);
220
221 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
222 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
223
224 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &clearBarrier);
225
226 // Clear layers with predefined values
227 for (deUint32 layerNdx = 0; layerNdx < numLayers; ++layerNdx)
228 {
229 const float componentValue = float(16 * layerNdx) / 255.0f;
230 const tcu::Vec4 clearColor = tcu::Vec4(componentValue, componentValue, componentValue, 1.0f);
231 const VkDeviceSize bufferOffset = layerNdx * layerSize;
232 const VkImageSubresourceLayers imageSubresource = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, layerNdx, 1u);
233 const VkBufferImageCopy bufferImageCopyRegion = makeBufferImageCopy(bufferOffset, imageSubresource, makeOffset3D(0u, 0u, 0u), imageExtent);
234
235 fillBuffer(vk, device, *clearBufferAlloc, bufferOffset, layerSize, m_format, clearColor);
236
237 vk.cmdCopyBufferToImage(*cmdBuffer, *clearBuffer, image->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &bufferImageCopyRegion);
238 }
239
240 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &preShaderImageBarrier);
241
242 vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
243
244 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0, 0, DE_NULL, 1, &postShaderBarrier, 0, DE_NULL);
245
246 endCommandBuffer(vk, *cmdBuffer);
247
248 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
249
250 invalidateAlloc(vk, device, resultBufferAlloc);
251
252 // Check cube 0
253 for (deUint32 layerNdx = 0; layerNdx < 6; ++layerNdx)
254 {
255 const deUint32 layerUsed = cube0LayerStart + layerNdx;
256 const float componentValue = float(16 * layerUsed) / 255.0f;
257 const tcu::Vec4 expectedColor = tcu::Vec4(componentValue, componentValue, componentValue, 1.0f);
258 const tcu::Vec4 resultColor = readVec4(resultBufferAlloc.getHostPtr(), layerNdx);
259 const tcu::Vec4 delta = expectedColor - resultColor;
260
261 if (deFloatAbs(delta.x()) > eps || deFloatAbs(delta.y()) > eps || deFloatAbs(delta.z()) > eps || deFloatAbs(delta.w()) > eps)
262 result = false;
263 }
264
265 // Check cube 1
266 for (deUint32 layerNdx = 0; layerNdx < 6; ++layerNdx)
267 {
268 const deUint32 layerUsed = cube1LayerStart + layerNdx;
269 const float componentValue = float(16 * layerUsed) / 255.0f;
270 const tcu::Vec4 expectedColor = tcu::Vec4(componentValue, componentValue, componentValue, 1.0f);
271 const tcu::Vec4 resultColor = readVec4(resultBufferAlloc.getHostPtr(), layerNdx + 6u);
272 const tcu::Vec4 delta = expectedColor - resultColor;
273
274 if (deFloatAbs(delta.x()) > eps || deFloatAbs(delta.y()) > eps || deFloatAbs(delta.z()) > eps || deFloatAbs(delta.w()) > eps)
275 result = false;
276 }
277
278 if (result)
279 return tcu::TestStatus::pass("pass");
280 else
281 return tcu::TestStatus::fail("fail");
282 }
283
284 class MisalignedCubeTest : public TestCase
285 {
286 public:
287 MisalignedCubeTest (tcu::TestContext& testCtx,
288 const std::string& name,
289 const std::string& description,
290 const tcu::IVec3& size,
291 const VkFormat format);
292
293 void initPrograms (SourceCollections& programCollection) const;
294 TestInstance* createInstance (Context& context) const;
295
296 private:
297 const tcu::IVec3 m_size;
298 const VkFormat m_format;
299 };
300
MisalignedCubeTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const tcu::IVec3 & size,const VkFormat format)301 MisalignedCubeTest::MisalignedCubeTest (tcu::TestContext& testCtx,
302 const std::string& name,
303 const std::string& description,
304 const tcu::IVec3& size,
305 const VkFormat format)
306 : TestCase (testCtx, name, description)
307 , m_size (size)
308 , m_format (format)
309 {
310 }
311
initPrograms(SourceCollections & programCollection) const312 void MisalignedCubeTest::initPrograms (SourceCollections& programCollection) const
313 {
314 const std::string formatQualifierStr = getShaderImageFormatQualifier(mapVkFormat(m_format));
315
316 std::ostringstream src;
317 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
318 << "\n"
319 << "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
320 << "layout (binding = 0, " << formatQualifierStr << ") " << "readonly uniform highp imageCube u_cubeImage0;\n"
321 << "layout (binding = 1, " << formatQualifierStr << ") " << "readonly uniform highp imageCube u_cubeImage1;\n"
322 << "layout (binding = 2) writeonly buffer Output\n"
323 << "{\n"
324 << " vec4 cube0_color0;\n"
325 << " vec4 cube0_color1;\n"
326 << " vec4 cube0_color2;\n"
327 << " vec4 cube0_color3;\n"
328 << " vec4 cube0_color4;\n"
329 << " vec4 cube0_color5;\n"
330 << " vec4 cube1_color0;\n"
331 << " vec4 cube1_color1;\n"
332 << " vec4 cube1_color2;\n"
333 << " vec4 cube1_color3;\n"
334 << " vec4 cube1_color4;\n"
335 << " vec4 cube1_color5;\n"
336 << "} sb_out;\n"
337 << "\n"
338 << "void main (void)\n"
339 << "{\n"
340 << " sb_out.cube0_color0 = imageLoad(u_cubeImage0, ivec3(1, 1, 0));\n"
341 << " sb_out.cube0_color1 = imageLoad(u_cubeImage0, ivec3(1, 1, 1));\n"
342 << " sb_out.cube0_color2 = imageLoad(u_cubeImage0, ivec3(1, 1, 2));\n"
343 << " sb_out.cube0_color3 = imageLoad(u_cubeImage0, ivec3(1, 1, 3));\n"
344 << " sb_out.cube0_color4 = imageLoad(u_cubeImage0, ivec3(1, 1, 4));\n"
345 << " sb_out.cube0_color5 = imageLoad(u_cubeImage0, ivec3(1, 1, 5));\n"
346 << " sb_out.cube1_color0 = imageLoad(u_cubeImage1, ivec3(1, 1, 0));\n"
347 << " sb_out.cube1_color1 = imageLoad(u_cubeImage1, ivec3(1, 1, 1));\n"
348 << " sb_out.cube1_color2 = imageLoad(u_cubeImage1, ivec3(1, 1, 2));\n"
349 << " sb_out.cube1_color3 = imageLoad(u_cubeImage1, ivec3(1, 1, 3));\n"
350 << " sb_out.cube1_color4 = imageLoad(u_cubeImage1, ivec3(1, 1, 4));\n"
351 << " sb_out.cube1_color5 = imageLoad(u_cubeImage1, ivec3(1, 1, 5));\n"
352 << "}\n";
353
354 programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
355 }
356
createInstance(Context & context) const357 TestInstance* MisalignedCubeTest::createInstance (Context& context) const
358 {
359 return new MisalignedCubeTestInstance(context, m_size, m_format);
360 }
361
362 //! Base sizes used to generate actual imager sizes in the test.
363 static const tcu::IVec3 s_baseImageSizes[] =
364 {
365 tcu::IVec3(16, 16, 7),
366 tcu::IVec3(16, 16, 8),
367 tcu::IVec3(16, 16, 9),
368 tcu::IVec3(16, 16, 10),
369 tcu::IVec3(16, 16, 11),
370 };
371
372 } // anonymous ns
373
createMisalignedCubeTests(tcu::TestContext & testCtx)374 tcu::TestCaseGroup* createMisalignedCubeTests (tcu::TestContext& testCtx)
375 {
376 de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "misaligned_cube", "Cube image with misaligned baseArrayLayer test cases"));
377
378 const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
379
380 for (int imageSizeNdx = 0; imageSizeNdx < DE_LENGTH_OF_ARRAY(s_baseImageSizes); ++imageSizeNdx)
381 {
382 const tcu::IVec3 size = s_baseImageSizes[imageSizeNdx];
383
384 testGroup->addChild(new MisalignedCubeTest(testCtx, de::toString(size.z()), "", size, format));
385 }
386
387 return testGroup.release();
388 }
389
390 } // image
391 } // vkt
392