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 <sstream>
45 #include <vector>
46
47 namespace vkt
48 {
49 namespace pipeline
50 {
51
52 using namespace vk;
53 using de::MovePtr;
54
55 namespace
56 {
57 enum ImageAccessType
58 {
59 StorageImage = 0,
60 Sampler,
61 CombinedImageSampler
62 };
63
64 enum TestType
65 {
66 Compute,
67 Fragment
68 };
69
70 struct TestParameters
71 {
72 tcu::IVec3 imageSize;
73 uint32_t mipLevel;
74 int32_t layerNdx;
75 ImageAccessType imageType;
76 TestType testType;
77 VkFormat imageFormat;
78 PipelineConstructionType pipelineConstructionType;
79 };
80
computeMipLevelDimension(int32_t baseLevelDimension,uint32_t mipLevel)81 inline int32_t computeMipLevelDimension(int32_t baseLevelDimension, uint32_t mipLevel)
82 {
83 return de::max(baseLevelDimension >> mipLevel, 1);
84 }
85
computeMipLevelSize(tcu::IVec3 baseLevelSize,uint32_t mipLevel)86 tcu::IVec3 computeMipLevelSize(tcu::IVec3 baseLevelSize, uint32_t mipLevel)
87 {
88 int32_t width = computeMipLevelDimension(baseLevelSize.x(), mipLevel);
89 int32_t height = computeMipLevelDimension(baseLevelSize.y(), mipLevel);
90 int32_t depth = computeMipLevelDimension(baseLevelSize.z(), mipLevel);
91 return tcu::IVec3(width, height, depth);
92 }
93
copyImageLayerToBuffer(const DeviceInterface & vk,VkCommandBuffer cmdBuffer,VkImage image,VkBuffer buffer,tcu::IVec2 size,VkAccessFlags srcAccessMask,VkImageLayout oldLayout,uint32_t layerToCopy,uint32_t mipLevel)94 void copyImageLayerToBuffer(const DeviceInterface &vk, VkCommandBuffer cmdBuffer, VkImage image, VkBuffer buffer,
95 tcu::IVec2 size, VkAccessFlags srcAccessMask, VkImageLayout oldLayout, uint32_t layerToCopy,
96 uint32_t mipLevel)
97 {
98 const VkImageSubresourceRange subresourceRange =
99 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 1u, 0, 1u);
100 const VkImageMemoryBarrier imageBarrier = {
101 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType
102 DE_NULL, // const void* pNext
103 srcAccessMask, // VkAccessFlags srcAccessMask
104 VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask
105 oldLayout, // VkImageLayout oldLayout
106 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout
107 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
108 VK_QUEUE_FAMILY_IGNORED, // uint32_t destQueueFamilyIndex
109 image, // VkImage image
110 subresourceRange // VkImageSubresourceRange subresourceRange
111 };
112
113 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u,
114 DE_NULL, 0u, DE_NULL, 1u, &imageBarrier);
115
116 const VkImageSubresourceLayers subresource = {
117 subresourceRange.aspectMask, // VkImageAspectFlags aspectMask
118 mipLevel, // uint32_t mipLevel
119 0u, // uint32_t baseArrayLayer
120 1u, // uint32_t layerCount
121 };
122
123 const VkBufferImageCopy region = {
124 0ull, // VkDeviceSize bufferOffset
125 0u, // uint32_t bufferRowLength
126 0u, // uint32_t bufferImageHeight
127 subresource, // VkImageSubresourceLayers imageSubresource
128 makeOffset3D(0, 0, (int)layerToCopy), // VkOffset3D imageOffset
129 makeExtent3D(size.x(), size.y(), 1u) // VkExtent3D imageExtent
130 };
131
132 vk.cmdCopyImageToBuffer(cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, 1u, ®ion);
133
134 const VkBufferMemoryBarrier bufferBarrier = {
135 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType
136 DE_NULL, // const void* pNext
137 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask
138 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask
139 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
140 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex
141 buffer, // VkBuffer buffer
142 0ull, // VkDeviceSize offset
143 VK_WHOLE_SIZE // VkDeviceSize size
144 };
145
146 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u,
147 &bufferBarrier, 0u, DE_NULL);
148 }
149
150 // 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)151 void fillImage(const tcu::PixelBufferAccess &image, const int layer)
152 {
153 const tcu::Vec4 clearColor = tcu::Vec4(1); // White clear color.
154 for (int z = 0; z < image.getSize().z(); ++z)
155 for (int y = 0; y < image.getSize().y(); ++y)
156 for (int x = 0; x < image.getSize().x(); ++x)
157 {
158 if (z == layer)
159 {
160 const float c = (float)((x + y) & 1);
161 const tcu::Vec4 color = tcu::Vec4(c, c, c, 1.0f);
162 image.setPixel(color, x, y, z);
163 }
164 else
165 {
166 image.setPixel(clearColor, x, y, z);
167 }
168 }
169 }
170
171 class Image2DView3DImageInstance : public vkt::TestInstance
172 {
173 public:
Image2DView3DImageInstance(Context & context,const TestParameters testParameters)174 Image2DView3DImageInstance(Context &context, const TestParameters testParameters)
175 : vkt::TestInstance(context)
176 , m_testParameters(testParameters)
177 {
178 }
179
180 tcu::TestStatus iterate(void);
181
182 private:
183 void runComputePipeline(const VkDescriptorSet &descriptorSet, const VkDescriptorSetLayout descriptorSetLayout,
184 tcu::IVec3 &testMipLevelSize, VkCommandBuffer cmdBuffer, VkImage image,
185 VkBuffer outputBuffer);
186
187 void runGraphicsPipeline(const VkDescriptorSet &descriptorSet, const VkDescriptorSetLayout descriptorSetLayout,
188 tcu::IVec3 &testMipLevelSize, VkCommandBuffer cmdBuffer, VkImage image,
189 VkBuffer outputBuffer);
190 const TestParameters m_testParameters;
191 };
192
runComputePipeline(const VkDescriptorSet & descriptorSet,const VkDescriptorSetLayout descriptorSetLayout,tcu::IVec3 & testMipLevelSize,VkCommandBuffer cmdBuffer,VkImage image,VkBuffer outputBuffer)193 void Image2DView3DImageInstance::runComputePipeline(const VkDescriptorSet &descriptorSet,
194 const VkDescriptorSetLayout descriptorSetLayout,
195 tcu::IVec3 &testMipLevelSize, VkCommandBuffer cmdBuffer,
196 VkImage image, VkBuffer outputBuffer)
197 {
198 const DeviceInterface &vk = m_context.getDeviceInterface();
199 const VkDevice device = m_context.getDevice();
200 const VkQueue queue = m_context.getUniversalQueue();
201 const bool useSampler = m_testParameters.imageType != StorageImage;
202
203 const Unique<VkShaderModule> shaderModule(
204 createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0u));
205 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, descriptorSetLayout));
206 const Unique<VkPipeline> pipeline(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
207
208 vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
209 vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet, 0u,
210 DE_NULL);
211 vk.cmdDispatch(cmdBuffer, testMipLevelSize.x(), testMipLevelSize.y(), 1u);
212
213 // Copy the result image to a buffer.
214 copyImageLayerToBuffer(vk, cmdBuffer, image, outputBuffer, testMipLevelSize.xy(), VK_ACCESS_SHADER_WRITE_BIT,
215 VK_IMAGE_LAYOUT_GENERAL, useSampler ? 0u : m_testParameters.layerNdx,
216 useSampler ? 0u : m_testParameters.mipLevel);
217
218 endCommandBuffer(vk, cmdBuffer);
219
220 // Wait for completion.
221 submitCommandsAndWait(vk, device, queue, cmdBuffer);
222 }
223
runGraphicsPipeline(const VkDescriptorSet & descriptorSet,const VkDescriptorSetLayout descriptorSetLayout,tcu::IVec3 & testMipLevelSize,VkCommandBuffer cmdBuffer,VkImage image,VkBuffer outputBuffer)224 void Image2DView3DImageInstance::runGraphicsPipeline(const VkDescriptorSet &descriptorSet,
225 const VkDescriptorSetLayout descriptorSetLayout,
226 tcu::IVec3 &testMipLevelSize, VkCommandBuffer cmdBuffer,
227 VkImage image, VkBuffer outputBuffer)
228 {
229 const InstanceInterface &vki = m_context.getInstanceInterface();
230 const DeviceInterface &vk = m_context.getDeviceInterface();
231 const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
232 const VkDevice device = m_context.getDevice();
233 const VkQueue queue = m_context.getUniversalQueue();
234 const bool useSampler = m_testParameters.imageType != StorageImage;
235
236 const ShaderWrapper vertShader(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
237 const ShaderWrapper fragShader(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
238 const PipelineLayoutWrapper pipelineLayout(m_testParameters.pipelineConstructionType, vk, device,
239 descriptorSetLayout);
240 RenderPassWrapper renderPass(m_testParameters.pipelineConstructionType, vk, device);
241 const std::vector<VkViewport> viewport = {
242 makeViewport(m_testParameters.imageSize.x(), m_testParameters.imageSize.y())};
243 const std::vector<VkRect2D> scissor = {makeRect2D(m_testParameters.imageSize.x(), m_testParameters.imageSize.y())};
244
245 const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
246 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType
247 DE_NULL, // const void* pNext
248 0u, // VkPipelineInputAssemblyStateCreateFlags flags
249 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, // VkPrimitiveTopology topology
250 VK_FALSE // VkBool32 primitiveRestartEnable
251 };
252
253 const VkVertexInputBindingDescription vertexInputBindingDescription = {
254 0u, // uint32_t binding
255 sizeof(tcu::Vec4), // uint32_t stride
256 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate
257 };
258
259 const VkVertexInputAttributeDescription vertexInputAttributeDescription = {
260 0u, // uint32_t location
261 0u, // uint32_t binding
262 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format
263 0u // uint32_t offset
264 };
265
266 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfoDefault = {
267 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType
268 DE_NULL, // const void* pNext
269 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags
270 1u, // uint32_t vertexBindingDescriptionCount
271 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions
272 1u, // uint32_t vertexAttributeDescriptionCount
273 &vertexInputAttributeDescription // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions
274 };
275
276 vk::GraphicsPipelineWrapper graphicsPipeline(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(),
277 m_testParameters.pipelineConstructionType, 0u);
278 graphicsPipeline.setMonolithicPipelineLayout(pipelineLayout)
279 .setDefaultDepthStencilState()
280 .setDefaultRasterizationState()
281 .setDefaultMultisampleState()
282 .setupVertexInputState(&vertexInputStateCreateInfoDefault, &inputAssemblyStateCreateInfo)
283 .setupPreRasterizationShaderState(viewport, scissor, pipelineLayout, *renderPass, 0u, vertShader)
284 .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragShader)
285 .setupFragmentOutputState(*renderPass, 0u)
286 .buildPipeline();
287
288 renderPass.createFramebuffer(vk, device, 0u, DE_NULL, DE_NULL, testMipLevelSize.x(), testMipLevelSize.y());
289
290 // Create vertex buffer and fill it with full screen quad.
291 const std::vector<tcu::Vec4> vertexData = {
292 {-1, -1, 1, 1},
293 {1, -1, 1, 1},
294 {1, 1, 1, 1},
295 {-1, 1, 1, 1},
296 };
297 size_t vertexBufferSize = sizeof(tcu::Vec4) * vertexData.size();
298 BufferWithMemory vertexBuffer(vk, device, m_context.getDefaultAllocator(),
299 makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
300 MemoryRequirement::HostVisible);
301 deMemcpy(vertexBuffer.getAllocation().getHostPtr(), vertexData.data(), vertexBufferSize);
302 flushAlloc(vk, device, vertexBuffer.getAllocation());
303
304 VkDeviceSize vertexBufferOffset = 0;
305 vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &*vertexBuffer, &vertexBufferOffset);
306
307 graphicsPipeline.bind(cmdBuffer);
308 vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet, 0u,
309 DE_NULL);
310
311 renderPass.begin(vk, cmdBuffer, makeRect2D(testMipLevelSize.xy()));
312 vk.cmdDraw(cmdBuffer, 4, 1, 0, 0);
313 renderPass.end(vk, cmdBuffer);
314
315 // Copy the result image to a buffer.
316 copyImageLayerToBuffer(vk, cmdBuffer, image, outputBuffer, testMipLevelSize.xy(), VK_ACCESS_SHADER_WRITE_BIT,
317 VK_IMAGE_LAYOUT_GENERAL, useSampler ? 0u : m_testParameters.layerNdx,
318 useSampler ? 0u : m_testParameters.mipLevel);
319
320 endCommandBuffer(vk, cmdBuffer);
321
322 // Wait for completion.
323 submitCommandsAndWait(vk, device, queue, cmdBuffer);
324 }
325
iterate(void)326 tcu::TestStatus Image2DView3DImageInstance::iterate(void)
327 {
328 const DeviceInterface &vk = m_context.getDeviceInterface();
329 const VkDevice device = m_context.getDevice();
330 const VkQueue queue = m_context.getUniversalQueue();
331 const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
332 Allocator &allocator = m_context.getDefaultAllocator();
333 tcu::IVec3 imageSize = m_testParameters.imageSize;
334 const bool useSampler = m_testParameters.imageType != StorageImage;
335 const tcu::TextureFormat textureFormat = mapVkFormat(m_testParameters.imageFormat);
336 const uint32_t mipLevelCount = 3;
337
338 tcu::IVec3 testMipLevelSize = computeMipLevelSize(m_testParameters.imageSize, m_testParameters.mipLevel);
339 uint32_t bufferSize =
340 testMipLevelSize.x() * testMipLevelSize.y() * testMipLevelSize.z() * textureFormat.getPixelSize();
341 const BufferWithMemory outputBuffer(vk, device, allocator,
342 makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT),
343 MemoryRequirement::HostVisible);
344
345 // Input image is used with sampler cases only.
346 de::MovePtr<BufferWithMemory> inputImageBuffer;
347
348 // Upload the test image data for sampler cases.
349 if (useSampler)
350 {
351 // Initialize the input image's mip level and fill the target layer with a chess pattern, others will be white.
352 tcu::TextureLevel inputImageMipLevel(textureFormat, testMipLevelSize.x(), testMipLevelSize.y(),
353 testMipLevelSize.z());
354 fillImage(inputImageMipLevel.getAccess(), m_testParameters.layerNdx);
355
356 // Create a buffer to upload the image.
357 const VkBufferCreateInfo bufferCreateInfo =
358 makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
359 inputImageBuffer = de::MovePtr<BufferWithMemory>(
360 new BufferWithMemory(vk, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible));
361
362 // Upload target mip level to the input buffer.
363 deMemcpy(inputImageBuffer->getAllocation().getHostPtr(), inputImageMipLevel.getAccess().getDataPtr(),
364 bufferSize);
365 flushAlloc(vk, device, inputImageBuffer->getAllocation());
366 }
367
368 // Create the test image: sampled image or storage image, depending on the test type.
369 const VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
370 (useSampler ? VK_IMAGE_USAGE_SAMPLED_BIT : VK_IMAGE_USAGE_STORAGE_BIT);
371 const VkImageCreateInfo imageCreateInfo = {
372 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType
373 DE_NULL, // const void* pNext
374 VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT, // VkImageCreateFlags flags
375 VK_IMAGE_TYPE_3D, // VkImageType imageType
376 m_testParameters.imageFormat, // VkFormat format
377 makeExtent3D(imageSize.x(), imageSize.y(), imageSize.z()), // VkExtent3D extent
378 (uint32_t)mipLevelCount, // uint32_t mipLevels
379 1u, // uint32_t arrayLayers
380 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
381 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling
382 usage, // VkImageUsageFlags usage
383 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode
384 0u, // uint32_t queueFamilyIndexCount
385 DE_NULL, // const uint32_t* pQueueFamilyIndices
386 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
387 };
388 ImageWithMemory testImage(vk, device, allocator, imageCreateInfo, MemoryRequirement::Any);
389
390 // Make an image view covering one of the mip levels.
391 const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(
392 VK_IMAGE_ASPECT_COLOR_BIT, m_testParameters.mipLevel, 1u, m_testParameters.layerNdx, 1u);
393 const Unique<VkImageView> imageView(
394 makeImageView(vk, device, *testImage, VK_IMAGE_VIEW_TYPE_2D, m_testParameters.imageFormat, subresourceRange));
395
396 // resultImage is used in sampler / combined image sampler tests to verify the sampled image.
397 MovePtr<ImageWithMemory> resultImage;
398 Move<VkImageView> resultImageView;
399 Move<VkSampler> sampler;
400 if (useSampler)
401 {
402 const VkImageCreateInfo resultImageCreateInfo = {
403 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType
404 DE_NULL, // const void* pNext
405 0U, // VkImageCreateFlags flags
406 VK_IMAGE_TYPE_2D, // VkImageType imageType
407 m_testParameters.imageFormat, // VkFormat format
408 makeExtent3D(testMipLevelSize.x(), testMipLevelSize.y(), 1), // VkExtent3D extent
409 1u, // uint32_t mipLevels
410 1u, // uint32_t arrayLayers
411 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
412 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling
413 VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
414 VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage
415 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode
416 0u, // uint32_t queueFamilyIndexCount
417 DE_NULL, // const uint32_t* pQueueFamilyIndices
418 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
419 };
420
421 resultImage = MovePtr<ImageWithMemory>(
422 new ImageWithMemory(vk, device, allocator, resultImageCreateInfo, MemoryRequirement::Any));
423 const VkImageSubresourceRange resultImgSubresourceRange =
424 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
425 resultImageView = makeImageView(vk, device, **resultImage, VK_IMAGE_VIEW_TYPE_2D, m_testParameters.imageFormat,
426 resultImgSubresourceRange);
427
428 const VkSamplerCreateInfo samplerCreateInfo = {
429 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType
430 DE_NULL, // const void* pNext
431 (VkSamplerCreateFlags)0, // VkSamplerCreateFlags flags
432 VK_FILTER_NEAREST, // VkFilter magFilter
433 VK_FILTER_NEAREST, // VkFilter minFilter
434 VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode
435 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeU
436 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeV
437 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW
438 0.0f, // float mipLodBias
439 VK_FALSE, // VkBool32 anisotropyEnable
440 1.0f, // float maxAnisotropy
441 VK_FALSE, // VkBool32 compareEnable
442 VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp
443 0.0f, // float minLod
444 1.0f, // float maxLod
445 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor
446 VK_FALSE, // VkBool32 unnormalizedCoordinates
447 };
448 sampler = createSampler(vk, device, &samplerCreateInfo);
449 }
450
451 // Create the descriptor set.
452 DescriptorSetLayoutBuilder descriptorSetLayoutBuilder;
453 DescriptorPoolBuilder descriptorPoolBuilder;
454
455 VkShaderStageFlags shaderStage =
456 m_testParameters.testType == Compute ? VK_SHADER_STAGE_COMPUTE_BIT : VK_SHADER_STAGE_FRAGMENT_BIT;
457 VkPipelineStageFlags pipelineStage = m_testParameters.testType == Compute ? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT :
458 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
459 switch (m_testParameters.imageType)
460 {
461 case StorageImage:
462 descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStage);
463 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
464 break;
465 case Sampler:
466 descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, shaderStage);
467 descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLER, shaderStage);
468 descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStage);
469 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
470 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLER);
471 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
472 break;
473 case CombinedImageSampler:
474 descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, shaderStage);
475 descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStage);
476 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
477 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
478 break;
479 default:
480 TCU_THROW(InternalError, "Unimplemented testImage type.");
481 }
482
483 if (useSampler)
484 {
485 // Clear the result image.
486 clearColorImage(vk, device, queue, m_context.getUniversalQueueFamilyIndex(), **resultImage,
487 tcu::Vec4(0, 0, 0, 1), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, pipelineStage, 0u,
488 1u);
489 }
490 else
491 {
492 // Clear the test image.
493 clearColorImage(vk, device, queue, m_context.getUniversalQueueFamilyIndex(), testImage.get(),
494 tcu::Vec4(0, 0, 0, 1), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, pipelineStage, 0u,
495 1u, 0u, mipLevelCount);
496 }
497
498 // Prepare the command buffer.
499 const Unique<VkCommandPool> cmdPool(makeCommandPool(vk, device, queueFamilyIndex));
500 const Unique<VkCommandBuffer> cmdBuffer(
501 allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
502
503 // Start recording commands.
504 beginCommandBuffer(vk, *cmdBuffer);
505
506 if (useSampler)
507 {
508 // Copy the input image to the target mip level.
509 std::vector<VkBufferImageCopy> copies;
510 copies.push_back(makeBufferImageCopy(
511 makeExtent3D(testMipLevelSize),
512 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, m_testParameters.mipLevel, 0, 1)));
513 copyBufferToImage(vk, *cmdBuffer, **inputImageBuffer, bufferSize, copies, VK_IMAGE_ASPECT_COLOR_BIT,
514 mipLevelCount, 1u, *testImage, VK_IMAGE_LAYOUT_GENERAL, pipelineStage);
515 }
516
517 const Move<VkDescriptorSetLayout> descriptorSetLayout(descriptorSetLayoutBuilder.build(vk, device));
518 const Move<VkDescriptorPool> descriptorPool(
519 descriptorPoolBuilder.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
520 const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
521 const VkDescriptorImageInfo testImageDescriptorInfo =
522 makeDescriptorImageInfo(*sampler, *imageView, VK_IMAGE_LAYOUT_GENERAL);
523
524 // Write descriptor update.
525 {
526 DescriptorSetUpdateBuilder descriptorSetUpdateBuilder;
527 uint32_t bindingIdx = 0;
528
529 switch (m_testParameters.imageType)
530 {
531 case StorageImage:
532 descriptorSetUpdateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
533 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &testImageDescriptorInfo);
534 break;
535 case Sampler:
536 descriptorSetUpdateBuilder.writeSingle(*descriptorSet,
537 DescriptorSetUpdateBuilder::Location::binding(bindingIdx++),
538 VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &testImageDescriptorInfo);
539 descriptorSetUpdateBuilder.writeSingle(*descriptorSet,
540 DescriptorSetUpdateBuilder::Location::binding(bindingIdx++),
541 VK_DESCRIPTOR_TYPE_SAMPLER, &testImageDescriptorInfo);
542 break;
543 case CombinedImageSampler:
544 descriptorSetUpdateBuilder.writeSingle(*descriptorSet,
545 DescriptorSetUpdateBuilder::Location::binding(bindingIdx++),
546 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &testImageDescriptorInfo);
547 break;
548 }
549
550 if (useSampler)
551 {
552 const VkDescriptorImageInfo resultImageDescriptorInfo =
553 makeDescriptorImageInfo(DE_NULL, *resultImageView, VK_IMAGE_LAYOUT_GENERAL);
554 descriptorSetUpdateBuilder.writeSingle(*descriptorSet,
555 DescriptorSetUpdateBuilder::Location::binding(bindingIdx),
556 VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &resultImageDescriptorInfo);
557 }
558
559 descriptorSetUpdateBuilder.update(vk, device);
560 }
561
562 if (m_testParameters.testType == Compute)
563 runComputePipeline(*descriptorSet, *descriptorSetLayout, testMipLevelSize, *cmdBuffer,
564 useSampler ? **resultImage : *testImage, *outputBuffer);
565 else
566 runGraphicsPipeline(*descriptorSet, *descriptorSetLayout, testMipLevelSize, *cmdBuffer,
567 useSampler ? **resultImage : *testImage, *outputBuffer);
568
569 // Validate the results.
570 {
571 // Create a reference image.
572 // 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.
573 tcu::TextureLevel referenceImage(textureFormat, testMipLevelSize.x(), testMipLevelSize.y(), 1u);
574 fillImage(referenceImage.getAccess(), 0u);
575
576 const Allocation &outputBufferAllocation = outputBuffer.getAllocation();
577 invalidateAlloc(vk, device, outputBufferAllocation);
578
579 const uint32_t *bufferPtr = static_cast<uint32_t *>(outputBufferAllocation.getHostPtr());
580 tcu::ConstPixelBufferAccess pixelBufferAccess(mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), testMipLevelSize.x(),
581 testMipLevelSize.y(), 1u, bufferPtr);
582
583 if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Result", "Result comparison",
584 referenceImage, pixelBufferAccess, tcu::Vec4(0.01f), tcu::COMPARE_LOG_ON_ERROR))
585 return tcu::TestStatus::fail("Pixel comparison failed.");
586 }
587
588 return tcu::TestStatus::pass("pass");
589 }
590
591 class ComputeImage2DView3DImageTest : public vkt::TestCase
592 {
593 public:
ComputeImage2DView3DImageTest(tcu::TestContext & testContext,const char * name,const TestParameters & testParameters)594 ComputeImage2DView3DImageTest(tcu::TestContext &testContext, const char *name, const TestParameters &testParameters)
595 : vkt::TestCase(testContext, name)
596 , m_testParameters(testParameters)
597 {
598 }
~ComputeImage2DView3DImageTest(void)599 virtual ~ComputeImage2DView3DImageTest(void)
600 {
601 }
602
603 virtual void initPrograms(SourceCollections &sourceCollections) const;
604 virtual void checkSupport(Context &context) const;
605 virtual TestInstance *createInstance(Context &context) const;
606
607 private:
608 const TestParameters m_testParameters;
609 };
610
checkSupport(Context & context) const611 void ComputeImage2DView3DImageTest::checkSupport(Context &context) const
612 {
613 DE_ASSERT(m_testParameters.pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC);
614
615 if (!context.isDeviceFunctionalitySupported("VK_EXT_image_2d_view_of_3d"))
616 TCU_THROW(NotSupportedError, "VK_EXT_image_2d_view_of_3d functionality not supported.");
617
618 if (!context.getImage2DViewOf3DFeaturesEXT().image2DViewOf3D)
619 TCU_THROW(NotSupportedError, "image2DViewOf3D not supported.");
620
621 if (m_testParameters.imageType != StorageImage && !context.getImage2DViewOf3DFeaturesEXT().sampler2DViewOf3D)
622 TCU_THROW(NotSupportedError, "sampler2DViewOf3D not supported.");
623 }
624
initPrograms(SourceCollections & sourceCollections) const625 void ComputeImage2DView3DImageTest::initPrograms(SourceCollections &sourceCollections) const
626 {
627 std::ostringstream src;
628 tcu::IVec3 mipLevelSize = computeMipLevelSize(m_testParameters.imageSize, m_testParameters.mipLevel);
629 if (m_testParameters.imageType == StorageImage)
630 {
631 src << "#version 450 core\n"
632 << "layout (local_size_x = 1, local_size_y = 1) in;\n"
633 << "layout (binding = 0, rgba8) writeonly uniform highp image2D storageImage;\n"
634 << "void main (void) {\n"
635 << " ivec2 uv = ivec2(gl_GlobalInvocationID.xy);\n"
636 << " float c = float((uv.x + uv.y) & 1);\n"
637 << " vec4 color = vec4(c, c, c, 1.0);\n"
638 << " imageStore(storageImage, uv, color);\n"
639 << "}\n";
640 }
641 else if (m_testParameters.imageType == Sampler)
642 {
643 src << "#version 450 core\n"
644 << "layout (local_size_x = 1, local_size_y = 1) in;\n"
645 << "layout (set=0, binding = 0) uniform texture2D image;\n"
646 << "layout (set=0, binding = 1) uniform sampler samp;\n"
647 << "layout (rgba8, set=0, binding = 2) writeonly uniform highp image2D verifyImage;\n"
648 << "void main (void) {\n"
649 << " ivec2 uv = ivec2(gl_GlobalInvocationID.xy);\n"
650 << " vec2 texCoord = vec2(gl_GlobalInvocationID.xy) / " << mipLevelSize.x() << ".0;\n"
651 << " vec4 color = texture(sampler2D(image, samp), texCoord);\n"
652 << " imageStore(verifyImage, uv, color);\n"
653 << "}\n";
654 }
655 else if (m_testParameters.imageType == CombinedImageSampler)
656 {
657 src << "#version 450 core\n"
658 << "layout (local_size_x = 1, local_size_y = 1) in;\n"
659 << "layout (binding = 0) uniform sampler2D combinedSampler;\n"
660 << "layout (rgba8, set=0, binding=1) writeonly uniform highp image2D verifyImage;\n"
661 << "void main (void) {\n"
662 << " ivec2 uv = ivec2(gl_GlobalInvocationID.xy);\n"
663 << " vec2 texCoord = vec2(gl_GlobalInvocationID.xy) / " << mipLevelSize.x() << ".0;\n"
664 << " vec4 color = texture(combinedSampler, texCoord);\n"
665 << " imageStore(verifyImage, uv, color);\n"
666 << "}\n";
667 }
668
669 sourceCollections.glslSources.add("comp") << glu::ComputeSource(src.str());
670 }
671
createInstance(Context & context) const672 TestInstance *ComputeImage2DView3DImageTest::createInstance(Context &context) const
673 {
674 return new Image2DView3DImageInstance(context, m_testParameters);
675 }
676
677 class FragmentImage2DView3DImageTest : public vkt::TestCase
678 {
679 public:
FragmentImage2DView3DImageTest(tcu::TestContext & testContext,const char * name,const TestParameters & testParameters)680 FragmentImage2DView3DImageTest(tcu::TestContext &testContext, const char *name,
681 const TestParameters &testParameters)
682 : vkt::TestCase(testContext, name)
683 , m_testParameters(testParameters)
684 {
685 }
~FragmentImage2DView3DImageTest(void)686 virtual ~FragmentImage2DView3DImageTest(void)
687 {
688 }
689
690 virtual void initPrograms(SourceCollections &sourceCollections) const;
691 virtual void checkSupport(Context &context) const;
692 virtual TestInstance *createInstance(Context &context) const;
693
694 private:
695 const TestParameters m_testParameters;
696 };
697
initPrograms(SourceCollections & sourceCollections) const698 void FragmentImage2DView3DImageTest::initPrograms(SourceCollections &sourceCollections) const
699 {
700 std::stringstream vertShader;
701 vertShader << "#version 450 core\n"
702 << "layout(location = 0) in vec4 in_position;\n"
703 << "out gl_PerVertex {\n"
704 << " vec4 gl_Position;\n"
705 << " float gl_PointSize;\n"
706 << "};\n"
707 << "void main() {\n"
708 << " gl_PointSize = 1.0;\n"
709 << " gl_Position = in_position;\n"
710 << "}\n";
711 sourceCollections.glslSources.add("vert") << glu::VertexSource(vertShader.str());
712
713 tcu::IVec3 mipLevelSize = computeMipLevelSize(m_testParameters.imageSize, m_testParameters.mipLevel);
714 std::stringstream fragShader;
715 if (m_testParameters.imageType == StorageImage)
716 {
717 fragShader << "#version 450 core\n"
718 << "layout(rgba8, set = 0, binding = 0) uniform image2D storageImage;\n"
719 << "void main()\n"
720 << "{\n"
721 << " ivec2 uv = ivec2(gl_FragCoord.xy);\n"
722 << " float c = float((uv.x + uv.y) & 1);\n"
723 << " vec4 color = vec4(c, c, c, 1.0);\n"
724 << " imageStore(storageImage, uv, color);\n"
725 << "}\n";
726 }
727
728 else if (m_testParameters.imageType == Sampler)
729 {
730 fragShader << "#version 450 core\n"
731 << "layout (set = 0, binding = 0) uniform texture2D image;\n"
732 << "layout (set = 0, binding = 1) uniform sampler samp;\n"
733 << "layout (rgba8, set = 0, binding = 2) uniform image2D verifyImage;\n"
734 << "void main (void) {\n"
735 << " ivec2 uv = ivec2(gl_FragCoord.xy);\n"
736 << " vec2 texCoord = gl_FragCoord.xy / " << mipLevelSize.x() << ".0;\n"
737 << " vec4 color = texture(sampler2D(image, samp), texCoord);\n"
738 << " imageStore(verifyImage, uv, color);\n"
739 << "}\n";
740 }
741 else if (m_testParameters.imageType == CombinedImageSampler)
742 {
743 fragShader << "#version 450 core\n"
744 << "layout (set = 0, binding = 0) uniform sampler2D combinedSampler;\n"
745 << "layout (rgba8, set = 0, binding = 1) uniform image2D verifyImage;\n"
746 << "void main (void) {\n"
747 << " ivec2 uv = ivec2(gl_FragCoord.xy);\n"
748 << " vec2 texCoord = gl_FragCoord.xy / " << mipLevelSize.x() << ".0;\n"
749 << " vec4 color = texture(combinedSampler, texCoord);\n"
750 << " imageStore(verifyImage, uv, color);\n"
751 << "}\n";
752 }
753 sourceCollections.glslSources.add("frag") << glu::FragmentSource(fragShader.str());
754 }
755
checkSupport(Context & context) const756 void FragmentImage2DView3DImageTest::checkSupport(Context &context) const
757 {
758 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
759 m_testParameters.pipelineConstructionType);
760
761 if (!context.isDeviceFunctionalitySupported("VK_EXT_image_2d_view_of_3d"))
762 TCU_THROW(NotSupportedError, "VK_EXT_image_2d_view_of_3d functionality not supported.");
763
764 if (!context.getImage2DViewOf3DFeaturesEXT().image2DViewOf3D)
765 TCU_THROW(NotSupportedError, "image2DViewOf3D not supported.");
766
767 if (m_testParameters.imageType != StorageImage && !context.getImage2DViewOf3DFeaturesEXT().sampler2DViewOf3D)
768 TCU_THROW(NotSupportedError, "texture2DViewOf3D not supported.");
769
770 if (!context.getDeviceFeatures().fragmentStoresAndAtomics)
771 TCU_THROW(NotSupportedError, "fragmentStoresAndAtomics not supported");
772 }
773
createInstance(Context & context) const774 TestInstance *FragmentImage2DView3DImageTest::createInstance(Context &context) const
775 {
776 return new Image2DView3DImageInstance(context, m_testParameters);
777 }
778
779 } // namespace
780
createImage2DViewOf3DTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)781 tcu::TestCaseGroup *createImage2DViewOf3DTests(tcu::TestContext &testCtx,
782 PipelineConstructionType pipelineConstructionType)
783 {
784 de::MovePtr<tcu::TestCaseGroup> imageTests(new tcu::TestCaseGroup(testCtx, "image_2d_view_3d_image"));
785 de::MovePtr<tcu::TestCaseGroup> computeGroup(new tcu::TestCaseGroup(testCtx, "compute"));
786 de::MovePtr<tcu::TestCaseGroup> fragmentGroup(new tcu::TestCaseGroup(testCtx, "fragment"));
787
788 const struct
789 {
790 const ImageAccessType imageType;
791 const std::string name;
792 } imageAccessTypes[]{
793 {StorageImage, "storage"}, {Sampler, "sampler"}, {CombinedImageSampler, "combined_image_sampler"}};
794
795 const int32_t imageDimension = 64;
796 for (const auto &imageAccessType : imageAccessTypes)
797 {
798 de::MovePtr<tcu::TestCaseGroup> computeSubGroup(new tcu::TestCaseGroup(testCtx, imageAccessType.name.c_str()));
799 de::MovePtr<tcu::TestCaseGroup> fragmentSubGroup(new tcu::TestCaseGroup(testCtx, imageAccessType.name.c_str()));
800 for (uint32_t mipLevel = 0; mipLevel < 3; mipLevel += 2)
801 {
802 // Test the first and the last layer of the mip level.
803 std::vector<int32_t> layers = {0, computeMipLevelDimension(imageDimension, mipLevel) - 1};
804 for (const auto &layer : layers)
805 {
806 TestParameters testParameters{
807 tcu::IVec3(imageDimension), // IVec3 imageSize
808 mipLevel, // uint32_t mipLevel
809 layer, // int32_t layerNdx
810 imageAccessType.imageType, // ImageAccessType imageType
811 Fragment, // TestType testType
812 VK_FORMAT_R8G8B8A8_UNORM, // VkFormat imageFormat
813 pipelineConstructionType // PipelineConstructionType pipelineConstructionType
814 };
815 std::string testName = "mip" + std::to_string(mipLevel) + "_layer" + std::to_string(layer);
816 fragmentSubGroup->addChild(
817 new FragmentImage2DView3DImageTest(testCtx, testName.c_str(), testParameters));
818
819 if (pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
820 {
821 testParameters.testType = Compute;
822 computeSubGroup->addChild(
823 new ComputeImage2DView3DImageTest(testCtx, testName.c_str(), testParameters));
824 }
825 }
826 }
827 computeGroup->addChild(computeSubGroup.release());
828 fragmentGroup->addChild(fragmentSubGroup.release());
829 }
830
831 imageTests->addChild(computeGroup.release());
832 imageTests->addChild(fragmentGroup.release());
833 return imageTests.release();
834 }
835
836 } // namespace pipeline
837 } // namespace vkt
838