| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2022 The Khronos Group Inc. |
| * Copyright (c) 2022 Google LLC. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktPipelineImage2DViewOf3DTests.hpp" |
| #include "vkPipelineConstructionUtil.hpp" |
| #include "vktTestCase.hpp" |
| #include "vkImageUtil.hpp" |
| #include "vkPrograms.hpp" |
| #include "vkTypeUtil.hpp" |
| #include "vkObjUtil.hpp" |
| #include "vkCmdUtil.hpp" |
| #include "vkBuilderUtil.hpp" |
| #include "vkImageWithMemory.hpp" |
| #include "vkBufferWithMemory.hpp" |
| #include "vkBarrierUtil.hpp" |
| #include "tcuTexture.hpp" |
| #include "tcuPlatform.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "deMemory.h" |
| |
| #include <sstream> |
| #include <vector> |
| |
| namespace vkt |
| { |
| namespace pipeline |
| { |
| |
| using namespace vk; |
| using de::MovePtr; |
| |
| namespace |
| { |
| enum ImageAccessType { |
| StorageImage = 0, |
| Sampler, |
| CombinedImageSampler |
| }; |
| |
| enum TestType { |
| Compute, |
| Fragment |
| }; |
| |
| struct TestParameters { |
| tcu::IVec3 imageSize; |
| uint32_t mipLevel; |
| int32_t layerNdx; |
| ImageAccessType imageType; |
| TestType testType; |
| VkFormat imageFormat; |
| PipelineConstructionType pipelineConstructionType; |
| }; |
| |
| inline int32_t computeMipLevelDimension (int32_t baseLevelDimension, uint32_t mipLevel) |
| { |
| return de::max(baseLevelDimension >> mipLevel, 1); |
| } |
| |
| tcu::IVec3 computeMipLevelSize (tcu::IVec3 baseLevelSize, uint32_t mipLevel) |
| { |
| int32_t width = computeMipLevelDimension(baseLevelSize.x(), mipLevel); |
| int32_t height = computeMipLevelDimension(baseLevelSize.y(), mipLevel); |
| int32_t depth = computeMipLevelDimension(baseLevelSize.z(), mipLevel); |
| return tcu::IVec3(width, height, depth); |
| } |
| |
| void copyImageLayerToBuffer (const DeviceInterface& vk, |
| VkCommandBuffer cmdBuffer, |
| VkImage image, |
| VkBuffer buffer, |
| tcu::IVec2 size, |
| VkAccessFlags srcAccessMask, |
| VkImageLayout oldLayout, |
| deUint32 layerToCopy, |
| uint32_t mipLevel) |
| { |
| const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 1u, 0, 1u); |
| const VkImageMemoryBarrier imageBarrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| srcAccessMask, // VkAccessFlags srcAccessMask |
| VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask |
| oldLayout, // VkImageLayout oldLayout |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 destQueueFamilyIndex |
| image, // VkImage image |
| subresourceRange // VkImageSubresourceRange subresourceRange |
| }; |
| |
| vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, |
| 0u, DE_NULL, 0u, DE_NULL, 1u, &imageBarrier); |
| |
| const VkImageSubresourceLayers subresource = |
| { |
| subresourceRange.aspectMask, // VkImageAspectFlags aspectMask |
| mipLevel, // deUint32 mipLevel |
| 0u, // deUint32 baseArrayLayer |
| 1u, // deUint32 layerCount |
| }; |
| |
| const VkBufferImageCopy region = |
| { |
| 0ull, // VkDeviceSize bufferOffset |
| 0u, // deUint32 bufferRowLength |
| 0u, // deUint32 bufferImageHeight |
| subresource, // VkImageSubresourceLayers imageSubresource |
| makeOffset3D(0, 0, (int)layerToCopy), // VkOffset3D imageOffset |
| makeExtent3D(size.x(), size.y(), 1u) // VkExtent3D imageExtent |
| }; |
| |
| vk.cmdCopyImageToBuffer(cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, 1u, ®ion); |
| |
| const VkBufferMemoryBarrier bufferBarrier = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask |
| VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex |
| buffer, // VkBuffer buffer |
| 0ull, // VkDeviceSize offset |
| VK_WHOLE_SIZE // VkDeviceSize size |
| }; |
| |
| vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, |
| 0u, DE_NULL, 1u, &bufferBarrier, 0u, DE_NULL); |
| } |
| |
| // Draws a chess pattern to the given 'layer' (z-dimension) of the 'image'. Other layers will be cleared to white. |
| void fillImage (const tcu::PixelBufferAccess& image, const int layer) |
| { |
| const tcu::Vec4 clearColor = tcu::Vec4(1); // White clear color. |
| for (int z = 0; z < image.getSize().z(); ++z) |
| for (int y = 0; y < image.getSize().y(); ++y) |
| for (int x = 0; x < image.getSize().x(); ++x) |
| { |
| if (z == layer) |
| { |
| const float c = (float)((x + y) & 1); |
| const tcu::Vec4 color = tcu::Vec4(c, c, c, 1.0f); |
| image.setPixel(color, x, y, z); |
| } |
| else |
| { |
| image.setPixel(clearColor, x, y, z); |
| } |
| } |
| } |
| |
| |
| class Image2DView3DImageInstance : public vkt::TestInstance |
| { |
| public: |
| Image2DView3DImageInstance (Context& context, |
| const TestParameters testParameters) |
| : vkt::TestInstance(context), |
| m_testParameters(testParameters) |
| {} |
| |
| tcu::TestStatus iterate (void); |
| private: |
| void runComputePipeline (const VkDescriptorSet& descriptorSet, |
| const VkDescriptorSetLayout descriptorSetLayout, |
| tcu::IVec3& testMipLevelSize, |
| VkCommandBuffer cmdBuffer, |
| VkImage image, |
| VkBuffer outputBuffer); |
| |
| void runGraphicsPipeline (const VkDescriptorSet& descriptorSet, |
| const VkDescriptorSetLayout descriptorSetLayout, |
| tcu::IVec3& testMipLevelSize, |
| VkCommandBuffer cmdBuffer, |
| VkImage image, |
| VkBuffer outputBuffer); |
| const TestParameters m_testParameters; |
| }; |
| |
| void Image2DView3DImageInstance::runComputePipeline (const VkDescriptorSet& descriptorSet, |
| const VkDescriptorSetLayout descriptorSetLayout, |
| tcu::IVec3& testMipLevelSize, |
| VkCommandBuffer cmdBuffer, |
| VkImage image, |
| VkBuffer outputBuffer) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| const bool useSampler = m_testParameters.imageType != StorageImage; |
| |
| const Unique<VkShaderModule> shaderModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0u)); |
| const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, descriptorSetLayout)); |
| const Unique<VkPipeline> pipeline (makeComputePipeline(vk, device, *pipelineLayout, *shaderModule)); |
| |
| vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline); |
| vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL); |
| vk.cmdDispatch(cmdBuffer, testMipLevelSize.x(), testMipLevelSize.y(), 1u); |
| |
| // Copy the result image to a buffer. |
| 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); |
| |
| endCommandBuffer(vk, cmdBuffer); |
| |
| // Wait for completion. |
| submitCommandsAndWait(vk, device, queue, cmdBuffer); |
| } |
| |
| void Image2DView3DImageInstance::runGraphicsPipeline (const VkDescriptorSet& descriptorSet, |
| const VkDescriptorSetLayout descriptorSetLayout, |
| tcu::IVec3& testMipLevelSize, |
| VkCommandBuffer cmdBuffer, |
| VkImage image, |
| VkBuffer outputBuffer) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| const bool useSampler = m_testParameters.imageType != StorageImage; |
| |
| const Unique<VkShaderModule> vertShader (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u)); |
| const Unique<VkShaderModule> fragShader (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u)); |
| const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, descriptorSetLayout)); |
| const Move<VkRenderPass> renderPass = makeRenderPass(vk, device); |
| const std::vector<VkViewport> viewport = {makeViewport (m_testParameters.imageSize.x(), m_testParameters.imageSize.y())}; |
| const std::vector<VkRect2D> scissor = {makeRect2D (m_testParameters.imageSize.x(), m_testParameters.imageSize.y())}; |
| |
| const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkPipelineInputAssemblyStateCreateFlags flags |
| VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, // VkPrimitiveTopology topology |
| VK_FALSE // VkBool32 primitiveRestartEnable |
| }; |
| |
| const VkVertexInputBindingDescription vertexInputBindingDescription = |
| { |
| 0u, // deUint32 binding |
| sizeof(tcu::Vec4), // deUint32 stride |
| VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate |
| }; |
| |
| const VkVertexInputAttributeDescription vertexInputAttributeDescription = |
| { |
| 0u, // deUint32 location |
| 0u, // deUint32 binding |
| VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format |
| 0u // deUint32 offset |
| }; |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfoDefault = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags |
| 1u, // deUint32 vertexBindingDescriptionCount |
| &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions |
| 1u, // deUint32 vertexAttributeDescriptionCount |
| &vertexInputAttributeDescription // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions |
| }; |
| |
| vk::GraphicsPipelineWrapper graphicsPipeline (vk, device, m_testParameters.pipelineConstructionType, 0u); |
| graphicsPipeline.setMonolithicPipelineLayout(*pipelineLayout) |
| .setDefaultDepthStencilState() |
| .setDefaultRasterizationState() |
| .setDefaultMultisampleState() |
| .setupVertexInputStete(&vertexInputStateCreateInfoDefault, &inputAssemblyStateCreateInfo) |
| .setupPreRasterizationShaderState(viewport, |
| scissor, |
| *pipelineLayout, |
| *renderPass, |
| 0u, |
| *vertShader) |
| .setupFragmentShaderState(*pipelineLayout, *renderPass, 0u, *fragShader) |
| .setupFragmentOutputState(*renderPass, 0u) |
| .buildPipeline(); |
| |
| const Move<VkFramebuffer> framebuffer = makeFramebuffer(vk, device, *renderPass, 0u, DE_NULL, testMipLevelSize.x(), testMipLevelSize.y()); |
| |
| // Create vertex buffer and fill it with full screen quad. |
| const std::vector<tcu::Vec4> vertexData = { |
| {-1, -1, 1, 1}, |
| { 1, -1, 1, 1}, |
| { 1, 1, 1, 1}, |
| {-1, 1, 1, 1}, |
| }; |
| size_t vertexBufferSize = sizeof(tcu::Vec4) * vertexData.size(); |
| BufferWithMemory vertexBuffer( |
| vk, |
| device, |
| m_context.getDefaultAllocator(), |
| makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), |
| MemoryRequirement::HostVisible); |
| deMemcpy(vertexBuffer.getAllocation().getHostPtr(), vertexData.data(), vertexBufferSize); |
| flushAlloc(vk, device, vertexBuffer.getAllocation()); |
| |
| VkDeviceSize vertexBufferOffset = 0; |
| vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &*vertexBuffer, &vertexBufferOffset); |
| |
| vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.getPipeline()); |
| vk.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL); |
| |
| beginRenderPass(vk, cmdBuffer, *renderPass, *framebuffer, makeRect2D(testMipLevelSize.xy())); |
| vk.cmdDraw(cmdBuffer, 4, 1, 0, 0); |
| endRenderPass(vk, cmdBuffer); |
| |
| // Copy the result image to a buffer. |
| 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); |
| |
| endCommandBuffer(vk, cmdBuffer); |
| |
| // Wait for completion. |
| submitCommandsAndWait(vk, device, queue, cmdBuffer); |
| } |
| |
| tcu::TestStatus Image2DView3DImageInstance::iterate (void) |
| { |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice device = m_context.getDevice(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); |
| Allocator& allocator = m_context.getDefaultAllocator(); |
| tcu::IVec3 imageSize = m_testParameters.imageSize; |
| const bool useSampler = m_testParameters.imageType != StorageImage; |
| const tcu::TextureFormat textureFormat = mapVkFormat(m_testParameters.imageFormat); |
| const uint32_t mipLevelCount = 3; |
| |
| tcu::IVec3 testMipLevelSize = computeMipLevelSize(m_testParameters.imageSize, m_testParameters.mipLevel); |
| uint32_t bufferSize = testMipLevelSize.x() * testMipLevelSize.y() * testMipLevelSize.z() * textureFormat.getPixelSize(); |
| const BufferWithMemory outputBuffer (vk, device, allocator, makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible); |
| |
| // Input image is used with sampler cases only. |
| de::MovePtr<BufferWithMemory> inputImageBuffer; |
| |
| // Upload the test image data for sampler cases. |
| if (useSampler) |
| { |
| // Initialize the input image's mip level and fill the target layer with a chess pattern, others will be white. |
| tcu::TextureLevel inputImageMipLevel (textureFormat, testMipLevelSize.x(), testMipLevelSize.y(), testMipLevelSize.z()); |
| fillImage(inputImageMipLevel.getAccess(), m_testParameters.layerNdx); |
| |
| // Create a buffer to upload the image. |
| const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| inputImageBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vk, device, allocator, bufferCreateInfo, MemoryRequirement::HostVisible)); |
| |
| // Upload target mip level to the input buffer. |
| deMemcpy(inputImageBuffer->getAllocation().getHostPtr(), inputImageMipLevel.getAccess().getDataPtr(), bufferSize); |
| flushAlloc(vk, device, inputImageBuffer->getAllocation()); |
| } |
| |
| // Create the test image: sampled image or storage image, depending on the test type. |
| const VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | |
| VK_IMAGE_USAGE_TRANSFER_DST_BIT | |
| (useSampler ? VK_IMAGE_USAGE_SAMPLED_BIT : VK_IMAGE_USAGE_STORAGE_BIT); |
| const VkImageCreateInfo imageCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT, // VkImageCreateFlags flags |
| VK_IMAGE_TYPE_3D, // VkImageType imageType |
| m_testParameters.imageFormat, // VkFormat format |
| makeExtent3D(imageSize.x(), imageSize.y(), imageSize.z()), // VkExtent3D extent |
| (uint32_t)mipLevelCount, // uint32_t mipLevels |
| 1u, // uint32_t arrayLayers |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling |
| usage, // VkImageUsageFlags usage |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode |
| 0u, // uint32_t queueFamilyIndexCount |
| DE_NULL, // const uint32_t* pQueueFamilyIndices |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout |
| }; |
| ImageWithMemory testImage (vk, device, allocator, imageCreateInfo, MemoryRequirement::Any); |
| |
| // Make an image view covering one of the mip levels. |
| const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, m_testParameters.mipLevel, 1u, m_testParameters.layerNdx, 1u); |
| const Unique<VkImageView> imageView (makeImageView(vk, device, *testImage, VK_IMAGE_VIEW_TYPE_2D, m_testParameters.imageFormat, subresourceRange)); |
| |
| // resultImage is used in sampler / combined image sampler tests to verify the sampled image. |
| MovePtr<ImageWithMemory> resultImage; |
| Move<VkImageView> resultImageView; |
| Move<VkSampler> sampler; |
| if (useSampler) |
| { |
| const VkImageCreateInfo resultImageCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0U, // VkImageCreateFlags flags |
| VK_IMAGE_TYPE_2D, // VkImageType imageType |
| m_testParameters.imageFormat, // VkFormat format |
| makeExtent3D(testMipLevelSize.x(), testMipLevelSize.y(), 1), // VkExtent3D extent |
| 1u, // deUint32 mipLevels |
| 1u, // deUint32 arrayLayers |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling |
| VK_IMAGE_USAGE_STORAGE_BIT | |
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT | |
| VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode |
| 0u, // deUint32 queueFamilyIndexCount |
| DE_NULL, // const deUint32* pQueueFamilyIndices |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout |
| }; |
| |
| resultImage = MovePtr<ImageWithMemory>(new ImageWithMemory(vk, device, allocator, resultImageCreateInfo, MemoryRequirement::Any)); |
| const VkImageSubresourceRange resultImgSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); |
| resultImageView = makeImageView(vk, device, **resultImage, VK_IMAGE_VIEW_TYPE_2D, m_testParameters.imageFormat, resultImgSubresourceRange); |
| |
| const VkSamplerCreateInfo samplerCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkSamplerCreateFlags)0, // VkSamplerCreateFlags flags |
| VK_FILTER_NEAREST, // VkFilter magFilter |
| VK_FILTER_NEAREST, // VkFilter minFilter |
| VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeU |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeV |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW |
| 0.0f, // float mipLodBias |
| VK_FALSE, // VkBool32 anisotropyEnable |
| 1.0f, // float maxAnisotropy |
| VK_FALSE, // VkBool32 compareEnable |
| VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp |
| 0.0f, // float minLod |
| 1.0f, // float maxLod |
| VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor |
| VK_FALSE, // VkBool32 unnormalizedCoordinates |
| }; |
| sampler = createSampler(vk, device, &samplerCreateInfo); |
| } |
| |
| |
| // Create the descriptor set. |
| DescriptorSetLayoutBuilder descriptorSetLayoutBuilder; |
| DescriptorPoolBuilder descriptorPoolBuilder; |
| |
| VkShaderStageFlags shaderStage = m_testParameters.testType == Compute ? VK_SHADER_STAGE_COMPUTE_BIT : VK_SHADER_STAGE_FRAGMENT_BIT; |
| VkPipelineStageFlags pipelineStage = m_testParameters.testType == Compute ? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; |
| switch (m_testParameters.imageType) |
| { |
| case StorageImage: |
| descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStage); |
| descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); |
| break; |
| case Sampler: |
| descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, shaderStage); |
| descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_SAMPLER, shaderStage); |
| descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStage); |
| descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); |
| descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLER); |
| descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); |
| break; |
| case CombinedImageSampler: |
| descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, shaderStage); |
| descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, shaderStage); |
| descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); |
| descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); |
| break; |
| default: |
| TCU_THROW(InternalError, "Unimplemented testImage type."); |
| } |
| |
| if (useSampler) |
| { |
| // Clear the result image. |
| 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); |
| } |
| else |
| { |
| // Clear the test image. |
| 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); |
| } |
| |
| // Prepare the command buffer. |
| const Unique<VkCommandPool> cmdPool (makeCommandPool(vk, device, queueFamilyIndex)); |
| const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| |
| // Start recording commands. |
| beginCommandBuffer(vk, *cmdBuffer); |
| |
| if (useSampler) |
| { |
| // Copy the input image to the target mip level. |
| std::vector<VkBufferImageCopy> copies; |
| copies.push_back(makeBufferImageCopy(makeExtent3D(testMipLevelSize), makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, m_testParameters.mipLevel, 0, 1))); |
| copyBufferToImage(vk, *cmdBuffer, **inputImageBuffer, bufferSize, copies, VK_IMAGE_ASPECT_COLOR_BIT, mipLevelCount, 1u, *testImage, VK_IMAGE_LAYOUT_GENERAL, pipelineStage); |
| } |
| |
| const Move<VkDescriptorSetLayout> descriptorSetLayout (descriptorSetLayoutBuilder.build(vk, device)); |
| const Move<VkDescriptorPool> descriptorPool (descriptorPoolBuilder.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u)); |
| const Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout)); |
| const VkDescriptorImageInfo testImageDescriptorInfo = makeDescriptorImageInfo(*sampler, *imageView, VK_IMAGE_LAYOUT_GENERAL); |
| |
| // Write descriptor update. |
| { |
| DescriptorSetUpdateBuilder descriptorSetUpdateBuilder; |
| uint32_t bindingIdx = 0; |
| |
| switch (m_testParameters.imageType) |
| { |
| case StorageImage: |
| descriptorSetUpdateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &testImageDescriptorInfo); |
| break; |
| case Sampler: |
| descriptorSetUpdateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bindingIdx++), VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &testImageDescriptorInfo); |
| descriptorSetUpdateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bindingIdx++), VK_DESCRIPTOR_TYPE_SAMPLER, &testImageDescriptorInfo); |
| break; |
| case CombinedImageSampler: |
| descriptorSetUpdateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bindingIdx++), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &testImageDescriptorInfo); |
| break; |
| } |
| |
| if (useSampler) |
| { |
| const VkDescriptorImageInfo resultImageDescriptorInfo = makeDescriptorImageInfo(DE_NULL, *resultImageView, VK_IMAGE_LAYOUT_GENERAL); |
| descriptorSetUpdateBuilder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bindingIdx), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &resultImageDescriptorInfo); |
| } |
| |
| descriptorSetUpdateBuilder.update(vk, device); |
| } |
| |
| if (m_testParameters.testType == Compute) |
| runComputePipeline(*descriptorSet, *descriptorSetLayout, testMipLevelSize, *cmdBuffer, useSampler ? **resultImage : *testImage, *outputBuffer); |
| else |
| runGraphicsPipeline(*descriptorSet, *descriptorSetLayout, testMipLevelSize, *cmdBuffer, useSampler ? **resultImage : *testImage, *outputBuffer); |
| |
| // Validate the results. |
| { |
| // Create a reference image. |
| // 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. |
| tcu::TextureLevel referenceImage (textureFormat, testMipLevelSize.x(), testMipLevelSize.y(), 1u); |
| fillImage(referenceImage.getAccess(), 0u); |
| |
| const Allocation& outputBufferAllocation = outputBuffer.getAllocation(); |
| invalidateAlloc(vk, device, outputBufferAllocation); |
| |
| const deUint32* bufferPtr = static_cast<deUint32*>(outputBufferAllocation.getHostPtr()); |
| tcu::ConstPixelBufferAccess pixelBufferAccess (mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), testMipLevelSize.x(), testMipLevelSize.y(), 1u, bufferPtr); |
| |
| if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Result", "Result comparison", referenceImage, pixelBufferAccess, tcu::Vec4(0.01f), tcu::COMPARE_LOG_ON_ERROR)) |
| return tcu::TestStatus::fail("Pixel comparison failed."); |
| |
| } |
| |
| return tcu::TestStatus::pass("pass"); |
| } |
| |
| class ComputeImage2DView3DImageTest : public vkt::TestCase |
| { |
| public: |
| ComputeImage2DView3DImageTest (tcu::TestContext& testContext, |
| const char* name, |
| const char* description, |
| const TestParameters& testParameters) |
| : vkt::TestCase (testContext, name, description), |
| m_testParameters (testParameters) {} |
| virtual ~ComputeImage2DView3DImageTest (void) {} |
| |
| virtual void initPrograms (SourceCollections& sourceCollections) const; |
| virtual void checkSupport (Context& context) const; |
| virtual TestInstance* createInstance (Context& context) const; |
| private: |
| const TestParameters m_testParameters; |
| }; |
| |
| |
| void ComputeImage2DView3DImageTest::checkSupport (Context& context) const |
| { |
| DE_ASSERT(m_testParameters.pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC); |
| |
| if (!context.isDeviceFunctionalitySupported("VK_EXT_image_2d_view_of_3d")) |
| TCU_THROW(NotSupportedError, "VK_EXT_image_2d_view_of_3d functionality not supported."); |
| |
| if (!context.getImage2DViewOf3DFeaturesEXT().image2DViewOf3D) |
| TCU_THROW(NotSupportedError, "image2DViewOf3D not supported."); |
| |
| if (m_testParameters.imageType != StorageImage && !context.getImage2DViewOf3DFeaturesEXT().sampler2DViewOf3D) |
| TCU_THROW(NotSupportedError, "sampler2DViewOf3D not supported."); |
| } |
| |
| void ComputeImage2DView3DImageTest::initPrograms (SourceCollections& sourceCollections) const |
| { |
| std::ostringstream src; |
| tcu::IVec3 mipLevelSize = computeMipLevelSize(m_testParameters.imageSize, m_testParameters.mipLevel); |
| if (m_testParameters.imageType == StorageImage) |
| { |
| src << "#version 450 core\n" |
| << "layout (local_size_x = 1, local_size_y = 1) in;\n" |
| << "layout (binding = 0, rgba8) writeonly uniform highp image2D storageImage;\n" |
| << "void main (void) {\n" |
| << " ivec2 uv = ivec2(gl_GlobalInvocationID.xy);\n" |
| << " float c = float((uv.x + uv.y) & 1);\n" |
| << " vec4 color = vec4(c, c, c, 1.0);\n" |
| << " imageStore(storageImage, uv, color);\n" |
| << "}\n"; |
| } |
| else if (m_testParameters.imageType == Sampler) |
| { |
| src << "#version 450 core\n" |
| << "layout (local_size_x = 1, local_size_y = 1) in;\n" |
| << "layout (set=0, binding = 0) uniform texture2D image;\n" |
| << "layout (set=0, binding = 1) uniform sampler samp;\n" |
| << "layout (rgba8, set=0, binding = 2) writeonly uniform highp image2D verifyImage;\n" |
| << "void main (void) {\n" |
| << " ivec2 uv = ivec2(gl_GlobalInvocationID.xy);\n" |
| << " vec2 texCoord = vec2(gl_GlobalInvocationID.xy) / " << mipLevelSize.x() <<".0;\n" |
| << " vec4 color = texture(sampler2D(image, samp), texCoord);\n" |
| << " imageStore(verifyImage, uv, color);\n" |
| << "}\n"; |
| } |
| else if (m_testParameters.imageType == CombinedImageSampler) |
| { |
| src << "#version 450 core\n" |
| << "layout (local_size_x = 1, local_size_y = 1) in;\n" |
| << "layout (binding = 0) uniform sampler2D combinedSampler;\n" |
| << "layout (rgba8, set=0, binding=1) writeonly uniform highp image2D verifyImage;\n" |
| << "void main (void) {\n" |
| << " ivec2 uv = ivec2(gl_GlobalInvocationID.xy);\n" |
| << " vec2 texCoord = vec2(gl_GlobalInvocationID.xy) / " << mipLevelSize.x() <<".0;\n" |
| << " vec4 color = texture(combinedSampler, texCoord);\n" |
| << " imageStore(verifyImage, uv, color);\n" |
| << "}\n"; |
| } |
| |
| sourceCollections.glslSources.add("comp") << glu::ComputeSource(src.str()); |
| } |
| |
| TestInstance* ComputeImage2DView3DImageTest::createInstance (Context& context) const |
| { |
| return new Image2DView3DImageInstance(context, m_testParameters); |
| } |
| |
| class FragmentImage2DView3DImageTest : public vkt::TestCase |
| { |
| public: |
| FragmentImage2DView3DImageTest (tcu::TestContext& testContext, |
| const char* name, |
| const char* description, |
| const TestParameters& testParameters) |
| : vkt::TestCase (testContext, name, description), |
| m_testParameters (testParameters) {} |
| virtual ~FragmentImage2DView3DImageTest (void) {} |
| |
| virtual void initPrograms (SourceCollections& sourceCollections) const; |
| virtual void checkSupport (Context& context) const; |
| virtual TestInstance* createInstance (Context& context) const; |
| private: |
| const TestParameters m_testParameters; |
| }; |
| |
| void FragmentImage2DView3DImageTest::initPrograms (SourceCollections& sourceCollections) const |
| { |
| std::stringstream vertShader; |
| vertShader << "#version 450 core\n" |
| << "layout(location = 0) in vec4 in_position;\n" |
| << "out gl_PerVertex {\n" |
| << " vec4 gl_Position;\n" |
| << " float gl_PointSize;\n" |
| << "};\n" |
| << "void main() {\n" |
| << " gl_PointSize = 1.0;\n" |
| << " gl_Position = in_position;\n" |
| << "}\n"; |
| sourceCollections.glslSources.add("vert") << glu::VertexSource(vertShader.str()); |
| |
| tcu::IVec3 mipLevelSize = computeMipLevelSize(m_testParameters.imageSize, m_testParameters.mipLevel); |
| std::stringstream fragShader; |
| if (m_testParameters.imageType == StorageImage) |
| { |
| fragShader << "#version 450 core\n" |
| << "layout(rgba8, set = 0, binding = 0) uniform image2D storageImage;\n" |
| << "void main()\n" |
| << "{\n" |
| << " ivec2 uv = ivec2(gl_FragCoord.xy);\n" |
| << " float c = float((uv.x + uv.y) & 1);\n" |
| << " vec4 color = vec4(c, c, c, 1.0);\n" |
| << " imageStore(storageImage, uv, color);\n" |
| << "}\n"; |
| } |
| |
| else if (m_testParameters.imageType == Sampler) |
| { |
| fragShader << "#version 450 core\n" |
| << "layout (set = 0, binding = 0) uniform texture2D image;\n" |
| << "layout (set = 0, binding = 1) uniform sampler samp;\n" |
| << "layout (rgba8, set = 0, binding = 2) uniform image2D verifyImage;\n" |
| << "void main (void) {\n" |
| << " ivec2 uv = ivec2(gl_FragCoord.xy);\n" |
| << " vec2 texCoord = gl_FragCoord.xy / " << mipLevelSize.x() <<".0;\n" |
| << " vec4 color = texture(sampler2D(image, samp), texCoord);\n" |
| << " imageStore(verifyImage, uv, color);\n" |
| << "}\n"; |
| } |
| else if (m_testParameters.imageType == CombinedImageSampler) |
| { |
| fragShader << "#version 450 core\n" |
| << "layout (set = 0, binding = 0) uniform sampler2D combinedSampler;\n" |
| << "layout (rgba8, set = 0, binding = 1) uniform image2D verifyImage;\n" |
| << "void main (void) {\n" |
| << " ivec2 uv = ivec2(gl_FragCoord.xy);\n" |
| << " vec2 texCoord = gl_FragCoord.xy / " << mipLevelSize.x() <<".0;\n" |
| << " vec4 color = texture(combinedSampler, texCoord);\n" |
| << " imageStore(verifyImage, uv, color);\n" |
| << "}\n"; |
| } |
| sourceCollections.glslSources.add("frag") << glu::FragmentSource(fragShader.str()); |
| } |
| |
| void FragmentImage2DView3DImageTest::checkSupport (Context& context) const |
| { |
| checkPipelineLibraryRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_testParameters.pipelineConstructionType); |
| |
| if (!context.isDeviceFunctionalitySupported("VK_EXT_image_2d_view_of_3d")) |
| TCU_THROW(NotSupportedError, "VK_EXT_image_2d_view_of_3d functionality not supported."); |
| |
| if (!context.getImage2DViewOf3DFeaturesEXT().image2DViewOf3D) |
| TCU_THROW(NotSupportedError, "image2DViewOf3D not supported."); |
| |
| if (m_testParameters.imageType != StorageImage && !context.getImage2DViewOf3DFeaturesEXT().sampler2DViewOf3D) |
| TCU_THROW(NotSupportedError, "texture2DViewOf3D not supported."); |
| |
| if (!context.getDeviceFeatures().fragmentStoresAndAtomics) |
| TCU_THROW(NotSupportedError, "fragmentStoresAndAtomics not supported"); |
| } |
| |
| TestInstance* FragmentImage2DView3DImageTest::createInstance (Context& context) const |
| { |
| return new Image2DView3DImageInstance(context, m_testParameters); |
| } |
| |
| } // anonymous |
| |
| tcu::TestCaseGroup* createImage2DViewOf3DTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType) |
| { |
| de::MovePtr<tcu::TestCaseGroup> imageTests (new tcu::TestCaseGroup(testCtx, "image_2d_view_3d_image", "2D view 3D image tests")); |
| de::MovePtr<tcu::TestCaseGroup> computeGroup (new tcu::TestCaseGroup(testCtx, "compute", "Compute shader tests.")); |
| de::MovePtr<tcu::TestCaseGroup> fragmentGroup (new tcu::TestCaseGroup(testCtx, "fragment", "Fragment shader tests.")); |
| |
| const struct { |
| const ImageAccessType imageType; |
| const std::string name; |
| } imageAccessTypes [] { |
| { StorageImage, "storage" }, |
| { Sampler, "sampler" }, |
| { CombinedImageSampler, "combined_image_sampler" } |
| }; |
| |
| const int32_t imageDimension = 64; |
| for (const auto& imageAccessType : imageAccessTypes) |
| { |
| de::MovePtr<tcu::TestCaseGroup> computeSubGroup (new tcu::TestCaseGroup(testCtx, imageAccessType.name.c_str(), "Fragment shader tests.")); |
| de::MovePtr<tcu::TestCaseGroup> fragmentSubGroup (new tcu::TestCaseGroup(testCtx, imageAccessType.name.c_str(), "Fragment shader tests.")); |
| for (uint32_t mipLevel = 0; mipLevel < 3; mipLevel += 2) |
| { |
| // Test the first and the last layer of the mip level. |
| std::vector<int32_t> layers = { 0, computeMipLevelDimension(imageDimension, mipLevel) -1 }; |
| for (const auto& layer : layers) |
| { |
| TestParameters testParameters { |
| tcu::IVec3(imageDimension), // IVec3 imageSize |
| mipLevel, // uint32_t mipLevel |
| layer, // int32_t layerNdx |
| imageAccessType.imageType, // ImageAccessType imageType |
| Fragment, // TestType testType |
| VK_FORMAT_R8G8B8A8_UNORM, // VkFormat imageFormat |
| pipelineConstructionType // PipelineConstructionType pipelineConstructionType |
| }; |
| std::string testName = "mip" + std::to_string(mipLevel) + "_layer" + std::to_string(layer); |
| fragmentSubGroup->addChild(new FragmentImage2DView3DImageTest(testCtx, testName.c_str(), "description", testParameters)); |
| |
| if (pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC) |
| { |
| testParameters.testType = Compute; |
| computeSubGroup->addChild(new ComputeImage2DView3DImageTest(testCtx, testName.c_str(), "description", testParameters)); |
| } |
| } |
| } |
| computeGroup->addChild(computeSubGroup.release()); |
| fragmentGroup->addChild(fragmentSubGroup.release()); |
| } |
| |
| imageTests->addChild(computeGroup.release()); |
| imageTests->addChild(fragmentGroup.release()); |
| return imageTests.release(); |
| } |
| |
| } // pipeline |
| } // vkt |