/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2016 The Khronos Group Inc. * Copyright (c) 2016 Imagination Technologies Ltd. * * 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 Robustness Utilities *//*--------------------------------------------------------------------*/ #include "vktRobustnessUtil.hpp" #include "vkDefs.hpp" #include "vkImageUtil.hpp" #include "vkPrograms.hpp" #include "vkQueryUtil.hpp" #include "vkRefUtil.hpp" #include "vkTypeUtil.hpp" #include "vkCmdUtil.hpp" #include "vkObjUtil.hpp" #include "deMath.h" #include #include #include namespace vkt { namespace robustness { using namespace vk; Move createRobustBufferAccessDevice (Context& context) { const float queuePriority = 1.0f; // Create a universal queue that supports graphics and compute const VkDeviceQueueCreateInfo queueParams = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkDeviceQueueCreateFlags flags; context.getUniversalQueueFamilyIndex(), // deUint32 queueFamilyIndex; 1u, // deUint32 queueCount; &queuePriority // const float* pQueuePriorities; }; VkPhysicalDeviceFeatures enabledFeatures = context.getDeviceFeatures(); enabledFeatures.robustBufferAccess = true; const VkDeviceCreateInfo deviceParams = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkDeviceCreateFlags flags; 1u, // deUint32 queueCreateInfoCount; &queueParams, // const VkDeviceQueueCreateInfo* pQueueCreateInfos; 0u, // deUint32 enabledLayerCount; DE_NULL, // const char* const* ppEnabledLayerNames; 0u, // deUint32 enabledExtensionCount; DE_NULL, // const char* const* ppEnabledExtensionNames; &enabledFeatures // const VkPhysicalDeviceFeatures* pEnabledFeatures; }; return createDevice(context.getPlatformInterface(), context.getInstance(), context.getInstanceInterface(), context.getPhysicalDevice(), &deviceParams); } bool areEqual (float a, float b) { return deFloatAbs(a - b) <= 0.001f; } bool isValueZero (const void* valuePtr, size_t valueSizeInBytes) { const deUint8* bytePtr = reinterpret_cast(valuePtr); for (size_t i = 0; i < valueSizeInBytes; i++) { if (bytePtr[i] != 0) return false; } return true; } bool isValueWithinBuffer (const void* buffer, VkDeviceSize bufferSize, const void* valuePtr, size_t valueSizeInBytes) { const deUint8* byteBuffer = reinterpret_cast(buffer); if (bufferSize < ((VkDeviceSize)valueSizeInBytes)) return false; for (VkDeviceSize i = 0; i <= (bufferSize - valueSizeInBytes); i++) { if (!deMemCmp(&byteBuffer[i], valuePtr, valueSizeInBytes)) return true; } return false; } bool isValueWithinBufferOrZero (const void* buffer, VkDeviceSize bufferSize, const void* valuePtr, size_t valueSizeInBytes) { return isValueWithinBuffer(buffer, bufferSize, valuePtr, valueSizeInBytes) || isValueZero(valuePtr, valueSizeInBytes); } bool verifyOutOfBoundsVec4 (const void* vecPtr, VkFormat bufferFormat) { if (isUintFormat(bufferFormat)) { const deUint32* data = (deUint32*)vecPtr; return data[0] == 0u && data[1] == 0u && data[2] == 0u && (data[3] == 0u || data[3] == 1u || data[3] == std::numeric_limits::max()); } else if (isIntFormat(bufferFormat)) { const deInt32* data = (deInt32*)vecPtr; return data[0] == 0 && data[1] == 0 && data[2] == 0 && (data[3] == 0 || data[3] == 1 || data[3] == std::numeric_limits::max()); } else if (isFloatFormat(bufferFormat)) { const float* data = (float*)vecPtr; return areEqual(data[0], 0.0f) && areEqual(data[1], 0.0f) && areEqual(data[2], 0.0f) && (areEqual(data[3], 0.0f) || areEqual(data[3], 1.0f)); } else if (bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32) { return *((deUint32*)vecPtr) == 0xc0000000u; } DE_ASSERT(false); return false; } void populateBufferWithTestValues (void* buffer, VkDeviceSize size, VkFormat format) { // Assign a sequence of 32-bit values for (VkDeviceSize scalarNdx = 0; scalarNdx < size / 4; scalarNdx++) { const deUint32 valueIndex = (deUint32)(2 + scalarNdx); // Do not use 0 or 1 if (isUintFormat(format)) { reinterpret_cast(buffer)[scalarNdx] = valueIndex; } else if (isIntFormat(format)) { reinterpret_cast(buffer)[scalarNdx] = -deInt32(valueIndex); } else if (isFloatFormat(format)) { reinterpret_cast(buffer)[scalarNdx] = float(valueIndex); } else if (format == VK_FORMAT_A2B10G10R10_UNORM_PACK32) { const deUint32 r = ((valueIndex + 0) & ((2u << 10) - 1u)); const deUint32 g = ((valueIndex + 1) & ((2u << 10) - 1u)); const deUint32 b = ((valueIndex + 2) & ((2u << 10) - 1u)); const deUint32 a = ((valueIndex + 0) & ((2u << 2) - 1u)); reinterpret_cast(buffer)[scalarNdx] = (a << 30) | (b << 20) | (g << 10) | r; } else { DE_ASSERT(false); } } } void logValue (std::ostringstream& logMsg, const void* valuePtr, VkFormat valueFormat, size_t valueSize) { if (isUintFormat(valueFormat)) { logMsg << *reinterpret_cast(valuePtr); } else if (isIntFormat(valueFormat)) { logMsg << *reinterpret_cast(valuePtr); } else if (isFloatFormat(valueFormat)) { logMsg << *reinterpret_cast(valuePtr); } else { const deUint8* bytePtr = reinterpret_cast(valuePtr); const std::ios::fmtflags streamFlags = logMsg.flags(); logMsg << std::hex; for (size_t i = 0; i < valueSize; i++) { logMsg << " " << (deUint32)bytePtr[i]; } logMsg.flags(streamFlags); } } // TestEnvironment TestEnvironment::TestEnvironment (Context& context, VkDevice device, VkDescriptorSetLayout descriptorSetLayout, VkDescriptorSet descriptorSet) : m_context (context) , m_device (device) , m_descriptorSetLayout (descriptorSetLayout) , m_descriptorSet (descriptorSet) { const DeviceInterface& vk = context.getDeviceInterface(); // Create command pool { const VkCommandPoolCreateInfo commandPoolParams = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCommandPoolCreateFlags flags; context.getUniversalQueueFamilyIndex() // deUint32 queueFamilyIndex; }; m_commandPool = createCommandPool(vk, m_device, &commandPoolParams); } // Create command buffer { const VkCommandBufferAllocateInfo commandBufferAllocateInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; *m_commandPool, // VkCommandPool commandPool; VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level; 1u, // deUint32 bufferCount; }; m_commandBuffer = allocateCommandBuffer(vk, m_device, &commandBufferAllocateInfo); } } VkCommandBuffer TestEnvironment::getCommandBuffer (void) { return *m_commandBuffer; } // GraphicsEnvironment GraphicsEnvironment::GraphicsEnvironment (Context& context, VkDevice device, VkDescriptorSetLayout descriptorSetLayout, VkDescriptorSet descriptorSet, const VertexBindings& vertexBindings, const VertexAttributes& vertexAttributes, const DrawConfig& drawConfig) : TestEnvironment (context, device, descriptorSetLayout, descriptorSet) , m_renderSize (16, 16) , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM) { const DeviceInterface& vk = context.getDeviceInterface(); const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); const VkComponentMapping componentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; SimpleAllocator memAlloc (vk, m_device, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice())); // Create color image and view { const VkImageCreateInfo colorImageParams = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkImageCreateFlags flags; VK_IMAGE_TYPE_2D, // VkImageType imageType; m_colorFormat, // VkFormat format; { (deUint32)m_renderSize.x(), (deUint32)m_renderSize.y(), 1u }, // VkExtent3D extent; 1u, // deUint32 mipLevels; 1u, // deUint32 arrayLayers; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 1u, // deUint32 queueFamilyIndexCount; &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout; }; m_colorImage = createImage(vk, m_device, &colorImageParams); m_colorImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, m_device, *m_colorImage), MemoryRequirement::Any); VK_CHECK(vk.bindImageMemory(m_device, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset())); const VkImageViewCreateInfo colorAttachmentViewParams = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkImageViewCreateFlags flags; *m_colorImage, // VkImage image; VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; m_colorFormat, // VkFormat format; componentMappingRGBA, // VkComponentMapping components; { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } // VkImageSubresourceRange subresourceRange; }; m_colorAttachmentView = createImageView(vk, m_device, &colorAttachmentViewParams); } // Create render pass m_renderPass = makeRenderPass(vk, m_device, m_colorFormat); // Create framebuffer { const VkFramebufferCreateInfo framebufferParams = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkFramebufferCreateFlags flags; *m_renderPass, // VkRenderPass renderPass; 1u, // deUint32 attachmentCount; &m_colorAttachmentView.get(), // const VkImageView* pAttachments; (deUint32)m_renderSize.x(), // deUint32 width; (deUint32)m_renderSize.y(), // deUint32 height; 1u // deUint32 layers; }; m_framebuffer = createFramebuffer(vk, m_device, &framebufferParams); } // Create pipeline layout { const VkPipelineLayoutCreateInfo pipelineLayoutParams = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineLayoutCreateFlags flags; 1u, // deUint32 setLayoutCount; &m_descriptorSetLayout, // const VkDescriptorSetLayout* pSetLayouts; 0u, // deUint32 pushConstantRangeCount; DE_NULL // const VkPushConstantRange* pPushConstantRanges; }; m_pipelineLayout = createPipelineLayout(vk, m_device, &pipelineLayoutParams); } m_vertexShaderModule = createShaderModule(vk, m_device, m_context.getBinaryCollection().get("vertex"), 0); m_fragmentShaderModule = createShaderModule(vk, m_device, m_context.getBinaryCollection().get("fragment"), 0); // Create pipeline { const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineVertexInputStateCreateFlags flags; (deUint32)vertexBindings.size(), // deUint32 vertexBindingDescriptionCount; vertexBindings.data(), // const VkVertexInputBindingDescription* pVertexBindingDescriptions; (deUint32)vertexAttributes.size(), // deUint32 vertexAttributeDescriptionCount; vertexAttributes.data() // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; }; const std::vector viewports (1, makeViewport(m_renderSize)); const std::vector scissors (1, makeRect2D(m_renderSize)); m_graphicsPipeline = makeGraphicsPipeline(vk, // const DeviceInterface& vk m_device, // const VkDevice device *m_pipelineLayout, // const VkPipelineLayout pipelineLayout *m_vertexShaderModule, // const VkShaderModule vertexShaderModule DE_NULL, // const VkShaderModule tessellationControlShaderModule DE_NULL, // const VkShaderModule tessellationEvalShaderModule DE_NULL, // const VkShaderModule geometryShaderModule *m_fragmentShaderModule, // const VkShaderModule fragmentShaderModule *m_renderPass, // const VkRenderPass renderPass viewports, // const std::vector& viewports scissors, // const std::vector& scissors VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, // const VkPrimitiveTopology topology 0u, // const deUint32 subpass 0u, // const deUint32 patchControlPoints &vertexInputStateParams); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo } // Record commands { const VkImageMemoryBarrier imageLayoutBarrier = { 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; *m_colorImage, // VkImage image; { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } // VkImageSubresourceRange subresourceRange; }; beginCommandBuffer(vk, *m_commandBuffer, 0u); { vk.cmdPipelineBarrier(*m_commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageLayoutBarrier); beginRenderPass(vk, *m_commandBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), tcu::Vec4(0.0f)); { const std::vector vertexBufferOffsets(drawConfig.vertexBuffers.size(), 0ull); vk.cmdBindPipeline(*m_commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipeline); vk.cmdBindDescriptorSets(*m_commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0, 1, &m_descriptorSet, 0, DE_NULL); vk.cmdBindVertexBuffers(*m_commandBuffer, 0, (deUint32)drawConfig.vertexBuffers.size(), drawConfig.vertexBuffers.data(), vertexBufferOffsets.data()); if (drawConfig.indexBuffer == DE_NULL || drawConfig.indexCount == 0) { vk.cmdDraw(*m_commandBuffer, drawConfig.vertexCount, drawConfig.instanceCount, 0, 0); } else { vk.cmdBindIndexBuffer(*m_commandBuffer, drawConfig.indexBuffer, 0, VK_INDEX_TYPE_UINT32); vk.cmdDrawIndexed(*m_commandBuffer, drawConfig.indexCount, drawConfig.instanceCount, 0, 0, 0); } } endRenderPass(vk, *m_commandBuffer); } endCommandBuffer(vk, *m_commandBuffer); } } // ComputeEnvironment ComputeEnvironment::ComputeEnvironment (Context& context, VkDevice device, VkDescriptorSetLayout descriptorSetLayout, VkDescriptorSet descriptorSet) : TestEnvironment (context, device, descriptorSetLayout, descriptorSet) { const DeviceInterface& vk = context.getDeviceInterface(); // Create pipeline layout { const VkPipelineLayoutCreateInfo pipelineLayoutParams = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineLayoutCreateFlags flags; 1u, // deUint32 setLayoutCount; &m_descriptorSetLayout, // const VkDescriptorSetLayout* pSetLayouts; 0u, // deUint32 pushConstantRangeCount; DE_NULL // const VkPushConstantRange* pPushConstantRanges; }; m_pipelineLayout = createPipelineLayout(vk, m_device, &pipelineLayoutParams); } // Create compute pipeline { m_computeShaderModule = createShaderModule(vk, m_device, m_context.getBinaryCollection().get("compute"), 0); const VkPipelineShaderStageCreateInfo computeStageParams = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineShaderStageCreateFlags flags; VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage; *m_computeShaderModule, // VkShaderModule module; "main", // const char* pName; DE_NULL, // const VkSpecializationInfo* pSpecializationInfo; }; const VkComputePipelineCreateInfo computePipelineParams = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineCreateFlags flags; computeStageParams, // VkPipelineShaderStageCreateInfo stage; *m_pipelineLayout, // VkPipelineLayout layout; DE_NULL, // VkPipeline basePipelineHandle; 0u // deInt32 basePipelineIndex; }; m_computePipeline = createComputePipeline(vk, m_device, DE_NULL, &computePipelineParams); } // Record commands { beginCommandBuffer(vk, *m_commandBuffer, 0u); vk.cmdBindPipeline(*m_commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_computePipeline); vk.cmdBindDescriptorSets(*m_commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0, 1, &m_descriptorSet, 0, DE_NULL); vk.cmdDispatch(*m_commandBuffer, 32, 32, 1); endCommandBuffer(vk, *m_commandBuffer); } } } // robustness } // vkt