| /* |
| * Copyright (c) 2023-2025 Nintendo |
| * Copyright (c) 2023-2025 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" |
| #include "../framework/shader_object_helper.h" |
| #include "../framework/descriptor_helper.h" |
| #include "../framework/shader_templates.h" |
| #include "utils/math_utils.h" |
| |
| void ShaderObjectTest::InitBasicShaderObject(void *instance_pnext) { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| AddRequiredFeature(vkt::Feature::shaderObject); |
| RETURN_IF_SKIP(Init(nullptr, nullptr, instance_pnext)); |
| } |
| |
| void ShaderObjectTest::InitBasicMeshShaderObject(APIVersion target_api_version) { |
| SetTargetApiVersion(target_api_version); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderObject); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| AddRequiredFeature(vkt::Feature::meshShader); |
| AddRequiredFeature(vkt::Feature::taskShader); |
| |
| RETURN_IF_SKIP(Init()); |
| } |
| |
| class PositiveShaderObject : public ShaderObjectTest {}; |
| |
| void ShaderObjectTest::CreateMinimalShaders() { |
| std::vector<uint32_t> vert_spirv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| VkShaderCreateInfoEXT create_info = vku::InitStructHelper(); |
| create_info.stage = VK_SHADER_STAGE_VERTEX_BIT; |
| create_info.nextStage = VK_SHADER_STAGE_FRAGMENT_BIT; |
| if (m_device->GetFeatures().tessellationShader) { |
| create_info.nextStage |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; |
| } |
| if (m_device->GetFeatures().geometryShader) { |
| create_info.nextStage |= VK_SHADER_STAGE_GEOMETRY_BIT; |
| } |
| create_info.codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| create_info.codeSize = vert_spirv.size() * sizeof(uint32_t); |
| create_info.pCode = vert_spirv.data(); |
| create_info.pName = "main"; |
| m_vert_shader.Init(*m_device, create_info); |
| |
| std::vector<uint32_t> frag_spirv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| create_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; |
| create_info.nextStage = 0u; |
| create_info.codeSize = frag_spirv.size() * sizeof(uint32_t); |
| create_info.pCode = frag_spirv.data(); |
| m_frag_shader.Init(*m_device, create_info); |
| } |
| |
| 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, 1u, &createInfo, nullptr, &shader); |
| vk::DestroyShaderEXT(*m_device, 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 vert_shader(*m_device, stage, kVertexMinimalGlsl); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindShadersEXT(m_command_buffer, 1u, &stage, &vert_shader.handle()); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawWithVertAndFragShaderObjects) { |
| TEST_DESCRIPTION("Draw with only vertex and fragment shader objects bound."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitDynamicRenderTarget(); |
| CreateMinimalShaders(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude(); |
| m_command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.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, GetShaderBinaryDataEXT not implemented"; |
| } |
| |
| InitDynamicRenderTarget(); |
| CreateMinimalShaders(); |
| |
| size_t vertDataSize; |
| vk::GetShaderBinaryDataEXT(*m_device, m_vert_shader, &vertDataSize, nullptr); |
| std::vector<uint8_t> vertData(vertDataSize); |
| vk::GetShaderBinaryDataEXT(*m_device, m_vert_shader, &vertDataSize, vertData.data()); |
| |
| size_t fragDataSize; |
| vk::GetShaderBinaryDataEXT(*m_device, m_frag_shader, &fragDataSize, nullptr); |
| std::vector<uint8_t> fragData(fragDataSize); |
| vk::GetShaderBinaryDataEXT(*m_device, m_frag_shader, &fragDataSize, fragData.data()); |
| |
| vkt::Shader binary_vert_shader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, vertData); |
| vkt::Shader binary_frag_shader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, fragData); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude(); |
| m_command_buffer.BindShaders(binary_vert_shader, binary_frag_shader); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.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] = ShaderCreateInfoLink(vert_spv, VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT); |
| createInfos[1] = ShaderCreateInfoLink(frag_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| VkShaderEXT shaders[2]; |
| vk::CreateShadersEXT(*m_device, 2u, createInfos, nullptr, shaders); |
| |
| for (uint32_t i = 0; i < 2; ++i) { |
| vk::DestroyShaderEXT(*m_device, shaders[i], nullptr); |
| } |
| } |
| |
| TEST_F(PositiveShaderObject, LinkedGraphicsShaders) { |
| TEST_DESCRIPTION("Create linked vertex and fragment shaders."); |
| AddRequiredFeature(vkt::Feature::geometryShader); |
| AddRequiredFeature(vkt::Feature::tessellationShader); |
| 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] = ShaderCreateInfoLink(vert_spv, VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT); |
| createInfos[1] = |
| ShaderCreateInfoLink(tesc_spv, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT); |
| createInfos[2] = ShaderCreateInfoLink(tese_spv, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_GEOMETRY_BIT); |
| createInfos[3] = ShaderCreateInfoLink(geom_spv, VK_SHADER_STAGE_GEOMETRY_BIT, VK_SHADER_STAGE_FRAGMENT_BIT); |
| createInfos[4] = ShaderCreateInfoLink(frag_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| VkShaderEXT shaders[5]; |
| vk::CreateShadersEXT(*m_device, 5u, createInfos, nullptr, shaders); |
| |
| for (uint32_t i = 0; i < 5; ++i) { |
| vk::DestroyShaderEXT(*m_device, shaders[i], nullptr); |
| } |
| } |
| |
| TEST_F(PositiveShaderObject, MissingCmdSetDepthBiasEnable) { |
| TEST_DESCRIPTION("Draw with shaders without setting depth bias enable."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitDynamicRenderTarget(); |
| CreateMinimalShaders(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude({VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE}); |
| vk::CmdSetRasterizerDiscardEnableEXT(m_command_buffer, VK_TRUE); |
| m_command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, VertFragShaderDraw) { |
| TEST_DESCRIPTION("Test drawing with a vertex and fragment shader"); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| |
| 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"; |
| |
| 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 vert_shader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, vert_src); |
| const vkt::Shader frag_shader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, frag_src); |
| |
| vkt::Buffer buffer(*m_device, sizeof(float) * 4u, kHostVisibleMemProps, VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| |
| vkt::Image image(*m_device, m_width, m_height, VK_FORMAT_R32G32B32A32_SFLOAT, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); |
| image.SetLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); |
| vkt::ImageView view = image.CreateView(); |
| |
| 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 = {m_width, m_height}; |
| begin_rendering_info.layerCount = 1u; |
| begin_rendering_info.colorAttachmentCount = 1u; |
| begin_rendering_info.pColorAttachments = &color_attachment; |
| |
| m_command_buffer.Begin(); |
| vk::CmdBeginRenderingKHR(m_command_buffer, &begin_rendering_info); |
| m_command_buffer.BindShaders(vert_shader, frag_shader); |
| SetDefaultDynamicStatesExclude(); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| vk::CmdEndRenderingKHR(m_command_buffer); |
| |
| { |
| VkImageMemoryBarrier image_memory_barrier = vku::InitStructHelper(); |
| image_memory_barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; |
| image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; |
| image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; |
| image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
| image_memory_barrier.image = image; |
| image_memory_barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; |
| vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, |
| 0u, nullptr, 0u, nullptr, 1u, &image_memory_barrier); |
| } |
| |
| VkBufferImageCopy copy_region = {}; |
| copy_region.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; |
| copy_region.imageOffset.x = static_cast<int32_t>(m_width / 2) + 1; |
| copy_region.imageOffset.y = static_cast<int32_t>(m_height / 2) + 1; |
| copy_region.imageExtent = {1, 1, 1}; |
| |
| vk::CmdCopyImageToBuffer(m_command_buffer, image, VK_IMAGE_LAYOUT_GENERAL, buffer, 1u, ©_region); |
| |
| m_command_buffer.End(); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawWithAllGraphicsShaderStagesUsed) { |
| TEST_DESCRIPTION("Test drawing using all graphics shader"); |
| |
| AddRequiredFeature(vkt::Feature::geometryShader); |
| AddRequiredFeature(vkt::Feature::tessellationShader); |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| |
| 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"; |
| |
| 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"; |
| |
| 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"; |
| |
| 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"; |
| |
| 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 vert_shader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, vert_src); |
| const vkt::Shader tesc_shader(*m_device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, tesc_src); |
| const vkt::Shader tese_shader(*m_device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, tese_src); |
| const vkt::Shader geom_shader(*m_device, VK_SHADER_STAGE_GEOMETRY_BIT, geom_src); |
| const vkt::Shader frag_shader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, frag_src); |
| |
| vkt::Image image(*m_device, m_width, m_height, VK_FORMAT_R32G32B32A32_SFLOAT, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); |
| image.SetLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); |
| vkt::ImageView view = image.CreateView(); |
| |
| 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 = {0, 0}; |
| begin_rendering_info.renderArea.extent = {m_width, m_height}; |
| begin_rendering_info.layerCount = 1u; |
| begin_rendering_info.viewMask = 0x0; |
| begin_rendering_info.colorAttachmentCount = 1u; |
| begin_rendering_info.pColorAttachments = &color_attachment; |
| |
| m_command_buffer.Begin(); |
| vk::CmdBeginRenderingKHR(m_command_buffer, &begin_rendering_info); |
| m_command_buffer.BindShaders(vert_shader, tesc_shader, tese_shader, geom_shader, frag_shader); |
| SetDefaultDynamicStatesExclude({}, true); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| vk::CmdEndRenderingKHR(m_command_buffer); |
| |
| m_command_buffer.End(); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| |
| TEST_F(PositiveShaderObject, ComputeShader) { |
| TEST_DESCRIPTION("Test dispatching with compute shader"); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| |
| 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"; |
| |
| vkt::Buffer storage_buffer(*m_device, 16u * sizeof(float), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps); |
| |
| OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}}); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| descriptor_set.WriteDescriptorBufferInfo(0, storage_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| VkDescriptorSetLayout descriptor_set_layout = descriptor_set.layout_; |
| |
| const vkt::Shader comp_shader(*m_device, VK_SHADER_STAGE_COMPUTE_BIT, comp_src, &descriptor_set_layout); |
| |
| m_command_buffer.Begin(); |
| |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0u, 1u, &descriptor_set.set_, 0u, |
| nullptr); |
| |
| m_command_buffer.BindCompShader(comp_shader); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| |
| m_command_buffer.End(); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| |
| TEST_F(PositiveShaderObject, TaskMeshShadersDraw) { |
| TEST_DESCRIPTION("Test drawing using task and mesh shaders"); |
| |
| RETURN_IF_SKIP(InitBasicMeshShaderObject(VK_API_VERSION_1_3)); |
| |
| 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"; |
| |
| 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"; |
| |
| 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 task_shader(*m_device, VK_SHADER_STAGE_TASK_BIT_EXT, task_src); |
| const vkt::Shader mesh_shader(*m_device, VK_SHADER_STAGE_MESH_BIT_EXT, mesh_src); |
| const vkt::Shader frag_shader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, frag_src); |
| |
| vkt::Image image(*m_device, m_width, m_height, VK_FORMAT_R32G32B32A32_SFLOAT, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); |
| image.SetLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); |
| vkt::ImageView view = image.CreateView(); |
| |
| 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 = {0, 0}; |
| begin_rendering_info.renderArea.extent = {m_width, m_height}; |
| begin_rendering_info.layerCount = 1u; |
| begin_rendering_info.viewMask = 0x0; |
| begin_rendering_info.colorAttachmentCount = 1u; |
| begin_rendering_info.pColorAttachments = &color_attachment; |
| |
| m_command_buffer.Begin(); |
| vk::CmdBeginRenderingKHR(m_command_buffer, &begin_rendering_info); |
| m_command_buffer.BindMeshShaders(task_shader, mesh_shader, frag_shader); |
| SetDefaultDynamicStatesExclude(); |
| vk::CmdDrawMeshTasksEXT(m_command_buffer, 1, 1, 1); |
| vk::CmdEndRenderingKHR(m_command_buffer); |
| |
| m_command_buffer.End(); |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| |
| TEST_F(PositiveShaderObject, FailCreateShaders) { |
| TEST_DESCRIPTION("Test failing to create shaders"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredFeature(vkt::Feature::geometryShader); |
| AddRequiredFeature(vkt::Feature::tessellationShader); |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| if (IsPlatformMockICD()) { |
| GTEST_SKIP() << "Test not supported by MockICD because shader needs to fail"; |
| } |
| |
| 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"; |
| |
| 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"; |
| |
| 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"; |
| |
| 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"; |
| |
| 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 shader_stages[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 create_infos[shaders_count]; |
| for (uint32_t i = 0; i < shaders_count; ++i) { |
| create_infos[i] = vku::InitStructHelper(); |
| create_infos[i].stage = shader_stages[i % stages_count]; |
| create_infos[i].codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| create_infos[i].codeSize = spv[i % stages_count].size() * sizeof(uint32_t); |
| create_infos[i].pCode = spv[i % stages_count].data(); |
| create_infos[i].pName = "main"; |
| } |
| |
| // Binary code must be aligned to 16 bytes |
| std::vector<uint8_t> garbage(create_infos[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), create_infos[fail_index].pCode, create_infos[fail_index].codeSize); |
| create_infos[fail_index].codeType = VK_SHADER_CODE_TYPE_BINARY_EXT; |
| create_infos[fail_index].pCode = reinterpret_cast<const void *>(pCode); |
| |
| VkResult res = vk::CreateShadersEXT(*m_device, 20u, create_infos, nullptr, shaders); |
| ASSERT_EQ(res, VK_INCOMPATIBLE_SHADER_BINARY_EXT); |
| |
| for (uint32_t i = 0; i < shaders_count; ++i) { |
| // We don't know which or if any shaders were actually created |
| if (shaders[i] != VK_NULL_HANDLE) { |
| vk::DestroyShaderEXT(*m_device, shaders[i], nullptr); |
| } |
| } |
| } |
| |
| TEST_F(PositiveShaderObject, DrawMinimalDynamicStates) { |
| TEST_DESCRIPTION("Draw with only required dynamic states set."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitDynamicRenderTarget(); |
| CreateMinimalShaders(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| |
| 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_command_buffer, 1u, &viewport); |
| vk::CmdSetScissorWithCountEXT(m_command_buffer, 1u, &scissor); |
| vk::CmdSetRasterizerDiscardEnableEXT(m_command_buffer, VK_FALSE); |
| vk::CmdSetStencilTestEnableEXT(m_command_buffer, VK_FALSE); |
| vk::CmdSetPolygonModeEXT(m_command_buffer, VK_POLYGON_MODE_FILL); |
| vk::CmdSetRasterizationSamplesEXT(m_command_buffer, VK_SAMPLE_COUNT_1_BIT); |
| VkSampleMask sampleMask = 1u; |
| vk::CmdSetSampleMaskEXT(m_command_buffer, VK_SAMPLE_COUNT_1_BIT, &sampleMask); |
| vk::CmdSetAlphaToCoverageEnableEXT(m_command_buffer, VK_FALSE); |
| vk::CmdSetCullModeEXT(m_command_buffer, VK_CULL_MODE_NONE); |
| vk::CmdSetDepthTestEnableEXT(m_command_buffer, VK_FALSE); |
| vk::CmdSetDepthWriteEnableEXT(m_command_buffer, VK_FALSE); |
| vk::CmdSetDepthBoundsTestEnableEXT(m_command_buffer, VK_FALSE); |
| vk::CmdSetDepthBiasEnableEXT(m_command_buffer, VK_FALSE); |
| vk::CmdSetPrimitiveTopologyEXT(m_command_buffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); |
| vk::CmdSetVertexInputEXT(m_command_buffer, 0u, nullptr, 0u, nullptr); |
| vk::CmdSetPrimitiveRestartEnableEXT(m_command_buffer, VK_FALSE); |
| VkBool32 colorBlendEnable = VK_FALSE; |
| vk::CmdSetColorBlendEnableEXT(m_command_buffer, 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_command_buffer, 0u, 1u, &colorWriteMask); |
| 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, |
| }; |
| vk::CmdSetColorBlendEquationEXT(m_command_buffer, 0u, 1u, &colorBlendEquation); |
| |
| m_command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawMinimalDynamicStatesRasterizationDisabled) { |
| TEST_DESCRIPTION("Draw with only required dynamic states set."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitDynamicRenderTarget(); |
| CreateMinimalShaders(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| |
| 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_command_buffer, 1u, &viewport); |
| vk::CmdSetScissorWithCountEXT(m_command_buffer, 1u, &scissor); |
| vk::CmdSetRasterizerDiscardEnableEXT(m_command_buffer, VK_TRUE); |
| vk::CmdSetStencilTestEnableEXT(m_command_buffer, VK_FALSE); |
| vk::CmdSetPrimitiveTopologyEXT(m_command_buffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); |
| vk::CmdSetVertexInputEXT(m_command_buffer, 0u, nullptr, 0u, nullptr); |
| vk::CmdSetPrimitiveRestartEnableEXT(m_command_buffer, VK_FALSE); |
| |
| m_command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, ShadersDescriptorSets) { |
| TEST_DESCRIPTION("Draw with shaders using multiple descriptor sets."); |
| |
| AddRequiredFeature(vkt::Feature::vertexPipelineStoresAndAtomics); |
| 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_}); |
| |
| 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"; |
| |
| 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_, frag_descriptor_set.layout_}; |
| |
| const vkt::Shader vert_shader(*m_device, ShaderCreateInfo(vert_spv, VK_SHADER_STAGE_VERTEX_BIT, 2, descriptor_set_layouts)); |
| const vkt::Shader frag_shader(*m_device, ShaderCreateInfo(frag_spv, VK_SHADER_STAGE_FRAGMENT_BIT, 2, descriptor_set_layouts)); |
| |
| vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
| vert_descriptor_set.WriteDescriptorBufferInfo(0, buffer, 0, 32, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| vert_descriptor_set.UpdateDescriptorSets(); |
| |
| auto image_ci = vkt::Image::ImageCreateInfo2D(64, 64, 1, 2, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT); |
| vkt::Image image(*m_device, image_ci, vkt::set_layout); |
| vkt::ImageView view = image.CreateView(VK_IMAGE_VIEW_TYPE_2D, 0, 1, 1, 1); |
| vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo()); |
| |
| frag_descriptor_set.WriteDescriptorImageInfo(0, view, sampler); |
| frag_descriptor_set.UpdateDescriptorSets(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude(); |
| m_command_buffer.BindShaders(vert_shader, frag_shader); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0u, 1u, &vert_descriptor_set.set_, |
| 0u, nullptr); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 1u, 1u, &frag_descriptor_set.set_, |
| 0u, nullptr); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, DescriptorBuffer) { |
| TEST_DESCRIPTION("use VK_EXT_descriptor_buffer and do a basic draw."); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::descriptorBuffer); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| AddRequiredFeature(vkt::Feature::shaderObject); |
| RETURN_IF_SKIP(Init()); |
| InitDynamicRenderTarget(); |
| |
| vkt::Buffer buffer(*m_device, 4096, VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, vkt::device_address); |
| |
| VkDescriptorBufferBindingInfoEXT buffer_binding_info = vku::InitStructHelper(); |
| buffer_binding_info.address = buffer.Address(); |
| buffer_binding_info.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; |
| |
| const VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}; |
| const vkt::DescriptorSetLayout set_layout(*m_device, {binding}, VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&set_layout}); |
| |
| const char frag_spv[] = R"glsl( |
| #version 460 |
| layout(location = 0) out vec4 uFragColor; |
| layout(set=0, binding=0) uniform foo { vec4 x; } bar; |
| void main(){ |
| uFragColor = bar.x; |
| } |
| )glsl"; |
| |
| const vkt::Shader vert_shader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl, &set_layout.handle()); |
| const vkt::Shader frag_shader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, frag_spv, &set_layout.handle()); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude(); |
| m_command_buffer.BindShaders(vert_shader, frag_shader); |
| vk::CmdBindDescriptorBuffersEXT(m_command_buffer, 1, &buffer_binding_info); |
| |
| uint32_t buffer_index = 0u; |
| VkDeviceSize offset = 0u; |
| vk::CmdSetDescriptorBufferOffsetsEXT(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0u, 1u, &buffer_index, |
| &offset); |
| |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, MultiplePushConstants) { |
| TEST_DESCRIPTION("Draw with shaders using multiple push constants."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitDynamicRenderTarget(); |
| |
| const char vert_src[] = R"glsl( |
| #version 460 |
| layout (push_constant) uniform constants { |
| int pos; |
| } pushConst; |
| void main() { |
| gl_Position = vec4(pushConst.pos); |
| } |
| )glsl"; |
| |
| 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] = { |
| {VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(int)}, |
| {VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(int), sizeof(float)}, |
| }; |
| vkt::PipelineLayout pipeline_layout(*m_device, {}, {push_constant_ranges[0], push_constant_ranges[1]}); |
| |
| const vkt::Shader vert_shader(*m_device, |
| ShaderCreateInfo(vert_spv, VK_SHADER_STAGE_VERTEX_BIT, 0, nullptr, 2, push_constant_ranges)); |
| const vkt::Shader frag_shader(*m_device, |
| ShaderCreateInfo(frag_spv, VK_SHADER_STAGE_FRAGMENT_BIT, 0, nullptr, 2, push_constant_ranges)); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| |
| int pos = 1; |
| vk::CmdPushConstants(m_command_buffer, pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0u, sizeof(int), &pos); |
| float color = 1.0f; |
| vk::CmdPushConstants(m_command_buffer, pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(int), sizeof(float), &color); |
| |
| SetDefaultDynamicStatesExclude(); |
| m_command_buffer.BindShaders(vert_shader, frag_shader); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, MultipleSpecializationConstants) { |
| TEST_DESCRIPTION("Draw with shaders using multiple specialization constants."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitDynamicRenderTarget(); |
| |
| const char vert_src[] = R"glsl( |
| #version 460 |
| layout (constant_id = 0) const int pos = 1; |
| void main() { |
| gl_Position = vec4(pos); |
| } |
| )glsl"; |
| |
| 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; |
| |
| const vkt::Shader vert_shader( |
| *m_device, ShaderCreateInfo(vert_spv, VK_SHADER_STAGE_VERTEX_BIT, 0, nullptr, 0, nullptr, &specialization_info)); |
| const vkt::Shader frag_shader( |
| *m_device, ShaderCreateInfo(frag_spv, VK_SHADER_STAGE_FRAGMENT_BIT, 0, nullptr, 0, nullptr, &specialization_info)); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| |
| SetDefaultDynamicStatesExclude(); |
| m_command_buffer.BindShaders(vert_shader, frag_shader); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, IndirectDraw) { |
| TEST_DESCRIPTION("Draw with all 5 shaders stages using indirect draw and seconary command buffers."); |
| |
| AddRequiredFeature(vkt::Feature::geometryShader); |
| AddRequiredFeature(vkt::Feature::tessellationShader); |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitDynamicRenderTarget(); |
| |
| 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"; |
| |
| 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"; |
| |
| 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"; |
| |
| 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"; |
| |
| 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 vert_shader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, vert_src); |
| const vkt::Shader tesc_shader(*m_device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, tesc_src); |
| const vkt::Shader tese_shader(*m_device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, tese_src); |
| const vkt::Shader geom_shader(*m_device, VK_SHADER_STAGE_GEOMETRY_BIT, geom_src); |
| const vkt::Shader frag_shader(*m_device, 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_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| |
| SetDefaultDynamicStatesExclude({}, true); |
| m_command_buffer.BindShaders(vert_shader, tesc_shader, tese_shader, geom_shader, frag_shader); |
| vk::CmdDrawIndirect(m_command_buffer, indirect_buffer, 0u, 1u, 0u); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawInSecondaryCommandBuffers) { |
| TEST_DESCRIPTION("Draw in secondary command buffers."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitDynamicRenderTarget(); |
| CreateMinimalShaders(); |
| |
| const std::optional<uint32_t> graphics_queue_family_index = m_device->QueueFamily(VK_QUEUE_GRAPHICS_BIT); |
| |
| 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(), GetRenderTargetArea()); |
| command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| SetDefaultDynamicStatesExclude({}, false, command_buffer); |
| vk::CmdDraw(command_buffer, 4, 1, 0, 0); |
| command_buffer.EndRendering(); |
| command_buffer.End(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdExecuteCommands(m_command_buffer, 1u, &command_buffer.handle()); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, OutputToMultipleAttachments) { |
| TEST_DESCRIPTION("Draw with fragment shader writing to multiple attachments."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| |
| InitDynamicRenderTarget(); |
| |
| 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 vert_shader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| const vkt::Shader frag_shader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, frag_src); |
| |
| vkt::Image img1(*m_device, m_width, m_height, m_render_target_fmt, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); |
| vkt::Image img2(*m_device, m_width, m_height, m_render_target_fmt, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); |
| |
| vkt::ImageView view1 = img1.CreateView(); |
| vkt::ImageView view2 = img2.CreateView(); |
| |
| 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; |
| |
| VkRenderingInfo rendering_info = vku::InitStructHelper(); |
| rendering_info.renderArea = {{0, 0}, {m_width, m_height}}; |
| rendering_info.layerCount = 1u; |
| rendering_info.colorAttachmentCount = 2u; |
| rendering_info.pColorAttachments = attachments; |
| |
| m_command_buffer.Begin(); |
| vk::CmdBeginRenderingKHR(m_command_buffer, &rendering_info); |
| SetDefaultDynamicStatesExclude(); |
| VkBool32 blend_enable = VK_TRUE; |
| vk::CmdSetColorBlendEnableEXT(m_command_buffer, 1u, 1u, &blend_enable); |
| VkColorBlendEquationEXT color_blend_equation = {}; |
| vk::CmdSetColorBlendEquationEXT(m_command_buffer, 1u, 1u, &color_blend_equation); |
| VkColorComponentFlags color_write_mask = VK_COLOR_COMPONENT_R_BIT; |
| vk::CmdSetColorWriteMaskEXT(m_command_buffer, 1u, 1u, &color_write_mask); |
| m_command_buffer.BindShaders(vert_shader, frag_shader); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| vk::CmdEndRenderingKHR(m_command_buffer); |
| m_command_buffer.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->Physical(), 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); |
| CreateMinimalShaders(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude(); |
| m_command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| VkBool32 enabled = VK_FALSE; |
| vk::CmdSetColorBlendEnableEXT(m_command_buffer, 0, 1, &enabled); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawInSecondaryCommandBuffersWithRenderPassContinue) { |
| TEST_DESCRIPTION("Draw in secondary command buffers with render pass continue flag."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| |
| InitDynamicRenderTarget(); |
| CreateMinimalShaders(); |
| |
| const std::optional<uint32_t> graphics_queue_family_index = m_device->QueueFamily(VK_QUEUE_GRAPHICS_BIT); |
| |
| 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 inheritance_rendering_info = vku::InitStructHelper(); |
| inheritance_rendering_info.colorAttachmentCount = 1; |
| inheritance_rendering_info.pColorAttachmentFormats = &m_render_target_fmt; |
| inheritance_rendering_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; |
| VkCommandBufferInheritanceInfo hinfo = vku::InitStructHelper(&inheritance_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); |
| command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| SetDefaultDynamicStatesExclude({}, false, command_buffer); |
| vk::CmdDraw(command_buffer, 4, 1, 0, 0); |
| command_buffer.End(); |
| |
| m_command_buffer.Begin(); |
| |
| VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper(); |
| color_attachment.imageView = GetDynamicRenderTarget(); |
| color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| |
| VkRenderingInfo rendering_info = vku::InitStructHelper(); |
| rendering_info.flags = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT; |
| rendering_info.colorAttachmentCount = 1; |
| rendering_info.pColorAttachments = &color_attachment; |
| rendering_info.layerCount = 1; |
| rendering_info.renderArea = {{0, 0}, {1, 1}}; |
| |
| m_command_buffer.BeginRendering(rendering_info); |
| |
| vk::CmdExecuteCommands(m_command_buffer, 1u, &command_buffer.handle()); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawRebindingShaders) { |
| TEST_DESCRIPTION("Draw after rebinding only some shaders."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredFeature(vkt::Feature::geometryShader); |
| AddRequiredFeature(vkt::Feature::tessellationShader); |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| |
| InitDynamicRenderTarget(); |
| |
| const VkShaderStageFlagBits vert_stage = VK_SHADER_STAGE_VERTEX_BIT; |
| const VkShaderStageFlagBits tesc_stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; |
| const VkShaderStageFlagBits tese_stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; |
| const VkShaderStageFlagBits geom_stage = VK_SHADER_STAGE_GEOMETRY_BIT; |
| const VkShaderStageFlagBits frag_stage = VK_SHADER_STAGE_FRAGMENT_BIT; |
| |
| const vkt::Shader vert_shader(*m_device, vert_stage, kVertexMinimalGlsl); |
| const vkt::Shader tesc_shader(*m_device, tesc_stage, kTessellationControlMinimalGlsl); |
| const vkt::Shader tese_shader(*m_device, tese_stage, kTessellationEvalMinimalGlsl); |
| const vkt::Shader geom_shader(*m_device, geom_stage, kGeometryMinimalGlsl); |
| const vkt::Shader frag_shader(*m_device, frag_stage, kFragmentMinimalGlsl); |
| // when last stage, need to remake without nextStage |
| const auto tese_spv = GLSLToSPV(tese_stage, kTessellationEvalMinimalGlsl); |
| auto tese_shader_ci = ShaderCreateInfoNoNextStage(tese_spv, tese_stage); |
| const vkt::Shader tese_no_next_shader(*m_device, tese_shader_ci); |
| |
| const VkShaderEXT null_shader = VK_NULL_HANDLE; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| |
| SetDefaultDynamicStatesExclude({}, true); |
| |
| vk::CmdBindShadersEXT(m_command_buffer, 1u, &vert_stage, &vert_shader.handle()); |
| vk::CmdBindShadersEXT(m_command_buffer, 1u, &tesc_stage, &null_shader); |
| vk::CmdBindShadersEXT(m_command_buffer, 1u, &tese_stage, &null_shader); |
| vk::CmdBindShadersEXT(m_command_buffer, 1u, &geom_stage, &null_shader); |
| vk::CmdBindShadersEXT(m_command_buffer, 1u, &frag_stage, &frag_shader.handle()); |
| vk::CmdSetPrimitiveTopologyEXT(m_command_buffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP); |
| vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u); |
| |
| vk::CmdBindShadersEXT(m_command_buffer, 1u, &geom_stage, &geom_shader.handle()); |
| vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u); |
| |
| vk::CmdBindShadersEXT(m_command_buffer, 1u, &tesc_stage, &tesc_shader.handle()); |
| vk::CmdBindShadersEXT(m_command_buffer, 1u, &tese_stage, &tese_shader.handle()); |
| vk::CmdBindShadersEXT(m_command_buffer, 1u, &geom_stage, &null_shader); |
| vk::CmdSetPrimitiveTopologyEXT(m_command_buffer, VK_PRIMITIVE_TOPOLOGY_PATCH_LIST); |
| vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u); |
| |
| vk::CmdBindShadersEXT(m_command_buffer, 1u, &tese_stage, &tese_no_next_shader.handle()); |
| vk::CmdBindShadersEXT(m_command_buffer, 1u, &frag_stage, &null_shader); |
| vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u); |
| |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawWithBinaryShaders) { |
| TEST_DESCRIPTION("Draw using binary shaders."); |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredFeature(vkt::Feature::geometryShader); |
| AddRequiredFeature(vkt::Feature::tessellationShader); |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| if (IsPlatformMockICD()) { |
| GTEST_SKIP() << "Test not supported by MockICD, GetShaderBinaryDataEXT not implemented"; |
| } |
| InitDynamicRenderTarget(); |
| |
| VkShaderStageFlagBits shader_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}; |
| |
| 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 binary_shaders[5]; |
| for (uint32_t i = 0; i < 5u; ++i) { |
| VkShaderCreateInfoEXT create_info = vku::InitStructHelper(); |
| create_info.stage = shader_stages[i]; |
| create_info.nextStage = 0u; |
| if (i < 4) { |
| create_info.nextStage = shader_stages[i + 1]; |
| } |
| create_info.codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; |
| create_info.codeSize = spv[i].size() * sizeof(spv[i][0]); |
| create_info.pCode = spv[i].data(); |
| create_info.pName = "main"; |
| |
| vk::CreateShadersEXT(*m_device, 1u, &create_info, nullptr, &shaders[i]); |
| size_t data_size; |
| vk::GetShaderBinaryDataEXT(*m_device, shaders[i], &data_size, nullptr); |
| // Allocate enough space to guarantee 16 byte alignment |
| std::vector<uint8_t> data(data_size + 15); |
| // Get 16 byte aligned pointer |
| void *storage_ptr = reinterpret_cast<void *>(Align(reinterpret_cast<uintptr_t>(data.data()), (uintptr_t)16)); |
| |
| vk::GetShaderBinaryDataEXT(*m_device, shaders[i], &data_size, storage_ptr); |
| |
| create_info.codeType = VK_SHADER_CODE_TYPE_BINARY_EXT; |
| create_info.codeSize = data_size; |
| create_info.pCode = storage_ptr; |
| vk::CreateShadersEXT(*m_device, 1u, &create_info, nullptr, &binary_shaders[i]); |
| } |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude({}, true); |
| |
| vk::CmdBindShadersEXT(m_command_buffer, 5u, shader_stages, binary_shaders); |
| |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| |
| for (uint32_t i = 0; i < 5; ++i) { |
| vk::DestroyShaderEXT(*m_device, shaders[i], nullptr); |
| vk::DestroyShaderEXT(*m_device, binary_shaders[i], nullptr); |
| } |
| } |
| |
| TEST_F(PositiveShaderObject, DrawNotLastStage) { |
| TEST_DESCRIPTION("https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/7320"); |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitDynamicRenderTarget(); |
| |
| const auto vs_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| auto vs_shader_ci = ShaderCreateInfoNoNextStage(vs_spv, VK_SHADER_STAGE_VERTEX_BIT); |
| vs_shader_ci.nextStage = VK_SHADER_STAGE_FRAGMENT_BIT; |
| const vkt::Shader vert_shader(*m_device, vs_shader_ci); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude(); |
| const VkShaderStageFlagBits stages[] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT}; |
| vk::CmdBindShadersEXT(m_command_buffer, 1u, &stages[0], &vert_shader.handle()); |
| vk::CmdBindShadersEXT(m_command_buffer, 1u, &stages[1], VK_NULL_HANDLE); |
| vk::CmdSetRasterizerDiscardEnableEXT(m_command_buffer, VK_TRUE); |
| vk::CmdDraw(m_command_buffer, 3u, 1u, 0u, 0u); |
| |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, NotSettingDepthBounds) { |
| TEST_DESCRIPTION("Draw without setting depth bounds."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitDynamicRenderTarget(); |
| CreateMinimalShaders(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude({VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE, VK_DYNAMIC_STATE_DEPTH_BOUNDS}); |
| vk::CmdSetRasterizerDiscardEnableEXT(m_command_buffer, VK_TRUE); |
| m_command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, CreateAndDrawLinkedAndUnlinkedShaders) { |
| TEST_DESCRIPTION("Create and draw with some linked and some unlinked shaders."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredFeature(vkt::Feature::geometryShader); |
| AddRequiredFeature(vkt::Feature::tessellationShader); |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| 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 vert_spv = GLSLToSPV(stages[0], kVertexMinimalGlsl); |
| const auto tesc_spv = GLSLToSPV(stages[1], kTessellationControlMinimalGlsl); |
| const auto tese_spv = GLSLToSPV(stages[2], kTessellationEvalMinimalGlsl); |
| const auto geom_spv = GLSLToSPV(stages[3], kGeometryMinimalGlsl); |
| const auto frag_spv = GLSLToSPV(stages[4], kFragmentMinimalGlsl); |
| |
| VkShaderCreateInfoEXT create_infos[5]; |
| create_infos[0] = ShaderCreateInfoLink(vert_spv, stages[0], stages[1]); |
| create_infos[1] = ShaderCreateInfoLink(tesc_spv, stages[1], stages[2]); |
| create_infos[2] = ShaderCreateInfoLink(tese_spv, stages[2], stages[3] | stages[4]); |
| // unlinked shader |
| create_infos[3] = ShaderCreateInfoLink(geom_spv, stages[3], stages[4]); |
| create_infos[3].flags = 0; |
| create_infos[4] = ShaderCreateInfoLink(frag_spv, stages[4]); |
| create_infos[4].flags = 0; |
| |
| VkShaderEXT shaders[5]; |
| vk::CreateShadersEXT(*m_device, 3u, create_infos, nullptr, shaders); |
| for (uint32_t i = 3u; i < 5u; ++i) { |
| vk::CreateShadersEXT(*m_device, 1u, &create_infos[i], nullptr, &shaders[i]); |
| } |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude({}, true); |
| |
| vk::CmdBindShadersEXT(m_command_buffer, 5u, stages, shaders); |
| |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| |
| for (uint32_t i = 0; i < 5u; ++i) { |
| vk::DestroyShaderEXT(*m_device, shaders[i], nullptr); |
| } |
| } |
| |
| TEST_F(PositiveShaderObject, IgnoredColorAttachmentCount) { |
| TEST_DESCRIPTION("https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/6523/diffs"); |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitDynamicRenderTarget(); |
| CreateMinimalShaders(); |
| |
| VkRenderingInfo rendering_info = vku::InitStructHelper(); |
| rendering_info.colorAttachmentCount = 0; |
| rendering_info.layerCount = 1; |
| rendering_info.renderArea = {{0, 0}, {1, 1}}; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRendering(rendering_info); |
| |
| SetDefaultDynamicStatesExclude({VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT}); |
| m_command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, DisabledColorBlend) { |
| TEST_DESCRIPTION("Draw with shader objects without setting vkCmdSetColorBlendEquationEXT when color blend is disabled."); |
| |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitDynamicRenderTarget(); |
| CreateMinimalShaders(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude({VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT}); |
| m_command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| VkBool32 color_blend_enable = VK_FALSE; |
| vk::CmdSetColorBlendEnableEXT(m_command_buffer, 0u, 1u, &color_blend_enable); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, DrawWithVertGeomFragShaderObjects) { |
| TEST_DESCRIPTION("Draw with vertex, geometry and fragment shader objects bound."); |
| |
| AddRequiredFeature(vkt::Feature::geometryShader); |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| |
| InitDynamicRenderTarget(); |
| |
| const char vert_src[] = R"glsl( |
| #version 450 |
| |
| void main(void) { |
| vec2 pos = vec2(float(gl_VertexIndex & 1), float((gl_VertexIndex >> 1) & 1)); |
| gl_Position = vec4(pos - 0.5f, 0.0f, 1.0f); |
| } |
| )glsl"; |
| |
| const char geom_src[] = R"glsl( |
| #version 450 |
| layout(triangles) in; |
| layout(triangle_strip, max_vertices = 4) out; |
| |
| layout(location = 0) out vec4 color; |
| |
| void main(void) |
| { |
| gl_Position = gl_in[0].gl_Position; |
| gl_Position.y *= 1.5f; |
| gl_Position.z = 0.5f; |
| color = vec4(1.0f, 0.0f, 0.0f, 1.0f); |
| EmitVertex(); |
| gl_Position = gl_in[1].gl_Position; |
| gl_Position.y *= 1.5f; |
| gl_Position.z = 0.5f; |
| color = vec4(0.0f, 1.0f, 0.0f, 1.0f); |
| EmitVertex(); |
| gl_Position = gl_in[2].gl_Position; |
| gl_Position.y *= 1.5f; |
| gl_Position.z = 0.5f; |
| color = vec4(0.0f, 0.0f, 1.0f, 1.0f); |
| EmitVertex(); |
| EndPrimitive(); |
| } |
| )glsl"; |
| |
| const char frag_src[] = R"glsl( |
| #version 450 |
| |
| layout(location = 0) in vec4 in_color; |
| layout(location = 0) out vec4 out_color; |
| |
| void main(void) { |
| out_color = in_color; |
| } |
| )glsl"; |
| |
| const vkt::Shader vert_shader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, vert_src); |
| const vkt::Shader geom_shader(*m_device, VK_SHADER_STAGE_GEOMETRY_BIT, geom_src); |
| const vkt::Shader frag_shader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, frag_src); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude(); |
| m_command_buffer.BindShaders(vert_shader, frag_shader); |
| m_command_buffer.BindShaders(vert_shader, geom_shader, frag_shader); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, LineRasterization) { |
| AddRequiredExtensions(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::smoothLines); |
| AddRequiredFeature(vkt::Feature::alphaToOne); |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitRenderTarget(); |
| CreateMinimalShaders(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude({VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT, VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT, |
| VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY}); |
| m_command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| vk::CmdSetPrimitiveTopologyEXT(m_command_buffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP); |
| vk::CmdSetAlphaToOneEnableEXT(m_command_buffer, VK_TRUE); |
| vk::CmdSetLineRasterizationModeEXT(m_command_buffer, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH); |
| vk::CmdDraw(m_command_buffer, 4u, 1u, 0u, 0u); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, DiscardRectangleModeEXT) { |
| AddRequiredExtensions(VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME); |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| if (!DeviceExtensionSupported(VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME, 2)) { |
| GTEST_SKIP() << "need VK_EXT_discard_rectangles version 2"; |
| } |
| InitDynamicRenderTarget(); |
| CreateMinimalShaders(); |
| VkPhysicalDeviceDiscardRectanglePropertiesEXT discard_rectangle_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(discard_rectangle_properties); |
| std::vector<VkRect2D> discard_rectangles(discard_rectangle_properties.maxDiscardRectangles); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude(); |
| vk::CmdSetDiscardRectangleEnableEXT(m_command_buffer, VK_TRUE); |
| vk::CmdSetDiscardRectangleEXT(m_command_buffer, 0u, discard_rectangles.size(), discard_rectangles.data()); |
| vk::CmdSetDiscardRectangleModeEXT(m_command_buffer, VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT); |
| m_command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, SetPatchControlPointsEXT) { |
| AddRequiredFeature(vkt::Feature::tessellationShader); |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitDynamicRenderTarget(); |
| |
| const vkt::Shader vert_shader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl); |
| const vkt::Shader tesc_shader(*m_device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, kTessellationControlMinimalGlsl); |
| const vkt::Shader tese_shader(*m_device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, kTessellationEvalMinimalGlsl); |
| const vkt::Shader frag_shader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude({VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT, VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY}); |
| m_command_buffer.BindShaders(vert_shader, tesc_shader, tese_shader, frag_shader); |
| vk::CmdSetPrimitiveTopologyEXT(m_command_buffer, VK_PRIMITIVE_TOPOLOGY_PATCH_LIST); |
| vk::CmdSetPatchControlPointsEXT(m_command_buffer, 3); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, SetPointTopologyNoWrite) { |
| TEST_DESCRIPTION("Point size is ignored with maintenance5"); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::maintenance5); |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitDynamicRenderTarget(); |
| CreateMinimalShaders(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude(); |
| m_command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| vk::CmdSetPrimitiveTopologyEXT(m_command_buffer, VK_PRIMITIVE_TOPOLOGY_POINT_LIST); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, SetColorBlendAdvancedEXT) { |
| AddRequiredExtensions(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME); |
| RETURN_IF_SKIP(InitBasicShaderObject()); |
| InitDynamicRenderTarget(); |
| CreateMinimalShaders(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude({VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT}); |
| VkBool32 blend_enable = VK_TRUE; |
| vk::CmdSetColorBlendEnableEXT(m_command_buffer, 0u, 1u, &blend_enable); |
| VkColorBlendAdvancedEXT advanced = {VK_BLEND_OP_ADD, VK_FALSE, VK_FALSE, VK_BLEND_OVERLAP_UNCORRELATED_EXT, VK_FALSE}; |
| vk::CmdSetColorBlendAdvancedEXT(m_command_buffer, 0u, 1u, &advanced); |
| VkColorBlendEquationEXT equation = { |
| VK_BLEND_FACTOR_CONSTANT_COLOR, |
| VK_BLEND_FACTOR_ONE, |
| VK_BLEND_OP_ADD, |
| VK_BLEND_FACTOR_ONE, |
| VK_BLEND_FACTOR_ONE, |
| VK_BLEND_OP_ADD, |
| }; |
| vk::CmdSetColorBlendEquationEXT(m_command_buffer, 1u, 1u, &equation); |
| m_command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, MultiCreateGraphicsCompute) { |
| AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| AddRequiredFeature(vkt::Feature::shaderObject); |
| RETURN_IF_SKIP(Init()); |
| InitDynamicRenderTarget(); |
| |
| const auto vert_spv = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kMinimalShaderGlsl); |
| const auto frag_spv = GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kMinimalShaderGlsl); |
| const auto comp_spv = GLSLToSPV(VK_SHADER_STAGE_COMPUTE_BIT, kMinimalShaderGlsl); |
| |
| VkShaderCreateInfoEXT shader_create_infos[3]; |
| shader_create_infos[0] = ShaderCreateInfoLink(vert_spv, VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT); |
| shader_create_infos[1] = ShaderCreateInfoLink(frag_spv, VK_SHADER_STAGE_FRAGMENT_BIT); |
| shader_create_infos[2] = ShaderCreateInfo(comp_spv, VK_SHADER_STAGE_COMPUTE_BIT); |
| |
| VkShaderEXT shaders[3]; |
| vk::CreateShadersEXT(*m_device, 3, shader_create_infos, nullptr, shaders); |
| |
| VkRenderingInfo rendering_info = vku::InitStructHelper(); |
| rendering_info.colorAttachmentCount = 0; |
| rendering_info.layerCount = 1; |
| rendering_info.renderArea = {{0, 0}, {1, 1}}; |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRendering(rendering_info); |
| SetDefaultDynamicStatesExclude({VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT}); |
| const VkShaderStageFlagBits stages[] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT}; |
| vk::CmdBindShadersEXT(m_command_buffer, 2, stages, shaders); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| |
| for (uint32_t i = 0; i < 3; ++i) { |
| vk::DestroyShaderEXT(*m_device, shaders[i], nullptr); |
| } |
| } |
| |
| TEST_F(PositiveShaderObject, CustomResolve) { |
| AddRequiredExtensions(VK_EXT_CUSTOM_RESOLVE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| AddRequiredFeature(vkt::Feature::shaderObject); |
| AddRequiredFeature(vkt::Feature::customResolve); |
| RETURN_IF_SKIP(Init()); |
| CreateMinimalShaders(); |
| |
| VkFormat color_format = VK_FORMAT_B8G8R8A8_UNORM; |
| VkImageCreateInfo image_ci = vkt::Image::ImageCreateInfo2D(32, 32, 1, 1, color_format, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); |
| image_ci.samples = VK_SAMPLE_COUNT_4_BIT; |
| vkt::Image color_image(*m_device, image_ci); |
| vkt::ImageView color_image_view = color_image.CreateView(); |
| |
| image_ci.samples = VK_SAMPLE_COUNT_1_BIT; |
| vkt::Image resolve_image(*m_device, image_ci); |
| vkt::ImageView resolve_image_view = resolve_image.CreateView(); |
| |
| VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper(); |
| color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| color_attachment.imageView = color_image_view; |
| color_attachment.resolveMode = VK_RESOLVE_MODE_CUSTOM_BIT_EXT; |
| color_attachment.resolveImageView = resolve_image_view; |
| color_attachment.resolveImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
| |
| VkRenderingInfo begin_rendering_info = vku::InitStructHelper(); |
| begin_rendering_info.flags = VK_RENDERING_CUSTOM_RESOLVE_BIT_EXT; |
| begin_rendering_info.colorAttachmentCount = 1; |
| begin_rendering_info.pColorAttachments = &color_attachment; |
| begin_rendering_info.layerCount = 1; |
| begin_rendering_info.renderArea = {{0, 0}, {1, 1}}; |
| VkBeginCustomResolveInfoEXT begin_resolve_info = vku::InitStructHelper(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRendering(begin_rendering_info); |
| SetDefaultDynamicStatesExclude(); |
| vk::CmdSetRasterizationSamplesEXT(m_command_buffer, VK_SAMPLE_COUNT_4_BIT); |
| m_command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| vk::CmdBeginCustomResolveEXT(m_command_buffer, &begin_resolve_info); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(PositiveShaderObject, DisableShaderValidation) { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| AddRequiredFeature(vkt::Feature::shaderObject); |
| const VkLayerSettingEXT setting = {OBJECT_LAYER_NAME, "check_shaders", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &kVkFalse}; |
| VkLayerSettingsCreateInfoEXT layer_setting_ci = {VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, nullptr, 1, &setting}; |
| RETURN_IF_SKIP(InitFramework(&layer_setting_ci)); |
| RETURN_IF_SKIP(InitState()); |
| InitDynamicRenderTarget(); |
| CreateMinimalShaders(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| SetDefaultDynamicStatesExclude(); |
| m_command_buffer.BindShaders(m_vert_shader, m_frag_shader); |
| vk::CmdDraw(m_command_buffer, 4, 1, 0, 0); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |