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