| /* |
| * Copyright (c) 2023 Nintendo |
| * Copyright (c) 2023 LunarG, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| */ |
| |
| #include "../framework/layer_validation_tests.h" |
| |
| void ShaderObjectTest::InitBasicShaderObject(void *pNextFeatures, APIVersion targetApiVersion, bool coreFeatures) { |
| SetTargetApiVersion(targetApiVersion); |
| AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| RETURN_IF_SKIP(InitFramework()) |
| |
| VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering_features = vku::InitStructHelper(pNextFeatures); |
| VkPhysicalDeviceShaderObjectFeaturesEXT shader_object_features = vku::InitStructHelper(&dynamic_rendering_features); |
| auto features2 = GetPhysicalDeviceFeatures2(shader_object_features); |
| if (!coreFeatures) { |
| features2 = vku::InitStructHelper(&shader_object_features); |
| } |
| if (!shader_object_features.shaderObject) { |
| GTEST_SKIP() << "Test requires (unsupported) shaderObject , skipping."; |
| } |
| |
| RETURN_IF_SKIP(InitState(nullptr, &features2, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)); |
| } |
| |
| void ShaderObjectTest::BindVertFragShader(const vkt::Shader &vertShader, const vkt::Shader &fragShader) { |
| const VkShaderStageFlagBits stages[] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, |
| VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_GEOMETRY_BIT, |
| VK_SHADER_STAGE_FRAGMENT_BIT}; |
| const VkShaderEXT shaders[] = {vertShader.handle(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, fragShader.handle()}; |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 5u, stages, shaders); |
| } |
| |
| void ShaderObjectTest::BindCompShader(const vkt::Shader &compShader) { |
| const VkShaderStageFlagBits stages[] = {VK_SHADER_STAGE_COMPUTE_BIT}; |
| const VkShaderEXT shaders[] = {compShader.handle()}; |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 1u, stages, shaders); |
| } |
| |
| void ShaderObjectTest::SetDefaultDynamicStates(const std::vector<VkDynamicState> &exclude, bool tessellation, |
| VkCommandBuffer commandBuffer) { |
| const auto excluded = [&exclude](VkDynamicState state) { |
| return std::find(exclude.begin(), exclude.end(), state) != exclude.end(); |
| }; |
| vertexBuffer.init(*m_device, 32u, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
| |
| VkCommandBuffer cmdBuffer = commandBuffer ? commandBuffer : m_commandBuffer->handle(); |
| VkViewport viewport = {0, 0, static_cast<float>(m_width), static_cast<float>(m_height), 0.0f, 1.0f}; |
| VkRect2D scissor = {{0, 0}, {m_width, m_height}}; |
| if (!excluded(VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT)) vk::CmdSetViewportWithCountEXT(cmdBuffer, 1u, &viewport); |
| if (!excluded(VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT)) vk::CmdSetScissorWithCountEXT(cmdBuffer, 1u, &scissor); |
| if (!excluded(VK_DYNAMIC_STATE_LINE_WIDTH)) vk::CmdSetLineWidth(cmdBuffer, 1.0f); |
| if (!excluded(VK_DYNAMIC_STATE_DEPTH_BIAS)) vk::CmdSetDepthBias(cmdBuffer, 1.0f, 0.0f, 1.0f); |
| float blendConstants[4] = {1.0f, 1.0f, 1.0f, 1.0f}; |
| if (!excluded(VK_DYNAMIC_STATE_BLEND_CONSTANTS)) vk::CmdSetBlendConstants(cmdBuffer, blendConstants); |
| if (!excluded(VK_DYNAMIC_STATE_DEPTH_BOUNDS)) vk::CmdSetDepthBounds(cmdBuffer, 0.0f, 1.0f); |
| if (!excluded(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK)) |
| vk::CmdSetStencilCompareMask(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, 0xFFFFFFFF); |
| if (!excluded(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK)) |
| vk::CmdSetStencilWriteMask(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, 0xFFFFFFFF); |
| if (!excluded(VK_DYNAMIC_STATE_STENCIL_REFERENCE)) |
| vk::CmdSetStencilReference(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, 0xFFFFFFFF); |
| VkDeviceSize offset = 0u; |
| VkDeviceSize size = sizeof(float); |
| if (!excluded(VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE)) |
| vk::CmdBindVertexBuffers2EXT(cmdBuffer, 0, 1, &vertexBuffer.handle(), &offset, &size, &size); |
| if (!excluded(VK_DYNAMIC_STATE_CULL_MODE)) vk::CmdSetCullModeEXT(cmdBuffer, VK_CULL_MODE_NONE); |
| if (!excluded(VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE)) vk::CmdSetDepthBoundsTestEnableEXT(cmdBuffer, VK_FALSE); |
| if (!excluded(VK_DYNAMIC_STATE_DEPTH_COMPARE_OP)) vk::CmdSetDepthCompareOpEXT(cmdBuffer, VK_COMPARE_OP_NEVER); |
| if (!excluded(VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE)) vk::CmdSetDepthTestEnableEXT(cmdBuffer, VK_FALSE); |
| if (!excluded(VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE)) vk::CmdSetDepthWriteEnableEXT(cmdBuffer, VK_FALSE); |
| if (!excluded(VK_DYNAMIC_STATE_FRONT_FACE)) vk::CmdSetFrontFaceEXT(cmdBuffer, VK_FRONT_FACE_CLOCKWISE); |
| if (!excluded(VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY)) |
| vk::CmdSetPrimitiveTopologyEXT(cmdBuffer, |
| tessellation ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP); |
| if (!excluded(VK_DYNAMIC_STATE_STENCIL_OP)) |
| vk::CmdSetStencilOpEXT(cmdBuffer, VK_STENCIL_FACE_FRONT_AND_BACK, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, |
| VK_STENCIL_OP_KEEP, VK_COMPARE_OP_NEVER); |
| if (!excluded(VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE)) vk::CmdSetStencilTestEnableEXT(cmdBuffer, VK_FALSE); |
| if (!excluded(VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE)) vk::CmdSetDepthBiasEnableEXT(cmdBuffer, VK_FALSE); |
| if (!excluded(VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE)) vk::CmdSetPrimitiveRestartEnableEXT(cmdBuffer, VK_FALSE); |
| if (!excluded(VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT)) vk::CmdSetRasterizerDiscardEnableEXT(cmdBuffer, VK_FALSE); |
| if (!excluded(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT)) vk::CmdSetVertexInputEXT(cmdBuffer, 0u, nullptr, 0u, nullptr); |
| if (!excluded(VK_DYNAMIC_STATE_LOGIC_OP_EXT)) vk::CmdSetLogicOpEXT(cmdBuffer, VK_LOGIC_OP_COPY); |
| if (!excluded(VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT)) vk::CmdSetPatchControlPointsEXT(cmdBuffer, 4u); |
| if (!excluded(VK_DYNAMIC_STATE_TESSELLATION_DOMAIN_ORIGIN_EXT)) |
| vk::CmdSetTessellationDomainOriginEXT(cmdBuffer, VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT); |
| if (!excluded(VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT)) vk::CmdSetDepthClampEnableEXT(cmdBuffer, VK_FALSE); |
| if (!excluded(VK_DYNAMIC_STATE_POLYGON_MODE_EXT)) vk::CmdSetPolygonModeEXT(cmdBuffer, VK_POLYGON_MODE_FILL); |
| if (!excluded(VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT)) vk::CmdSetRasterizationSamplesEXT(cmdBuffer, VK_SAMPLE_COUNT_1_BIT); |
| VkSampleMask sampleMask = 0xFFFFFFFF; |
| if (!excluded(VK_DYNAMIC_STATE_SAMPLE_MASK_EXT)) vk::CmdSetSampleMaskEXT(cmdBuffer, VK_SAMPLE_COUNT_1_BIT, &sampleMask); |
| if (!excluded(VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT)) vk::CmdSetAlphaToCoverageEnableEXT(cmdBuffer, VK_FALSE); |
| if (!excluded(VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT)) vk::CmdSetAlphaToOneEnableEXT(cmdBuffer, VK_FALSE); |
| if (!excluded(VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT)) vk::CmdSetLogicOpEnableEXT(cmdBuffer, VK_FALSE); |
| VkBool32 colorBlendEnable = VK_FALSE; |
| if (!excluded(VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT)) vk::CmdSetColorBlendEnableEXT(cmdBuffer, 0u, 1u, &colorBlendEnable); |
| VkColorBlendEquationEXT colorBlendEquation = { |
| VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ONE, VK_BLEND_OP_ADD, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ONE, VK_BLEND_OP_ADD, |
| }; |
| if (!excluded(VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT)) |
| vk::CmdSetColorBlendEquationEXT(cmdBuffer, 0u, 1u, &colorBlendEquation); |
| VkColorComponentFlags colorWriteMask = |
| VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; |
| if (!excluded(VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT)) vk::CmdSetColorWriteMaskEXT(cmdBuffer, 0u, 1u, &colorWriteMask); |
| } |
| |
| TEST_F(PositiveShaderObject, CreateAndDestroyShaderObject) { |
| TEST_DESCRIPTION("Create and destroy shader object."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| |
| const auto spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| |
| VkShaderCreateInfoEXT createInfo = vku::InitStructHelper(); |
| createInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; |
| createInfo.codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| createInfo.codeSize = spv.size() * sizeof(spv[0]); |
| createInfo.pCode = spv.data(); |
| createInfo.pName = "main"; |
| |
| VkShaderEXT shader; |
| vk::CreateShadersEXT(m_device->handle(), 1u, &createInfo, nullptr, &shader); |
| vk::DestroyShaderEXT(m_device->handle(), shader, nullptr); |
| } |
| |
| TEST_F(PositiveShaderObject, BindShaderObject) { |
| TEST_DESCRIPTION("Use graphics shaders with unsupported command pool."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| |
| VkShaderStageFlagBits stage = VK_SHADER_STAGE_VERTEX_BIT; |
| const vkt::Shader vertShader(*m_device, stage, GLSLToSPV(stage, kVertexMinimalGlsl)); |
| |
| m_commandBuffer->begin(); |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 1u, &stage, &vertShader.handle()); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawWithVertAndFragShaderObjects) { |
| TEST_DESCRIPTION("Draw with only vertex and fragment shader objects bound."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| |
| InitDynamicRenderTarget(); |
| |
| const vkt::Shader vertShader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl)); |
| |
| const vkt::Shader fragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, |
| GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl)); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| SetDefaultDynamicStates(); |
| BindVertFragShader(vertShader, fragShader); |
| vk::CmdDraw(m_commandBuffer->handle(), 4, 1, 0, 0); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawWithVertAndFragBinaryShaderObjects) { |
| TEST_DESCRIPTION("Draw with binary vertex and fragment shader objects bound."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| if (IsPlatformMockICD()) { |
| GTEST_SKIP() << "Test not supported by MockICD"; |
| } |
| |
| InitDynamicRenderTarget(); |
| |
| const vkt::Shader vertShader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl)); |
| |
| const vkt::Shader fragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, |
| GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl)); |
| |
| size_t vertDataSize; |
| vk::GetShaderBinaryDataEXT(*m_device, vertShader.handle(), &vertDataSize, nullptr); |
| std::vector<uint8_t> vertData(vertDataSize); |
| vk::GetShaderBinaryDataEXT(*m_device, vertShader.handle(), &vertDataSize, vertData.data()); |
| |
| size_t fragDataSize; |
| vk::GetShaderBinaryDataEXT(*m_device, fragShader.handle(), &fragDataSize, nullptr); |
| std::vector<uint8_t> fragData(fragDataSize); |
| vk::GetShaderBinaryDataEXT(*m_device, fragShader.handle(), &fragDataSize, fragData.data()); |
| |
| vkt::Shader binaryVertShader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, vertData); |
| vkt::Shader binaryFragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, fragData); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| SetDefaultDynamicStates(); |
| BindVertFragShader(binaryVertShader, binaryFragShader); |
| vk::CmdDraw(m_commandBuffer->handle(), 4, 1, 0, 0); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, LinkedVertexAndFragmentShaders) { |
| TEST_DESCRIPTION("Create linked vertex and fragment shaders."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| |
| const auto vert_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| const auto frag_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| |
| VkShaderCreateInfoEXT createInfos[2]; |
| createInfos[0] = vku::InitStructHelper(); |
| createInfos[0].flags = VK_SHADER_CREATE_LINK_STAGE_BIT_EXT; |
| createInfos[0].stage = VK_SHADER_STAGE_VERTEX_BIT; |
| createInfos[0].nextStage = VK_SHADER_STAGE_FRAGMENT_BIT; |
| createInfos[0].codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| createInfos[0].codeSize = vert_spv.size() * sizeof(vert_spv[0]); |
| createInfos[0].pCode = vert_spv.data(); |
| createInfos[0].pName = "main"; |
| createInfos[1] = vku::InitStructHelper(); |
| createInfos[1].flags = VK_SHADER_CREATE_LINK_STAGE_BIT_EXT; |
| createInfos[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; |
| createInfos[1].codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| createInfos[1].codeSize = frag_spv.size() * sizeof(frag_spv[0]); |
| createInfos[1].pCode = frag_spv.data(); |
| createInfos[1].pName = "main"; |
| |
| VkShaderEXT shaders[2]; |
| vk::CreateShadersEXT(m_device->handle(), 2u, createInfos, nullptr, shaders); |
| |
| for (uint32_t i = 0; i < 2; ++i) { |
| vk::DestroyShaderEXT(m_device->handle(), shaders[i], nullptr); |
| } |
| } |
| |
| TEST_F(PositiveShaderObject, LinkedGraphicsShaders) { |
| TEST_DESCRIPTION("Create linked vertex and fragment shaders."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| |
| const auto vert_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| const auto tesc_spv = GLSLToSPV(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, kTessellationControlMinimalGlsl); |
| const auto tese_spv = GLSLToSPV(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, kTessellationEvalMinimalGlsl); |
| const auto geom_spv = GLSLToSPV(VK_SHADER_STAGE_GEOMETRY_BIT, kGeometryMinimalGlsl); |
| const auto frag_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| |
| VkShaderCreateInfoEXT createInfos[5]; |
| createInfos[0] = vku::InitStructHelper(); |
| createInfos[0].flags = VK_SHADER_CREATE_LINK_STAGE_BIT_EXT; |
| createInfos[0].stage = VK_SHADER_STAGE_VERTEX_BIT; |
| createInfos[0].nextStage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; |
| createInfos[0].codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| createInfos[0].codeSize = vert_spv.size() * sizeof(vert_spv[0]); |
| createInfos[0].pCode = vert_spv.data(); |
| createInfos[0].pName = "main"; |
| createInfos[1] = vku::InitStructHelper(); |
| createInfos[1].flags = VK_SHADER_CREATE_LINK_STAGE_BIT_EXT; |
| createInfos[1].stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; |
| createInfos[1].nextStage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; |
| createInfos[1].codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| createInfos[1].codeSize = tesc_spv.size() * sizeof(tesc_spv[0]); |
| createInfos[1].pCode = tesc_spv.data(); |
| createInfos[1].pName = "main"; |
| createInfos[2] = vku::InitStructHelper(); |
| createInfos[2].flags = VK_SHADER_CREATE_LINK_STAGE_BIT_EXT; |
| createInfos[2].stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; |
| createInfos[2].nextStage = VK_SHADER_STAGE_GEOMETRY_BIT; |
| createInfos[2].codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| createInfos[2].codeSize = tese_spv.size() * sizeof(tese_spv[0]); |
| createInfos[2].pCode = tese_spv.data(); |
| createInfos[2].pName = "main"; |
| createInfos[3] = vku::InitStructHelper(); |
| createInfos[3].flags = VK_SHADER_CREATE_LINK_STAGE_BIT_EXT; |
| createInfos[3].stage = VK_SHADER_STAGE_GEOMETRY_BIT; |
| createInfos[3].nextStage = VK_SHADER_STAGE_FRAGMENT_BIT; |
| createInfos[3].codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| createInfos[3].codeSize = geom_spv.size() * sizeof(geom_spv[0]); |
| createInfos[3].pCode = geom_spv.data(); |
| createInfos[3].pName = "main"; |
| createInfos[4] = vku::InitStructHelper(); |
| createInfos[4].flags = VK_SHADER_CREATE_LINK_STAGE_BIT_EXT; |
| createInfos[4].stage = VK_SHADER_STAGE_FRAGMENT_BIT; |
| createInfos[4].nextStage = 0u; |
| createInfos[4].codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| createInfos[4].codeSize = frag_spv.size() * sizeof(frag_spv[0]); |
| createInfos[4].pCode = frag_spv.data(); |
| createInfos[4].pName = "main"; |
| |
| VkShaderEXT shaders[5]; |
| vk::CreateShadersEXT(m_device->handle(), 5u, createInfos, nullptr, shaders); |
| |
| for (uint32_t i = 0; i < 5; ++i) { |
| vk::DestroyShaderEXT(m_device->handle(), shaders[i], nullptr); |
| } |
| } |
| |
| TEST_F(PositiveShaderObject, MissingCmdSetDepthBiasEnable) { |
| TEST_DESCRIPTION("Draw with shaders without setting depth bias enable."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| InitDynamicRenderTarget(); |
| |
| VkShaderStageFlagBits stages[] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT}; |
| const vkt::Shader vertShader(*m_device, stages[0], GLSLToSPV(stages[0], kVertexMinimalGlsl)); |
| const vkt::Shader fragShader(*m_device, stages[1], GLSLToSPV(stages[1], kFragmentMinimalGlsl)); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| SetDefaultDynamicStates({VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE}); |
| vk::CmdSetRasterizerDiscardEnableEXT(m_commandBuffer->handle(), VK_TRUE); |
| BindVertFragShader(vertShader, fragShader); |
| vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, VertFragShaderDraw) { |
| TEST_DESCRIPTION("Test drawing with a vertex and fragment shader"); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| |
| static const char vert_src[] = R"glsl( |
| #version 460 |
| void main() { |
| vec2 pos = vec2(float(gl_VertexIndex & 1), float((gl_VertexIndex >> 1) & 1)); |
| gl_Position = vec4(pos - 0.5f, 0.0f, 1.0f); |
| } |
| )glsl"; |
| |
| static const char frag_src[] = R"glsl( |
| #version 460 |
| layout(location = 0) out vec4 uFragColor; |
| void main(){ |
| uFragColor = vec4(0.2f, 0.4f, 0.6f, 0.8f); |
| } |
| )glsl"; |
| |
| VkShaderStageFlagBits shaderStages[] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT}; |
| |
| VkShaderStageFlagBits unusedShaderStages[] = {VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, |
| VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_GEOMETRY_BIT}; |
| |
| const vkt::Shader vertShader(*m_device, shaderStages[0], GLSLToSPV(shaderStages[0], vert_src)); |
| const vkt::Shader fragShader(*m_device, shaderStages[1], GLSLToSPV(shaderStages[1], frag_src)); |
| |
| VkShaderEXT shaders[] = {vertShader.handle(), fragShader.handle()}; |
| |
| vkt::Buffer buffer(*m_device, sizeof(float) * 4u, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, |
| VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| |
| VkImageCreateInfo imageInfo = vku::InitStructHelper(); |
| imageInfo.imageType = VK_IMAGE_TYPE_2D; |
| imageInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT; |
| imageInfo.extent = {static_cast<uint32_t>(m_width), static_cast<uint32_t>(m_height), 1}; |
| imageInfo.mipLevels = 1u; |
| imageInfo.arrayLayers = 1u; |
| imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; |
| imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; |
| imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| imageInfo.queueFamilyIndexCount = 0u; |
| imageInfo.pQueueFamilyIndices = nullptr; |
| imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| VkImageObj image(m_device); |
| image.init(&imageInfo); |
| VkImageView view = image.targetView(imageInfo.format); |
| |
| VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper(); |
| color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| color_attachment.imageView = view; |
| |
| VkRenderingInfo begin_rendering_info = vku::InitStructHelper(); |
| begin_rendering_info.renderArea.extent.width = static_cast<uint32_t>(m_width); |
| begin_rendering_info.renderArea.extent.height = static_cast<uint32_t>(m_height); |
| begin_rendering_info.layerCount = 1u; |
| begin_rendering_info.colorAttachmentCount = 1u; |
| begin_rendering_info.pColorAttachments = &color_attachment; |
| |
| auto vkCmdBeginRenderingKHR = |
| reinterpret_cast<PFN_vkCmdBeginRenderingKHR>(vk::GetDeviceProcAddr(device(), "vkCmdBeginRenderingKHR")); |
| auto vkCmdEndRenderingKHR = reinterpret_cast<PFN_vkCmdEndRenderingKHR>(vk::GetDeviceProcAddr(device(), "vkCmdEndRenderingKHR")); |
| |
| m_commandBuffer->begin(); |
| |
| { |
| VkImageMemoryBarrier imageMemoryBarrier = vku::InitStructHelper(); |
| imageMemoryBarrier.srcAccessMask = VK_ACCESS_NONE; |
| imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; |
| imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| imageMemoryBarrier.image = image.handle(); |
| imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| imageMemoryBarrier.subresourceRange.baseMipLevel = 0u; |
| imageMemoryBarrier.subresourceRange.levelCount = 1u; |
| imageMemoryBarrier.subresourceRange.baseArrayLayer = 0u; |
| imageMemoryBarrier.subresourceRange.layerCount = 1u; |
| vk::CmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, |
| &imageMemoryBarrier); |
| } |
| vkCmdBeginRenderingKHR(m_commandBuffer->handle(), &begin_rendering_info); |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 2u, shaderStages, shaders); |
| for (const auto &unusedShader : unusedShaderStages) { |
| VkShaderEXT null_shader = VK_NULL_HANDLE; |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 1u, &unusedShader, &null_shader); |
| } |
| SetDefaultDynamicStates(); |
| vk::CmdDraw(m_commandBuffer->handle(), 4, 1, 0, 0); |
| vkCmdEndRenderingKHR(m_commandBuffer->handle()); |
| |
| { |
| VkImageMemoryBarrier imageMemoryBarrier = vku::InitStructHelper(); |
| imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; |
| imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; |
| imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; |
| imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| imageMemoryBarrier.image = image.handle(); |
| imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| imageMemoryBarrier.subresourceRange.baseMipLevel = 0u; |
| imageMemoryBarrier.subresourceRange.levelCount = 1u; |
| imageMemoryBarrier.subresourceRange.baseArrayLayer = 0u; |
| imageMemoryBarrier.subresourceRange.layerCount = 1u; |
| vk::CmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, |
| VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &imageMemoryBarrier); |
| } |
| |
| VkBufferImageCopy copyRegion = {}; |
| copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| copyRegion.imageSubresource.mipLevel = 0u; |
| copyRegion.imageSubresource.baseArrayLayer = 0u; |
| copyRegion.imageSubresource.layerCount = 1u; |
| copyRegion.imageOffset.x = static_cast<int32_t>(m_width / 2) + 1; |
| copyRegion.imageOffset.y = static_cast<int32_t>(m_height / 2) + 1; |
| copyRegion.imageExtent.width = 1u; |
| copyRegion.imageExtent.height = 1u; |
| copyRegion.imageExtent.depth = 1u; |
| |
| vk::CmdCopyImageToBuffer(m_commandBuffer->handle(), image.handle(), VK_IMAGE_LAYOUT_GENERAL, buffer.handle(), 1u, ©Region); |
| |
| m_commandBuffer->end(); |
| |
| VkCommandBuffer commandBufferHandle = m_commandBuffer->handle(); |
| VkSubmitInfo submitInfo = vku::InitStructHelper(); |
| submitInfo.commandBufferCount = 1u; |
| submitInfo.pCommandBuffers = &commandBufferHandle; |
| vk::QueueSubmit(m_default_queue, 1, &submitInfo, VK_NULL_HANDLE); |
| vk::QueueWaitIdle(m_default_queue); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawWithAllGraphicsShaderStagesUsed) { |
| TEST_DESCRIPTION("Test drawing using all graphics shader"); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| VkPhysicalDeviceFeatures features; |
| GetPhysicalDeviceFeatures(&features); |
| if (!features.tessellationShader || !features.geometryShader) { |
| GTEST_SKIP() << "Required shaders not supported."; |
| } |
| |
| static const char vert_src[] = R"glsl( |
| #version 460 |
| void main() { |
| vec2 pos = vec2(float(gl_VertexIndex & 1), float((gl_VertexIndex >> 1) & 1)); |
| gl_Position = vec4(pos - 0.5f, 0.0f, 1.0f);; |
| } |
| )glsl"; |
| |
| static const char tesc_src[] = R"glsl( |
| #version 450 |
| layout(vertices = 4) out; |
| void main (void) { |
| if (gl_InvocationID == 0) { |
| gl_TessLevelInner[0] = 1.0; |
| gl_TessLevelInner[1] = 1.0; |
| gl_TessLevelOuter[0] = 1.0; |
| gl_TessLevelOuter[1] = 1.0; |
| gl_TessLevelOuter[2] = 1.0; |
| gl_TessLevelOuter[3] = 1.0; |
| } |
| gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; |
| } |
| )glsl"; |
| |
| static const char tese_src[] = R"glsl( |
| #version 450 |
| layout(quads, equal_spacing) in; |
| void main (void) { |
| float u = gl_TessCoord.x; |
| float v = gl_TessCoord.y; |
| float omu = 1.0f - u; |
| float omv = 1.0f - v; |
| gl_Position = omu * omv * gl_in[0].gl_Position + u * omv * gl_in[2].gl_Position + u * v * gl_in[3].gl_Position + omu * v * gl_in[1].gl_Position; |
| gl_Position.x *= 1.5f; |
| } |
| )glsl"; |
| |
| static const char geom_src[] = R"glsl( |
| #version 450 |
| layout(triangles) in; |
| layout(triangle_strip, max_vertices = 4) out; |
| |
| void main(void) |
| { |
| gl_Position = gl_in[0].gl_Position; |
| gl_Position.y *= 1.5f; |
| gl_Position.z = 0.5f; |
| EmitVertex(); |
| gl_Position = gl_in[1].gl_Position; |
| gl_Position.y *= 1.5f; |
| gl_Position.z = 0.5f; |
| EmitVertex(); |
| gl_Position = gl_in[2].gl_Position; |
| gl_Position.y *= 1.5f; |
| gl_Position.z = 0.5f; |
| EmitVertex(); |
| EndPrimitive(); |
| } |
| )glsl"; |
| |
| static const char frag_src[] = R"glsl( |
| #version 460 |
| layout(location = 0) out vec4 uFragColor; |
| void main(){ |
| uFragColor = vec4(0.2f, 0.4f, 0.6f, 0.8f); |
| } |
| )glsl"; |
| |
| VkShaderStageFlagBits shaderStages[] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, |
| VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_GEOMETRY_BIT, |
| VK_SHADER_STAGE_FRAGMENT_BIT}; |
| |
| std::vector<uint32_t> spv[5]; |
| spv[0] = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vert_src); |
| spv[1] = GLSLToSPV(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, tesc_src); |
| spv[2] = GLSLToSPV(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, tese_src); |
| spv[3] = GLSLToSPV(VK_SHADER_STAGE_GEOMETRY_BIT, geom_src); |
| spv[4] = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, frag_src); |
| |
| const vkt::Shader vertShader(*m_device, shaderStages[0], GLSLToSPV(shaderStages[0], vert_src)); |
| const vkt::Shader tescShader(*m_device, shaderStages[1], GLSLToSPV(shaderStages[1], tesc_src)); |
| const vkt::Shader teseShader(*m_device, shaderStages[2], GLSLToSPV(shaderStages[2], tese_src)); |
| const vkt::Shader geomShader(*m_device, shaderStages[3], GLSLToSPV(shaderStages[3], geom_src)); |
| const vkt::Shader fragShader(*m_device, shaderStages[4], GLSLToSPV(shaderStages[4], frag_src)); |
| |
| VkShaderEXT shaders[5] = {vertShader.handle(), tescShader.handle(), teseShader.handle(), geomShader.handle(), |
| fragShader.handle()}; |
| |
| VkImageCreateInfo imageInfo = vku::InitStructHelper(); |
| imageInfo.flags = 0; |
| imageInfo.imageType = VK_IMAGE_TYPE_2D; |
| imageInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT; |
| imageInfo.extent = {static_cast<uint32_t>(m_width), static_cast<uint32_t>(m_height), 1}; |
| imageInfo.mipLevels = 1u; |
| imageInfo.arrayLayers = 1u; |
| imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; |
| imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; |
| imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| imageInfo.queueFamilyIndexCount = 0u; |
| imageInfo.pQueueFamilyIndices = nullptr; |
| imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| VkImageObj image(m_device); |
| image.init(&imageInfo); |
| VkImageView view = image.targetView(imageInfo.format); |
| |
| VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper(); |
| color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| color_attachment.imageView = view; |
| |
| VkRenderingInfo begin_rendering_info = vku::InitStructHelper(); |
| begin_rendering_info.flags = 0u; |
| begin_rendering_info.renderArea.offset.x = 0; |
| begin_rendering_info.renderArea.offset.y = 0; |
| begin_rendering_info.renderArea.extent.width = static_cast<uint32_t>(m_width); |
| begin_rendering_info.renderArea.extent.height = static_cast<uint32_t>(m_height); |
| begin_rendering_info.layerCount = 1u; |
| begin_rendering_info.viewMask = 0x0; |
| begin_rendering_info.colorAttachmentCount = 1u; |
| begin_rendering_info.pColorAttachments = &color_attachment; |
| |
| auto vkCmdBeginRenderingKHR = |
| reinterpret_cast<PFN_vkCmdBeginRenderingKHR>(vk::GetDeviceProcAddr(device(), "vkCmdBeginRenderingKHR")); |
| auto vkCmdEndRenderingKHR = reinterpret_cast<PFN_vkCmdEndRenderingKHR>(vk::GetDeviceProcAddr(device(), "vkCmdEndRenderingKHR")); |
| |
| m_commandBuffer->begin(); |
| |
| { |
| VkImageMemoryBarrier imageMemoryBarrier = vku::InitStructHelper(); |
| imageMemoryBarrier.srcAccessMask = VK_ACCESS_NONE; |
| imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; |
| imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| imageMemoryBarrier.image = image.handle(); |
| imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| imageMemoryBarrier.subresourceRange.baseMipLevel = 0u; |
| imageMemoryBarrier.subresourceRange.levelCount = 1u; |
| imageMemoryBarrier.subresourceRange.baseArrayLayer = 0u; |
| imageMemoryBarrier.subresourceRange.layerCount = 1u; |
| vk::CmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, |
| &imageMemoryBarrier); |
| } |
| vkCmdBeginRenderingKHR(m_commandBuffer->handle(), &begin_rendering_info); |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 5u, shaderStages, shaders); |
| SetDefaultDynamicStates(); |
| vk::CmdDraw(m_commandBuffer->handle(), 4, 1, 0, 0); |
| vkCmdEndRenderingKHR(m_commandBuffer->handle()); |
| |
| m_commandBuffer->end(); |
| |
| VkCommandBuffer commandBufferHandle = m_commandBuffer->handle(); |
| VkSubmitInfo submitInfo = vku::InitStructHelper(); |
| submitInfo.commandBufferCount = 1u; |
| submitInfo.pCommandBuffers = &commandBufferHandle; |
| vk::QueueSubmit(m_default_queue, 1, &submitInfo, VK_NULL_HANDLE); |
| vk::QueueWaitIdle(m_default_queue); |
| } |
| |
| TEST_F(PositiveShaderObject, ComputeShader) { |
| TEST_DESCRIPTION("Test dispatching with compute shader"); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| |
| static const char comp_src[] = R"glsl( |
| #version 450 |
| layout(local_size_x=16, local_size_x=1, local_size_x=1) in; |
| layout(binding = 0) buffer Output { |
| uint values[16]; |
| } buffer_out; |
| |
| void main() { |
| buffer_out.values[gl_LocalInvocationID.x] = gl_LocalInvocationID.x; |
| } |
| )glsl"; |
| |
| VkShaderStageFlagBits shaderStages[] = {VK_SHADER_STAGE_COMPUTE_BIT}; |
| |
| vkt::Buffer storageBuffer(*m_device, sizeof(float), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, |
| VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); |
| |
| VkDescriptorPoolSize ds_type_count = {}; |
| ds_type_count.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; |
| ds_type_count.descriptorCount = 1; |
| |
| VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper(); |
| ds_pool_ci.maxSets = 1; |
| ds_pool_ci.poolSizeCount = 1; |
| ds_pool_ci.flags = 0; |
| ds_pool_ci.pPoolSizes = &ds_type_count; |
| |
| vkt::DescriptorPool ds_pool(*m_device, ds_pool_ci); |
| |
| VkDescriptorSetLayoutBinding dsl_binding = {}; |
| dsl_binding.binding = 0; |
| dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; |
| dsl_binding.descriptorCount = 1; |
| dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; |
| dsl_binding.pImmutableSamplers = nullptr; |
| |
| const vkt::DescriptorSetLayout ds_layout(*m_device, {dsl_binding}); |
| |
| VkDescriptorSet descriptorSet; |
| VkDescriptorSetAllocateInfo alloc_info = vku::InitStructHelper(); |
| alloc_info.descriptorSetCount = 1; |
| alloc_info.descriptorPool = ds_pool.handle(); |
| alloc_info.pSetLayouts = &ds_layout.handle(); |
| vk::AllocateDescriptorSets(m_device->device(), &alloc_info, &descriptorSet); |
| |
| VkDescriptorBufferInfo storage_buffer_info = {storageBuffer.handle(), 0, sizeof(uint32_t)}; |
| |
| VkWriteDescriptorSet descriptorWrite = vku::InitStructHelper(); |
| descriptorWrite.dstSet = descriptorSet; |
| descriptorWrite.dstBinding = 0; |
| descriptorWrite.descriptorCount = 1; |
| descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; |
| descriptorWrite.pBufferInfo = &storage_buffer_info; |
| |
| vk::UpdateDescriptorSets(m_device->handle(), 1u, &descriptorWrite, 0u, nullptr); |
| |
| const vkt::DescriptorSetLayout descriptor_set_layout(*m_device, {dsl_binding}); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set_layout}); |
| |
| VkDescriptorSetLayout descriptorSetLayout = descriptor_set_layout.handle(); |
| |
| const vkt::Shader compShader(*m_device, shaderStages[0], GLSLToSPV(shaderStages[0], comp_src), &descriptorSetLayout); |
| |
| m_commandBuffer->begin(); |
| |
| vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout.handle(), 0u, 1u, |
| &descriptorSet, 0u, nullptr); |
| |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 1u, shaderStages, &compShader.handle()); |
| // setdefaul(vertexBuffer.handle(), false); |
| vk::CmdDispatch(m_commandBuffer->handle(), 1, 1, 1); |
| |
| m_commandBuffer->end(); |
| |
| VkCommandBuffer commandBufferHandle = m_commandBuffer->handle(); |
| VkSubmitInfo submitInfo = vku::InitStructHelper(); |
| submitInfo.commandBufferCount = 1u; |
| submitInfo.pCommandBuffers = &commandBufferHandle; |
| vk::QueueSubmit(m_default_queue, 1, &submitInfo, VK_NULL_HANDLE); |
| vk::QueueWaitIdle(m_default_queue); |
| } |
| |
| TEST_F(PositiveShaderObject, TaskMeshShadersDraw) { |
| TEST_DESCRIPTION("Test drawing using task and mesh shaders"); |
| |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| VkPhysicalDeviceMaintenance4Features maintenance_4_features = vku::InitStructHelper(); |
| VkPhysicalDeviceMeshShaderFeaturesEXT mesh_shader_features = vku::InitStructHelper(&maintenance_4_features); |
| RETURN_IF_SKIP(InitBasicShaderObject(&mesh_shader_features, VK_API_VERSION_1_3)) |
| |
| VkPhysicalDeviceFeatures features; |
| GetPhysicalDeviceFeatures(&features); |
| |
| if (!mesh_shader_features.taskShader || !mesh_shader_features.meshShader) { |
| GTEST_SKIP() << "Task and mesh shaders are required"; |
| } |
| if (!maintenance_4_features.maintenance4) { |
| GTEST_SKIP() << "maintenance4 not supported"; |
| } |
| static const char task_src[] = R"glsl( |
| #version 450 |
| #extension GL_EXT_mesh_shader : require |
| layout (local_size_x=1, local_size_y=1, local_size_z=1) in; |
| void main () { |
| EmitMeshTasksEXT(1u, 1u, 1u); |
| } |
| )glsl"; |
| |
| static const char mesh_src[] = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : require |
| layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; |
| layout(max_vertices = 3) out; |
| layout(max_primitives = 1) out; |
| layout(triangles) out; |
| void main() { |
| SetMeshOutputsEXT(3, 1); |
| gl_MeshVerticesEXT[0].gl_Position = vec4(-1.0, -1.0, 0.0f, 1.0f); |
| gl_MeshVerticesEXT[1].gl_Position = vec4( 3.0, -1.0, 0.0f, 1.0f); |
| gl_MeshVerticesEXT[2].gl_Position = vec4(-1.0, 3.0, 0.0f, 1.0f); |
| gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2); |
| } |
| )glsl"; |
| |
| static const char frag_src[] = R"glsl( |
| #version 460 |
| layout(location = 0) out vec4 uFragColor; |
| void main(){ |
| uFragColor = vec4(0.2f, 0.4f, 0.6f, 0.8f); |
| } |
| )glsl"; |
| |
| VkShaderStageFlagBits shaderStages[] = {VK_SHADER_STAGE_TASK_BIT_EXT, VK_SHADER_STAGE_MESH_BIT_EXT, |
| VK_SHADER_STAGE_FRAGMENT_BIT}; |
| |
| const vkt::Shader taskShader(*m_device, shaderStages[0], |
| GLSLToSPV(shaderStages[0], task_src, "main", nullptr, SPV_ENV_VULKAN_1_3)); |
| const vkt::Shader meshShader(*m_device, shaderStages[1], |
| GLSLToSPV(shaderStages[1], mesh_src, "main", nullptr, SPV_ENV_VULKAN_1_3)); |
| const vkt::Shader fragShader(*m_device, shaderStages[2], GLSLToSPV(shaderStages[2], frag_src)); |
| |
| VkShaderEXT shaders[3] = {taskShader.handle(), meshShader.handle(), fragShader.handle()}; |
| |
| VkImageCreateInfo imageInfo = vku::InitStructHelper(); |
| imageInfo.flags = 0; |
| imageInfo.imageType = VK_IMAGE_TYPE_2D; |
| imageInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT; |
| imageInfo.extent = {static_cast<uint32_t>(m_width), static_cast<uint32_t>(m_height), 1}; |
| imageInfo.mipLevels = 1u; |
| imageInfo.arrayLayers = 1u; |
| imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; |
| imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; |
| imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| imageInfo.queueFamilyIndexCount = 0u; |
| imageInfo.pQueueFamilyIndices = nullptr; |
| imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| VkImageObj image(m_device); |
| image.init(&imageInfo); |
| VkImageView view = image.targetView(imageInfo.format); |
| |
| VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper(); |
| color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| color_attachment.imageView = view; |
| |
| VkRenderingInfo begin_rendering_info = vku::InitStructHelper(); |
| begin_rendering_info.flags = 0u; |
| begin_rendering_info.renderArea.offset.x = 0; |
| begin_rendering_info.renderArea.offset.y = 0; |
| begin_rendering_info.renderArea.extent.width = static_cast<uint32_t>(m_width); |
| begin_rendering_info.renderArea.extent.height = static_cast<uint32_t>(m_height); |
| begin_rendering_info.layerCount = 1u; |
| begin_rendering_info.viewMask = 0x0; |
| begin_rendering_info.colorAttachmentCount = 1u; |
| begin_rendering_info.pColorAttachments = &color_attachment; |
| |
| auto vkCmdBeginRenderingKHR = |
| reinterpret_cast<PFN_vkCmdBeginRenderingKHR>(vk::GetDeviceProcAddr(device(), "vkCmdBeginRenderingKHR")); |
| auto vkCmdEndRenderingKHR = reinterpret_cast<PFN_vkCmdEndRenderingKHR>(vk::GetDeviceProcAddr(device(), "vkCmdEndRenderingKHR")); |
| auto vkCmdDrawMeshTasksEXT = |
| reinterpret_cast<PFN_vkCmdDrawMeshTasksEXT>(vk::GetDeviceProcAddr(device(), "vkCmdDrawMeshTasksEXT")); |
| |
| m_commandBuffer->begin(); |
| |
| { |
| VkImageMemoryBarrier imageMemoryBarrier = vku::InitStructHelper(); |
| imageMemoryBarrier.srcAccessMask = VK_ACCESS_NONE; |
| imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; |
| imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
| imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| imageMemoryBarrier.image = image.handle(); |
| imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| imageMemoryBarrier.subresourceRange.baseMipLevel = 0u; |
| imageMemoryBarrier.subresourceRange.levelCount = 1u; |
| imageMemoryBarrier.subresourceRange.baseArrayLayer = 0u; |
| imageMemoryBarrier.subresourceRange.layerCount = 1u; |
| vk::CmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, |
| &imageMemoryBarrier); |
| } |
| vkCmdBeginRenderingKHR(m_commandBuffer->handle(), &begin_rendering_info); |
| std::vector<VkShaderStageFlagBits> nullStages = {VK_SHADER_STAGE_VERTEX_BIT}; |
| if (features.tessellationShader) { |
| nullStages.push_back(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT); |
| nullStages.push_back(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT); |
| } |
| if (features.geometryShader) { |
| nullStages.push_back(VK_SHADER_STAGE_GEOMETRY_BIT); |
| } |
| for (const auto stage : nullStages) { |
| VkShaderEXT nullShader = VK_NULL_HANDLE; |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 1u, &stage, &nullShader); |
| } |
| |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 3u, shaderStages, shaders); |
| SetDefaultDynamicStates(); |
| vkCmdDrawMeshTasksEXT(m_commandBuffer->handle(), 1, 1, 1); |
| vkCmdEndRenderingKHR(m_commandBuffer->handle()); |
| |
| m_commandBuffer->end(); |
| |
| VkCommandBuffer commandBufferHandle = m_commandBuffer->handle(); |
| VkSubmitInfo submitInfo = vku::InitStructHelper(); |
| submitInfo.commandBufferCount = 1u; |
| submitInfo.pCommandBuffers = &commandBufferHandle; |
| vk::QueueSubmit(m_default_queue, 1, &submitInfo, VK_NULL_HANDLE); |
| vk::QueueWaitIdle(m_default_queue); |
| } |
| |
| TEST_F(PositiveShaderObject, FailCreateShaders) { |
| TEST_DESCRIPTION("Test failing to create shaders"); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| if (IsPlatformMockICD()) { |
| GTEST_SKIP() << "Test not supported by MockICD"; |
| } |
| |
| static const char vert_src[] = R"glsl( |
| #version 460 |
| void main() { |
| vec2 pos = vec2(float(gl_VertexIndex & 1), float((gl_VertexIndex >> 1) & 1)); |
| gl_Position = vec4(pos - 0.5f, 0.0f, 1.0f);; |
| } |
| )glsl"; |
| |
| static const char tesc_src[] = R"glsl( |
| #version 450 |
| layout(vertices = 4) out; |
| void main (void) { |
| if (gl_InvocationID == 0) { |
| gl_TessLevelInner[0] = 1.0; |
| gl_TessLevelInner[1] = 1.0; |
| gl_TessLevelOuter[0] = 1.0; |
| gl_TessLevelOuter[1] = 1.0; |
| gl_TessLevelOuter[2] = 1.0; |
| gl_TessLevelOuter[3] = 1.0; |
| } |
| gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; |
| } |
| )glsl"; |
| |
| static const char tese_src[] = R"glsl( |
| #version 450 |
| layout(quads, equal_spacing) in; |
| void main (void) { |
| float u = gl_TessCoord.x; |
| float v = gl_TessCoord.y; |
| float omu = 1.0f - u; |
| float omv = 1.0f - v; |
| gl_Position = omu * omv * gl_in[0].gl_Position + u * omv * gl_in[2].gl_Position + u * v * gl_in[3].gl_Position + omu * v * gl_in[1].gl_Position; |
| gl_Position.x *= 1.5f; |
| } |
| )glsl"; |
| |
| static const char geom_src[] = R"glsl( |
| #version 450 |
| layout(triangles) in; |
| layout(triangle_strip, max_vertices = 4) out; |
| |
| void main(void) |
| { |
| gl_Position = gl_in[0].gl_Position; |
| gl_Position.y *= 1.5f; |
| gl_Position.z = 0.5f; |
| EmitVertex(); |
| gl_Position = gl_in[1].gl_Position; |
| gl_Position.y *= 1.5f; |
| gl_Position.z = 0.5f; |
| EmitVertex(); |
| gl_Position = gl_in[2].gl_Position; |
| gl_Position.y *= 1.5f; |
| gl_Position.z = 0.5f; |
| EmitVertex(); |
| EndPrimitive(); |
| } |
| )glsl"; |
| |
| static const char frag_src[] = R"glsl( |
| #version 460 |
| layout(location = 0) out vec4 uFragColor; |
| void main(){ |
| uFragColor = vec4(0.2f, 0.4f, 0.6f, 0.8f); |
| } |
| )glsl"; |
| |
| constexpr uint32_t stages_count = 5; |
| constexpr uint32_t shaders_count = 20; |
| constexpr uint32_t fail_index = 15; |
| |
| VkShaderStageFlagBits shaderStages[stages_count] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, |
| VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_GEOMETRY_BIT, |
| VK_SHADER_STAGE_FRAGMENT_BIT}; |
| |
| std::vector<uint32_t> spv[stages_count]; |
| spv[0] = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vert_src); |
| spv[1] = GLSLToSPV(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, tesc_src); |
| spv[2] = GLSLToSPV(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, tese_src); |
| spv[3] = GLSLToSPV(VK_SHADER_STAGE_GEOMETRY_BIT, geom_src); |
| spv[4] = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, frag_src); |
| |
| VkShaderEXT shaders[shaders_count]; |
| |
| VkShaderCreateInfoEXT createInfos[shaders_count]; |
| for (uint32_t i = 0; i < shaders_count; ++i) { |
| createInfos[i] = vku::InitStructHelper(); |
| createInfos[i].stage = shaderStages[i % stages_count]; |
| createInfos[i].codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| createInfos[i].codeSize = spv[i % stages_count].size() * sizeof(uint32_t); |
| createInfos[i].pCode = spv[i % stages_count].data(); |
| createInfos[i].pName = "main"; |
| } |
| |
| // Binary code must be aligned to 16 bytes |
| std::vector<uint8_t> garbage(createInfos[fail_index].codeSize + 16); |
| auto pCode = reinterpret_cast<std::uintptr_t>(garbage.data()); |
| while (pCode % 16 != 0) { |
| pCode += 1; |
| } |
| std::memcpy(reinterpret_cast<void *>(pCode), createInfos[fail_index].pCode, createInfos[fail_index].codeSize); |
| createInfos[fail_index].codeType = VK_SHADER_CODE_TYPE_BINARY_EXT; |
| createInfos[fail_index].pCode = reinterpret_cast<const void *>(pCode); |
| |
| VkResult res = vk::CreateShadersEXT(m_device->handle(), 20u, createInfos, nullptr, shaders); |
| ASSERT_EQ(res, VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT); |
| |
| for (uint32_t i = 0; i < shaders_count; ++i) { |
| if (i < fail_index) { |
| vk::DestroyShaderEXT(m_device->handle(), shaders[i], nullptr); |
| } |
| } |
| } |
| |
| TEST_F(PositiveShaderObject, DrawMinimalDynamicStates) { |
| TEST_DESCRIPTION("Draw with only required dynamic states set."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject(nullptr, VK_API_VERSION_1_1, false)) |
| |
| InitDynamicRenderTarget(); |
| |
| const vkt::Shader vertShader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl)); |
| |
| const vkt::Shader fragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, |
| GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl)); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| |
| VkViewport viewport = {0, 0, static_cast<float>(m_width), static_cast<float>(m_height), 0.0f, 1.0f}; |
| VkRect2D scissor = {{0, 0}, {m_width, m_height}}; |
| vk::CmdSetViewportWithCountEXT(m_commandBuffer->handle(), 1u, &viewport); |
| vk::CmdSetScissorWithCountEXT(m_commandBuffer->handle(), 1u, &scissor); |
| vk::CmdSetRasterizerDiscardEnableEXT(m_commandBuffer->handle(), VK_FALSE); |
| vk::CmdSetStencilTestEnableEXT(m_commandBuffer->handle(), VK_FALSE); |
| vk::CmdSetPolygonModeEXT(m_commandBuffer->handle(), VK_POLYGON_MODE_FILL); |
| vk::CmdSetRasterizationSamplesEXT(m_commandBuffer->handle(), VK_SAMPLE_COUNT_1_BIT); |
| VkSampleMask sampleMask = 1u; |
| vk::CmdSetSampleMaskEXT(m_commandBuffer->handle(), VK_SAMPLE_COUNT_1_BIT, &sampleMask); |
| vk::CmdSetAlphaToCoverageEnableEXT(m_commandBuffer->handle(), VK_FALSE); |
| vk::CmdSetCullModeEXT(m_commandBuffer->handle(), VK_CULL_MODE_NONE); |
| vk::CmdSetDepthTestEnableEXT(m_commandBuffer->handle(), VK_FALSE); |
| vk::CmdSetDepthWriteEnableEXT(m_commandBuffer->handle(), VK_FALSE); |
| vk::CmdSetDepthBoundsTestEnableEXT(m_commandBuffer->handle(), VK_FALSE); |
| vk::CmdSetDepthBiasEnableEXT(m_commandBuffer->handle(), VK_FALSE); |
| vk::CmdSetPrimitiveTopologyEXT(m_commandBuffer->handle(), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); |
| vk::CmdSetVertexInputEXT(m_commandBuffer->handle(), 0u, nullptr, 0u, nullptr); |
| vk::CmdSetPrimitiveRestartEnableEXT(m_commandBuffer->handle(), VK_FALSE); |
| VkBool32 colorBlendEnable = VK_FALSE; |
| vk::CmdSetColorBlendEnableEXT(m_commandBuffer->handle(), 0u, 1u, &colorBlendEnable); |
| VkColorComponentFlags colorWriteMask = |
| VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; |
| vk::CmdSetColorWriteMaskEXT(m_commandBuffer->handle(), 0u, 1u, &colorWriteMask); |
| |
| BindVertFragShader(vertShader, fragShader); |
| vk::CmdDraw(m_commandBuffer->handle(), 4, 1, 0, 0); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawMinimalDynamicStatesRasterizationDisabled) { |
| TEST_DESCRIPTION("Draw with only required dynamic states set."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject(nullptr, VK_API_VERSION_1_1, false)) |
| |
| InitDynamicRenderTarget(); |
| |
| const vkt::Shader vertShader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl)); |
| |
| const vkt::Shader fragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, |
| GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl)); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| |
| VkViewport viewport = {0, 0, static_cast<float>(m_width), static_cast<float>(m_height), 0.0f, 1.0f}; |
| VkRect2D scissor = {{0, 0}, {m_width, m_height}}; |
| vk::CmdSetViewportWithCountEXT(m_commandBuffer->handle(), 1u, &viewport); |
| vk::CmdSetScissorWithCountEXT(m_commandBuffer->handle(), 1u, &scissor); |
| vk::CmdSetRasterizerDiscardEnableEXT(m_commandBuffer->handle(), VK_TRUE); |
| vk::CmdSetStencilTestEnableEXT(m_commandBuffer->handle(), VK_FALSE); |
| vk::CmdSetPrimitiveTopologyEXT(m_commandBuffer->handle(), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); |
| vk::CmdSetVertexInputEXT(m_commandBuffer->handle(), 0u, nullptr, 0u, nullptr); |
| vk::CmdSetPrimitiveRestartEnableEXT(m_commandBuffer->handle(), VK_FALSE); |
| |
| BindVertFragShader(vertShader, fragShader); |
| vk::CmdDraw(m_commandBuffer->handle(), 4, 1, 0, 0); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, ShadersDescriptorSets) { |
| TEST_DESCRIPTION("Draw with shaders using multiple descriptor sets."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| InitDynamicRenderTarget(); |
| |
| OneOffDescriptorSet vert_descriptor_set(m_device, |
| { |
| {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr}, |
| }); |
| OneOffDescriptorSet frag_descriptor_set( |
| m_device, { |
| {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}, |
| }); |
| |
| vkt::PipelineLayout pipeline_layout(*m_device, {&vert_descriptor_set.layout_, &frag_descriptor_set.layout_}); |
| |
| static const char vert_src[] = R"glsl( |
| #version 460 |
| layout(location = 0) out vec2 uv; |
| layout(set = 0, binding = 0) buffer Buffer { |
| vec4 pos; |
| } buf; |
| void main() { |
| uv = vec2(gl_VertexIndex & 1, (gl_VertexIndex >> 1) & 1); |
| gl_Position = vec4(buf.pos); |
| } |
| )glsl"; |
| |
| static const char frag_src[] = R"glsl( |
| #version 460 |
| layout(set = 1, binding = 0) uniform sampler2D s; |
| layout(location = 0) in vec2 uv; |
| layout(location = 0) out vec4 uFragColor; |
| void main(){ |
| uFragColor = texture(s, uv); |
| } |
| )glsl"; |
| |
| const auto vert_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vert_src); |
| const auto frag_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, frag_src); |
| |
| VkDescriptorSetLayout descriptor_set_layouts[] = {vert_descriptor_set.layout_.handle(), frag_descriptor_set.layout_.handle()}; |
| |
| VkShaderCreateInfoEXT vert_create_info = vku::InitStructHelper(); |
| vert_create_info.stage = VK_SHADER_STAGE_VERTEX_BIT; |
| vert_create_info.codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| vert_create_info.codeSize = vert_spv.size() * sizeof(vert_spv[0]); |
| vert_create_info.pCode = vert_spv.data(); |
| vert_create_info.pName = "main"; |
| vert_create_info.setLayoutCount = 2u; |
| vert_create_info.pSetLayouts = descriptor_set_layouts; |
| |
| VkShaderCreateInfoEXT frag_create_info = vku::InitStructHelper(); |
| frag_create_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; |
| frag_create_info.codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| frag_create_info.codeSize = frag_spv.size() * sizeof(frag_spv[0]); |
| frag_create_info.pCode = frag_spv.data(); |
| frag_create_info.pName = "main"; |
| frag_create_info.setLayoutCount = 2u; |
| frag_create_info.pSetLayouts = descriptor_set_layouts; |
| |
| const vkt::Shader vertShader(*m_device, vert_create_info); |
| const vkt::Shader fragShader(*m_device, frag_create_info); |
| |
| vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
| vert_descriptor_set.WriteDescriptorBufferInfo(0, buffer.handle(), 0, 32, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| vert_descriptor_set.UpdateDescriptorSets(); |
| |
| auto image_ci = |
| VkImageObj::ImageCreateInfo2D(64, 64, 1, 2, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_TILING_OPTIMAL); |
| VkImageObj image(m_device); |
| image.Init(image_ci); |
| VkImageView view = image.targetView(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 1, 1); |
| |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| vkt::Sampler sampler(*m_device, sampler_info); |
| |
| frag_descriptor_set.WriteDescriptorImageInfo(0, view, sampler.handle()); |
| frag_descriptor_set.UpdateDescriptorSets(); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| SetDefaultDynamicStates(); |
| BindVertFragShader(vertShader, fragShader); |
| vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0u, 1u, |
| &vert_descriptor_set.set_, 0u, nullptr); |
| vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 1u, 1u, |
| &frag_descriptor_set.set_, 0u, nullptr); |
| vk::CmdDraw(m_commandBuffer->handle(), 4, 1, 0, 0); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, MultiplePushConstants) { |
| TEST_DESCRIPTION("Draw with shaders using multiple push constants."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| InitDynamicRenderTarget(); |
| |
| static const char vert_src[] = R"glsl( |
| #version 460 |
| layout (push_constant) uniform constants { |
| int pos; |
| } pushConst; |
| void main() { |
| gl_Position = vec4(pushConst.pos); |
| } |
| )glsl"; |
| |
| static const char frag_src[] = R"glsl( |
| #version 460 |
| layout (push_constant) uniform constants { |
| layout(offset = 4) float c; |
| } pushConst; |
| layout(location = 0) out vec4 uFragColor; |
| void main(){ |
| uFragColor = vec4(pushConst.c); |
| } |
| )glsl"; |
| |
| const auto vert_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vert_src); |
| const auto frag_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, frag_src); |
| |
| VkPushConstantRange push_constant_ranges[2]; |
| push_constant_ranges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; |
| push_constant_ranges[0].offset = 0u; |
| push_constant_ranges[0].size = sizeof(int); |
| push_constant_ranges[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; |
| push_constant_ranges[1].offset = sizeof(int); |
| push_constant_ranges[1].size = sizeof(float); |
| vkt::PipelineLayout pipeline_layout(*m_device, {}, {push_constant_ranges[0], push_constant_ranges[1]}); |
| |
| VkShaderCreateInfoEXT vert_create_info = vku::InitStructHelper(); |
| vert_create_info.stage = VK_SHADER_STAGE_VERTEX_BIT; |
| vert_create_info.codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| vert_create_info.codeSize = vert_spv.size() * sizeof(vert_spv[0]); |
| vert_create_info.pCode = vert_spv.data(); |
| vert_create_info.pName = "main"; |
| vert_create_info.pushConstantRangeCount = 2u; |
| vert_create_info.pPushConstantRanges = push_constant_ranges; |
| |
| VkShaderCreateInfoEXT frag_create_info = vku::InitStructHelper(); |
| frag_create_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; |
| frag_create_info.codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| frag_create_info.codeSize = frag_spv.size() * sizeof(frag_spv[0]); |
| frag_create_info.pCode = frag_spv.data(); |
| frag_create_info.pName = "main"; |
| frag_create_info.pushConstantRangeCount = 2u; |
| frag_create_info.pPushConstantRanges = push_constant_ranges; |
| |
| const vkt::Shader vertShader(*m_device, vert_create_info); |
| const vkt::Shader fragShader(*m_device, frag_create_info); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| |
| int pos = 1; |
| vk::CmdPushConstants(m_commandBuffer->handle(), pipeline_layout.handle(), VK_SHADER_STAGE_VERTEX_BIT, 0u, sizeof(int), &pos); |
| float color = 1.0f; |
| vk::CmdPushConstants(m_commandBuffer->handle(), pipeline_layout.handle(), VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(int), |
| sizeof(float), &color); |
| |
| SetDefaultDynamicStates(); |
| BindVertFragShader(vertShader, fragShader); |
| vk::CmdDraw(m_commandBuffer->handle(), 4, 1, 0, 0); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, MultipleSpecializationConstants) { |
| TEST_DESCRIPTION("Draw with shaders using multiple specialization constants."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| InitDynamicRenderTarget(); |
| |
| static const char vert_src[] = R"glsl( |
| #version 460 |
| layout (constant_id = 0) const int pos = 1; |
| void main() { |
| gl_Position = vec4(pos); |
| } |
| )glsl"; |
| |
| static const char frag_src[] = R"glsl( |
| #version 460 |
| layout (constant_id = 1) const float c = 0.0f; |
| layout(location = 0) out vec4 uFragColor; |
| void main(){ |
| uFragColor = vec4(c); |
| } |
| )glsl"; |
| |
| const auto vert_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vert_src); |
| const auto frag_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, frag_src); |
| |
| VkSpecializationMapEntry map_entries[2]; |
| map_entries[0].constantID = 0u; |
| map_entries[0].offset = 0u; |
| map_entries[0].size = sizeof(int); |
| map_entries[1].constantID = 1u; |
| map_entries[1].offset = sizeof(int); |
| map_entries[1].size = sizeof(float); |
| |
| struct Data { |
| int pos = 0u; |
| float color = 1.0f; |
| } data; |
| |
| VkSpecializationInfo specialization_info; |
| specialization_info.mapEntryCount = 2; |
| specialization_info.pMapEntries = map_entries; |
| specialization_info.dataSize = sizeof(int) + sizeof(float); |
| specialization_info.pData = &data; |
| |
| VkShaderCreateInfoEXT vert_create_info = vku::InitStructHelper(); |
| vert_create_info.stage = VK_SHADER_STAGE_VERTEX_BIT; |
| vert_create_info.codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| vert_create_info.codeSize = vert_spv.size() * sizeof(vert_spv[0]); |
| vert_create_info.pCode = vert_spv.data(); |
| vert_create_info.pName = "main"; |
| vert_create_info.pSpecializationInfo = &specialization_info; |
| |
| VkShaderCreateInfoEXT frag_create_info = vku::InitStructHelper(); |
| frag_create_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; |
| frag_create_info.codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| frag_create_info.codeSize = frag_spv.size() * sizeof(frag_spv[0]); |
| frag_create_info.pCode = frag_spv.data(); |
| frag_create_info.pName = "main"; |
| frag_create_info.pSpecializationInfo = &specialization_info; |
| |
| const vkt::Shader vertShader(*m_device, vert_create_info); |
| const vkt::Shader fragShader(*m_device, frag_create_info); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| |
| SetDefaultDynamicStates(); |
| BindVertFragShader(vertShader, fragShader); |
| vk::CmdDraw(m_commandBuffer->handle(), 4, 1, 0, 0); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, IndirectDraw) { |
| TEST_DESCRIPTION("Draw with all 5 shaders stages using indirect draw and seconary command buffers."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| InitDynamicRenderTarget(); |
| |
| static const char vert_src[] = R"glsl( |
| #version 460 |
| void main() { |
| vec2 pos = vec2(float(gl_VertexIndex & 1), float((gl_VertexIndex >> 1) & 1)); |
| gl_Position = vec4(pos - 0.5f, 0.0f, 1.0f);; |
| } |
| )glsl"; |
| |
| static const char tesc_src[] = R"glsl( |
| #version 450 |
| layout(vertices = 4) out; |
| void main (void) { |
| if (gl_InvocationID == 0) { |
| gl_TessLevelInner[0] = 1.0; |
| gl_TessLevelInner[1] = 1.0; |
| gl_TessLevelOuter[0] = 1.0; |
| gl_TessLevelOuter[1] = 1.0; |
| gl_TessLevelOuter[2] = 1.0; |
| gl_TessLevelOuter[3] = 1.0; |
| } |
| gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; |
| } |
| )glsl"; |
| |
| static const char tese_src[] = R"glsl( |
| #version 450 |
| layout(quads, equal_spacing) in; |
| void main (void) { |
| float u = gl_TessCoord.x; |
| float v = gl_TessCoord.y; |
| float omu = 1.0f - u; |
| float omv = 1.0f - v; |
| gl_Position = omu * omv * gl_in[0].gl_Position + u * omv * gl_in[2].gl_Position + u * v * gl_in[3].gl_Position + omu * v * gl_in[1].gl_Position; |
| gl_Position.x *= 1.5f; |
| } |
| )glsl"; |
| |
| static const char geom_src[] = R"glsl( |
| #version 450 |
| layout(triangles) in; |
| layout(triangle_strip, max_vertices = 4) out; |
| |
| void main(void) |
| { |
| gl_Position = gl_in[0].gl_Position; |
| gl_Position.y *= 1.5f; |
| gl_Position.z = 0.5f; |
| EmitVertex(); |
| gl_Position = gl_in[1].gl_Position; |
| gl_Position.y *= 1.5f; |
| gl_Position.z = 0.5f; |
| EmitVertex(); |
| gl_Position = gl_in[2].gl_Position; |
| gl_Position.y *= 1.5f; |
| gl_Position.z = 0.5f; |
| EmitVertex(); |
| EndPrimitive(); |
| } |
| )glsl"; |
| |
| static const char frag_src[] = R"glsl( |
| #version 460 |
| layout(location = 0) out vec4 uFragColor; |
| void main(){ |
| uFragColor = vec4(0.2f, 0.4f, 0.6f, 0.8f); |
| } |
| )glsl"; |
| |
| const vkt::Shader vertShader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vert_src)); |
| const vkt::Shader tescShader(*m_device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, |
| GLSLToSPV(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, tesc_src)); |
| const vkt::Shader teseShader(*m_device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, |
| GLSLToSPV(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, tese_src)); |
| const vkt::Shader geomShader(*m_device, VK_SHADER_STAGE_GEOMETRY_BIT, GLSLToSPV(VK_SHADER_STAGE_GEOMETRY_BIT, geom_src)); |
| const vkt::Shader fragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, frag_src)); |
| |
| vkt::Buffer indirect_buffer(*m_device, 32, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| |
| SetDefaultDynamicStates(); |
| |
| const VkShaderStageFlagBits stages[] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, |
| VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_GEOMETRY_BIT, |
| VK_SHADER_STAGE_FRAGMENT_BIT}; |
| const VkShaderEXT shaders[] = {vertShader.handle(), tescShader.handle(), teseShader.handle(), geomShader.handle(), |
| fragShader.handle()}; |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 5u, stages, shaders); |
| |
| vk::CmdDrawIndirect(m_commandBuffer->handle(), indirect_buffer.handle(), 0u, 1u, 0u); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawInSecondaryCommandBuffers) { |
| TEST_DESCRIPTION("Draw in secondary command buffers."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| |
| InitDynamicRenderTarget(); |
| |
| const vkt::Shader vertShader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl)); |
| |
| const vkt::Shader fragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, |
| GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl)); |
| |
| const std::optional<uint32_t> graphics_queue_family_index = m_device->QueueFamilyMatching(VK_QUEUE_GRAPHICS_BIT, 0u); |
| |
| vkt::CommandPool command_pool(*m_device, graphics_queue_family_index.value()); |
| vkt::CommandBuffer command_buffer(m_device, &command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY); |
| command_buffer.begin(); |
| command_buffer.BeginRenderingColor(GetDynamicRenderTarget()); |
| const VkShaderStageFlagBits stages[] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, |
| VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_GEOMETRY_BIT, |
| VK_SHADER_STAGE_FRAGMENT_BIT}; |
| const VkShaderEXT shaders[] = {vertShader.handle(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, fragShader.handle()}; |
| vk::CmdBindShadersEXT(command_buffer.handle(), 5u, stages, shaders); |
| SetDefaultDynamicStates({}, true, command_buffer.handle()); |
| vk::CmdDraw(command_buffer.handle(), 4, 1, 0, 0); |
| command_buffer.EndRendering(); |
| command_buffer.end(); |
| |
| m_commandBuffer->begin(); |
| vk::CmdExecuteCommands(m_commandBuffer->handle(), 1u, &command_buffer.handle()); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, OutputToMultipleAttachments) { |
| TEST_DESCRIPTION("Draw with fragment shader writing to multiple attachments."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| |
| InitDynamicRenderTarget(); |
| |
| static const char frag_src[] = R"glsl( |
| #version 460 |
| layout(location = 0) out vec4 uFragColor1; |
| layout(location = 1) out vec4 uFragColor2; |
| void main(){ |
| uFragColor1 = vec4(0,1,0,1); |
| uFragColor2 = vec4(1,0,1,0); |
| } |
| )glsl"; |
| |
| const vkt::Shader vertShader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl)); |
| |
| const vkt::Shader fragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, frag_src)); |
| |
| VkImageObj img1(m_device); |
| img1.Init(m_width, m_height, 1, m_render_target_fmt, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, |
| VK_IMAGE_TILING_OPTIMAL); |
| VkImageObj img2(m_device); |
| img2.Init(m_width, m_height, 1, m_render_target_fmt, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, |
| VK_IMAGE_TILING_OPTIMAL); |
| |
| VkImageView view1 = img1.targetView(m_render_target_fmt); |
| VkImageView view2 = img2.targetView(m_render_target_fmt); |
| |
| VkRenderingAttachmentInfo attachments[2]; |
| attachments[0] = vku::InitStructHelper(); |
| attachments[0].imageView = view1; |
| attachments[0].imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
| attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
| attachments[1] = vku::InitStructHelper(); |
| attachments[1].imageView = view2; |
| attachments[1].imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
| attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
| |
| VkRenderingInfoKHR renderingInfo = vku::InitStructHelper(); |
| renderingInfo.renderArea = {{0, 0}, {100u, 100u}}; |
| renderingInfo.layerCount = 1u; |
| renderingInfo.colorAttachmentCount = 2u; |
| renderingInfo.pColorAttachments = attachments; |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| SetDefaultDynamicStates(); |
| BindVertFragShader(vertShader, fragShader); |
| vk::CmdDraw(m_commandBuffer->handle(), 4, 1, 0, 0); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawWithNonBlendableFormat) { |
| TEST_DESCRIPTION("Draw with shader objects to an attachment format that does not support blending."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| |
| VkFormatProperties props; |
| vk::GetPhysicalDeviceFormatProperties(m_device->phy().handle(), VK_FORMAT_R32_UINT, &props); |
| |
| if ((props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0 || |
| (props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT) != 0) { |
| GTEST_SKIP() << "color attachment format not suitable."; |
| } |
| |
| InitDynamicRenderTarget(VK_FORMAT_R32_UINT); |
| |
| const vkt::Shader vertShader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl)); |
| |
| const vkt::Shader fragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, |
| GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl)); |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| SetDefaultDynamicStates(); |
| BindVertFragShader(vertShader, fragShader); |
| VkBool32 enabled = VK_FALSE; |
| vk::CmdSetColorBlendEnableEXT(m_commandBuffer->handle(), 0, 1, &enabled); |
| vk::CmdDraw(m_commandBuffer->handle(), 4, 1, 0, 0); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawInSecondaryCommandBuffersWithRenderPassContinue) { |
| TEST_DESCRIPTION("Draw in secondary command buffers with render pass continue flag."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject(nullptr, VK_API_VERSION_1_3)) |
| |
| InitDynamicRenderTarget(); |
| |
| const vkt::Shader vertShader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl)); |
| |
| const vkt::Shader fragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, |
| GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl)); |
| |
| const std::optional<uint32_t> graphics_queue_family_index = m_device->QueueFamilyMatching(VK_QUEUE_GRAPHICS_BIT, 0u); |
| |
| vkt::CommandPool command_pool(*m_device, graphics_queue_family_index.value()); |
| vkt::CommandBuffer command_buffer(m_device, &command_pool, VK_COMMAND_BUFFER_LEVEL_SECONDARY); |
| VkCommandBufferInheritanceRenderingInfo rendering_info = vku::InitStructHelper(); |
| rendering_info.colorAttachmentCount = 1; |
| rendering_info.pColorAttachmentFormats = &m_render_target_fmt; |
| rendering_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; |
| VkCommandBufferInheritanceInfo hinfo = vku::InitStructHelper(&rendering_info); |
| VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); |
| begin_info.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; |
| begin_info.pInheritanceInfo = &hinfo; |
| command_buffer.begin(&begin_info); |
| const VkShaderStageFlagBits stages[] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, |
| VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_GEOMETRY_BIT, |
| VK_SHADER_STAGE_FRAGMENT_BIT}; |
| const VkShaderEXT shaders[] = {vertShader.handle(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, fragShader.handle()}; |
| vk::CmdBindShadersEXT(command_buffer.handle(), 5u, stages, shaders); |
| SetDefaultDynamicStates({}, true, command_buffer.handle()); |
| vk::CmdDraw(command_buffer.handle(), 4, 1, 0, 0); |
| command_buffer.end(); |
| |
| m_commandBuffer->begin(); |
| |
| VkRenderingAttachmentInfoKHR color_attachment = vku::InitStructHelper(); |
| color_attachment.imageView = GetDynamicRenderTarget(); |
| color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| |
| VkRenderingInfoKHR renderingInfo = vku::InitStructHelper(); |
| renderingInfo.flags = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT; |
| renderingInfo.colorAttachmentCount = 1; |
| renderingInfo.pColorAttachments = &color_attachment; |
| renderingInfo.layerCount = 1; |
| renderingInfo.renderArea = {{0, 0}, {1, 1}}; |
| |
| m_commandBuffer->BeginRendering(renderingInfo); |
| |
| vk::CmdExecuteCommands(m_commandBuffer->handle(), 1u, &command_buffer.handle()); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawRebindingShaders) { |
| TEST_DESCRIPTION("Draw after rebinding only some shaders."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject(nullptr, VK_API_VERSION_1_3)) |
| |
| InitDynamicRenderTarget(); |
| |
| const VkShaderStageFlagBits vertStage = VK_SHADER_STAGE_VERTEX_BIT; |
| const VkShaderStageFlagBits tescStage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; |
| const VkShaderStageFlagBits teseStage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; |
| const VkShaderStageFlagBits geomStage = VK_SHADER_STAGE_GEOMETRY_BIT; |
| const VkShaderStageFlagBits fragStage = VK_SHADER_STAGE_FRAGMENT_BIT; |
| |
| const vkt::Shader vertShader(*m_device, vertStage, GLSLToSPV(vertStage, kVertexMinimalGlsl)); |
| const vkt::Shader tescShader(*m_device, tescStage, GLSLToSPV(tescStage, kTessellationControlMinimalGlsl)); |
| const vkt::Shader teseShader(*m_device, teseStage, GLSLToSPV(teseStage, kTessellationEvalMinimalGlsl)); |
| const vkt::Shader geomShader(*m_device, geomStage, GLSLToSPV(geomStage, kGeometryMinimalGlsl)); |
| const vkt::Shader fragShader(*m_device, fragStage, GLSLToSPV(fragStage, kFragmentMinimalGlsl)); |
| |
| const VkShaderEXT nullShader = VK_NULL_HANDLE; |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| |
| SetDefaultDynamicStates(); |
| |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 1u, &vertStage, &vertShader.handle()); |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 1u, &tescStage, &nullShader); |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 1u, &teseStage, &nullShader); |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 1u, &geomStage, &nullShader); |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 1u, &fragStage, &fragShader.handle()); |
| vk::CmdDraw(m_commandBuffer->handle(), 4u, 1u, 0u, 0u); |
| |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 1u, &geomStage, &geomShader.handle()); |
| vk::CmdDraw(m_commandBuffer->handle(), 4u, 1u, 0u, 0u); |
| |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 1u, &tescStage, &tescShader.handle()); |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 1u, &teseStage, &teseShader.handle()); |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 1u, &geomStage, &nullShader); |
| vk::CmdDraw(m_commandBuffer->handle(), 4u, 1u, 0u, 0u); |
| |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 1u, &fragStage, &nullShader); |
| vk::CmdDraw(m_commandBuffer->handle(), 4u, 1u, 0u, 0u); |
| |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, TestVertexAttributeMatching) { |
| TEST_DESCRIPTION("Test vertex inputs."); |
| |
| VkPhysicalDeviceVulkanMemoryModelFeatures vulkanMemoryModelFeatures = vku::InitStructHelper(); |
| RETURN_IF_SKIP(InitBasicShaderObject(&vulkanMemoryModelFeatures)) |
| if (!vulkanMemoryModelFeatures.vulkanMemoryModel || !vulkanMemoryModelFeatures.vulkanMemoryModelDeviceScope) { |
| GTEST_SKIP() << "vulkanMemoryModel or vulkanMemoryModelDeviceScope not supported."; |
| } |
| InitDynamicRenderTarget(); |
| |
| static const char vert_src[] = R"glsl( |
| #version 460 |
| #extension GL_EXT_shader_explicit_arithmetic_types : enable |
| layout(location = 0) in int pos; |
| layout(location = 0) out int64_t pos1; |
| void main() { |
| gl_Position = vec4(pos); |
| pos1 = 0; |
| } |
| )glsl"; |
| |
| VkShaderStageFlagBits stages[] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT}; |
| const vkt::Shader vertShader(*m_device, stages[0], GLSLToSPV(stages[0], vert_src)); |
| const vkt::Shader fragShader(*m_device, stages[1], GLSLToSPV(stages[1], kFragmentMinimalGlsl)); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| SetDefaultDynamicStates(); |
| BindVertFragShader(vertShader, fragShader); |
| |
| VkVertexInputBindingDescription2EXT vertexBindingDescription = vku::InitStructHelper(); |
| vertexBindingDescription.binding = 0u; |
| vertexBindingDescription.stride = 16u; |
| vertexBindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; |
| vertexBindingDescription.divisor = 1u; |
| |
| VkVertexInputAttributeDescription2EXT vertexAttributeDescription = vku::InitStructHelper(); |
| vertexAttributeDescription.location = 0u; |
| vertexAttributeDescription.binding = 0u; |
| vertexAttributeDescription.format = VK_FORMAT_R32G32B32A32_UINT; |
| vertexAttributeDescription.offset = 0u; |
| |
| vk::CmdSetVertexInputEXT(m_commandBuffer->handle(), 1u, &vertexBindingDescription, 1u, &vertexAttributeDescription); |
| |
| vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawWithBinaryShaders) { |
| TEST_DESCRIPTION("Draw using binary shaders."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| if (IsPlatformMockICD()) { |
| GTEST_SKIP() << "Test not supported by MockICD"; |
| } |
| InitDynamicRenderTarget(); |
| |
| VkShaderStageFlagBits shaderStages[] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, |
| VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_GEOMETRY_BIT, |
| VK_SHADER_STAGE_FRAGMENT_BIT}; |
| |
| std::vector<uint32_t> spv[5]; |
| spv[0] = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| spv[1] = GLSLToSPV(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, kTessellationControlMinimalGlsl); |
| spv[2] = GLSLToSPV(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, kTessellationEvalMinimalGlsl); |
| spv[3] = GLSLToSPV(VK_SHADER_STAGE_GEOMETRY_BIT, kGeometryMinimalGlsl); |
| spv[4] = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| |
| VkShaderEXT shaders[5]; |
| VkShaderEXT binaryShaders[5]; |
| for (uint32_t i = 0; i < 5u; ++i) { |
| VkShaderCreateInfoEXT createInfo = vku::InitStructHelper(); |
| createInfo.stage = shaderStages[i]; |
| createInfo.nextStage = 0u; |
| if (i < 4) { |
| createInfo.nextStage = shaderStages[i + 1]; |
| } |
| createInfo.codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| createInfo.codeSize = spv[i].size() * sizeof(spv[i][0]); |
| createInfo.pCode = spv[i].data(); |
| createInfo.pName = "main"; |
| |
| vk::CreateShadersEXT(*m_device, 1u, &createInfo, nullptr, &shaders[i]); |
| size_t dataSize; |
| vk::GetShaderBinaryDataEXT(*m_device, shaders[i], &dataSize, nullptr); |
| std::vector<uint8_t> data(dataSize); |
| vk::GetShaderBinaryDataEXT(*m_device, shaders[i], &dataSize, data.data()); |
| |
| createInfo.codeType = VK_SHADER_CODE_TYPE_BINARY_EXT; |
| createInfo.codeSize = dataSize; |
| createInfo.pCode = data.data(); |
| vk::CreateShadersEXT(*m_device, 1u, &createInfo, nullptr, &binaryShaders[i]); |
| } |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| SetDefaultDynamicStates(); |
| |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 5u, shaderStages, binaryShaders); |
| |
| vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| |
| for (uint32_t i = 0; i < 5; ++i) { |
| vk::DestroyShaderEXT(*m_device, shaders[i], nullptr); |
| vk::DestroyShaderEXT(*m_device, binaryShaders[i], nullptr); |
| } |
| } |
| |
| TEST_F(PositiveShaderObject, NotSettingDepthBounds) { |
| TEST_DESCRIPTION("Draw without setting depth bounds."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()) |
| |
| InitDynamicRenderTarget(); |
| |
| const vkt::Shader vertShader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl)); |
| |
| const vkt::Shader fragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, |
| GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl)); |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| SetDefaultDynamicStates({VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE, VK_DYNAMIC_STATE_DEPTH_BOUNDS}); |
| vk::CmdSetRasterizerDiscardEnableEXT(m_commandBuffer->handle(), VK_TRUE); |
| BindVertFragShader(vertShader, fragShader); |
| vk::CmdDraw(m_commandBuffer->handle(), 4, 1, 0, 0); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(PositiveShaderObject, CreateAndDrawLinkedAndUnlinkedShaders) { |
| TEST_DESCRIPTION("Create and draw with some linked and some unlinked shaders."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject(nullptr, VK_API_VERSION_1_3)) |
| |
| InitDynamicRenderTarget(); |
| |
| const VkShaderStageFlagBits stages[] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, |
| VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_GEOMETRY_BIT, |
| VK_SHADER_STAGE_FRAGMENT_BIT}; |
| |
| const auto vertSpirv = GLSLToSPV(stages[0], kVertexMinimalGlsl); |
| const auto tescSpirv = GLSLToSPV(stages[1], kTessellationControlMinimalGlsl); |
| const auto teseSpirv = GLSLToSPV(stages[2], kTessellationEvalMinimalGlsl); |
| const auto geomSpirv = GLSLToSPV(stages[3], kGeometryMinimalGlsl); |
| const auto fragSpirv = GLSLToSPV(stages[4], kFragmentMinimalGlsl); |
| |
| VkShaderCreateInfoEXT createInfos[5]; |
| |
| createInfos[0] = vku::InitStructHelper(); |
| createInfos[0].flags = VK_SHADER_CREATE_LINK_STAGE_BIT_EXT; |
| createInfos[0].stage = stages[0]; |
| createInfos[0].nextStage = stages[1]; |
| createInfos[0].codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| createInfos[0].codeSize = vertSpirv.size() * sizeof(vertSpirv[0]); |
| createInfos[0].pCode = vertSpirv.data(); |
| createInfos[0].pName = "main"; |
| |
| createInfos[1] = vku::InitStructHelper(); |
| createInfos[1].flags = VK_SHADER_CREATE_LINK_STAGE_BIT_EXT; |
| createInfos[1].stage = stages[1]; |
| createInfos[1].nextStage = stages[2]; |
| createInfos[1].codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| createInfos[1].codeSize = tescSpirv.size() * sizeof(tescSpirv[0]); |
| createInfos[1].pCode = tescSpirv.data(); |
| createInfos[1].pName = "main"; |
| |
| createInfos[2] = vku::InitStructHelper(); |
| createInfos[2].flags = VK_SHADER_CREATE_LINK_STAGE_BIT_EXT; |
| createInfos[2].stage = stages[2]; |
| createInfos[2].nextStage = stages[3] | stages[4]; |
| createInfos[2].codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| createInfos[2].codeSize = teseSpirv.size() * sizeof(teseSpirv[0]); |
| createInfos[2].pCode = teseSpirv.data(); |
| createInfos[2].pName = "main"; |
| |
| createInfos[3] = vku::InitStructHelper(); |
| createInfos[3].stage = stages[3]; |
| createInfos[3].nextStage = stages[4]; |
| createInfos[3].codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| createInfos[3].codeSize = geomSpirv.size() * sizeof(geomSpirv[0]); |
| createInfos[3].pCode = geomSpirv.data(); |
| createInfos[3].pName = "main"; |
| |
| createInfos[4] = vku::InitStructHelper(); |
| createInfos[4].stage = stages[4]; |
| createInfos[4].nextStage = 0u; |
| createInfos[4].codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| createInfos[4].codeSize = fragSpirv.size() * sizeof(fragSpirv[0]); |
| createInfos[4].pCode = fragSpirv.data(); |
| createInfos[4].pName = "main"; |
| |
| VkShaderEXT shaders[5]; |
| vk::CreateShadersEXT(*m_device, 3u, createInfos, nullptr, shaders); |
| for (uint32_t i = 3u; i < 5u; ++i) { |
| vk::CreateShadersEXT(*m_device, 1u, &createInfos[i], nullptr, &shaders[i]); |
| } |
| |
| m_commandBuffer->begin(); |
| m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget()); |
| SetDefaultDynamicStates(); |
| |
| vk::CmdBindShadersEXT(m_commandBuffer->handle(), 5u, stages, shaders); |
| |
| vk::CmdDraw(m_commandBuffer->handle(), 4, 1, 0, 0); |
| m_commandBuffer->EndRendering(); |
| m_commandBuffer->end(); |
| |
| for (uint32_t i = 0; i < 5u; ++i) { |
| vk::DestroyShaderEXT(*m_device, shaders[i], nullptr); |
| } |
| } |