| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2017 The Khronos Group Inc. |
| * |
| * 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 vktPipelineRenderToImageTests.cpp |
| * \brief Render to image tests |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktPipelineRenderToImageTests.hpp" |
| #include "vktPipelineMakeUtil.hpp" |
| #include "vktTestCase.hpp" |
| #include "vktTestCaseUtil.hpp" |
| #include "vktPipelineVertexUtil.hpp" |
| #include "vktTestGroupUtil.hpp" |
| #include "vkObjUtil.hpp" |
| |
| #include "vkMemUtil.hpp" |
| #include "vkQueryUtil.hpp" |
| #include "vkTypeUtil.hpp" |
| #include "vkRefUtil.hpp" |
| #include "vkBuilderUtil.hpp" |
| #include "vkPrograms.hpp" |
| #include "vkImageUtil.hpp" |
| #include "vkCmdUtil.hpp" |
| |
| #include "tcuTextureUtil.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "tcuTestLog.hpp" |
| #include "tcuPlatform.hpp" |
| #include "vkPlatform.hpp" |
| |
| #include "deUniquePtr.hpp" |
| #include "deSharedPtr.hpp" |
| |
| #include <string> |
| #include <vector> |
| #include <set> |
| |
| namespace vkt |
| { |
| namespace pipeline |
| { |
| namespace |
| { |
| using namespace vk; |
| using de::UniquePtr; |
| using de::MovePtr; |
| using de::SharedPtr; |
| using tcu::IVec3; |
| using tcu::Vec4; |
| using tcu::UVec4; |
| using tcu::IVec2; |
| using tcu::IVec4; |
| using tcu::BVec4; |
| using std::vector; |
| |
| typedef SharedPtr<Unique<VkImageView> > SharedPtrVkImageView; |
| typedef SharedPtr<Unique<VkPipeline> > SharedPtrVkPipeline; |
| |
| enum Constants |
| { |
| NUM_CUBE_FACES = 6, |
| REFERENCE_COLOR_VALUE = 125, |
| REFERENCE_STENCIL_VALUE = 42, |
| MAX_SIZE = -1, //!< Should be queried at runtime and replaced with max possible value |
| MAX_VERIFICATION_REGION_SIZE = 32, //!< Limit the checked area to a small size, especially for huge images |
| MAX_VERIFICATION_REGION_DEPTH = 8, |
| |
| MASK_W = (1 | 0 | 0 | 0), |
| MASK_W_LAYERS = (1 | 0 | 0 | 8), |
| MASK_WH = (1 | 2 | 0 | 0), |
| MASK_WH_LAYERS = (1 | 2 | 0 | 8), |
| MASK_WHD = (1 | 2 | 4 | 0), |
| }; |
| |
| enum AllocationKind |
| { |
| ALLOCATION_KIND_SUBALLOCATED = 0, |
| ALLOCATION_KIND_DEDICATED, |
| }; |
| |
| static const float REFERENCE_DEPTH_VALUE = 1.0f; |
| static const Vec4 COLOR_TABLE[] = |
| { |
| Vec4(0.9f, 0.0f, 0.0f, 1.0f), |
| Vec4(0.6f, 1.0f, 0.0f, 1.0f), |
| Vec4(0.3f, 0.0f, 1.0f, 1.0f), |
| Vec4(0.1f, 1.0f, 1.0f, 1.0f), |
| Vec4(0.8f, 1.0f, 0.0f, 1.0f), |
| Vec4(0.5f, 0.0f, 1.0f, 1.0f), |
| Vec4(0.2f, 0.0f, 0.0f, 1.0f), |
| Vec4(1.0f, 1.0f, 0.0f, 1.0f), |
| }; |
| |
| struct CaseDef |
| { |
| VkImageViewType viewType; |
| IVec4 imageSizeHint; //!< (w, h, d, layers), a component may have a symbolic value MAX_SIZE |
| VkFormat colorFormat; |
| VkFormat depthStencilFormat; //! A depth/stencil format, or UNDEFINED if not used |
| AllocationKind allocationKind; |
| }; |
| |
| template<typename T> |
| inline SharedPtr<Unique<T> > makeSharedPtr (Move<T> move) |
| { |
| return SharedPtr<Unique<T> >(new Unique<T>(move)); |
| } |
| |
| template<typename T> |
| inline VkDeviceSize sizeInBytes (const vector<T>& vec) |
| { |
| return vec.size() * sizeof(vec[0]); |
| } |
| |
| inline bool isCube (const VkImageViewType viewType) |
| { |
| return (viewType == VK_IMAGE_VIEW_TYPE_CUBE || viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY); |
| } |
| |
| inline VkDeviceSize product (const IVec4& v) |
| { |
| return ((static_cast<VkDeviceSize>(v.x()) * v.y()) * v.z()) * v.w(); |
| } |
| |
| template<typename T> |
| inline T sum (const vector<T>& v) |
| { |
| T total = static_cast<T>(0); |
| for (typename vector<T>::const_iterator it = v.begin(); it != v.end(); ++it) |
| total += *it; |
| return total; |
| } |
| |
| template <typename T, int Size> |
| int findIndexOfMaxComponent (const tcu::Vector<T, Size>& vec) |
| { |
| int index = 0; |
| T value = vec[0]; |
| |
| for (int i = 1; i < Size; ++i) |
| { |
| if (vec[i] > value) |
| { |
| index = i; |
| value = vec[i]; |
| } |
| } |
| |
| return index; |
| } |
| |
| inline int maxLayersOrDepth (const IVec4& size) |
| { |
| // This is safe because 3D images must have layers (w) = 1 |
| return deMax32(size.z(), size.w()); |
| } |
| |
| de::MovePtr<Allocation> bindBuffer (const InstanceInterface& vki, |
| const DeviceInterface& vkd, |
| const VkPhysicalDevice& physDevice, |
| const VkDevice device, |
| const VkBuffer& buffer, |
| const MemoryRequirement requirement, |
| Allocator& allocator, |
| AllocationKind allocationKind) |
| { |
| switch (allocationKind) |
| { |
| case ALLOCATION_KIND_SUBALLOCATED: |
| { |
| return vk::bindBuffer(vkd, device, allocator, buffer, requirement); |
| } |
| |
| case ALLOCATION_KIND_DEDICATED: |
| { |
| return bindBufferDedicated(vki, vkd, physDevice, device, buffer, requirement); |
| } |
| |
| default: |
| { |
| TCU_THROW(InternalError, "Invalid allocation kind"); |
| } |
| } |
| } |
| |
| de::MovePtr<Allocation> bindImage (const InstanceInterface& vki, |
| const DeviceInterface& vkd, |
| const VkPhysicalDevice& physDevice, |
| const VkDevice device, |
| const VkImage& image, |
| const MemoryRequirement requirement, |
| Allocator& allocator, |
| AllocationKind allocationKind) |
| { |
| switch (allocationKind) |
| { |
| case ALLOCATION_KIND_SUBALLOCATED: |
| { |
| return vk::bindImage(vkd, device, allocator, image, requirement); |
| } |
| |
| case ALLOCATION_KIND_DEDICATED: |
| { |
| return bindImageDedicated(vki, vkd, physDevice, device, image, requirement); |
| } |
| |
| default: |
| { |
| TCU_THROW(InternalError, "Invalid allocation kind"); |
| } |
| } |
| } |
| |
| // This is very test specific, so be careful if you want to reuse this code. |
| Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface& vk, |
| const VkDevice device, |
| const VkPipeline basePipeline, // for derivatives |
| const VkPipelineLayout pipelineLayout, |
| const VkRenderPass renderPass, |
| const VkShaderModule vertexModule, |
| const VkShaderModule fragmentModule, |
| const IVec2& renderSize, |
| const VkPrimitiveTopology topology, |
| const deUint32 subpass, |
| const bool useDepth, |
| const bool useStencil) |
| { |
| const VkVertexInputBindingDescription vertexInputBindingDescription = |
| { |
| 0u, // uint32_t binding; |
| sizeof(Vertex4RGBA), // uint32_t stride; |
| VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate; |
| }; |
| |
| const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = |
| { |
| { |
| 0u, // uint32_t location; |
| 0u, // uint32_t binding; |
| VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; |
| 0u, // uint32_t offset; |
| }, |
| { |
| 1u, // uint32_t location; |
| 0u, // uint32_t binding; |
| VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; |
| sizeof(Vec4), // uint32_t offset; |
| } |
| }; |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags; |
| 1u, // uint32_t vertexBindingDescriptionCount; |
| &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions; |
| DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions), // uint32_t vertexAttributeDescriptionCount; |
| vertexInputAttributeDescriptions, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; |
| }; |
| |
| const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags flags; |
| topology, // VkPrimitiveTopology topology; |
| VK_FALSE, // VkBool32 primitiveRestartEnable; |
| }; |
| |
| const VkViewport viewport = makeViewport(renderSize); |
| const VkRect2D scissor = makeRect2D(renderSize); |
| |
| const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags; |
| 1u, // uint32_t viewportCount; |
| &viewport, // const VkViewport* pViewports; |
| 1u, // uint32_t scissorCount; |
| &scissor, // const VkRect2D* pScissors; |
| }; |
| |
| const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineRasterizationStateCreateFlags)0, // VkPipelineRasterizationStateCreateFlags flags; |
| VK_FALSE, // VkBool32 depthClampEnable; |
| VK_FALSE, // VkBool32 rasterizerDiscardEnable; |
| VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode; |
| VK_CULL_MODE_NONE, // VkCullModeFlags cullMode; |
| VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace; |
| VK_FALSE, // VkBool32 depthBiasEnable; |
| 0.0f, // float depthBiasConstantFactor; |
| 0.0f, // float depthBiasClamp; |
| 0.0f, // float depthBiasSlopeFactor; |
| 1.0f, // float lineWidth; |
| }; |
| |
| const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples; |
| VK_FALSE, // VkBool32 sampleShadingEnable; |
| 0.0f, // float minSampleShading; |
| DE_NULL, // const VkSampleMask* pSampleMask; |
| VK_FALSE, // VkBool32 alphaToCoverageEnable; |
| VK_FALSE // VkBool32 alphaToOneEnable; |
| }; |
| |
| const VkStencilOpState stencilOpState = makeStencilOpState( |
| VK_STENCIL_OP_KEEP, // stencil fail |
| VK_STENCIL_OP_KEEP, // depth & stencil pass |
| VK_STENCIL_OP_KEEP, // depth only fail |
| VK_COMPARE_OP_EQUAL, // compare op |
| ~0u, // compare mask |
| ~0u, // write mask |
| static_cast<deUint32>(REFERENCE_STENCIL_VALUE)); // reference |
| |
| VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags; |
| useDepth, // VkBool32 depthTestEnable; |
| VK_FALSE, // VkBool32 depthWriteEnable; |
| VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp; |
| VK_FALSE, // VkBool32 depthBoundsTestEnable; |
| useStencil, // VkBool32 stencilTestEnable; |
| stencilOpState, // VkStencilOpState front; |
| stencilOpState, // VkStencilOpState back; |
| 0.0f, // float minDepthBounds; |
| 1.0f, // float maxDepthBounds; |
| }; |
| |
| const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; |
| // Number of blend attachments must equal the number of color attachments during any subpass. |
| const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = |
| { |
| VK_FALSE, // VkBool32 blendEnable; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor; |
| VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor; |
| VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor; |
| VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor; |
| VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp; |
| colorComponentsAll, // VkColorComponentFlags colorWriteMask; |
| }; |
| |
| const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags; |
| VK_FALSE, // VkBool32 logicOpEnable; |
| VK_LOGIC_OP_COPY, // VkLogicOp logicOp; |
| 1u, // deUint32 attachmentCount; |
| &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments; |
| { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4]; |
| }; |
| |
| const VkPipelineShaderStageCreateInfo pShaderStages[] = |
| { |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage; |
| vertexModule, // VkShaderModule module; |
| "main", // const char* pName; |
| DE_NULL, // const VkSpecializationInfo* pSpecializationInfo; |
| }, |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage; |
| fragmentModule, // VkShaderModule module; |
| "main", // const char* pName; |
| DE_NULL, // const VkSpecializationInfo* pSpecializationInfo; |
| } |
| }; |
| |
| const VkPipelineCreateFlags flags = (basePipeline == DE_NULL ? VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT |
| : VK_PIPELINE_CREATE_DERIVATIVE_BIT); |
| |
| const VkGraphicsPipelineCreateInfo graphicsPipelineInfo = |
| { |
| VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| flags, // VkPipelineCreateFlags flags; |
| DE_LENGTH_OF_ARRAY(pShaderStages), // deUint32 stageCount; |
| pShaderStages, // const VkPipelineShaderStageCreateInfo* pStages; |
| &vertexInputStateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; |
| &pipelineInputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; |
| DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState; |
| &pipelineViewportStateInfo, // const VkPipelineViewportStateCreateInfo* pViewportState; |
| &pipelineRasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState; |
| &pipelineMultisampleStateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; |
| &pipelineDepthStencilStateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; |
| &pipelineColorBlendStateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; |
| DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState; |
| pipelineLayout, // VkPipelineLayout layout; |
| renderPass, // VkRenderPass renderPass; |
| subpass, // deUint32 subpass; |
| basePipeline, // VkPipeline basePipelineHandle; |
| -1, // deInt32 basePipelineIndex; |
| }; |
| |
| return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo); |
| } |
| |
| //! Make a render pass with one subpass per color attachment and depth/stencil attachment (if used). |
| Move<VkRenderPass> makeRenderPass (const DeviceInterface& vk, |
| const VkDevice device, |
| const VkFormat colorFormat, |
| const VkFormat depthStencilFormat, |
| const deUint32 numLayers, |
| const VkImageLayout initialColorImageLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| const VkImageLayout initialDepthStencilImageLayout = VK_IMAGE_LAYOUT_UNDEFINED) |
| { |
| const VkAttachmentDescription colorAttachmentDescription = |
| { |
| (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags; |
| colorFormat, // VkFormat format; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; |
| VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; |
| initialColorImageLayout, // VkImageLayout initialLayout; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout; |
| }; |
| vector<VkAttachmentDescription> attachmentDescriptions(numLayers, colorAttachmentDescription); |
| |
| const VkAttachmentDescription depthStencilAttachmentDescription = |
| { |
| (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags; |
| depthStencilFormat, // VkFormat format; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp; |
| VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp; |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; |
| initialDepthStencilImageLayout, // VkImageLayout initialLayout; |
| VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout; |
| }; |
| |
| if (depthStencilFormat != VK_FORMAT_UNDEFINED) |
| attachmentDescriptions.insert(attachmentDescriptions.end(), numLayers, depthStencilAttachmentDescription); |
| |
| // Create a subpass for each attachment (each attachement is a layer of an arrayed image). |
| vector<VkAttachmentReference> colorAttachmentReferences (numLayers); |
| vector<VkAttachmentReference> depthStencilAttachmentReferences(numLayers); |
| vector<VkSubpassDescription> subpasses; |
| |
| // Ordering here must match the framebuffer attachments |
| for (deUint32 i = 0; i < numLayers; ++i) |
| { |
| const VkAttachmentReference attachmentRef = |
| { |
| i, // deUint32 attachment; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout; |
| }; |
| const VkAttachmentReference depthStencilAttachmentRef = |
| { |
| i + numLayers, // deUint32 attachment; |
| VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout layout; |
| }; |
| |
| colorAttachmentReferences[i] = attachmentRef; |
| depthStencilAttachmentReferences[i] = depthStencilAttachmentRef; |
| |
| const VkAttachmentReference* pDepthStencilAttachment = (depthStencilFormat != VK_FORMAT_UNDEFINED ? &depthStencilAttachmentReferences[i] : DE_NULL); |
| const VkSubpassDescription subpassDescription = |
| { |
| (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags; |
| VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; |
| 0u, // deUint32 inputAttachmentCount; |
| DE_NULL, // const VkAttachmentReference* pInputAttachments; |
| 1u, // deUint32 colorAttachmentCount; |
| &colorAttachmentReferences[i], // const VkAttachmentReference* pColorAttachments; |
| DE_NULL, // const VkAttachmentReference* pResolveAttachments; |
| pDepthStencilAttachment, // const VkAttachmentReference* pDepthStencilAttachment; |
| 0u, // deUint32 preserveAttachmentCount; |
| DE_NULL // const deUint32* pPreserveAttachments; |
| }; |
| subpasses.push_back(subpassDescription); |
| } |
| |
| const VkRenderPassCreateInfo renderPassInfo = |
| { |
| VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags; |
| static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount; |
| &attachmentDescriptions[0], // const VkAttachmentDescription* pAttachments; |
| static_cast<deUint32>(subpasses.size()), // deUint32 subpassCount; |
| &subpasses[0], // const VkSubpassDescription* pSubpasses; |
| 0u, // deUint32 dependencyCount; |
| DE_NULL // const VkSubpassDependency* pDependencies; |
| }; |
| |
| return createRenderPass(vk, device, &renderPassInfo); |
| } |
| |
| Move<VkImage> makeImage (const DeviceInterface& vk, |
| const VkDevice device, |
| VkImageCreateFlags flags, |
| VkImageType imageType, |
| const VkFormat format, |
| const IVec3& size, |
| const deUint32 numMipLevels, |
| const deUint32 numLayers, |
| const VkImageUsageFlags usage) |
| { |
| const VkImageCreateInfo imageParams = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| flags, // VkImageCreateFlags flags; |
| imageType, // VkImageType imageType; |
| format, // VkFormat format; |
| makeExtent3D(size), // VkExtent3D extent; |
| numMipLevels, // deUint32 mipLevels; |
| numLayers, // deUint32 arrayLayers; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; |
| usage, // VkImageUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 0u, // deUint32 queueFamilyIndexCount; |
| DE_NULL, // const deUint32* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| }; |
| return createImage(vk, device, &imageParams); |
| } |
| |
| inline VkImageSubresourceRange makeColorSubresourceRange (const int baseArrayLayer, const int layerCount) |
| { |
| return makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, static_cast<deUint32>(baseArrayLayer), static_cast<deUint32>(layerCount)); |
| } |
| |
| //! Get a reference clear value based on color format. |
| VkClearValue getClearValue (const VkFormat format) |
| { |
| if (isUintFormat(format) || isIntFormat(format)) |
| return makeClearValueColorU32(REFERENCE_COLOR_VALUE, REFERENCE_COLOR_VALUE, REFERENCE_COLOR_VALUE, REFERENCE_COLOR_VALUE); |
| else |
| return makeClearValueColorF32(1.0f, 1.0f, 1.0f, 1.0f); |
| } |
| |
| std::string getColorFormatStr (const int numComponents, const bool isUint, const bool isSint) |
| { |
| std::ostringstream str; |
| if (numComponents == 1) |
| str << (isUint ? "uint" : isSint ? "int" : "float"); |
| else |
| str << (isUint ? "u" : isSint ? "i" : "") << "vec" << numComponents; |
| |
| return str.str(); |
| } |
| |
| //! A half-viewport quad. Use with TRIANGLE_STRIP topology. |
| vector<Vertex4RGBA> genFullQuadVertices (const int subpassCount) |
| { |
| vector<Vertex4RGBA> vectorData; |
| for (int subpassNdx = 0; subpassNdx < subpassCount; ++subpassNdx) |
| { |
| Vertex4RGBA data = |
| { |
| Vec4(0.0f, -1.0f, 0.0f, 1.0f), |
| COLOR_TABLE[subpassNdx % DE_LENGTH_OF_ARRAY(COLOR_TABLE)], |
| }; |
| vectorData.push_back(data); |
| data.position = Vec4(0.0f, 1.0f, 0.0f, 1.0f); |
| vectorData.push_back(data); |
| data.position = Vec4(1.0f, -1.0f, 0.0f, 1.0f); |
| vectorData.push_back(data); |
| data.position = Vec4(1.0f, 1.0f, 0.0f, 1.0f); |
| vectorData.push_back(data); |
| } |
| return vectorData; |
| } |
| |
| VkImageType getImageType (const VkImageViewType viewType) |
| { |
| switch (viewType) |
| { |
| case VK_IMAGE_VIEW_TYPE_1D: |
| case VK_IMAGE_VIEW_TYPE_1D_ARRAY: |
| return VK_IMAGE_TYPE_1D; |
| |
| case VK_IMAGE_VIEW_TYPE_2D: |
| case VK_IMAGE_VIEW_TYPE_2D_ARRAY: |
| case VK_IMAGE_VIEW_TYPE_CUBE: |
| case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: |
| return VK_IMAGE_TYPE_2D; |
| |
| case VK_IMAGE_VIEW_TYPE_3D: |
| return VK_IMAGE_TYPE_3D; |
| |
| default: |
| DE_ASSERT(0); |
| return VK_IMAGE_TYPE_LAST; |
| } |
| } |
| |
| //! ImageViewType for accessing a single layer/slice of an image |
| VkImageViewType getImageViewSliceType (const VkImageViewType viewType) |
| { |
| switch (viewType) |
| { |
| case VK_IMAGE_VIEW_TYPE_1D: |
| case VK_IMAGE_VIEW_TYPE_1D_ARRAY: |
| return VK_IMAGE_VIEW_TYPE_1D; |
| |
| case VK_IMAGE_VIEW_TYPE_2D: |
| case VK_IMAGE_VIEW_TYPE_2D_ARRAY: |
| case VK_IMAGE_VIEW_TYPE_CUBE: |
| case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: |
| case VK_IMAGE_VIEW_TYPE_3D: |
| return VK_IMAGE_VIEW_TYPE_2D; |
| |
| default: |
| DE_ASSERT(0); |
| return VK_IMAGE_VIEW_TYPE_LAST; |
| } |
| } |
| |
| VkImageCreateFlags getImageCreateFlags (const VkImageViewType viewType) |
| { |
| VkImageCreateFlags flags = (VkImageCreateFlags)0; |
| |
| if (viewType == VK_IMAGE_VIEW_TYPE_3D) flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR; |
| if (isCube(viewType)) flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; |
| |
| return flags; |
| } |
| |
| void generateExpectedImage (const tcu::PixelBufferAccess& outputImage, const IVec2& renderSize, const int colorDepthOffset) |
| { |
| const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(outputImage.getFormat().type); |
| const bool isInt = (channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER || channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER); |
| const VkClearValue clearValue = getClearValue(mapTextureFormat(outputImage.getFormat())); |
| |
| if (isInt) |
| tcu::clear(outputImage, IVec4(clearValue.color.int32)); |
| else |
| tcu::clear(outputImage, Vec4(clearValue.color.float32)); |
| |
| for (int z = 0; z < outputImage.getDepth(); ++z) |
| { |
| const Vec4& setColor = COLOR_TABLE[(z + colorDepthOffset) % DE_LENGTH_OF_ARRAY(COLOR_TABLE)]; |
| const IVec4 setColorInt = (static_cast<float>(REFERENCE_COLOR_VALUE) * setColor).cast<deInt32>(); |
| |
| for (int y = 0; y < renderSize.y(); ++y) |
| for (int x = renderSize.x()/2; x < renderSize.x(); ++x) |
| { |
| if (isInt) |
| outputImage.setPixel(setColorInt, x, y, z); |
| else |
| outputImage.setPixel(setColor, x, y, z); |
| } |
| } |
| } |
| |
| deUint32 selectMatchingMemoryType (const VkPhysicalDeviceMemoryProperties& deviceMemProps, deUint32 allowedMemTypeBits, MemoryRequirement requirement) |
| { |
| const deUint32 compatibleTypes = getCompatibleMemoryTypes(deviceMemProps, requirement); |
| const deUint32 candidates = allowedMemTypeBits & compatibleTypes; |
| |
| if (candidates == 0) |
| TCU_THROW(NotSupportedError, "No compatible memory type found"); |
| |
| return (deUint32)deCtz32(candidates); |
| } |
| |
| IVec4 getMaxImageSize (const VkImageViewType viewType, const IVec4& sizeHint) |
| { |
| //Limits have been taken from the vulkan specification |
| IVec4 size = IVec4( |
| sizeHint.x() != MAX_SIZE ? sizeHint.x() : 4096, |
| sizeHint.y() != MAX_SIZE ? sizeHint.y() : 4096, |
| sizeHint.z() != MAX_SIZE ? sizeHint.z() : 256, |
| sizeHint.w() != MAX_SIZE ? sizeHint.w() : 256); |
| |
| switch (viewType) |
| { |
| case VK_IMAGE_VIEW_TYPE_1D: |
| case VK_IMAGE_VIEW_TYPE_1D_ARRAY: |
| size.x() = deMin32(4096, size.x()); |
| break; |
| |
| case VK_IMAGE_VIEW_TYPE_2D: |
| case VK_IMAGE_VIEW_TYPE_2D_ARRAY: |
| size.x() = deMin32(4096, size.x()); |
| size.y() = deMin32(4096, size.y()); |
| break; |
| |
| case VK_IMAGE_VIEW_TYPE_3D: |
| size.x() = deMin32(256, size.x()); |
| size.y() = deMin32(256, size.y()); |
| break; |
| |
| case VK_IMAGE_VIEW_TYPE_CUBE: |
| case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: |
| size.x() = deMin32(4096, size.x()); |
| size.y() = deMin32(4096, size.y()); |
| size.w() = deMin32(252, size.w()); |
| size.w() = NUM_CUBE_FACES * (size.w() / NUM_CUBE_FACES); // round down to 6 faces |
| break; |
| |
| default: |
| DE_ASSERT(0); |
| return IVec4(); |
| } |
| |
| return size; |
| } |
| |
| deUint32 getMemoryTypeNdx (Context& context, const CaseDef& caseDef) |
| { |
| const DeviceInterface& vk = context.getDeviceInterface(); |
| const InstanceInterface& vki = context.getInstanceInterface(); |
| const VkDevice device = context.getDevice(); |
| const VkPhysicalDevice physDevice = context.getPhysicalDevice(); |
| |
| const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vki, physDevice); |
| Move<VkImage> colorImage; |
| VkMemoryRequirements memReqs; |
| |
| const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| const IVec4 imageSize = getMaxImageSize(caseDef.viewType, caseDef.imageSizeHint); |
| |
| //create image, don't bind any memory to it |
| colorImage = makeImage(vk, device, getImageCreateFlags(caseDef.viewType), getImageType(caseDef.viewType), caseDef.colorFormat, |
| imageSize.swizzle(0, 1, 2), 1u, imageSize.w(), imageUsage); |
| |
| vk.getImageMemoryRequirements(device, *colorImage, &memReqs); |
| return selectMatchingMemoryType(memoryProperties, memReqs.memoryTypeBits, MemoryRequirement::Any); |
| } |
| |
| VkDeviceSize getMaxDeviceHeapSize (Context& context, const CaseDef& caseDef) |
| { |
| const InstanceInterface& vki = context.getInstanceInterface(); |
| const VkPhysicalDevice physDevice = context.getPhysicalDevice(); |
| const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vki, physDevice); |
| const deUint32 memoryTypeNdx = getMemoryTypeNdx (context, caseDef); |
| |
| return memoryProperties.memoryHeaps[memoryProperties.memoryTypes[memoryTypeNdx].heapIndex].size; |
| } |
| |
| //! Get a smaller image size. Returns a vector of zeroes, if it can't reduce more. |
| IVec4 getReducedImageSize (const CaseDef& caseDef, IVec4 size) |
| { |
| const int maxIndex = findIndexOfMaxComponent(size); |
| const int reducedSize = size[maxIndex] >> 1; |
| |
| switch (caseDef.viewType) |
| { |
| case VK_IMAGE_VIEW_TYPE_CUBE: |
| case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: |
| if (maxIndex < 2) |
| size.x() = size.y() = reducedSize; |
| else if (maxIndex == 3 && reducedSize >= NUM_CUBE_FACES) |
| size.w() = NUM_CUBE_FACES * (reducedSize / NUM_CUBE_FACES); // round down to a multiple of 6 |
| else |
| size = IVec4(0); |
| break; |
| |
| default: |
| size[maxIndex] = reducedSize; |
| break; |
| } |
| |
| if (reducedSize == 0) |
| size = IVec4(0); |
| |
| return size; |
| } |
| |
| bool isDepthStencilFormatSupported (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkFormat format) |
| { |
| const VkFormatProperties properties = getPhysicalDeviceFormatProperties(vki, physDevice, format); |
| return (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0; |
| } |
| |
| VkImageAspectFlags getFormatAspectFlags (const VkFormat format) |
| { |
| if (format == VK_FORMAT_UNDEFINED) |
| return 0; |
| |
| const tcu::TextureFormat::ChannelOrder order = mapVkFormat(format).order; |
| |
| switch (order) |
| { |
| case tcu::TextureFormat::DS: return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; |
| case tcu::TextureFormat::D: return VK_IMAGE_ASPECT_DEPTH_BIT; |
| case tcu::TextureFormat::S: return VK_IMAGE_ASPECT_STENCIL_BIT; |
| default: return VK_IMAGE_ASPECT_COLOR_BIT; |
| } |
| } |
| |
| void initPrograms (SourceCollections& programCollection, const CaseDef caseDef) |
| { |
| const int numComponents = getNumUsedChannels(mapVkFormat(caseDef.colorFormat).order); |
| const bool isUint = isUintFormat(caseDef.colorFormat); |
| const bool isSint = isIntFormat(caseDef.colorFormat); |
| |
| // Vertex shader |
| { |
| std::ostringstream src; |
| src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" |
| << "\n" |
| << "layout(location = 0) in vec4 in_position;\n" |
| << "layout(location = 1) in vec4 in_color;\n" |
| << "layout(location = 0) out vec4 out_color;\n" |
| << "\n" |
| << "out gl_PerVertex {\n" |
| << " vec4 gl_Position;\n" |
| << "};\n" |
| << "\n" |
| << "void main(void)\n" |
| << "{\n" |
| << " gl_Position = in_position;\n" |
| << " out_color = in_color;\n" |
| << "}\n"; |
| |
| programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); |
| } |
| |
| // Fragment shader |
| { |
| std::ostringstream colorValue; |
| colorValue << REFERENCE_COLOR_VALUE; |
| const std::string colorFormat = getColorFormatStr(numComponents, isUint, isSint); |
| const std::string colorInteger = (isUint || isSint ? " * "+colorFormat+"("+colorValue.str()+")" :""); |
| |
| std::ostringstream src; |
| src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" |
| << "\n" |
| << "layout(location = 0) in vec4 in_color;\n" |
| << "layout(location = 0) out " << colorFormat << " o_color;\n" |
| << "\n" |
| << "void main(void)\n" |
| << "{\n" |
| << " o_color = " << colorFormat << "(" |
| << (numComponents == 1 ? "in_color.r" : |
| numComponents == 2 ? "in_color.rg" : |
| numComponents == 3 ? "in_color.rgb" : "in_color") |
| << colorInteger |
| << ");\n" |
| << "}\n"; |
| |
| programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); |
| } |
| } |
| |
| //! See testAttachmentSize() description |
| tcu::TestStatus testWithSizeReduction (Context& context, const CaseDef& caseDef) |
| { |
| const DeviceInterface& vk = context.getDeviceInterface(); |
| const InstanceInterface& vki = context.getInstanceInterface(); |
| const VkDevice device = context.getDevice(); |
| const VkPhysicalDevice physDevice = context.getPhysicalDevice(); |
| const VkQueue queue = context.getUniversalQueue(); |
| const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); |
| Allocator& allocator = context.getDefaultAllocator(); |
| |
| // The memory might be too small to allocate a largest possible attachment, so try to account for that. |
| const bool useDepthStencil = (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED); |
| |
| IVec4 imageSize = getMaxImageSize(caseDef.viewType, caseDef.imageSizeHint); |
| VkDeviceSize colorSize = product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.colorFormat)); |
| VkDeviceSize depthStencilSize = (useDepthStencil ? product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.depthStencilFormat)) : 0ull); |
| |
| const VkDeviceSize reserveForChecking = 500ull * 1024ull; //left 512KB |
| const float additionalMemory = 1.15f; //left some free memory on device (15%) |
| VkDeviceSize neededMemory = static_cast<VkDeviceSize>(static_cast<float>(colorSize + depthStencilSize) * additionalMemory) + reserveForChecking; |
| VkDeviceSize maxMemory = getMaxDeviceHeapSize(context, caseDef) >> 2; |
| |
| vk::PlatformMemoryLimits memoryLimits; |
| context.getTestContext().getPlatform().getVulkanPlatform().getMemoryLimits(memoryLimits); |
| maxMemory = std::min(maxMemory, VkDeviceSize(memoryLimits.totalSystemMemory)); |
| |
| const VkDeviceSize deviceMemoryBudget = std::min(neededMemory, maxMemory); |
| bool allocationPossible = false; |
| |
| // Keep reducing the size, if image size is too big |
| while (neededMemory > deviceMemoryBudget) |
| { |
| imageSize = getReducedImageSize(caseDef, imageSize); |
| |
| if (imageSize == IVec4()) |
| return tcu::TestStatus::fail("Couldn't create an image with required size"); |
| |
| colorSize = product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.colorFormat)); |
| depthStencilSize = (useDepthStencil ? product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.depthStencilFormat)) : 0ull); |
| neededMemory = static_cast<VkDeviceSize>(static_cast<double>(colorSize + depthStencilSize) * additionalMemory); |
| } |
| |
| // Keep reducing the size, if allocation return out of any memory |
| while (!allocationPossible) |
| { |
| VkDeviceMemory object = 0; |
| const VkMemoryAllocateInfo allocateInfo = |
| { |
| VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, //VkStructureType sType; |
| DE_NULL, //const void* pNext; |
| neededMemory, //VkDeviceSize allocationSize; |
| getMemoryTypeNdx(context, caseDef) //deUint32 memoryTypeIndex; |
| }; |
| |
| const VkResult result = vk.allocateMemory(device, &allocateInfo, DE_NULL, &object); |
| |
| if (VK_ERROR_OUT_OF_DEVICE_MEMORY == result || VK_ERROR_OUT_OF_HOST_MEMORY == result) |
| { |
| imageSize = getReducedImageSize(caseDef, imageSize); |
| |
| if (imageSize == IVec4()) |
| return tcu::TestStatus::fail("Couldn't create an image with required size"); |
| |
| colorSize = product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.colorFormat)); |
| depthStencilSize = (useDepthStencil ? product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.depthStencilFormat)) : 0ull); |
| neededMemory = static_cast<VkDeviceSize>(static_cast<double>(colorSize + depthStencilSize) * additionalMemory) + reserveForChecking; |
| } |
| else if (VK_SUCCESS != result) |
| { |
| return tcu::TestStatus::fail("Couldn't allocate memory"); |
| } |
| else |
| { |
| //free memory using Move pointer |
| Move<VkDeviceMemory> memoryAllocated (check<VkDeviceMemory>(object), Deleter<VkDeviceMemory>(vk, device, DE_NULL)); |
| allocationPossible = true; |
| } |
| } |
| |
| context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Using an image with size (width, height, depth, layers) = " << imageSize << tcu::TestLog::EndMessage; |
| |
| // "Slices" is either the depth of a 3D image, or the number of layers of an arrayed image |
| const deInt32 numSlices = maxLayersOrDepth(imageSize); |
| |
| // Determine the verification bounds. The checked region will be in the center of the rendered image |
| const IVec4 checkSize = tcu::min(imageSize, IVec4(MAX_VERIFICATION_REGION_SIZE, |
| MAX_VERIFICATION_REGION_SIZE, |
| MAX_VERIFICATION_REGION_DEPTH, |
| MAX_VERIFICATION_REGION_DEPTH)); |
| const IVec4 checkOffset = (imageSize - checkSize) / 2; |
| |
| // Only make enough space for the check region |
| const VkDeviceSize colorBufferSize = product(checkSize) * tcu::getPixelSize(mapVkFormat(caseDef.colorFormat)); |
| const Unique<VkBuffer> colorBuffer (makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT)); |
| const UniquePtr<Allocation> colorBufferAlloc (bindBuffer(vki, vk, physDevice, device, *colorBuffer, MemoryRequirement::HostVisible, allocator, caseDef.allocationKind)); |
| |
| { |
| deMemset(colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize)); |
| flushAlloc(vk, device, *colorBufferAlloc); |
| } |
| |
| const Unique<VkShaderModule> vertexModule (createShaderModule (vk, device, context.getBinaryCollection().get("vert"), 0u)); |
| const Unique<VkShaderModule> fragmentModule (createShaderModule (vk, device, context.getBinaryCollection().get("frag"), 0u)); |
| const Unique<VkRenderPass> renderPass (makeRenderPass (vk, device, caseDef.colorFormat, caseDef.depthStencilFormat, static_cast<deUint32>(numSlices), |
| (caseDef.viewType == VK_IMAGE_VIEW_TYPE_3D) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL |
| : VK_IMAGE_LAYOUT_UNDEFINED)); |
| const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout (vk, device)); |
| vector<SharedPtrVkPipeline> pipelines; |
| |
| Move<VkImage> colorImage; |
| MovePtr<Allocation> colorImageAlloc; |
| vector<SharedPtrVkImageView> colorAttachments; |
| Move<VkImage> depthStencilImage; |
| MovePtr<Allocation> depthStencilImageAlloc; |
| vector<SharedPtrVkImageView> depthStencilAttachments; |
| vector<VkImageView> attachmentHandles; // all attachments (color and d/s) |
| Move<VkBuffer> vertexBuffer; |
| MovePtr<Allocation> vertexBufferAlloc; |
| Move<VkFramebuffer> framebuffer; |
| |
| // Create a color image |
| { |
| const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| |
| colorImage = makeImage(vk, device, getImageCreateFlags(caseDef.viewType), getImageType(caseDef.viewType), caseDef.colorFormat, |
| imageSize.swizzle(0, 1, 2), 1u, imageSize.w(), imageUsage); |
| colorImageAlloc = bindImage(vki, vk, physDevice, device, *colorImage, MemoryRequirement::Any, allocator, caseDef.allocationKind); |
| } |
| |
| // Create a depth/stencil image (always a 2D image, optionally layered) |
| if (useDepthStencil) |
| { |
| const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; |
| |
| depthStencilImage = makeImage(vk, device, (VkImageCreateFlags)0, VK_IMAGE_TYPE_2D, caseDef.depthStencilFormat, |
| IVec3(imageSize.x(), imageSize.y(), 1), 1u, numSlices, imageUsage); |
| depthStencilImageAlloc = bindImage(vki, vk, physDevice, device, *depthStencilImage, MemoryRequirement::Any, allocator, caseDef.allocationKind); |
| } |
| |
| // Create a vertex buffer |
| { |
| const vector<Vertex4RGBA> vertices = genFullQuadVertices(numSlices); |
| const VkDeviceSize vertexBufferSize = sizeInBytes(vertices); |
| |
| vertexBuffer = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); |
| vertexBufferAlloc = bindBuffer(vki, vk, physDevice, device, *vertexBuffer, MemoryRequirement::HostVisible, allocator, caseDef.allocationKind); |
| |
| deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize)); |
| flushAlloc(vk, device, *vertexBufferAlloc); |
| } |
| |
| // Prepare color image upfront for rendering to individual slices. 3D slices aren't separate subresources, so they shouldn't be transitioned |
| // during each subpass like array layers. |
| if (caseDef.viewType == VK_IMAGE_VIEW_TYPE_3D) |
| { |
| const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex)); |
| const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool)); |
| |
| beginCommandBuffer(vk, *cmdBuffer); |
| |
| const VkImageMemoryBarrier imageBarrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkAccessFlags)0, // VkAccessFlags srcAccessMask; |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout; |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex; |
| *colorImage, // VkImage image; |
| { // VkImageSubresourceRange subresourceRange; |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask; |
| 0u, // uint32_t baseMipLevel; |
| 1u, // uint32_t levelCount; |
| 0u, // uint32_t baseArrayLayer; |
| static_cast<deUint32>(imageSize.w()), // uint32_t layerCount; |
| } |
| }; |
| |
| vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, |
| 0u, DE_NULL, 0u, DE_NULL, 1u, &imageBarrier); |
| |
| endCommandBuffer(vk, *cmdBuffer); |
| submitCommandsAndWait(vk, device, queue, *cmdBuffer); |
| } |
| |
| // For each image layer or slice (3D), create an attachment and a pipeline |
| { |
| const VkImageAspectFlags depthStencilAspect = getFormatAspectFlags(caseDef.depthStencilFormat); |
| const bool useDepth = (depthStencilAspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; |
| const bool useStencil = (depthStencilAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; |
| VkPipeline basePipeline = DE_NULL; |
| |
| // Color attachments are first in the framebuffer |
| for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx) |
| { |
| colorAttachments.push_back(makeSharedPtr( |
| makeImageView(vk, device, *colorImage, getImageViewSliceType(caseDef.viewType), caseDef.colorFormat, makeColorSubresourceRange(subpassNdx, 1)))); |
| attachmentHandles.push_back(**colorAttachments.back()); |
| |
| // We also have to create pipelines for each subpass |
| pipelines.push_back(makeSharedPtr(makeGraphicsPipeline( |
| vk, device, basePipeline, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, imageSize.swizzle(0, 1), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, |
| static_cast<deUint32>(subpassNdx), useDepth, useStencil))); |
| |
| basePipeline = **pipelines.front(); |
| } |
| |
| // Then D/S attachments, if any |
| if (useDepthStencil) |
| for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx) |
| { |
| depthStencilAttachments.push_back(makeSharedPtr( |
| makeImageView(vk, device, *depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, caseDef.depthStencilFormat, makeImageSubresourceRange(depthStencilAspect, 0u, 1u, subpassNdx, 1u)))); |
| attachmentHandles.push_back(**depthStencilAttachments.back()); |
| } |
| } |
| |
| framebuffer = makeFramebuffer(vk, device, *renderPass, static_cast<deUint32>(attachmentHandles.size()), &attachmentHandles[0], static_cast<deUint32>(imageSize.x()), static_cast<deUint32>(imageSize.y())); |
| |
| { |
| const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex)); |
| const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool)); |
| |
| beginCommandBuffer(vk, *cmdBuffer); |
| { |
| vector<VkClearValue> clearValues (numSlices, getClearValue(caseDef.colorFormat)); |
| |
| if (useDepthStencil) |
| clearValues.insert(clearValues.end(), numSlices, makeClearValueDepthStencil(REFERENCE_DEPTH_VALUE, REFERENCE_STENCIL_VALUE)); |
| |
| const VkDeviceSize vertexBufferOffset = 0ull; |
| |
| beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, imageSize.x(), imageSize.y()), (deUint32)clearValues.size(), &clearValues[0]); |
| vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset); |
| } |
| |
| // Draw |
| for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(numSlices); ++subpassNdx) |
| { |
| if (subpassNdx != 0) |
| vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE); |
| |
| vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelines[subpassNdx]); |
| vk.cmdDraw(*cmdBuffer, 4u, 1u, subpassNdx*4u, 0u); |
| } |
| |
| endRenderPass(vk, *cmdBuffer); |
| |
| // Copy colorImage -> host visible colorBuffer |
| { |
| const VkImageMemoryBarrier imageBarriers[] = |
| { |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags outputMask; |
| VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags inputMask; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout; |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 destQueueFamilyIndex; |
| *colorImage, // VkImage image; |
| makeColorSubresourceRange(0, imageSize.w()) // VkImageSubresourceRange subresourceRange; |
| } |
| }; |
| |
| vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, |
| 0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(imageBarriers), imageBarriers); |
| |
| // Copy the checked region rather than the whole image |
| const VkImageSubresourceLayers subresource = |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask; |
| 0u, // uint32_t mipLevel; |
| static_cast<deUint32>(checkOffset.w()), // uint32_t baseArrayLayer; |
| static_cast<deUint32>(checkSize.w()), // uint32_t layerCount; |
| }; |
| |
| const VkBufferImageCopy region = |
| { |
| 0ull, // VkDeviceSize bufferOffset; |
| 0u, // uint32_t bufferRowLength; |
| 0u, // uint32_t bufferImageHeight; |
| subresource, // VkImageSubresourceLayers imageSubresource; |
| makeOffset3D(checkOffset.x(), checkOffset.y(), checkOffset.z()), // VkOffset3D imageOffset; |
| makeExtent3D(checkSize.swizzle(0, 1, 2)), // VkExtent3D imageExtent; |
| }; |
| |
| vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, ®ion); |
| |
| const VkBufferMemoryBarrier bufferBarriers[] = |
| { |
| { |
| 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, // uint32_t srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex; |
| *colorBuffer, // 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, DE_LENGTH_OF_ARRAY(bufferBarriers), bufferBarriers, 0u, DE_NULL); |
| } |
| |
| endCommandBuffer(vk, *cmdBuffer); |
| submitCommandsAndWait(vk, device, queue, *cmdBuffer); |
| } |
| |
| // Verify results |
| { |
| invalidateAlloc(vk, device, *colorBufferAlloc); |
| |
| const tcu::TextureFormat format = mapVkFormat(caseDef.colorFormat); |
| const int checkDepth = maxLayersOrDepth(checkSize); |
| const int depthOffset = maxLayersOrDepth(checkOffset); |
| const tcu::ConstPixelBufferAccess resultImage (format, checkSize.x(), checkSize.y(), checkDepth, colorBufferAlloc->getHostPtr()); |
| tcu::TextureLevel textureLevel (format, checkSize.x(), checkSize.y(), checkDepth); |
| const tcu::PixelBufferAccess expectedImage = textureLevel.getAccess(); |
| bool ok = false; |
| |
| generateExpectedImage(expectedImage, checkSize.swizzle(0, 1), depthOffset); |
| |
| if (isFloatFormat(caseDef.colorFormat)) |
| ok = tcu::floatThresholdCompare(context.getTestContext().getLog(), "Image Comparison", "", expectedImage, resultImage, tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT); |
| else |
| ok = tcu::intThresholdCompare(context.getTestContext().getLog(), "Image Comparison", "", expectedImage, resultImage, tcu::UVec4(2), tcu::COMPARE_LOG_RESULT); |
| |
| return ok ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail"); |
| } |
| } |
| |
| void checkImageViewTypeRequirements (Context& context, const VkImageViewType viewType) |
| { |
| if (viewType == VK_IMAGE_VIEW_TYPE_3D) |
| context.requireDeviceFunctionality("VK_KHR_maintenance1"); |
| |
| if (viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) |
| context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_IMAGE_CUBE_ARRAY); |
| } |
| |
| void checkSupportAttachmentSize (Context& context, const CaseDef caseDef) |
| { |
| checkImageViewTypeRequirements(context, caseDef.viewType); |
| |
| if (caseDef.allocationKind == ALLOCATION_KIND_DEDICATED) |
| context.requireDeviceFunctionality("VK_KHR_dedicated_allocation"); |
| |
| if (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED && !isDepthStencilFormatSupported(context.getInstanceInterface(), context.getPhysicalDevice(), caseDef.depthStencilFormat)) |
| TCU_THROW(NotSupportedError, "Unsupported depth/stencil format"); |
| } |
| |
| //! A test that can exercise very big color and depth/stencil attachment sizes. |
| //! If the total memory consumed by images is too large, or if the implementation returns OUT_OF_MEMORY error somewhere, |
| //! the test can be retried with a next increment of size reduction index, making the attachments smaller. |
| tcu::TestStatus testAttachmentSize (Context& context, const CaseDef caseDef) |
| { |
| return testWithSizeReduction(context, caseDef); |
| // Never reached |
| } |
| |
| vector<IVec4> getMipLevelSizes (IVec4 baseSize) |
| { |
| vector<IVec4> levels; |
| levels.push_back(baseSize); |
| |
| while (baseSize.x() != 1 || baseSize.y() != 1 || baseSize.z() != 1) |
| { |
| baseSize.x() = deMax32(baseSize.x() >> 1, 1); |
| baseSize.y() = deMax32(baseSize.y() >> 1, 1); |
| baseSize.z() = deMax32(baseSize.z() >> 1, 1); |
| levels.push_back(baseSize); |
| } |
| |
| return levels; |
| } |
| |
| //! Compute memory consumed by each mip level, including all layers. Sizes include a padding for alignment. |
| vector<VkDeviceSize> getPerMipLevelStorageSize (const vector<IVec4>& mipLevelSizes, const VkDeviceSize pixelSize) |
| { |
| const deInt64 levelAlignment = 16; |
| vector<VkDeviceSize> storageSizes; |
| |
| for (vector<IVec4>::const_iterator it = mipLevelSizes.begin(); it != mipLevelSizes.end(); ++it) |
| storageSizes.push_back(deAlign64(pixelSize * product(*it), levelAlignment)); |
| |
| return storageSizes; |
| } |
| |
| void drawToMipLevel (const Context& context, |
| const CaseDef& caseDef, |
| const int mipLevel, |
| const IVec4& mipSize, |
| const int numSlices, |
| const VkImage colorImage, |
| const VkImage depthStencilImage, |
| const VkBuffer vertexBuffer, |
| const VkPipelineLayout pipelineLayout, |
| const VkShaderModule vertexModule, |
| const VkShaderModule fragmentModule) |
| { |
| const DeviceInterface& vk = context.getDeviceInterface(); |
| const VkDevice device = context.getDevice(); |
| const VkQueue queue = context.getUniversalQueue(); |
| const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); |
| const VkImageAspectFlags depthStencilAspect = getFormatAspectFlags(caseDef.depthStencilFormat); |
| const bool useDepth = (depthStencilAspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; |
| const bool useStencil = (depthStencilAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; |
| const Unique<VkRenderPass> renderPass (makeRenderPass(vk, device, caseDef.colorFormat, caseDef.depthStencilFormat, static_cast<deUint32>(numSlices), |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, |
| VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); |
| vector<SharedPtrVkPipeline> pipelines; |
| vector<SharedPtrVkImageView> colorAttachments; |
| vector<SharedPtrVkImageView> depthStencilAttachments; |
| vector<VkImageView> attachmentHandles; // all attachments (color and d/s) |
| |
| // For each image layer or slice (3D), create an attachment and a pipeline |
| { |
| VkPipeline basePipeline = DE_NULL; |
| |
| // Color attachments are first in the framebuffer |
| for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx) |
| { |
| colorAttachments.push_back(makeSharedPtr(makeImageView( |
| vk, device, colorImage, getImageViewSliceType(caseDef.viewType), caseDef.colorFormat, |
| makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 1u, subpassNdx, 1u)))); |
| attachmentHandles.push_back(**colorAttachments.back()); |
| |
| // We also have to create pipelines for each subpass |
| pipelines.push_back(makeSharedPtr(makeGraphicsPipeline( |
| vk, device, basePipeline, pipelineLayout, *renderPass, vertexModule, fragmentModule, mipSize.swizzle(0, 1), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, |
| static_cast<deUint32>(subpassNdx), useDepth, useStencil))); |
| |
| basePipeline = **pipelines.front(); |
| } |
| |
| // Then D/S attachments, if any |
| if (useDepth || useStencil) |
| for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx) |
| { |
| depthStencilAttachments.push_back(makeSharedPtr(makeImageView( |
| vk, device, depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, caseDef.depthStencilFormat, |
| makeImageSubresourceRange(depthStencilAspect, mipLevel, 1u, subpassNdx, 1u)))); |
| attachmentHandles.push_back(**depthStencilAttachments.back()); |
| } |
| } |
| |
| const Unique<VkFramebuffer> framebuffer (makeFramebuffer(vk, device, *renderPass, static_cast<deUint32>(attachmentHandles.size()), &attachmentHandles[0], |
| static_cast<deUint32>(mipSize.x()), static_cast<deUint32>(mipSize.y()))); |
| |
| { |
| const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex)); |
| const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool)); |
| |
| beginCommandBuffer(vk, *cmdBuffer); |
| { |
| vector<VkClearValue> clearValues (numSlices, getClearValue(caseDef.colorFormat)); |
| |
| if (useDepth || useStencil) |
| clearValues.insert(clearValues.end(), numSlices, makeClearValueDepthStencil(REFERENCE_DEPTH_VALUE, REFERENCE_STENCIL_VALUE)); |
| |
| const VkDeviceSize vertexBufferOffset = 0ull; |
| |
| beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, mipSize.x(), mipSize.y()), (deUint32)clearValues.size(), &clearValues[0]); |
| vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset); |
| } |
| |
| // Draw |
| for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(numSlices); ++subpassNdx) |
| { |
| if (subpassNdx != 0) |
| vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE); |
| |
| vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelines[subpassNdx]); |
| vk.cmdDraw(*cmdBuffer, 4u, 1u, subpassNdx*4u, 0u); |
| } |
| |
| endRenderPass(vk, *cmdBuffer); |
| |
| endCommandBuffer(vk, *cmdBuffer); |
| submitCommandsAndWait(vk, device, queue, *cmdBuffer); |
| } |
| } |
| |
| void checkSupportRenderToMipMaps (Context& context, const CaseDef caseDef) |
| { |
| checkImageViewTypeRequirements(context, caseDef.viewType); |
| |
| if (caseDef.allocationKind == ALLOCATION_KIND_DEDICATED) |
| context.requireDeviceFunctionality("VK_KHR_dedicated_allocation"); |
| |
| if (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED && !isDepthStencilFormatSupported(context.getInstanceInterface(), context.getPhysicalDevice(), caseDef.depthStencilFormat)) |
| TCU_THROW(NotSupportedError, "Unsupported depth/stencil format"); |
| } |
| |
| //! Use image mip levels as attachments |
| tcu::TestStatus testRenderToMipMaps (Context& context, const CaseDef caseDef) |
| { |
| const DeviceInterface& vk = context.getDeviceInterface(); |
| const InstanceInterface& vki = context.getInstanceInterface(); |
| const VkDevice device = context.getDevice(); |
| const VkPhysicalDevice physDevice = context.getPhysicalDevice(); |
| const VkQueue queue = context.getUniversalQueue(); |
| const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); |
| Allocator& allocator = context.getDefaultAllocator(); |
| |
| const IVec4 imageSize = caseDef.imageSizeHint; // MAX_SIZE is not used in this test |
| const deInt32 numSlices = maxLayersOrDepth(imageSize); |
| const vector<IVec4> mipLevelSizes = getMipLevelSizes(imageSize); |
| const vector<VkDeviceSize> mipLevelStorageSizes = getPerMipLevelStorageSize(mipLevelSizes, tcu::getPixelSize(mapVkFormat(caseDef.colorFormat))); |
| const int numMipLevels = static_cast<int>(mipLevelSizes.size()); |
| const bool useDepthStencil = (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED); |
| |
| // Create a color buffer big enough to hold all layers and mip levels |
| const VkDeviceSize colorBufferSize = sum(mipLevelStorageSizes); |
| const Unique<VkBuffer> colorBuffer (makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT)); |
| const UniquePtr<Allocation> colorBufferAlloc (bindBuffer(vki, vk, physDevice, device, *colorBuffer, MemoryRequirement::HostVisible, allocator, caseDef.allocationKind)); |
| |
| { |
| deMemset(colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize)); |
| flushAlloc(vk, device, *colorBufferAlloc); |
| } |
| |
| const Unique<VkShaderModule> vertexModule (createShaderModule (vk, device, context.getBinaryCollection().get("vert"), 0u)); |
| const Unique<VkShaderModule> fragmentModule (createShaderModule (vk, device, context.getBinaryCollection().get("frag"), 0u)); |
| const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout (vk, device)); |
| |
| Move<VkImage> colorImage; |
| MovePtr<Allocation> colorImageAlloc; |
| Move<VkImage> depthStencilImage; |
| MovePtr<Allocation> depthStencilImageAlloc; |
| Move<VkBuffer> vertexBuffer; |
| MovePtr<Allocation> vertexBufferAlloc; |
| |
| // Create a color image |
| { |
| const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| |
| colorImage = makeImage(vk, device, getImageCreateFlags(caseDef.viewType), getImageType(caseDef.viewType), caseDef.colorFormat, |
| imageSize.swizzle(0, 1, 2), numMipLevels, imageSize.w(), imageUsage); |
| colorImageAlloc = bindImage(vki, vk, physDevice, device, *colorImage, MemoryRequirement::Any, allocator, caseDef.allocationKind); |
| } |
| |
| // Create a depth/stencil image (always a 2D image, optionally layered) |
| if (useDepthStencil) |
| { |
| const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; |
| |
| depthStencilImage = makeImage(vk, device, (VkImageCreateFlags)0, VK_IMAGE_TYPE_2D, caseDef.depthStencilFormat, |
| IVec3(imageSize.x(), imageSize.y(), 1), numMipLevels, numSlices, imageUsage); |
| depthStencilImageAlloc = bindImage(vki, vk, physDevice, device, *depthStencilImage, MemoryRequirement::Any, allocator, caseDef.allocationKind); |
| } |
| |
| // Create a vertex buffer |
| { |
| const vector<Vertex4RGBA> vertices = genFullQuadVertices(numSlices); |
| const VkDeviceSize vertexBufferSize = sizeInBytes(vertices); |
| |
| vertexBuffer = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); |
| vertexBufferAlloc = bindBuffer(vki, vk, physDevice, device, *vertexBuffer, MemoryRequirement::HostVisible, allocator, caseDef.allocationKind); |
| |
| deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize)); |
| flushAlloc(vk, device, *vertexBufferAlloc); |
| } |
| |
| // Prepare images |
| { |
| const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex)); |
| const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool)); |
| |
| beginCommandBuffer(vk, *cmdBuffer); |
| |
| const VkImageMemoryBarrier imageBarriers[] = |
| { |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkAccessFlags)0, // VkAccessFlags srcAccessMask; |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout; |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex; |
| *colorImage, // VkImage image; |
| { // VkImageSubresourceRange subresourceRange; |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask; |
| 0u, // uint32_t baseMipLevel; |
| static_cast<deUint32>(numMipLevels), // uint32_t levelCount; |
| 0u, // uint32_t baseArrayLayer; |
| static_cast<deUint32>(imageSize.w()), // uint32_t layerCount; |
| }, |
| }, |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkAccessFlags)0, // VkAccessFlags srcAccessMask; |
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout; |
| VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout; |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex; |
| *depthStencilImage, // VkImage image; |
| { // VkImageSubresourceRange subresourceRange; |
| getFormatAspectFlags(caseDef.depthStencilFormat), // VkImageAspectFlags aspectMask; |
| 0u, // uint32_t baseMipLevel; |
| static_cast<deUint32>(numMipLevels), // uint32_t levelCount; |
| 0u, // uint32_t baseArrayLayer; |
| static_cast<deUint32>(numSlices), // uint32_t layerCount; |
| }, |
| } |
| }; |
| |
| const deUint32 numImageBarriers = static_cast<deUint32>(DE_LENGTH_OF_ARRAY(imageBarriers) - (useDepthStencil ? 0 : 1)); |
| |
| vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, 0u, |
| 0u, DE_NULL, 0u, DE_NULL, numImageBarriers, imageBarriers); |
| |
| endCommandBuffer(vk, *cmdBuffer); |
| submitCommandsAndWait(vk, device, queue, *cmdBuffer); |
| } |
| |
| // Draw |
| for (int mipLevel = 0; mipLevel < numMipLevels; ++mipLevel) |
| { |
| const IVec4& mipSize = mipLevelSizes[mipLevel]; |
| const int levelSlices = maxLayersOrDepth(mipSize); |
| |
| drawToMipLevel (context, caseDef, mipLevel, mipSize, levelSlices, *colorImage, *depthStencilImage, *vertexBuffer, *pipelineLayout, |
| *vertexModule, *fragmentModule); |
| } |
| |
| // Copy results: colorImage -> host visible colorBuffer |
| { |
| const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex)); |
| const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool)); |
| |
| beginCommandBuffer(vk, *cmdBuffer); |
| |
| { |
| const VkImageMemoryBarrier imageBarriers[] = |
| { |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask; |
| VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout; |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout; |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex; |
| *colorImage, // VkImage image; |
| { // VkImageSubresourceRange subresourceRange; |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask; |
| 0u, // uint32_t baseMipLevel; |
| static_cast<deUint32>(numMipLevels), // uint32_t levelCount; |
| 0u, // uint32_t baseArrayLayer; |
| static_cast<deUint32>(imageSize.w()), // uint32_t layerCount; |
| }, |
| } |
| }; |
| |
| vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, |
| 0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(imageBarriers), imageBarriers); |
| } |
| { |
| vector<VkBufferImageCopy> regions; |
| VkDeviceSize levelOffset = 0ull; |
| VkBufferImageCopy workRegion = |
| { |
| 0ull, // VkDeviceSize bufferOffset; |
| 0u, // uint32_t bufferRowLength; |
| 0u, // uint32_t bufferImageHeight; |
| makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, imageSize.w()), // VkImageSubresourceLayers imageSubresource; |
| makeOffset3D(0, 0, 0), // VkOffset3D imageOffset; |
| makeExtent3D(0, 0, 0), // VkExtent3D imageExtent; |
| }; |
| |
| for (int mipLevel = 0; mipLevel < numMipLevels; ++mipLevel) |
| { |
| workRegion.bufferOffset = levelOffset; |
| workRegion.imageSubresource.mipLevel = static_cast<deUint32>(mipLevel); |
| workRegion.imageExtent = makeExtent3D(mipLevelSizes[mipLevel].swizzle(0, 1, 2)); |
| |
| regions.push_back(workRegion); |
| |
| levelOffset += mipLevelStorageSizes[mipLevel]; |
| } |
| |
| vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, static_cast<deUint32>(regions.size()), ®ions[0]); |
| } |
| { |
| const VkBufferMemoryBarrier bufferBarriers[] = |
| { |
| { |
| 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, // uint32_t srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex; |
| *colorBuffer, // 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, DE_LENGTH_OF_ARRAY(bufferBarriers), bufferBarriers, 0u, DE_NULL); |
| } |
| |
| endCommandBuffer(vk, *cmdBuffer); |
| submitCommandsAndWait(vk, device, queue, *cmdBuffer); |
| } |
| |
| // Verify results (per mip level) |
| { |
| invalidateAlloc(vk, device, *colorBufferAlloc); |
| |
| const tcu::TextureFormat format = mapVkFormat(caseDef.colorFormat); |
| |
| VkDeviceSize levelOffset = 0ull; |
| bool allOk = true; |
| |
| for (int mipLevel = 0; mipLevel < numMipLevels; ++mipLevel) |
| { |
| const IVec4& mipSize = mipLevelSizes[mipLevel]; |
| const void* const pLevelData = static_cast<const deUint8*>(colorBufferAlloc->getHostPtr()) + levelOffset; |
| const int levelDepth = maxLayersOrDepth(mipSize); |
| const tcu::ConstPixelBufferAccess resultImage (format, mipSize.x(), mipSize.y(), levelDepth, pLevelData); |
| tcu::TextureLevel textureLevel (format, mipSize.x(), mipSize.y(), levelDepth); |
| const tcu::PixelBufferAccess expectedImage = textureLevel.getAccess(); |
| const std::string comparisonName = "Mip level " + de::toString(mipLevel); |
| bool ok = false; |
| |
| generateExpectedImage(expectedImage, mipSize.swizzle(0, 1), 0); |
| |
| if (isFloatFormat(caseDef.colorFormat)) |
| ok = tcu::floatThresholdCompare(context.getTestContext().getLog(), "Image Comparison", comparisonName.c_str(), expectedImage, resultImage, tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT); |
| else |
| ok = tcu::intThresholdCompare(context.getTestContext().getLog(), "Image Comparison", comparisonName.c_str(), expectedImage, resultImage, tcu::UVec4(2), tcu::COMPARE_LOG_RESULT); |
| |
| allOk = allOk && ok; // keep testing all levels, even if we know it's a fail overall |
| levelOffset += mipLevelStorageSizes[mipLevel]; |
| } |
| |
| return allOk ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail"); |
| } |
| } |
| |
| std::string getSizeDescription (const IVec4& size) |
| { |
| std::ostringstream str; |
| |
| const char* const description[4] = |
| { |
| "width", "height", "depth", "layers" |
| }; |
| |
| int numMaxComponents = 0; |
| |
| for (int i = 0; i < 4; ++i) |
| { |
| if (size[i] == MAX_SIZE) |
| { |
| if (numMaxComponents > 0) |
| str << "_"; |
| |
| str << description[i]; |
| ++numMaxComponents; |
| } |
| } |
| |
| if (numMaxComponents == 0) |
| str << "small"; |
| |
| return str.str(); |
| } |
| |
| inline std::string getFormatString (const VkFormat format) |
| { |
| std::string name(getFormatName(format)); |
| return de::toLower(name.substr(10)); |
| } |
| |
| std::string getFormatString (const VkFormat colorFormat, const VkFormat depthStencilFormat) |
| { |
| std::ostringstream str; |
| str << getFormatString(colorFormat); |
| if (depthStencilFormat != VK_FORMAT_UNDEFINED) |
| str << "_" << getFormatString(depthStencilFormat); |
| return str.str(); |
| } |
| |
| std::string getShortImageViewTypeName (const VkImageViewType imageViewType) |
| { |
| std::string s(getImageViewTypeName(imageViewType)); |
| return de::toLower(s.substr(19)); |
| } |
| |
| inline BVec4 bvecFromMask (deUint32 mask) |
| { |
| return BVec4((mask >> 0) & 1, |
| (mask >> 1) & 1, |
| (mask >> 2) & 1, |
| (mask >> 3) & 1); |
| } |
| |
| vector<IVec4> genSizeCombinations (const IVec4& baselineSize, const deUint32 sizeMask, const VkImageViewType imageViewType) |
| { |
| vector<IVec4> sizes; |
| std::set<deUint32> masks; |
| |
| for (deUint32 i = 0; i < (1u << 4); ++i) |
| { |
| // Cube images have square faces |
| if (isCube(imageViewType) && ((i & MASK_WH) != 0)) |
| i |= MASK_WH; |
| |
| masks.insert(i & sizeMask); |
| } |
| |
| for (std::set<deUint32>::const_iterator it = masks.begin(); it != masks.end(); ++it) |
| sizes.push_back(tcu::select(IVec4(MAX_SIZE), baselineSize, bvecFromMask(*it))); |
| |
| return sizes; |
| } |
| |
| void addTestCasesWithFunctions (tcu::TestCaseGroup* group, AllocationKind allocationKind) |
| { |
| const struct |
| { |
| VkImageViewType viewType; |
| IVec4 baselineSize; //!< image size: (dimX, dimY, dimZ, arraySize) |
| deUint32 sizeMask; //!< if a dimension is masked, generate a huge size case for it |
| } testCase[] = |
| { |
| { VK_IMAGE_VIEW_TYPE_1D, IVec4(54, 1, 1, 1), MASK_W }, |
| { VK_IMAGE_VIEW_TYPE_1D_ARRAY, IVec4(54, 1, 1, 4), MASK_W_LAYERS }, |
| { VK_IMAGE_VIEW_TYPE_2D, IVec4(44, 23, 1, 1), MASK_WH }, |
| { VK_IMAGE_VIEW_TYPE_2D_ARRAY, IVec4(44, 23, 1, 4), MASK_WH_LAYERS }, |
| { VK_IMAGE_VIEW_TYPE_3D, IVec4(22, 31, 7, 1), MASK_WHD }, |
| { VK_IMAGE_VIEW_TYPE_CUBE, IVec4(35, 35, 1, 6), MASK_WH }, |
| { VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, IVec4(35, 35, 1, 2*6), MASK_WH_LAYERS }, |
| }; |
| |
| const VkFormat format[] = |
| { |
| VK_FORMAT_R8G8B8A8_UNORM, |
| VK_FORMAT_R32_UINT, |
| VK_FORMAT_R16G16_SINT, |
| VK_FORMAT_R32G32B32A32_SFLOAT, |
| VK_FORMAT_A1R5G5B5_UNORM_PACK16, |
| VK_FORMAT_R5G6B5_UNORM_PACK16, |
| VK_FORMAT_A2B10G10R10_UINT_PACK32, |
| VK_FORMAT_A2B10G10R10_UNORM_PACK32 |
| }; |
| |
| const VkFormat depthStencilFormat[] = |
| { |
| VK_FORMAT_UNDEFINED, // don't use a depth/stencil attachment |
| VK_FORMAT_D16_UNORM, |
| VK_FORMAT_S8_UINT, |
| VK_FORMAT_D24_UNORM_S8_UINT, // one of the following mixed formats must be supported |
| VK_FORMAT_D32_SFLOAT_S8_UINT, |
| }; |
| |
| for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(testCase); ++caseNdx) |
| { |
| MovePtr<tcu::TestCaseGroup> imageGroup(new tcu::TestCaseGroup(group->getTestContext(), getShortImageViewTypeName(testCase[caseNdx].viewType).c_str(), "")); |
| |
| // Generate attachment size cases |
| { |
| const vector<IVec4> sizes = genSizeCombinations(testCase[caseNdx].baselineSize, testCase[caseNdx].sizeMask, testCase[caseNdx].viewType); |
| |
| MovePtr<tcu::TestCaseGroup> smallGroup(new tcu::TestCaseGroup(group->getTestContext(), "small", "")); |
| MovePtr<tcu::TestCaseGroup> hugeGroup (new tcu::TestCaseGroup(group->getTestContext(), "huge", "")); |
| |
| imageGroup->addChild(smallGroup.get()); |
| imageGroup->addChild(hugeGroup.get()); |
| |
| for (vector<IVec4>::const_iterator sizeIter = sizes.begin(); sizeIter != sizes.end(); ++sizeIter) |
| { |
| // The first size is the baseline size, put it in a dedicated group |
| if (sizeIter == sizes.begin()) |
| { |
| for (int dsFormatNdx = 0; dsFormatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormat); ++dsFormatNdx) |
| for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(format); ++formatNdx) |
| { |
| const CaseDef caseDef = |
| { |
| testCase[caseNdx].viewType, // VkImageViewType imageType; |
| *sizeIter, // IVec4 imageSizeHint; |
| format[formatNdx], // VkFormat colorFormat; |
| depthStencilFormat[dsFormatNdx], // VkFormat depthStencilFormat; |
| allocationKind // AllocationKind allocationKind; |
| }; |
| addFunctionCaseWithPrograms(smallGroup.get(), getFormatString(format[formatNdx], depthStencilFormat[dsFormatNdx]), "", checkSupportAttachmentSize, initPrograms, testAttachmentSize, caseDef); |
| } |
| } |
| else // All huge cases go into a separate group |
| { |
| if (allocationKind != ALLOCATION_KIND_DEDICATED) |
| { |
| MovePtr<tcu::TestCaseGroup> sizeGroup (new tcu::TestCaseGroup(group->getTestContext(), getSizeDescription(*sizeIter).c_str(), "")); |
| const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM; |
| |
| // Use the same color format for all cases, to reduce the number of permutations |
| for (int dsFormatNdx = 0; dsFormatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormat); ++dsFormatNdx) |
| { |
| const CaseDef caseDef = |
| { |
| testCase[caseNdx].viewType, // VkImageViewType viewType; |
| *sizeIter, // IVec4 imageSizeHint; |
| colorFormat, // VkFormat colorFormat; |
| depthStencilFormat[dsFormatNdx], // VkFormat depthStencilFormat; |
| allocationKind // AllocationKind allocationKind; |
| }; |
| addFunctionCaseWithPrograms(sizeGroup.get(), getFormatString(colorFormat, depthStencilFormat[dsFormatNdx]), "", checkSupportAttachmentSize, initPrograms, testAttachmentSize, caseDef); |
| } |
| hugeGroup->addChild(sizeGroup.release()); |
| } |
| } |
| } |
| smallGroup.release(); |
| hugeGroup.release(); |
| } |
| |
| // Generate mip map cases |
| { |
| MovePtr<tcu::TestCaseGroup> mipmapGroup(new tcu::TestCaseGroup(group->getTestContext(), "mipmap", "")); |
| |
| for (int dsFormatNdx = 0; dsFormatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormat); ++dsFormatNdx) |
| for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(format); ++formatNdx) |
| { |
| const CaseDef caseDef = |
| { |
| testCase[caseNdx].viewType, // VkImageViewType imageType; |
| testCase[caseNdx].baselineSize, // IVec4 imageSizeHint; |
| format[formatNdx], // VkFormat colorFormat; |
| depthStencilFormat[dsFormatNdx], // VkFormat depthStencilFormat; |
| allocationKind // AllocationKind allocationKind; |
| }; |
| addFunctionCaseWithPrograms(mipmapGroup.get(), getFormatString(format[formatNdx], depthStencilFormat[dsFormatNdx]), "", checkSupportRenderToMipMaps, initPrograms, testRenderToMipMaps, caseDef); |
| } |
| imageGroup->addChild(mipmapGroup.release()); |
| } |
| |
| group->addChild(imageGroup.release()); |
| } |
| } |
| |
| void addCoreRenderToImageTests (tcu::TestCaseGroup* group) |
| { |
| addTestCasesWithFunctions(group, ALLOCATION_KIND_SUBALLOCATED); |
| } |
| |
| void addDedicatedAllocationRenderToImageTests (tcu::TestCaseGroup* group) |
| { |
| addTestCasesWithFunctions(group, ALLOCATION_KIND_DEDICATED); |
| } |
| |
| } // anonymous ns |
| |
| tcu::TestCaseGroup* createRenderToImageTests (tcu::TestContext& testCtx) |
| { |
| de::MovePtr<tcu::TestCaseGroup> renderToImageTests (new tcu::TestCaseGroup(testCtx, "render_to_image", "Render to image tests")); |
| |
| renderToImageTests->addChild(createTestGroup(testCtx, "core", "Core render to image tests", addCoreRenderToImageTests)); |
| renderToImageTests->addChild(createTestGroup(testCtx, "dedicated_allocation", "Render to image tests for dedicated memory allocation", addDedicatedAllocationRenderToImageTests)); |
| |
| return renderToImageTests.release(); |
| } |
| |
| } // pipeline |
| } // vkt |