| /* Copyright (c) 2021 The Khronos Group Inc. |
| * Copyright (c) 2021 NVIDIA Corporation |
| * |
| * 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 |
| * |
| * Author: David Zhao Akeley <dakeley@nvidia.com> |
| */ |
| |
| #include <array> |
| #include <cassert> |
| #include <stdio.h> |
| #include <vector> |
| |
| #include "layer_validation_tests.h" |
| |
| // Common data structures needed for tests. |
| class ViewportInheritanceTestData { |
| // Borrowed owner device. |
| VkDevice m_device{}; |
| |
| // Renderpass, draw to one attachment of format m_colorFormat. |
| VkFormat m_colorFormat{}; |
| VkRenderPass m_renderPass{}; |
| |
| // Framebuffer data. |
| VkImageObj m_colorImageObj; |
| VkImageView m_colorImageView{}; |
| VkFramebuffer m_framebuffer{}; |
| |
| // Do-nothing vertex and fragment programs. |
| static const uint32_t kVertexSpirV[166]; |
| static const uint32_t kFragmentSpirV[83]; |
| std::array<VkPipelineShaderStageCreateInfo, 2> m_shaderStages{}; |
| |
| // Do-nothing graphics pipelines. |
| // dynamic state pipelines have viewport/scissor as sole dynamic state; static state pipelines have no dynamic state. |
| // the i-th pipeline needs i viewports/scissors (0th uses EXT dynamic viewport/scissor count). |
| // m_staticStatePipelines[0] is unused. |
| VkPipelineLayout m_pipelineLayout{}; |
| std::array<VkPipeline, 33> m_dynamicStatePipelines{}, m_staticStatePipelines{}; |
| |
| // Various premade state structs for graphics pipeline. |
| static const VkPipelineVertexInputStateCreateInfo kVertexInputState; |
| static const VkPipelineInputAssemblyStateCreateInfo kInputAssemblyState; |
| static const VkPipelineRasterizationStateCreateInfo kRasterizationState; |
| static const VkPipelineMultisampleStateCreateInfo kMultisampleState; |
| static const VkPipelineDepthStencilStateCreateInfo kDepthStencilState; |
| static const VkPipelineColorBlendAttachmentState kBlendAttachmentState; |
| static const VkPipelineColorBlendStateCreateInfo kBlendState; |
| static const VkPipelineDynamicStateCreateInfo kStaticState; |
| static const VkPipelineDynamicStateCreateInfo kDynamicState; |
| static const VkPipelineDynamicStateCreateInfo kDynamicStateWithCount; |
| |
| public: |
| // Premade viewport and scissor arrays for testing. |
| static const VkViewport kViewportArray[32]; |
| static const VkViewport kViewportDepthOnlyArray[32]; |
| static const VkViewport kViewportAlternateDepthArray[32]; |
| static const VkRect2D kScissorArray[32]; |
| |
| private: |
| // Set to a failure message if initialization failed. |
| const char* m_failureReason = nullptr; |
| |
| void PickColorFormat(VkPhysicalDevice physical_device) { |
| std::array<VkFormat, 7> formats = {VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_R8G8B8A8_UNORM, |
| VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_SNORM, VK_FORMAT_B8G8R8A8_SNORM, |
| VK_FORMAT_R32G32B32A32_SFLOAT}; |
| for (VkFormat candidate : formats) { |
| VkImageFormatProperties properties; |
| VkResult result = |
| vk::GetPhysicalDeviceImageFormatProperties(physical_device, candidate, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0, &properties); |
| if (result == VK_SUCCESS) { |
| m_colorFormat = candidate; |
| return; |
| } |
| } |
| m_failureReason = "No color attachment format found"; |
| } |
| |
| void CreateRenderPass() { |
| assert(m_colorFormat != VK_FORMAT_UNDEFINED); |
| VkAttachmentDescription color_attachment = {0, |
| m_colorFormat, |
| VK_SAMPLE_COUNT_1_BIT, |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, |
| VK_ATTACHMENT_STORE_OP_STORE, |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, |
| VK_IMAGE_LAYOUT_UNDEFINED, |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; |
| VkAttachmentReference color_reference = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; |
| VkSubpassDescription subpass = { |
| 0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &color_reference, nullptr, nullptr, 0, nullptr}; |
| VkRenderPassCreateInfo info = { |
| VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &color_attachment, 1, &subpass, 0, nullptr}; |
| VkResult result = vk::CreateRenderPass(m_device, &info, nullptr, &m_renderPass); |
| if (result != VK_SUCCESS) m_failureReason = "Could not create render pass."; |
| } |
| |
| void CreateColorImageObj() { |
| assert(m_colorFormat != VK_FORMAT_UNDEFINED); |
| m_colorImageObj.Init(128, 128, 1, m_colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); |
| if (!m_colorImageObj.initialized()) { |
| m_failureReason = "Image not initialized"; |
| } |
| } |
| |
| void CreateColorView() { |
| assert(!m_colorImageView); |
| VkImageViewCreateInfo info = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, |
| nullptr, |
| 0, |
| m_colorImageObj.handle(), |
| VK_IMAGE_VIEW_TYPE_2D, |
| m_colorFormat, |
| {}, |
| {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; |
| VkResult result = vk::CreateImageView(m_device, &info, nullptr, &m_colorImageView); |
| if (result != VK_SUCCESS) m_failureReason = "Could not create image view"; |
| } |
| |
| void CreateFramebuffer() { |
| assert(!m_framebuffer); |
| VkFramebufferCreateInfo info = { |
| VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, m_renderPass, 1, &m_colorImageView, 128, 128, 1}; |
| VkResult result = vk::CreateFramebuffer(m_device, &info, nullptr, &m_framebuffer); |
| if (result != VK_SUCCESS) m_failureReason = "Could not create framebuffer"; |
| } |
| |
| void CreatePipelineLayout() { |
| assert(!m_pipelineLayout); |
| VkPipelineLayoutCreateInfo info = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; |
| VkResult result = vk::CreatePipelineLayout(m_device, &info, nullptr, &m_pipelineLayout); |
| if (result != VK_SUCCESS) m_failureReason = "Could not create pipeline layout"; |
| } |
| |
| void CreateShaderStages() { |
| VkShaderModuleCreateInfo vertex_info = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, nullptr, 0, sizeof kVertexSpirV, |
| kVertexSpirV}; |
| m_shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; |
| m_shaderStages[0].pNext = nullptr; |
| m_shaderStages[0].flags = 0; |
| m_shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; |
| VkResult result = vk::CreateShaderModule(m_device, &vertex_info, nullptr, &m_shaderStages[0].module); |
| m_shaderStages[0].pName = "main"; |
| m_shaderStages[0].pSpecializationInfo = nullptr; |
| if (result != VK_SUCCESS) { |
| m_failureReason = "Could not create vertex program"; |
| return; |
| } |
| |
| VkShaderModuleCreateInfo fragment_info = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, nullptr, 0, sizeof kFragmentSpirV, |
| kFragmentSpirV}; |
| m_shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; |
| m_shaderStages[1].pNext = nullptr; |
| m_shaderStages[1].flags = 0; |
| m_shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; |
| result = vk::CreateShaderModule(m_device, &fragment_info, nullptr, &m_shaderStages[1].module); |
| m_shaderStages[1].pName = "main"; |
| m_shaderStages[1].pSpecializationInfo = nullptr; |
| if (result != VK_SUCCESS) { |
| m_failureReason = "Could not create fragment program"; |
| return; |
| } |
| } |
| |
| void Cleanup() { |
| for (VkPipeline& pipeline : m_dynamicStatePipelines) { |
| vk::DestroyPipeline(m_device, pipeline, nullptr); |
| pipeline = VK_NULL_HANDLE; |
| } |
| for (VkPipeline& pipeline : m_staticStatePipelines) { |
| vk::DestroyPipeline(m_device, pipeline, nullptr); |
| pipeline = VK_NULL_HANDLE; |
| } |
| for (auto& stage : m_shaderStages) { |
| vk::DestroyShaderModule(m_device, stage.module, nullptr); |
| stage.module = VK_NULL_HANDLE; |
| } |
| vk::DestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); |
| m_pipelineLayout = VK_NULL_HANDLE; |
| vk::DestroyFramebuffer(m_device, m_framebuffer, nullptr); |
| m_framebuffer = VK_NULL_HANDLE; |
| vk::DestroyImageView(m_device, m_colorImageView, nullptr); |
| m_colorImageView = VK_NULL_HANDLE; |
| vk::DestroyRenderPass(m_device, m_renderPass, nullptr); |
| m_renderPass = VK_NULL_HANDLE; |
| } |
| |
| public: |
| // Check if the gpu has the needed features, and call InitState requesting the needed features. |
| // Return whether the needed features were found or not. |
| template <typename AddDeviceExtension> |
| static bool InitState(VkRenderFramework* p_framework, AddDeviceExtension add_device_extension, const char** pp_reason, |
| bool inheritedViewportScissor2D, bool extended_dynamic_state_multi_viewport, |
| bool disable_multi_viewport = false) { |
| VkPhysicalDeviceExtendedDynamicStateFeaturesEXT ext = { |
| VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT, nullptr}; |
| VkPhysicalDeviceInheritedViewportScissorFeaturesNV nv = { |
| VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV, &ext}; |
| VkPhysicalDeviceFeatures2 features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, &nv}; |
| VkPhysicalDevice gpu = p_framework->gpu(); |
| |
| // Enable extended dynamic state if requested. |
| if (extended_dynamic_state_multi_viewport) { |
| if (!p_framework->DeviceExtensionSupported(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME)) { |
| *pp_reason = "missing " VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME; |
| return false; |
| } |
| add_device_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); |
| } |
| |
| // Always try to enable the tested extension (but maybe won't actually enable relevant feature.) |
| if (p_framework->DeviceExtensionSupported(VK_NV_INHERITED_VIEWPORT_SCISSOR_EXTENSION_NAME)) { |
| add_device_extension(VK_NV_INHERITED_VIEWPORT_SCISSOR_EXTENSION_NAME); |
| } else { |
| *pp_reason = "missing " VK_NV_INHERITED_VIEWPORT_SCISSOR_EXTENSION_NAME; |
| return false; |
| } |
| |
| vk::GetPhysicalDeviceFeatures2(gpu, &features2); |
| |
| if (extended_dynamic_state_multi_viewport) { |
| if (!features2.features.multiViewport) { |
| *pp_reason = "missing multiViewport feature"; |
| return false; |
| } |
| if (!ext.extendedDynamicState) { |
| *pp_reason = "missing extendedDynamicState feature"; |
| return false; |
| } |
| } |
| if (!nv.inheritedViewportScissor2D && !inheritedViewportScissor2D) { |
| *pp_reason = "missing inheritedViewportScissor2D feature"; |
| return false; |
| } |
| nv.inheritedViewportScissor2D = inheritedViewportScissor2D; |
| |
| if (disable_multi_viewport) { |
| features2.features.multiViewport = VK_FALSE; |
| } |
| |
| p_framework->InitState(nullptr, &features2, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); |
| return true; |
| } |
| |
| ViewportInheritanceTestData(VkDeviceObj* p_device_obj, VkPhysicalDevice physical_device) : m_colorImageObj(p_device_obj) { |
| m_device = p_device_obj->handle(); |
| try { |
| PickColorFormat(physical_device); |
| if (m_failureReason) return; |
| CreateRenderPass(); |
| if (m_failureReason) return; |
| CreateColorImageObj(); |
| if (m_failureReason) return; |
| CreateColorView(); |
| if (m_failureReason) return; |
| CreateFramebuffer(); |
| if (m_failureReason) return; |
| CreatePipelineLayout(); |
| if (m_failureReason) return; |
| CreateShaderStages(); |
| if (m_failureReason) return; |
| } |
| catch (...) { |
| Cleanup(); |
| throw; |
| } |
| } |
| |
| ~ViewportInheritanceTestData() { Cleanup(); } |
| |
| // nullptr indicates successful construction. |
| const char* FailureReason() const { return m_failureReason; }; |
| |
| // Get the graphics pipeline with the specified viewport/scissor state configuration, creating it if needed. |
| // viewport_scissor_count == 0 and dynamic_viewport_scissor == true indicates EXT viewport/scissor with count dynamic state. |
| // All pipelines are destroyed when the class is destroyed. |
| VkPipeline GetGraphicsPipeline(bool dynamic_viewport_scissor, uint32_t viewport_scissor_count) { |
| assert(dynamic_viewport_scissor || viewport_scissor_count != 0); |
| assert(size_t(viewport_scissor_count) < m_dynamicStatePipelines.size()); |
| VkPipeline* p_pipeline = |
| &(dynamic_viewport_scissor ? m_dynamicStatePipelines : m_staticStatePipelines)[viewport_scissor_count]; |
| if (*p_pipeline) { |
| return *p_pipeline; |
| } |
| |
| // Need some static viewport/scissors if no dynamic state. Their values don't really matter; the only purpose |
| // of static viewport/scissor pipelines is to test messing up the dynamic state. |
| std::vector<VkViewport> static_viewports; |
| std::vector<VkRect2D> static_scissors; |
| if (!dynamic_viewport_scissor) { |
| VkViewport viewport { 0, 0, 128, 128, 0, 1 }; |
| static_viewports = std::vector<VkViewport>(viewport_scissor_count, viewport); |
| static_scissors.resize(viewport_scissor_count); |
| } |
| VkPipelineViewportStateCreateInfo viewport_state = {VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, |
| nullptr, |
| 0, |
| viewport_scissor_count, |
| static_viewports.data(), |
| viewport_scissor_count, |
| static_scissors.data()}; |
| const VkPipelineDynamicStateCreateInfo& dynamic_state = |
| dynamic_viewport_scissor == false ? kStaticState : viewport_scissor_count == 0 ? kDynamicStateWithCount : kDynamicState; |
| |
| VkGraphicsPipelineCreateInfo info = {VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, |
| nullptr, |
| 0, |
| uint32_t(m_shaderStages.size()), |
| m_shaderStages.data(), |
| &kVertexInputState, |
| &kInputAssemblyState, |
| nullptr, // tess |
| &viewport_state, |
| &kRasterizationState, |
| &kMultisampleState, |
| &kDepthStencilState, |
| &kBlendState, |
| &dynamic_state, |
| m_pipelineLayout, |
| m_renderPass, |
| 0}; |
| VkResult result = vk::CreateGraphicsPipelines(m_device, VK_NULL_HANDLE, 1, &info, nullptr, p_pipeline); |
| if (result < 0) m_failureReason = "Failed to create graphics pipeline"; |
| return result >= 0 ? *p_pipeline : VK_NULL_HANDLE; |
| } |
| |
| // Bind the graphics pipeline with the specified viewport/scissor state configuration. |
| void BindGraphicsPipeline(VkCommandBuffer cmd, bool dynamic_viewport_scissor, uint32_t viewport_scissor_count) { |
| VkPipeline pipeline = GetGraphicsPipeline(dynamic_viewport_scissor, viewport_scissor_count); |
| if (pipeline) vk::CmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); |
| } |
| |
| // Make a primary command buffer and begin recording. |
| VkCommandBuffer MakeBeginPrimaryCommandBuffer(VkCommandPool pool) const { |
| VkCommandBufferAllocateInfo info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, nullptr, pool, |
| VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1}; |
| VkCommandBuffer cmd; |
| vk::AllocateCommandBuffers(m_device, &info, &cmd); |
| BeginPrimaryCommandBuffer(cmd); |
| return cmd; |
| } |
| |
| // Begin recording the primary command buffer. |
| VkResult BeginPrimaryCommandBuffer(VkCommandBuffer cmd) const { |
| VkCommandBufferBeginInfo info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, 0, nullptr}; |
| return vk::BeginCommandBuffer(cmd, &info); |
| } |
| |
| // Begin the render pass, with subpass contents provided by secondary command buffers. |
| void BeginRenderPass(VkCommandBuffer cmd) const { |
| VkRenderPassBeginInfo info = { |
| VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, m_renderPass, m_framebuffer, {{0, 0}, {128, 128}}, 0, nullptr}; |
| vk::CmdBeginRenderPass(cmd, &info, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); |
| } |
| |
| // Make a secondary (non-subpass) command buffer and begin recording. |
| VkCommandBuffer MakeBeginSecondaryCommandBuffer(VkCommandPool pool, VkFlags usage = 0, |
| const void* inheritance_pNext = nullptr) const { |
| VkCommandBufferAllocateInfo info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, nullptr, pool, |
| VK_COMMAND_BUFFER_LEVEL_SECONDARY, 1}; |
| VkCommandBuffer cmd; |
| vk::AllocateCommandBuffers(m_device, &info, &cmd); |
| BeginSecondaryCommandBuffer(cmd, usage, inheritance_pNext); |
| return cmd; |
| } |
| |
| // Begin recording the (non-subpass) secondary command buffer. |
| VkResult BeginSecondaryCommandBuffer(VkCommandBuffer cmd, VkFlags usage = 0, const void* inheritance_pNext = nullptr) const { |
| VkCommandBufferInheritanceInfo inheritance = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, inheritance_pNext, |
| m_renderPass}; |
| VkCommandBufferBeginInfo info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, usage, &inheritance}; |
| return vk::BeginCommandBuffer(cmd, &info); |
| } |
| |
| // Make a subpass secondary command buffer (for the class's render pass) and begin recording. |
| // If a nonzero array of viewports is given, this enabled viewport/scissor inheritance and |
| // passes the list of expected viewport depths. |
| VkCommandBuffer MakeBeginSubpassCommandBuffer(VkCommandPool pool, uint32_t inherited_viewport_count, |
| const VkViewport* p_viewport_depths) const { |
| VkCommandBufferAllocateInfo info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, nullptr, pool, |
| VK_COMMAND_BUFFER_LEVEL_SECONDARY, 1}; |
| VkCommandBuffer cmd; |
| vk::AllocateCommandBuffers(m_device, &info, &cmd); |
| BeginSubpassCommandBuffer(cmd, inherited_viewport_count, p_viewport_depths); |
| return cmd; |
| } |
| |
| // Same as above, but recycle the given secondary command buffer. |
| VkResult BeginSubpassCommandBuffer(VkCommandBuffer cmd, uint32_t inherited_viewport_count, |
| const VkViewport* p_viewport_depths) const { |
| VkCommandBufferInheritanceViewportScissorInfoNV viewport_scissor = { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV, nullptr, |
| inherited_viewport_count != 0, inherited_viewport_count, p_viewport_depths }; |
| VkCommandBufferInheritanceInfo inheritance = { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, &viewport_scissor, m_renderPass, 0, m_framebuffer }; |
| VkCommandBufferBeginInfo info = { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, |
| VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inheritance}; |
| return vk::BeginCommandBuffer(cmd, &info); |
| } |
| }; |
| |
| TEST_F(VkLayerTest, ViewportInheritance) { |
| TEST_DESCRIPTION("Simple correct and incorrect usage of VK_NV_inherited_viewport_scissor"); |
| m_instance_extension_names.push_back("VK_KHR_get_physical_device_properties2"); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| bool has_features = false; |
| const char* missing_feature_string = nullptr; |
| auto self = this; |
| ASSERT_NO_FATAL_FAILURE(has_features = ViewportInheritanceTestData::InitState( |
| this, [self](const char* extension) { self->m_device_extension_names.push_back(extension); }, |
| &missing_feature_string, true, false)); |
| if (!has_features) { |
| printf("%s\n", missing_feature_string); |
| return; |
| } |
| |
| m_errorMonitor->ExpectSuccess(); |
| ViewportInheritanceTestData test_data(m_device, gpu()); |
| if (test_data.FailureReason()) { |
| printf("%s Test internal failure: %s\n", kSkipPrefix, test_data.FailureReason()); |
| return; |
| } |
| VkCommandPool pool = m_commandPool->handle(); |
| |
| VkCommandBuffer subpass_cmd = test_data.MakeBeginSubpassCommandBuffer(pool, 1, test_data.kViewportDepthOnlyArray); |
| test_data.BindGraphicsPipeline(subpass_cmd, true, 1); |
| vk::CmdDraw(subpass_cmd, 3, 1, 0, 0); |
| vk::EndCommandBuffer(subpass_cmd); |
| |
| // Basic correct usage, provide viewport in primary that has the correct depth. |
| VkCommandBuffer primary_cmd = test_data.MakeBeginPrimaryCommandBuffer(pool); |
| vk::CmdSetViewport(primary_cmd, 0, 1, test_data.kViewportArray); |
| vk::CmdSetScissor(primary_cmd, 0, 1, test_data.kScissorArray); |
| test_data.BeginRenderPass(primary_cmd); |
| vk::CmdExecuteCommands(primary_cmd, 1, &subpass_cmd); |
| vk::CmdEndRenderPass(primary_cmd); |
| vk::EndCommandBuffer(primary_cmd); |
| m_errorMonitor->VerifyNotFound(); |
| |
| // Viewport with incorrect depth range. |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); |
| test_data.BeginPrimaryCommandBuffer(primary_cmd); |
| vk::CmdSetViewport(primary_cmd, 0, 1, test_data.kViewportAlternateDepthArray); |
| vk::CmdSetScissor(primary_cmd, 0, 1, test_data.kScissorArray); |
| test_data.BeginRenderPass(primary_cmd); |
| vk::CmdExecuteCommands(primary_cmd, 1, &subpass_cmd); |
| vk::CmdEndRenderPass(primary_cmd); |
| vk::EndCommandBuffer(primary_cmd); |
| m_errorMonitor->VerifyFound(); |
| |
| // Viewport not provided. |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); |
| test_data.BeginPrimaryCommandBuffer(primary_cmd); |
| vk::CmdSetScissor(primary_cmd, 0, 1, test_data.kScissorArray); |
| test_data.BeginRenderPass(primary_cmd); |
| vk::CmdExecuteCommands(primary_cmd, 1, &subpass_cmd); |
| vk::CmdEndRenderPass(primary_cmd); |
| vk::EndCommandBuffer(primary_cmd); |
| m_errorMonitor->VerifyFound(); |
| |
| // Scissor not provided. |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); |
| test_data.BeginPrimaryCommandBuffer(primary_cmd); |
| vk::CmdSetViewport(primary_cmd, 0, 1, test_data.kViewportArray); |
| test_data.BeginRenderPass(primary_cmd); |
| vk::CmdExecuteCommands(primary_cmd, 1, &subpass_cmd); |
| vk::CmdEndRenderPass(primary_cmd); |
| vk::EndCommandBuffer(primary_cmd); |
| m_errorMonitor->VerifyFound(); |
| |
| // again (i.e. no stale state left over when resetting a secondary command buffer). |
| // Don't swap the loop order or you'll mess up subpass_cmd for upcoming tests. |
| for (int should_fail = 1; should_fail >= 0; --should_fail) { |
| if (should_fail) { |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // viewport |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // scissor |
| test_data.BeginSubpassCommandBuffer(subpass_cmd, 0, nullptr); |
| } |
| else { |
| m_errorMonitor->ExpectSuccess(); |
| test_data.BeginSubpassCommandBuffer(subpass_cmd, 1, test_data.kViewportDepthOnlyArray); |
| } |
| test_data.BindGraphicsPipeline(subpass_cmd, true, 1); |
| vk::CmdDraw(subpass_cmd, 3, 1, 0, 0); |
| vk::EndCommandBuffer(subpass_cmd); |
| |
| test_data.BeginPrimaryCommandBuffer(primary_cmd); |
| vk::CmdSetViewport(primary_cmd, 0, 1, test_data.kViewportArray); |
| vk::CmdSetScissor(primary_cmd, 0, 1, test_data.kScissorArray); |
| test_data.BeginRenderPass(primary_cmd); |
| vk::CmdExecuteCommands(primary_cmd, 1, &subpass_cmd); |
| vk::CmdEndRenderPass(primary_cmd); |
| vk::EndCommandBuffer(primary_cmd); |
| |
| if (should_fail) m_errorMonitor->VerifyFound(); |
| else m_errorMonitor->VerifyNotFound(); |
| } |
| |
| // Secondary that binds a static viewport/scissor pipeline. |
| VkCommandBuffer static_state_cmd = test_data.MakeBeginSubpassCommandBuffer(pool, 0, nullptr); |
| test_data.BindGraphicsPipeline(static_state_cmd, false, 1); |
| vk::EndCommandBuffer(static_state_cmd); |
| |
| // Test that the validation layers still flag missing state when inheritance is disabled, then stops flagging it when enabled |
| // Test that inheritance fails if a static viewport/scissor pipeline |
| // trashes the state before it is inherited (but it's okay if it's |
| // trashed afterwards). |
| for (int should_fail = 0; should_fail < 2; ++should_fail) { |
| if (should_fail) { |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // viewport |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // scissor |
| } |
| else { |
| m_errorMonitor->ExpectSuccess(); |
| } |
| std::array<VkCommandBuffer, 2> secondaries = {should_fail ? static_state_cmd : subpass_cmd, |
| should_fail ? subpass_cmd : static_state_cmd}; |
| |
| test_data.BeginPrimaryCommandBuffer(primary_cmd); |
| vk::CmdSetViewport(primary_cmd, 0, 1, test_data.kViewportArray); |
| vk::CmdSetScissor(primary_cmd, 0, 1, test_data.kScissorArray); |
| test_data.BeginRenderPass(primary_cmd); |
| vk::CmdExecuteCommands(primary_cmd, secondaries.size(), secondaries.data()); |
| vk::CmdEndRenderPass(primary_cmd); |
| vk::EndCommandBuffer(primary_cmd); |
| |
| if (should_fail) m_errorMonitor->VerifyFound(); |
| else m_errorMonitor->VerifyNotFound(); |
| } |
| |
| // Check that the validation layers don't count the primary |
| // command buffer state when overwritten by static |
| // viewport/scissor pipeline. |
| for (int should_fail = 0; should_fail < 2; ++should_fail) { |
| if (should_fail) { |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // viewport |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // scissor |
| } |
| else { |
| m_errorMonitor->ExpectSuccess(); |
| } |
| |
| test_data.BeginPrimaryCommandBuffer(primary_cmd); |
| vk::CmdSetViewport(primary_cmd, 0, 1, test_data.kViewportArray); |
| vk::CmdSetScissor(primary_cmd, 0, 1, test_data.kScissorArray); |
| if (should_fail) test_data.BindGraphicsPipeline(primary_cmd, false, 1); |
| test_data.BeginRenderPass(primary_cmd); |
| vk::CmdExecuteCommands(primary_cmd, 1, &subpass_cmd); |
| vk::CmdEndRenderPass(primary_cmd); |
| vk::EndCommandBuffer(primary_cmd); |
| |
| if (should_fail) m_errorMonitor->VerifyFound(); |
| else m_errorMonitor->VerifyNotFound(); |
| } |
| |
| // Check that the validation layers DON'T report mismatched viewport depth when the secondary command buffer does not actually |
| // consume the viewport in drawing commands (weird corner case). |
| VkCommandBuffer no_draw_cmd = test_data.MakeBeginSubpassCommandBuffer(pool, 1, test_data.kViewportDepthOnlyArray); |
| test_data.BindGraphicsPipeline(no_draw_cmd, true, 1); // but no subsequent draw call. |
| vk::EndCommandBuffer(no_draw_cmd); |
| |
| for (int should_fail = 0; should_fail < 2; ++should_fail) { |
| if (should_fail) { |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // viewport |
| } |
| else { |
| m_errorMonitor->ExpectSuccess(); |
| } |
| |
| test_data.BeginPrimaryCommandBuffer(primary_cmd); |
| vk::CmdSetViewport(primary_cmd, 0, 1, test_data.kViewportAlternateDepthArray); |
| vk::CmdSetScissor(primary_cmd, 0, 1, test_data.kScissorArray); |
| test_data.BeginRenderPass(primary_cmd); |
| vk::CmdExecuteCommands(primary_cmd, 1, should_fail ? &subpass_cmd : &no_draw_cmd); |
| vk::CmdEndRenderPass(primary_cmd); |
| vk::EndCommandBuffer(primary_cmd); |
| |
| if (should_fail) m_errorMonitor->VerifyFound(); |
| else m_errorMonitor->VerifyNotFound(); |
| } |
| |
| // Check that the validation layers are not okay with binding static viewport/scissor pipelines when inheritance enabled, or |
| // setting viewport/scissor explicitly, but are okay if inheritance is not enabled (no regression). |
| for (int should_fail = 0; should_fail < 2; ++should_fail) { |
| if (!should_fail) m_errorMonitor->ExpectSuccess(); |
| |
| if (should_fail) m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBindPipeline-commandBuffer-04808"); |
| test_data.BeginSubpassCommandBuffer(no_draw_cmd, should_fail, test_data.kViewportDepthOnlyArray); |
| test_data.BindGraphicsPipeline(no_draw_cmd, false, 1); |
| if (should_fail) m_errorMonitor->VerifyFound(); |
| |
| // Check that the validation layers flag setting viewport/scissor with inheritance. |
| if (should_fail) m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdSetViewport-commandBuffer-04821"); |
| vk::CmdSetViewport(no_draw_cmd, 0, 1, test_data.kViewportArray); |
| if (should_fail) m_errorMonitor->VerifyFound(); |
| if (should_fail) m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdSetScissor-viewportScissor2D-04789"); |
| vk::CmdSetScissor(no_draw_cmd, 0, 1, test_data.kScissorArray); |
| if (should_fail) m_errorMonitor->VerifyFound(); |
| |
| vk::EndCommandBuffer(no_draw_cmd); |
| if (!should_fail) m_errorMonitor->VerifyNotFound(); |
| } |
| |
| // Check for at least 1 viewport depth given when enabling inheritance. |
| for (int should_fail = 0; should_fail < 2; ++should_fail) { |
| if (should_fail) { |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, |
| "VUID-VkCommandBufferInheritanceViewportScissorInfoNV-viewportScissor2D-04784"); |
| } |
| else { |
| m_errorMonitor->ExpectSuccess(); |
| } |
| VkCommandBufferInheritanceViewportScissorInfoNV viewport_scissor = { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV, nullptr, should_fail ? VK_TRUE : VK_FALSE, |
| 0, test_data.kViewportArray /* avoid null pointer crash still */ }; |
| VkCommandBuffer cmd = |
| test_data.MakeBeginSecondaryCommandBuffer(pool, VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &viewport_scissor); |
| // vk::EndCommandBuffer(cmd); // seg faults. |
| (void)cmd; |
| |
| if (should_fail) m_errorMonitor->VerifyFound(); |
| else m_errorMonitor->VerifyNotFound(); |
| } |
| |
| // Check for VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkCommandBufferInheritanceViewportScissorInfoNV-viewportScissor2D-04786"); |
| VkCommandBufferInheritanceViewportScissorInfoNV viewport_scissor = { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV, nullptr, VK_TRUE, 1, test_data.kViewportArray}; |
| test_data.MakeBeginSecondaryCommandBuffer(pool, 0, &viewport_scissor); |
| m_errorMonitor->VerifyFound(); |
| |
| // Check that validation layers allow getting inherited viewport/scissor state from earlier secondary command buffer, but not |
| // from a different vkCmdExecuteCommands. |
| VkCommandBuffer set_viewport_cmd = test_data.MakeBeginSubpassCommandBuffer(pool, 0, nullptr); |
| vk::CmdSetViewport(set_viewport_cmd, 0, 1, test_data.kViewportArray); |
| vk::EndCommandBuffer(set_viewport_cmd); |
| VkCommandBuffer set_scissor_cmd = test_data.MakeBeginSubpassCommandBuffer(pool, 0, nullptr); |
| vk::CmdSetScissor(set_scissor_cmd, 0, 1, test_data.kScissorArray); |
| vk::EndCommandBuffer(set_scissor_cmd); |
| |
| for (int should_fail = 0; should_fail < 2; ++should_fail) { |
| test_data.BeginPrimaryCommandBuffer(primary_cmd); |
| test_data.BeginRenderPass(primary_cmd); |
| if (should_fail) { |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // viewport |
| vk::CmdExecuteCommands(primary_cmd, 1, &set_viewport_cmd); |
| VkCommandBuffer secondaries[2] = {set_scissor_cmd, subpass_cmd}; |
| vk::CmdExecuteCommands(primary_cmd, 2, secondaries); |
| } |
| else { |
| m_errorMonitor->ExpectSuccess(); |
| VkCommandBuffer secondaries[3] = {set_viewport_cmd, set_scissor_cmd, subpass_cmd}; |
| vk::CmdExecuteCommands(primary_cmd, 3, secondaries); |
| } |
| vk::CmdEndRenderPass(primary_cmd); |
| vk::EndCommandBuffer(primary_cmd); |
| |
| if (should_fail) m_errorMonitor->VerifyFound(); |
| else m_errorMonitor->VerifyNotFound(); |
| } |
| } |
| |
| TEST_F(VkLayerTest, ViewportInheritanceMissingFeature) { |
| TEST_DESCRIPTION("Error using VK_NV_inherited_viewport_scissor without enabling feature."); |
| m_instance_extension_names.push_back("VK_KHR_get_physical_device_properties2"); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| bool has_features = false; |
| const char* missing_feature_string = nullptr; |
| auto self = this; |
| ASSERT_NO_FATAL_FAILURE(has_features = ViewportInheritanceTestData::InitState( |
| this, [self](const char* extension) { self->m_device_extension_names.push_back(extension); }, |
| &missing_feature_string, false, false)); |
| if (!has_features) { |
| printf("%s\n", missing_feature_string); |
| return; |
| } |
| |
| ViewportInheritanceTestData test_data(m_device, gpu()); |
| if (test_data.FailureReason()) { |
| printf("%s Test internal failure: %s\n", kSkipPrefix, test_data.FailureReason()); |
| return; |
| } |
| VkCommandPool pool = m_commandPool->handle(); |
| |
| m_errorMonitor->ExpectSuccess(); |
| test_data.MakeBeginSubpassCommandBuffer(pool, 0, nullptr); |
| m_errorMonitor->VerifyNotFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkCommandBufferInheritanceViewportScissorInfoNV-viewportScissor2D-04782"); |
| test_data.MakeBeginSubpassCommandBuffer(pool, 1, test_data.kViewportArray); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, ViewportInheritanceMultiViewport) { |
| TEST_DESCRIPTION("VK_NV_inherited_viewport_scissor tests with multiple viewports/scissors"); |
| m_instance_extension_names.push_back("VK_KHR_get_physical_device_properties2"); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| bool has_features = false; |
| const char* missing_feature_string = nullptr; |
| auto self = this; |
| ASSERT_NO_FATAL_FAILURE(has_features = ViewportInheritanceTestData::InitState( |
| this, [self](const char* extension) { self->m_device_extension_names.push_back(extension); }, |
| &missing_feature_string, true, true)); |
| if (!has_features) { |
| printf("%s\n", missing_feature_string); |
| return; |
| } |
| |
| ViewportInheritanceTestData test_data(m_device, gpu()); |
| if (test_data.FailureReason()) { |
| printf("%s Test internal failure: %s\n", kSkipPrefix, test_data.FailureReason()); |
| return; |
| } |
| VkCommandPool pool = m_commandPool->handle(); |
| |
| // Test using viewport/scissor with count state without providing it to be inherited. |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // viewport |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // scissor |
| VkCommandBuffer draw_cmd = test_data.MakeBeginSubpassCommandBuffer(pool, 1, test_data.kViewportArray); |
| test_data.BindGraphicsPipeline(draw_cmd, true, 0 /* dynamic viewport and scissor count */); |
| vk::CmdDraw(draw_cmd, 3, 1, 0, 0); |
| vk::EndCommandBuffer(draw_cmd); |
| |
| VkCommandBuffer primary_cmd = test_data.MakeBeginPrimaryCommandBuffer(pool); |
| vk::CmdSetViewport(primary_cmd, 0, 1, test_data.kViewportArray); // inadequate, needs with count |
| vk::CmdSetScissor(primary_cmd, 0, 1, test_data.kScissorArray); |
| test_data.BeginRenderPass(primary_cmd); |
| vk::CmdExecuteCommands(primary_cmd, 1, &draw_cmd); |
| vk::CmdEndRenderPass(primary_cmd); |
| vk::EndCommandBuffer(primary_cmd); |
| m_errorMonitor->VerifyFound(); |
| |
| // Test drawing with pipeline that uses more viewports than have been inherited. |
| for (int i = 0; i < 4; ++i) { |
| auto should_fail = i & 1; |
| if (should_fail) m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // viewport |
| else m_errorMonitor->ExpectSuccess(); |
| |
| test_data.BeginSubpassCommandBuffer(draw_cmd, should_fail ? 1 : 2, test_data.kViewportDepthOnlyArray); |
| test_data.BindGraphicsPipeline(draw_cmd, true, 2); // Uses 2 viewports |
| vk::CmdDraw(draw_cmd, 3, 1, 0, 0); |
| if (i & 2) { |
| // Uses only 1 viewport, should not cause us to "forget" the earlier need for 2 viewports. |
| test_data.BindGraphicsPipeline(draw_cmd, true, 1); |
| vk::CmdDraw(draw_cmd, 3, 1, 0, 0); |
| } |
| vk::EndCommandBuffer(draw_cmd); |
| |
| test_data.BeginPrimaryCommandBuffer(primary_cmd); |
| vk::CmdSetViewport(primary_cmd, 0, 2, test_data.kViewportArray); |
| vk::CmdSetScissor(primary_cmd, 0, 2, test_data.kScissorArray); |
| test_data.BeginRenderPass(primary_cmd); |
| vk::CmdExecuteCommands(primary_cmd, 1, &draw_cmd); |
| vk::CmdEndRenderPass(primary_cmd); |
| vk::EndCommandBuffer(primary_cmd); |
| |
| if (should_fail) m_errorMonitor->VerifyFound(); |
| else m_errorMonitor->VerifyNotFound(); |
| } |
| |
| // Test providing needed viewports in secondary command buffer, and trashing it by binding static state pipeline in another |
| // secondary command buffer. |
| VkCommandBuffer set_state_fixed_count_cmd = test_data.MakeBeginSubpassCommandBuffer(pool, 0, nullptr); |
| vk::CmdSetViewport(set_state_fixed_count_cmd, 0, 2, test_data.kViewportArray); |
| vk::CmdSetScissor(set_state_fixed_count_cmd, 0, 2, test_data.kScissorArray); |
| vk::EndCommandBuffer(set_state_fixed_count_cmd); |
| |
| auto vkCmdSetViewportWithCountEXT = |
| PFN_vkCmdSetViewportWithCountEXT(vk::GetDeviceProcAddr(m_device->handle(), "vkCmdSetViewportWithCountEXT")); |
| assert(vkCmdSetViewportWithCountEXT); |
| auto vkCmdSetScissorWithCountEXT = |
| PFN_vkCmdSetScissorWithCountEXT(vk::GetDeviceProcAddr(m_device->handle(), "vkCmdSetScissorWithCountEXT")); |
| assert(vkCmdSetScissorWithCountEXT); |
| |
| VkCommandBuffer set_state_with_count_cmd = test_data.MakeBeginSubpassCommandBuffer(pool, 0, nullptr); |
| vkCmdSetViewportWithCountEXT(set_state_with_count_cmd, 2, test_data.kViewportArray); |
| vkCmdSetScissorWithCountEXT(set_state_with_count_cmd, 2, test_data.kScissorArray); |
| vk::EndCommandBuffer(set_state_with_count_cmd); |
| |
| VkCommandBuffer static_state_cmd = test_data.MakeBeginSubpassCommandBuffer(pool, 0, nullptr); |
| test_data.BindGraphicsPipeline(static_state_cmd, false, 2); |
| test_data.BindGraphicsPipeline(static_state_cmd, true, 1); // Should not "forgive" eariler static state pipeline. |
| vk::EndCommandBuffer(static_state_cmd); |
| |
| for (int i = 0; i < 8; ++i) { |
| auto should_fail = i & 1; |
| auto use_with_count = i & 4; |
| if (should_fail) { |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // viewport 0 (or with count) |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // scissor 0 (or with count) |
| if (!use_with_count) { |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // viewport 1 |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // scissor 1 |
| } |
| } |
| else { |
| m_errorMonitor->ExpectSuccess(); |
| } |
| |
| test_data.BeginSubpassCommandBuffer(draw_cmd, 2, test_data.kViewportDepthOnlyArray); |
| test_data.BindGraphicsPipeline(draw_cmd, true, use_with_count ? 0 : 2); |
| vk::CmdDraw(draw_cmd, 3, 1, 0, 0); |
| vk::EndCommandBuffer(draw_cmd); |
| |
| VkCommandBuffer set_state_cmd = use_with_count ? set_state_with_count_cmd : set_state_fixed_count_cmd; |
| VkCommandBuffer secondaries[3]; |
| uint32_t secondaries_count; |
| |
| switch (i % 4) { |
| case 0: |
| secondaries[0] = static_state_cmd; |
| secondaries[1] = set_state_cmd; |
| secondaries[2] = draw_cmd; |
| secondaries_count = 3; |
| break; |
| case 1: |
| secondaries[0] = draw_cmd; |
| secondaries_count = 1; |
| break; |
| case 2: |
| secondaries[0] = set_state_cmd; |
| secondaries[1] = draw_cmd; |
| secondaries[2] = static_state_cmd; // Okay as it's after the drawing commands. |
| secondaries_count = 3; |
| break; |
| case 3: default: |
| secondaries[0] = set_state_cmd; |
| secondaries[1] = static_state_cmd; // Trashes the dynamic state |
| secondaries[2] = draw_cmd; |
| secondaries_count = 3; |
| break; |
| } |
| |
| test_data.BeginPrimaryCommandBuffer(primary_cmd); |
| test_data.BeginRenderPass(primary_cmd); |
| vk::CmdExecuteCommands(primary_cmd, secondaries_count, secondaries); |
| vk::CmdEndRenderPass(primary_cmd); |
| vk::EndCommandBuffer(primary_cmd); |
| |
| if (should_fail) m_errorMonitor->VerifyFound(); |
| else m_errorMonitor->VerifyNotFound(); |
| } |
| |
| // Test mismatched depth count detection, but allow it if the mismatched viewport is not actually used. |
| // 0: viewport 1 mismatch, passes as draw only consumes correct 0th viewport. |
| // 1: fail, mismatched viewport 1. |
| // 2: pass, 2 correct viewports used. (also tests vkCmdSetViewport split between primary and secondary). |
| for (int i = 0; i < 3; ++i) { |
| auto should_fail = i & 1; |
| if (should_fail) { |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); // viewport 1 |
| } |
| else { |
| m_errorMonitor->ExpectSuccess(); |
| } |
| |
| test_data.BeginSubpassCommandBuffer(draw_cmd, 2, test_data.kViewportDepthOnlyArray); |
| test_data.BindGraphicsPipeline(draw_cmd, true, i == 0 ? 1 : 2); |
| vk::CmdDraw(draw_cmd, 3, 1, 0, 0); |
| vk::EndCommandBuffer(draw_cmd); |
| |
| test_data.BeginSubpassCommandBuffer(set_state_fixed_count_cmd, 0, nullptr); |
| vk::CmdSetViewport(set_state_fixed_count_cmd, 1, 1, i == 2 ? &test_data.kViewportArray[1] : &test_data.kViewportAlternateDepthArray[1]); |
| vk::CmdSetScissor(set_state_fixed_count_cmd, 1, 1, &test_data.kScissorArray[1]); |
| vk::EndCommandBuffer(set_state_fixed_count_cmd); |
| |
| test_data.BeginPrimaryCommandBuffer(primary_cmd); |
| vk::CmdSetViewport(primary_cmd, 0, 1, &test_data.kViewportArray[0]); |
| vk::CmdSetScissor(primary_cmd, 0, 1, &test_data.kScissorArray[0]); |
| test_data.BeginRenderPass(primary_cmd); |
| VkCommandBuffer secondaries[] = {set_state_fixed_count_cmd, draw_cmd}; |
| vk::CmdExecuteCommands(primary_cmd, 2, secondaries); |
| vk::CmdEndRenderPass(primary_cmd); |
| vk::EndCommandBuffer(primary_cmd); |
| |
| if (should_fail) m_errorMonitor->VerifyFound(); |
| else m_errorMonitor->VerifyNotFound(); |
| } |
| |
| // Test dynamic viewport count failing due to either exceeding the viewport inheritance limit, or inheriting a viewport with |
| // incorrect depth. |
| for (int i = 0; i < 8; ++i) { |
| auto state_in_secondary = i & 1; |
| auto should_fail = i & 2; |
| auto inherited_incorrect_depth = i & 4; |
| |
| if (should_fail) m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDraw-commandBuffer-02701"); |
| else m_errorMonitor->ExpectSuccess(); |
| |
| VkViewport viewports[3]; |
| viewports[0] = test_data.kViewportArray[0]; |
| viewports[1] = test_data.kViewportArray[1]; |
| if (inherited_incorrect_depth) { |
| viewports[2] = test_data.kViewportAlternateDepthArray[2]; // Will be a problem only when using all 3 viewports. |
| } |
| else { |
| viewports[2] = test_data.kViewportArray[2]; |
| } |
| |
| uint32_t inherited_count = should_fail && !inherited_incorrect_depth ? 2 : 3; |
| test_data.BeginSubpassCommandBuffer(draw_cmd, inherited_count, test_data.kViewportDepthOnlyArray); |
| test_data.BindGraphicsPipeline(draw_cmd, true, 0); |
| vk::CmdDraw(draw_cmd, 3, 1, 0, 0); |
| vk::EndCommandBuffer(draw_cmd); |
| |
| test_data.BeginPrimaryCommandBuffer(primary_cmd); |
| |
| // Decoy command, should be overwritten later. |
| vkCmdSetViewportWithCountEXT(primary_cmd, 3, test_data.kViewportAlternateDepthArray); |
| |
| // Record state setting commands in either the primary, or auxilliary secondary, command buffer. |
| VkCommandBuffer set_state_cmd; |
| if (state_in_secondary) { |
| set_state_cmd = set_state_with_count_cmd; |
| test_data.BeginSubpassCommandBuffer(set_state_cmd, 0, nullptr); |
| } |
| else { |
| set_state_cmd = primary_cmd; |
| } |
| uint32_t count = should_fail ? 3 : 2; |
| vkCmdSetViewportWithCountEXT(set_state_cmd, count, viewports); |
| vkCmdSetScissorWithCountEXT(set_state_cmd, count, test_data.kScissorArray); |
| if (state_in_secondary) { |
| vk::EndCommandBuffer(set_state_cmd); |
| } |
| |
| test_data.BeginRenderPass(primary_cmd); |
| if (state_in_secondary) { |
| VkCommandBuffer secondaries[] = {set_state_cmd, draw_cmd}; |
| vk::CmdExecuteCommands(primary_cmd, 2, secondaries); |
| } |
| else { |
| vk::CmdExecuteCommands(primary_cmd, 1, &draw_cmd); |
| } |
| vk::CmdEndRenderPass(primary_cmd); |
| vk::EndCommandBuffer(primary_cmd); |
| |
| if (should_fail) m_errorMonitor->VerifyFound(); |
| else m_errorMonitor->VerifyNotFound(); |
| } |
| } |
| |
| TEST_F(VkLayerTest, ViewportInheritanceScissorMissingFeature) { |
| TEST_DESCRIPTION("Error using VK_NV_inherited_viewport_scissor without enabling multiViewport feature."); |
| m_instance_extension_names.push_back("VK_KHR_get_physical_device_properties2"); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| bool has_features = false; |
| const char* missing_feature_string = nullptr; |
| auto self = this; |
| ASSERT_NO_FATAL_FAILURE(has_features = ViewportInheritanceTestData::InitState( |
| this, [self](const char* extension) { self->m_device_extension_names.push_back(extension); }, |
| &missing_feature_string, true, false, true)); |
| if (!has_features) { |
| printf("%s\n", missing_feature_string); |
| return; |
| } |
| |
| ViewportInheritanceTestData test_data(m_device, gpu()); |
| if (test_data.FailureReason()) { |
| printf("%s Test internal failure: %s\n", kSkipPrefix, test_data.FailureReason()); |
| return; |
| } |
| VkCommandPool pool = m_commandPool->handle(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkCommandBufferInheritanceViewportScissorInfoNV-viewportScissor2D-04783"); |
| test_data.MakeBeginSubpassCommandBuffer(pool, 2, test_data.kViewportArray); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, PipelineMissingDynamicStateDiscardRectangle) { |
| TEST_DESCRIPTION("Bind pipeline with missing dynamic state discard rectangle."); |
| |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| if (!DeviceExtensionSupported(gpu(), nullptr, VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME)) { |
| printf("%s Extension %s is not supported.\n", kSkipPrefix, VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME); |
| return; |
| } |
| m_device_extension_names.push_back(VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME); |
| bool has_features = false; |
| const char* missing_feature_string = nullptr; |
| auto self = this; |
| ASSERT_NO_FATAL_FAILURE(has_features = ViewportInheritanceTestData::InitState( |
| this, [self](const char* extension) { self->m_device_extension_names.push_back(extension); }, |
| &missing_feature_string, true, false, true)); |
| if (!has_features) { |
| printf("%s\n", missing_feature_string); |
| return; |
| } |
| ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); |
| |
| VkCommandPoolObj pool(m_device, m_device->graphics_queue_node_index_, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); |
| VkCommandBufferObj secondary(m_device, &pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY); |
| |
| ViewportInheritanceTestData test_data(m_device, gpu()); |
| if (test_data.FailureReason()) { |
| printf("%s Test internal failure: %s\n", kSkipPrefix, test_data.FailureReason()); |
| return; |
| } |
| |
| VkCommandBufferInheritanceViewportScissorInfoNV viewport_scissor = |
| LvlInitStruct<VkCommandBufferInheritanceViewportScissorInfoNV>(); |
| viewport_scissor.viewportScissor2D = VK_TRUE; |
| viewport_scissor.viewportDepthCount = 1; |
| viewport_scissor.pViewportDepths = test_data.kViewportArray; |
| |
| VkCommandBufferInheritanceInfo cbii = LvlInitStruct<VkCommandBufferInheritanceInfo>(&viewport_scissor); |
| cbii.renderPass = m_renderPass; |
| |
| VkCommandBufferBeginInfo cbbi = LvlInitStruct<VkCommandBufferBeginInfo>(); |
| cbbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; |
| cbbi.pInheritanceInfo = &cbii; |
| |
| VkRect2D discard_rectangle = {}; |
| VkPipelineDiscardRectangleStateCreateInfoEXT discard_rectangle_state = |
| LvlInitStruct<VkPipelineDiscardRectangleStateCreateInfoEXT>(); |
| discard_rectangle_state.discardRectangleCount = 1; |
| discard_rectangle_state.pDiscardRectangles = &discard_rectangle; |
| |
| const VkDynamicState dyn_states[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; |
| VkPipelineDynamicStateCreateInfo dyn_state_ci = LvlInitStruct<VkPipelineDynamicStateCreateInfo>(); |
| dyn_state_ci.dynamicStateCount = 2; |
| dyn_state_ci.pDynamicStates = dyn_states; |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.InitInfo(); |
| pipe.gp_ci_.pNext = &discard_rectangle_state; |
| pipe.gp_ci_.pDynamicState = &dyn_state_ci; |
| pipe.InitState(); |
| pipe.CreateGraphicsPipeline(); |
| |
| vk::BeginCommandBuffer(secondary.handle(), &cbbi); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBindPipeline-commandBuffer-04809"); |
| vk::CmdBindPipeline(secondary.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.pipeline_); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| |
| // SPIR-V blobs for graphics pipeline. |
| |
| // #version 460 |
| // void main() { gl_Position = vec4(1); } |
| const uint32_t ViewportInheritanceTestData::kVertexSpirV[166] = { |
| 0x07230203, 0x00010000, 0x0008000a, 0x00000014, 0x00000000, 0x00020011, 0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, |
| 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0006000f, 0x00000000, 0x00000004, 0x6e69616d, |
| 0x00000000, 0x0000000d, 0x00030003, 0x00000002, 0x000001cc, 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, 0x00060005, |
| 0x0000000b, 0x505f6c67, 0x65567265, 0x78657472, 0x00000000, 0x00060006, 0x0000000b, 0x00000000, 0x505f6c67, 0x7469736f, |
| 0x006e6f69, 0x00070006, 0x0000000b, 0x00000001, 0x505f6c67, 0x746e696f, 0x657a6953, 0x00000000, 0x00070006, 0x0000000b, |
| 0x00000002, 0x435f6c67, 0x4470696c, 0x61747369, 0x0065636e, 0x00070006, 0x0000000b, 0x00000003, 0x435f6c67, 0x446c6c75, |
| 0x61747369, 0x0065636e, 0x00030005, 0x0000000d, 0x00000000, 0x00050048, 0x0000000b, 0x00000000, 0x0000000b, 0x00000000, |
| 0x00050048, 0x0000000b, 0x00000001, 0x0000000b, 0x00000001, 0x00050048, 0x0000000b, 0x00000002, 0x0000000b, 0x00000003, |
| 0x00050048, 0x0000000b, 0x00000003, 0x0000000b, 0x00000004, 0x00030047, 0x0000000b, 0x00000002, 0x00020013, 0x00000002, |
| 0x00030021, 0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, 0x00040017, 0x00000007, 0x00000006, 0x00000004, |
| 0x00040015, 0x00000008, 0x00000020, 0x00000000, 0x0004002b, 0x00000008, 0x00000009, 0x00000001, 0x0004001c, 0x0000000a, |
| 0x00000006, 0x00000009, 0x0006001e, 0x0000000b, 0x00000007, 0x00000006, 0x0000000a, 0x0000000a, 0x00040020, 0x0000000c, |
| 0x00000003, 0x0000000b, 0x0004003b, 0x0000000c, 0x0000000d, 0x00000003, 0x00040015, 0x0000000e, 0x00000020, 0x00000001, |
| 0x0004002b, 0x0000000e, 0x0000000f, 0x00000000, 0x0004002b, 0x00000006, 0x00000010, 0x3f800000, 0x0007002c, 0x00000007, |
| 0x00000011, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00040020, 0x00000012, 0x00000003, 0x00000007, 0x00050036, |
| 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x00050041, 0x00000012, 0x00000013, 0x0000000d, |
| 0x0000000f, 0x0003003e, 0x00000013, 0x00000011, 0x000100fd, 0x00010038}; |
| |
| // #version 460 |
| // layout(location = 0) out vec4 color; |
| // void main() { color = vec4(1); } |
| const uint32_t ViewportInheritanceTestData::kFragmentSpirV[83] = { |
| 0x07230203, 0x00010000, 0x0008000a, 0x0000000c, 0x00000000, 0x00020011, 0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, |
| 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001, 0x0006000f, 0x00000004, 0x00000004, 0x6e69616d, |
| 0x00000000, 0x00000009, 0x00030010, 0x00000004, 0x00000007, 0x00030003, 0x00000002, 0x000001cc, 0x00040005, 0x00000004, |
| 0x6e69616d, 0x00000000, 0x00040005, 0x00000009, 0x6f6c6f63, 0x00000072, 0x00040047, 0x00000009, 0x0000001e, 0x00000000, |
| 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, 0x00040017, 0x00000007, |
| 0x00000006, 0x00000004, 0x00040020, 0x00000008, 0x00000003, 0x00000007, 0x0004003b, 0x00000008, 0x00000009, 0x00000003, |
| 0x0004002b, 0x00000006, 0x0000000a, 0x3f800000, 0x0007002c, 0x00000007, 0x0000000b, 0x0000000a, 0x0000000a, 0x0000000a, |
| 0x0000000a, 0x00050036, 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x0003003e, 0x00000009, |
| 0x0000000b, 0x000100fd, 0x00010038}; |
| |
| const VkPipelineVertexInputStateCreateInfo ViewportInheritanceTestData::kVertexInputState = { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, nullptr, 0, 0, nullptr, 0, nullptr}; |
| |
| const VkPipelineInputAssemblyStateCreateInfo ViewportInheritanceTestData::kInputAssemblyState = { |
| VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, nullptr, 0, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_FALSE}; |
| |
| const VkPipelineRasterizationStateCreateInfo ViewportInheritanceTestData::kRasterizationState = { |
| VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, |
| nullptr, |
| 0, |
| VK_FALSE, |
| VK_FALSE, |
| VK_POLYGON_MODE_FILL, |
| VK_CULL_MODE_BACK_BIT, |
| VK_FRONT_FACE_COUNTER_CLOCKWISE, |
| }; |
| |
| const VkPipelineMultisampleStateCreateInfo ViewportInheritanceTestData::kMultisampleState = { |
| VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, |
| nullptr, |
| 0, |
| VK_SAMPLE_COUNT_1_BIT, |
| }; |
| |
| const VkPipelineDepthStencilStateCreateInfo ViewportInheritanceTestData::kDepthStencilState = { |
| VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, NULL}; |
| |
| const VkPipelineColorBlendAttachmentState ViewportInheritanceTestData::kBlendAttachmentState = { |
| VK_FALSE, |
| VK_BLEND_FACTOR_ZERO, |
| VK_BLEND_FACTOR_ZERO, |
| VK_BLEND_OP_ADD, |
| VK_BLEND_FACTOR_ZERO, |
| VK_BLEND_FACTOR_ZERO, |
| VK_BLEND_OP_ADD, |
| VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT}; |
| |
| const VkPipelineColorBlendStateCreateInfo ViewportInheritanceTestData::kBlendState = { |
| VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, |
| nullptr, |
| 0, |
| VK_FALSE, |
| VK_LOGIC_OP_CLEAR, |
| 1, |
| &kBlendAttachmentState, |
| {}}; |
| |
| const VkPipelineDynamicStateCreateInfo ViewportInheritanceTestData::kStaticState = { |
| VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, nullptr, 0, 0, nullptr}; |
| |
| static const std::array<VkDynamicState, 2> kDynamicStateArray = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; |
| const VkPipelineDynamicStateCreateInfo ViewportInheritanceTestData::kDynamicState = { |
| VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, nullptr, 0, |
| static_cast<uint32_t>(kDynamicStateArray.size()), kDynamicStateArray.data()}; |
| |
| static const std::array<VkDynamicState, 2> kDynamicStateWithCountArray = {VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT, |
| VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT}; |
| const VkPipelineDynamicStateCreateInfo ViewportInheritanceTestData::kDynamicStateWithCount = { |
| VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, nullptr, 0, |
| static_cast<uint32_t>(kDynamicStateWithCountArray.size()), kDynamicStateWithCountArray.data()}; |
| |
| const VkViewport ViewportInheritanceTestData::kViewportArray[32] = { |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 1.00f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.01f, 0.99f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.02f, 0.98f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.03f, 0.97f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.04f, 0.96f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.05f, 0.95f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.06f, 0.94f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.07f, 0.93f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.08f, 0.92f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.09f, 0.91f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.10f, 0.90f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.11f, 0.89f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.12f, 0.88f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.13f, 0.87f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.14f, 0.86f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.15f, 0.85f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.16f, 0.84f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.17f, 0.83f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.18f, 0.82f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.19f, 0.81f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.20f, 0.80f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.21f, 0.79f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.22f, 0.78f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.23f, 0.77f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.24f, 0.76f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.25f, 0.75f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.26f, 0.74f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.27f, 0.73f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.28f, 0.72f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.29f, 0.71f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.30f, 0.70f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.31f, 0.69f}, |
| }; |
| |
| const VkViewport ViewportInheritanceTestData::kViewportDepthOnlyArray[32] = { |
| {0.0f, 0.0f, 0.0f, 0.0f, 0.00f, 1.00f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.01f, 0.99f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.02f, 0.98f}, |
| {0.0f, 0.0f, 0.0f, 0.0f, 0.03f, 0.97f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.04f, 0.96f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.05f, 0.95f}, |
| {0.0f, 0.0f, 0.0f, 0.0f, 0.06f, 0.94f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.07f, 0.93f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.08f, 0.92f}, |
| {0.0f, 0.0f, 0.0f, 0.0f, 0.09f, 0.91f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.10f, 0.90f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.11f, 0.89f}, |
| {0.0f, 0.0f, 0.0f, 0.0f, 0.12f, 0.88f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.13f, 0.87f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.14f, 0.86f}, |
| {0.0f, 0.0f, 0.0f, 0.0f, 0.15f, 0.85f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.16f, 0.84f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.17f, 0.83f}, |
| {0.0f, 0.0f, 0.0f, 0.0f, 0.18f, 0.82f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.19f, 0.81f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.20f, 0.80f}, |
| {0.0f, 0.0f, 0.0f, 0.0f, 0.21f, 0.79f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.22f, 0.78f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.23f, 0.77f}, |
| {0.0f, 0.0f, 0.0f, 0.0f, 0.24f, 0.76f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.25f, 0.75f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.26f, 0.74f}, |
| {0.0f, 0.0f, 0.0f, 0.0f, 0.27f, 0.73f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.28f, 0.72f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.29f, 0.71f}, |
| {0.0f, 0.0f, 0.0f, 0.0f, 0.30f, 0.70f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.31f, 0.69f}, |
| }; |
| |
| const VkViewport ViewportInheritanceTestData::kViewportAlternateDepthArray[32] = { |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.88f, 1.00f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.01f, 0.00f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 0.98f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.03f, 0.00f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 0.96f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.05f, 0.00f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 0.94f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.07f, 0.00f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 0.92f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.09f, 0.00f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 0.90f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.11f, 0.00f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 0.88f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.13f, 0.00f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 0.86f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.15f, 0.00f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 0.84f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.17f, 0.00f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 0.82f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.19f, 0.00f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 0.80f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.21f, 0.00f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 0.78f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.23f, 0.00f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 0.76f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.25f, 0.00f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 0.74f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.27f, 0.00f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 0.72f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.29f, 0.00f}, |
| {0.0f, 0.0f, 128.0f, 128.0f, 0.00f, 0.70f}, {0.0f, 0.0f, 128.0f, 128.0f, 0.31f, 0.00f}, |
| }; |
| |
| const VkRect2D ViewportInheritanceTestData::kScissorArray[32] = { |
| {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, |
| {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, |
| {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, |
| {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, |
| {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, |
| {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, |
| {{0, 0}, {128, 128}}, {{0, 0}, {128, 128}}, |
| }; |