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