1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2022 The Khronos Group Inc.
6 * Copyright (c) 2022 Valve Corporation.
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
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktPipelineImageSlicedViewOf3DTests.hpp"
26 #include "vktTestCase.hpp"
27
28 #include "vkImageUtil.hpp"
29 #include "vkTypeUtil.hpp"
30 #include "vkObjUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkBuilderUtil.hpp"
33 #include "vkImageWithMemory.hpp"
34 #include "vkBufferWithMemory.hpp"
35 #include "vkBarrierUtil.hpp"
36
37 #include "tcuTexture.hpp"
38 #include "tcuImageCompare.hpp"
39 #include "tcuTextureUtil.hpp"
40
41 #include "deRandom.hpp"
42
43 #include <sstream>
44 #include <vector>
45 #include <tuple>
46 #include <set>
47 #include <limits>
48 #include <string>
49 #include <algorithm>
50
51 namespace vkt
52 {
53 namespace pipeline
54 {
55
56 using namespace vk;
57
58 namespace
59 {
60
61 constexpr uint32_t kWidth = 8u;
62 constexpr uint32_t kHeight = 8u;
63 constexpr VkFormat kFormat = VK_FORMAT_R8G8B8A8_UINT;
64 constexpr uint32_t kVertexCount = 3u;
65 constexpr auto kUsageLayout = VK_IMAGE_LAYOUT_GENERAL;
66
67 enum class TestType
68 {
69 LOAD = 0,
70 STORE,
71 };
72
73 struct TestParams
74 {
75 TestType testType;
76 VkShaderStageFlagBits stage;
77 uint32_t width;
78 uint32_t height;
79 uint32_t depth;
80 uint32_t offset;
81
82 private:
83 // We want to test both normal ranges and VK_REMAINING_3D_SLICES_EXT, but in the latter case we cannot blindly use the range
84 // value for some operations. See getActualRange() and getSlicedViewRange().
85 uint32_t range;
86
87 public:
88 tcu::Maybe<uint32_t> mipLevel;
89 bool sampleImg;
90
TestParamsvkt::pipeline::__anon979985df0111::TestParams91 TestParams (TestType testType_, VkShaderStageFlagBits stage_, uint32_t width_, uint32_t height_, uint32_t depth_, uint32_t offset_, uint32_t range_,
92 const tcu::Maybe<uint32_t>& mipLevel_, bool sampleImg_)
93 : testType (testType_)
94 , stage (stage_)
95 , width (width_)
96 , height (height_)
97 , depth (depth_)
98 , offset (offset_)
99 , range (range_)
100 , mipLevel (mipLevel_)
101 , sampleImg (sampleImg_)
102 {
103 DE_ASSERT(stage == VK_SHADER_STAGE_COMPUTE_BIT || stage == VK_SHADER_STAGE_FRAGMENT_BIT);
104 DE_ASSERT(range > 0u);
105
106 const auto selectedLevel = getSelectedLevel();
107
108 if (useMipMaps())
109 {
110 // To simplify things.
111 DE_ASSERT(width == height && width == depth);
112
113 const auto maxMipLevelCount = getMaxMipLevelCount();
114 DE_ASSERT(selectedLevel < maxMipLevelCount);
115 DE_UNREF(maxMipLevelCount); // For release builds.
116 }
117
118 const uint32_t selectedLevelDepth = (depth >> selectedLevel);
119 DE_UNREF(selectedLevelDepth); // For release builds.
120
121 if (!useRemainingSlices())
122 DE_ASSERT(offset + range <= selectedLevelDepth);
123 else
124 DE_ASSERT(offset < selectedLevelDepth);
125 }
126
getSelectedLevelvkt::pipeline::__anon979985df0111::TestParams127 uint32_t getSelectedLevel (void) const
128 {
129 return (useMipMaps() ? mipLevel.get() : 0u);
130 }
131
getFullImageLevelsvkt::pipeline::__anon979985df0111::TestParams132 uint32_t getFullImageLevels (void) const
133 {
134 return (useMipMaps() ? getMaxMipLevelCount() : 1u);
135 }
136
getActualRangevkt::pipeline::__anon979985df0111::TestParams137 uint32_t getActualRange (void) const
138 {
139 const auto levelDepth = (depth >> getSelectedLevel());
140 DE_ASSERT(levelDepth > 0u);
141
142 return (useRemainingSlices() ? (levelDepth - offset) : range);
143 }
144
getSlicedViewRangevkt::pipeline::__anon979985df0111::TestParams145 uint32_t getSlicedViewRange (void) const
146 {
147 return range;
148 }
149
getSliceExtentvkt::pipeline::__anon979985df0111::TestParams150 VkExtent3D getSliceExtent (void) const
151 {
152 const auto selectedLevel = getSelectedLevel();
153 const auto extent = makeExtent3D((width >> selectedLevel),
154 (height >> selectedLevel),
155 getActualRange());
156
157 DE_ASSERT(extent.width > 0u);
158 DE_ASSERT(extent.height > 0u);
159 DE_ASSERT(extent.depth > 0u);
160 return extent;
161 }
162
getFullLevelExtentvkt::pipeline::__anon979985df0111::TestParams163 VkExtent3D getFullLevelExtent (void) const
164 {
165 const auto selectedLevel = getSelectedLevel();
166 const auto extent = makeExtent3D((width >> selectedLevel),
167 (height >> selectedLevel),
168 (depth >> selectedLevel));
169
170 DE_ASSERT(extent.width > 0u);
171 DE_ASSERT(extent.height > 0u);
172 DE_ASSERT(extent.depth > 0u);
173 return extent;
174 }
175
getMaxMipLevelCountForSizevkt::pipeline::__anon979985df0111::TestParams176 static uint32_t getMaxMipLevelCountForSize (uint32_t size)
177 {
178 DE_ASSERT(size <= static_cast<uint32_t>(std::numeric_limits<int32_t>::max()));
179 return static_cast<uint32_t>(deLog2Floor32(static_cast<int32_t>(size)) + 1);
180 }
181
182 private:
getMaxMipLevelCountvkt::pipeline::__anon979985df0111::TestParams183 uint32_t getMaxMipLevelCount (void) const
184 {
185 return getMaxMipLevelCountForSize(depth);
186 }
187
useMipMapsvkt::pipeline::__anon979985df0111::TestParams188 bool useMipMaps (void) const
189 {
190 return static_cast<bool>(mipLevel);
191 }
192
useRemainingSlicesvkt::pipeline::__anon979985df0111::TestParams193 bool useRemainingSlices (void) const
194 {
195 return (range == VK_REMAINING_3D_SLICES_EXT);
196 }
197 };
198
199 class SlicedViewTestCase : public vkt::TestCase
200 {
201 public:
SlicedViewTestCase(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)202 SlicedViewTestCase (tcu::TestContext& testCtx, const std::string& name, const TestParams& params)
203 : vkt::TestCase(testCtx, name), m_params(params) {}
~SlicedViewTestCase(void)204 virtual ~SlicedViewTestCase (void) {}
205
206 void initPrograms (vk::SourceCollections& programCollection) const override;
207 TestInstance* createInstance (Context& context) const override;
208 void checkSupport (Context& context) const override;
209
210 protected:
211 const TestParams m_params;
212 };
213
214 class SlicedViewTestInstance : public vkt::TestInstance
215 {
216 public:
SlicedViewTestInstance(Context & context,const TestParams & params)217 SlicedViewTestInstance (Context& context, const TestParams& params)
218 : vkt::TestInstance(context), m_params (params)
219 {}
~SlicedViewTestInstance(void)220 virtual ~SlicedViewTestInstance (void) {}
221
222 protected:
223 virtual void runPipeline (const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer, const VkImageView slicedImage, const VkImageView auxiliarImage);
224 virtual void runGraphicsPipeline (const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer);
225 virtual void runComputePipeline (const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer);
226 bool runSamplingPipeline (const VkImage fullImage, const VkImageView slicedView, const VkExtent3D& levelExtent);
227
228 const TestParams m_params;
229
230 Move<VkDescriptorSetLayout> m_setLayout;
231 Move<VkDescriptorPool> m_descriptorPool;
232 Move<VkDescriptorSet> m_descriptorSet;
233 Move<VkPipelineLayout> m_pipelineLayout;
234
235 // Only for graphics pipelines.
236 Move<VkRenderPass> m_renderPass;
237 Move<VkFramebuffer> m_framebuffer;
238
239 Move<VkPipeline> m_pipeline;
240 };
241
242 class SlicedViewLoadTestInstance : public SlicedViewTestInstance
243 {
244 public:
SlicedViewLoadTestInstance(Context & context,const TestParams & params)245 SlicedViewLoadTestInstance (Context& context, const TestParams& params) : SlicedViewTestInstance(context, params) {}
~SlicedViewLoadTestInstance(void)246 virtual ~SlicedViewLoadTestInstance (void) {}
247
248 tcu::TestStatus iterate (void);
249 };
250
251 class SlicedViewStoreTestInstance : public SlicedViewTestInstance
252 {
253 public:
SlicedViewStoreTestInstance(Context & context,const TestParams & params)254 SlicedViewStoreTestInstance (Context& context, const TestParams& params) : SlicedViewTestInstance(context, params) {}
~SlicedViewStoreTestInstance(void)255 virtual ~SlicedViewStoreTestInstance (void) {}
256
257 tcu::TestStatus iterate (void);
258 };
259
checkSupport(Context & context) const260 void SlicedViewTestCase::checkSupport (Context &context) const
261 {
262 context.requireDeviceFunctionality(VK_EXT_IMAGE_SLICED_VIEW_OF_3D_EXTENSION_NAME);
263
264 if (m_params.stage == VK_SHADER_STAGE_FRAGMENT_BIT)
265 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FRAGMENT_STORES_AND_ATOMICS);
266 }
267
initPrograms(vk::SourceCollections & programCollection) const268 void SlicedViewTestCase::initPrograms(vk::SourceCollections &programCollection) const
269 {
270 const std::string bindings =
271 "layout (rgba8ui, set=0, binding=0) uniform uimage3D slicedImage;\n"
272 "layout (rgba8ui, set=0, binding=1) uniform uimage3D auxiliarImage;\n"
273 ;
274
275 std::string loadFrom;
276 std::string storeTo;
277
278 // We may need to load stuff from the sliced image into an auxiliary image if we're testing load, or we may need to store stuff
279 // to the sliced image, read from the auxiliary image if we're testing stores.
280 if (m_params.testType == TestType::LOAD)
281 {
282 loadFrom = "slicedImage";
283 storeTo = "auxiliarImage";
284 }
285 else if (m_params.testType == TestType::STORE)
286 {
287 loadFrom = "auxiliarImage";
288 storeTo = "slicedImage";
289 }
290 else
291 DE_ASSERT(false);
292
293 std::ostringstream mainOperation;
294
295 // Note: "coords" will vary depending on the shader stage.
296 mainOperation
297 << " const ivec3 size = imageSize(slicedImage);\n"
298 << " const uvec4 badColor = uvec4(0, 0, 0, 0);\n"
299 << " const uvec4 goodColor = imageLoad(" << loadFrom << ", coords);\n"
300 << " const uvec4 storedColor = ((size.z == " << m_params.getActualRange() << ") ? goodColor : badColor);\n"
301 << " imageStore(" << storeTo << ", coords, storedColor);\n"
302 ;
303
304 if (m_params.stage == VK_SHADER_STAGE_COMPUTE_BIT)
305 {
306 // For compute, we'll launch as many workgroups as slices, and each invocation will handle one pixel.
307 const auto sliceExtent = m_params.getSliceExtent();
308 std::ostringstream comp;
309 comp
310 << "#version 460\n"
311 << "layout (local_size_x=" << sliceExtent.width << ", local_size_y=" << sliceExtent.height << ", local_size_z=1) in;\n"
312 << bindings
313 << "void main (void) {\n"
314 << " const ivec3 coords = ivec3(ivec2(gl_LocalInvocationID.xy), int(gl_WorkGroupID.x));\n"
315 << mainOperation.str()
316 << "}\n"
317 ;
318 programCollection.glslSources.add("comp") << glu::ComputeSource(comp.str());
319 }
320 else if (m_params.stage == VK_SHADER_STAGE_FRAGMENT_BIT)
321 {
322 // For fragment, we'll draw as many instances as slices, and each draw will use a full-screen triangle to generate as many
323 // fragment shader invocations as pixels in the image (the framebuffer needs to have the same size as the storage images).
324 std::ostringstream frag;
325 frag
326 << "#version 460\n"
327 << "layout (location=0) in flat int zCoord;\n"
328 << bindings
329 << "void main (void) {\n"
330 << " const ivec3 coords = ivec3(ivec2(gl_FragCoord.xy), zCoord);\n"
331 << mainOperation.str()
332 << "}\n"
333 ;
334
335 std::ostringstream vert;
336 vert
337 << "#version 460\n"
338 << "layout (location=0) out flat int zCoord;\n"
339 << "vec2 positions[3] = vec2[](\n"
340 << " vec2(-1.0, -1.0),\n"
341 << " vec2( 3.0, -1.0),\n"
342 << " vec2(-1.0, 3.0)\n"
343 << ");\n"
344 << "void main() {\n"
345 << " gl_Position = vec4(positions[gl_VertexIndex % 3], 0.0, 1.0);\n"
346 << " zCoord = int(gl_InstanceIndex);\n"
347 << "}\n"
348 ;
349
350 programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
351 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
352 }
353 else
354 {
355 DE_ASSERT(false);
356 }
357
358 if (m_params.sampleImg)
359 {
360 // Prepare a compute shader that will sample the whole level to verify it's available.
361 const auto levelExtent = m_params.getFullLevelExtent();
362
363 std::ostringstream comp;
364 comp
365 << "#version 460\n"
366 << "layout (local_size_x=" << levelExtent.width << ", local_size_y=" << levelExtent.height << ", local_size_z=" << levelExtent.depth << ") in;\n"
367 << "layout (set=0, binding=0) uniform usampler3D combinedSampler;\n" // The image being tested.
368 << "layout (set=0, binding=1, rgba8ui) uniform uimage3D auxiliarImage;\n" // Verification storage image.
369 << "void main() {\n"
370 << " const vec3 levelExtent = vec3(" << levelExtent.width << ", " << levelExtent.height << ", " << levelExtent.depth << ");\n"
371 << " const vec3 sampleCoords = vec3(\n"
372 << " (float(gl_LocalInvocationID.x) + 0.5) / levelExtent.x,\n"
373 << " (float(gl_LocalInvocationID.y) + 0.5) / levelExtent.y,\n"
374 << " (float(gl_LocalInvocationID.z) + 0.5) / levelExtent.z);\n"
375 << " const ivec3 storeCoords = ivec3(int(gl_LocalInvocationID.x), int(gl_LocalInvocationID.y), int(gl_LocalInvocationID.z));\n"
376 << " const uvec4 sampledColor = texture(combinedSampler, sampleCoords);\n"
377 << " imageStore(auxiliarImage, storeCoords, sampledColor);\n"
378 << "}\n"
379 ;
380 programCollection.glslSources.add("compSample") << glu::ComputeSource(comp.str());
381 }
382 }
383
createInstance(Context & context) const384 TestInstance* SlicedViewTestCase::createInstance (Context& context) const
385 {
386 if (m_params.testType == TestType::LOAD)
387 return new SlicedViewLoadTestInstance(context, m_params);
388 if (m_params.testType == TestType::STORE)
389 return new SlicedViewStoreTestInstance(context, m_params);
390
391 DE_ASSERT(false);
392 return nullptr;
393 }
394
makeIVec3(uint32_t width,uint32_t height,uint32_t depth)395 tcu::IVec3 makeIVec3 (uint32_t width, uint32_t height, uint32_t depth)
396 {
397 return tcu::IVec3(static_cast<int>(width), static_cast<int>(height), static_cast<int>(depth));
398 }
399
makePixelBufferAccess(const BufferWithMemory & buffer,const tcu::IVec3 & size,const tcu::TextureFormat & format)400 de::MovePtr<tcu::PixelBufferAccess> makePixelBufferAccess (const BufferWithMemory& buffer, const tcu::IVec3& size, const tcu::TextureFormat& format)
401 {
402 de::MovePtr<tcu::PixelBufferAccess> bufferImage (new tcu::PixelBufferAccess(format, size, buffer.getAllocation().getHostPtr()));
403 return bufferImage;
404 }
405
makeTransferBuffer(const VkExtent3D & extent,const tcu::TextureFormat & format,const DeviceInterface & vkd,const VkDevice device,Allocator & alloc)406 de::MovePtr<BufferWithMemory> makeTransferBuffer (const VkExtent3D& extent, const tcu::TextureFormat& format,
407 const DeviceInterface& vkd, const VkDevice device, Allocator& alloc)
408 {
409 DE_ASSERT(extent.width > 0u);
410 DE_ASSERT(extent.height > 0u);
411 DE_ASSERT(extent.depth > 0u);
412
413 const auto pixelSizeBytes = tcu::getPixelSize(format);
414 const auto pixelCount = extent.width * extent.height * extent.depth;
415 const auto bufferSize = static_cast<VkDeviceSize>(pixelCount) * static_cast<VkDeviceSize>(pixelSizeBytes);
416 const auto bufferUsage = (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
417 const auto bufferCreateInfo = makeBufferCreateInfo(bufferSize, bufferUsage);
418
419 de::MovePtr<BufferWithMemory> buffer (new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible));
420 return buffer;
421 }
422
makeAndFillTransferBuffer(const VkExtent3D & extent,const tcu::TextureFormat & format,const DeviceInterface & vkd,const VkDevice device,Allocator & alloc)423 de::MovePtr<BufferWithMemory> makeAndFillTransferBuffer (const VkExtent3D& extent, const tcu::TextureFormat& format,
424 const DeviceInterface& vkd, const VkDevice device, Allocator& alloc)
425 {
426 DE_ASSERT(tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
427
428 auto buffer = makeTransferBuffer(extent, format, vkd, device, alloc);
429 const auto size = makeIVec3(extent.width, extent.height, extent.depth);
430 auto bufferImg = makePixelBufferAccess(*buffer, size, format);
431
432 // Fill image with predefined pattern.
433 for (int z = 0; z < size.z(); ++z)
434 for (int y = 0; y < size.y(); ++y)
435 for (int x = 0; x < size.x(); ++x)
436 {
437 const tcu::UVec4 color (
438 static_cast<uint32_t>(0x80 | x),
439 static_cast<uint32_t>(0x80 | y),
440 static_cast<uint32_t>(0x80 | z),
441 1u
442 );
443 bufferImg->setPixel(color, x, y, z);
444 }
445
446 return buffer;
447 }
448
make3DImage(const DeviceInterface & vkd,const VkDevice device,Allocator & alloc,const VkFormat format,const VkExtent3D & extent,uint32_t mipLevels,const bool sampling)449 de::MovePtr<ImageWithMemory> make3DImage (const DeviceInterface &vkd, const VkDevice device, Allocator& alloc, const VkFormat format, const VkExtent3D& extent, uint32_t mipLevels, const bool sampling)
450 {
451 const VkImageUsageFlags imageUsage = (VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT
452 | (sampling ? VK_IMAGE_USAGE_SAMPLED_BIT : static_cast<VkImageUsageFlagBits>(0)));
453
454 const VkImageCreateInfo imageCreateInfo =
455 {
456 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
457 nullptr, // const void* pNext;
458 0u, // VkImageCreateFlags flags;
459 VK_IMAGE_TYPE_3D, // VkImageType imageType;
460 format, // VkFormat format;
461 extent, // VkExtent3D extent;
462 mipLevels, // uint32_t mipLevels;
463 1u, // uint32_t arrayLayers;
464 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
465 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
466 imageUsage, // VkImageUsageFlags usage;
467 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
468 0u, // uint32_t queueFamilyIndexCount;
469 nullptr, // const uint32_t* pQueueFamilyIndices;
470 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
471 };
472
473 de::MovePtr<ImageWithMemory> image (new ImageWithMemory(vkd, device, alloc, imageCreateInfo, MemoryRequirement::Any));
474 return image;
475 }
476
makeCommonImageSubresourceRange(uint32_t baseLevel,uint32_t levelCount)477 VkImageSubresourceRange makeCommonImageSubresourceRange (uint32_t baseLevel, uint32_t levelCount)
478 {
479 return makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, baseLevel, levelCount, 0u, 1u);
480 }
481
makeCommonImageSubresourceLayers(uint32_t mipLevel)482 VkImageSubresourceLayers makeCommonImageSubresourceLayers (uint32_t mipLevel)
483 {
484 return makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 0u, 1u);
485 }
486
make3DImageView(const DeviceInterface & vkd,const VkDevice device,const VkImage image,const VkFormat format,const tcu::Maybe<tcu::UVec2> & slices,uint32_t mipLevel,uint32_t levelCount)487 Move<VkImageView> make3DImageView (const DeviceInterface &vkd, const VkDevice device, const VkImage image, const VkFormat format,
488 const tcu::Maybe<tcu::UVec2>& slices/*x=offset, y=range)*/, uint32_t mipLevel, uint32_t levelCount)
489 {
490 const bool subSlice = static_cast<bool>(slices);
491
492 VkImageViewSlicedCreateInfoEXT sliceCreateInfo = initVulkanStructure();
493
494 if (subSlice)
495 {
496 sliceCreateInfo.sliceOffset = slices->x();
497 sliceCreateInfo.sliceCount = slices->y();
498 }
499
500 const VkImageViewCreateInfo viewCreateInfo =
501 {
502 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
503 (subSlice ? &sliceCreateInfo : nullptr), // const void* pNext;
504 0u, // VkImageViewCreateFlags flags;
505 image, // VkImage image;
506 VK_IMAGE_VIEW_TYPE_3D, // VkImageViewType viewType;
507 format, // VkFormat format;
508 makeComponentMappingRGBA(), // VkComponentMapping components;
509 makeCommonImageSubresourceRange(mipLevel, levelCount), // VkImageSubresourceRange subresourceRange;
510 };
511
512 return createImageView(vkd, device, &viewCreateInfo);
513 }
514
makePipelineStage(VkShaderStageFlagBits shaderStage)515 VkPipelineStageFlagBits makePipelineStage (VkShaderStageFlagBits shaderStage)
516 {
517 if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT)
518 return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
519 if (shaderStage == VK_SHADER_STAGE_COMPUTE_BIT)
520 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
521
522 DE_ASSERT(false);
523 return VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM;
524 }
525
runPipeline(const DeviceInterface & vkd,const VkDevice device,const VkCommandBuffer cmdBuffer,const VkImageView slicedImage,const VkImageView auxiliarImage)526 void SlicedViewTestInstance::runPipeline (const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer, const VkImageView slicedImage, const VkImageView auxiliarImage)
527 {
528 // The layouts created and used here must match the shaders.
529 const auto descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
530
531 DescriptorSetLayoutBuilder layoutBuilder;
532 layoutBuilder.addSingleBinding(descriptorType, m_params.stage);
533 layoutBuilder.addSingleBinding(descriptorType, m_params.stage);
534 m_setLayout = layoutBuilder.build(vkd, device);
535
536 DescriptorPoolBuilder poolBuilder;
537 poolBuilder.addType(descriptorType, 2u);
538 m_descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
539
540 m_descriptorSet = makeDescriptorSet(vkd, device, m_descriptorPool.get(), m_setLayout.get());
541 m_pipelineLayout = makePipelineLayout(vkd, device, m_setLayout.get());
542
543 DescriptorSetUpdateBuilder updateBuilder;
544 const auto slicedImageDescInfo = makeDescriptorImageInfo(DE_NULL, slicedImage, kUsageLayout);
545 const auto auxiliarImageDescInfo = makeDescriptorImageInfo(DE_NULL, auxiliarImage, kUsageLayout);
546 updateBuilder.writeSingle(m_descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &slicedImageDescInfo);
547 updateBuilder.writeSingle(m_descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), descriptorType, &auxiliarImageDescInfo);
548 updateBuilder.update(vkd, device);
549
550 if (m_params.stage == VK_SHADER_STAGE_FRAGMENT_BIT)
551 runGraphicsPipeline(vkd, device, cmdBuffer);
552 else if (m_params.stage == VK_SHADER_STAGE_COMPUTE_BIT)
553 runComputePipeline(vkd, device, cmdBuffer);
554 else
555 DE_ASSERT(false);
556 }
557
runGraphicsPipeline(const DeviceInterface & vkd,const VkDevice device,const VkCommandBuffer cmdBuffer)558 void SlicedViewTestInstance::runGraphicsPipeline (const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer)
559 {
560 const auto sliceExtent = m_params.getSliceExtent();
561 const auto& binaries = m_context.getBinaryCollection();
562 const auto vertShader = createShaderModule(vkd, device, binaries.get("vert"));
563 const auto fragShader = createShaderModule(vkd, device, binaries.get("frag"));
564 const auto extent = makeExtent3D(sliceExtent.width, sliceExtent.height, 1u);
565 const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
566
567 m_renderPass = makeRenderPass(vkd, device);
568 m_framebuffer = makeFramebuffer(vkd, device, m_renderPass.get(), 0u, nullptr, sliceExtent.width, sliceExtent.height);
569
570 const std::vector<VkViewport> viewports (1u, makeViewport(extent));
571 const std::vector<VkRect2D> scissors (1u, makeRect2D(extent));
572
573 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = initVulkanStructure();
574
575 m_pipeline = makeGraphicsPipeline(vkd, device, m_pipelineLayout.get(),
576 vertShader.get(), DE_NULL, DE_NULL, DE_NULL, fragShader.get(),
577 m_renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u,
578 &vertexInputStateCreateInfo);
579
580 beginRenderPass(vkd, cmdBuffer, m_renderPass.get(), m_framebuffer.get(), scissors.at(0u));
581 vkd.cmdBindPipeline(cmdBuffer, bindPoint, m_pipeline.get());
582 vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, m_pipelineLayout.get(), 0u, 1u, &m_descriptorSet.get(), 0u, nullptr);
583 vkd.cmdDraw(cmdBuffer, kVertexCount, sliceExtent.depth, 0u, 0u);
584 endRenderPass(vkd, cmdBuffer);
585 }
586
runComputePipeline(const DeviceInterface & vkd,const VkDevice device,const VkCommandBuffer cmdBuffer)587 void SlicedViewTestInstance::runComputePipeline (const DeviceInterface& vkd, const VkDevice device, const VkCommandBuffer cmdBuffer)
588 {
589 const auto bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
590 const auto compShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp"));
591
592 m_pipeline = makeComputePipeline(vkd, device, m_pipelineLayout.get(), compShader.get());
593
594 vkd.cmdBindPipeline(cmdBuffer, bindPoint, m_pipeline.get());
595 vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, m_pipelineLayout.get(), 0u, 1u, &m_descriptorSet.get(), 0u, nullptr);
596 vkd.cmdDispatch(cmdBuffer, m_params.getActualRange(), 1u, 1u);
597 }
598
runSamplingPipeline(const VkImage fullImage,const VkImageView slicedView,const VkExtent3D & levelExtent)599 bool SlicedViewTestInstance::runSamplingPipeline (const VkImage fullImage, const VkImageView slicedView, const VkExtent3D& levelExtent)
600 {
601 const auto& vkd = m_context.getDeviceInterface();
602 const auto device = m_context.getDevice();
603 const auto qfIndex = m_context.getUniversalQueueFamilyIndex();
604 const auto queue = m_context.getUniversalQueue();
605 auto& alloc = m_context.getDefaultAllocator();
606
607 const auto bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
608 const auto shaderStage = VK_SHADER_STAGE_COMPUTE_BIT;
609 const auto pipelineStage = makePipelineStage(shaderStage);
610
611 // Command pool and buffer.
612 const auto cmdPool = makeCommandPool(vkd, device, qfIndex);
613 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
614 const auto cmdBuffer = cmdBufferPtr.get();
615
616 // Descriptor set layout and pipeline layout.
617 DescriptorSetLayoutBuilder setLayoutBuilder;
618 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, shaderStage);
619 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStage);
620 const auto setLayout = setLayoutBuilder.build(vkd, device);
621 const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
622
623 // Pipeline.
624 const auto compShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("compSample"));
625 const auto pipeline = makeComputePipeline(vkd, device, pipelineLayout.get(), compShader.get());
626
627 // Descriptor pool and set.
628 DescriptorPoolBuilder poolBuilder;
629 poolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
630 poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
631 const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
632 const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
633
634 // Update descriptor set.
635 const VkSamplerCreateInfo samplerCreateInfo =
636 {
637 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType;
638 nullptr, // const void* pNext;
639 0u, // VkSamplerCreateFlags flags;
640 VK_FILTER_NEAREST, // VkFilter magFilter;
641 VK_FILTER_NEAREST, // VkFilter minFilter;
642 VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode;
643 VK_SAMPLER_ADDRESS_MODE_REPEAT, // VkSamplerAddressMode addressModeU;
644 VK_SAMPLER_ADDRESS_MODE_REPEAT, // VkSamplerAddressMode addressModeV;
645 VK_SAMPLER_ADDRESS_MODE_REPEAT, // VkSamplerAddressMode addressModeW;
646 0.0f, // float mipLodBias;
647 VK_FALSE, // VkBool32 anisotropyEnable;
648 1.0f, // float maxAnisotropy;
649 VK_FALSE, // VkBool32 compareEnable;
650 VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
651 0.0f, // float minLod;
652 0.0f, // float maxLod;
653 VK_BORDER_COLOR_INT_TRANSPARENT_BLACK, // VkBorderColor borderColor;
654 VK_FALSE, // VkBool32 unnormalizedCoordinates;
655 };
656 const auto sampler = createSampler(vkd, device, &samplerCreateInfo);
657
658 // This will be used as a storage image to verify the sampling results.
659 // It has the same size as the full level extent, but only a single level and not sliced.
660 const auto auxiliarImage = make3DImage(vkd, device, alloc, kFormat, levelExtent, 1u, false/*sampling*/);
661 const auto auxiliarView = make3DImageView(vkd, device, auxiliarImage->get(), kFormat, tcu::Nothing, 0u, 1u);
662
663 DescriptorSetUpdateBuilder updateBuilder;
664 const auto sampledImageInfo = makeDescriptorImageInfo(sampler.get(), slicedView, kUsageLayout);
665 const auto storageImageInfo = makeDescriptorImageInfo(DE_NULL, auxiliarView.get(), kUsageLayout);
666 updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &sampledImageInfo);
667 updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &storageImageInfo);
668 updateBuilder.update(vkd, device);
669
670 const auto tcuFormat = mapVkFormat(kFormat);
671 const auto verifBuffer = makeTransferBuffer(levelExtent, tcuFormat, vkd, device, alloc);
672 const auto refBuffer = makeTransferBuffer(levelExtent, tcuFormat, vkd, device, alloc);
673
674 beginCommandBuffer(vkd, cmdBuffer);
675
676 // Move auxiliar image to the proper layout.
677 const auto shaderAccess = (VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT);
678 const auto colorSRR = makeCommonImageSubresourceRange(0u, 1u);
679 const auto preDispatchBarrier = makeImageMemoryBarrier(0u, shaderAccess, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, auxiliarImage->get(), colorSRR);
680 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, pipelineStage, &preDispatchBarrier);
681
682 vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipeline.get());
683 vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
684 vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
685
686 // Sync shader writes before copying to verification buffer.
687 const auto preCopyBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
688 cmdPipelineMemoryBarrier(vkd, cmdBuffer, pipelineStage, VK_PIPELINE_STAGE_TRANSFER_BIT, &preCopyBarrier);
689
690 // Copy storage image to verification buffer.
691 const auto colorSRL = makeCommonImageSubresourceLayers(0u);
692 const auto copyRegion = makeBufferImageCopy(levelExtent, colorSRL);
693 vkd.cmdCopyImageToBuffer(cmdBuffer, auxiliarImage->get(), kUsageLayout, verifBuffer->get(), 1u, ©Region);
694
695 // Copy full level from the original full image to the reference buffer to compare them.
696 const auto refSRL = makeCommonImageSubresourceLayers(m_params.getSelectedLevel());
697 const auto refCopy = makeBufferImageCopy(levelExtent, refSRL);
698 vkd.cmdCopyImageToBuffer(cmdBuffer, fullImage, kUsageLayout, refBuffer->get(), 1u, &refCopy);
699
700 // Sync copies to host.
701 const auto postCopyBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
702 cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &postCopyBarrier);
703
704 endCommandBuffer(vkd, cmdBuffer);
705 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
706
707 // Compare both buffers.
708 auto& verifBufferAlloc = verifBuffer->getAllocation();
709 auto& refBufferAlloc = refBuffer->getAllocation();
710 invalidateAlloc(vkd, device, verifBufferAlloc);
711 invalidateAlloc(vkd, device, refBufferAlloc);
712
713 const auto iExtent = makeIVec3(levelExtent.width, levelExtent.height, levelExtent.depth);
714 const tcu::ConstPixelBufferAccess verifAcces (tcuFormat, iExtent, verifBufferAlloc.getHostPtr());
715 const tcu::ConstPixelBufferAccess refAccess (tcuFormat, iExtent, refBufferAlloc.getHostPtr());
716
717 auto& log = m_context.getTestContext().getLog();
718 const tcu::UVec4 threshold (0u, 0u, 0u, 0u);
719 return tcu::intThresholdCompare(log, "SamplingResult", "", refAccess, verifAcces, threshold, tcu::COMPARE_LOG_ON_ERROR);
720 }
721
iterate(void)722 tcu::TestStatus SlicedViewLoadTestInstance::iterate (void)
723 {
724 const auto& vkd = m_context.getDeviceInterface();
725 const auto device = m_context.getDevice();
726 auto& alloc = m_context.getDefaultAllocator();
727 const auto qfIndex = m_context.getUniversalQueueFamilyIndex();
728 const auto queue = m_context.getUniversalQueue();
729
730 const auto mipLevel = m_params.getSelectedLevel();
731 const auto fullExtent = makeExtent3D(m_params.width, m_params.height, m_params.depth);
732 const auto sliceExtent = m_params.getSliceExtent();
733 const auto tcuFormat = mapVkFormat(kFormat);
734 const auto auxiliarBuffer = makeAndFillTransferBuffer(sliceExtent, tcuFormat, vkd, device, alloc);
735 const auto verifBuffer = makeTransferBuffer(sliceExtent, tcuFormat, vkd, device, alloc);
736 const auto fullImage = make3DImage(vkd, device, alloc, kFormat, fullExtent, m_params.getFullImageLevels(), m_params.sampleImg);
737 const auto fullSRR = makeCommonImageSubresourceRange(0u, VK_REMAINING_MIP_LEVELS);
738 const auto singleSRR = makeCommonImageSubresourceRange(0u, 1u);
739 const auto targetLevelSRL = makeCommonImageSubresourceLayers(mipLevel);
740 const auto baseLevelSRL = makeCommonImageSubresourceLayers(0u);
741 const auto clearColor = makeClearValueColorU32(0u, 0u, 0u, 0u);
742 const auto pipelineStage = makePipelineStage(m_params.stage);
743
744 const auto cmdPool = makeCommandPool(vkd, device, qfIndex);
745 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
746 const auto cmdBuffer = cmdBufferPtr.get();
747
748 beginCommandBuffer(vkd, cmdBuffer);
749
750 // Zero-out full image.
751 const auto preClearBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT,
752 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
753 fullImage->get(), fullSRR);
754 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, 0u, VK_PIPELINE_STAGE_TRANSFER_BIT, &preClearBarrier);
755 vkd.cmdClearColorImage(cmdBuffer, fullImage->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor.color, 1u, &fullSRR);
756
757 // Copy reference buffer to full image at the right offset.
758 const auto preCopyBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
759 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
760 fullImage->get(), fullSRR);
761 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &preCopyBarrier);
762
763 const VkBufferImageCopy sliceCopy =
764 {
765 0ull, // VkDeviceSize bufferOffset;
766 0u, // deUint32 bufferRowLength;
767 0u, // deUint32 bufferImageHeight;
768 targetLevelSRL, // VkImageSubresourceLayers imageSubresource;
769 makeOffset3D(0, 0, static_cast<int32_t>(m_params.offset)), // VkOffset3D imageOffset;
770 sliceExtent, // VkExtent3D imageExtent;
771 };
772 vkd.cmdCopyBufferToImage(cmdBuffer, auxiliarBuffer->get(), fullImage->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &sliceCopy);
773
774 // Move full image to the general layout to be able to read from or write to it from the shader.
775 // Note: read-only optimal is not a valid layout for this.
776 const auto postCopyBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
777 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, kUsageLayout,
778 fullImage->get(), fullSRR);
779 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, pipelineStage, &postCopyBarrier);
780
781 // Create sliced view of the full image.
782 const auto slicedView = make3DImageView(vkd, device, fullImage->get(), kFormat, tcu::just(tcu::UVec2(m_params.offset, m_params.getSlicedViewRange())), mipLevel, 1u);
783
784 // Create storage image and view with reduced size (this will be the destination image in the shader).
785 const auto auxiliarImage = make3DImage(vkd, device, alloc, kFormat, sliceExtent, 1u, false/*sampling*/);
786 const auto auxiliarView = make3DImageView(vkd, device, auxiliarImage->get(), kFormat, tcu::Nothing, 0u, 1u);
787
788 // Move the auxiliar image to the general layout for writing.
789 const auto preWriteBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, kUsageLayout, auxiliarImage->get(), singleSRR);
790 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, 0u, pipelineStage, &preWriteBarrier);
791
792 // Run load operation.
793 runPipeline(vkd, device, cmdBuffer, slicedView.get(), auxiliarView.get());
794
795 // Copy auxiliar image (result) to verification buffer.
796 const auto preVerifCopyBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
797 cmdPipelineMemoryBarrier(vkd, cmdBuffer, pipelineStage, VK_PIPELINE_STAGE_TRANSFER_BIT, &preVerifCopyBarrier);
798 const auto verifCopyRegion = makeBufferImageCopy(sliceExtent, baseLevelSRL);
799 vkd.cmdCopyImageToBuffer(cmdBuffer, auxiliarImage->get(), kUsageLayout, verifBuffer->get(), 1u, &verifCopyRegion);
800
801 // Sync verification buffer with host reads.
802 const auto preHostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
803 cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier);
804
805 endCommandBuffer(vkd, cmdBuffer);
806 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
807
808 const auto sliceExtentIV3 = makeIVec3(sliceExtent.width, sliceExtent.height, sliceExtent.depth);
809 auto& auxiliarBufferAlloc = auxiliarBuffer->getAllocation();
810 auto& verifBufferAlloc = verifBuffer->getAllocation();
811
812 // Invalidate verification buffer allocation.
813 invalidateAlloc(vkd, device, verifBufferAlloc);
814
815 // Compare auxiliar buffer and verification buffer.
816 const tcu::ConstPixelBufferAccess initialImage (tcuFormat, sliceExtentIV3, auxiliarBufferAlloc.getHostPtr());
817 const tcu::ConstPixelBufferAccess finalImage (tcuFormat, sliceExtentIV3, verifBufferAlloc.getHostPtr());
818
819 auto& log = m_context.getTestContext().getLog();
820 const tcu::UVec4 threshold(0u, 0u, 0u, 0u);
821
822 if (!tcu::intThresholdCompare(log, "Comparison", "Comparison of reference and result", initialImage, finalImage, threshold, tcu::COMPARE_LOG_ON_ERROR))
823 return tcu::TestStatus::fail("Image comparison failed; check log for details");
824
825 if (m_params.sampleImg && !runSamplingPipeline(fullImage->get(), slicedView.get(), m_params.getFullLevelExtent()))
826 return tcu::TestStatus::fail("Sampling full level failed; check log for details");
827
828 return tcu::TestStatus::pass("Pass");
829 }
830
iterate(void)831 tcu::TestStatus SlicedViewStoreTestInstance::iterate (void)
832 {
833 const auto& vkd = m_context.getDeviceInterface();
834 const auto device = m_context.getDevice();
835 auto& alloc = m_context.getDefaultAllocator();
836 const auto qfIndex = m_context.getUniversalQueueFamilyIndex();
837 const auto queue = m_context.getUniversalQueue();
838
839 const auto mipLevel = m_params.getSelectedLevel();
840 const auto fullExtent = makeExtent3D(m_params.width, m_params.height, m_params.depth);
841 const auto sliceExtent = m_params.getSliceExtent();
842 const auto tcuFormat = mapVkFormat(kFormat);
843 const auto auxiliarBuffer = makeAndFillTransferBuffer(sliceExtent, tcuFormat, vkd, device, alloc);
844 const auto verifBuffer = makeTransferBuffer(sliceExtent, tcuFormat, vkd, device, alloc);
845 const auto fullImage = make3DImage(vkd, device, alloc, kFormat, fullExtent, m_params.getFullImageLevels(), m_params.sampleImg);
846 const auto fullSRR = makeCommonImageSubresourceRange(0u, VK_REMAINING_MIP_LEVELS);
847 const auto singleSRR = makeCommonImageSubresourceRange(0u, 1u);
848 const auto targetLevelSRL = makeCommonImageSubresourceLayers(mipLevel);
849 const auto baseLevelSRL = makeCommonImageSubresourceLayers(0u);
850 const auto clearColor = makeClearValueColorU32(0u, 0u, 0u, 0u);
851 const auto pipelineStage = makePipelineStage(m_params.stage);
852
853 const auto cmdPool = makeCommandPool(vkd, device, qfIndex);
854 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
855 const auto cmdBuffer = cmdBufferPtr.get();
856
857 beginCommandBuffer(vkd, cmdBuffer);
858
859 // Zero-out full image.
860 const auto preClearBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, fullImage->get(), fullSRR);
861 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, 0u, VK_PIPELINE_STAGE_TRANSFER_BIT, &preClearBarrier);
862 vkd.cmdClearColorImage(cmdBuffer, fullImage->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor.color, 1u, &fullSRR);
863
864 // Create sliced view of the full image.
865 const auto slicedView = make3DImageView(vkd, device, fullImage->get(), kFormat, tcu::just(tcu::UVec2(m_params.offset, m_params.getSlicedViewRange())), mipLevel, 1u);
866
867 // Create storage image and view with reduced size (this will be the source image in the shader).
868 const auto auxiliarImage = make3DImage(vkd, device, alloc, kFormat, sliceExtent, 1u, false/*sampling*/);
869 const auto auxiliarView = make3DImageView(vkd, device, auxiliarImage->get(), kFormat, tcu::Nothing, 0u, 1u);
870
871 // Copy reference buffer into auxiliar image.
872 const auto preCopyBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, auxiliarImage->get(), singleSRR);
873 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, 0u, VK_PIPELINE_STAGE_TRANSFER_BIT, &preCopyBarrier);
874 const auto sliceCopy = makeBufferImageCopy(sliceExtent, baseLevelSRL);
875 vkd.cmdCopyBufferToImage(cmdBuffer, auxiliarBuffer->get(), auxiliarImage->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &sliceCopy);
876
877 // Move both images to the general layout for reading and writing.
878 // Note: read-only optimal is not a valid layout for the read image.
879 const auto preShaderBarrierAux = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, kUsageLayout, auxiliarImage->get(), singleSRR);
880 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, pipelineStage, &preShaderBarrierAux);
881 const auto preShaderBarrierFull = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, kUsageLayout, fullImage->get(), fullSRR);
882 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, pipelineStage, &preShaderBarrierFull);
883
884 // Run store operation.
885 runPipeline(vkd, device, cmdBuffer, slicedView.get(), auxiliarView.get());
886
887 // Copy the right section of the full image (result) to verification buffer.
888 const auto preVerifCopyBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
889 cmdPipelineMemoryBarrier(vkd, cmdBuffer, pipelineStage, VK_PIPELINE_STAGE_TRANSFER_BIT, &preVerifCopyBarrier);
890
891 const VkBufferImageCopy verifCopy =
892 {
893 0ull, // VkDeviceSize bufferOffset;
894 0u, // deUint32 bufferRowLength;
895 0u, // deUint32 bufferImageHeight;
896 targetLevelSRL, // VkImageSubresourceLayers imageSubresource;
897 makeOffset3D(0, 0, static_cast<int32_t>(m_params.offset)), // VkOffset3D imageOffset;
898 sliceExtent, // VkExtent3D imageExtent;
899 };
900 vkd.cmdCopyImageToBuffer(cmdBuffer, fullImage->get(), kUsageLayout, verifBuffer->get(), 1u, &verifCopy);
901
902 // Sync verification buffer with host reads.
903 const auto preHostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
904 cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &preHostBarrier);
905
906 endCommandBuffer(vkd, cmdBuffer);
907 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
908
909 const auto sliceExtentIV3 = makeIVec3(sliceExtent.width, sliceExtent.height, sliceExtent.depth);
910 auto& auxiliarBufferAlloc = auxiliarBuffer->getAllocation();
911 auto& verifBufferAlloc = verifBuffer->getAllocation();
912
913 // Invalidate verification buffer allocation.
914 invalidateAlloc(vkd, device, verifBufferAlloc);
915
916 // Compare auxiliar buffer and verification buffer.
917 const tcu::ConstPixelBufferAccess initialImage (tcuFormat, sliceExtentIV3, auxiliarBufferAlloc.getHostPtr());
918 const tcu::ConstPixelBufferAccess finalImage (tcuFormat, sliceExtentIV3, verifBufferAlloc.getHostPtr());
919
920 auto& log = m_context.getTestContext().getLog();
921 const tcu::UVec4 threshold(0u, 0u, 0u, 0u);
922
923 if (!tcu::intThresholdCompare(log, "Comparison", "Comparison of reference and result", initialImage, finalImage, threshold, tcu::COMPARE_LOG_ON_ERROR))
924 return tcu::TestStatus::fail("Image comparison failed; check log for details");
925
926 if (m_params.sampleImg && !runSamplingPipeline(fullImage->get(), slicedView.get(), m_params.getFullLevelExtent()))
927 return tcu::TestStatus::fail("Sampling full level failed; check log for details");
928
929 return tcu::TestStatus::pass("Pass");
930 }
931
932 using TestCaseGroupPtr = de::MovePtr<tcu::TestCaseGroup>;
933
934 } // anonymous
935
createImageSlicedViewOf3DTests(tcu::TestContext & testCtx)936 tcu::TestCaseGroup* createImageSlicedViewOf3DTests (tcu::TestContext& testCtx)
937 {
938 TestCaseGroupPtr imageTests (new tcu::TestCaseGroup(testCtx, "sliced_view_of_3d_image"));
939
940 const struct
941 {
942 VkShaderStageFlagBits stage;
943 const char* name;
944 } stageCases[] =
945 {
946 { VK_SHADER_STAGE_COMPUTE_BIT, "comp" },
947 { VK_SHADER_STAGE_FRAGMENT_BIT, "frag" },
948 };
949
950 const struct
951 {
952 TestType testType;
953 const char* name;
954 } testTypeCases[] =
955 {
956 { TestType::LOAD, "load" },
957 { TestType::STORE, "store" },
958 };
959
960 const struct
961 {
962 bool sampleImg;
963 const char* suffix;
964 } samplingCases[] =
965 {
966 { false, "" },
967 { true, "_with_sampling" },
968 };
969
970 const uint32_t seed = 1667817299u;
971 de::Random rnd (seed);
972
973 // Basic tests with 2 slices and a view of the first or second slice.
974 {
975 const uint32_t basicDepth = 2u;
976 const uint32_t basicRange = 1u;
977
978 TestCaseGroupPtr basicTests (new tcu::TestCaseGroup(testCtx, "basic"));
979
980 for (const auto& testTypeCase : testTypeCases)
981 {
982 TestCaseGroupPtr testTypeGroup (new tcu::TestCaseGroup(testCtx, testTypeCase.name));
983
984 for (const auto& stageCase : stageCases)
985 {
986 TestCaseGroupPtr stageGroup (new tcu::TestCaseGroup(testCtx, stageCase.name));
987
988 for (uint32_t offset = 0u; offset < basicDepth; ++offset)
989 {
990 for (const auto& samplingCase : samplingCases)
991 {
992 const auto testName = "offset_" + std::to_string(offset) + samplingCase.suffix;
993 TestParams params (testTypeCase.testType, stageCase.stage, kWidth, kHeight, basicDepth, offset, basicRange, tcu::Nothing, samplingCase.sampleImg);
994
995 stageGroup->addChild(new SlicedViewTestCase(testCtx, testName, params));
996 }
997 }
998
999 testTypeGroup->addChild(stageGroup.release());
1000 }
1001
1002 basicTests->addChild(testTypeGroup.release());
1003 }
1004
1005 imageTests->addChild(basicTests.release());
1006 }
1007
1008 // Full slice tests.
1009 {
1010 const uint32_t fullDepth = 4u;
1011
1012 TestCaseGroupPtr fullSliceTests (new tcu::TestCaseGroup(testCtx, "full_slice"));
1013
1014 for (const auto& testTypeCase : testTypeCases)
1015 {
1016 TestCaseGroupPtr testTypeGroup (new tcu::TestCaseGroup(testCtx, testTypeCase.name));
1017
1018 for (const auto& stageCase : stageCases)
1019 {
1020 for (const auto& samplingCase : samplingCases)
1021 {
1022 const auto testName = std::string(stageCase.name) + samplingCase.suffix;
1023 TestParams params (testTypeCase.testType, stageCase.stage, kWidth, kHeight, fullDepth, 0u, fullDepth, tcu::Nothing, samplingCase.sampleImg);
1024 testTypeGroup->addChild(new SlicedViewTestCase(testCtx, testName, params));
1025 }
1026 }
1027
1028 fullSliceTests->addChild(testTypeGroup.release());
1029 }
1030
1031 imageTests->addChild(fullSliceTests.release());
1032 }
1033
1034 // Pseudorandom test cases.
1035 {
1036 using CaseId = std::tuple<uint32_t, uint32_t, uint32_t>; // depth, offset, range
1037 using CaseIdSet = std::set<CaseId>;
1038
1039 const uint32_t depthCases = 5u;
1040 const uint32_t rangeCases = 5u;
1041 const int minDepth = 10u;
1042 const int maxDepth = 32u;
1043
1044 TestCaseGroupPtr randomTests (new tcu::TestCaseGroup(testCtx, "random"));
1045
1046 for (const auto& testTypeCase : testTypeCases)
1047 {
1048 TestCaseGroupPtr testTypeGroup (new tcu::TestCaseGroup(testCtx, testTypeCase.name));
1049
1050 for (const auto& stageCase : stageCases)
1051 {
1052 TestCaseGroupPtr stageGroup (new tcu::TestCaseGroup(testCtx, stageCase.name));
1053
1054 CaseIdSet generatedCases;
1055
1056 for (uint32_t i = 0u; i < depthCases; ++i)
1057 {
1058 const uint32_t depth = static_cast<uint32_t>(rnd.getInt(minDepth, maxDepth));
1059
1060 for (uint32_t j = 0u; j < rangeCases; ++j)
1061 {
1062 uint32_t offset = 0u;
1063 uint32_t range = 0u;
1064
1065 for (;;)
1066 {
1067 DE_ASSERT(depth > 0u);
1068 offset = static_cast<uint32_t>(rnd.getInt(0, static_cast<int>(depth - 1u)));
1069
1070 DE_ASSERT(offset < depth);
1071 range = static_cast<uint32_t>(rnd.getInt(0, static_cast<int>(depth - offset)));
1072
1073 // 0 is interpreted as VK_REMAINING_3D_SLICES_EXT.
1074 if (range == 0u)
1075 range = VK_REMAINING_3D_SLICES_EXT;
1076
1077 // The current seed may generate duplicate cases with non-unique names, so we filter those out.
1078 const CaseId currentCase (depth, offset, range);
1079 if (de::contains(begin(generatedCases), end(generatedCases), currentCase))
1080 continue;
1081
1082 generatedCases.insert(currentCase);
1083 break;
1084 }
1085
1086 const auto rangeStr = ((range == VK_REMAINING_3D_SLICES_EXT) ? "remaining_3d_slices" : std::to_string(range));
1087 const auto testName = "depth_" + std::to_string(depth) + "_offset_" + std::to_string(offset) + "_range_" + rangeStr;
1088 TestParams params (testTypeCase.testType, stageCase.stage, kWidth, kHeight, depth, offset, range, tcu::Nothing, false);
1089
1090 stageGroup->addChild(new SlicedViewTestCase(testCtx, testName, params));
1091 }
1092 }
1093
1094 testTypeGroup->addChild(stageGroup.release());
1095 }
1096
1097 randomTests->addChild(testTypeGroup.release());
1098 }
1099
1100 imageTests->addChild(randomTests.release());
1101 }
1102
1103 // Mip level test cases.
1104 {
1105 using CaseId = std::tuple<uint32_t, uint32_t>; // depth, offset, range
1106 using CaseIdSet = std::set<CaseId>;
1107
1108 const uint32_t casesPerLevel = 2u;
1109 const uint32_t width = kWidth;
1110 const uint32_t height = kWidth;
1111 const uint32_t depth = kWidth;
1112 const uint32_t maxLevels = TestParams::getMaxMipLevelCountForSize(kWidth);
1113
1114 TestCaseGroupPtr mipLevelTests (new tcu::TestCaseGroup(testCtx, "mip_level"));
1115
1116 for (const auto& testTypeCase : testTypeCases)
1117 {
1118 TestCaseGroupPtr testTypeGroup (new tcu::TestCaseGroup(testCtx, testTypeCase.name));
1119
1120 for (const auto& stageCase : stageCases)
1121 {
1122 TestCaseGroupPtr stageGroup (new tcu::TestCaseGroup(testCtx, stageCase.name));
1123
1124 for (uint32_t level = 0u; level < maxLevels; ++level)
1125 {
1126 const auto levelSize = (depth >> level);
1127 const auto groupName = "level_" + std::to_string(level);
1128 CaseIdSet generatedCases;
1129
1130 DE_ASSERT(levelSize > 0u);
1131
1132 TestCaseGroupPtr levelGroup (new tcu::TestCaseGroup(testCtx, groupName.c_str()));
1133
1134 // Generate a few pseudorandom cases per mip level.
1135 for (uint32_t i = 0u; i < casesPerLevel; ++i)
1136 {
1137 uint32_t offset = 0u;
1138 uint32_t range = 0u;
1139
1140 for (;;)
1141 {
1142 offset = static_cast<uint32_t>(rnd.getInt(0, static_cast<int>(levelSize - 1u)));
1143 DE_ASSERT(offset < levelSize);
1144
1145 range = static_cast<uint32_t>(rnd.getInt(0, static_cast<int>(levelSize - offset)));
1146
1147 // 0 is interpreted as VK_REMAINING_3D_SLICES_EXT.
1148 if (range == 0u)
1149 range = VK_REMAINING_3D_SLICES_EXT;
1150
1151 const CaseId currentCase (offset, range);
1152 if (de::contains(begin(generatedCases), end(generatedCases), currentCase))
1153 continue;
1154
1155 generatedCases.insert(currentCase);
1156 break;
1157 }
1158
1159 const auto rangeStr = ((range == VK_REMAINING_3D_SLICES_EXT) ? "remaining_3d_slices" : std::to_string(range));
1160 const auto testName = "offset_" + std::to_string(offset) + "_range_" + rangeStr;
1161 TestParams params (testTypeCase.testType, stageCase.stage, width, height, depth, offset, range, tcu::just(level), false);
1162
1163 levelGroup->addChild(new SlicedViewTestCase(testCtx, testName, params));
1164 }
1165
1166 stageGroup->addChild(levelGroup.release());
1167 }
1168
1169 testTypeGroup->addChild(stageGroup.release());
1170 }
1171
1172 mipLevelTests->addChild(testTypeGroup.release());
1173 }
1174
1175 imageTests->addChild(mipLevelTests.release());
1176 }
1177
1178 return imageTests.release();
1179 }
1180
1181 } // pipeline
1182 } // vkt
1183