1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2022 The Khronos Group Inc.
6 * Copyright (c) 2022 Google LLC.
7 * Copyright (c) 2023 LunarG, Inc.
8 * Copyright (c) 2023 Nintendo
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 *//*!
23 * \file
24 * \brief
25 *//*--------------------------------------------------------------------*/
26
27 #include "vktPipelineImage2DViewOf3DTests.hpp"
28 #include "vkPipelineConstructionUtil.hpp"
29 #include "vktTestCase.hpp"
30 #include "vkImageUtil.hpp"
31 #include "vkPrograms.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vkCmdUtil.hpp"
35 #include "vkBuilderUtil.hpp"
36 #include "vkImageWithMemory.hpp"
37 #include "vkBufferWithMemory.hpp"
38 #include "vkBarrierUtil.hpp"
39 #include "tcuTexture.hpp"
40 #include "tcuPlatform.hpp"
41 #include "tcuImageCompare.hpp"
42 #include "deMemory.h"
43
44 #include <cstdint>
45 #include <sstream>
46 #include <vector>
47
48 namespace vkt
49 {
50 namespace pipeline
51 {
52
53 using namespace vk;
54 using de::MovePtr;
55
56 namespace
57 {
58
59 using DeviceMemorySp = de::SharedPtr<vk::Unique<vk::VkDeviceMemory>>;
60
61 enum ImageAccessType
62 {
63 StorageImage = 0,
64 Sampler,
65 CombinedImageSampler
66 };
67
68 enum ImageBindingType
69 {
70 Normal = 0,
71 Sparse,
72 };
73
74 enum TestType
75 {
76 Compute,
77 Fragment
78 };
79
80 struct TestParameters
81 {
82 tcu::IVec3 imageSize;
83 uint32_t mipLevel;
84 int32_t layerNdx;
85 ImageAccessType imageType;
86 TestType testType;
87 VkFormat imageFormat;
88 PipelineConstructionType pipelineConstructionType;
89 ImageBindingType imageBindingType;
90 };
91
computeMipLevelDimension(int32_t baseLevelDimension,uint32_t mipLevel)92 inline int32_t computeMipLevelDimension(int32_t baseLevelDimension, uint32_t mipLevel)
93 {
94 return de::max(baseLevelDimension >> mipLevel, 1);
95 }
96
computeMipLevelSize(tcu::IVec3 baseLevelSize,uint32_t mipLevel)97 tcu::IVec3 computeMipLevelSize(tcu::IVec3 baseLevelSize, uint32_t mipLevel)
98 {
99 int32_t width = computeMipLevelDimension(baseLevelSize.x(), mipLevel);
100 int32_t height = computeMipLevelDimension(baseLevelSize.y(), mipLevel);
101 int32_t depth = computeMipLevelDimension(baseLevelSize.z(), mipLevel);
102 return tcu::IVec3(width, height, depth);
103 }
104
copyImageLayerToBuffer(const DeviceInterface & vk,VkCommandBuffer cmdBuffer,VkImage image,VkBuffer buffer,tcu::IVec2 size,VkAccessFlags srcAccessMask,VkImageLayout oldLayout,uint32_t layerToCopy,uint32_t mipLevel)105 void copyImageLayerToBuffer(const DeviceInterface &vk, VkCommandBuffer cmdBuffer, VkImage image, VkBuffer buffer,
106 tcu::IVec2 size, VkAccessFlags srcAccessMask, VkImageLayout oldLayout, uint32_t layerToCopy,
107 uint32_t mipLevel)
108 {
109 const VkImageSubresourceRange subresourceRange =
110 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 1u, 0, 1u);
111 const VkImageMemoryBarrier imageBarrier = {
112 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType
113 nullptr, // const void* pNext
114 srcAccessMask, // VkAccessFlags srcAccessMask
115 VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask
116 oldLayout, // VkImageLayout oldLayout
117 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout
118 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
119 VK_QUEUE_FAMILY_IGNORED, // uint32_t destQueueFamilyIndex
120 image, // VkImage image
121 subresourceRange // VkImageSubresourceRange subresourceRange
122 };
123
124 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u,
125 nullptr, 0u, nullptr, 1u, &imageBarrier);
126
127 const VkImageSubresourceLayers subresource = {
128 subresourceRange.aspectMask, // VkImageAspectFlags aspectMask
129 mipLevel, // uint32_t mipLevel
130 0u, // uint32_t baseArrayLayer
131 1u, // uint32_t layerCount
132 };
133
134 const VkBufferImageCopy region = {
135 0ull, // VkDeviceSize bufferOffset
136 0u, // uint32_t bufferRowLength
137 0u, // uint32_t bufferImageHeight
138 subresource, // VkImageSubresourceLayers imageSubresource
139 makeOffset3D(0, 0, (int)layerToCopy), // VkOffset3D imageOffset
140 makeExtent3D(size.x(), size.y(), 1u) // VkExtent3D imageExtent
141 };
142
143 vk.cmdCopyImageToBuffer(cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, 1u, ®ion);
144
145 const VkBufferMemoryBarrier bufferBarrier = {
146 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType
147 nullptr, // const void* pNext
148 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask
149 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask
150 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
151 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex
152 buffer, // VkBuffer buffer
153 0ull, // VkDeviceSize offset
154 VK_WHOLE_SIZE // VkDeviceSize size
155 };
156
157 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, nullptr, 1u,
158 &bufferBarrier, 0u, nullptr);
159 }
160
161 // Draws a chess pattern to the given 'layer' (z-dimension) of the 'image'. Other layers will be cleared to white.
fillImage(const tcu::PixelBufferAccess & image,const int layer)162 void fillImage(const tcu::PixelBufferAccess &image, const int layer)
163 {
164 const tcu::Vec4 clearColor = tcu::Vec4(1); // White clear color.
165 for (int z = 0; z < image.getSize().z(); ++z)
166 for (int y = 0; y < image.getSize().y(); ++y)
167 for (int x = 0; x < image.getSize().x(); ++x)
168 {
169 if (z == layer)
170 {
171 const float c = (float)((x + y) & 1);
172 const tcu::Vec4 color = tcu::Vec4(c, c, c, 1.0f);
173 image.setPixel(color, x, y, z);
174 }
175 else
176 {
177 image.setPixel(clearColor, x, y, z);
178 }
179 }
180 }
181
182 template <typename T>
makeVkSharedPtr(vk::Move<T> vkMove)183 inline de::SharedPtr<vk::Unique<T>> makeVkSharedPtr(vk::Move<T> vkMove)
184 {
185 return de::SharedPtr<vk::Unique<T>>(new vk::Unique<T>(vkMove));
186 }
187
getMemoryType(const InstanceInterface & instance,const VkPhysicalDevice physicalDevice,const VkMemoryRequirements & objectMemoryRequirements,const MemoryRequirement & memoryRequirement,uint32_t & memTypeIdx)188 bool getMemoryType(const InstanceInterface &instance, const VkPhysicalDevice physicalDevice,
189 const VkMemoryRequirements &objectMemoryRequirements, const MemoryRequirement &memoryRequirement,
190 uint32_t &memTypeIdx)
191 {
192 bool memTypeFound = false;
193 const VkPhysicalDeviceMemoryProperties deviceMemoryProperties =
194 getPhysicalDeviceMemoryProperties(instance, physicalDevice);
195
196 for (uint32_t memoryTypeIdx = 0; !memTypeFound && memoryTypeIdx < deviceMemoryProperties.memoryTypeCount;
197 ++memoryTypeIdx)
198 {
199 if ((objectMemoryRequirements.memoryTypeBits & (1u << memoryTypeIdx)) != 0 &&
200 memoryRequirement.matchesHeap(deviceMemoryProperties.memoryTypes[memoryTypeIdx].propertyFlags))
201 {
202 memTypeIdx = memoryTypeIdx;
203 memTypeFound = true;
204 }
205 }
206 return memTypeFound;
207 }
208
makeSparseMemoryBinding(const DeviceInterface & vk,const VkDevice device,const VkDeviceSize allocationSize,const uint32_t memoryType,const VkDeviceSize resourceOffset,const VkSparseMemoryBindFlags flags)209 VkSparseMemoryBind makeSparseMemoryBinding(const DeviceInterface &vk, const VkDevice device,
210 const VkDeviceSize allocationSize, const uint32_t memoryType,
211 const VkDeviceSize resourceOffset, const VkSparseMemoryBindFlags flags)
212 {
213 const VkMemoryAllocateInfo allocInfo = {
214 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType;
215 nullptr, // const void* pNext;
216 allocationSize, // VkDeviceSize allocationSize;
217 memoryType, // uint32_t memoryTypeIndex;
218 };
219
220 VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
221 VK_CHECK(vk.allocateMemory(device, &allocInfo, VK_NULL_HANDLE, &deviceMemory));
222
223 VkSparseMemoryBind memoryBind;
224
225 memoryBind.resourceOffset = resourceOffset;
226 memoryBind.size = allocationSize;
227 memoryBind.memory = deviceMemory;
228 memoryBind.memoryOffset = 0u;
229 memoryBind.flags = flags;
230
231 return memoryBind;
232 }
233
234 class Image2DView3DImageInstance : public vkt::TestInstance
235 {
236 public:
Image2DView3DImageInstance(Context & context,const TestParameters testParameters)237 Image2DView3DImageInstance(Context &context, const TestParameters testParameters)
238 : vkt::TestInstance(context)
239 , m_testParameters(testParameters)
240 {
241 }
242
243 tcu::TestStatus iterate(void);
244
245 private:
246 void runComputePipeline(const VkDescriptorSet &descriptorSet, const VkDescriptorSetLayout descriptorSetLayout,
247 tcu::IVec3 &testMipLevelSize, VkCommandBuffer cmdBuffer, VkImage image,
248 VkBuffer outputBuffer, const VkSemaphore *sparseImageSemaphore);
249
250 void runGraphicsPipeline(const VkDescriptorSet &descriptorSet, const VkDescriptorSetLayout descriptorSetLayout,
251 tcu::IVec3 &testMipLevelSize, VkCommandBuffer cmdBuffer, VkImage image,
252 VkBuffer outputBuffer, const VkSemaphore *sparseImageSemaphore);
253 const TestParameters m_testParameters;
254 };
255
commonSubmission(const DeviceInterface & vk,const VkDevice & device,const VkQueue & queue,VkCommandBuffer & cmdBuffer,const VkSemaphore * sparseImageSemaphore)256 void commonSubmission(const DeviceInterface &vk, const VkDevice &device, const VkQueue &queue,
257 VkCommandBuffer &cmdBuffer, const VkSemaphore *sparseImageSemaphore)
258 {
259 const VkPipelineStageFlags stageFlags[] = {VK_PIPELINE_STAGE_TRANSFER_BIT};
260 const uint32_t waitSemaphoreCount = (sparseImageSemaphore != nullptr) ? 1u : 0u;
261 const VkPipelineStageFlags *waitStages = (sparseImageSemaphore != nullptr) ? stageFlags : nullptr;
262 submitCommandsAndWait(vk, device, queue, cmdBuffer, /*useDeviceGroups*/ false, /*deviceMask*/ 1u,
263 waitSemaphoreCount, sparseImageSemaphore, waitStages);
264 }
265
runComputePipeline(const VkDescriptorSet & descriptorSet,const VkDescriptorSetLayout descriptorSetLayout,tcu::IVec3 & testMipLevelSize,VkCommandBuffer cmdBuffer,VkImage image,VkBuffer outputBuffer,const VkSemaphore * sparseImageSemaphore)266 void Image2DView3DImageInstance::runComputePipeline(const VkDescriptorSet &descriptorSet,
267 const VkDescriptorSetLayout descriptorSetLayout,
268 tcu::IVec3 &testMipLevelSize, VkCommandBuffer cmdBuffer,
269 VkImage image, VkBuffer outputBuffer,
270 const VkSemaphore *sparseImageSemaphore)
271 {
272 const DeviceInterface &vk = m_context.getDeviceInterface();
273 const VkDevice device = m_context.getDevice();
274 const VkQueue queue = m_context.getUniversalQueue();
275 const bool useSampler = m_testParameters.imageType != StorageImage;
276
277 const Unique<VkShaderModule> shaderModule(
278 createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0u));
279 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, descriptorSetLayout));
280 const Unique<VkPipeline> pipeline(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
281
282 vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
283 vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet, 0u,
284 nullptr);
285 vk.cmdDispatch(cmdBuffer, testMipLevelSize.x(), testMipLevelSize.y(), 1u);
286
287 // Copy the result image to a buffer.
288 copyImageLayerToBuffer(vk, cmdBuffer, image, outputBuffer, testMipLevelSize.xy(), VK_ACCESS_SHADER_WRITE_BIT,
289 VK_IMAGE_LAYOUT_GENERAL, useSampler ? 0u : m_testParameters.layerNdx,
290 useSampler ? 0u : m_testParameters.mipLevel);
291
292 endCommandBuffer(vk, cmdBuffer);
293
294 // Wait for completion.
295 commonSubmission(vk, device, queue, cmdBuffer, sparseImageSemaphore);
296 }
297
runGraphicsPipeline(const VkDescriptorSet & descriptorSet,const VkDescriptorSetLayout descriptorSetLayout,tcu::IVec3 & testMipLevelSize,VkCommandBuffer cmdBuffer,VkImage image,VkBuffer outputBuffer,const VkSemaphore * sparseImageSemaphore)298 void Image2DView3DImageInstance::runGraphicsPipeline(const VkDescriptorSet &descriptorSet,
299 const VkDescriptorSetLayout descriptorSetLayout,
300 tcu::IVec3 &testMipLevelSize, VkCommandBuffer cmdBuffer,
301 VkImage image, VkBuffer outputBuffer,
302 const VkSemaphore *sparseImageSemaphore)
303 {
304 const InstanceInterface &vki = m_context.getInstanceInterface();
305 const DeviceInterface &vk = m_context.getDeviceInterface();
306 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
307 const VkDevice device = m_context.getDevice();
308 const VkQueue queue = m_context.getUniversalQueue();
309 const bool useSampler = m_testParameters.imageType != StorageImage;
310
311 const ShaderWrapper vertShader(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
312 const ShaderWrapper fragShader(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
313 const PipelineLayoutWrapper pipelineLayout(m_testParameters.pipelineConstructionType, vk, device,
314 descriptorSetLayout);
315 RenderPassWrapper renderPass(m_testParameters.pipelineConstructionType, vk, device);
316 const std::vector<VkViewport> viewport = {
317 makeViewport(m_testParameters.imageSize.x(), m_testParameters.imageSize.y())};
318 const std::vector<VkRect2D> scissor = {makeRect2D(m_testParameters.imageSize.x(), m_testParameters.imageSize.y())};
319
320 const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
321 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType
322 nullptr, // const void* pNext
323 0u, // VkPipelineInputAssemblyStateCreateFlags flags
324 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, // VkPrimitiveTopology topology
325 VK_FALSE // VkBool32 primitiveRestartEnable
326 };
327
328 const VkVertexInputBindingDescription vertexInputBindingDescription = {
329 0u, // uint32_t binding
330 sizeof(tcu::Vec4), // uint32_t stride
331 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate
332 };
333
334 const VkVertexInputAttributeDescription vertexInputAttributeDescription = {
335 0u, // uint32_t location
336 0u, // uint32_t binding
337 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format
338 0u // uint32_t offset
339 };
340
341 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfoDefault = {
342 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType
343 nullptr, // const void* pNext
344 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags
345 1u, // uint32_t vertexBindingDescriptionCount
346 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions
347 1u, // uint32_t vertexAttributeDescriptionCount
348 &vertexInputAttributeDescription // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions
349 };
350
351 vk::GraphicsPipelineWrapper graphicsPipeline(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(),
352 m_testParameters.pipelineConstructionType, 0u);
353 graphicsPipeline.setMonolithicPipelineLayout(pipelineLayout)
354 .setDefaultDepthStencilState()
355 .setDefaultRasterizationState()
356 .setDefaultMultisampleState()
357 .setupVertexInputState(&vertexInputStateCreateInfoDefault, &inputAssemblyStateCreateInfo)
358 .setupPreRasterizationShaderState(viewport, scissor, pipelineLayout, *renderPass, 0u, vertShader)
359 .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragShader)
360 .setupFragmentOutputState(*renderPass, 0u)
361 .buildPipeline();
362
363 renderPass.createFramebuffer(vk, device, 0u, nullptr, nullptr, testMipLevelSize.x(), testMipLevelSize.y());
364
365 // Create vertex buffer and fill it with full screen quad.
366 const std::vector<tcu::Vec4> vertexData = {
367 {-1, -1, 1, 1},
368 {1, -1, 1, 1},
369 {1, 1, 1, 1},
370 {-1, 1, 1, 1},
371 };
372 size_t vertexBufferSize = sizeof(tcu::Vec4) * vertexData.size();
373 BufferWithMemory vertexBuffer(vk, device, m_context.getDefaultAllocator(),
374 makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
375 MemoryRequirement::HostVisible);
376 deMemcpy(vertexBuffer.getAllocation().getHostPtr(), vertexData.data(), vertexBufferSize);
377 flushAlloc(vk, device, vertexBuffer.getAllocation());
378
379 VkDeviceSize vertexBufferOffset = 0;
380 vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &*vertexBuffer, &vertexBufferOffset);
381
382 graphicsPipeline.bind(cmdBuffer);
383 vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet, 0u,
384 nullptr);
385
386 renderPass.begin(vk, cmdBuffer, makeRect2D(testMipLevelSize.xy()));
387 vk.cmdDraw(cmdBuffer, 4, 1, 0, 0);
388 renderPass.end(vk, cmdBuffer);
389
390 // Copy the result image to a buffer.
391 copyImageLayerToBuffer(vk, cmdBuffer, image, outputBuffer, testMipLevelSize.xy(), VK_ACCESS_SHADER_WRITE_BIT,
392 VK_IMAGE_LAYOUT_GENERAL, useSampler ? 0u : m_testParameters.layerNdx,
393 useSampler ? 0u : m_testParameters.mipLevel);
394
395 endCommandBuffer(vk, cmdBuffer);
396
397 // Wait for completion.
398 commonSubmission(vk, device, queue, cmdBuffer, sparseImageSemaphore);
399 }
400
iterate(void)401 tcu::TestStatus Image2DView3DImageInstance::iterate(void)
402 {
403 const DeviceInterface &vk = m_context.getDeviceInterface();
404 const VkDevice device = m_context.getDevice();
405 const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
406 Allocator &allocator = m_context.getDefaultAllocator();
407 tcu::IVec3 imageSize = m_testParameters.imageSize;
408 const bool useSampler = m_testParameters.imageType != StorageImage;
409 const bool useSparseBinding = m_testParameters.imageBindingType == Sparse;
410 const tcu::TextureFormat textureFormat = mapVkFormat(m_testParameters.imageFormat);
411 const uint32_t mipLevelCount = 3;
412
413 tcu::IVec3 testMipLevelSize = computeMipLevelSize(m_testParameters.imageSize, m_testParameters.mipLevel);
414 uint32_t bufferSize =
415 testMipLevelSize.x() * testMipLevelSize.y() * testMipLevelSize.z() * textureFormat.getPixelSize();
416 const BufferWithMemory outputBuffer(vk, device, allocator,
417 makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT),
418 MemoryRequirement::HostVisible);
419
420 // Input image is used with sampler cases only.
421 de::MovePtr<BufferWithMemory> inputImageBuffer;
422
423 // Upload the test image data for sampler cases.
424 if (useSampler)
425 {
426 // Initialize the input image's mip level and fill the target layer with a chess pattern, others will be white.
427 tcu::TextureLevel inputImageMipLevel(textureFormat, testMipLevelSize.x(), testMipLevelSize.y(),
428 testMipLevelSize.z());
429 fillImage(inputImageMipLevel.getAccess(), m_testParameters.layerNdx);
430
431 // Create a buffer to upload the image.
432 const VkBufferCreateInfo bufferCreateInfo =
433 makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
434 inputImageBuffer = de::MovePtr<BufferWithMemory>(
435 new BufferWithMemory(vk, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible));
436
437 // Upload target mip level to the input buffer.
438 deMemcpy(inputImageBuffer->getAllocation().getHostPtr(), inputImageMipLevel.getAccess().getDataPtr(),
439 bufferSize);
440 flushAlloc(vk, device, inputImageBuffer->getAllocation());
441 }
442
443 VkImageCreateFlags flags = VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT;
444
445 if (useSparseBinding)
446 flags |= VK_IMAGE_CREATE_SPARSE_BINDING_BIT;
447
448 // Create the test image: sampled image or storage image, depending on the test type.
449 const VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
450 (useSampler ? VK_IMAGE_USAGE_SAMPLED_BIT : VK_IMAGE_USAGE_STORAGE_BIT);
451 const VkImageCreateInfo imageCreateInfo = {
452 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType
453 nullptr, // const void* pNext
454 flags, // VkImageCreateFlags flags
455 VK_IMAGE_TYPE_3D, // VkImageType imageType
456 m_testParameters.imageFormat, // VkFormat format
457 makeExtent3D(imageSize.x(), imageSize.y(), imageSize.z()), // VkExtent3D extent
458 (uint32_t)mipLevelCount, // uint32_t mipLevels
459 1u, // uint32_t arrayLayers
460 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
461 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling
462 usage, // VkImageUsageFlags usage
463 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode
464 0u, // uint32_t queueFamilyIndexCount
465 nullptr, // const uint32_t* pQueueFamilyIndices
466 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
467 };
468
469 de::MovePtr<ImageWithMemory> normalImage;
470 Move<VkImage> sparseImage;
471 Move<VkSemaphore> sparseImageSemaphore;
472 std::vector<DeviceMemorySp> deviceMemUniquePtrVec;
473
474 if (!useSparseBinding)
475 // Create a normal image and bind device memory too
476 normalImage = de::MovePtr<ImageWithMemory>(
477 new ImageWithMemory(vk, device, allocator, imageCreateInfo, MemoryRequirement::Any));
478 else
479 // Create an image now and bind device memory later
480 sparseImage = createImage(vk, device, &imageCreateInfo);
481
482 const VkImage &testImage = useSparseBinding ? sparseImage.get() : (*normalImage).get();
483
484 if (useSparseBinding)
485 {
486 const InstanceInterface &instance = m_context.getInstanceInterface();
487 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
488 const VkQueue sparseQueue = m_context.getSparseQueue();
489 std::vector<VkSparseMemoryBind> sparseMemoryBindings;
490
491 const VkMemoryRequirements imageMemoryReqs = getImageMemoryRequirements(vk, device, testImage);
492
493 if (imageMemoryReqs.size > getPhysicalDeviceProperties(instance, physicalDevice).limits.sparseAddressSpaceSize)
494 TCU_THROW(NotSupportedError, "Required memory size for sparse resource exceeds device limits");
495
496 DE_ASSERT((imageMemoryReqs.size % imageMemoryReqs.alignment) == 0);
497
498 uint32_t memoryType;
499 bool memoryTypeFound =
500 getMemoryType(instance, physicalDevice, imageMemoryReqs, MemoryRequirement::Any, memoryType);
501 if (!memoryTypeFound)
502 return tcu::TestStatus::fail("Required memory type for sparse resouce not found");
503
504 const uint32_t numSparseBindings = static_cast<uint32_t>(imageMemoryReqs.size / imageMemoryReqs.alignment);
505 for (uint32_t bindingIdx = 0; bindingIdx < numSparseBindings; ++bindingIdx)
506 {
507 const VkSparseMemoryBind sparseMemoryBinding =
508 makeSparseMemoryBinding(vk, device, imageMemoryReqs.alignment, memoryType,
509 imageMemoryReqs.alignment * bindingIdx, (VkSparseMemoryBindFlags)0u);
510
511 deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(
512 check<VkDeviceMemory>(sparseMemoryBinding.memory), Deleter<VkDeviceMemory>(vk, device, nullptr))));
513
514 sparseMemoryBindings.push_back(sparseMemoryBinding);
515 }
516
517 const VkSparseImageOpaqueMemoryBindInfo opaqueBindingInfo = makeSparseImageOpaqueMemoryBindInfo(
518 testImage, de::sizeU32(sparseMemoryBindings), de::dataOrNull(sparseMemoryBindings));
519
520 sparseImageSemaphore = createSemaphore(vk, device);
521
522 const VkBindSparseInfo bindSparseInfo = {
523 VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, //VkStructureType sType;
524 nullptr, //const void* pNext;
525 0u, //uint32_t waitSemaphoreCount;
526 nullptr, //const VkSemaphore* pWaitSemaphores;
527 0u, //uint32_t bufferBindCount;
528 nullptr, //const VkSparseBufferMemoryBindInfo* pBufferBinds;
529 1u, //uint32_t imageOpaqueBindCount;
530 &opaqueBindingInfo, //const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds;
531 0u, //uint32_t imageBindCount;
532 nullptr, //const VkSparseImageMemoryBindInfo* pImageBinds;
533 1u, //uint32_t signalSemaphoreCount;
534 &sparseImageSemaphore.get() //const VkSemaphore* pSignalSemaphores;
535 };
536
537 VK_CHECK(vk.queueBindSparse(sparseQueue, 1u, &bindSparseInfo, VK_NULL_HANDLE));
538 }
539
540 // Make an image view covering one of the mip levels.
541 const VkImageSubresourceRange viewSubresourceRange = makeImageSubresourceRange(
542 VK_IMAGE_ASPECT_COLOR_BIT, m_testParameters.mipLevel, 1u, m_testParameters.layerNdx, 1u);
543 const Unique<VkImageView> imageView(makeImageView(vk, device, testImage, VK_IMAGE_VIEW_TYPE_2D,
544 m_testParameters.imageFormat, viewSubresourceRange));
545
546 // resultImage is used in sampler / combined image sampler tests to verify the sampled image.
547 MovePtr<ImageWithMemory> resultImage;
548 VkImageSubresourceRange resultImgSubresourceRange = {};
549 Move<VkImageView> resultImageView;
550 Move<VkSampler> sampler;
551 if (useSampler)
552 {
553 const VkImageCreateInfo resultImageCreateInfo = {
554 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType
555 nullptr, // const void* pNext
556 0U, // VkImageCreateFlags flags
557 VK_IMAGE_TYPE_2D, // VkImageType imageType
558 m_testParameters.imageFormat, // VkFormat format
559 makeExtent3D(testMipLevelSize.x(), testMipLevelSize.y(), 1), // VkExtent3D extent
560 1u, // uint32_t mipLevels
561 1u, // uint32_t arrayLayers
562 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
563 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling
564 VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
565 VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage
566 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode
567 0u, // uint32_t queueFamilyIndexCount
568 nullptr, // const uint32_t* pQueueFamilyIndices
569 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
570 };
571
572 resultImage = MovePtr<ImageWithMemory>(
573 new ImageWithMemory(vk, device, allocator, resultImageCreateInfo, MemoryRequirement::Any));
574 resultImgSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
575 resultImageView = makeImageView(vk, device, **resultImage, VK_IMAGE_VIEW_TYPE_2D, m_testParameters.imageFormat,
576 resultImgSubresourceRange);
577
578 const VkSamplerCreateInfo samplerCreateInfo = {
579 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType
580 nullptr, // const void* pNext
581 (VkSamplerCreateFlags)0, // VkSamplerCreateFlags flags
582 VK_FILTER_NEAREST, // VkFilter magFilter
583 VK_FILTER_NEAREST, // VkFilter minFilter
584 VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode
585 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeU
586 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeV
587 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW
588 0.0f, // float mipLodBias
589 VK_FALSE, // VkBool32 anisotropyEnable
590 1.0f, // float maxAnisotropy
591 VK_FALSE, // VkBool32 compareEnable
592 VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp
593 0.0f, // float minLod
594 1.0f, // float maxLod
595 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor
596 VK_FALSE, // VkBool32 unnormalizedCoordinates
597 };
598 sampler = createSampler(vk, device, &samplerCreateInfo);
599 }
600
601 // Create the descriptor set.
602 DescriptorSetLayoutBuilder descriptorSetLayoutBuilder;
603 DescriptorPoolBuilder descriptorPoolBuilder;
604
605 VkShaderStageFlags shaderStage =
606 m_testParameters.testType == Compute ? VK_SHADER_STAGE_COMPUTE_BIT : VK_SHADER_STAGE_FRAGMENT_BIT;
607 VkPipelineStageFlags pipelineStage = m_testParameters.testType == Compute ? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT :
608 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
609 switch (m_testParameters.imageType)
610 {
611 case StorageImage:
612 descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStage);
613 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
614 break;
615 case Sampler:
616 descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, shaderStage);
617 descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLER, shaderStage);
618 descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStage);
619 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
620 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLER);
621 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
622 break;
623 case CombinedImageSampler:
624 descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, shaderStage);
625 descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStage);
626 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
627 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
628 break;
629 default:
630 TCU_THROW(InternalError, "Unimplemented testImage type.");
631 }
632
633 // Prepare the command buffer.
634 const Unique<VkCommandPool> cmdPool(makeCommandPool(vk, device, queueFamilyIndex));
635 const Unique<VkCommandBuffer> cmdBuffer(
636 allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
637
638 // Start recording commands.
639 beginCommandBuffer(vk, *cmdBuffer);
640
641 if (useSampler)
642 {
643 // Clear the result image.
644 const VkImageMemoryBarrier preImageBarrier = {
645 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
646 nullptr, // const void* pNext;
647 0u, // VkAccessFlags srcAccessMask;
648 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask;
649 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
650 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout;
651 queueFamilyIndex, // uint32_t srcQueueFamilyIndex;
652 queueFamilyIndex, // uint32_t dstQueueFamilyIndex;
653 **resultImage, // VkImage image;
654 resultImgSubresourceRange // VkImageSubresourceRange subresourceRange;
655 };
656 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
657 (VkDependencyFlags)0, 0, nullptr, 0, nullptr, 1, &preImageBarrier);
658
659 const VkClearColorValue clearColor = makeClearValueColor(tcu::Vec4(0, 0, 0, 1)).color;
660 vk.cmdClearColorImage(*cmdBuffer, **resultImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1,
661 &resultImgSubresourceRange);
662
663 const VkImageMemoryBarrier postImageBarrier = {
664 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
665 nullptr, // const void* pNext;
666 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
667 VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags dstAccessMask;
668 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout;
669 VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout;
670 queueFamilyIndex, // uint32_t srcQueueFamilyIndex;
671 queueFamilyIndex, // uint32_t dstQueueFamilyIndex;
672 **resultImage, // VkImage image;
673 resultImgSubresourceRange // VkImageSubresourceRange subresourceRange;
674 };
675 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, pipelineStage, (VkDependencyFlags)0, 0,
676 nullptr, 0, nullptr, 1, &postImageBarrier);
677 }
678 else
679 {
680 const auto singleMipSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
681 const auto allMipsSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, mipLevelCount, 0u, 1u);
682
683 // Clear the test image.
684 const VkImageMemoryBarrier preImageBarrier = {
685 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
686 nullptr, // const void* pNext;
687 0u, // VkAccessFlags srcAccessMask;
688 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask;
689 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
690 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout;
691 queueFamilyIndex, // uint32_t srcQueueFamilyIndex;
692 queueFamilyIndex, // uint32_t dstQueueFamilyIndex;
693 testImage, // VkImage image;
694 allMipsSRR, // VkImageSubresourceRange subresourceRange;
695 };
696 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
697 (VkDependencyFlags)0, 0, nullptr, 0, nullptr, 1, &preImageBarrier);
698
699 const VkClearColorValue clearColor = makeClearValueColor(tcu::Vec4(0, 0, 0, 1)).color;
700 vk.cmdClearColorImage(*cmdBuffer, testImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1,
701 &singleMipSRR);
702
703 const VkImageMemoryBarrier postImageBarrier = {
704 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
705 nullptr, // const void* pNext;
706 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
707 VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags dstAccessMask;
708 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout;
709 VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout;
710 queueFamilyIndex, // uint32_t srcQueueFamilyIndex;
711 queueFamilyIndex, // uint32_t dstQueueFamilyIndex;
712 testImage, // VkImage image;
713 allMipsSRR, // VkImageSubresourceRange subresourceRange;
714 };
715 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, pipelineStage, (VkDependencyFlags)0, 0,
716 nullptr, 0, nullptr, 1, &postImageBarrier);
717 }
718
719 if (useSampler)
720 {
721 // Copy the input image to the target mip level.
722 std::vector<VkBufferImageCopy> copies;
723 copies.push_back(makeBufferImageCopy(
724 makeExtent3D(testMipLevelSize),
725 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, m_testParameters.mipLevel, 0, 1)));
726 copyBufferToImage(vk, *cmdBuffer, **inputImageBuffer, bufferSize, copies, VK_IMAGE_ASPECT_COLOR_BIT,
727 mipLevelCount, 1u, testImage, VK_IMAGE_LAYOUT_GENERAL, pipelineStage);
728 }
729
730 const Move<VkDescriptorSetLayout> descriptorSetLayout(descriptorSetLayoutBuilder.build(vk, device));
731 const Move<VkDescriptorPool> descriptorPool(
732 descriptorPoolBuilder.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
733 const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
734 const VkDescriptorImageInfo testImageDescriptorInfo =
735 makeDescriptorImageInfo(*sampler, *imageView, VK_IMAGE_LAYOUT_GENERAL);
736
737 // Write descriptor update.
738 {
739 DescriptorSetUpdateBuilder descriptorSetUpdateBuilder;
740 uint32_t bindingIdx = 0;
741
742 switch (m_testParameters.imageType)
743 {
744 case StorageImage:
745 descriptorSetUpdateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
746 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &testImageDescriptorInfo);
747 break;
748 case Sampler:
749 descriptorSetUpdateBuilder.writeSingle(*descriptorSet,
750 DescriptorSetUpdateBuilder::Location::binding(bindingIdx++),
751 VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &testImageDescriptorInfo);
752 descriptorSetUpdateBuilder.writeSingle(*descriptorSet,
753 DescriptorSetUpdateBuilder::Location::binding(bindingIdx++),
754 VK_DESCRIPTOR_TYPE_SAMPLER, &testImageDescriptorInfo);
755 break;
756 case CombinedImageSampler:
757 descriptorSetUpdateBuilder.writeSingle(*descriptorSet,
758 DescriptorSetUpdateBuilder::Location::binding(bindingIdx++),
759 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &testImageDescriptorInfo);
760 break;
761 }
762
763 if (useSampler)
764 {
765 const VkDescriptorImageInfo resultImageDescriptorInfo =
766 makeDescriptorImageInfo(VK_NULL_HANDLE, *resultImageView, VK_IMAGE_LAYOUT_GENERAL);
767 descriptorSetUpdateBuilder.writeSingle(*descriptorSet,
768 DescriptorSetUpdateBuilder::Location::binding(bindingIdx),
769 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &resultImageDescriptorInfo);
770 }
771
772 descriptorSetUpdateBuilder.update(vk, device);
773 }
774
775 const VkSemaphore *sparseImageSemaphorePtr = (useSparseBinding ? &sparseImageSemaphore.get() : nullptr);
776
777 if (m_testParameters.testType == Compute)
778 runComputePipeline(*descriptorSet, *descriptorSetLayout, testMipLevelSize, *cmdBuffer,
779 useSampler ? **resultImage : testImage, *outputBuffer, sparseImageSemaphorePtr);
780 else
781 runGraphicsPipeline(*descriptorSet, *descriptorSetLayout, testMipLevelSize, *cmdBuffer,
782 useSampler ? **resultImage : testImage, *outputBuffer, sparseImageSemaphorePtr);
783
784 // Validate the results.
785 {
786 // Create a reference image.
787 // The reference image has always a depth of 1, because it will be compared to the 2D result image (sampler cases) or to a single layer of a 3D image.
788 tcu::TextureLevel referenceImage(textureFormat, testMipLevelSize.x(), testMipLevelSize.y(), 1u);
789 fillImage(referenceImage.getAccess(), 0u);
790
791 const Allocation &outputBufferAllocation = outputBuffer.getAllocation();
792 invalidateAlloc(vk, device, outputBufferAllocation);
793
794 const uint32_t *bufferPtr = static_cast<uint32_t *>(outputBufferAllocation.getHostPtr());
795 tcu::ConstPixelBufferAccess pixelBufferAccess(mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), testMipLevelSize.x(),
796 testMipLevelSize.y(), 1u, bufferPtr);
797
798 if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Result", "Result comparison",
799 referenceImage, pixelBufferAccess, tcu::Vec4(0.01f), tcu::COMPARE_LOG_ON_ERROR))
800 return tcu::TestStatus::fail("Pixel comparison failed.");
801 }
802
803 return tcu::TestStatus::pass("pass");
804 }
805
806 class ComputeImage2DView3DImageTest : public vkt::TestCase
807 {
808 public:
ComputeImage2DView3DImageTest(tcu::TestContext & testContext,const char * name,const TestParameters & testParameters)809 ComputeImage2DView3DImageTest(tcu::TestContext &testContext, const char *name, const TestParameters &testParameters)
810 : vkt::TestCase(testContext, name)
811 , m_testParameters(testParameters)
812 {
813 }
~ComputeImage2DView3DImageTest(void)814 virtual ~ComputeImage2DView3DImageTest(void)
815 {
816 }
817
818 virtual void initPrograms(SourceCollections &sourceCollections) const;
819 virtual void checkSupport(Context &context) const;
820 virtual TestInstance *createInstance(Context &context) const;
821
822 private:
823 const TestParameters m_testParameters;
824 };
825
checkSupport(Context & context) const826 void ComputeImage2DView3DImageTest::checkSupport(Context &context) const
827 {
828 DE_ASSERT(m_testParameters.pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC);
829
830 if (!context.isDeviceFunctionalitySupported("VK_EXT_image_2d_view_of_3d"))
831 TCU_THROW(NotSupportedError, "VK_EXT_image_2d_view_of_3d functionality not supported.");
832
833 if (!context.getImage2DViewOf3DFeaturesEXT().image2DViewOf3D)
834 TCU_THROW(NotSupportedError, "image2DViewOf3D not supported.");
835
836 if (m_testParameters.imageType != StorageImage && !context.getImage2DViewOf3DFeaturesEXT().sampler2DViewOf3D)
837 TCU_THROW(NotSupportedError, "sampler2DViewOf3D not supported.");
838
839 if (m_testParameters.imageBindingType == Sparse)
840 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SPARSE_BINDING);
841 }
842
initPrograms(SourceCollections & sourceCollections) const843 void ComputeImage2DView3DImageTest::initPrograms(SourceCollections &sourceCollections) const
844 {
845 std::ostringstream src;
846 tcu::IVec3 mipLevelSize = computeMipLevelSize(m_testParameters.imageSize, m_testParameters.mipLevel);
847 if (m_testParameters.imageType == StorageImage)
848 {
849 src << "#version 450 core\n"
850 << "layout (local_size_x = 1, local_size_y = 1) in;\n"
851 << "layout (binding = 0, rgba8) writeonly uniform highp image2D storageImage;\n"
852 << "void main (void) {\n"
853 << " ivec2 uv = ivec2(gl_GlobalInvocationID.xy);\n"
854 << " float c = float((uv.x + uv.y) & 1);\n"
855 << " vec4 color = vec4(c, c, c, 1.0);\n"
856 << " imageStore(storageImage, uv, color);\n"
857 << "}\n";
858 }
859 else if (m_testParameters.imageType == Sampler)
860 {
861 src << "#version 450 core\n"
862 << "layout (local_size_x = 1, local_size_y = 1) in;\n"
863 << "layout (set=0, binding = 0) uniform texture2D image;\n"
864 << "layout (set=0, binding = 1) uniform sampler samp;\n"
865 << "layout (rgba8, set=0, binding = 2) writeonly uniform highp image2D verifyImage;\n"
866 << "void main (void) {\n"
867 << " ivec2 uv = ivec2(gl_GlobalInvocationID.xy);\n"
868 << " vec2 texCoord = vec2(gl_GlobalInvocationID.xy) / " << mipLevelSize.x() << ".0;\n"
869 << " vec4 color = texture(sampler2D(image, samp), texCoord);\n"
870 << " imageStore(verifyImage, uv, color);\n"
871 << "}\n";
872 }
873 else if (m_testParameters.imageType == CombinedImageSampler)
874 {
875 src << "#version 450 core\n"
876 << "layout (local_size_x = 1, local_size_y = 1) in;\n"
877 << "layout (binding = 0) uniform sampler2D combinedSampler;\n"
878 << "layout (rgba8, set=0, binding=1) writeonly uniform highp image2D verifyImage;\n"
879 << "void main (void) {\n"
880 << " ivec2 uv = ivec2(gl_GlobalInvocationID.xy);\n"
881 << " vec2 texCoord = vec2(gl_GlobalInvocationID.xy) / " << mipLevelSize.x() << ".0;\n"
882 << " vec4 color = texture(combinedSampler, texCoord);\n"
883 << " imageStore(verifyImage, uv, color);\n"
884 << "}\n";
885 }
886
887 sourceCollections.glslSources.add("comp") << glu::ComputeSource(src.str());
888 }
889
createInstance(Context & context) const890 TestInstance *ComputeImage2DView3DImageTest::createInstance(Context &context) const
891 {
892 return new Image2DView3DImageInstance(context, m_testParameters);
893 }
894
895 class FragmentImage2DView3DImageTest : public vkt::TestCase
896 {
897 public:
FragmentImage2DView3DImageTest(tcu::TestContext & testContext,const char * name,const TestParameters & testParameters)898 FragmentImage2DView3DImageTest(tcu::TestContext &testContext, const char *name,
899 const TestParameters &testParameters)
900 : vkt::TestCase(testContext, name)
901 , m_testParameters(testParameters)
902 {
903 }
~FragmentImage2DView3DImageTest(void)904 virtual ~FragmentImage2DView3DImageTest(void)
905 {
906 }
907
908 virtual void initPrograms(SourceCollections &sourceCollections) const;
909 virtual void checkSupport(Context &context) const;
910 virtual TestInstance *createInstance(Context &context) const;
911
912 private:
913 const TestParameters m_testParameters;
914 };
915
initPrograms(SourceCollections & sourceCollections) const916 void FragmentImage2DView3DImageTest::initPrograms(SourceCollections &sourceCollections) const
917 {
918 std::stringstream vertShader;
919 vertShader << "#version 450 core\n"
920 << "layout(location = 0) in vec4 in_position;\n"
921 << "out gl_PerVertex {\n"
922 << " vec4 gl_Position;\n"
923 << " float gl_PointSize;\n"
924 << "};\n"
925 << "void main() {\n"
926 << " gl_PointSize = 1.0;\n"
927 << " gl_Position = in_position;\n"
928 << "}\n";
929 sourceCollections.glslSources.add("vert") << glu::VertexSource(vertShader.str());
930
931 tcu::IVec3 mipLevelSize = computeMipLevelSize(m_testParameters.imageSize, m_testParameters.mipLevel);
932 std::stringstream fragShader;
933 if (m_testParameters.imageType == StorageImage)
934 {
935 fragShader << "#version 450 core\n"
936 << "layout(rgba8, set = 0, binding = 0) uniform image2D storageImage;\n"
937 << "void main()\n"
938 << "{\n"
939 << " ivec2 uv = ivec2(gl_FragCoord.xy);\n"
940 << " float c = float((uv.x + uv.y) & 1);\n"
941 << " vec4 color = vec4(c, c, c, 1.0);\n"
942 << " imageStore(storageImage, uv, color);\n"
943 << "}\n";
944 }
945
946 else if (m_testParameters.imageType == Sampler)
947 {
948 fragShader << "#version 450 core\n"
949 << "layout (set = 0, binding = 0) uniform texture2D image;\n"
950 << "layout (set = 0, binding = 1) uniform sampler samp;\n"
951 << "layout (rgba8, set = 0, binding = 2) uniform image2D verifyImage;\n"
952 << "void main (void) {\n"
953 << " ivec2 uv = ivec2(gl_FragCoord.xy);\n"
954 << " vec2 texCoord = gl_FragCoord.xy / " << mipLevelSize.x() << ".0;\n"
955 << " vec4 color = texture(sampler2D(image, samp), texCoord);\n"
956 << " imageStore(verifyImage, uv, color);\n"
957 << "}\n";
958 }
959 else if (m_testParameters.imageType == CombinedImageSampler)
960 {
961 fragShader << "#version 450 core\n"
962 << "layout (set = 0, binding = 0) uniform sampler2D combinedSampler;\n"
963 << "layout (rgba8, set = 0, binding = 1) uniform image2D verifyImage;\n"
964 << "void main (void) {\n"
965 << " ivec2 uv = ivec2(gl_FragCoord.xy);\n"
966 << " vec2 texCoord = gl_FragCoord.xy / " << mipLevelSize.x() << ".0;\n"
967 << " vec4 color = texture(combinedSampler, texCoord);\n"
968 << " imageStore(verifyImage, uv, color);\n"
969 << "}\n";
970 }
971 sourceCollections.glslSources.add("frag") << glu::FragmentSource(fragShader.str());
972 }
973
checkSupport(Context & context) const974 void FragmentImage2DView3DImageTest::checkSupport(Context &context) const
975 {
976 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
977 m_testParameters.pipelineConstructionType);
978
979 if (!context.isDeviceFunctionalitySupported("VK_EXT_image_2d_view_of_3d"))
980 TCU_THROW(NotSupportedError, "VK_EXT_image_2d_view_of_3d functionality not supported.");
981
982 if (!context.getImage2DViewOf3DFeaturesEXT().image2DViewOf3D)
983 TCU_THROW(NotSupportedError, "image2DViewOf3D not supported.");
984
985 if (m_testParameters.imageType != StorageImage && !context.getImage2DViewOf3DFeaturesEXT().sampler2DViewOf3D)
986 TCU_THROW(NotSupportedError, "texture2DViewOf3D not supported.");
987
988 if (!context.getDeviceFeatures().fragmentStoresAndAtomics)
989 TCU_THROW(NotSupportedError, "fragmentStoresAndAtomics not supported");
990
991 if (m_testParameters.imageBindingType == Sparse)
992 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SPARSE_BINDING);
993 }
994
createInstance(Context & context) const995 TestInstance *FragmentImage2DView3DImageTest::createInstance(Context &context) const
996 {
997 return new Image2DView3DImageInstance(context, m_testParameters);
998 }
999
1000 } // namespace
1001
createImage2DViewOf3DTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)1002 tcu::TestCaseGroup *createImage2DViewOf3DTests(tcu::TestContext &testCtx,
1003 PipelineConstructionType pipelineConstructionType)
1004 {
1005 de::MovePtr<tcu::TestCaseGroup> imageTests(new tcu::TestCaseGroup(testCtx, "image_2d_view_3d_image"));
1006 de::MovePtr<tcu::TestCaseGroup> computeGroup(new tcu::TestCaseGroup(testCtx, "compute"));
1007 de::MovePtr<tcu::TestCaseGroup> fragmentGroup(new tcu::TestCaseGroup(testCtx, "fragment"));
1008
1009 const struct
1010 {
1011 const ImageAccessType imageType;
1012 const std::string name;
1013 } imageAccessTypes[]{
1014 {StorageImage, "storage"}, {Sampler, "sampler"}, {CombinedImageSampler, "combined_image_sampler"}};
1015
1016 const int32_t imageDimension = 64;
1017 for (const auto &imageAccessType : imageAccessTypes)
1018 {
1019 de::MovePtr<tcu::TestCaseGroup> computeSubGroup(new tcu::TestCaseGroup(testCtx, imageAccessType.name.c_str()));
1020 de::MovePtr<tcu::TestCaseGroup> fragmentSubGroup(new tcu::TestCaseGroup(testCtx, imageAccessType.name.c_str()));
1021 for (uint32_t mipLevel = 0; mipLevel < 3; mipLevel += 2)
1022 {
1023 // Test the first and the last layer of the mip level.
1024 std::vector<int32_t> layers = {0, computeMipLevelDimension(imageDimension, mipLevel) - 1};
1025 for (const auto &layer : layers)
1026 {
1027 for (const auto &imageBindingType : {ImageBindingType::Normal, ImageBindingType::Sparse})
1028 {
1029 TestParameters testParameters{
1030 tcu::IVec3(imageDimension), // IVec3 imageSize
1031 mipLevel, // uint32_t mipLevel
1032 layer, // int32_t layerNdx
1033 imageAccessType.imageType, // ImageAccessType imageType
1034 Fragment, // TestType testType
1035 VK_FORMAT_R8G8B8A8_UNORM, // VkFormat imageFormat
1036 pipelineConstructionType, // PipelineConstructionType pipelineConstructionType
1037 imageBindingType // ImageBindingType imageBindingType
1038 };
1039 std::string testName = "mip" + std::to_string(mipLevel) + "_layer" + std::to_string(layer) +
1040 (imageBindingType == Sparse ? "_sparse" : "");
1041 fragmentSubGroup->addChild(
1042 new FragmentImage2DView3DImageTest(testCtx, testName.c_str(), testParameters));
1043
1044 if (pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
1045 {
1046 testParameters.testType = Compute;
1047 computeSubGroup->addChild(
1048 new ComputeImage2DView3DImageTest(testCtx, testName.c_str(), testParameters));
1049 }
1050 }
1051 }
1052 }
1053 computeGroup->addChild(computeSubGroup.release());
1054 fragmentGroup->addChild(fragmentSubGroup.release());
1055 }
1056
1057 imageTests->addChild(computeGroup.release());
1058 imageTests->addChild(fragmentGroup.release());
1059 return imageTests.release();
1060 }
1061
1062 } // namespace pipeline
1063 } // namespace vkt
1064