/* * Copyright (c) 2015-2016 The Khronos Group Inc. * Copyright (c) 2015-2016 Valve Corporation * Copyright (c) 2015-2016 LunarG, Inc. * Copyright (c) 2015-2016 Google, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and/or associated documentation files (the "Materials"), to * deal in the Materials without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Materials, and to permit persons to whom the Materials are * furnished to do so, subject to the following conditions: * * The above copyright notice(s) and this permission notice shall be included in * all copies or substantial portions of the Materials. * * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE * USE OR OTHER DEALINGS IN THE MATERIALS. * * Author: Chia-I Wu <olvaffe@gmail.com> * Author: Chris Forbes <chrisf@ijw.co.nz> * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> * Author: Mark Lobodzinski <mark@lunarg.com> * Author: Mike Stroyan <mike@LunarG.com> * Author: Tobin Ehlis <tobine@google.com> * Author: Tony Barbour <tony@LunarG.com> */ #include <vulkan/vulkan.h> #include "test_common.h" #include "vkrenderframework.h" #include "vk_layer_config.h" #include "icd-spv.h" #define GLM_FORCE_RADIANS #include "glm/glm.hpp" #include <glm/gtc/matrix_transform.hpp> #define MEM_TRACKER_TESTS 1 #define OBJ_TRACKER_TESTS 1 #define DRAW_STATE_TESTS 1 #define THREADING_TESTS 1 #define SHADER_CHECKER_TESTS 1 #define DEVICE_LIMITS_TESTS 1 #define IMAGE_TESTS 1 //-------------------------------------------------------------------------------------- // Mesh and VertexFormat Data //-------------------------------------------------------------------------------------- struct Vertex { float posX, posY, posZ, posW; // Position data float r, g, b, a; // Color }; #define XYZ1(_x_, _y_, _z_) (_x_), (_y_), (_z_), 1.f typedef enum _BsoFailSelect { BsoFailNone = 0x00000000, BsoFailLineWidth = 0x00000001, BsoFailDepthBias = 0x00000002, BsoFailViewport = 0x00000004, BsoFailScissor = 0x00000008, BsoFailBlend = 0x00000010, BsoFailDepthBounds = 0x00000020, BsoFailStencilReadMask = 0x00000040, BsoFailStencilWriteMask = 0x00000080, BsoFailStencilReference = 0x00000100, } BsoFailSelect; struct vktriangle_vs_uniform { // Must start with MVP float mvp[4][4]; float position[3][4]; float color[3][4]; }; static const char bindStateVertShaderText[] = "#version 400\n" "#extension GL_ARB_separate_shader_objects : require\n" "#extension GL_ARB_shading_language_420pack : require\n" "vec2 vertices[3];\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main() {\n" " vertices[0] = vec2(-1.0, -1.0);\n" " vertices[1] = vec2( 1.0, -1.0);\n" " vertices[2] = vec2( 0.0, 1.0);\n" " gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0);\n" "}\n"; static const char bindStateFragShaderText[] = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location = 0) out vec4 uFragColor;\n" "void main(){\n" " uFragColor = vec4(0,1,0,1);\n" "}\n"; static VKAPI_ATTR VkBool32 VKAPI_CALL myDbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg, void *pUserData); // ******************************************************** // ErrorMonitor Usage: // // Call SetDesiredFailureMsg with a string to be compared against all // encountered log messages. Passing NULL will match all log messages. // logMsg will return true for skipCall only if msg is matched or NULL. // // Call DesiredMsgFound to determine if the desired failure message // was encountered. class ErrorMonitor { public: ErrorMonitor() { test_platform_thread_create_mutex(&m_mutex); test_platform_thread_lock_mutex(&m_mutex); m_msgFlags = VK_DEBUG_REPORT_INFORMATION_BIT_EXT; m_bailout = NULL; test_platform_thread_unlock_mutex(&m_mutex); } void SetDesiredFailureMsg(VkFlags msgFlags, const char *msgString) { test_platform_thread_lock_mutex(&m_mutex); m_desiredMsg.clear(); m_failureMsg.clear(); m_otherMsgs.clear(); m_desiredMsg = msgString; m_msgFound = VK_FALSE; m_msgFlags = msgFlags; test_platform_thread_unlock_mutex(&m_mutex); } VkBool32 CheckForDesiredMsg(VkFlags msgFlags, const char *msgString) { VkBool32 result = VK_FALSE; test_platform_thread_lock_mutex(&m_mutex); if (m_bailout != NULL) { *m_bailout = true; } string errorString(msgString); if (msgFlags & m_msgFlags) { if (errorString.find(m_desiredMsg) != string::npos) { m_failureMsg = errorString; m_msgFound = VK_TRUE; result = VK_TRUE; } else { m_otherMsgs.push_back(errorString); } } test_platform_thread_unlock_mutex(&m_mutex); return result; } vector<string> GetOtherFailureMsgs(void) { return m_otherMsgs; } string GetFailureMsg(void) { return m_failureMsg; } VkBool32 DesiredMsgFound(void) { return m_msgFound; } void SetBailout(bool *bailout) { m_bailout = bailout; } void DumpFailureMsgs(void) { vector<string> otherMsgs = GetOtherFailureMsgs(); cout << "Other error messages logged for this test were:" << endl; for (auto iter = otherMsgs.begin(); iter != otherMsgs.end(); iter++) { cout << " " << *iter << endl; } } private: VkFlags m_msgFlags; string m_desiredMsg; string m_failureMsg; vector<string> m_otherMsgs; test_platform_thread_mutex m_mutex; bool *m_bailout; VkBool32 m_msgFound; }; static VKAPI_ATTR VkBool32 VKAPI_CALL myDbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg, void *pUserData) { if (msgFlags & (VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_ERROR_BIT_EXT)) { ErrorMonitor *errMonitor = (ErrorMonitor *)pUserData; return errMonitor->CheckForDesiredMsg(msgFlags, pMsg); } return false; } class VkLayerTest : public VkRenderFramework { public: VkResult BeginCommandBuffer(VkCommandBufferObj &commandBuffer); VkResult EndCommandBuffer(VkCommandBufferObj &commandBuffer); void VKTriangleTest(const char *vertShaderText, const char *fragShaderText, BsoFailSelect failMask); void GenericDrawPreparation(VkCommandBufferObj *commandBuffer, VkPipelineObj &pipelineobj, VkDescriptorSetObj &descriptorSet, BsoFailSelect failMask); void GenericDrawPreparation(VkPipelineObj &pipelineobj, VkDescriptorSetObj &descriptorSet, BsoFailSelect failMask) { GenericDrawPreparation(m_commandBuffer, pipelineobj, descriptorSet, failMask); } /* Convenience functions that use built-in command buffer */ VkResult BeginCommandBuffer() { return BeginCommandBuffer(*m_commandBuffer); } VkResult EndCommandBuffer() { return EndCommandBuffer(*m_commandBuffer); } void Draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) { m_commandBuffer->Draw(vertexCount, instanceCount, firstVertex, firstInstance); } void DrawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) { m_commandBuffer->DrawIndexed(indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); } void QueueCommandBuffer() { m_commandBuffer->QueueCommandBuffer(); } void QueueCommandBuffer(const VkFence &fence) { m_commandBuffer->QueueCommandBuffer(fence); } void BindVertexBuffer(VkConstantBufferObj *vertexBuffer, VkDeviceSize offset, uint32_t binding) { m_commandBuffer->BindVertexBuffer(vertexBuffer, offset, binding); } void BindIndexBuffer(VkIndexBufferObj *indexBuffer, VkDeviceSize offset) { m_commandBuffer->BindIndexBuffer(indexBuffer, offset); } protected: ErrorMonitor *m_errorMonitor; virtual void SetUp() { std::vector<const char *> instance_layer_names; std::vector<const char *> device_layer_names; std::vector<const char *> instance_extension_names; std::vector<const char *> device_extension_names; instance_extension_names.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); /* * Since CreateDbgMsgCallback is an instance level extension call * any extension / layer that utilizes that feature also needs * to be enabled at create instance time. */ // Use Threading layer first to protect others from // ThreadCommandBufferCollision test instance_layer_names.push_back("VK_LAYER_GOOGLE_threading"); instance_layer_names.push_back("VK_LAYER_LUNARG_object_tracker"); instance_layer_names.push_back("VK_LAYER_LUNARG_core_validation"); instance_layer_names.push_back("VK_LAYER_LUNARG_device_limits"); instance_layer_names.push_back("VK_LAYER_LUNARG_image"); instance_layer_names.push_back("VK_LAYER_GOOGLE_unique_objects"); device_layer_names.push_back("VK_LAYER_GOOGLE_threading"); device_layer_names.push_back("VK_LAYER_LUNARG_object_tracker"); device_layer_names.push_back("VK_LAYER_LUNARG_core_validation"); device_layer_names.push_back("VK_LAYER_LUNARG_device_limits"); device_layer_names.push_back("VK_LAYER_LUNARG_image"); device_layer_names.push_back("VK_LAYER_GOOGLE_unique_objects"); this->app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; this->app_info.pNext = NULL; this->app_info.pApplicationName = "layer_tests"; this->app_info.applicationVersion = 1; this->app_info.pEngineName = "unittest"; this->app_info.engineVersion = 1; this->app_info.apiVersion = VK_API_VERSION_1_0; m_errorMonitor = new ErrorMonitor; InitFramework(instance_layer_names, device_layer_names, instance_extension_names, device_extension_names, myDbgFunc, m_errorMonitor); } virtual void TearDown() { // Clean up resources before we reset ShutdownFramework(); delete m_errorMonitor; } }; VkResult VkLayerTest::BeginCommandBuffer(VkCommandBufferObj &commandBuffer) { VkResult result; result = commandBuffer.BeginCommandBuffer(); /* * For render test all drawing happens in a single render pass * on a single command buffer. */ if (VK_SUCCESS == result && renderPass()) { commandBuffer.BeginRenderPass(renderPassBeginInfo()); } return result; } VkResult VkLayerTest::EndCommandBuffer(VkCommandBufferObj &commandBuffer) { VkResult result; if (renderPass()) { commandBuffer.EndRenderPass(); } result = commandBuffer.EndCommandBuffer(); return result; } void VkLayerTest::VKTriangleTest(const char *vertShaderText, const char *fragShaderText, BsoFailSelect failMask) { // Create identity matrix int i; struct vktriangle_vs_uniform data; glm::mat4 Projection = glm::mat4(1.0f); glm::mat4 View = glm::mat4(1.0f); glm::mat4 Model = glm::mat4(1.0f); glm::mat4 MVP = Projection * View * Model; const int matrixSize = sizeof(MVP); const int bufSize = sizeof(vktriangle_vs_uniform) / sizeof(float); memcpy(&data.mvp, &MVP[0][0], matrixSize); static const Vertex tri_data[] = { {XYZ1(-1, -1, 0), XYZ1(1.f, 0.f, 0.f)}, {XYZ1(1, -1, 0), XYZ1(0.f, 1.f, 0.f)}, {XYZ1(0, 1, 0), XYZ1(0.f, 0.f, 1.f)}, }; for (i = 0; i < 3; i++) { data.position[i][0] = tri_data[i].posX; data.position[i][1] = tri_data[i].posY; data.position[i][2] = tri_data[i].posZ; data.position[i][3] = tri_data[i].posW; data.color[i][0] = tri_data[i].r; data.color[i][1] = tri_data[i].g; data.color[i][2] = tri_data[i].b; data.color[i][3] = tri_data[i].a; } ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitViewport()); VkConstantBufferObj constantBuffer(m_device, bufSize * 2, sizeof(float), (const void *)&data); VkShaderObj vs(m_device, vertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj ps(m_device, fragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipelineobj(m_device); pipelineobj.AddColorAttachment(); pipelineobj.AddShader(&vs); pipelineobj.AddShader(&ps); if (failMask & BsoFailLineWidth) { pipelineobj.MakeDynamic(VK_DYNAMIC_STATE_LINE_WIDTH); } if (failMask & BsoFailDepthBias) { pipelineobj.MakeDynamic(VK_DYNAMIC_STATE_DEPTH_BIAS); } // Viewport and scissors must stay in synch or other errors will occur than // the ones we want if (failMask & BsoFailViewport) { pipelineobj.MakeDynamic(VK_DYNAMIC_STATE_VIEWPORT); m_viewports.clear(); m_scissors.clear(); } if (failMask & BsoFailScissor) { pipelineobj.MakeDynamic(VK_DYNAMIC_STATE_SCISSOR); m_scissors.clear(); m_viewports.clear(); } if (failMask & BsoFailBlend) { pipelineobj.MakeDynamic(VK_DYNAMIC_STATE_BLEND_CONSTANTS); } if (failMask & BsoFailDepthBounds) { pipelineobj.MakeDynamic(VK_DYNAMIC_STATE_DEPTH_BOUNDS); } if (failMask & BsoFailStencilReadMask) { pipelineobj.MakeDynamic(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK); } if (failMask & BsoFailStencilWriteMask) { pipelineobj.MakeDynamic(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK); } if (failMask & BsoFailStencilReference) { pipelineobj.MakeDynamic(VK_DYNAMIC_STATE_STENCIL_REFERENCE); } VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendBuffer(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, constantBuffer); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); ASSERT_VK_SUCCESS(BeginCommandBuffer()); GenericDrawPreparation(pipelineobj, descriptorSet, failMask); // render triangle Draw(3, 1, 0, 0); // finalize recording of the command buffer EndCommandBuffer(); QueueCommandBuffer(); } void VkLayerTest::GenericDrawPreparation(VkCommandBufferObj *commandBuffer, VkPipelineObj &pipelineobj, VkDescriptorSetObj &descriptorSet, BsoFailSelect failMask) { if (m_depthStencil->Initialized()) { commandBuffer->ClearAllBuffers(m_clear_color, m_depth_clear_color, m_stencil_clear_color, m_depthStencil); } else { commandBuffer->ClearAllBuffers(m_clear_color, m_depth_clear_color, m_stencil_clear_color, NULL); } commandBuffer->PrepareAttachments(); // Make sure depthWriteEnable is set so that Depth fail test will work // correctly // Make sure stencilTestEnable is set so that Stencil fail test will work // correctly VkStencilOpState stencil = {}; stencil.failOp = VK_STENCIL_OP_KEEP; stencil.passOp = VK_STENCIL_OP_KEEP; stencil.depthFailOp = VK_STENCIL_OP_KEEP; stencil.compareOp = VK_COMPARE_OP_NEVER; VkPipelineDepthStencilStateCreateInfo ds_ci = {}; ds_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; ds_ci.pNext = NULL; ds_ci.depthTestEnable = VK_FALSE; ds_ci.depthWriteEnable = VK_TRUE; ds_ci.depthCompareOp = VK_COMPARE_OP_NEVER; ds_ci.depthBoundsTestEnable = VK_FALSE; ds_ci.stencilTestEnable = VK_TRUE; ds_ci.front = stencil; ds_ci.back = stencil; pipelineobj.SetDepthStencil(&ds_ci); pipelineobj.SetViewport(m_viewports); pipelineobj.SetScissor(m_scissors); descriptorSet.CreateVKDescriptorSet(commandBuffer); VkResult err = pipelineobj.CreateVKPipeline( descriptorSet.GetPipelineLayout(), renderPass()); ASSERT_VK_SUCCESS(err); commandBuffer->BindPipeline(pipelineobj); commandBuffer->BindDescriptorSet(descriptorSet); } // ******************************************************************************************************************** // ******************************************************************************************************************** // ******************************************************************************************************************** // ******************************************************************************************************************** #if MEM_TRACKER_TESTS #if 0 TEST_F(VkLayerTest, CallResetCommandBufferBeforeCompletion) { vk_testing::Fence testFence; VkFenceCreateInfo fenceInfo = {}; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.pNext = NULL; fenceInfo.flags = 0; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Resetting CB"); ASSERT_NO_FATAL_FAILURE(InitState()); VkMemoryPropertyFlags reqs = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; vk_testing::Buffer buffer; buffer.init_as_dst(*m_device, (VkDeviceSize)20, reqs); BeginCommandBuffer(); m_commandBuffer->FillBuffer(buffer.handle(), 0, 4, 0x11111111); EndCommandBuffer(); testFence.init(*m_device, fenceInfo); // Bypass framework since it does the waits automatically VkResult err = VK_SUCCESS; VkSubmitInfo submit_info; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.pNext = NULL; submit_info.waitSemaphoreCount = 0; submit_info.pWaitSemaphores = NULL; submit_info.pWaitDstStageMask = NULL; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &m_commandBuffer->handle(); submit_info.signalSemaphoreCount = 0; submit_info.pSignalSemaphores = NULL; err = vkQueueSubmit( m_device->m_queue, 1, &submit_info, testFence.handle()); ASSERT_VK_SUCCESS( err ); // Introduce failure by calling begin again before checking fence vkResetCommandBuffer(m_commandBuffer->handle(), 0); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Resetting CB (0xaddress) before it has completed. You must check CB flag before.'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CallBeginCommandBufferBeforeCompletion) { vk_testing::Fence testFence; VkFenceCreateInfo fenceInfo = {}; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.pNext = NULL; fenceInfo.flags = 0; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Calling vkBeginCommandBuffer() on active CB"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitViewport()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); BeginCommandBuffer(); m_commandBuffer->ClearAllBuffers(m_clear_color, m_depth_clear_color, m_stencil_clear_color, NULL); EndCommandBuffer(); testFence.init(*m_device, fenceInfo); // Bypass framework since it does the waits automatically VkResult err = VK_SUCCESS; VkSubmitInfo submit_info; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.pNext = NULL; submit_info.waitSemaphoreCount = 0; submit_info.pWaitSemaphores = NULL; submit_info.pWaitDstStageMask = NULL; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &m_commandBuffer->handle(); submit_info.signalSemaphoreCount = 0; submit_info.pSignalSemaphores = NULL; err = vkQueueSubmit( m_device->m_queue, 1, &submit_info, testFence.handle()); ASSERT_VK_SUCCESS( err ); VkCommandBufferInheritanceInfo hinfo = {}; VkCommandBufferBeginInfo info = {}; info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; info.renderPass = VK_NULL_HANDLE; info.subpass = 0; info.framebuffer = VK_NULL_HANDLE; info.occlusionQueryEnable = VK_FALSE; info.queryFlags = 0; info.pipelineStatistics = 0; // Introduce failure by calling BCB again before checking fence vkBeginCommandBuffer(m_commandBuffer->handle(), &info); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Calling vkBeginCommandBuffer() on an active CB (0xaddress) before it has completed'"; m_errorMonitor->DumpFailureMsgs(); } } #endif TEST_F(VkLayerTest, MapMemWithoutHostVisibleBit) { VkResult err; bool pass; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Mapping Memory without VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT"); ASSERT_NO_FATAL_FAILURE(InitState()); // Create an image, allocate memory, free it, and then try to bind it VkImage image; VkDeviceMemory mem; VkMemoryRequirements mem_reqs; const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; const int32_t tex_width = 32; const int32_t tex_height = 32; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = tex_format; image_create_info.extent.width = tex_width; image_create_info.extent.height = tex_height; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.tiling = VK_IMAGE_TILING_LINEAR; image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; image_create_info.flags = 0; VkMemoryAllocateInfo mem_alloc = {}; mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; mem_alloc.pNext = NULL; mem_alloc.allocationSize = 0; // Introduce failure, do NOT set memProps to // VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT mem_alloc.memoryTypeIndex = 1; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image); ASSERT_VK_SUCCESS(err); vkGetImageMemoryRequirements(m_device->device(), image, &mem_reqs); mem_alloc.allocationSize = mem_reqs.size; pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &mem_alloc, 0, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); if (!pass) { // If we can't find any unmappable memory this test doesn't // make sense vkDestroyImage(m_device->device(), image, NULL); return; } // allocate memory err = vkAllocateMemory(m_device->device(), &mem_alloc, NULL, &mem); ASSERT_VK_SUCCESS(err); // Try to bind free memory that has been freed err = vkBindImageMemory(m_device->device(), image, mem, 0); ASSERT_VK_SUCCESS(err); // Map memory as if to initialize the image void *mappedAddress = NULL; err = vkMapMemory(m_device->device(), mem, 0, VK_WHOLE_SIZE, 0, &mappedAddress); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Error received did not match " "expected error message from vkMapMemory in MemTracker'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyImage(m_device->device(), image, NULL); } // TODO : Is this test still valid. Not sure it is with updates to memory // binding model // Verify and delete the test of fix the check // TEST_F(VkLayerTest, FreeBoundMemory) //{ // VkResult err; // // m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_WARNING_BIT_EXT, // "Freeing memory object while it still has references"); // // ASSERT_NO_FATAL_FAILURE(InitState()); // // Create an image, allocate memory, free it, and then try to bind it // VkImage image; // VkDeviceMemory mem; // VkMemoryRequirements mem_reqs; // // const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; // const int32_t tex_width = 32; // const int32_t tex_height = 32; // // const VkImageCreateInfo image_create_info = { // .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // .pNext = NULL, // .imageType = VK_IMAGE_TYPE_2D, // .format = tex_format, // .extent = { tex_width, tex_height, 1 }, // .mipLevels = 1, // .arraySize = 1, // .samples = VK_SAMPLE_COUNT_1_BIT, // .tiling = VK_IMAGE_TILING_LINEAR, // .usage = VK_IMAGE_USAGE_SAMPLED_BIT, // .flags = 0, // }; // VkMemoryAllocateInfo mem_alloc = { // .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // .pNext = NULL, // .allocationSize = 0, // .memoryTypeIndex = 0, // }; // // err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image); // ASSERT_VK_SUCCESS(err); // // err = vkGetImageMemoryRequirements(m_device->device(), // image, // &mem_reqs); // ASSERT_VK_SUCCESS(err); // // mem_alloc.allocationSize = mem_reqs.size; // // err = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &mem_alloc, // 0); // ASSERT_VK_SUCCESS(err); // // // allocate memory // err = vkAllocateMemory(m_device->device(), &mem_alloc, NULL, &mem); // ASSERT_VK_SUCCESS(err); // // // Bind memory to Image object // err = vkBindImageMemory(m_device->device(), image, mem, 0); // ASSERT_VK_SUCCESS(err); // // // Introduce validation failure, free memory while still bound to object // vkFreeMemory(m_device->device(), mem, NULL); // // if (!m_errorMonitor->DesiredMsgFound()) { // FAIL() << "Did not receive Warning 'Freeing memory object while it // still has references'"); // m_errorMonitor->DumpFailureMsgs(); // } //} TEST_F(VkLayerTest, RebindMemory) { VkResult err; bool pass; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "which has already been bound to mem object"); ASSERT_NO_FATAL_FAILURE(InitState()); // Create an image, allocate memory, free it, and then try to bind it VkImage image; VkDeviceMemory mem1; VkDeviceMemory mem2; VkMemoryRequirements mem_reqs; const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; const int32_t tex_width = 32; const int32_t tex_height = 32; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = tex_format; image_create_info.extent.width = tex_width; image_create_info.extent.height = tex_height; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.tiling = VK_IMAGE_TILING_LINEAR; image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; image_create_info.flags = 0; VkMemoryAllocateInfo mem_alloc = {}; mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; mem_alloc.pNext = NULL; mem_alloc.allocationSize = 0; mem_alloc.memoryTypeIndex = 0; // Introduce failure, do NOT set memProps to // VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT mem_alloc.memoryTypeIndex = 1; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image); ASSERT_VK_SUCCESS(err); vkGetImageMemoryRequirements(m_device->device(), image, &mem_reqs); mem_alloc.allocationSize = mem_reqs.size; pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &mem_alloc, 0); ASSERT_TRUE(pass); // allocate 2 memory objects err = vkAllocateMemory(m_device->device(), &mem_alloc, NULL, &mem1); ASSERT_VK_SUCCESS(err); err = vkAllocateMemory(m_device->device(), &mem_alloc, NULL, &mem2); ASSERT_VK_SUCCESS(err); // Bind first memory object to Image object err = vkBindImageMemory(m_device->device(), image, mem1, 0); ASSERT_VK_SUCCESS(err); // Introduce validation failure, try to bind a different memory object to // the same image object err = vkBindImageMemory(m_device->device(), image, mem2, 0); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error when rebinding memory to an object"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyImage(m_device->device(), image, NULL); vkFreeMemory(m_device->device(), mem1, NULL); vkFreeMemory(m_device->device(), mem2, NULL); } TEST_F(VkLayerTest, SubmitSignaledFence) { vk_testing::Fence testFence; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "submitted in SIGNALED state. Fences " "must be reset before being submitted"); VkFenceCreateInfo fenceInfo = {}; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.pNext = NULL; fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitViewport()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); BeginCommandBuffer(); m_commandBuffer->ClearAllBuffers(m_clear_color, m_depth_clear_color, m_stencil_clear_color, NULL); EndCommandBuffer(); testFence.init(*m_device, fenceInfo); VkSubmitInfo submit_info; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.pNext = NULL; submit_info.waitSemaphoreCount = 0; submit_info.pWaitSemaphores = NULL; submit_info.pWaitDstStageMask = NULL; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &m_commandBuffer->handle(); submit_info.signalSemaphoreCount = 0; submit_info.pSignalSemaphores = NULL; vkQueueSubmit(m_device->m_queue, 1, &submit_info, testFence.handle()); vkQueueWaitIdle(m_device->m_queue); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'VkQueueSubmit with fence in " "SIGNALED_STATE'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, ResetUnsignaledFence) { vk_testing::Fence testFence; VkFenceCreateInfo fenceInfo = {}; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.pNext = NULL; // TODO: verify that this matches layer m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_WARNING_BIT_EXT, "submitted to VkResetFences in UNSIGNALED STATE"); ASSERT_NO_FATAL_FAILURE(InitState()); testFence.init(*m_device, fenceInfo); VkFence fences[1] = {testFence.handle()}; vkResetFences(m_device->device(), 1, fences); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'VkResetFences with fence in " "UNSIGNALED_STATE'"; m_errorMonitor->DumpFailureMsgs(); } } /* TODO: Update for changes due to bug-14075 tiling across render passes */ #if 0 TEST_F(VkLayerTest, InvalidUsageBits) { // Initiate Draw w/o a PSO bound m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Invalid usage flag for image "); ASSERT_NO_FATAL_FAILURE(InitState()); VkCommandBufferObj commandBuffer(m_device); BeginCommandBuffer(); const VkExtent3D e3d = { .width = 128, .height = 128, .depth = 1, }; const VkImageCreateInfo ici = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = NULL, .imageType = VK_IMAGE_TYPE_2D, .format = VK_FORMAT_D32_SFLOAT_S8_UINT, .extent = e3d, .mipLevels = 1, .arraySize = 1, .samples = VK_SAMPLE_COUNT_1_BIT, .tiling = VK_IMAGE_TILING_LINEAR, .usage = 0, // Not setting VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT .flags = 0, }; VkImage dsi; vkCreateImage(m_device->device(), &ici, NULL, &dsi); VkDepthStencilView dsv; const VkDepthStencilViewCreateInfo dsvci = { .sType = VK_STRUCTURE_TYPE_DEPTH_STENCIL_VIEW_CREATE_INFO, .pNext = NULL, .image = dsi, .mipLevel = 0, .baseArrayLayer = 0, .arraySize = 1, .flags = 0, }; vkCreateDepthStencilView(m_device->device(), &dsvci, NULL, &dsv); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Error received was not 'Invalid usage flag for image...'"; m_errorMonitor->DumpFailureMsgs(); } } #endif // 0 #endif // MEM_TRACKER_TESTS #if OBJ_TRACKER_TESTS TEST_F(VkLayerTest, PipelineNotBound) { VkResult err; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Invalid VkPipeline Object "); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_ci.pNext = NULL; pipeline_layout_ci.setLayoutCount = 1; pipeline_layout_ci.pSetLayouts = &ds_layout; VkPipelineLayout pipeline_layout; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); ASSERT_VK_SUCCESS(err); VkPipeline badPipeline = (VkPipeline)((size_t)0xbaadb1be); BeginCommandBuffer(); vkCmdBindPipeline(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, badPipeline); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Error received was not 'Invalid VkPipeline Object 0xbaadb1be'" << endl; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, BindInvalidMemory) { VkResult err; bool pass; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Invalid VkDeviceMemory Object "); ASSERT_NO_FATAL_FAILURE(InitState()); // Create an image, allocate memory, free it, and then try to bind it VkImage image; VkDeviceMemory mem; VkMemoryRequirements mem_reqs; const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; const int32_t tex_width = 32; const int32_t tex_height = 32; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = tex_format; image_create_info.extent.width = tex_width; image_create_info.extent.height = tex_height; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.tiling = VK_IMAGE_TILING_LINEAR; image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; image_create_info.flags = 0; VkMemoryAllocateInfo mem_alloc = {}; mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; mem_alloc.pNext = NULL; mem_alloc.allocationSize = 0; mem_alloc.memoryTypeIndex = 0; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image); ASSERT_VK_SUCCESS(err); vkGetImageMemoryRequirements(m_device->device(), image, &mem_reqs); mem_alloc.allocationSize = mem_reqs.size; pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &mem_alloc, 0); ASSERT_TRUE(pass); // allocate memory err = vkAllocateMemory(m_device->device(), &mem_alloc, NULL, &mem); ASSERT_VK_SUCCESS(err); // Introduce validation failure, free memory before binding vkFreeMemory(m_device->device(), mem, NULL); // Try to bind free memory that has been freed err = vkBindImageMemory(m_device->device(), image, mem, 0); // This may very well return an error. (void)err; if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Invalid VkDeviceMemory Object " "0x<handle>'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyImage(m_device->device(), image, NULL); } TEST_F(VkLayerTest, BindMemoryToDestroyedObject) { VkResult err; bool pass; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Invalid VkImage Object "); ASSERT_NO_FATAL_FAILURE(InitState()); // Create an image object, allocate memory, destroy the object and then try // to bind it VkImage image; VkDeviceMemory mem; VkMemoryRequirements mem_reqs; const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; const int32_t tex_width = 32; const int32_t tex_height = 32; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = tex_format; image_create_info.extent.width = tex_width; image_create_info.extent.height = tex_height; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.tiling = VK_IMAGE_TILING_LINEAR; image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; image_create_info.flags = 0; VkMemoryAllocateInfo mem_alloc = {}; mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; mem_alloc.pNext = NULL; mem_alloc.allocationSize = 0; mem_alloc.memoryTypeIndex = 0; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image); ASSERT_VK_SUCCESS(err); vkGetImageMemoryRequirements(m_device->device(), image, &mem_reqs); mem_alloc.allocationSize = mem_reqs.size; pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &mem_alloc, 0); ASSERT_TRUE(pass); // Allocate memory err = vkAllocateMemory(m_device->device(), &mem_alloc, NULL, &mem); ASSERT_VK_SUCCESS(err); // Introduce validation failure, destroy Image object before binding vkDestroyImage(m_device->device(), image, NULL); ASSERT_VK_SUCCESS(err); // Now Try to bind memory to this destroyed object err = vkBindImageMemory(m_device->device(), image, mem, 0); // This may very well return an error. (void)err; if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Invalid VkImage Object 0x<handle>'"; m_errorMonitor->DumpFailureMsgs(); } vkFreeMemory(m_device->device(), mem, NULL); } #endif // OBJ_TRACKER_TESTS #if DRAW_STATE_TESTS TEST_F(VkLayerTest, LineWidthStateNotBound) { m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Dynamic line width state not set for this command buffer"); TEST_DESCRIPTION("Simple Draw Call that validates failure when a line " "width state object is not bound beforehand"); VKTriangleTest(bindStateVertShaderText, bindStateFragShaderText, BsoFailLineWidth); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Dynamic line width state not set for " "this command buffer'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, DepthBiasStateNotBound) { m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Dynamic depth bias state not set for this command buffer"); TEST_DESCRIPTION("Simple Draw Call that validates failure when a depth " "bias state object is not bound beforehand"); VKTriangleTest(bindStateVertShaderText, bindStateFragShaderText, BsoFailDepthBias); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Dynamic depth bias state not set for " "this command buffer'"; m_errorMonitor->DumpFailureMsgs(); } } // Disable these two tests until we can sort out how to track multiple layer // errors TEST_F(VkLayerTest, ViewportStateNotBound) { m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Dynamic viewport state not set for this command buffer"); TEST_DESCRIPTION("Simple Draw Call that validates failure when a viewport " "state object is not bound beforehand"); VKTriangleTest(bindStateVertShaderText, bindStateFragShaderText, BsoFailViewport); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not recieve Error 'Dynamic scissor state not set for " "this command buffer'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, ScissorStateNotBound) { m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Dynamic scissor state not set for this command buffer"); TEST_DESCRIPTION("Simple Draw Call that validates failure when a viewport " "state object is not bound beforehand"); VKTriangleTest(bindStateVertShaderText, bindStateFragShaderText, BsoFailScissor); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not recieve Error ' Expected: 'Dynamic scissor state " "not set for this command buffer'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, BlendStateNotBound) { m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Dynamic blend object state not set for this command buffer"); TEST_DESCRIPTION("Simple Draw Call that validates failure when a blend " "state object is not bound beforehand"); VKTriangleTest(bindStateVertShaderText, bindStateFragShaderText, BsoFailBlend); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not recieve Error 'Dynamic blend object state not set " "for this command buffer'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, DepthBoundsStateNotBound) { m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Dynamic depth bounds state not set for this command buffer"); TEST_DESCRIPTION("Simple Draw Call that validates failure when a depth " "bounds state object is not bound beforehand"); VKTriangleTest(bindStateVertShaderText, bindStateFragShaderText, BsoFailDepthBounds); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Dynamic depth bounds state not set " "for this command buffer'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, StencilReadMaskNotSet) { m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Dynamic stencil read mask state not set for this command buffer"); ASSERT_NO_FATAL_FAILURE(InitState()); TEST_DESCRIPTION("Simple Draw Call that validates failure when a stencil " "read mask is not set beforehand"); VKTriangleTest(bindStateVertShaderText, bindStateFragShaderText, BsoFailStencilReadMask); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Dynamic stencil read mask state not " "set for this command buffer'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, StencilWriteMaskNotSet) { m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Dynamic stencil write mask state not set for this command buffer"); ASSERT_NO_FATAL_FAILURE(InitState()); TEST_DESCRIPTION("Simple Draw Call that validates failure when a stencil " "write mask is not set beforehand"); VKTriangleTest(bindStateVertShaderText, bindStateFragShaderText, BsoFailStencilWriteMask); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Dynamic stencil write mask state not " "set for this command buffer'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, StencilReferenceNotSet) { m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Dynamic stencil reference state not set for this command buffer"); TEST_DESCRIPTION("Simple Draw Call that validates failure when a stencil " "reference is not set beforehand"); VKTriangleTest(bindStateVertShaderText, bindStateFragShaderText, BsoFailStencilReference); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Dynamic stencil reference state not " "set for this command buffer'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CommandBufferTwoSubmits) { vk_testing::Fence testFence; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "was begun w/ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT set, but has " "been submitted"); VkFenceCreateInfo fenceInfo = {}; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.pNext = NULL; fenceInfo.flags = 0; ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitViewport()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); // We luck out b/c by default the framework creates CB w/ the // VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT set BeginCommandBuffer(); m_commandBuffer->ClearAllBuffers(m_clear_color, m_depth_clear_color, m_stencil_clear_color, NULL); EndCommandBuffer(); testFence.init(*m_device, fenceInfo); // Bypass framework since it does the waits automatically VkResult err = VK_SUCCESS; VkSubmitInfo submit_info; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.pNext = NULL; submit_info.waitSemaphoreCount = 0; submit_info.pWaitSemaphores = NULL; submit_info.pWaitDstStageMask = NULL; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &m_commandBuffer->handle(); submit_info.signalSemaphoreCount = 0; submit_info.pSignalSemaphores = NULL; err = vkQueueSubmit(m_device->m_queue, 1, &submit_info, testFence.handle()); ASSERT_VK_SUCCESS(err); // Cause validation error by re-submitting cmd buffer that should only be // submitted once err = vkQueueSubmit(m_device->m_queue, 1, &submit_info, testFence.handle()); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'CB (0xaddress) was created w/ " "VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT set...'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, AllocDescriptorFromEmptyPool) { // Initiate Draw w/o a PSO bound VkResult err; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Unable to allocate 1 descriptors of " "type " "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER "); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); // Create Pool w/ 1 Sampler descriptor, but try to alloc Uniform Buffer // descriptor from it VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_SAMPLER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.flags = 0; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Unable to allocate 1 descriptors of " "type VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, FreeDescriptorFromOneShotPool) { VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "It is invalid to call vkFreeDescriptorSets() with a pool created " "without setting VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT."); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.flags = 0; // Not specifying VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT means // app can only call vkResetDescriptorPool on this pool.; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); err = vkFreeDescriptorSets(m_device->device(), ds_pool, 1, &descriptorSet); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'It is invalid to call " "vkFreeDescriptorSets() with a pool created with...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, InvalidDescriptorPool) { // TODO : Simple check for bad object should be added to ObjectTracker to // catch this case // The DS check for this is after driver has been called to validate DS // internal data struct // Attempt to clear DS Pool with bad object /* m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Unable to find pool node for pool 0xbaad6001 specified in vkResetDescriptorPool() call"); VkDescriptorPool badPool = (VkDescriptorPool)0xbaad6001; vkResetDescriptorPool(device(), badPool); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Unable to find pool node for pool 0xbaad6001 specified in vkResetDescriptorPool() call'"; m_errorMonitor->DumpFailureMsgs(); }*/ } TEST_F(VkLayerTest, InvalidDescriptorSet) { // TODO : Simple check for bad object should be added to ObjectTracker to // catch this case // The DS check for this is after driver has been called to validate DS // internal data struct // Create a valid cmd buffer // call vkCmdBindDescriptorSets w/ false DS } TEST_F(VkLayerTest, InvalidDescriptorSetLayout) { // TODO : Simple check for bad object should be added to ObjectTracker to // catch this case // The DS check for this is after driver has been called to validate DS // internal data struct } TEST_F(VkLayerTest, InvalidPipeline) { // TODO : Simple check for bad object should be added to ObjectTracker to // catch this case // The DS check for this is after driver has been called to validate DS // internal data struct // Create a valid cmd buffer // call vkCmdBindPipeline w/ false Pipeline // // m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, // "Attempt to bind Pipeline "); // // ASSERT_NO_FATAL_FAILURE(InitState()); // VkCommandBufferObj commandBuffer(m_device); // BeginCommandBuffer(); // VkPipeline badPipeline = (VkPipeline)0xbaadb1be; // vkCmdBindPipeline(commandBuffer.GetBufferHandle(), // VK_PIPELINE_BIND_POINT_GRAPHICS, badPipeline); // // if (!m_errorMonitor->DesiredMsgFound()) { // FAIL() << "Did not receive Error 'Attempt to bind Pipeline // 0xbaadb1be that doesn't exist!'"; // m_errorMonitor->DumpFailureMsgs(); // } } TEST_F(VkLayerTest, DescriptorSetNotUpdated) { // Create and update CommandBuffer then call QueueSubmit w/o calling End on // CommandBuffer VkResult err; // TODO: verify that this matches layer m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_WARNING_BIT_EXT, " bound but it was never updated. "); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitViewport()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_ci.pNext = NULL; pipeline_layout_ci.setLayoutCount = 1; pipeline_layout_ci.pSetLayouts = &ds_layout; VkPipelineLayout pipeline_layout; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); ASSERT_VK_SUCCESS(err); VkShaderObj vs(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this); // TODO - We shouldn't need a fragment shader but add it to be able to run // on more devices VkShaderObj fs(m_device, bindStateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddShader(&vs); pipe.AddShader(&fs); pipe.CreateVKPipeline(pipeline_layout, renderPass()); BeginCommandBuffer(); vkCmdBindPipeline(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle()); vkCmdBindDescriptorSets(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptorSet, 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not recieve Warning 'DS <blah> bound but it was never " "updated. You may want to either update it or not bind it.'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, InvalidBufferViewObject) { // Create a single TEXEL_BUFFER descriptor and send it an invalid bufferView VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Attempt to update descriptor with invalid bufferView "); ASSERT_NO_FATAL_FAILURE(InitState()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkBufferView view = (VkBufferView)((size_t)0xbaadbeef); // invalid bufferView object VkWriteDescriptorSet descriptor_write; memset(&descriptor_write, 0, sizeof(descriptor_write)); descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write.dstSet = descriptorSet; descriptor_write.dstBinding = 0; descriptor_write.descriptorCount = 1; descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; descriptor_write.pTexelBufferView = &view; vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Attempt to update descriptor with " "invalid bufferView'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, InvalidDynamicOffsetCases) { // Create a descriptorSet w/ dynamic descriptor and then hit 3 offset error // cases: // 1. No dynamicOffset supplied // 2. Too many dynamicOffsets supplied // 3. Dynamic offset oversteps buffer being updated VkResult err; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, " requires 1 dynamicOffsets, but only " "0 dynamicOffsets are left in " "pDynamicOffsets "); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitViewport()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_ci.pNext = NULL; pipeline_layout_ci.setLayoutCount = 1; pipeline_layout_ci.pSetLayouts = &ds_layout; VkPipelineLayout pipeline_layout; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); ASSERT_VK_SUCCESS(err); // Create a buffer to update the descriptor with uint32_t qfi = 0; VkBufferCreateInfo buffCI = {}; buffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffCI.size = 1024; buffCI.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; buffCI.queueFamilyIndexCount = 1; buffCI.pQueueFamilyIndices = &qfi; VkBuffer dyub; err = vkCreateBuffer(m_device->device(), &buffCI, NULL, &dyub); ASSERT_VK_SUCCESS(err); // Correctly update descriptor to avoid "NOT_UPDATED" error VkDescriptorBufferInfo buffInfo = {}; buffInfo.buffer = dyub; buffInfo.offset = 0; buffInfo.range = 1024; VkWriteDescriptorSet descriptor_write; memset(&descriptor_write, 0, sizeof(descriptor_write)); descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write.dstSet = descriptorSet; descriptor_write.dstBinding = 0; descriptor_write.descriptorCount = 1; descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; descriptor_write.pBufferInfo = &buffInfo; vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); BeginCommandBuffer(); vkCmdBindDescriptorSets(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptorSet, 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Error received was not 'descriptorSet #0 (0x<ADDR>) " "requires 1 dynamicOffsets, but only 0 dynamicOffsets are " "left in pDynamicOffsets array...'"; m_errorMonitor->DumpFailureMsgs(); } uint32_t pDynOff[2] = {512, 756}; // Now cause error b/c too many dynOffsets in array for # of dyn descriptors m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Attempting to bind 1 descriptorSets with 1 dynamic descriptors, but "); vkCmdBindDescriptorSets(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptorSet, 2, pDynOff); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Error received was not 'Attempting to bind 1 descriptorSets " "with 1 dynamic descriptors, but dynamicOffsetCount is 0...'"; m_errorMonitor->DumpFailureMsgs(); } // Finally cause error due to dynamicOffset being too big m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, " from its update, this oversteps its buffer ("); // Create PSO to be used for draw-time errors below char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "out gl_PerVertex { \n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = vec4(1);\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out vec4 x;\n" "layout(set=0) layout(binding=0) uniform foo { int x; int y; } bar;\n" "void main(){\n" " x = vec4(bar.y);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddShader(&vs); pipe.AddShader(&fs); pipe.AddColorAttachment(); pipe.CreateVKPipeline(pipeline_layout, renderPass()); vkCmdBindPipeline(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle()); // This update should succeed, but offset size of 512 will overstep buffer // /w range 1024 & size 1024 vkCmdBindDescriptorSets(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptorSet, 1, pDynOff); Draw(1, 0, 0, 0); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Error received was not 'VkDescriptorSet (0x<ADDR>) bound as " "set #0 has dynamic offset 512. Combined with offet 0 and " "range 1024 from its update, this oversteps...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, InvalidPushConstants) { // Hit push constant error cases: // 1. Create PipelineLayout where push constant overstep maxPushConstantSize // 2. Incorrectly set push constant size to 0 // 3. Incorrectly set push constant size to non-multiple of 4 // 4. Attempt push constant update that exceeds maxPushConstantSize VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCreatePipelineLayout() call has push constants with offset "); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitViewport()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkPushConstantRange pc_range = {}; pc_range.size = 0xFFFFFFFFu; pc_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_ci.pushConstantRangeCount = 1; pipeline_layout_ci.pPushConstantRanges = &pc_range; VkPipelineLayout pipeline_layout; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Error received was not 'vkCreatePipelineLayout() call has " "push constants with offset 0...'"; m_errorMonitor->DumpFailureMsgs(); } // Now cause errors due to size 0 and non-4 byte aligned size pc_range.size = 0; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCreatePipelineLayout() call has push constant index 0 with size 0"); err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Error received was not 'vkCreatePipelineLayout() call has " "push constant index 0 with size 0...'"; m_errorMonitor->DumpFailureMsgs(); } pc_range.size = 1; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCreatePipelineLayout() call has push constant index 0 with size 1"); err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Error received was not 'vkCreatePipelineLayout() call has " "push constant index 0 with size 0...'"; m_errorMonitor->DumpFailureMsgs(); } // Cause error due to bad size in vkCmdPushConstants() call m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdPushConstants() call has push constants with offset "); pipeline_layout_ci.pushConstantRangeCount = 0; pipeline_layout_ci.pPushConstantRanges = NULL; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); ASSERT_VK_SUCCESS(err); BeginCommandBuffer(); vkCmdPushConstants(m_commandBuffer->GetBufferHandle(), pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 0xFFFFFFFFu, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Error received was not 'vkCmdPushConstants() call has push " "constants with offset 0...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); } TEST_F(VkLayerTest, DescriptorSetCompatibility) { // Test various desriptorSet errors with bad binding combinations VkResult err; ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitViewport()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); static const uint32_t NUM_DESCRIPTOR_TYPES = 5; VkDescriptorPoolSize ds_type_count[NUM_DESCRIPTOR_TYPES] = {}; ds_type_count[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count[0].descriptorCount = 10; ds_type_count[1].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; ds_type_count[1].descriptorCount = 2; ds_type_count[2].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; ds_type_count[2].descriptorCount = 2; ds_type_count[3].type = VK_DESCRIPTOR_TYPE_SAMPLER; ds_type_count[3].descriptorCount = 5; // TODO : LunarG ILO driver currently asserts in desc.c w/ INPUT_ATTACHMENT // type // ds_type_count[4].type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; ds_type_count[4].type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; ds_type_count[4].descriptorCount = 2; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 5; ds_pool_ci.poolSizeCount = NUM_DESCRIPTOR_TYPES; ds_pool_ci.pPoolSizes = ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); static const uint32_t MAX_DS_TYPES_IN_LAYOUT = 2; VkDescriptorSetLayoutBinding dsl_binding[MAX_DS_TYPES_IN_LAYOUT] = {}; dsl_binding[0].binding = 0; dsl_binding[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding[0].descriptorCount = 5; dsl_binding[0].stageFlags = VK_SHADER_STAGE_ALL; dsl_binding[0].pImmutableSamplers = NULL; // Create layout identical to set0 layout but w/ different stageFlags VkDescriptorSetLayoutBinding dsl_fs_stage_only = {}; dsl_fs_stage_only.binding = 0; dsl_fs_stage_only.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_fs_stage_only.descriptorCount = 5; dsl_fs_stage_only.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; // Different stageFlags to cause error at // bind time dsl_fs_stage_only.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = dsl_binding; static const uint32_t NUM_LAYOUTS = 4; VkDescriptorSetLayout ds_layout[NUM_LAYOUTS] = {}; VkDescriptorSetLayout ds_layout_fs_only = {}; // Create 4 unique layouts for full pipelineLayout, and 1 special fs-only // layout for error case err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout[0]); ASSERT_VK_SUCCESS(err); ds_layout_ci.pBindings = &dsl_fs_stage_only; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout_fs_only); ASSERT_VK_SUCCESS(err); dsl_binding[0].binding = 0; dsl_binding[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; dsl_binding[0].descriptorCount = 2; dsl_binding[1].binding = 1; dsl_binding[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; dsl_binding[1].descriptorCount = 2; dsl_binding[1].stageFlags = VK_SHADER_STAGE_ALL; dsl_binding[1].pImmutableSamplers = NULL; ds_layout_ci.pBindings = dsl_binding; ds_layout_ci.bindingCount = 2; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout[1]); ASSERT_VK_SUCCESS(err); dsl_binding[0].binding = 0; dsl_binding[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; dsl_binding[0].descriptorCount = 5; ds_layout_ci.bindingCount = 1; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout[2]); ASSERT_VK_SUCCESS(err); dsl_binding[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; dsl_binding[0].descriptorCount = 2; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout[3]); ASSERT_VK_SUCCESS(err); static const uint32_t NUM_SETS = 4; VkDescriptorSet descriptorSet[NUM_SETS] = {}; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = NUM_LAYOUTS; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, descriptorSet); ASSERT_VK_SUCCESS(err); VkDescriptorSet ds0_fs_only = {}; alloc_info.descriptorSetCount = 1; alloc_info.pSetLayouts = &ds_layout_fs_only; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &ds0_fs_only); ASSERT_VK_SUCCESS(err); VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_ci.pNext = NULL; pipeline_layout_ci.setLayoutCount = NUM_LAYOUTS; pipeline_layout_ci.pSetLayouts = ds_layout; VkPipelineLayout pipeline_layout; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); ASSERT_VK_SUCCESS(err); // Create pipelineLayout with only one setLayout pipeline_layout_ci.setLayoutCount = 1; VkPipelineLayout single_pipe_layout; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &single_pipe_layout); ASSERT_VK_SUCCESS(err); // Create pipelineLayout with 2 descriptor setLayout at index 0 pipeline_layout_ci.pSetLayouts = &ds_layout[3]; VkPipelineLayout pipe_layout_one_desc; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipe_layout_one_desc); ASSERT_VK_SUCCESS(err); // Create pipelineLayout with 5 SAMPLER descriptor setLayout at index 0 pipeline_layout_ci.pSetLayouts = &ds_layout[2]; VkPipelineLayout pipe_layout_five_samp; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipe_layout_five_samp); ASSERT_VK_SUCCESS(err); // Create pipelineLayout with UB type, but stageFlags for FS only pipeline_layout_ci.pSetLayouts = &ds_layout_fs_only; VkPipelineLayout pipe_layout_fs_only; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipe_layout_fs_only); ASSERT_VK_SUCCESS(err); // Create pipelineLayout w/ incompatible set0 layout, but set1 is fine VkDescriptorSetLayout pl_bad_s0[2] = {}; pl_bad_s0[0] = ds_layout_fs_only; pl_bad_s0[1] = ds_layout[1]; pipeline_layout_ci.setLayoutCount = 2; pipeline_layout_ci.pSetLayouts = pl_bad_s0; VkPipelineLayout pipe_layout_bad_set0; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipe_layout_bad_set0); ASSERT_VK_SUCCESS(err); // Create a buffer to update the descriptor with uint32_t qfi = 0; VkBufferCreateInfo buffCI = {}; buffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffCI.size = 1024; buffCI.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; buffCI.queueFamilyIndexCount = 1; buffCI.pQueueFamilyIndices = &qfi; VkBuffer dyub; err = vkCreateBuffer(m_device->device(), &buffCI, NULL, &dyub); ASSERT_VK_SUCCESS(err); // Correctly update descriptor to avoid "NOT_UPDATED" error static const uint32_t NUM_BUFFS = 5; VkDescriptorBufferInfo buffInfo[NUM_BUFFS] = {}; for (uint32_t i = 0; i < NUM_BUFFS; ++i) { buffInfo[i].buffer = dyub; buffInfo[i].offset = 0; buffInfo[i].range = 1024; } VkImage image; const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; const int32_t tex_width = 32; const int32_t tex_height = 32; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = tex_format; image_create_info.extent.width = tex_width; image_create_info.extent.height = tex_height; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.tiling = VK_IMAGE_TILING_LINEAR; image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; image_create_info.flags = 0; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image); ASSERT_VK_SUCCESS(err); VkMemoryRequirements memReqs; VkDeviceMemory imageMem; bool pass; VkMemoryAllocateInfo memAlloc = {}; memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memAlloc.pNext = NULL; memAlloc.allocationSize = 0; memAlloc.memoryTypeIndex = 0; vkGetImageMemoryRequirements(m_device->device(), image, &memReqs); memAlloc.allocationSize = memReqs.size; pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &memAlloc, 0); ASSERT_TRUE(pass); err = vkAllocateMemory(m_device->device(), &memAlloc, NULL, &imageMem); ASSERT_VK_SUCCESS(err); err = vkBindImageMemory(m_device->device(), image, imageMem, 0); ASSERT_VK_SUCCESS(err); VkImageViewCreateInfo image_view_create_info = {}; image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; image_view_create_info.image = image; image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; image_view_create_info.format = tex_format; image_view_create_info.subresourceRange.layerCount = 1; image_view_create_info.subresourceRange.baseMipLevel = 0; image_view_create_info.subresourceRange.levelCount = 1; image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; VkImageView view; err = vkCreateImageView(m_device->device(), &image_view_create_info, NULL, &view); ASSERT_VK_SUCCESS(err); VkDescriptorImageInfo imageInfo[4] = {}; imageInfo[0].imageView = view; imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo[1].imageView = view; imageInfo[1].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo[2].imageView = view; imageInfo[2].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo[3].imageView = view; imageInfo[3].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; static const uint32_t NUM_SET_UPDATES = 3; VkWriteDescriptorSet descriptor_write[NUM_SET_UPDATES] = {}; descriptor_write[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write[0].dstSet = descriptorSet[0]; descriptor_write[0].dstBinding = 0; descriptor_write[0].descriptorCount = 5; descriptor_write[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptor_write[0].pBufferInfo = buffInfo; descriptor_write[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write[1].dstSet = descriptorSet[1]; descriptor_write[1].dstBinding = 0; descriptor_write[1].descriptorCount = 2; descriptor_write[1].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; descriptor_write[1].pImageInfo = imageInfo; descriptor_write[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write[2].dstSet = descriptorSet[1]; descriptor_write[2].dstBinding = 1; descriptor_write[2].descriptorCount = 2; descriptor_write[2].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; descriptor_write[2].pImageInfo = &imageInfo[2]; vkUpdateDescriptorSets(m_device->device(), 3, descriptor_write, 0, NULL); // Create PSO to be used for draw-time errors below char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = vec4(1);\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out vec4 x;\n" "layout(set=0) layout(binding=0) uniform foo { int x; int y; } bar;\n" "void main(){\n" " x = vec4(bar.y);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddShader(&vs); pipe.AddShader(&fs); pipe.AddColorAttachment(); pipe.CreateVKPipeline(pipe_layout_fs_only, renderPass()); BeginCommandBuffer(); vkCmdBindPipeline(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle()); // NOTE : I believe LunarG ilo driver has bug (LX#189) that requires binding // of PSO // here before binding DSs. Otherwise we assert in cmd_copy_dset_data() of // cmd_pipeline.c // due to the fact that cmd_alloc_dset_data() has not been called in // cmd_bind_graphics_pipeline() // TODO : Want to cause various binding incompatibility issues here to test // DrawState // First cause various verify_layout_compatibility() fails // Second disturb early and late sets and verify INFO msgs // verify_set_layout_compatibility fail cases: // 1. invalid VkPipelineLayout (layout) passed into vkCmdBindDescriptorSets m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, " due to: invalid VkPipelineLayout "); vkCmdBindDescriptorSets(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, (VkPipelineLayout)((size_t)0xbaadb1be), 0, 1, &descriptorSet[0], 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive correct error msg when attempting to bind " "descriptorSets with invalid VkPipelineLayout."; m_errorMonitor->DumpFailureMsgs(); } // 2. layoutIndex exceeds # of layouts in layout m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, " attempting to bind set to index 1"); vkCmdBindDescriptorSets(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, single_pipe_layout, 0, 2, &descriptorSet[0], 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive correct error msg when attempting to bind " "descriptorSet to index 1 when pipelineLayout only has index " "0."; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineLayout(m_device->device(), single_pipe_layout, NULL); // 3. Pipeline setLayout[0] has 2 descriptors, but set being bound has 5 // descriptors m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, ", but corresponding set being bound has 5 descriptors."); vkCmdBindDescriptorSets( m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_layout_one_desc, 0, 1, &descriptorSet[0], 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive correct error msg when attempting to bind " "descriptorSet w/ 5 descriptors to pipelineLayout with only " "2 descriptors."; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineLayout(m_device->device(), pipe_layout_one_desc, NULL); // 4. same # of descriptors but mismatch in type m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, " descriptor from pipelineLayout is type 'VK_DESCRIPTOR_TYPE_SAMPLER'"); vkCmdBindDescriptorSets( m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_layout_five_samp, 0, 1, &descriptorSet[0], 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive correct error msg when attempting to bind " "UNIFORM_BUFFER descriptorSet to pipelineLayout with " "overlapping SAMPLER type."; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineLayout(m_device->device(), pipe_layout_five_samp, NULL); // 5. same # of descriptors but mismatch in stageFlags m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, " descriptor from pipelineLayout has stageFlags "); vkCmdBindDescriptorSets( m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_layout_fs_only, 0, 1, &descriptorSet[0], 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive correct error msg when attempting to bind " "UNIFORM_BUFFER descriptorSet with ALL stageFlags to " "pipelineLayout with FS-only stageFlags."; m_errorMonitor->DumpFailureMsgs(); } // Cause INFO messages due to disturbing previously bound Sets // First bind sets 0 & 1 vkCmdBindDescriptorSets(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 2, &descriptorSet[0], 0, NULL); // 1. Disturb bound set0 by re-binding set1 w/ updated pipelineLayout m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, " previously bound as set #0 was disturbed "); vkCmdBindDescriptorSets( m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_layout_bad_set0, 1, 1, &descriptorSet[1], 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive correct info msg when binding Set1 w/ " "pipelineLayout that should disturb Set0."; m_errorMonitor->DumpFailureMsgs(); } vkCmdBindDescriptorSets(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 2, &descriptorSet[0], 0, NULL); // 2. Disturb set after last bound set m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, " newly bound as set #0 so set #1 and " "any subsequent sets were disturbed "); vkCmdBindDescriptorSets(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_layout_fs_only, 0, 1, &ds0_fs_only, 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive correct info msg when re-binding Set0 w/ " "pipelineLayout that should disturb Set1."; m_errorMonitor->DumpFailureMsgs(); } // Cause draw-time errors due to PSO incompatibilities // 1. Error due to not binding required set (we actually use same code as // above to disturb set0) vkCmdBindDescriptorSets(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 2, &descriptorSet[0], 0, NULL); vkCmdBindDescriptorSets( m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_layout_bad_set0, 1, 1, &descriptorSet[1], 0, NULL); m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, " uses set #0 but that set is not bound."); Draw(1, 0, 0, 0); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive correct error msg when attempting draw " "requiring Set0 but Set0 is not bound."; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineLayout(m_device->device(), pipe_layout_bad_set0, NULL); // 2. Error due to bound set not being compatible with PSO's // VkPipelineLayout (diff stageFlags in this case) vkCmdBindDescriptorSets(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 2, &descriptorSet[0], 0, NULL); m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, " bound as set #0 is not compatible with "); Draw(1, 0, 0, 0); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive correct error msg when attempted draw where " "bound Set0 layout is not compatible PSO Set0 layout."; m_errorMonitor->DumpFailureMsgs(); } // Remaining clean-up vkDestroyPipelineLayout(m_device->device(), pipe_layout_fs_only, NULL); for (uint32_t i = 0; i < NUM_LAYOUTS; ++i) { vkDestroyDescriptorSetLayout(m_device->device(), ds_layout[i], NULL); } vkDestroyDescriptorSetLayout(m_device->device(), ds_layout_fs_only, NULL); vkFreeDescriptorSets(m_device->device(), ds_pool, 1, descriptorSet); vkDestroyBuffer(m_device->device(), dyub, NULL); vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, NoBeginCommandBuffer) { m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "You must call vkBeginCommandBuffer() before this call to "); ASSERT_NO_FATAL_FAILURE(InitState()); VkCommandBufferObj commandBuffer(m_device, m_commandPool); // Call EndCommandBuffer() w/o calling BeginCommandBuffer() vkEndCommandBuffer(commandBuffer.GetBufferHandle()); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not recieve Error 'You must call vkBeginCommandBuffer() " "before this call to vkEndCommandBuffer()'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, SecondaryCommandBufferNullRenderpass) { VkResult err; VkCommandBuffer draw_cmd; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, " must specify a valid renderpass parameter."); ASSERT_NO_FATAL_FAILURE(InitState()); VkCommandBufferAllocateInfo cmd = {}; cmd.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; cmd.pNext = NULL; cmd.commandPool = m_commandPool; cmd.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; cmd.commandBufferCount = 1; err = vkAllocateCommandBuffers(m_device->device(), &cmd, &draw_cmd); ASSERT_VK_SUCCESS(err); // Force the failure by not setting the Renderpass and Framebuffer fields VkCommandBufferBeginInfo cmd_buf_info = {}; VkCommandBufferInheritanceInfo cmd_buf_hinfo = {}; cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; cmd_buf_info.pNext = NULL; cmd_buf_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; cmd_buf_info.pInheritanceInfo = &cmd_buf_hinfo; // The error should be caught by validation of the BeginCommandBuffer call vkBeginCommandBuffer(draw_cmd, &cmd_buf_info); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkBeginCommandBuffer(): Secondary " "Command Buffers (0x<ADDR>) must specify a valid renderpass " "parameter.'"; m_errorMonitor->DumpFailureMsgs(); } vkFreeCommandBuffers(m_device->device(), m_commandPool, 1, &draw_cmd); } TEST_F(VkLayerTest, CommandBufferResetErrors) { // Cause error due to Begin while recording CB // Then cause 2 errors for attempting to reset CB w/o having // VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT set for the pool from // which CBs were allocated. Note that this bit is off by default. m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Cannot call Begin on CB"); ASSERT_NO_FATAL_FAILURE(InitState()); // Calls AllocateCommandBuffers VkCommandBufferObj commandBuffer(m_device, m_commandPool); // Force the failure by setting the Renderpass and Framebuffer fields with // (fake) data VkCommandBufferBeginInfo cmd_buf_info = {}; VkCommandBufferInheritanceInfo cmd_buf_hinfo = {}; cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; cmd_buf_info.pNext = NULL; cmd_buf_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; cmd_buf_info.pInheritanceInfo = &cmd_buf_hinfo; // Begin CB to transition to recording state vkBeginCommandBuffer(commandBuffer.GetBufferHandle(), &cmd_buf_info); // Can't re-begin. This should trigger error vkBeginCommandBuffer(commandBuffer.GetBufferHandle(), &cmd_buf_info); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Cannot call Begin on CB (0x<ADDR>) " "in the RECORDING state...'"; m_errorMonitor->DumpFailureMsgs(); } m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Attempt to reset command buffer "); VkCommandBufferResetFlags flags = 0; // Don't care about flags for this test // Reset attempt will trigger error due to incorrect CommandPool state vkResetCommandBuffer(commandBuffer.GetBufferHandle(), flags); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Attempt to reset command buffer " "(0x<ADDR>) created from command pool...'"; m_errorMonitor->DumpFailureMsgs(); } m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, " attempts to implicitly reset cmdBuffer created from "); // Transition CB to RECORDED state vkEndCommandBuffer(commandBuffer.GetBufferHandle()); // Now attempting to Begin will implicitly reset, which triggers error vkBeginCommandBuffer(commandBuffer.GetBufferHandle(), &cmd_buf_info); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Call to vkBeginCommandBuffer() on " "command buffer (0x<ADDR>) attempts to implicitly reset...'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, InvalidPipelineCreateState) { // Attempt to Create Gfx Pipeline w/o a VS VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Invalid Pipeline CreateInfo State: Vtx Shader required"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_ci.setLayoutCount = 1; pipeline_layout_ci.pSetLayouts = &ds_layout; VkPipelineLayout pipeline_layout; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); ASSERT_VK_SUCCESS(err); VkViewport vp = {}; // Just need dummy vp to point to VkRect2D sc = {}; // dummy scissor to point to VkPipelineViewportStateCreateInfo vp_state_ci = {}; vp_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; vp_state_ci.scissorCount = 1; vp_state_ci.pScissors = ≻ vp_state_ci.viewportCount = 1; vp_state_ci.pViewports = &vp; VkPipelineRasterizationStateCreateInfo rs_state_ci = {}; rs_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rs_state_ci.polygonMode = VK_POLYGON_MODE_FILL; rs_state_ci.cullMode = VK_CULL_MODE_BACK_BIT; rs_state_ci.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; rs_state_ci.depthClampEnable = VK_FALSE; rs_state_ci.rasterizerDiscardEnable = VK_FALSE; rs_state_ci.depthBiasEnable = VK_FALSE; VkGraphicsPipelineCreateInfo gp_ci = {}; gp_ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; gp_ci.pViewportState = &vp_state_ci; gp_ci.pRasterizationState = &rs_state_ci; gp_ci.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; gp_ci.layout = pipeline_layout; gp_ci.renderPass = renderPass(); VkPipelineCacheCreateInfo pc_ci = {}; pc_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; pc_ci.initialDataSize = 0; pc_ci.pInitialData = 0; VkPipeline pipeline; VkPipelineCache pipelineCache; err = vkCreatePipelineCache(m_device->device(), &pc_ci, NULL, &pipelineCache); ASSERT_VK_SUCCESS(err); err = vkCreateGraphicsPipelines(m_device->device(), pipelineCache, 1, &gp_ci, NULL, &pipeline); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Invalid Pipeline CreateInfo State: " "Vtx Shader required'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineCache(m_device->device(), pipelineCache, NULL); vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } /*// TODO : This test should be good, but needs Tess support in compiler to run TEST_F(VkLayerTest, InvalidPatchControlPoints) { // Attempt to Create Gfx Pipeline w/o a VS VkResult err; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Invalid Pipeline CreateInfo State: VK_PRIMITIVE_TOPOLOGY_PATCH primitive "); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), VK_DESCRIPTOR_POOL_USAGE_NON_FREE, 1, &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; err = vkAllocateDescriptorSets(m_device->device(), ds_pool, VK_DESCRIPTOR_SET_USAGE_NON_FREE, 1, &ds_layout, &descriptorSet); ASSERT_VK_SUCCESS(err); VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_ci.pNext = NULL; pipeline_layout_ci.setLayoutCount = 1; pipeline_layout_ci.pSetLayouts = &ds_layout; VkPipelineLayout pipeline_layout; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); ASSERT_VK_SUCCESS(err); VkPipelineShaderStageCreateInfo shaderStages[3]; memset(&shaderStages, 0, 3 * sizeof(VkPipelineShaderStageCreateInfo)); VkShaderObj vs(m_device,bindStateVertShaderText,VK_SHADER_STAGE_VERTEX_BIT, this); // Just using VS txt for Tess shaders as we don't care about functionality VkShaderObj tc(m_device,bindStateVertShaderText,VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, this); VkShaderObj te(m_device,bindStateVertShaderText,VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, this); shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; shaderStages[0].shader = vs.handle(); shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shaderStages[1].stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; shaderStages[1].shader = tc.handle(); shaderStages[2].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shaderStages[2].stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; shaderStages[2].shader = te.handle(); VkPipelineInputAssemblyStateCreateInfo iaCI = {}; iaCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; iaCI.topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; VkPipelineTessellationStateCreateInfo tsCI = {}; tsCI.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; tsCI.patchControlPoints = 0; // This will cause an error VkGraphicsPipelineCreateInfo gp_ci = {}; gp_ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; gp_ci.pNext = NULL; gp_ci.stageCount = 3; gp_ci.pStages = shaderStages; gp_ci.pVertexInputState = NULL; gp_ci.pInputAssemblyState = &iaCI; gp_ci.pTessellationState = &tsCI; gp_ci.pViewportState = NULL; gp_ci.pRasterizationState = NULL; gp_ci.pMultisampleState = NULL; gp_ci.pDepthStencilState = NULL; gp_ci.pColorBlendState = NULL; gp_ci.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; gp_ci.layout = pipeline_layout; gp_ci.renderPass = renderPass(); VkPipelineCacheCreateInfo pc_ci = {}; pc_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; pc_ci.pNext = NULL; pc_ci.initialSize = 0; pc_ci.initialData = 0; pc_ci.maxSize = 0; VkPipeline pipeline; VkPipelineCache pipelineCache; err = vkCreatePipelineCache(m_device->device(), &pc_ci, NULL, &pipelineCache); ASSERT_VK_SUCCESS(err); err = vkCreateGraphicsPipelines(m_device->device(), pipelineCache, 1, &gp_ci, NULL, &pipeline); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Invalid Pipeline CreateInfo State: VK_PRIMITIVE_TOPOLOGY_PATCH primitive...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineCache(m_device->device(), pipelineCache, NULL); vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } */ // Set scissor and viewport counts to different numbers TEST_F(VkLayerTest, PSOViewportScissorCountMismatch) { // Attempt to Create Gfx Pipeline w/o a VS VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Gfx Pipeline viewport count (1) must match scissor count (0)."); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_ci.setLayoutCount = 1; pipeline_layout_ci.pSetLayouts = &ds_layout; VkPipelineLayout pipeline_layout; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); ASSERT_VK_SUCCESS(err); VkViewport vp = {}; // Just need dummy vp to point to VkPipelineViewportStateCreateInfo vp_state_ci = {}; vp_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; vp_state_ci.scissorCount = 0; vp_state_ci.viewportCount = 1; // Count mismatch should cause error vp_state_ci.pViewports = &vp; VkPipelineRasterizationStateCreateInfo rs_state_ci = {}; rs_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rs_state_ci.polygonMode = VK_POLYGON_MODE_FILL; rs_state_ci.cullMode = VK_CULL_MODE_BACK_BIT; rs_state_ci.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; rs_state_ci.depthClampEnable = VK_FALSE; rs_state_ci.rasterizerDiscardEnable = VK_FALSE; rs_state_ci.depthBiasEnable = VK_FALSE; VkPipelineShaderStageCreateInfo shaderStages[2]; memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo)); VkShaderObj vs(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, bindStateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this); // TODO - We shouldn't need a fragment shader // but add it to be able to run on more devices shaderStages[0] = vs.GetStageCreateInfo(); shaderStages[1] = fs.GetStageCreateInfo(); VkGraphicsPipelineCreateInfo gp_ci = {}; gp_ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; gp_ci.stageCount = 2; gp_ci.pStages = shaderStages; gp_ci.pViewportState = &vp_state_ci; gp_ci.pRasterizationState = &rs_state_ci; gp_ci.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; gp_ci.layout = pipeline_layout; gp_ci.renderPass = renderPass(); VkPipelineCacheCreateInfo pc_ci = {}; pc_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; VkPipeline pipeline; VkPipelineCache pipelineCache; err = vkCreatePipelineCache(m_device->device(), &pc_ci, NULL, &pipelineCache); ASSERT_VK_SUCCESS(err); err = vkCreateGraphicsPipelines(m_device->device(), pipelineCache, 1, &gp_ci, NULL, &pipeline); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Gfx Pipeline viewport count (1) must " "match scissor count (0).'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineCache(m_device->device(), pipelineCache, NULL); vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } // Don't set viewport state in PSO. This is an error b/c we always need this // state // for the counts even if the data is going to be set dynamically. TEST_F(VkLayerTest, PSOViewportStateNotSet) { // Attempt to Create Gfx Pipeline w/o a VS VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Gfx Pipeline pViewportState is null. Even if "); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_ci.setLayoutCount = 1; pipeline_layout_ci.pSetLayouts = &ds_layout; VkPipelineLayout pipeline_layout; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); ASSERT_VK_SUCCESS(err); VkDynamicState sc_state = VK_DYNAMIC_STATE_SCISSOR; // Set scissor as dynamic to avoid second error VkPipelineDynamicStateCreateInfo dyn_state_ci = {}; dyn_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dyn_state_ci.dynamicStateCount = 1; dyn_state_ci.pDynamicStates = &sc_state; VkPipelineShaderStageCreateInfo shaderStages[2]; memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo)); VkShaderObj vs(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, bindStateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this); // TODO - We shouldn't need a fragment shader // but add it to be able to run on more devices shaderStages[0] = vs.GetStageCreateInfo(); shaderStages[1] = fs.GetStageCreateInfo(); VkPipelineRasterizationStateCreateInfo rs_state_ci = {}; rs_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rs_state_ci.polygonMode = VK_POLYGON_MODE_FILL; rs_state_ci.cullMode = VK_CULL_MODE_BACK_BIT; rs_state_ci.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; rs_state_ci.depthClampEnable = VK_FALSE; rs_state_ci.rasterizerDiscardEnable = VK_FALSE; rs_state_ci.depthBiasEnable = VK_FALSE; VkGraphicsPipelineCreateInfo gp_ci = {}; gp_ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; gp_ci.stageCount = 2; gp_ci.pStages = shaderStages; gp_ci.pRasterizationState = &rs_state_ci; gp_ci.pViewportState = NULL; // Not setting VP state w/o dynamic vp state // should cause validation error gp_ci.pDynamicState = &dyn_state_ci; gp_ci.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; gp_ci.layout = pipeline_layout; gp_ci.renderPass = renderPass(); VkPipelineCacheCreateInfo pc_ci = {}; pc_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; VkPipeline pipeline; VkPipelineCache pipelineCache; err = vkCreatePipelineCache(m_device->device(), &pc_ci, NULL, &pipelineCache); ASSERT_VK_SUCCESS(err); err = vkCreateGraphicsPipelines(m_device->device(), pipelineCache, 1, &gp_ci, NULL, &pipeline); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Gfx Pipeline pViewportState is null. " "Even if...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineCache(m_device->device(), pipelineCache, NULL); vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } // Create PSO w/o non-zero viewportCount but no viewport data // Then run second test where dynamic scissor count doesn't match PSO scissor // count TEST_F(VkLayerTest, PSOViewportCountWithoutDataAndDynScissorMismatch) { VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Gfx Pipeline viewportCount is 1, but pViewports is NULL. "); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_ci.setLayoutCount = 1; pipeline_layout_ci.pSetLayouts = &ds_layout; VkPipelineLayout pipeline_layout; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); ASSERT_VK_SUCCESS(err); VkPipelineViewportStateCreateInfo vp_state_ci = {}; vp_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; vp_state_ci.viewportCount = 1; vp_state_ci.pViewports = NULL; // Null vp w/ count of 1 should cause error vp_state_ci.scissorCount = 1; vp_state_ci.pScissors = NULL; // Scissor is dynamic (below) so this won't cause error VkDynamicState sc_state = VK_DYNAMIC_STATE_SCISSOR; // Set scissor as dynamic to avoid that error VkPipelineDynamicStateCreateInfo dyn_state_ci = {}; dyn_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dyn_state_ci.dynamicStateCount = 1; dyn_state_ci.pDynamicStates = &sc_state; VkPipelineShaderStageCreateInfo shaderStages[2]; memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo)); VkShaderObj vs(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, bindStateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this); // TODO - We shouldn't need a fragment shader // but add it to be able to run on more devices shaderStages[0] = vs.GetStageCreateInfo(); shaderStages[1] = fs.GetStageCreateInfo(); VkPipelineVertexInputStateCreateInfo vi_ci = {}; vi_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vi_ci.pNext = nullptr; vi_ci.vertexBindingDescriptionCount = 0; vi_ci.pVertexBindingDescriptions = nullptr; vi_ci.vertexAttributeDescriptionCount = 0; vi_ci.pVertexAttributeDescriptions = nullptr; VkPipelineInputAssemblyStateCreateInfo ia_ci = {}; ia_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; ia_ci.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; VkPipelineRasterizationStateCreateInfo rs_ci = {}; rs_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rs_ci.pNext = nullptr; VkPipelineColorBlendStateCreateInfo cb_ci = {}; cb_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; cb_ci.pNext = nullptr; VkGraphicsPipelineCreateInfo gp_ci = {}; gp_ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; gp_ci.stageCount = 2; gp_ci.pStages = shaderStages; gp_ci.pVertexInputState = &vi_ci; gp_ci.pInputAssemblyState = &ia_ci; gp_ci.pViewportState = &vp_state_ci; gp_ci.pRasterizationState = &rs_ci; gp_ci.pColorBlendState = &cb_ci; gp_ci.pDynamicState = &dyn_state_ci; gp_ci.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; gp_ci.layout = pipeline_layout; gp_ci.renderPass = renderPass(); VkPipelineCacheCreateInfo pc_ci = {}; pc_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; VkPipeline pipeline; VkPipelineCache pipelineCache; err = vkCreatePipelineCache(m_device->device(), &pc_ci, NULL, &pipelineCache); ASSERT_VK_SUCCESS(err); err = vkCreateGraphicsPipelines(m_device->device(), pipelineCache, 1, &gp_ci, NULL, &pipeline); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not recieve Error 'Gfx Pipeline viewportCount is 1, but " "pViewports is NULL...'"; m_errorMonitor->DumpFailureMsgs(); } // Now hit second fail case where we set scissor w/ different count than PSO // First need to successfully create the PSO from above by setting // pViewports m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Dynamic scissorCount from vkCmdSetScissor() is 2, but PSO " "scissorCount is 1. These counts must match."); VkViewport vp = {}; // Just need dummy vp to point to vp_state_ci.pViewports = &vp; err = vkCreateGraphicsPipelines(m_device->device(), pipelineCache, 1, &gp_ci, NULL, &pipeline); ASSERT_VK_SUCCESS(err); BeginCommandBuffer(); vkCmdBindPipeline(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); VkRect2D scissors[2] = {}; // don't care about data // Count of 2 doesn't match PSO count of 1 vkCmdSetScissor(m_commandBuffer->GetBufferHandle(), 0, 2, scissors); Draw(1, 0, 0, 0); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Dynamic scissorCount from " "vkCmdSetScissor() is 2, but PSO scissorCount is 1...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineCache(m_device->device(), pipelineCache, NULL); vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } // Create PSO w/o non-zero scissorCount but no scissor data // Then run second test where dynamic viewportCount doesn't match PSO // viewportCount TEST_F(VkLayerTest, PSOScissorCountWithoutDataAndDynViewportMismatch) { VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Gfx Pipeline scissorCount is 1, but pScissors is NULL. "); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_ci.setLayoutCount = 1; pipeline_layout_ci.pSetLayouts = &ds_layout; VkPipelineLayout pipeline_layout; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); ASSERT_VK_SUCCESS(err); VkPipelineViewportStateCreateInfo vp_state_ci = {}; vp_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; vp_state_ci.scissorCount = 1; vp_state_ci.pScissors = NULL; // Null scissor w/ count of 1 should cause error vp_state_ci.viewportCount = 1; vp_state_ci.pViewports = NULL; // vp is dynamic (below) so this won't cause error VkDynamicState vp_state = VK_DYNAMIC_STATE_VIEWPORT; // Set scissor as dynamic to avoid that error VkPipelineDynamicStateCreateInfo dyn_state_ci = {}; dyn_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dyn_state_ci.dynamicStateCount = 1; dyn_state_ci.pDynamicStates = &vp_state; VkPipelineShaderStageCreateInfo shaderStages[2]; memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo)); VkShaderObj vs(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, bindStateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this); // TODO - We shouldn't need a fragment shader // but add it to be able to run on more devices shaderStages[0] = vs.GetStageCreateInfo(); shaderStages[1] = fs.GetStageCreateInfo(); VkPipelineVertexInputStateCreateInfo vi_ci = {}; vi_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vi_ci.pNext = nullptr; vi_ci.vertexBindingDescriptionCount = 0; vi_ci.pVertexBindingDescriptions = nullptr; vi_ci.vertexAttributeDescriptionCount = 0; vi_ci.pVertexAttributeDescriptions = nullptr; VkPipelineInputAssemblyStateCreateInfo ia_ci = {}; ia_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; ia_ci.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; VkPipelineRasterizationStateCreateInfo rs_ci = {}; rs_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rs_ci.pNext = nullptr; VkPipelineColorBlendStateCreateInfo cb_ci = {}; cb_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; cb_ci.pNext = nullptr; VkGraphicsPipelineCreateInfo gp_ci = {}; gp_ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; gp_ci.stageCount = 2; gp_ci.pStages = shaderStages; gp_ci.pVertexInputState = &vi_ci; gp_ci.pInputAssemblyState = &ia_ci; gp_ci.pViewportState = &vp_state_ci; gp_ci.pRasterizationState = &rs_ci; gp_ci.pColorBlendState = &cb_ci; gp_ci.pDynamicState = &dyn_state_ci; gp_ci.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; gp_ci.layout = pipeline_layout; gp_ci.renderPass = renderPass(); VkPipelineCacheCreateInfo pc_ci = {}; pc_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; VkPipeline pipeline; VkPipelineCache pipelineCache; err = vkCreatePipelineCache(m_device->device(), &pc_ci, NULL, &pipelineCache); ASSERT_VK_SUCCESS(err); err = vkCreateGraphicsPipelines(m_device->device(), pipelineCache, 1, &gp_ci, NULL, &pipeline); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not recieve Error 'Gfx Pipeline scissorCount is 1, but " "pScissors is NULL...'"; m_errorMonitor->DumpFailureMsgs(); } // Now hit second fail case where we set scissor w/ different count than PSO // First need to successfully create the PSO from above by setting // pViewports m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Dynamic viewportCount from vkCmdSetViewport() is 2, but PSO " "viewportCount is 1. These counts must match."); VkRect2D sc = {}; // Just need dummy vp to point to vp_state_ci.pScissors = ≻ err = vkCreateGraphicsPipelines(m_device->device(), pipelineCache, 1, &gp_ci, NULL, &pipeline); ASSERT_VK_SUCCESS(err); BeginCommandBuffer(); vkCmdBindPipeline(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); VkViewport viewports[2] = {}; // don't care about data // Count of 2 doesn't match PSO count of 1 vkCmdSetViewport(m_commandBuffer->GetBufferHandle(), 0, 2, viewports); Draw(1, 0, 0, 0); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Dynamic viewportCount from " "vkCmdSetViewport() is 2, but PSO viewportCount is 1...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineCache(m_device->device(), pipelineCache, NULL); vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, NullRenderPass) { // Bind a NULL RenderPass m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "You cannot use a NULL RenderPass object in vkCmdBeginRenderPass()"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); BeginCommandBuffer(); // Don't care about RenderPass handle b/c error should be flagged before // that vkCmdBeginRenderPass(m_commandBuffer->GetBufferHandle(), NULL, VK_SUBPASS_CONTENTS_INLINE); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'You cannot use a NULL RenderPass " "object in vkCmdBeginRenderPass()'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, RenderPassWithinRenderPass) { // Bind a BeginRenderPass within an active RenderPass m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "It is invalid to issue this call inside an active render pass"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); BeginCommandBuffer(); // Just create a dummy Renderpass that's non-NULL so we can get to the // proper error VkRenderPassBeginInfo rp_begin = {}; rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; rp_begin.pNext = NULL; rp_begin.renderPass = renderPass(); rp_begin.framebuffer = framebuffer(); vkCmdBeginRenderPass(m_commandBuffer->GetBufferHandle(), &rp_begin, VK_SUBPASS_CONTENTS_INLINE); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'It is invalid to issue this call " "inside an active render pass...'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, FillBufferWithinRenderPass) { // Call CmdFillBuffer within an active renderpass m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "It is invalid to issue this call inside an active render pass"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); // Renderpass is started here BeginCommandBuffer(); VkMemoryPropertyFlags reqs = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; vk_testing::Buffer dstBuffer; dstBuffer.init_as_dst(*m_device, (VkDeviceSize)1024, reqs); m_commandBuffer->FillBuffer(dstBuffer.handle(), 0, 4, 0x11111111); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'It is invalid to issue this call " "inside an active render pass...'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, UpdateBufferWithinRenderPass) { // Call CmdUpdateBuffer within an active renderpass m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "It is invalid to issue this call inside an active render pass"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); // Renderpass is started here BeginCommandBuffer(); VkMemoryPropertyFlags reqs = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; vk_testing::Buffer dstBuffer; dstBuffer.init_as_dst(*m_device, (VkDeviceSize)1024, reqs); VkDeviceSize dstOffset = 0; VkDeviceSize dataSize = 1024; const uint32_t *pData = NULL; vkCmdUpdateBuffer(m_commandBuffer->GetBufferHandle(), dstBuffer.handle(), dstOffset, dataSize, pData); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'It is invalid to issue this call " "inside an active render pass...'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, ClearColorImageWithinRenderPass) { // Call CmdClearColorImage within an active RenderPass m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "It is invalid to issue this call inside an active render pass"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); // Renderpass is started here BeginCommandBuffer(); VkClearColorValue clear_color; memset(clear_color.uint32, 0, sizeof(uint32_t) * 4); VkMemoryPropertyFlags reqs = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; const int32_t tex_width = 32; const int32_t tex_height = 32; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = tex_format; image_create_info.extent.width = tex_width; image_create_info.extent.height = tex_height; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.tiling = VK_IMAGE_TILING_LINEAR; image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; vk_testing::Image dstImage; dstImage.init(*m_device, (const VkImageCreateInfo &)image_create_info, reqs); const VkImageSubresourceRange range = vk_testing::Image::subresource_range( image_create_info, VK_IMAGE_ASPECT_COLOR_BIT); vkCmdClearColorImage(m_commandBuffer->GetBufferHandle(), dstImage.handle(), VK_IMAGE_LAYOUT_GENERAL, &clear_color, 1, &range); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'It is invalid to issue this call " "inside an active render pass...'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, ClearDepthStencilImageWithinRenderPass) { // Call CmdClearDepthStencilImage within an active RenderPass m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "It is invalid to issue this call inside an active render pass"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); // Renderpass is started here BeginCommandBuffer(); VkClearDepthStencilValue clear_value = {0}; VkMemoryPropertyFlags reqs = 0; VkImageCreateInfo image_create_info = vk_testing::Image::create_info(); image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = VK_FORMAT_D24_UNORM_S8_UINT; image_create_info.extent.width = 64; image_create_info.extent.height = 64; image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; image_create_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; vk_testing::Image dstImage; dstImage.init(*m_device, (const VkImageCreateInfo &)image_create_info, reqs); const VkImageSubresourceRange range = vk_testing::Image::subresource_range( image_create_info, VK_IMAGE_ASPECT_DEPTH_BIT); vkCmdClearDepthStencilImage( m_commandBuffer->GetBufferHandle(), dstImage.handle(), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, &clear_value, 1, &range); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'It is invalid to issue this call " "inside an active render pass...'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, ClearColorAttachmentsOutsideRenderPass) { // Call CmdClearAttachmentss outside of an active RenderPass VkResult err; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdClearAttachments: This call " "must be issued inside an active " "render pass"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); // Start no RenderPass err = m_commandBuffer->BeginCommandBuffer(); ASSERT_VK_SUCCESS(err); VkClearAttachment color_attachment; color_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; color_attachment.clearValue.color.float32[0] = 0; color_attachment.clearValue.color.float32[1] = 0; color_attachment.clearValue.color.float32[2] = 0; color_attachment.clearValue.color.float32[3] = 0; color_attachment.colorAttachment = 0; VkClearRect clear_rect = {{{0, 0}, {32, 32}}}; vkCmdClearAttachments(m_commandBuffer->GetBufferHandle(), 1, &color_attachment, 1, &clear_rect); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCmdClearAttachments: This call " "must be issued inside an active render pass.'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, InvalidDynamicStateObject) { // Create a valid cmd buffer // call vkCmdBindDynamicStateObject w/ false DS Obj // TODO : Simple check for bad object should be added to ObjectTracker to // catch this case // The DS check for this is after driver has been called to validate DS // internal data struct } TEST_F(VkLayerTest, IdxBufferAlignmentError) { // Bind a BeginRenderPass within an active RenderPass VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdBindIndexBuffer() offset (0x7) does not fall on "); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); uint32_t qfi = 0; VkBufferCreateInfo buffCI = {}; buffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffCI.size = 1024; buffCI.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; buffCI.queueFamilyIndexCount = 1; buffCI.pQueueFamilyIndices = &qfi; VkBuffer ib; err = vkCreateBuffer(m_device->device(), &buffCI, NULL, &ib); ASSERT_VK_SUCCESS(err); BeginCommandBuffer(); ASSERT_VK_SUCCESS(err); // vkCmdBindPipeline(m_commandBuffer->GetBufferHandle(), // VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle()); // Should error before calling to driver so don't care about actual data vkCmdBindIndexBuffer(m_commandBuffer->GetBufferHandle(), ib, 7, VK_INDEX_TYPE_UINT16); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCmdBindIndexBuffer() offset (0x7) " "does not fall on ...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyBuffer(m_device->device(), ib, NULL); } TEST_F(VkLayerTest, InvalidQueueFamilyIndex) { // Create an out-of-range queueFamilyIndex m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCreateBuffer has QueueFamilyIndex greater than"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkBufferCreateInfo buffCI = {}; buffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffCI.size = 1024; buffCI.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; buffCI.queueFamilyIndexCount = 1; // Introduce failure by specifying invalid queue_family_index uint32_t qfi = 777; buffCI.pQueueFamilyIndices = &qfi; VkBuffer ib; vkCreateBuffer(m_device->device(), &buffCI, NULL, &ib); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCreateBuffer() has " "QueueFamilyIndex greater than...'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, ExecuteCommandsPrimaryCB) { // Attempt vkCmdExecuteCommands w/ a primary cmd buffer (should only be // secondary) m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdExecuteCommands() called w/ Primary Cmd Buffer "); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); BeginCommandBuffer(); // ASSERT_VK_SUCCESS(err); VkCommandBuffer primCB = m_commandBuffer->GetBufferHandle(); vkCmdExecuteCommands(m_commandBuffer->GetBufferHandle(), 1, &primCB); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCmdExecuteCommands() called w/ " "Primary Cmd Buffer '"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, DSTypeMismatch) { // Create DS w/ layout of one type and attempt Update w/ mis-matched type VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Write descriptor update has descriptor " "type VK_DESCRIPTOR_TYPE_SAMPLER that " "does not match "); ASSERT_NO_FATAL_FAILURE(InitState()); // VkDescriptorSetObj descriptorSet(m_device); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkSamplerCreateInfo sampler_ci = {}; sampler_ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; sampler_ci.pNext = NULL; sampler_ci.magFilter = VK_FILTER_NEAREST; sampler_ci.minFilter = VK_FILTER_NEAREST; sampler_ci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; sampler_ci.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.mipLodBias = 1.0; sampler_ci.anisotropyEnable = VK_FALSE; sampler_ci.maxAnisotropy = 1; sampler_ci.compareEnable = VK_FALSE; sampler_ci.compareOp = VK_COMPARE_OP_NEVER; sampler_ci.minLod = 1.0; sampler_ci.maxLod = 1.0; sampler_ci.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; sampler_ci.unnormalizedCoordinates = VK_FALSE; VkSampler sampler; err = vkCreateSampler(m_device->device(), &sampler_ci, NULL, &sampler); ASSERT_VK_SUCCESS(err); VkDescriptorImageInfo info = {}; info.sampler = sampler; VkWriteDescriptorSet descriptor_write; memset(&descriptor_write, 0, sizeof(descriptor_write)); descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write.dstSet = descriptorSet; descriptor_write.descriptorCount = 1; // This is a mismatched type for the layout which expects BUFFER descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; descriptor_write.pImageInfo = &info; vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Write descriptor update has " "descriptor type VK_DESCRIPTOR_TYPE_SAMPLER that does not " "match...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroySampler(m_device->device(), sampler, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, DSUpdateOutOfBounds) { // For overlapping Update, have arrayIndex exceed that of layout VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Descriptor update type of " "VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET " "is out of bounds for matching binding"); ASSERT_NO_FATAL_FAILURE(InitState()); // VkDescriptorSetObj descriptorSet(m_device); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkSamplerCreateInfo sampler_ci = {}; sampler_ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; sampler_ci.pNext = NULL; sampler_ci.magFilter = VK_FILTER_NEAREST; sampler_ci.minFilter = VK_FILTER_NEAREST; sampler_ci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; sampler_ci.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.mipLodBias = 1.0; sampler_ci.anisotropyEnable = VK_FALSE; sampler_ci.maxAnisotropy = 1; sampler_ci.compareEnable = VK_FALSE; sampler_ci.compareOp = VK_COMPARE_OP_NEVER; sampler_ci.minLod = 1.0; sampler_ci.maxLod = 1.0; sampler_ci.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; sampler_ci.unnormalizedCoordinates = VK_FALSE; VkSampler sampler; err = vkCreateSampler(m_device->device(), &sampler_ci, NULL, &sampler); ASSERT_VK_SUCCESS(err); VkDescriptorImageInfo info = {}; info.sampler = sampler; VkWriteDescriptorSet descriptor_write; memset(&descriptor_write, 0, sizeof(descriptor_write)); descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write.dstSet = descriptorSet; descriptor_write.dstArrayElement = 1; /* This index out of bounds for the update */ descriptor_write.descriptorCount = 1; // This is the wrong type, but out of bounds will be flagged first descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; descriptor_write.pImageInfo = &info; vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Descriptor update type of " "VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET is out of bounds for " "matching binding...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroySampler(m_device->device(), sampler, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, InvalidDSUpdateIndex) { // Create layout w/ count of 1 and attempt update to that layout w/ binding // index 2 VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, " does not have binding to match update binding "); ASSERT_NO_FATAL_FAILURE(InitState()); // VkDescriptorSetObj descriptorSet(m_device); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkSamplerCreateInfo sampler_ci = {}; sampler_ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; sampler_ci.pNext = NULL; sampler_ci.magFilter = VK_FILTER_NEAREST; sampler_ci.minFilter = VK_FILTER_NEAREST; sampler_ci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; sampler_ci.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.mipLodBias = 1.0; sampler_ci.anisotropyEnable = VK_FALSE; sampler_ci.maxAnisotropy = 1; sampler_ci.compareEnable = VK_FALSE; sampler_ci.compareOp = VK_COMPARE_OP_NEVER; sampler_ci.minLod = 1.0; sampler_ci.maxLod = 1.0; sampler_ci.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; sampler_ci.unnormalizedCoordinates = VK_FALSE; VkSampler sampler; err = vkCreateSampler(m_device->device(), &sampler_ci, NULL, &sampler); ASSERT_VK_SUCCESS(err); VkDescriptorImageInfo info = {}; info.sampler = sampler; VkWriteDescriptorSet descriptor_write; memset(&descriptor_write, 0, sizeof(descriptor_write)); descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write.dstSet = descriptorSet; descriptor_write.dstBinding = 2; descriptor_write.descriptorCount = 1; // This is the wrong type, but out of bounds will be flagged first descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; descriptor_write.pImageInfo = &info; vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Descriptor Set <blah> does not have " "binding to match update binding '"; m_errorMonitor->DumpFailureMsgs(); } vkDestroySampler(m_device->device(), sampler, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, InvalidDSUpdateStruct) { // Call UpdateDS w/ struct type other than valid VK_STRUCTUR_TYPE_UPDATE_* // types VkResult err; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Unexpected UPDATE struct of type "); ASSERT_NO_FATAL_FAILURE(InitState()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkSamplerCreateInfo sampler_ci = {}; sampler_ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; sampler_ci.pNext = NULL; sampler_ci.magFilter = VK_FILTER_NEAREST; sampler_ci.minFilter = VK_FILTER_NEAREST; sampler_ci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; sampler_ci.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.mipLodBias = 1.0; sampler_ci.anisotropyEnable = VK_FALSE; sampler_ci.maxAnisotropy = 1; sampler_ci.compareEnable = VK_FALSE; sampler_ci.compareOp = VK_COMPARE_OP_NEVER; sampler_ci.minLod = 1.0; sampler_ci.maxLod = 1.0; sampler_ci.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; sampler_ci.unnormalizedCoordinates = VK_FALSE; VkSampler sampler; err = vkCreateSampler(m_device->device(), &sampler_ci, NULL, &sampler); ASSERT_VK_SUCCESS(err); VkDescriptorImageInfo info = {}; info.sampler = sampler; VkWriteDescriptorSet descriptor_write; memset(&descriptor_write, 0, sizeof(descriptor_write)); descriptor_write.sType = (VkStructureType)0x99999999; /* Intentionally broken struct type */ descriptor_write.dstSet = descriptorSet; descriptor_write.descriptorCount = 1; // This is the wrong type, but out of bounds will be flagged first descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; descriptor_write.pImageInfo = &info; vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Unexpected UPDATE struct of type '"; m_errorMonitor->DumpFailureMsgs(); } vkDestroySampler(m_device->device(), sampler, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, SampleDescriptorUpdateError) { // Create a single Sampler descriptor and send it an invalid Sampler VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Attempt to update descriptor with invalid sampler 0xbaadbeef"); ASSERT_NO_FATAL_FAILURE(InitState()); // TODO : Farm Descriptor setup code to helper function(s) to reduce copied // code VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_SAMPLER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkSampler sampler = (VkSampler)((size_t)0xbaadbeef); // Sampler with invalid handle VkDescriptorImageInfo descriptor_info; memset(&descriptor_info, 0, sizeof(VkDescriptorImageInfo)); descriptor_info.sampler = sampler; VkWriteDescriptorSet descriptor_write; memset(&descriptor_write, 0, sizeof(descriptor_write)); descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write.dstSet = descriptorSet; descriptor_write.dstBinding = 0; descriptor_write.descriptorCount = 1; descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; descriptor_write.pImageInfo = &descriptor_info; vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Attempt to update descriptor with " "invalid sampler...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, ImageViewDescriptorUpdateError) { // Create a single combined Image/Sampler descriptor and send it an invalid // imageView VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Attempt to update descriptor with invalid imageView 0xbaadbeef"); ASSERT_NO_FATAL_FAILURE(InitState()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkSamplerCreateInfo sampler_ci = {}; sampler_ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; sampler_ci.pNext = NULL; sampler_ci.magFilter = VK_FILTER_NEAREST; sampler_ci.minFilter = VK_FILTER_NEAREST; sampler_ci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; sampler_ci.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.mipLodBias = 1.0; sampler_ci.anisotropyEnable = VK_FALSE; sampler_ci.maxAnisotropy = 1; sampler_ci.compareEnable = VK_FALSE; sampler_ci.compareOp = VK_COMPARE_OP_NEVER; sampler_ci.minLod = 1.0; sampler_ci.maxLod = 1.0; sampler_ci.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; sampler_ci.unnormalizedCoordinates = VK_FALSE; VkSampler sampler; err = vkCreateSampler(m_device->device(), &sampler_ci, NULL, &sampler); ASSERT_VK_SUCCESS(err); VkImageView view = (VkImageView)((size_t)0xbaadbeef); // invalid imageView object VkDescriptorImageInfo descriptor_info; memset(&descriptor_info, 0, sizeof(VkDescriptorImageInfo)); descriptor_info.sampler = sampler; descriptor_info.imageView = view; VkWriteDescriptorSet descriptor_write; memset(&descriptor_write, 0, sizeof(descriptor_write)); descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write.dstSet = descriptorSet; descriptor_write.dstBinding = 0; descriptor_write.descriptorCount = 1; descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptor_write.pImageInfo = &descriptor_info; vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Attempt to update descriptor with " "invalid imageView...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroySampler(m_device->device(), sampler, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, CopyDescriptorUpdateErrors) { // Create DS w/ layout of 2 types, write update 1 and attempt to copy-update // into the other VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Copy descriptor update index 0, update " "count #1, has src update descriptor " "type VK_DESCRIPTOR_TYPE_SAMPLER "); ASSERT_NO_FATAL_FAILURE(InitState()); // VkDescriptorSetObj descriptorSet(m_device); VkDescriptorPoolSize ds_type_count[2] = {}; ds_type_count[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count[0].descriptorCount = 1; ds_type_count[1].type = VK_DESCRIPTOR_TYPE_SAMPLER; ds_type_count[1].descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 2; ds_pool_ci.pPoolSizes = ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding[2] = {}; dsl_binding[0].binding = 0; dsl_binding[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding[0].descriptorCount = 1; dsl_binding[0].stageFlags = VK_SHADER_STAGE_ALL; dsl_binding[0].pImmutableSamplers = NULL; dsl_binding[1].binding = 1; dsl_binding[1].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; dsl_binding[1].descriptorCount = 1; dsl_binding[1].stageFlags = VK_SHADER_STAGE_ALL; dsl_binding[1].pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 2; ds_layout_ci.pBindings = dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkSamplerCreateInfo sampler_ci = {}; sampler_ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; sampler_ci.pNext = NULL; sampler_ci.magFilter = VK_FILTER_NEAREST; sampler_ci.minFilter = VK_FILTER_NEAREST; sampler_ci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; sampler_ci.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_ci.mipLodBias = 1.0; sampler_ci.anisotropyEnable = VK_FALSE; sampler_ci.maxAnisotropy = 1; sampler_ci.compareEnable = VK_FALSE; sampler_ci.compareOp = VK_COMPARE_OP_NEVER; sampler_ci.minLod = 1.0; sampler_ci.maxLod = 1.0; sampler_ci.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; sampler_ci.unnormalizedCoordinates = VK_FALSE; VkSampler sampler; err = vkCreateSampler(m_device->device(), &sampler_ci, NULL, &sampler); ASSERT_VK_SUCCESS(err); VkDescriptorImageInfo info = {}; info.sampler = sampler; VkWriteDescriptorSet descriptor_write; memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet)); descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_write.dstSet = descriptorSet; descriptor_write.dstBinding = 1; // SAMPLER binding from layout above descriptor_write.descriptorCount = 1; descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; descriptor_write.pImageInfo = &info; // This write update should succeed vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); // Now perform a copy update that fails due to type mismatch VkCopyDescriptorSet copy_ds_update; memset(©_ds_update, 0, sizeof(VkCopyDescriptorSet)); copy_ds_update.sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET; copy_ds_update.srcSet = descriptorSet; copy_ds_update.srcBinding = 1; // copy from SAMPLER binding copy_ds_update.dstSet = descriptorSet; copy_ds_update.dstBinding = 0; // ERROR : copy to UNIFORM binding copy_ds_update.descriptorCount = 1; // copy 1 descriptor vkUpdateDescriptorSets(m_device->device(), 0, NULL, 1, ©_ds_update); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Copy descriptor update index 0, " "update count #1, has src update descriptor " "type_DESCRIPTOR_TYPE_SAMPLER'"; m_errorMonitor->DumpFailureMsgs(); } // Now perform a copy update that fails due to binding out of bounds m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Copy descriptor update 0 has srcBinding 3 which is out of bounds "); memset(©_ds_update, 0, sizeof(VkCopyDescriptorSet)); copy_ds_update.sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET; copy_ds_update.srcSet = descriptorSet; copy_ds_update.srcBinding = 3; // ERROR : Invalid binding for matching layout copy_ds_update.dstSet = descriptorSet; copy_ds_update.dstBinding = 0; copy_ds_update.descriptorCount = 1; // copy 1 descriptor vkUpdateDescriptorSets(m_device->device(), 0, NULL, 1, ©_ds_update); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Copy descriptor update 0 has " "srcBinding 3 which is out of bounds...'"; m_errorMonitor->DumpFailureMsgs(); } // Now perform a copy update that fails due to binding out of bounds m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Copy descriptor src update is out of bounds for matching binding 1 "); memset(©_ds_update, 0, sizeof(VkCopyDescriptorSet)); copy_ds_update.sType = VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET; copy_ds_update.srcSet = descriptorSet; copy_ds_update.srcBinding = 1; copy_ds_update.dstSet = descriptorSet; copy_ds_update.dstBinding = 0; copy_ds_update.descriptorCount = 5; // ERROR copy 5 descriptors (out of bounds for layout) vkUpdateDescriptorSets(m_device->device(), 0, NULL, 1, ©_ds_update); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Copy descriptor src update is out of " "bounds for matching binding 1...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroySampler(m_device->device(), sampler, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, NumSamplesMismatch) { // Create CommandBuffer where MSAA samples doesn't match RenderPass // sampleCount VkResult err; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Num samples mismatch! "); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkPipelineMultisampleStateCreateInfo pipe_ms_state_ci = {}; pipe_ms_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; pipe_ms_state_ci.pNext = NULL; pipe_ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_4_BIT; pipe_ms_state_ci.sampleShadingEnable = 0; pipe_ms_state_ci.minSampleShading = 1.0; pipe_ms_state_ci.pSampleMask = NULL; VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_ci.pNext = NULL; pipeline_layout_ci.setLayoutCount = 1; pipeline_layout_ci.pSetLayouts = &ds_layout; VkPipelineLayout pipeline_layout; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); ASSERT_VK_SUCCESS(err); VkShaderObj vs(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, bindStateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this); // TODO - We shouldn't need a fragment shader // but add it to be able to run on more devices VkPipelineObj pipe(m_device); pipe.AddShader(&vs); pipe.AddShader(&fs); pipe.SetMSAA(&pipe_ms_state_ci); pipe.CreateVKPipeline(pipeline_layout, renderPass()); BeginCommandBuffer(); vkCmdBindPipeline(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle()); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not recieve Error 'Num samples mismatch!...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, ClearCmdNoDraw) { // Create CommandBuffer where we add ClearCmd for FB Color attachment prior // to issuing a Draw VkResult err; // TODO: verify that this matches layer m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, "vkCmdClearAttachments() issued on CB object "); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkPipelineMultisampleStateCreateInfo pipe_ms_state_ci = {}; pipe_ms_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; pipe_ms_state_ci.pNext = NULL; pipe_ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_4_BIT; pipe_ms_state_ci.sampleShadingEnable = 0; pipe_ms_state_ci.minSampleShading = 1.0; pipe_ms_state_ci.pSampleMask = NULL; VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_ci.pNext = NULL; pipeline_layout_ci.setLayoutCount = 1; pipeline_layout_ci.pSetLayouts = &ds_layout; VkPipelineLayout pipeline_layout; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); ASSERT_VK_SUCCESS(err); VkShaderObj vs(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this); // TODO - We shouldn't need a fragment shader but add it to be able to run // on more devices VkShaderObj fs(m_device, bindStateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddShader(&vs); pipe.AddShader(&fs); pipe.SetMSAA(&pipe_ms_state_ci); pipe.CreateVKPipeline(pipeline_layout, renderPass()); BeginCommandBuffer(); // Main thing we care about for this test is that the VkImage obj we're // clearing matches Color Attachment of FB // Also pass down other dummy params to keep driver and paramchecker happy VkClearAttachment color_attachment; color_attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; color_attachment.clearValue.color.float32[0] = 1.0; color_attachment.clearValue.color.float32[1] = 1.0; color_attachment.clearValue.color.float32[2] = 1.0; color_attachment.clearValue.color.float32[3] = 1.0; color_attachment.colorAttachment = 0; VkClearRect clear_rect = { {{0, 0}, {(uint32_t)m_width, (uint32_t)m_height}}}; vkCmdClearAttachments(m_commandBuffer->GetBufferHandle(), 1, &color_attachment, 1, &clear_rect); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCommandClearAttachments() issued " "on CB object...'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } TEST_F(VkLayerTest, VtxBufferBadIndex) { VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, "but no vertex buffers are attached to this Pipeline State Object"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitViewport()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkPipelineMultisampleStateCreateInfo pipe_ms_state_ci = {}; pipe_ms_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; pipe_ms_state_ci.pNext = NULL; pipe_ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; pipe_ms_state_ci.sampleShadingEnable = 0; pipe_ms_state_ci.minSampleShading = 1.0; pipe_ms_state_ci.pSampleMask = NULL; VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_ci.pNext = NULL; pipeline_layout_ci.setLayoutCount = 1; pipeline_layout_ci.pSetLayouts = &ds_layout; VkPipelineLayout pipeline_layout; err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); ASSERT_VK_SUCCESS(err); VkShaderObj vs(m_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, bindStateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this); // TODO - We shouldn't need a fragment shader // but add it to be able to run on more devices VkPipelineObj pipe(m_device); pipe.AddShader(&vs); pipe.AddShader(&fs); pipe.SetMSAA(&pipe_ms_state_ci); pipe.SetViewport(m_viewports); pipe.SetScissor(m_scissors); pipe.CreateVKPipeline(pipeline_layout, renderPass()); BeginCommandBuffer(); vkCmdBindPipeline(m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.handle()); // Don't care about actual data, just need to get to draw to flag error static const float vbo_data[3] = {1.f, 0.f, 1.f}; VkConstantBufferObj vbo(m_device, sizeof(vbo_data), sizeof(float), (const void *)&vbo_data); BindVertexBuffer(&vbo, (VkDeviceSize)0, 1); // VBO idx 1, but no VBO in PSO Draw(1, 0, 0, 0); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Vtx Buffer Index 0 was bound, but no " "vtx buffers are attached to PSO.'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } #endif // DRAW_STATE_TESTS #if THREADING_TESTS #if GTEST_IS_THREADSAFE struct thread_data_struct { VkCommandBuffer commandBuffer; VkEvent event; bool bailout; }; extern "C" void *AddToCommandBuffer(void *arg) { struct thread_data_struct *data = (struct thread_data_struct *)arg; for (int i = 0; i < 10000; i++) { vkCmdSetEvent(data->commandBuffer, data->event, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); if (data->bailout) { break; } } return NULL; } TEST_F(VkLayerTest, ThreadCommandBufferCollision) { test_platform_thread thread; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "THREADING ERROR"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitViewport()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); // Calls AllocateCommandBuffers VkCommandBufferObj commandBuffer(m_device, m_commandPool); // Avoid creating RenderPass commandBuffer.BeginCommandBuffer(); VkEventCreateInfo event_info; VkEvent event; VkResult err; memset(&event_info, 0, sizeof(event_info)); event_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; err = vkCreateEvent(device(), &event_info, NULL, &event); ASSERT_VK_SUCCESS(err); err = vkResetEvent(device(), event); ASSERT_VK_SUCCESS(err); struct thread_data_struct data; data.commandBuffer = commandBuffer.GetBufferHandle(); data.event = event; data.bailout = false; m_errorMonitor->SetBailout(&data.bailout); // Add many entries to command buffer from another thread. test_platform_thread_create(&thread, AddToCommandBuffer, (void *)&data); // Add many entries to command buffer from this thread at the same time. AddToCommandBuffer(&data); test_platform_thread_join(thread, NULL); commandBuffer.EndCommandBuffer(); m_errorMonitor->SetBailout(NULL); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'THREADING ERROR' from using one " "VkCommandBufferObj in two threads"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyEvent(device(), event, NULL); } #endif // GTEST_IS_THREADSAFE #endif // THREADING_TESTS #if SHADER_CHECKER_TESTS TEST_F(VkLayerTest, InvalidSPIRVCodeSize) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Shader is not SPIR-V"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkShaderModule module; VkShaderModuleCreateInfo moduleCreateInfo; struct icd_spv_header spv; spv.magic = ICD_SPV_MAGIC; spv.version = ICD_SPV_VERSION; spv.gen_magic = 0; moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; moduleCreateInfo.pNext = NULL; moduleCreateInfo.pCode = (const uint32_t *)&spv; moduleCreateInfo.codeSize = 4; moduleCreateInfo.flags = 0; vkCreateShaderModule(m_device->device(), &moduleCreateInfo, NULL, &module); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not recieive Error 'Shader is not SPIR-V'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, InvalidSPIRVMagic) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Shader is not SPIR-V"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkShaderModule module; VkShaderModuleCreateInfo moduleCreateInfo; struct icd_spv_header spv; spv.magic = ~ICD_SPV_MAGIC; spv.version = ICD_SPV_VERSION; spv.gen_magic = 0; moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; moduleCreateInfo.pNext = NULL; moduleCreateInfo.pCode = (const uint32_t *)&spv; moduleCreateInfo.codeSize = sizeof(spv) + 10; moduleCreateInfo.flags = 0; vkCreateShaderModule(m_device->device(), &moduleCreateInfo, NULL, &module); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not recieive Error 'Shader is not SPIR-V'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, InvalidSPIRVVersion) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Shader is not SPIR-V"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkShaderModule module; VkShaderModuleCreateInfo moduleCreateInfo; struct icd_spv_header spv; spv.magic = ICD_SPV_MAGIC; spv.version = ~ICD_SPV_VERSION; spv.gen_magic = 0; moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; moduleCreateInfo.pNext = NULL; moduleCreateInfo.pCode = (const uint32_t *)&spv; moduleCreateInfo.codeSize = sizeof(spv) + 10; moduleCreateInfo.flags = 0; vkCreateShaderModule(m_device->device(), &moduleCreateInfo, NULL, &module); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not recieive Error 'Shader is not SPIR-V'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CreatePipelineVertexOutputNotConsumed) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, "not consumed by fragment shader"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out float x;\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = vec4(1);\n" " x = 0;\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out vec4 color;\n" "void main(){\n" " color = vec4(1);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddColorAttachment(); pipe.AddShader(&vs); pipe.AddShader(&fs); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Warning 'not consumed by fragment shader'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CreatePipelineFragmentInputNotProvided) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "not written by vertex shader"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = vec4(1);\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) in float x;\n" "layout(location=0) out vec4 color;\n" "void main(){\n" " color = vec4(x);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddColorAttachment(); pipe.AddShader(&vs); pipe.AddShader(&fs); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'not written by vertex shader'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CreatePipelineFragmentInputNotProvidedInBlock) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "not written by vertex shader"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = vec4(1);\n" "}\n"; char const *fsSource = "#version 450\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "in block { layout(location=0) float x; } ins;\n" "layout(location=0) out vec4 color;\n" "void main(){\n" " color = vec4(ins.x);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddColorAttachment(); pipe.AddShader(&vs); pipe.AddShader(&fs); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'not written by vertex shader'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CreatePipelineVsFsTypeMismatchArraySize) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Type mismatch on location 0.0: 'ptr to " "output arr[2] of float32' vs 'ptr to " "input arr[3] of float32'"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out float x[2];\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " x[0] = 0; x[1] = 0;\n" " gl_Position = vec4(1);\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) in float x[3];\n" "layout(location=0) out vec4 color;\n" "void main(){\n" " color = vec4(x[0] + x[1] + x[2]);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddColorAttachment(); pipe.AddShader(&vs); pipe.AddShader(&fs); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { m_errorMonitor->DumpFailureMsgs(); FAIL() << "Did not receive Error 'Type mismatch on location 0.0: 'ptr to " "output arr[2] of float32' vs 'ptr to input arr[3] of " "float32''"; } } TEST_F(VkLayerTest, CreatePipelineVsFsTypeMismatch) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Type mismatch on location 0"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out int x;\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " x = 0;\n" " gl_Position = vec4(1);\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) in float x;\n" /* VS writes int */ "layout(location=0) out vec4 color;\n" "void main(){\n" " color = vec4(x);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddColorAttachment(); pipe.AddShader(&vs); pipe.AddShader(&fs); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Type mismatch on location 0'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CreatePipelineVsFsTypeMismatchInBlock) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Type mismatch on location 0"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); char const *vsSource = "#version 450\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "out block { layout(location=0) int x; } outs;\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " outs.x = 0;\n" " gl_Position = vec4(1);\n" "}\n"; char const *fsSource = "#version 450\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "in block { layout(location=0) float x; } ins;\n" /* VS writes int */ "layout(location=0) out vec4 color;\n" "void main(){\n" " color = vec4(ins.x);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddColorAttachment(); pipe.AddShader(&vs); pipe.AddShader(&fs); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { m_errorMonitor->DumpFailureMsgs(); FAIL() << "Did not receive Error 'Type mismatch on location 0'"; } } TEST_F(VkLayerTest, CreatePipelineVsFsMismatchByLocation) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "location 0.0 which is not written by vertex shader"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); char const *vsSource = "#version 450\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "out block { layout(location=1) float x; } outs;\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " outs.x = 0;\n" " gl_Position = vec4(1);\n" "}\n"; char const *fsSource = "#version 450\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "in block { layout(location=0) float x; } ins;\n" "layout(location=0) out vec4 color;\n" "void main(){\n" " color = vec4(ins.x);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddColorAttachment(); pipe.AddShader(&vs); pipe.AddShader(&fs); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { m_errorMonitor->DumpFailureMsgs(); FAIL() << "Did not receive Error 'location 0.0 which is not written by vertex shader'"; } } TEST_F(VkLayerTest, CreatePipelineVsFsMismatchByComponent) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "location 0.1 which is not written by vertex shader"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); char const *vsSource = "#version 450\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "out block { layout(location=0, component=0) float x; } outs;\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " outs.x = 0;\n" " gl_Position = vec4(1);\n" "}\n"; char const *fsSource = "#version 450\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "in block { layout(location=0, component=1) float x; } ins;\n" "layout(location=0) out vec4 color;\n" "void main(){\n" " color = vec4(ins.x);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddColorAttachment(); pipe.AddShader(&vs); pipe.AddShader(&fs); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { m_errorMonitor->DumpFailureMsgs(); FAIL() << "Did not receive Error 'location 0.1 which is not written by vertex shader'"; } } TEST_F(VkLayerTest, CreatePipelineAttribNotConsumed) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, "location 0 not consumed by VS"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkVertexInputBindingDescription input_binding; memset(&input_binding, 0, sizeof(input_binding)); VkVertexInputAttributeDescription input_attrib; memset(&input_attrib, 0, sizeof(input_attrib)); input_attrib.format = VK_FORMAT_R32_SFLOAT; char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = vec4(1);\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out vec4 color;\n" "void main(){\n" " color = vec4(1);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddColorAttachment(); pipe.AddShader(&vs); pipe.AddShader(&fs); pipe.AddVertexInputBindings(&input_binding, 1); pipe.AddVertexInputAttribs(&input_attrib, 1); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Warning 'location 0 not consumed by VS'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CreatePipelineAttribLocationMismatch) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, "location 0 not consumed by VS"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkVertexInputBindingDescription input_binding; memset(&input_binding, 0, sizeof(input_binding)); VkVertexInputAttributeDescription input_attrib; memset(&input_attrib, 0, sizeof(input_attrib)); input_attrib.format = VK_FORMAT_R32_SFLOAT; char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=1) in float x;\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = vec4(x);\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out vec4 color;\n" "void main(){\n" " color = vec4(1);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddColorAttachment(); pipe.AddShader(&vs); pipe.AddShader(&fs); pipe.AddVertexInputBindings(&input_binding, 1); pipe.AddVertexInputAttribs(&input_attrib, 1); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { m_errorMonitor->DumpFailureMsgs(); FAIL() << "Did not receive Warning 'location 0 not consumed by VS'"; } } TEST_F(VkLayerTest, CreatePipelineAttribNotProvided) { m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "VS consumes input at location 0 but not provided"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) in vec4 x;\n" /* not provided */ "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = x;\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out vec4 color;\n" "void main(){\n" " color = vec4(1);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddColorAttachment(); pipe.AddShader(&vs); pipe.AddShader(&fs); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'VS consumes input at location 0 but " "not provided'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CreatePipelineAttribTypeMismatch) { m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "location 0 does not match VS input type"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkVertexInputBindingDescription input_binding; memset(&input_binding, 0, sizeof(input_binding)); VkVertexInputAttributeDescription input_attrib; memset(&input_attrib, 0, sizeof(input_attrib)); input_attrib.format = VK_FORMAT_R32_SFLOAT; char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) in int x;\n" /* attrib provided float */ "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = vec4(x);\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out vec4 color;\n" "void main(){\n" " color = vec4(1);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddColorAttachment(); pipe.AddShader(&vs); pipe.AddShader(&fs); pipe.AddVertexInputBindings(&input_binding, 1); pipe.AddVertexInputAttribs(&input_attrib, 1); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'location 0 does not match VS input " "type'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CreatePipelineAttribMatrixType) { m_errorMonitor->SetDesiredFailureMsg(~0u, ""); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkVertexInputBindingDescription input_binding; memset(&input_binding, 0, sizeof(input_binding)); VkVertexInputAttributeDescription input_attribs[2]; memset(input_attribs, 0, sizeof(input_attribs)); for (int i = 0; i < 2; i++) { input_attribs[i].format = VK_FORMAT_R32G32B32A32_SFLOAT; input_attribs[i].location = i; } char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) in mat2x4 x;\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = x[0] + x[1];\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out vec4 color;\n" "void main(){\n" " color = vec4(1);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddColorAttachment(); pipe.AddShader(&vs); pipe.AddShader(&fs); pipe.AddVertexInputBindings(&input_binding, 1); pipe.AddVertexInputAttribs(input_attribs, 2); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); /* expect success */ if (m_errorMonitor->DesiredMsgFound()) { FAIL() << "Expected to succeed but: " << m_errorMonitor->GetFailureMsg(); m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CreatePipelineAttribArrayType) { m_errorMonitor->SetDesiredFailureMsg(~0u, ""); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkVertexInputBindingDescription input_binding; memset(&input_binding, 0, sizeof(input_binding)); VkVertexInputAttributeDescription input_attribs[2]; memset(input_attribs, 0, sizeof(input_attribs)); for (int i = 0; i < 2; i++) { input_attribs[i].format = VK_FORMAT_R32G32B32A32_SFLOAT; input_attribs[i].location = i; } char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) in vec4 x[2];\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = x[0] + x[1];\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out vec4 color;\n" "void main(){\n" " color = vec4(1);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddColorAttachment(); pipe.AddShader(&vs); pipe.AddShader(&fs); pipe.AddVertexInputBindings(&input_binding, 1); pipe.AddVertexInputAttribs(input_attribs, 2); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (m_errorMonitor->DesiredMsgFound()) { FAIL() << "Expected to succeed but: " << m_errorMonitor->GetFailureMsg(); m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CreatePipelineAttribBindingConflict) { m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Duplicate vertex input binding descriptions for binding 0"); ASSERT_NO_FATAL_FAILURE(InitState()); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); /* Two binding descriptions for binding 0 */ VkVertexInputBindingDescription input_bindings[2]; memset(input_bindings, 0, sizeof(input_bindings)); VkVertexInputAttributeDescription input_attrib; memset(&input_attrib, 0, sizeof(input_attrib)); input_attrib.format = VK_FORMAT_R32_SFLOAT; char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) in float x;\n" /* attrib provided float */ "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = vec4(x);\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out vec4 color;\n" "void main(){\n" " color = vec4(1);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddColorAttachment(); pipe.AddShader(&vs); pipe.AddShader(&fs); pipe.AddVertexInputBindings(input_bindings, 2); pipe.AddVertexInputAttribs(&input_attrib, 1); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Duplicate vertex input binding " "descriptions for binding 0'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CreatePipelineFragmentOutputNotWritten) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "Attachment 0 not written by FS"); ASSERT_NO_FATAL_FAILURE(InitState()); char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = vec4(1);\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "void main(){\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddShader(&vs); pipe.AddShader(&fs); /* set up CB 0, not written */ pipe.AddColorAttachment(); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Attachment 0 not written by FS'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CreatePipelineFragmentOutputNotConsumed) { // TODO: verify that this matches layer m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_WARNING_BIT_EXT, "FS writes to output location 1 with no matching attachment"); ASSERT_NO_FATAL_FAILURE(InitState()); char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = vec4(1);\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out vec4 x;\n" "layout(location=1) out vec4 y;\n" /* no matching attachment for this */ "void main(){\n" " x = vec4(1);\n" " y = vec4(1);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddShader(&vs); pipe.AddShader(&fs); /* set up CB 0, not written */ pipe.AddColorAttachment(); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); /* FS writes CB 1, but we don't configure it */ VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'FS writes to output location 1 with " "no matching attachment'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CreatePipelineFragmentOutputTypeMismatch) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "does not match FS output type"); ASSERT_NO_FATAL_FAILURE(InitState()); char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = vec4(1);\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out ivec4 x;\n" /* not UNORM */ "void main(){\n" " x = ivec4(1);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddShader(&vs); pipe.AddShader(&fs); /* set up CB 0; type is UNORM by default */ pipe.AddColorAttachment(); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.AppendDummy(); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'does not match FS output type'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CreatePipelineUniformBlockNotProvided) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "not declared in pipeline layout"); ASSERT_NO_FATAL_FAILURE(InitState()); char const *vsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = vec4(1);\n" "}\n"; char const *fsSource = "#version 400\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out vec4 x;\n" "layout(set=0) layout(binding=0) uniform foo { int x; int y; } bar;\n" "void main(){\n" " x = vec4(bar.y);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddShader(&vs); pipe.AddShader(&fs); /* set up CB 0; type is UNORM by default */ pipe.AddColorAttachment(); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); /* should have generated an error -- pipeline layout does not * provide a uniform buffer in 0.0 */ if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'not declared in pipeline layout'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CreatePipelinePushConstantsNotInLayout) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "not declared in layout"); ASSERT_NO_FATAL_FAILURE(InitState()); char const *vsSource = "#version 450\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(push_constant, std430) uniform foo { float x; } consts;\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" "};\n" "void main(){\n" " gl_Position = vec4(consts.x);\n" "}\n"; char const *fsSource = "#version 450\n" "#extension GL_ARB_separate_shader_objects: require\n" "#extension GL_ARB_shading_language_420pack: require\n" "\n" "layout(location=0) out vec4 x;\n" "void main(){\n" " x = vec4(1);\n" "}\n"; VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); VkPipelineObj pipe(m_device); pipe.AddShader(&vs); pipe.AddShader(&fs); /* set up CB 0; type is UNORM by default */ pipe.AddColorAttachment(); ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); VkDescriptorSetObj descriptorSet(m_device); descriptorSet.CreateVKDescriptorSet(m_commandBuffer); pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); /* should have generated an error -- no push constant ranges provided! */ if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'not declared in pipeline layout'"; m_errorMonitor->DumpFailureMsgs(); } } #endif // SHADER_CHECKER_TESTS #if DEVICE_LIMITS_TESTS TEST_F(VkLayerTest, CreateImageLimitsViolationWidth) { m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "CreateImage extents exceed allowable limits for format"); ASSERT_NO_FATAL_FAILURE(InitState()); // Create an image VkImage image; const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; const int32_t tex_width = 32; const int32_t tex_height = 32; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = tex_format; image_create_info.extent.width = tex_width; image_create_info.extent.height = tex_height; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.tiling = VK_IMAGE_TILING_LINEAR; image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; image_create_info.flags = 0; // Introduce error by sending down a bogus width extent image_create_info.extent.width = 65536; vkCreateImage(m_device->device(), &image_create_info, NULL, &image); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'CreateImage extents exceed allowable " "limits for format'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, UpdateBufferAlignment) { uint32_t updateData[] = {1, 2, 3, 4, 5, 6, 7, 8}; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "dstOffset, is not a multiple of 4"); ASSERT_NO_FATAL_FAILURE(InitState()); VkMemoryPropertyFlags reqs = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; vk_testing::Buffer buffer; buffer.init_as_dst(*m_device, (VkDeviceSize)20, reqs); BeginCommandBuffer(); // Introduce failure by using offset that is not multiple of 4 m_commandBuffer->UpdateBuffer(buffer.handle(), 1, 4, updateData); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCommandUpdateBuffer parameter, " "VkDeviceSize dstOffset, is not a multiple of 4'"; m_errorMonitor->DumpFailureMsgs(); } // Introduce failure by using size that is not multiple of 4 m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "dataSize, is not a multiple of 4"); m_commandBuffer->UpdateBuffer(buffer.handle(), 0, 6, updateData); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCommandUpdateBuffer parameter, " "VkDeviceSize dataSize, is not a multiple of 4'"; m_errorMonitor->DumpFailureMsgs(); } EndCommandBuffer(); } TEST_F(VkLayerTest, FillBufferAlignment) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "dstOffset, is not a multiple of 4"); ASSERT_NO_FATAL_FAILURE(InitState()); VkMemoryPropertyFlags reqs = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; vk_testing::Buffer buffer; buffer.init_as_dst(*m_device, (VkDeviceSize)20, reqs); BeginCommandBuffer(); // Introduce failure by using offset that is not multiple of 4 m_commandBuffer->FillBuffer(buffer.handle(), 1, 4, 0x11111111); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCommandFillBuffer parameter, " "VkDeviceSize dstOffset, is not a multiple of 4'"; m_errorMonitor->DumpFailureMsgs(); } // Introduce failure by using size that is not multiple of 4 m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "size, is not a multiple of 4"); m_commandBuffer->FillBuffer(buffer.handle(), 0, 6, 0x11111111); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCommandFillBuffer parameter, " "VkDeviceSize size, is not a multiple of 4'"; m_errorMonitor->DumpFailureMsgs(); } EndCommandBuffer(); } #endif // DEVICE_LIMITS_TESTS #if IMAGE_TESTS TEST_F(VkLayerTest, InvalidImageView) { VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCreateImageView called with baseMipLevel 10 "); ASSERT_NO_FATAL_FAILURE(InitState()); // Create an image and try to create a view with bad baseMipLevel VkImage image; const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; const int32_t tex_width = 32; const int32_t tex_height = 32; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = tex_format; image_create_info.extent.width = tex_width; image_create_info.extent.height = tex_height; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.tiling = VK_IMAGE_TILING_LINEAR; image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; image_create_info.flags = 0; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image); ASSERT_VK_SUCCESS(err); VkImageViewCreateInfo image_view_create_info = {}; image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_view_create_info.image = image; image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; image_view_create_info.format = tex_format; image_view_create_info.subresourceRange.layerCount = 1; image_view_create_info.subresourceRange.baseMipLevel = 10; // cause an error image_view_create_info.subresourceRange.levelCount = 1; image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; VkImageView view; err = vkCreateImageView(m_device->device(), &image_view_create_info, NULL, &view); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCreateImageView called with " "baseMipLevel 10...'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, InvalidImageViewAspect) { VkResult err; m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCreateImageView: Color image " "formats must have ONLY the " "VK_IMAGE_ASPECT_COLOR_BIT set"); ASSERT_NO_FATAL_FAILURE(InitState()); // Create an image and try to create a view with an invalid aspectMask VkImage image; const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; const int32_t tex_width = 32; const int32_t tex_height = 32; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = tex_format; image_create_info.extent.width = tex_width; image_create_info.extent.height = tex_height; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.tiling = VK_IMAGE_TILING_LINEAR; image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; image_create_info.flags = 0; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image); ASSERT_VK_SUCCESS(err); VkImageViewCreateInfo image_view_create_info = {}; image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_view_create_info.image = image; image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; image_view_create_info.format = tex_format; image_view_create_info.subresourceRange.baseMipLevel = 0; image_view_create_info.subresourceRange.levelCount = 1; // Cause an error by setting an invalid image aspect image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_METADATA_BIT; VkImageView view; err = vkCreateImageView(m_device->device(), &image_view_create_info, NULL, &view); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'VkCreateImageView: Color image " "formats must have ...'"; m_errorMonitor->DumpFailureMsgs(); } } TEST_F(VkLayerTest, CopyImageTypeMismatch) { VkResult err; bool pass; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdCopyImage called with unmatched source and dest image types"); ASSERT_NO_FATAL_FAILURE(InitState()); // Create two images of different types and try to copy between them VkImage srcImage; VkImage dstImage; VkDeviceMemory srcMem; VkDeviceMemory destMem; VkMemoryRequirements memReqs; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = VK_FORMAT_B8G8R8A8_UNORM; image_create_info.extent.width = 32; image_create_info.extent.height = 32; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; image_create_info.flags = 0; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &srcImage); ASSERT_VK_SUCCESS(err); image_create_info.imageType = VK_IMAGE_TYPE_1D; image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &dstImage); ASSERT_VK_SUCCESS(err); // Allocate memory VkMemoryAllocateInfo memAlloc = {}; memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memAlloc.pNext = NULL; memAlloc.allocationSize = 0; memAlloc.memoryTypeIndex = 0; vkGetImageMemoryRequirements(m_device->device(), srcImage, &memReqs); memAlloc.allocationSize = memReqs.size; pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &memAlloc, 0); ASSERT_TRUE(pass); err = vkAllocateMemory(m_device->device(), &memAlloc, NULL, &srcMem); ASSERT_VK_SUCCESS(err); vkGetImageMemoryRequirements(m_device->device(), dstImage, &memReqs); memAlloc.allocationSize = memReqs.size; pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &memAlloc, 0); ASSERT_VK_SUCCESS(err); err = vkAllocateMemory(m_device->device(), &memAlloc, NULL, &destMem); ASSERT_VK_SUCCESS(err); err = vkBindImageMemory(m_device->device(), srcImage, srcMem, 0); ASSERT_VK_SUCCESS(err); err = vkBindImageMemory(m_device->device(), dstImage, destMem, 0); ASSERT_VK_SUCCESS(err); BeginCommandBuffer(); VkImageCopy copyRegion; copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyRegion.srcSubresource.mipLevel = 0; copyRegion.srcSubresource.baseArrayLayer = 0; copyRegion.srcSubresource.layerCount = 0; copyRegion.srcOffset.x = 0; copyRegion.srcOffset.y = 0; copyRegion.srcOffset.z = 0; copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyRegion.dstSubresource.mipLevel = 0; copyRegion.dstSubresource.baseArrayLayer = 0; copyRegion.dstSubresource.layerCount = 0; copyRegion.dstOffset.x = 0; copyRegion.dstOffset.y = 0; copyRegion.dstOffset.z = 0; copyRegion.extent.width = 1; copyRegion.extent.height = 1; copyRegion.extent.depth = 1; m_commandBuffer->CopyImage(srcImage, VK_IMAGE_LAYOUT_GENERAL, dstImage, VK_IMAGE_LAYOUT_GENERAL, 1, ©Region); EndCommandBuffer(); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCmdCopyImage called with unmatched " "source and dest image types'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyImage(m_device->device(), srcImage, NULL); vkDestroyImage(m_device->device(), dstImage, NULL); vkFreeMemory(m_device->device(), srcMem, NULL); vkFreeMemory(m_device->device(), destMem, NULL); } TEST_F(VkLayerTest, CopyImageFormatSizeMismatch) { // TODO : Create two images with different format sizes and vkCmdCopyImage // between them } TEST_F(VkLayerTest, CopyImageDepthStencilFormatMismatch) { VkResult err; bool pass; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdCopyImage called with unmatched source and dest image types"); ASSERT_NO_FATAL_FAILURE(InitState()); // Create two images of different types and try to copy between them VkImage srcImage; VkImage dstImage; VkDeviceMemory srcMem; VkDeviceMemory destMem; VkMemoryRequirements memReqs; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = VK_FORMAT_B8G8R8A8_UNORM; image_create_info.extent.width = 32; image_create_info.extent.height = 32; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.tiling = VK_IMAGE_TILING_LINEAR; image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; image_create_info.flags = 0; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &srcImage); ASSERT_VK_SUCCESS(err); image_create_info.imageType = VK_IMAGE_TYPE_1D; image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &dstImage); ASSERT_VK_SUCCESS(err); // Allocate memory VkMemoryAllocateInfo memAlloc = {}; memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memAlloc.pNext = NULL; memAlloc.allocationSize = 0; memAlloc.memoryTypeIndex = 0; vkGetImageMemoryRequirements(m_device->device(), srcImage, &memReqs); memAlloc.allocationSize = memReqs.size; pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &memAlloc, 0); ASSERT_TRUE(pass); err = vkAllocateMemory(m_device->device(), &memAlloc, NULL, &srcMem); ASSERT_VK_SUCCESS(err); vkGetImageMemoryRequirements(m_device->device(), dstImage, &memReqs); memAlloc.allocationSize = memReqs.size; pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &memAlloc, 0); ASSERT_TRUE(pass); err = vkAllocateMemory(m_device->device(), &memAlloc, NULL, &destMem); ASSERT_VK_SUCCESS(err); err = vkBindImageMemory(m_device->device(), srcImage, srcMem, 0); ASSERT_VK_SUCCESS(err); err = vkBindImageMemory(m_device->device(), dstImage, destMem, 0); ASSERT_VK_SUCCESS(err); BeginCommandBuffer(); VkImageCopy copyRegion; copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyRegion.srcSubresource.mipLevel = 0; copyRegion.srcSubresource.baseArrayLayer = 0; copyRegion.srcSubresource.layerCount = 0; copyRegion.srcOffset.x = 0; copyRegion.srcOffset.y = 0; copyRegion.srcOffset.z = 0; copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyRegion.dstSubresource.mipLevel = 0; copyRegion.dstSubresource.baseArrayLayer = 0; copyRegion.dstSubresource.layerCount = 0; copyRegion.dstOffset.x = 0; copyRegion.dstOffset.y = 0; copyRegion.dstOffset.z = 0; copyRegion.extent.width = 1; copyRegion.extent.height = 1; copyRegion.extent.depth = 1; m_commandBuffer->CopyImage(srcImage, VK_IMAGE_LAYOUT_GENERAL, dstImage, VK_IMAGE_LAYOUT_GENERAL, 1, ©Region); EndCommandBuffer(); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCmdCopyImage called with unmatched " "source and dest image types'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyImage(m_device->device(), srcImage, NULL); vkDestroyImage(m_device->device(), dstImage, NULL); vkFreeMemory(m_device->device(), srcMem, NULL); vkFreeMemory(m_device->device(), destMem, NULL); } TEST_F(VkLayerTest, ResolveImageLowSampleCount) { VkResult err; bool pass; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdResolveImage called with source sample count less than 2."); ASSERT_NO_FATAL_FAILURE(InitState()); // Create two images of sample count 1 and try to Resolve between them VkImage srcImage; VkImage dstImage; VkDeviceMemory srcMem; VkDeviceMemory destMem; VkMemoryRequirements memReqs; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = VK_FORMAT_B8G8R8A8_UNORM; image_create_info.extent.width = 32; image_create_info.extent.height = 1; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; image_create_info.flags = 0; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &srcImage); ASSERT_VK_SUCCESS(err); image_create_info.imageType = VK_IMAGE_TYPE_1D; image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &dstImage); ASSERT_VK_SUCCESS(err); // Allocate memory VkMemoryAllocateInfo memAlloc = {}; memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memAlloc.pNext = NULL; memAlloc.allocationSize = 0; memAlloc.memoryTypeIndex = 0; vkGetImageMemoryRequirements(m_device->device(), srcImage, &memReqs); memAlloc.allocationSize = memReqs.size; pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &memAlloc, 0); ASSERT_TRUE(pass); err = vkAllocateMemory(m_device->device(), &memAlloc, NULL, &srcMem); ASSERT_VK_SUCCESS(err); vkGetImageMemoryRequirements(m_device->device(), dstImage, &memReqs); memAlloc.allocationSize = memReqs.size; pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &memAlloc, 0); ASSERT_TRUE(pass); err = vkAllocateMemory(m_device->device(), &memAlloc, NULL, &destMem); ASSERT_VK_SUCCESS(err); err = vkBindImageMemory(m_device->device(), srcImage, srcMem, 0); ASSERT_VK_SUCCESS(err); err = vkBindImageMemory(m_device->device(), dstImage, destMem, 0); ASSERT_VK_SUCCESS(err); BeginCommandBuffer(); // Need memory barrier to VK_IMAGE_LAYOUT_GENERAL for source and dest? // VK_IMAGE_LAYOUT_UNDEFINED = 0, // VK_IMAGE_LAYOUT_GENERAL = 1, VkImageResolve resolveRegion; resolveRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; resolveRegion.srcSubresource.mipLevel = 0; resolveRegion.srcSubresource.baseArrayLayer = 0; resolveRegion.srcSubresource.layerCount = 0; resolveRegion.srcOffset.x = 0; resolveRegion.srcOffset.y = 0; resolveRegion.srcOffset.z = 0; resolveRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; resolveRegion.dstSubresource.mipLevel = 0; resolveRegion.dstSubresource.baseArrayLayer = 0; resolveRegion.dstSubresource.layerCount = 0; resolveRegion.dstOffset.x = 0; resolveRegion.dstOffset.y = 0; resolveRegion.dstOffset.z = 0; resolveRegion.extent.width = 1; resolveRegion.extent.height = 1; resolveRegion.extent.depth = 1; m_commandBuffer->ResolveImage(srcImage, VK_IMAGE_LAYOUT_GENERAL, dstImage, VK_IMAGE_LAYOUT_GENERAL, 1, &resolveRegion); EndCommandBuffer(); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCmdResolveImage called with source " "sample count less than 2.'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyImage(m_device->device(), srcImage, NULL); vkDestroyImage(m_device->device(), dstImage, NULL); vkFreeMemory(m_device->device(), srcMem, NULL); vkFreeMemory(m_device->device(), destMem, NULL); } TEST_F(VkLayerTest, ResolveImageHighSampleCount) { VkResult err; bool pass; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdResolveImage called with dest sample count greater than 1."); ASSERT_NO_FATAL_FAILURE(InitState()); // Create two images of sample count 2 and try to Resolve between them VkImage srcImage; VkImage dstImage; VkDeviceMemory srcMem; VkDeviceMemory destMem; VkMemoryRequirements memReqs; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = VK_FORMAT_B8G8R8A8_UNORM; image_create_info.extent.width = 32; image_create_info.extent.height = 1; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_2_BIT; image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; // Note: Some implementations expect color attachment usage for any // multisample surface image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; image_create_info.flags = 0; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &srcImage); ASSERT_VK_SUCCESS(err); image_create_info.imageType = VK_IMAGE_TYPE_1D; // Note: Some implementations expect color attachment usage for any // multisample surface image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &dstImage); ASSERT_VK_SUCCESS(err); // Allocate memory VkMemoryAllocateInfo memAlloc = {}; memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memAlloc.pNext = NULL; memAlloc.allocationSize = 0; memAlloc.memoryTypeIndex = 0; vkGetImageMemoryRequirements(m_device->device(), srcImage, &memReqs); memAlloc.allocationSize = memReqs.size; pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &memAlloc, 0); ASSERT_TRUE(pass); err = vkAllocateMemory(m_device->device(), &memAlloc, NULL, &srcMem); ASSERT_VK_SUCCESS(err); vkGetImageMemoryRequirements(m_device->device(), dstImage, &memReqs); memAlloc.allocationSize = memReqs.size; pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &memAlloc, 0); ASSERT_TRUE(pass); err = vkAllocateMemory(m_device->device(), &memAlloc, NULL, &destMem); ASSERT_VK_SUCCESS(err); err = vkBindImageMemory(m_device->device(), srcImage, srcMem, 0); ASSERT_VK_SUCCESS(err); err = vkBindImageMemory(m_device->device(), dstImage, destMem, 0); ASSERT_VK_SUCCESS(err); BeginCommandBuffer(); // Need memory barrier to VK_IMAGE_LAYOUT_GENERAL for source and dest? // VK_IMAGE_LAYOUT_UNDEFINED = 0, // VK_IMAGE_LAYOUT_GENERAL = 1, VkImageResolve resolveRegion; resolveRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; resolveRegion.srcSubresource.mipLevel = 0; resolveRegion.srcSubresource.baseArrayLayer = 0; resolveRegion.srcSubresource.layerCount = 0; resolveRegion.srcOffset.x = 0; resolveRegion.srcOffset.y = 0; resolveRegion.srcOffset.z = 0; resolveRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; resolveRegion.dstSubresource.mipLevel = 0; resolveRegion.dstSubresource.baseArrayLayer = 0; resolveRegion.dstSubresource.layerCount = 0; resolveRegion.dstOffset.x = 0; resolveRegion.dstOffset.y = 0; resolveRegion.dstOffset.z = 0; resolveRegion.extent.width = 1; resolveRegion.extent.height = 1; resolveRegion.extent.depth = 1; m_commandBuffer->ResolveImage(srcImage, VK_IMAGE_LAYOUT_GENERAL, dstImage, VK_IMAGE_LAYOUT_GENERAL, 1, &resolveRegion); EndCommandBuffer(); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCmdResolveImage called with dest " "sample count greater than 1.'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyImage(m_device->device(), srcImage, NULL); vkDestroyImage(m_device->device(), dstImage, NULL); vkFreeMemory(m_device->device(), srcMem, NULL); vkFreeMemory(m_device->device(), destMem, NULL); } TEST_F(VkLayerTest, ResolveImageFormatMismatch) { VkResult err; bool pass; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdResolveImage called with unmatched source and dest formats."); ASSERT_NO_FATAL_FAILURE(InitState()); // Create two images of different types and try to copy between them VkImage srcImage; VkImage dstImage; VkDeviceMemory srcMem; VkDeviceMemory destMem; VkMemoryRequirements memReqs; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = VK_FORMAT_B8G8R8A8_UNORM; image_create_info.extent.width = 32; image_create_info.extent.height = 1; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_2_BIT; image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; // Note: Some implementations expect color attachment usage for any // multisample surface image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; image_create_info.flags = 0; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &srcImage); ASSERT_VK_SUCCESS(err); // Set format to something other than source image image_create_info.format = VK_FORMAT_R32_SFLOAT; // Note: Some implementations expect color attachment usage for any // multisample surface image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &dstImage); ASSERT_VK_SUCCESS(err); // Allocate memory VkMemoryAllocateInfo memAlloc = {}; memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memAlloc.pNext = NULL; memAlloc.allocationSize = 0; memAlloc.memoryTypeIndex = 0; vkGetImageMemoryRequirements(m_device->device(), srcImage, &memReqs); memAlloc.allocationSize = memReqs.size; pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &memAlloc, 0); ASSERT_TRUE(pass); err = vkAllocateMemory(m_device->device(), &memAlloc, NULL, &srcMem); ASSERT_VK_SUCCESS(err); vkGetImageMemoryRequirements(m_device->device(), dstImage, &memReqs); memAlloc.allocationSize = memReqs.size; pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &memAlloc, 0); ASSERT_TRUE(pass); err = vkAllocateMemory(m_device->device(), &memAlloc, NULL, &destMem); ASSERT_VK_SUCCESS(err); err = vkBindImageMemory(m_device->device(), srcImage, srcMem, 0); ASSERT_VK_SUCCESS(err); err = vkBindImageMemory(m_device->device(), dstImage, destMem, 0); ASSERT_VK_SUCCESS(err); BeginCommandBuffer(); // Need memory barrier to VK_IMAGE_LAYOUT_GENERAL for source and dest? // VK_IMAGE_LAYOUT_UNDEFINED = 0, // VK_IMAGE_LAYOUT_GENERAL = 1, VkImageResolve resolveRegion; resolveRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; resolveRegion.srcSubresource.mipLevel = 0; resolveRegion.srcSubresource.baseArrayLayer = 0; resolveRegion.srcSubresource.layerCount = 0; resolveRegion.srcOffset.x = 0; resolveRegion.srcOffset.y = 0; resolveRegion.srcOffset.z = 0; resolveRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; resolveRegion.dstSubresource.mipLevel = 0; resolveRegion.dstSubresource.baseArrayLayer = 0; resolveRegion.dstSubresource.layerCount = 0; resolveRegion.dstOffset.x = 0; resolveRegion.dstOffset.y = 0; resolveRegion.dstOffset.z = 0; resolveRegion.extent.width = 1; resolveRegion.extent.height = 1; resolveRegion.extent.depth = 1; m_commandBuffer->ResolveImage(srcImage, VK_IMAGE_LAYOUT_GENERAL, dstImage, VK_IMAGE_LAYOUT_GENERAL, 1, &resolveRegion); EndCommandBuffer(); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCmdResolveImage called with " "unmatched source and dest formats.'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyImage(m_device->device(), srcImage, NULL); vkDestroyImage(m_device->device(), dstImage, NULL); vkFreeMemory(m_device->device(), srcMem, NULL); vkFreeMemory(m_device->device(), destMem, NULL); } TEST_F(VkLayerTest, ResolveImageTypeMismatch) { VkResult err; bool pass; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "vkCmdResolveImage called with unmatched source and dest image types."); ASSERT_NO_FATAL_FAILURE(InitState()); // Create two images of different types and try to copy between them VkImage srcImage; VkImage dstImage; VkDeviceMemory srcMem; VkDeviceMemory destMem; VkMemoryRequirements memReqs; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = VK_FORMAT_B8G8R8A8_UNORM; image_create_info.extent.width = 32; image_create_info.extent.height = 1; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_2_BIT; image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; // Note: Some implementations expect color attachment usage for any // multisample surface image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; image_create_info.flags = 0; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &srcImage); ASSERT_VK_SUCCESS(err); image_create_info.imageType = VK_IMAGE_TYPE_1D; // Note: Some implementations expect color attachment usage for any // multisample surface image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &dstImage); ASSERT_VK_SUCCESS(err); // Allocate memory VkMemoryAllocateInfo memAlloc = {}; memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memAlloc.pNext = NULL; memAlloc.allocationSize = 0; memAlloc.memoryTypeIndex = 0; vkGetImageMemoryRequirements(m_device->device(), srcImage, &memReqs); memAlloc.allocationSize = memReqs.size; pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &memAlloc, 0); ASSERT_TRUE(pass); err = vkAllocateMemory(m_device->device(), &memAlloc, NULL, &srcMem); ASSERT_VK_SUCCESS(err); vkGetImageMemoryRequirements(m_device->device(), dstImage, &memReqs); memAlloc.allocationSize = memReqs.size; pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &memAlloc, 0); ASSERT_TRUE(pass); err = vkAllocateMemory(m_device->device(), &memAlloc, NULL, &destMem); ASSERT_VK_SUCCESS(err); err = vkBindImageMemory(m_device->device(), srcImage, srcMem, 0); ASSERT_VK_SUCCESS(err); err = vkBindImageMemory(m_device->device(), dstImage, destMem, 0); ASSERT_VK_SUCCESS(err); BeginCommandBuffer(); // Need memory barrier to VK_IMAGE_LAYOUT_GENERAL for source and dest? // VK_IMAGE_LAYOUT_UNDEFINED = 0, // VK_IMAGE_LAYOUT_GENERAL = 1, VkImageResolve resolveRegion; resolveRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; resolveRegion.srcSubresource.mipLevel = 0; resolveRegion.srcSubresource.baseArrayLayer = 0; resolveRegion.srcSubresource.layerCount = 0; resolveRegion.srcOffset.x = 0; resolveRegion.srcOffset.y = 0; resolveRegion.srcOffset.z = 0; resolveRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; resolveRegion.dstSubresource.mipLevel = 0; resolveRegion.dstSubresource.baseArrayLayer = 0; resolveRegion.dstSubresource.layerCount = 0; resolveRegion.dstOffset.x = 0; resolveRegion.dstOffset.y = 0; resolveRegion.dstOffset.z = 0; resolveRegion.extent.width = 1; resolveRegion.extent.height = 1; resolveRegion.extent.depth = 1; m_commandBuffer->ResolveImage(srcImage, VK_IMAGE_LAYOUT_GENERAL, dstImage, VK_IMAGE_LAYOUT_GENERAL, 1, &resolveRegion); EndCommandBuffer(); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'vkCmdResolveImage called with " "unmatched source and dest image types.'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyImage(m_device->device(), srcImage, NULL); vkDestroyImage(m_device->device(), dstImage, NULL); vkFreeMemory(m_device->device(), srcMem, NULL); vkFreeMemory(m_device->device(), destMem, NULL); } TEST_F(VkLayerTest, DepthStencilImageViewWithColorAspectBitError) { // Create a single Image descriptor and cause it to first hit an error due // to using a DS format, then cause it to hit error due to COLOR_BIT not // set in aspect // The image format check comes 2nd in validation so we trigger it first, // then when we cause aspect fail next, bad format check will be preempted VkResult err; m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, "Combination depth/stencil image formats can have only the "); ASSERT_NO_FATAL_FAILURE(InitState()); VkDescriptorPoolSize ds_type_count = {}; ds_type_count.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; ds_type_count.descriptorCount = 1; VkDescriptorPoolCreateInfo ds_pool_ci = {}; ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; ds_pool_ci.pNext = NULL; ds_pool_ci.maxSets = 1; ds_pool_ci.poolSizeCount = 1; ds_pool_ci.pPoolSizes = &ds_type_count; VkDescriptorPool ds_pool; err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); ASSERT_VK_SUCCESS(err); VkDescriptorSetLayoutBinding dsl_binding = {}; dsl_binding.binding = 0; dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; dsl_binding.descriptorCount = 1; dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; dsl_binding.pImmutableSamplers = NULL; VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; ds_layout_ci.pNext = NULL; ds_layout_ci.bindingCount = 1; ds_layout_ci.pBindings = &dsl_binding; VkDescriptorSetLayout ds_layout; err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); ASSERT_VK_SUCCESS(err); VkDescriptorSet descriptorSet; VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorSetCount = 1; alloc_info.descriptorPool = ds_pool; alloc_info.pSetLayouts = &ds_layout; err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); ASSERT_VK_SUCCESS(err); VkImage image_bad; VkImage image_good; // One bad format and one good format for Color attachment const VkFormat tex_format_bad = VK_FORMAT_D32_SFLOAT_S8_UINT; const VkFormat tex_format_good = VK_FORMAT_B8G8R8A8_UNORM; const int32_t tex_width = 32; const int32_t tex_height = 32; VkImageCreateInfo image_create_info = {}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.pNext = NULL; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = tex_format_bad; image_create_info.extent.width = tex_width; image_create_info.extent.height = tex_height; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; image_create_info.flags = 0; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image_bad); ASSERT_VK_SUCCESS(err); image_create_info.format = tex_format_good; image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image_good); ASSERT_VK_SUCCESS(err); VkImageViewCreateInfo image_view_create_info = {}; image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_view_create_info.image = image_bad; image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; image_view_create_info.format = tex_format_bad; image_view_create_info.subresourceRange.baseArrayLayer = 0; image_view_create_info.subresourceRange.baseMipLevel = 0; image_view_create_info.subresourceRange.layerCount = 1; image_view_create_info.subresourceRange.levelCount = 1; image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; VkImageView view; err = vkCreateImageView(m_device->device(), &image_view_create_info, NULL, &view); if (!m_errorMonitor->DesiredMsgFound()) { FAIL() << "Did not receive Error 'Combination depth-stencil image " "formats can have only the....'"; m_errorMonitor->DumpFailureMsgs(); } vkDestroyImage(m_device->device(), image_bad, NULL); vkDestroyImage(m_device->device(), image_good, NULL); vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } #endif // IMAGE_TESTS int main(int argc, char **argv) { int result; ::testing::InitGoogleTest(&argc, argv); VkTestFramework::InitArgs(&argc, argv); ::testing::AddGlobalTestEnvironment(new TestEnvironment); result = RUN_ALL_TESTS(); VkTestFramework::Finish(); return result; }