From fd188ddd5176390efb22ed041d8aedad25d81dee Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Fri, 7 Jun 2019 13:07:57 -0300 Subject: Initial work on Vulkan: -Added VulkanContext -Added an X11 implementation -Added a rendering device abstraction -added a Vulkan rendering device abstraction -Engine does not work, only shows Godot logo (run it from bin/) --- drivers/vulkan/rendering_device_vulkan.cpp | 5164 ++++++++++++++++++++++++++++ 1 file changed, 5164 insertions(+) create mode 100644 drivers/vulkan/rendering_device_vulkan.cpp (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp new file mode 100644 index 0000000000..bcd103b67b --- /dev/null +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -0,0 +1,5164 @@ +#include "rendering_device_vulkan.h" +#include "drivers/vulkan/vulkan_context.h" + +#include "core/hashfuncs.h" +#include "core/project_settings.h" +#include "thirdparty/glslang/SPIRV/GlslangToSpv.h" +#include "thirdparty/glslang/glslang/Include/Types.h" + +void RenderingDeviceVulkan::_add_dependency(ID p_id, ID p_depends_on) { + + if (!dependency_map.has(p_depends_on)) { + dependency_map[p_depends_on] = Set(); + } + + dependency_map[p_depends_on].insert(p_id); + + if (!reverse_dependency_map.has(p_id)) { + reverse_dependency_map[p_id] = Set(); + } + + reverse_dependency_map[p_id].insert(p_depends_on); +} + +void RenderingDeviceVulkan::_free_dependencies(ID p_id) { + + //direct dependencies must be freed + List to_free; + Map >::Element *E = dependency_map.find(p_id); + if (E) { + + for (Set::Element *F = E->get().front(); F; F = F->next()) { + to_free.push_back(F->get()); + } + + dependency_map.erase(E); + + while (to_free.front()) { + free(to_free.front()->get()); + to_free.pop_front(); + } + } + + //reverse depenencies must be unreferenced + E = reverse_dependency_map.find(p_id); + + if (E) { + + for (Set::Element *F = E->get().front(); F; F = F->next()) { + Map >::Element *G = dependency_map.find(F->get()); + if (G) { + G->get().erase(p_id); + } + } + + reverse_dependency_map.erase(E); + } +} + +const VkFormat RenderingDeviceVulkan::vulkan_formats[RenderingDevice::DATA_FORMAT_MAX] = { + VK_FORMAT_R4G4_UNORM_PACK8, + VK_FORMAT_R4G4B4A4_UNORM_PACK16, + VK_FORMAT_B4G4R4A4_UNORM_PACK16, + VK_FORMAT_R5G6B5_UNORM_PACK16, + VK_FORMAT_B5G6R5_UNORM_PACK16, + VK_FORMAT_R5G5B5A1_UNORM_PACK16, + VK_FORMAT_B5G5R5A1_UNORM_PACK16, + VK_FORMAT_A1R5G5B5_UNORM_PACK16, + VK_FORMAT_R8_UNORM, + VK_FORMAT_R8_SNORM, + VK_FORMAT_R8_USCALED, + VK_FORMAT_R8_SSCALED, + VK_FORMAT_R8_UINT, + VK_FORMAT_R8_SINT, + VK_FORMAT_R8_SRGB, + VK_FORMAT_R8G8_UNORM, + VK_FORMAT_R8G8_SNORM, + VK_FORMAT_R8G8_USCALED, + VK_FORMAT_R8G8_SSCALED, + VK_FORMAT_R8G8_UINT, + VK_FORMAT_R8G8_SINT, + VK_FORMAT_R8G8_SRGB, + VK_FORMAT_R8G8B8_UNORM, + VK_FORMAT_R8G8B8_SNORM, + VK_FORMAT_R8G8B8_USCALED, + VK_FORMAT_R8G8B8_SSCALED, + VK_FORMAT_R8G8B8_UINT, + VK_FORMAT_R8G8B8_SINT, + VK_FORMAT_R8G8B8_SRGB, + VK_FORMAT_B8G8R8_UNORM, + VK_FORMAT_B8G8R8_SNORM, + VK_FORMAT_B8G8R8_USCALED, + VK_FORMAT_B8G8R8_SSCALED, + VK_FORMAT_B8G8R8_UINT, + VK_FORMAT_B8G8R8_SINT, + VK_FORMAT_B8G8R8_SRGB, + VK_FORMAT_R8G8B8A8_UNORM, + VK_FORMAT_R8G8B8A8_SNORM, + VK_FORMAT_R8G8B8A8_USCALED, + VK_FORMAT_R8G8B8A8_SSCALED, + VK_FORMAT_R8G8B8A8_UINT, + VK_FORMAT_R8G8B8A8_SINT, + VK_FORMAT_R8G8B8A8_SRGB, + VK_FORMAT_B8G8R8A8_UNORM, + VK_FORMAT_B8G8R8A8_SNORM, + VK_FORMAT_B8G8R8A8_USCALED, + VK_FORMAT_B8G8R8A8_SSCALED, + VK_FORMAT_B8G8R8A8_UINT, + VK_FORMAT_B8G8R8A8_SINT, + VK_FORMAT_B8G8R8A8_SRGB, + VK_FORMAT_A8B8G8R8_UNORM_PACK32, + VK_FORMAT_A8B8G8R8_SNORM_PACK32, + VK_FORMAT_A8B8G8R8_USCALED_PACK32, + VK_FORMAT_A8B8G8R8_SSCALED_PACK32, + VK_FORMAT_A8B8G8R8_UINT_PACK32, + VK_FORMAT_A8B8G8R8_SINT_PACK32, + VK_FORMAT_A8B8G8R8_SRGB_PACK32, + VK_FORMAT_A2R10G10B10_UNORM_PACK32, + VK_FORMAT_A2R10G10B10_SNORM_PACK32, + VK_FORMAT_A2R10G10B10_USCALED_PACK32, + VK_FORMAT_A2R10G10B10_SSCALED_PACK32, + VK_FORMAT_A2R10G10B10_UINT_PACK32, + VK_FORMAT_A2R10G10B10_SINT_PACK32, + VK_FORMAT_A2B10G10R10_UNORM_PACK32, + VK_FORMAT_A2B10G10R10_SNORM_PACK32, + VK_FORMAT_A2B10G10R10_USCALED_PACK32, + VK_FORMAT_A2B10G10R10_SSCALED_PACK32, + VK_FORMAT_A2B10G10R10_UINT_PACK32, + VK_FORMAT_A2B10G10R10_SINT_PACK32, + VK_FORMAT_R16_UNORM, + VK_FORMAT_R16_SNORM, + VK_FORMAT_R16_USCALED, + VK_FORMAT_R16_SSCALED, + VK_FORMAT_R16_UINT, + VK_FORMAT_R16_SINT, + VK_FORMAT_R16_SFLOAT, + VK_FORMAT_R16G16_UNORM, + VK_FORMAT_R16G16_SNORM, + VK_FORMAT_R16G16_USCALED, + VK_FORMAT_R16G16_SSCALED, + VK_FORMAT_R16G16_UINT, + VK_FORMAT_R16G16_SINT, + VK_FORMAT_R16G16_SFLOAT, + VK_FORMAT_R16G16B16_UNORM, + VK_FORMAT_R16G16B16_SNORM, + VK_FORMAT_R16G16B16_USCALED, + VK_FORMAT_R16G16B16_SSCALED, + VK_FORMAT_R16G16B16_UINT, + VK_FORMAT_R16G16B16_SINT, + VK_FORMAT_R16G16B16_SFLOAT, + VK_FORMAT_R16G16B16A16_UNORM, + VK_FORMAT_R16G16B16A16_SNORM, + VK_FORMAT_R16G16B16A16_USCALED, + VK_FORMAT_R16G16B16A16_SSCALED, + VK_FORMAT_R16G16B16A16_UINT, + VK_FORMAT_R16G16B16A16_SINT, + VK_FORMAT_R16G16B16A16_SFLOAT, + VK_FORMAT_R32_UINT, + VK_FORMAT_R32_SINT, + VK_FORMAT_R32_SFLOAT, + VK_FORMAT_R32G32_UINT, + VK_FORMAT_R32G32_SINT, + VK_FORMAT_R32G32_SFLOAT, + VK_FORMAT_R32G32B32_UINT, + VK_FORMAT_R32G32B32_SINT, + VK_FORMAT_R32G32B32_SFLOAT, + VK_FORMAT_R32G32B32A32_UINT, + VK_FORMAT_R32G32B32A32_SINT, + VK_FORMAT_R32G32B32A32_SFLOAT, + VK_FORMAT_R64_UINT, + VK_FORMAT_R64_SINT, + VK_FORMAT_R64_SFLOAT, + VK_FORMAT_R64G64_UINT, + VK_FORMAT_R64G64_SINT, + VK_FORMAT_R64G64_SFLOAT, + VK_FORMAT_R64G64B64_UINT, + VK_FORMAT_R64G64B64_SINT, + VK_FORMAT_R64G64B64_SFLOAT, + VK_FORMAT_R64G64B64A64_UINT, + VK_FORMAT_R64G64B64A64_SINT, + VK_FORMAT_R64G64B64A64_SFLOAT, + VK_FORMAT_B10G11R11_UFLOAT_PACK32, + VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, + VK_FORMAT_D16_UNORM, + VK_FORMAT_X8_D24_UNORM_PACK32, + VK_FORMAT_D32_SFLOAT, + VK_FORMAT_S8_UINT, + VK_FORMAT_D16_UNORM_S8_UINT, + VK_FORMAT_D24_UNORM_S8_UINT, + VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_FORMAT_BC1_RGB_UNORM_BLOCK, + VK_FORMAT_BC1_RGB_SRGB_BLOCK, + VK_FORMAT_BC1_RGBA_UNORM_BLOCK, + VK_FORMAT_BC1_RGBA_SRGB_BLOCK, + VK_FORMAT_BC2_UNORM_BLOCK, + VK_FORMAT_BC2_SRGB_BLOCK, + VK_FORMAT_BC3_UNORM_BLOCK, + VK_FORMAT_BC3_SRGB_BLOCK, + VK_FORMAT_BC4_UNORM_BLOCK, + VK_FORMAT_BC4_SNORM_BLOCK, + VK_FORMAT_BC5_UNORM_BLOCK, + VK_FORMAT_BC5_SNORM_BLOCK, + VK_FORMAT_BC6H_UFLOAT_BLOCK, + VK_FORMAT_BC6H_SFLOAT_BLOCK, + VK_FORMAT_BC7_UNORM_BLOCK, + VK_FORMAT_BC7_SRGB_BLOCK, + VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, + VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK, + VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK, + VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK, + VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK, + VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK, + VK_FORMAT_EAC_R11_UNORM_BLOCK, + VK_FORMAT_EAC_R11_SNORM_BLOCK, + VK_FORMAT_EAC_R11G11_UNORM_BLOCK, + VK_FORMAT_EAC_R11G11_SNORM_BLOCK, + VK_FORMAT_ASTC_4x4_UNORM_BLOCK, + VK_FORMAT_ASTC_4x4_SRGB_BLOCK, + VK_FORMAT_ASTC_5x4_UNORM_BLOCK, + VK_FORMAT_ASTC_5x4_SRGB_BLOCK, + VK_FORMAT_ASTC_5x5_UNORM_BLOCK, + VK_FORMAT_ASTC_5x5_SRGB_BLOCK, + VK_FORMAT_ASTC_6x5_UNORM_BLOCK, + VK_FORMAT_ASTC_6x5_SRGB_BLOCK, + VK_FORMAT_ASTC_6x6_UNORM_BLOCK, + VK_FORMAT_ASTC_6x6_SRGB_BLOCK, + VK_FORMAT_ASTC_8x5_UNORM_BLOCK, + VK_FORMAT_ASTC_8x5_SRGB_BLOCK, + VK_FORMAT_ASTC_8x6_UNORM_BLOCK, + VK_FORMAT_ASTC_8x6_SRGB_BLOCK, + VK_FORMAT_ASTC_8x8_UNORM_BLOCK, + VK_FORMAT_ASTC_8x8_SRGB_BLOCK, + VK_FORMAT_ASTC_10x5_UNORM_BLOCK, + VK_FORMAT_ASTC_10x5_SRGB_BLOCK, + VK_FORMAT_ASTC_10x6_UNORM_BLOCK, + VK_FORMAT_ASTC_10x6_SRGB_BLOCK, + VK_FORMAT_ASTC_10x8_UNORM_BLOCK, + VK_FORMAT_ASTC_10x8_SRGB_BLOCK, + VK_FORMAT_ASTC_10x10_UNORM_BLOCK, + VK_FORMAT_ASTC_10x10_SRGB_BLOCK, + VK_FORMAT_ASTC_12x10_UNORM_BLOCK, + VK_FORMAT_ASTC_12x10_SRGB_BLOCK, + VK_FORMAT_ASTC_12x12_UNORM_BLOCK, + VK_FORMAT_ASTC_12x12_SRGB_BLOCK, + VK_FORMAT_G8B8G8R8_422_UNORM, + VK_FORMAT_B8G8R8G8_422_UNORM, + VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, + VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, + VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, + VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, + VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, + VK_FORMAT_R10X6_UNORM_PACK16, + VK_FORMAT_R10X6G10X6_UNORM_2PACK16, + VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, + VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, + VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, + VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, + VK_FORMAT_R12X4_UNORM_PACK16, + VK_FORMAT_R12X4G12X4_UNORM_2PACK16, + VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, + VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, + VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, + VK_FORMAT_G16B16G16R16_422_UNORM, + VK_FORMAT_B16G16R16G16_422_UNORM, + VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, + VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, + VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, + VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, + VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, + VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, + VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, + VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG, + VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG, + VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG, + VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG, + VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG, + VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG, +}; + +const char *RenderingDeviceVulkan::named_formats[RenderingDevice::DATA_FORMAT_MAX] = { + "R4G4_Unorm_Pack8", + "R4G4B4A4_Unorm_Pack16", + "B4G4R4A4_Unorm_Pack16", + "R5G6B5_Unorm_Pack16", + "B5G6R5_Unorm_Pack16", + "R5G5B5A1_Unorm_Pack16", + "B5G5R5A1_Unorm_Pack16", + "A1R5G5B5_Unorm_Pack16", + "R8_Unorm", + "R8_Snorm", + "R8_Uscaled", + "R8_Sscaled", + "R8_Uint", + "R8_Sint", + "R8_Srgb", + "R8G8_Unorm", + "R8G8_Snorm", + "R8G8_Uscaled", + "R8G8_Sscaled", + "R8G8_Uint", + "R8G8_Sint", + "R8G8_Srgb", + "R8G8B8_Unorm", + "R8G8B8_Snorm", + "R8G8B8_Uscaled", + "R8G8B8_Sscaled", + "R8G8B8_Uint", + "R8G8B8_Sint", + "R8G8B8_Srgb", + "B8G8R8_Unorm", + "B8G8R8_Snorm", + "B8G8R8_Uscaled", + "B8G8R8_Sscaled", + "B8G8R8_Uint", + "B8G8R8_Sint", + "B8G8R8_Srgb", + "R8G8B8A8_Unorm", + "R8G8B8A8_Snorm", + "R8G8B8A8_Uscaled", + "R8G8B8A8_Sscaled", + "R8G8B8A8_Uint", + "R8G8B8A8_Sint", + "R8G8B8A8_Srgb", + "B8G8R8A8_Unorm", + "B8G8R8A8_Snorm", + "B8G8R8A8_Uscaled", + "B8G8R8A8_Sscaled", + "B8G8R8A8_Uint", + "B8G8R8A8_Sint", + "B8G8R8A8_Srgb", + "A8B8G8R8_Unorm_Pack32", + "A8B8G8R8_Snorm_Pack32", + "A8B8G8R8_Uscaled_Pack32", + "A8B8G8R8_Sscaled_Pack32", + "A8B8G8R8_Uint_Pack32", + "A8B8G8R8_Sint_Pack32", + "A8B8G8R8_Srgb_Pack32", + "A2R10G10B10_Unorm_Pack32", + "A2R10G10B10_Snorm_Pack32", + "A2R10G10B10_Uscaled_Pack32", + "A2R10G10B10_Sscaled_Pack32", + "A2R10G10B10_Uint_Pack32", + "A2R10G10B10_Sint_Pack32", + "A2B10G10R10_Unorm_Pack32", + "A2B10G10R10_Snorm_Pack32", + "A2B10G10R10_Uscaled_Pack32", + "A2B10G10R10_Sscaled_Pack32", + "A2B10G10R10_Uint_Pack32", + "A2B10G10R10_Sint_Pack32", + "R16_Unorm", + "R16_Snorm", + "R16_Uscaled", + "R16_Sscaled", + "R16_Uint", + "R16_Sint", + "R16_Sfloat", + "R16G16_Unorm", + "R16G16_Snorm", + "R16G16_Uscaled", + "R16G16_Sscaled", + "R16G16_Uint", + "R16G16_Sint", + "R16G16_Sfloat", + "R16G16B16_Unorm", + "R16G16B16_Snorm", + "R16G16B16_Uscaled", + "R16G16B16_Sscaled", + "R16G16B16_Uint", + "R16G16B16_Sint", + "R16G16B16_Sfloat", + "R16G16B16A16_Unorm", + "R16G16B16A16_Snorm", + "R16G16B16A16_Uscaled", + "R16G16B16A16_Sscaled", + "R16G16B16A16_Uint", + "R16G16B16A16_Sint", + "R16G16B16A16_Sfloat", + "R32_Uint", + "R32_Sint", + "R32_Sfloat", + "R32G32_Uint", + "R32G32_Sint", + "R32G32_Sfloat", + "R32G32B32_Uint", + "R32G32B32_Sint", + "R32G32B32_Sfloat", + "R32G32B32A32_Uint", + "R32G32B32A32_Sint", + "R32G32B32A32_Sfloat", + "R64_Uint", + "R64_Sint", + "R64_Sfloat", + "R64G64_Uint", + "R64G64_Sint", + "R64G64_Sfloat", + "R64G64B64_Uint", + "R64G64B64_Sint", + "R64G64B64_Sfloat", + "R64G64B64A64_Uint", + "R64G64B64A64_Sint", + "R64G64B64A64_Sfloat", + "B10G11R11_Ufloat_Pack32", + "E5B9G9R9_Ufloat_Pack32", + "D16_Unorm", + "X8_D24_Unorm_Pack32", + "D32_Sfloat", + "S8_Uint", + "D16_Unorm_S8_Uint", + "D24_Unorm_S8_Uint", + "D32_Sfloat_S8_Uint", + "Bc1_Rgb_Unorm_Block", + "Bc1_Rgb_Srgb_Block", + "Bc1_Rgba_Unorm_Block", + "Bc1_Rgba_Srgb_Block", + "Bc2_Unorm_Block", + "Bc2_Srgb_Block", + "Bc3_Unorm_Block", + "Bc3_Srgb_Block", + "Bc4_Unorm_Block", + "Bc4_Snorm_Block", + "Bc5_Unorm_Block", + "Bc5_Snorm_Block", + "Bc6H_Ufloat_Block", + "Bc6H_Sfloat_Block", + "Bc7_Unorm_Block", + "Bc7_Srgb_Block", + "Etc2_R8G8B8_Unorm_Block", + "Etc2_R8G8B8_Srgb_Block", + "Etc2_R8G8B8A1_Unorm_Block", + "Etc2_R8G8B8A1_Srgb_Block", + "Etc2_R8G8B8A8_Unorm_Block", + "Etc2_R8G8B8A8_Srgb_Block", + "Eac_R11_Unorm_Block", + "Eac_R11_Snorm_Block", + "Eac_R11G11_Unorm_Block", + "Eac_R11G11_Snorm_Block", + "Astc_4X4_Unorm_Block", + "Astc_4X4_Srgb_Block", + "Astc_5X4_Unorm_Block", + "Astc_5X4_Srgb_Block", + "Astc_5X5_Unorm_Block", + "Astc_5X5_Srgb_Block", + "Astc_6X5_Unorm_Block", + "Astc_6X5_Srgb_Block", + "Astc_6X6_Unorm_Block", + "Astc_6X6_Srgb_Block", + "Astc_8X5_Unorm_Block", + "Astc_8X5_Srgb_Block", + "Astc_8X6_Unorm_Block", + "Astc_8X6_Srgb_Block", + "Astc_8X8_Unorm_Block", + "Astc_8X8_Srgb_Block", + "Astc_10X5_Unorm_Block", + "Astc_10X5_Srgb_Block", + "Astc_10X6_Unorm_Block", + "Astc_10X6_Srgb_Block", + "Astc_10X8_Unorm_Block", + "Astc_10X8_Srgb_Block", + "Astc_10X10_Unorm_Block", + "Astc_10X10_Srgb_Block", + "Astc_12X10_Unorm_Block", + "Astc_12X10_Srgb_Block", + "Astc_12X12_Unorm_Block", + "Astc_12X12_Srgb_Block", + "G8B8G8R8_422_Unorm", + "B8G8R8G8_422_Unorm", + "G8_B8_R8_3Plane_420_Unorm", + "G8_B8R8_2Plane_420_Unorm", + "G8_B8_R8_3Plane_422_Unorm", + "G8_B8R8_2Plane_422_Unorm", + "G8_B8_R8_3Plane_444_Unorm", + "R10X6_Unorm_Pack16", + "R10X6G10X6_Unorm_2Pack16", + "R10X6G10X6B10X6A10X6_Unorm_4Pack16", + "G10X6B10X6G10X6R10X6_422_Unorm_4Pack16", + "B10X6G10X6R10X6G10X6_422_Unorm_4Pack16", + "G10X6_B10X6_R10X6_3Plane_420_Unorm_3Pack16", + "G10X6_B10X6R10X6_2Plane_420_Unorm_3Pack16", + "G10X6_B10X6_R10X6_3Plane_422_Unorm_3Pack16", + "G10X6_B10X6R10X6_2Plane_422_Unorm_3Pack16", + "G10X6_B10X6_R10X6_3Plane_444_Unorm_3Pack16", + "R12X4_Unorm_Pack16", + "R12X4G12X4_Unorm_2Pack16", + "R12X4G12X4B12X4A12X4_Unorm_4Pack16", + "G12X4B12X4G12X4R12X4_422_Unorm_4Pack16", + "B12X4G12X4R12X4G12X4_422_Unorm_4Pack16", + "G12X4_B12X4_R12X4_3Plane_420_Unorm_3Pack16", + "G12X4_B12X4R12X4_2Plane_420_Unorm_3Pack16", + "G12X4_B12X4_R12X4_3Plane_422_Unorm_3Pack16", + "G12X4_B12X4R12X4_2Plane_422_Unorm_3Pack16", + "G12X4_B12X4_R12X4_3Plane_444_Unorm_3Pack16", + "G16B16G16R16_422_Unorm", + "B16G16R16G16_422_Unorm", + "G16_B16_R16_3Plane_420_Unorm", + "G16_B16R16_2Plane_420_Unorm", + "G16_B16_R16_3Plane_422_Unorm", + "G16_B16R16_2Plane_422_Unorm", + "G16_B16_R16_3Plane_444_Unorm", + "Pvrtc1_2Bpp_Unorm_Block_Img", + "Pvrtc1_4Bpp_Unorm_Block_Img", + "Pvrtc2_2Bpp_Unorm_Block_Img", + "Pvrtc2_4Bpp_Unorm_Block_Img", + "Pvrtc1_2Bpp_Srgb_Block_Img", + "Pvrtc1_4Bpp_Srgb_Block_Img", + "Pvrtc2_2Bpp_Srgb_Block_Img", + "Pvrtc2_4Bpp_Srgb_Block_Img" +}; + +int RenderingDeviceVulkan::get_format_vertex_size(DataFormat p_format) { + switch (p_format) { + case DATA_FORMAT_R8_UNORM: + case DATA_FORMAT_R8_SNORM: + case DATA_FORMAT_R8_UINT: + case DATA_FORMAT_R8_SINT: + case DATA_FORMAT_R8G8_UNORM: + case DATA_FORMAT_R8G8_SNORM: + case DATA_FORMAT_R8G8_UINT: + case DATA_FORMAT_R8G8_SINT: + case DATA_FORMAT_R8G8B8_UNORM: + case DATA_FORMAT_R8G8B8_SNORM: + case DATA_FORMAT_R8G8B8_UINT: + case DATA_FORMAT_R8G8B8_SINT: + case DATA_FORMAT_B8G8R8_UNORM: + case DATA_FORMAT_B8G8R8_SNORM: + case DATA_FORMAT_B8G8R8_UINT: + case DATA_FORMAT_B8G8R8_SINT: + case DATA_FORMAT_R8G8B8A8_UNORM: + case DATA_FORMAT_R8G8B8A8_SNORM: + case DATA_FORMAT_R8G8B8A8_UINT: + case DATA_FORMAT_R8G8B8A8_SINT: + case DATA_FORMAT_B8G8R8A8_UNORM: + case DATA_FORMAT_B8G8R8A8_SNORM: + case DATA_FORMAT_B8G8R8A8_UINT: + case DATA_FORMAT_B8G8R8A8_SINT: return 4; + case DATA_FORMAT_R16_UNORM: + case DATA_FORMAT_R16_SNORM: + case DATA_FORMAT_R16_UINT: + case DATA_FORMAT_R16_SINT: + case DATA_FORMAT_R16_SFLOAT: return 4; + case DATA_FORMAT_R16G16_UNORM: + case DATA_FORMAT_R16G16_SNORM: + case DATA_FORMAT_R16G16_UINT: + case DATA_FORMAT_R16G16_SINT: + case DATA_FORMAT_R16G16_SFLOAT: return 4; + case DATA_FORMAT_R16G16B16_UNORM: + case DATA_FORMAT_R16G16B16_SNORM: + case DATA_FORMAT_R16G16B16_UINT: + case DATA_FORMAT_R16G16B16_SINT: + case DATA_FORMAT_R16G16B16_SFLOAT: return 8; + case DATA_FORMAT_R16G16B16A16_UNORM: + case DATA_FORMAT_R16G16B16A16_SNORM: + case DATA_FORMAT_R16G16B16A16_UINT: + case DATA_FORMAT_R16G16B16A16_SINT: + case DATA_FORMAT_R16G16B16A16_SFLOAT: return 8; + case DATA_FORMAT_R32_UINT: + case DATA_FORMAT_R32_SINT: + case DATA_FORMAT_R32_SFLOAT: return 4; + case DATA_FORMAT_R32G32_UINT: + case DATA_FORMAT_R32G32_SINT: + case DATA_FORMAT_R32G32_SFLOAT: return 8; + case DATA_FORMAT_R32G32B32_UINT: + case DATA_FORMAT_R32G32B32_SINT: + case DATA_FORMAT_R32G32B32_SFLOAT: return 12; + case DATA_FORMAT_R32G32B32A32_UINT: + case DATA_FORMAT_R32G32B32A32_SINT: + case DATA_FORMAT_R32G32B32A32_SFLOAT: return 16; + case DATA_FORMAT_R64_UINT: + case DATA_FORMAT_R64_SINT: + case DATA_FORMAT_R64_SFLOAT: return 8; + case DATA_FORMAT_R64G64_UINT: + case DATA_FORMAT_R64G64_SINT: + case DATA_FORMAT_R64G64_SFLOAT: return 16; + case DATA_FORMAT_R64G64B64_UINT: + case DATA_FORMAT_R64G64B64_SINT: + case DATA_FORMAT_R64G64B64_SFLOAT: return 24; + case DATA_FORMAT_R64G64B64A64_UINT: + case DATA_FORMAT_R64G64B64A64_SINT: + case DATA_FORMAT_R64G64B64A64_SFLOAT: return 32; + default: return 0; + } +} + +uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format) { + + switch (p_format) { + + case DATA_FORMAT_R4G4_UNORM_PACK8: return 1; + case DATA_FORMAT_R4G4B4A4_UNORM_PACK16: + case DATA_FORMAT_B4G4R4A4_UNORM_PACK16: + case DATA_FORMAT_R5G6B5_UNORM_PACK16: + case DATA_FORMAT_B5G6R5_UNORM_PACK16: + case DATA_FORMAT_R5G5B5A1_UNORM_PACK16: + case DATA_FORMAT_B5G5R5A1_UNORM_PACK16: + case DATA_FORMAT_A1R5G5B5_UNORM_PACK16: return 2; + case DATA_FORMAT_R8_UNORM: + case DATA_FORMAT_R8_SNORM: + case DATA_FORMAT_R8_USCALED: + case DATA_FORMAT_R8_SSCALED: + case DATA_FORMAT_R8_UINT: + case DATA_FORMAT_R8_SINT: + case DATA_FORMAT_R8_SRGB: return 1; + case DATA_FORMAT_R8G8_UNORM: + case DATA_FORMAT_R8G8_SNORM: + case DATA_FORMAT_R8G8_USCALED: + case DATA_FORMAT_R8G8_SSCALED: + case DATA_FORMAT_R8G8_UINT: + case DATA_FORMAT_R8G8_SINT: + case DATA_FORMAT_R8G8_SRGB: return 2; + case DATA_FORMAT_R8G8B8_UNORM: + case DATA_FORMAT_R8G8B8_SNORM: + case DATA_FORMAT_R8G8B8_USCALED: + case DATA_FORMAT_R8G8B8_SSCALED: + case DATA_FORMAT_R8G8B8_UINT: + case DATA_FORMAT_R8G8B8_SINT: + case DATA_FORMAT_R8G8B8_SRGB: + case DATA_FORMAT_B8G8R8_UNORM: + case DATA_FORMAT_B8G8R8_SNORM: + case DATA_FORMAT_B8G8R8_USCALED: + case DATA_FORMAT_B8G8R8_SSCALED: + case DATA_FORMAT_B8G8R8_UINT: + case DATA_FORMAT_B8G8R8_SINT: + case DATA_FORMAT_B8G8R8_SRGB: return 3; + case DATA_FORMAT_R8G8B8A8_UNORM: + case DATA_FORMAT_R8G8B8A8_SNORM: + case DATA_FORMAT_R8G8B8A8_USCALED: + case DATA_FORMAT_R8G8B8A8_SSCALED: + case DATA_FORMAT_R8G8B8A8_UINT: + case DATA_FORMAT_R8G8B8A8_SINT: + case DATA_FORMAT_R8G8B8A8_SRGB: + case DATA_FORMAT_B8G8R8A8_UNORM: + case DATA_FORMAT_B8G8R8A8_SNORM: + case DATA_FORMAT_B8G8R8A8_USCALED: + case DATA_FORMAT_B8G8R8A8_SSCALED: + case DATA_FORMAT_B8G8R8A8_UINT: + case DATA_FORMAT_B8G8R8A8_SINT: + case DATA_FORMAT_B8G8R8A8_SRGB: return 4; + case DATA_FORMAT_A8B8G8R8_UNORM_PACK32: + case DATA_FORMAT_A8B8G8R8_SNORM_PACK32: + case DATA_FORMAT_A8B8G8R8_USCALED_PACK32: + case DATA_FORMAT_A8B8G8R8_SSCALED_PACK32: + case DATA_FORMAT_A8B8G8R8_UINT_PACK32: + case DATA_FORMAT_A8B8G8R8_SINT_PACK32: + case DATA_FORMAT_A8B8G8R8_SRGB_PACK32: + case DATA_FORMAT_A2R10G10B10_UNORM_PACK32: + case DATA_FORMAT_A2R10G10B10_SNORM_PACK32: + case DATA_FORMAT_A2R10G10B10_USCALED_PACK32: + case DATA_FORMAT_A2R10G10B10_SSCALED_PACK32: + case DATA_FORMAT_A2R10G10B10_UINT_PACK32: + case DATA_FORMAT_A2R10G10B10_SINT_PACK32: + case DATA_FORMAT_A2B10G10R10_UNORM_PACK32: + case DATA_FORMAT_A2B10G10R10_SNORM_PACK32: + case DATA_FORMAT_A2B10G10R10_USCALED_PACK32: + case DATA_FORMAT_A2B10G10R10_SSCALED_PACK32: + case DATA_FORMAT_A2B10G10R10_UINT_PACK32: + case DATA_FORMAT_A2B10G10R10_SINT_PACK32: return 4; + case DATA_FORMAT_R16_UNORM: + case DATA_FORMAT_R16_SNORM: + case DATA_FORMAT_R16_USCALED: + case DATA_FORMAT_R16_SSCALED: + case DATA_FORMAT_R16_UINT: + case DATA_FORMAT_R16_SINT: + case DATA_FORMAT_R16_SFLOAT: return 2; + case DATA_FORMAT_R16G16_UNORM: + case DATA_FORMAT_R16G16_SNORM: + case DATA_FORMAT_R16G16_USCALED: + case DATA_FORMAT_R16G16_SSCALED: + case DATA_FORMAT_R16G16_UINT: + case DATA_FORMAT_R16G16_SINT: + case DATA_FORMAT_R16G16_SFLOAT: return 4; + case DATA_FORMAT_R16G16B16_UNORM: + case DATA_FORMAT_R16G16B16_SNORM: + case DATA_FORMAT_R16G16B16_USCALED: + case DATA_FORMAT_R16G16B16_SSCALED: + case DATA_FORMAT_R16G16B16_UINT: + case DATA_FORMAT_R16G16B16_SINT: + case DATA_FORMAT_R16G16B16_SFLOAT: return 6; + case DATA_FORMAT_R16G16B16A16_UNORM: + case DATA_FORMAT_R16G16B16A16_SNORM: + case DATA_FORMAT_R16G16B16A16_USCALED: + case DATA_FORMAT_R16G16B16A16_SSCALED: + case DATA_FORMAT_R16G16B16A16_UINT: + case DATA_FORMAT_R16G16B16A16_SINT: + case DATA_FORMAT_R16G16B16A16_SFLOAT: return 8; + case DATA_FORMAT_R32_UINT: + case DATA_FORMAT_R32_SINT: + case DATA_FORMAT_R32_SFLOAT: return 4; + case DATA_FORMAT_R32G32_UINT: + case DATA_FORMAT_R32G32_SINT: + case DATA_FORMAT_R32G32_SFLOAT: return 8; + case DATA_FORMAT_R32G32B32_UINT: + case DATA_FORMAT_R32G32B32_SINT: + case DATA_FORMAT_R32G32B32_SFLOAT: return 12; + case DATA_FORMAT_R32G32B32A32_UINT: + case DATA_FORMAT_R32G32B32A32_SINT: + case DATA_FORMAT_R32G32B32A32_SFLOAT: return 16; + case DATA_FORMAT_R64_UINT: + case DATA_FORMAT_R64_SINT: + case DATA_FORMAT_R64_SFLOAT: return 8; + case DATA_FORMAT_R64G64_UINT: + case DATA_FORMAT_R64G64_SINT: + case DATA_FORMAT_R64G64_SFLOAT: return 16; + case DATA_FORMAT_R64G64B64_UINT: + case DATA_FORMAT_R64G64B64_SINT: + case DATA_FORMAT_R64G64B64_SFLOAT: return 24; + case DATA_FORMAT_R64G64B64A64_UINT: + case DATA_FORMAT_R64G64B64A64_SINT: + case DATA_FORMAT_R64G64B64A64_SFLOAT: return 32; + case DATA_FORMAT_B10G11R11_UFLOAT_PACK32: + case DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32: return 4; + case DATA_FORMAT_D16_UNORM: return 2; + case DATA_FORMAT_X8_D24_UNORM_PACK32: return 4; + case DATA_FORMAT_D32_SFLOAT: return 4; + case DATA_FORMAT_S8_UINT: return 1; + case DATA_FORMAT_D16_UNORM_S8_UINT: return 4; + case DATA_FORMAT_D24_UNORM_S8_UINT: return 4; + case DATA_FORMAT_D32_SFLOAT_S8_UINT: return 5; //? + case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: + case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: + case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK: + case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK: + case DATA_FORMAT_BC2_UNORM_BLOCK: + case DATA_FORMAT_BC2_SRGB_BLOCK: + case DATA_FORMAT_BC3_UNORM_BLOCK: + case DATA_FORMAT_BC3_SRGB_BLOCK: + case DATA_FORMAT_BC4_UNORM_BLOCK: + case DATA_FORMAT_BC4_SNORM_BLOCK: + case DATA_FORMAT_BC5_UNORM_BLOCK: + case DATA_FORMAT_BC5_SNORM_BLOCK: + case DATA_FORMAT_BC6H_UFLOAT_BLOCK: + case DATA_FORMAT_BC6H_SFLOAT_BLOCK: + case DATA_FORMAT_BC7_UNORM_BLOCK: + case DATA_FORMAT_BC7_SRGB_BLOCK: return 1; + case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: return 1; + case DATA_FORMAT_EAC_R11_UNORM_BLOCK: + case DATA_FORMAT_EAC_R11_SNORM_BLOCK: + case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK: + case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK: return 1; + case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: + case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: + case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: + case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK: + case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK: + case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK: + case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK: + case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK: + case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK: return 1; + case DATA_FORMAT_G8B8G8R8_422_UNORM: + case DATA_FORMAT_B8G8R8G8_422_UNORM: return 4; + case DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM: + case DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM: + case DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM: + case DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM: + case DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM: return 4; + case DATA_FORMAT_R10X6_UNORM_PACK16: + case DATA_FORMAT_R10X6G10X6_UNORM_2PACK16: + case DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: + case DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: + case DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: + case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: + case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: + case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: + case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: + case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: + case DATA_FORMAT_R12X4_UNORM_PACK16: + case DATA_FORMAT_R12X4G12X4_UNORM_2PACK16: + case DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: + case DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: + case DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: + case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: + case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: + case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: + case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: + case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: return 2; + case DATA_FORMAT_G16B16G16R16_422_UNORM: + case DATA_FORMAT_B16G16R16G16_422_UNORM: + case DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM: + case DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM: + case DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM: + case DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM: + case DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM: return 8; + case DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return 1; + default: { + ERR_PRINT("Format not handled, bug"); + } + } + + return 1; +} + +// https://www.khronos.org/registry/DataFormat/specs/1.1/dataformat.1.1.pdf + +void RenderingDeviceVulkan::get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h) { + + switch (p_format) { + case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: + case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: + case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK: + case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK: + case DATA_FORMAT_BC2_UNORM_BLOCK: + case DATA_FORMAT_BC2_SRGB_BLOCK: + case DATA_FORMAT_BC3_UNORM_BLOCK: + case DATA_FORMAT_BC3_SRGB_BLOCK: + case DATA_FORMAT_BC4_UNORM_BLOCK: + case DATA_FORMAT_BC4_SNORM_BLOCK: + case DATA_FORMAT_BC5_UNORM_BLOCK: + case DATA_FORMAT_BC5_SNORM_BLOCK: + case DATA_FORMAT_BC6H_UFLOAT_BLOCK: + case DATA_FORMAT_BC6H_SFLOAT_BLOCK: + case DATA_FORMAT_BC7_UNORM_BLOCK: + case DATA_FORMAT_BC7_SRGB_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: + case DATA_FORMAT_EAC_R11_UNORM_BLOCK: + case DATA_FORMAT_EAC_R11_SNORM_BLOCK: + case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK: + case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK: + case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: //again, not sure about astc + case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: + case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: + case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK: + case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK: + case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK: + case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK: + case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK: + case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK: + r_w = 4; + r_h = 4; + return; + case DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: + r_w = 4; + r_h = 4; + return; + case DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: + r_w = 8; + r_h = 4; + return; + default: { + r_w = 1; + r_h = 1; + } + } +} + +uint32_t RenderingDeviceVulkan::get_compressed_image_format_block_byte_size(DataFormat p_format) { + + switch (p_format) { + case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: + case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: + case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK: + case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK: return 8; + case DATA_FORMAT_BC2_UNORM_BLOCK: + case DATA_FORMAT_BC2_SRGB_BLOCK: return 16; + case DATA_FORMAT_BC3_UNORM_BLOCK: + case DATA_FORMAT_BC3_SRGB_BLOCK: return 16; + case DATA_FORMAT_BC4_UNORM_BLOCK: + case DATA_FORMAT_BC4_SNORM_BLOCK: return 8; + case DATA_FORMAT_BC5_UNORM_BLOCK: + case DATA_FORMAT_BC5_SNORM_BLOCK: return 16; + case DATA_FORMAT_BC6H_UFLOAT_BLOCK: + case DATA_FORMAT_BC6H_SFLOAT_BLOCK: return 16; + case DATA_FORMAT_BC7_UNORM_BLOCK: + case DATA_FORMAT_BC7_SRGB_BLOCK: return 16; + case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: return 8; + case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: return 8; + case DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: return 16; + case DATA_FORMAT_EAC_R11_UNORM_BLOCK: + case DATA_FORMAT_EAC_R11_SNORM_BLOCK: return 8; + case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK: + case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK: return 16; + case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: //again, not sure about astc + case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK: + case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: + case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK: + case DATA_FORMAT_ASTC_5x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_5x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: + case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x5_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x5_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x8_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x8_SRGB_BLOCK: + case DATA_FORMAT_ASTC_10x10_UNORM_BLOCK: + case DATA_FORMAT_ASTC_10x10_SRGB_BLOCK: + case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK: + case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK: + case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK: + case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK: return 8; //wrong + case DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: return 8; //what varies is resolution + default: { + } + } + return 1; +} + +uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFormat p_format) { + + switch (p_format) { + case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: //these formats are half byte size, so rshift is 1 + case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: + case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK: + case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK: + case DATA_FORMAT_BC4_UNORM_BLOCK: + case DATA_FORMAT_BC4_SNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: + case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: + case DATA_FORMAT_EAC_R11_UNORM_BLOCK: + case DATA_FORMAT_EAC_R11_SNORM_BLOCK: + case DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return 1; + case DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: //these formats are quarter byte size, so rshift is 1 + case DATA_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: + case DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: + case DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: return 2; + default: { + } + } + + return 0; +} + +uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmap, uint32_t *r_blockw, uint32_t *r_blockh) { + + uint32_t w = p_width; + uint32_t h = p_height; + uint32_t d = p_depth; + + uint32_t size = 0; + + uint32_t pixel_size = get_image_format_pixel_size(p_format); + uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(p_format); + uint32_t blockw, blockh; + get_compressed_image_format_block_dimensions(p_format, blockw, blockh); + + for (uint32_t i = 0; i <= p_mipmap; i++) { + uint32_t bw = w % blockw != 0 ? w + (blockw - w % blockw) : w; + uint32_t bh = h % blockh != 0 ? h + (blockh - h % blockh) : h; + + print_line("bw " + itos(bw) + " bh " + itos(bh) + " pixsize " + itos(pixel_size) + " shift " + itos(pixel_rshift)); + uint32_t s = bw * bh; + + s *= pixel_size; + s >>= pixel_rshift; + size = s * d; + if (r_blockw) { + *r_blockw = bw; + } + if (r_blockh) { + *r_blockh = bh; + } + w = MAX(blockw, w >> 1); + h = MAX(blockh, h >> 1); + d = MAX(1, d >> 1); + } + + return size; +} + +uint32_t RenderingDeviceVulkan::get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth) { + + //formats and block size don't really matter here since they can all go down to 1px (even if block is larger) + int w = p_width; + int h = p_height; + int d = p_depth; + + int mipmaps = 1; + + while (true) { + + if (w == 1 && h == 1 && d == 1) { + break; + } + + w = MAX(1, w >> 1); + h = MAX(1, h >> 1); + d = MAX(1, d >> 1); + + mipmaps++; + }; + + return mipmaps; +} + +/////////////////////// + +const VkCompareOp RenderingDeviceVulkan::compare_operators[RenderingDevice::COMPARE_OP_MAX] = { + VK_COMPARE_OP_NEVER, + VK_COMPARE_OP_LESS, + VK_COMPARE_OP_EQUAL, + VK_COMPARE_OP_LESS_OR_EQUAL, + VK_COMPARE_OP_GREATER, + VK_COMPARE_OP_NOT_EQUAL, + VK_COMPARE_OP_GREATER_OR_EQUAL, + VK_COMPARE_OP_ALWAYS +}; + +const VkStencilOp RenderingDeviceVulkan::stencil_operations[RenderingDevice::STENCIL_OP_MAX] = { + VK_STENCIL_OP_KEEP, + VK_STENCIL_OP_ZERO, + VK_STENCIL_OP_REPLACE, + VK_STENCIL_OP_INCREMENT_AND_CLAMP, + VK_STENCIL_OP_DECREMENT_AND_CLAMP, + VK_STENCIL_OP_INVERT, + VK_STENCIL_OP_INCREMENT_AND_WRAP, + VK_STENCIL_OP_DECREMENT_AND_WRAP +}; + +const VkSampleCountFlagBits RenderingDeviceVulkan::rasterization_sample_count[RenderingDevice::TEXTURE_SAMPLES_MAX] = { + VK_SAMPLE_COUNT_1_BIT, + VK_SAMPLE_COUNT_2_BIT, + VK_SAMPLE_COUNT_4_BIT, + VK_SAMPLE_COUNT_8_BIT, + VK_SAMPLE_COUNT_16_BIT, + VK_SAMPLE_COUNT_32_BIT, + VK_SAMPLE_COUNT_64_BIT, +}; + +const VkLogicOp RenderingDeviceVulkan::logic_operations[RenderingDevice::LOGIC_OP_MAX] = { + VK_LOGIC_OP_CLEAR, + VK_LOGIC_OP_AND, + VK_LOGIC_OP_AND_REVERSE, + VK_LOGIC_OP_COPY, + VK_LOGIC_OP_AND_INVERTED, + VK_LOGIC_OP_NO_OP, + VK_LOGIC_OP_XOR, + VK_LOGIC_OP_OR, + VK_LOGIC_OP_NOR, + VK_LOGIC_OP_EQUIVALENT, + VK_LOGIC_OP_INVERT, + VK_LOGIC_OP_OR_REVERSE, + VK_LOGIC_OP_COPY_INVERTED, + VK_LOGIC_OP_OR_INVERTED, + VK_LOGIC_OP_NAND, + VK_LOGIC_OP_SET +}; + +const VkBlendFactor RenderingDeviceVulkan::blend_factors[RenderingDevice::BLEND_FACTOR_MAX] = { + VK_BLEND_FACTOR_ZERO, + VK_BLEND_FACTOR_ONE, + VK_BLEND_FACTOR_SRC_COLOR, + VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, + VK_BLEND_FACTOR_DST_COLOR, + VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, + VK_BLEND_FACTOR_SRC_ALPHA, + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + VK_BLEND_FACTOR_DST_ALPHA, + VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, + VK_BLEND_FACTOR_CONSTANT_COLOR, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, + VK_BLEND_FACTOR_CONSTANT_ALPHA, + VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA, + VK_BLEND_FACTOR_SRC_ALPHA_SATURATE, + VK_BLEND_FACTOR_SRC1_COLOR, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR, + VK_BLEND_FACTOR_SRC1_ALPHA, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA +}; +const VkBlendOp RenderingDeviceVulkan::blend_operations[RenderingDevice::BLEND_OP_MAX] = { + VK_BLEND_OP_ADD, + VK_BLEND_OP_SUBTRACT, + VK_BLEND_OP_REVERSE_SUBTRACT, + VK_BLEND_OP_MIN, + VK_BLEND_OP_MAX +}; + +const VkSamplerAddressMode RenderingDeviceVulkan::address_modes[RenderingDevice::SAMPLER_REPEAT_MODE_MAX] = { + VK_SAMPLER_ADDRESS_MODE_REPEAT, + VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE +}; + +const VkBorderColor RenderingDeviceVulkan::sampler_border_colors[RenderingDevice::SAMPLER_BORDER_COLOR_MAX] = { + VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, + VK_BORDER_COLOR_INT_TRANSPARENT_BLACK, + VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, + VK_BORDER_COLOR_INT_OPAQUE_BLACK, + VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, + VK_BORDER_COLOR_INT_OPAQUE_WHITE +}; +/***************************/ +/**** BUFFER MANAGEMENT ****/ +/***************************/ + +Error RenderingDeviceVulkan::_buffer_allocate(Buffer *p_buffer, uint32_t p_size, uint32_t p_usage, VmaMemoryUsage p_mapping) { + VkBufferCreateInfo bufferInfo; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.pNext = NULL; + bufferInfo.flags = 0; + bufferInfo.size = p_size; + bufferInfo.usage = p_usage; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + bufferInfo.queueFamilyIndexCount = 0; + bufferInfo.pQueueFamilyIndices = 0; + + VmaAllocationCreateInfo allocInfo; + allocInfo.flags = 0; + allocInfo.usage = p_mapping; + allocInfo.requiredFlags = 0; + allocInfo.preferredFlags = 0; + allocInfo.memoryTypeBits = 0; + allocInfo.pool = NULL; + allocInfo.pUserData = NULL; + + VkResult err = vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &p_buffer->buffer, &p_buffer->allocation, NULL); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + p_buffer->size = p_size; + p_buffer->buffer_info.buffer = p_buffer->buffer; + p_buffer->buffer_info.offset = 0; + p_buffer->buffer_info.range = p_size; + + return OK; +} + +Error RenderingDeviceVulkan::_buffer_free(Buffer *p_buffer) { + ERR_FAIL_COND_V(p_buffer->size == 0, ERR_INVALID_PARAMETER); + + vmaDestroyBuffer(allocator, p_buffer->buffer, p_buffer->allocation); + vmaFreeMemory(allocator, p_buffer->allocation); + p_buffer->buffer = NULL; + p_buffer->allocation = NULL; + p_buffer->size = 0; + + return OK; +} + +Error RenderingDeviceVulkan::_insert_staging_block() { + + VkBufferCreateInfo bufferInfo; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.pNext = NULL; + bufferInfo.flags = 0; + bufferInfo.size = staging_buffer_block_size; + bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + bufferInfo.queueFamilyIndexCount = 0; + bufferInfo.pQueueFamilyIndices = 0; + + VmaAllocationCreateInfo allocInfo; + allocInfo.flags = 0; + allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; + allocInfo.requiredFlags = 0; + allocInfo.preferredFlags = 0; + allocInfo.memoryTypeBits = 0; + allocInfo.pool = NULL; + allocInfo.pUserData = NULL; + + StagingBufferBlock block; + + VkResult err = vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &block.buffer, &block.allocation, NULL); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + block.frame_used = 0; + block.fill_amount = 0; + + staging_buffer_blocks.insert(staging_buffer_current, block); + return OK; +} + +Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment, bool p_on_draw_command_buffer) { + //determine a block to use + + r_alloc_size = p_amount; + + while (true) { + + r_alloc_offset = 0; + + //see if we can use current block + if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) { + //we used this block this frame, let's see if there is still room + + uint32_t write_from = staging_buffer_blocks[staging_buffer_current].fill_amount; + + { + uint32_t align_remainder = write_from % p_required_align; + if (align_remainder != 0) { + write_from += p_required_align - align_remainder; + } + } + + int32_t available_bytes = int32_t(staging_buffer_block_size) - int32_t(write_from); + + if ((int32_t)p_amount < available_bytes) { + //all is good, we should be ok, all will fit + r_alloc_offset = write_from; + } else if (p_can_segment && available_bytes >= (int32_t)p_required_align) { + //ok all won't fit but at least we can fit a chunkie + //all is good, update what needs to be written to + r_alloc_offset = write_from; + r_alloc_size = available_bytes - (available_bytes % p_required_align); + + } else { + //can't fit it into this buffer. + //will need to try next buffer + + staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size(); + + // before doing anything, though, let's check that we didn't manage to fill all blocks + // possible in a single frame + if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) { + //guess we did.. ok, let's see if we can insert a new block.. + if (staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) { + //we can, so we are safe + Error err = _insert_staging_block(); + if (err) { + return err; + } + //claim for this frame + staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; + } else { + // Ok, worst case scenario, all the staging buffers belong to this frame + // and this frame is not even done. + // If this is the main thread, it means the user is likely loading a lot of resources at once, + // otherwise, the thread should just be blocked until the next frame (currently unimplemented) + + if (false) { //separate thread from render + + //block_until_next_frame() + continue; + } else { + + //flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands + context->flush(true, p_on_draw_command_buffer); + //re-create the setup command + { + VkCommandBufferBeginInfo cmdbuf_begin; + cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdbuf_begin.pNext = NULL; + cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + cmdbuf_begin.pInheritanceInfo = NULL; + + VkResult err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + context->set_setup_buffer(frames[frame].setup_command_buffer); //append now so it's added before everything else + + if (p_on_draw_command_buffer) { + + err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + context->append_command_buffer(frames[frame].draw_command_buffer); + } + } + + //clear the whole staging buffer + for (int i = 0; i < staging_buffer_blocks.size(); i++) { + staging_buffer_blocks.write[i].frame_used = 0; + staging_buffer_blocks.write[i].fill_amount = 0; + } + //claim current + staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; + } + } + + } else { + //not from current frame, so continue and try again + continue; + } + } + + } else if (staging_buffer_blocks[staging_buffer_current].frame_used <= frames_drawn - frame_count) { + //this is an old block, which was already processed, let's reuse + staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; + staging_buffer_blocks.write[staging_buffer_current].fill_amount = 0; + } else if (staging_buffer_blocks[staging_buffer_current].frame_used > frames_drawn - frame_count) { + //this block may still be in use, let's not touch it unless we have to, so.. can we create a new one? + if (staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) { + //we are still allowed to create a new block, so let's do that and insert it for current pos + Error err = _insert_staging_block(); + if (err) { + return err; + } + //claim for this frame + staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; + } else { + // oops, we are out of room and we can't create more. + // let's flush older frames. + // The logic here is that if a game is loading a lot of data from the main thread, it will need to be stalled anyway. + // If loading from a separate thread, we can block that thread until next frame when more room is made (not currently implemented, though). + + if (false) { + //separate thread from render + //block_until_next_frame() + continue; //and try again + } else { + + context->flush(false); // flush previous frames (but don't touch setup command, so this frame) + + for (int i = 0; i < staging_buffer_blocks.size(); i++) { + //clear all blocks but the ones from this frame + int block_idx = (i + staging_buffer_current) % staging_buffer_blocks.size(); + if (staging_buffer_blocks[block_idx].frame_used == frames_drawn) { + break; //ok, we reached something from this frame, abort + } + + staging_buffer_blocks.write[block_idx].frame_used = 0; + staging_buffer_blocks.write[block_idx].fill_amount = 0; + } + + //claim for current frame + staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn; + } + } + } + + //all was good, break + break; + } + + staging_buffer_used = true; + + return OK; +} + +Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer, uint32_t p_required_align) { + + //submitting may get chunked for various reasons, so convert this to a task + size_t to_submit = p_data_size; + size_t submit_from = 0; + + while (to_submit > 0) { + + uint32_t block_write_offset; + uint32_t block_write_amount; + + Error err = _staging_buffer_allocate(MIN(to_submit, staging_buffer_block_size), p_required_align, block_write_offset, block_write_amount, p_use_draw_command_buffer); + if (err) { + return err; + } + + //map staging buffer (It's CPU and coherent) + + void *data_ptr = NULL; + { + VkResult vkerr = vmaMapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation, &data_ptr); + if (vkerr) { + ERR_FAIL_V(ERR_CANT_CREATE); + } + } + + //copy to staging buffer + copymem(((uint8_t *)data_ptr) + block_write_offset, p_data + submit_from, block_write_amount); + + //unmap + vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation); + //insert a command to copy this + + VkBufferCopy region; + region.srcOffset = block_write_offset; + region.dstOffset = submit_from + p_offset; + region.size = block_write_amount; + + vkCmdCopyBuffer(p_use_draw_command_buffer ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, staging_buffer_blocks[staging_buffer_current].buffer, p_buffer->buffer, 1, ®ion); + + staging_buffer_blocks.write[staging_buffer_current].fill_amount = block_write_offset + block_write_amount; + + to_submit -= block_write_amount; + submit_from += block_write_amount; + } + + return OK; +} + +/*****************/ +/**** TEXTURE ****/ +/*****************/ + +RenderingDevice::ID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector > &p_data) { + + _THREAD_SAFE_METHOD_ + + VkImageCreateInfo image_create_info; + image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_create_info.pNext = NULL; + image_create_info.flags = 0; + + if (p_format.type == TEXTURE_TYPE_CUBE || p_format.type == TEXTURE_TYPE_CUBE_ARRAY) { + image_create_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + } + /*if (p_format.type == TEXTURE_TYPE_2D || p_format.type == TEXTURE_TYPE_2D_ARRAY) { + image_create_info.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; + }*/ + + const VkImageType image_type[TEXTURE_TYPE_MAX] = { + VK_IMAGE_TYPE_1D, + VK_IMAGE_TYPE_2D, + VK_IMAGE_TYPE_3D, + VK_IMAGE_TYPE_2D, + VK_IMAGE_TYPE_1D, + VK_IMAGE_TYPE_2D, + VK_IMAGE_TYPE_3D + }; + + ERR_FAIL_INDEX_V(p_format.type, TEXTURE_TYPE_MAX, INVALID_ID); + + image_create_info.imageType = image_type[p_format.type]; + + ERR_FAIL_COND_V_MSG(p_format.width < 1, INVALID_ID, "Width must be equal or greater than 1 for all textures"); + + image_create_info.format = vulkan_formats[p_format.format]; + + image_create_info.extent.width = p_format.width; + if (image_create_info.imageType == VK_IMAGE_TYPE_3D || image_create_info.imageType == VK_IMAGE_TYPE_2D) { + ERR_FAIL_COND_V_MSG(p_format.height < 1, INVALID_ID, "Height must be equal or greater than 1 for 2D and 3D textures"); + image_create_info.extent.height = p_format.height; + } else { + image_create_info.extent.height = 1; + } + + if (image_create_info.imageType == VK_IMAGE_TYPE_3D) { + ERR_FAIL_COND_V_MSG(p_format.depth < 1, INVALID_ID, "Depth must be equal or greater than 1 for 3D textures"); + image_create_info.extent.depth = p_format.depth; + } else { + image_create_info.extent.depth = 1; + } + + ERR_FAIL_COND_V(p_format.mipmaps < 1, INVALID_ID); + + image_create_info.mipLevels = p_format.mipmaps; + + uint32_t array_layer_multiplier = 1; + if (p_format.type == TEXTURE_TYPE_CUBE_ARRAY || p_format.type == TEXTURE_TYPE_CUBE) { + array_layer_multiplier = 6; + } + if (p_format.type == TEXTURE_TYPE_1D_ARRAY || p_format.type == TEXTURE_TYPE_2D_ARRAY || p_format.type == TEXTURE_TYPE_CUBE_ARRAY || p_format.type == TEXTURE_TYPE_CUBE) { + ERR_FAIL_COND_V_MSG(p_format.array_layers < 1, INVALID_ID, + "Amount of layers must be equal or greater than 1 for arrays and cubemaps."); + if ((p_format.type == TEXTURE_TYPE_CUBE_ARRAY || p_format.type == TEXTURE_TYPE_CUBE) && (p_format.array_layers % 6) != 0) { + ERR_FAIL_V_MSG(INVALID_ID, "Cubemap and cubemap array textures must provide a layer number that is multiple of 6"); + } + image_create_info.arrayLayers = p_format.array_layers; + } else { + image_create_info.arrayLayers = 1; + } + + image_create_info.arrayLayers = p_format.array_layers; + + ERR_FAIL_INDEX_V(p_format.samples, TEXTURE_SAMPLES_MAX, INVALID_ID); + + image_create_info.samples = rasterization_sample_count[p_format.samples]; + image_create_info.tiling = (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL; + + //usage + image_create_info.usage = 0; + + if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; + } + + if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + } + + if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + } + + if (p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } + + image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_create_info.queueFamilyIndexCount = 0; + image_create_info.pQueueFamilyIndices = NULL; + image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + uint32_t required_mipmaps = get_image_required_mipmaps(image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth); + + ERR_FAIL_COND_V_MSG(required_mipmaps < image_create_info.mipLevels, INVALID_ID, + "Too many mipmaps requested for texture format and dimensions (" + itos(image_create_info.mipLevels) + "), maximum allowed: (" + itos(required_mipmaps) + ")."); + + if (p_data.size()) { + + ERR_FAIL_COND_V_MSG(!(p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT), INVALID_ID, + "Texture needs the TEXTURE_USAGE_CAN_UPDATE_BIT usage flag in order to be updated at initialization or later"); + + int expected_images = image_create_info.mipLevels * image_create_info.arrayLayers * array_layer_multiplier; + ERR_FAIL_COND_V_MSG(p_data.size() != expected_images, INVALID_ID, + "Default supplied data for image format is of invalid length (" + itos(p_data.size()) + "), should be (" + itos(expected_images) + ")."); + + int idx = 0; + for (uint32_t i = 0; i < image_create_info.arrayLayers * array_layer_multiplier; i++) { + for (uint32_t j = 0; j < image_create_info.mipLevels; j++) { + print_line("computed size from " + Vector3(image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth)); + uint32_t required_size = get_image_format_required_size(p_format.format, image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth, j); + ERR_FAIL_COND_V_MSG((uint32_t)p_data[idx].size() != required_size, INVALID_ID, + "Data for slice index " + itos(idx) + " (mapped to layer " + itos(i) + ", mipmap " + itos(j) + ") differs in size (supplied: " + itos(p_data[idx].size()) + ") than what is required by the format (" + itos(required_size) + ")."); + idx++; + } + } + } + + { + //validate that this image is supported for the intended use + VkFormatProperties properties; + vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), image_create_info.format, &properties); + VkFormatFeatureFlags flags; + + String format_text = "'" + String(named_formats[p_format.format]) + "'"; + + if (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) { + flags = properties.linearTilingFeatures; + format_text += " (with CPU read bit)"; + } else { + flags = properties.optimalTilingFeatures; + } + + if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT && !(flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { + ERR_FAIL_V_MSG(INVALID_ID, "Format " + format_text + " does not support usage as sampling texture."); + } + + if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) { + ERR_FAIL_V_MSG(INVALID_ID, "Format " + format_text + " does not support usage as color attachment."); + } + + if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + ERR_FAIL_V_MSG(INVALID_ID, "Format " + format_text + " does not support usage as depth-stencil attachment."); + } + + if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) { + ERR_FAIL_V_MSG(INVALID_ID, "Format " + format_text + " does not support usage as storage image."); + } + + if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_ATOMIC_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)) { + ERR_FAIL_V_MSG(INVALID_ID, "Format " + format_text + " does not support usage as atomic storage image."); + } + } + + //some view validation + + if (p_view.format_override != DATA_FORMAT_MAX) { + ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, INVALID_ID); + } + ERR_FAIL_INDEX_V(p_view.swizzle_r, TEXTURE_SWIZZLE_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_view.swizzle_g, TEXTURE_SWIZZLE_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_view.swizzle_b, TEXTURE_SWIZZLE_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_view.swizzle_a, TEXTURE_SWIZZLE_MAX, INVALID_ID); + + //allocate memory + + VmaAllocationCreateInfo allocInfo; + allocInfo.flags = 0; + allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + allocInfo.requiredFlags = 0; + allocInfo.preferredFlags = 0; + allocInfo.memoryTypeBits = 0; + allocInfo.pool = NULL; + allocInfo.pUserData = NULL; + + Texture texture; + + VkResult err = vmaCreateImage(allocator, &image_create_info, &allocInfo, &texture.image, &texture.allocation, &texture.allocation_info); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + texture.type = p_format.type; + texture.format = p_format.format; + texture.width = image_create_info.extent.width; + texture.height = image_create_info.extent.height; + texture.depth = image_create_info.extent.depth; + texture.layers = image_create_info.arrayLayers; + texture.mipmaps = image_create_info.mipLevels; + texture.usage_flags = p_format.usage_bits; + texture.samples = p_format.samples; + + if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + texture.aspect_mask = TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + texture.reading_layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; + texture.bound_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } else { + texture.aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; + texture.reading_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + texture.bound_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } + + texture.bound = false; + texture.owner = INVALID_ID; + + //create view + + VkImageViewCreateInfo image_view_create_info; + image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + image_view_create_info.pNext = NULL; + image_view_create_info.flags = 0; + image_view_create_info.image = texture.image; + + static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = { + VK_IMAGE_VIEW_TYPE_1D, + VK_IMAGE_VIEW_TYPE_2D, + VK_IMAGE_VIEW_TYPE_3D, + VK_IMAGE_VIEW_TYPE_CUBE, + VK_IMAGE_VIEW_TYPE_1D_ARRAY, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, + VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, + }; + + image_view_create_info.viewType = view_types[p_format.type]; + if (p_view.format_override == DATA_FORMAT_MAX) { + image_view_create_info.format = image_create_info.format; + } else { + image_view_create_info.format = vulkan_formats[p_view.format_override]; + } + + static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = { + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_ZERO, + VK_COMPONENT_SWIZZLE_ONE, + VK_COMPONENT_SWIZZLE_R, + VK_COMPONENT_SWIZZLE_G, + VK_COMPONENT_SWIZZLE_B, + VK_COMPONENT_SWIZZLE_A + }; + + image_view_create_info.components.r = component_swizzles[p_view.swizzle_r]; + image_view_create_info.components.g = component_swizzles[p_view.swizzle_g]; + image_view_create_info.components.b = component_swizzles[p_view.swizzle_b]; + image_view_create_info.components.a = component_swizzles[p_view.swizzle_a]; + + image_view_create_info.subresourceRange.baseMipLevel = 0; + image_view_create_info.subresourceRange.levelCount = image_create_info.mipLevels; + image_view_create_info.subresourceRange.baseArrayLayer = 0; + image_view_create_info.subresourceRange.layerCount = array_layer_multiplier * image_create_info.arrayLayers; + if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + } else { + image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + + err = vkCreateImageView(device, &image_view_create_info, NULL, &texture.view); + + if (err) { + vmaDestroyImage(allocator, texture.image, texture.allocation); + vmaFreeMemory(allocator, texture.allocation); + ERR_FAIL_V(INVALID_ID); + } + + //barrier to set layout + { + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_memory_barrier.newLayout = texture.reading_layout; + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = texture.image; + image_memory_barrier.subresourceRange.aspectMask = texture.aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = image_create_info.mipLevels; + image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.layerCount = image_create_info.arrayLayers * array_layer_multiplier; + + vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + ID id = texture_owner.make_id(texture); + + if (p_data.size()) { + + for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) { + for (uint32_t j = 0; j < image_create_info.mipLevels; j++) { + texture_update(id, j, i, p_data[i * image_create_info.mipLevels + j], true); + } + } + } + return id; +} + +RenderingDevice::ID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, ID p_with_texture) { + + Texture *src_texture = texture_owner.getornull(p_with_texture); + ERR_FAIL_COND_V(!src_texture, INVALID_ID); + + if (src_texture->owner != INVALID_ID) { //ahh this is a share + p_with_texture = src_texture->owner; + src_texture = texture_owner.getornull(src_texture->owner); + ERR_FAIL_COND_V(!src_texture, INVALID_ID); //this is a bug + } + + //create view + + Texture texture = *src_texture; + + uint32_t array_layer_multiplier = 1; + if (texture.type == TEXTURE_TYPE_CUBE_ARRAY || texture.type == TEXTURE_TYPE_CUBE) { + array_layer_multiplier = 6; + } + + VkImageViewCreateInfo image_view_create_info; + image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + image_view_create_info.pNext = NULL; + image_view_create_info.flags = 0; + image_view_create_info.image = texture.image; + + static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = { + VK_IMAGE_VIEW_TYPE_1D, + VK_IMAGE_VIEW_TYPE_2D, + VK_IMAGE_VIEW_TYPE_3D, + VK_IMAGE_VIEW_TYPE_CUBE, + VK_IMAGE_VIEW_TYPE_1D_ARRAY, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, + VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, + }; + + image_view_create_info.viewType = view_types[texture.type]; + if (p_view.format_override == DATA_FORMAT_MAX) { + image_view_create_info.format = vulkan_formats[texture.format]; + } else { + ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, INVALID_ID); + image_view_create_info.format = vulkan_formats[p_view.format_override]; + } + + static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = { + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_ZERO, + VK_COMPONENT_SWIZZLE_ONE, + VK_COMPONENT_SWIZZLE_R, + VK_COMPONENT_SWIZZLE_G, + VK_COMPONENT_SWIZZLE_B, + VK_COMPONENT_SWIZZLE_A + }; + + image_view_create_info.components.r = component_swizzles[p_view.swizzle_r]; + image_view_create_info.components.g = component_swizzles[p_view.swizzle_g]; + image_view_create_info.components.b = component_swizzles[p_view.swizzle_b]; + image_view_create_info.components.a = component_swizzles[p_view.swizzle_a]; + + image_view_create_info.subresourceRange.baseMipLevel = 0; + image_view_create_info.subresourceRange.levelCount = texture.mipmaps; + image_view_create_info.subresourceRange.layerCount = array_layer_multiplier * texture.layers; + image_view_create_info.subresourceRange.baseArrayLayer = 0; + + if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + } else { + image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + + VkResult err = vkCreateImageView(device, &image_view_create_info, NULL, &texture.view); + + if (err) { + ERR_FAIL_V(INVALID_ID); + } + + texture.owner = p_with_texture; + ID id = texture_owner.make_id(texture); + _add_dependency(id, p_with_texture); + + return id; +} + +Error RenderingDeviceVulkan::texture_update(ID p_texture, uint32_t p_mipmap, uint32_t p_layer, const PoolVector &p_data, bool p_sync_with_draw) { + + _THREAD_SAFE_METHOD_ + + Texture *texture = texture_owner.getornull(p_texture); + ERR_FAIL_COND_V(!texture, ERR_INVALID_PARAMETER); + + if (texture->owner != INVALID_ID) { + p_texture = texture->owner; + texture = texture_owner.getornull(texture->owner); + ERR_FAIL_COND_V(!texture, ERR_BUG); //this is a bug + } + + ERR_FAIL_COND_V_MSG(texture->bound, ERR_CANT_ACQUIRE_RESOURCE, + "Texture can't be updated while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); + + ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT), ERR_INVALID_PARAMETER, + "Texture requires the TEXTURE_USAGE_CAN_UPDATE_BIT in order to be updatable."); + + ERR_FAIL_COND_V(p_mipmap >= texture->mipmaps, ERR_INVALID_PARAMETER); + uint32_t layer_count = texture->layers; + if (texture->type == TEXTURE_TYPE_CUBE || texture->type == TEXTURE_TYPE_CUBE_ARRAY) { + layer_count *= 6; + } + ERR_FAIL_COND_V(p_layer >= layer_count, ERR_INVALID_PARAMETER); + + uint32_t width, height; + uint32_t image_size = get_image_format_required_size(texture->format, texture->width, texture->height, 1, p_mipmap, &width, &height); + uint32_t required_size = image_size * texture->depth; + + ERR_FAIL_COND_V_MSG(required_size != (uint32_t)p_data.size(), ERR_INVALID_PARAMETER, + "Required size for texture update (" + itos(required_size) + ") does not match data supplied size (" + itos(p_data.size()) + ")."); + + uint32_t region_size = texture_upload_region_size_px; + + PoolVector::Read r = p_data.read(); + + VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; + + //barrier to transfer + { + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.oldLayout = texture->reading_layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = texture->image; + image_memory_barrier.subresourceRange.aspectMask = texture->aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = p_mipmap; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + for (uint32_t z = 0; z < texture->depth; z++) { //for 3D textures, depth may be > 0 + + const uint8_t *read_ptr = r.ptr(); + read_ptr += image_size * z; + + for (uint32_t x = 0; x < width; x += region_size) { + for (uint32_t y = 0; y < height; y += region_size) { + + uint32_t region_w = MIN(region_size, width - x); + uint32_t region_h = MIN(region_size, height - y); + + uint32_t pixel_size = get_image_format_pixel_size(texture->format); + uint32_t to_allocate = region_w * region_h * pixel_size; + to_allocate >>= get_compressed_image_format_pixel_rshift(texture->format); + + uint32_t alloc_offset, alloc_size; + Error err = _staging_buffer_allocate(to_allocate, 32, alloc_offset, alloc_size, false, p_sync_with_draw); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + uint8_t *write_ptr; + + { //map + void *data_ptr = NULL; + VkResult vkerr = vmaMapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation, &data_ptr); + if (vkerr) { + ERR_FAIL_V(ERR_CANT_CREATE); + } + write_ptr = (uint8_t *)data_ptr; + write_ptr += alloc_offset; + } + + uint32_t block_w, block_h; + get_compressed_image_format_block_dimensions(texture->format, block_w, block_h); + + ERR_FAIL_COND_V(region_w % block_w, ERR_BUG); + ERR_FAIL_COND_V(region_h % block_h, ERR_BUG); + + if (block_w != 1 || block_h != 1) { + //compressed image (blocks) + //must copy a block region + + uint32_t block_size = get_compressed_image_format_block_byte_size(texture->format); + //re-create current variables in blocky format + uint32_t xb = x / block_w; + uint32_t yb = y / block_h; + uint32_t wb = width / block_w; + //uint32_t hb = height / block_h; + uint32_t region_wb = region_w / block_w; + uint32_t region_hb = region_h / block_h; + for (uint32_t xr = 0; xr < region_wb; xr++) { + for (uint32_t yr = 0; yr < region_hb; yr++) { + uint32_t src_offset = ((yr + yb) * wb + xr + xb) * block_size; + uint32_t dst_offset = (yr * region_wb + xr) * block_size; + //copy block + for (uint32_t i = 0; i < block_size; i++) { + write_ptr[dst_offset + i] = read_ptr[src_offset + i]; + } + } + } + + } else { + //regular image (pixels) + //must copy a pixel region + + for (uint32_t xr = 0; xr < region_w; xr++) { + for (uint32_t yr = 0; yr < region_h; yr++) { + uint32_t src_offset = ((yr + y) * width + xr + x) * pixel_size; + uint32_t dst_offset = (yr * region_w + xr) * pixel_size; + //copy block + for (uint32_t i = 0; i < pixel_size; i++) { + + write_ptr[dst_offset + i] = read_ptr[src_offset + i]; + } + } + } + } + + { //unmap + vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation); + } + + VkBufferImageCopy buffer_image_copy; + buffer_image_copy.bufferOffset = alloc_offset; + buffer_image_copy.bufferRowLength = 0; //tigthly packed + buffer_image_copy.bufferImageHeight = 0; //tigthly packed + + buffer_image_copy.imageSubresource.aspectMask = texture->aspect_mask; + buffer_image_copy.imageSubresource.baseArrayLayer = p_layer; + buffer_image_copy.imageSubresource.mipLevel = p_mipmap; + buffer_image_copy.imageSubresource.layerCount = 1; + + buffer_image_copy.imageOffset.x = x; + buffer_image_copy.imageOffset.y = y; + buffer_image_copy.imageOffset.z = z; + + buffer_image_copy.imageExtent.width = region_w; + buffer_image_copy.imageExtent.height = region_h; + buffer_image_copy.imageExtent.depth = 1; + + vkCmdCopyBufferToImage(command_buffer, staging_buffer_blocks[staging_buffer_current].buffer, texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_image_copy); + + staging_buffer_blocks.write[staging_buffer_current].fill_amount += alloc_size; + } + } + } + + //barrier to restore layout + { + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_memory_barrier.newLayout = texture->reading_layout; + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = texture->image; + image_memory_barrier.subresourceRange.aspectMask = texture->aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = p_mipmap; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + return OK; +} + +bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_format, TextureUsageBits p_usage) const { + ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false); + + _THREAD_SAFE_METHOD_ + + //validate that this image is supported for the intended use + VkFormatProperties properties; + vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), vulkan_formats[p_format], &properties); + VkFormatFeatureFlags flags; + + if (p_usage & TEXTURE_USAGE_CPU_READ_BIT) { + flags = properties.linearTilingFeatures; + } else { + flags = properties.optimalTilingFeatures; + } + + if (p_usage & TEXTURE_USAGE_SAMPLING_BIT && !(flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { + return false; + } + + if (p_usage & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) { + return false; + } + + if (p_usage & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + return false; + } + + if (p_usage & TEXTURE_USAGE_STORAGE_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) { + return false; + } + + if (p_usage & TEXTURE_USAGE_STORAGE_ATOMIC_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)) { + return false; + } + + return true; +} + +/********************/ +/**** ATTACHMENT ****/ +/********************/ + +VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector &p_format, InitialAction p_initial_action, FinalAction p_final_action, int *r_color_attachment_count) { + + Vector attachments; + Vector color_references; + Vector depth_stencil_references; + Vector resolve_references; + + for (int i = 0; i < p_format.size(); i++) { + + VkAttachmentDescription description; + + description.flags = 0; + ERR_FAIL_INDEX_V(p_format[i].format, DATA_FORMAT_MAX, VK_NULL_HANDLE); + description.format = vulkan_formats[p_format[i].format]; + ERR_FAIL_INDEX_V(p_format[i].samples, TEXTURE_SAMPLES_MAX, VK_NULL_HANDLE); + description.samples = rasterization_sample_count[p_format[i].samples]; + //anything below does not really matter, as vulkan just ignores it when creating a pipeline + + switch (p_initial_action) { + + case INITIAL_ACTION_CLEAR: { + description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } break; + case INITIAL_ACTION_KEEP_COLOR: { + if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + description.initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } + } break; + case INITIAL_ACTION_KEEP_COLOR_AND_DEPTH: { + + if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + description.initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + description.initialLayout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; //don't care what is there + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } + + } break; + case INITIAL_ACTION_CONTINUE: { + if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + description.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + description.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; //don't care what is there + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } + } break; + default: { + ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here + } + } + + switch (p_final_action) { + case FINAL_ACTION_READ_COLOR_AND_DEPTH: { + if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + + description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } + break; + case FINAL_ACTION_READ_COLOR_DISCARD_DEPTH: { + if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + + description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } + } break; + case FINAL_ACTION_DISCARD: { + if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + + description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } + } break; + case FINAL_ACTION_CONTINUE: { + if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + + description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } else { + description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there + } + + } break; + default: { + ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here + } + } + } + + attachments.push_back(description); + + VkAttachmentReference reference; + reference.attachment = i; + + if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + color_references.push_back(reference); + } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + depth_stencil_references.push_back(reference); + } else if (p_format[i].usage_flags & TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT) { + reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + resolve_references.push_back(reference); + } else { + ERR_FAIL_V_MSG(VK_NULL_HANDLE, "Texture index " + itos(i) + " is neither color, depth stencil or resolve so it can't be used as attachment."); + } + } + + ERR_FAIL_COND_V(depth_stencil_references.size() > 1, VK_NULL_HANDLE); + ERR_FAIL_COND_V(resolve_references.size() > 1, VK_NULL_HANDLE); + + VkSubpassDescription subpass; + subpass.flags = 0; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = 0; //unsupported for now + subpass.pInputAttachments = NULL; + subpass.colorAttachmentCount = color_references.size(); + subpass.pColorAttachments = color_references.ptr(); + subpass.pDepthStencilAttachment = depth_stencil_references.ptr(); + subpass.pResolveAttachments = resolve_references.ptr(); + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = NULL; + + VkRenderPassCreateInfo render_pass_create_info; + render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + render_pass_create_info.pNext = NULL; + render_pass_create_info.flags = 0; + render_pass_create_info.attachmentCount = attachments.size(); + render_pass_create_info.pAttachments = attachments.ptr(); + render_pass_create_info.subpassCount = 1; + render_pass_create_info.pSubpasses = &subpass; + render_pass_create_info.dependencyCount = 0; + render_pass_create_info.pDependencies = NULL; + + VkRenderPass render_pass; + VkResult res = vkCreateRenderPass(device, &render_pass_create_info, NULL, &render_pass); + ERR_FAIL_COND_V(res, VK_NULL_HANDLE); + + if (r_color_attachment_count) { + *r_color_attachment_count = color_references.size(); + } + return render_pass; +} + +RenderingDevice::ID RenderingDeviceVulkan::framebuffer_format_create(const Vector &p_format) { + + _THREAD_SAFE_METHOD_ + + FramebufferFormatKey key; + key.attachments = p_format; + + const Map::Element *E = framebuffer_format_cache.find(key); + if (E) { + //exists, return + return E->get(); + } + + int color_references; + VkRenderPass render_pass = _render_pass_create(p_format, INITIAL_ACTION_CLEAR, FINAL_ACTION_DISCARD, &color_references); //actions don't matter for this use case + + ID id = ID(framebuffer_format_cache.size()) | (ID(ID_TYPE_FRAMEBUFFER_FORMAT) << ID(ID_BASE_SHIFT)); + + E = framebuffer_format_cache.insert(key, id); + FramebufferFormat fb_format; + fb_format.E = E; + fb_format.color_attachments = color_references; + fb_format.render_pass = render_pass; + framebuffer_formats[id] = fb_format; + return id; +} + +/***********************/ +/**** RENDER TARGET ****/ +/***********************/ + +RenderingDevice::ID RenderingDeviceVulkan::framebuffer_create(const Vector &p_texture_attachments, ID p_format_check) { + + _THREAD_SAFE_METHOD_ + + Vector attachments; + Size2i size; + + for (int i = 0; i < p_texture_attachments.size(); i++) { + Texture *texture = texture_owner.getornull(p_texture_attachments[i]); + ERR_FAIL_COND_V_MSG(!texture, INVALID_ID, "Texture index supplied for framebuffer (" + itos(i) + ") is not a valid texture."); + + if (i == 0) { + size.width = texture->width; + size.height = texture->height; + } else { + ERR_FAIL_COND_V_MSG((uint32_t)size.width != texture->width || (uint32_t)size.height != texture->height, INVALID_ID, + "All textures in a framebuffer should be the same size."); + } + + AttachmentFormat af; + af.format = texture->format; + af.samples = texture->samples; + af.usage_flags = texture->usage_flags; + attachments.push_back(af); + } + + ID format_id = framebuffer_format_create(attachments); + if (format_id == INVALID_ID) { + return INVALID_ID; + } + + ERR_FAIL_COND_V_MSG(p_format_check != INVALID_ID && format_id != p_format_check, INVALID_ID, + "The format used to check this framebuffer differs from the intended framebuffer format."); + + Framebuffer framebuffer; + framebuffer.format_id = format_id; + framebuffer.texture_ids = p_texture_attachments; + framebuffer.size = size; + + ID id = framebuffer_owner.make_id(framebuffer); + + for (int i = 0; i < p_texture_attachments.size(); i++) { + _add_dependency(id, p_texture_attachments[i]); + } + + return id; +} + +RenderingDevice::ID RenderingDeviceVulkan::framebuffer_get_format(ID p_framebuffer) { + + _THREAD_SAFE_METHOD_ + + Framebuffer *framebuffer = framebuffer_owner.getornull(p_framebuffer); + ERR_FAIL_COND_V(!framebuffer, INVALID_ID); + + return framebuffer->format_id; +} + +/*****************/ +/**** SAMPLER ****/ +/*****************/ + +RenderingDevice::ID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) { + + _THREAD_SAFE_METHOD_ + + VkSamplerCreateInfo sampler_create_info; + sampler_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + sampler_create_info.pNext = NULL; + sampler_create_info.flags = 0; + sampler_create_info.magFilter = p_state.mag_filter == SAMPLER_FILTER_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; + sampler_create_info.minFilter = p_state.min_filter == SAMPLER_FILTER_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; + sampler_create_info.mipmapMode = p_state.mip_filter == SAMPLER_FILTER_LINEAR ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST; + + ERR_FAIL_INDEX_V(p_state.repeat_u, SAMPLER_REPEAT_MODE_MAX, INVALID_ID); + sampler_create_info.addressModeU = address_modes[p_state.repeat_u]; + ERR_FAIL_INDEX_V(p_state.repeat_v, SAMPLER_REPEAT_MODE_MAX, INVALID_ID); + sampler_create_info.addressModeV = address_modes[p_state.repeat_v]; + ERR_FAIL_INDEX_V(p_state.repeat_w, SAMPLER_REPEAT_MODE_MAX, INVALID_ID); + sampler_create_info.addressModeW = address_modes[p_state.repeat_w]; + + sampler_create_info.mipLodBias = p_state.lod_bias; + sampler_create_info.anisotropyEnable = p_state.use_anisotropy; + sampler_create_info.maxAnisotropy = p_state.anisotropy_max; + sampler_create_info.compareEnable = p_state.enable_compare; + + ERR_FAIL_INDEX_V(p_state.compare_op, COMPARE_OP_MAX, INVALID_ID); + sampler_create_info.compareOp = compare_operators[p_state.compare_op]; + + sampler_create_info.minLod = p_state.min_lod; + sampler_create_info.maxLod = p_state.max_lod; + + ERR_FAIL_INDEX_V(p_state.border_color, SAMPLER_BORDER_COLOR_MAX, INVALID_ID); + sampler_create_info.borderColor = sampler_border_colors[p_state.border_color]; + + sampler_create_info.unnormalizedCoordinates = p_state.unnormalized_uvw; + + VkSampler sampler; + VkResult res = vkCreateSampler(device, &sampler_create_info, NULL, &sampler); + ERR_FAIL_COND_V(res, INVALID_ID); + + return sampler_owner.make_id(sampler); +} + +/**********************/ +/**** VERTEX ARRAY ****/ +/**********************/ + +RenderingDevice::ID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const PoolVector &p_data) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, INVALID_ID); + + Buffer buffer; + _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + if (p_data.size()) { + uint64_t data_size = p_data.size(); + PoolVector::Read r = p_data.read(); + _buffer_update(&buffer, 0, r.ptr(), data_size); + } + return vertex_buffer_owner.make_id(buffer); +} + +// Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated +RenderingDevice::ID RenderingDeviceVulkan::vertex_description_create(const Vector &p_vertex_descriptions) { + + _THREAD_SAFE_METHOD_ + + VertexDescriptionKey key; + key.vertex_descriptions = p_vertex_descriptions; + const Map::Element *E = vertex_description_cache.find(key); + if (E) { + return E->get(); + } + //does not exist, create one and cache it + VertexDescriptionCache vdcache; + vdcache.bindings = memnew_arr(VkVertexInputBindingDescription, p_vertex_descriptions.size()); + vdcache.attributes = memnew_arr(VkVertexInputAttributeDescription, p_vertex_descriptions.size()); + Set used_locations; + for (int i = 0; i < p_vertex_descriptions.size(); i++) { + ERR_CONTINUE(p_vertex_descriptions[i].format >= DATA_FORMAT_MAX); + ERR_FAIL_COND_V(used_locations.has(p_vertex_descriptions[i].location), INVALID_ID); + + ERR_FAIL_COND_V_MSG(get_format_vertex_size(p_vertex_descriptions[i].format) == 0, INVALID_ID, + "Data format for attachment (" + itos(i) + ") is not valid for a vertex array."); + + vdcache.bindings[i].binding = i; + vdcache.bindings[i].stride = p_vertex_descriptions[i].stride; + vdcache.bindings[i].inputRate = p_vertex_descriptions[i].frequency == VERTEX_FREQUENCY_INSTANCE ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; + vdcache.attributes[i].binding = i; + vdcache.attributes[i].location = p_vertex_descriptions[i].location; + vdcache.attributes[i].format = vulkan_formats[p_vertex_descriptions[i].format]; + vdcache.attributes[i].offset = p_vertex_descriptions[i].offset; + used_locations.insert(p_vertex_descriptions[i].location); + } + + vdcache.create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vdcache.create_info.pNext = NULL; + vdcache.create_info.flags = 0; + + vdcache.create_info.vertexAttributeDescriptionCount = p_vertex_descriptions.size(); + vdcache.create_info.pVertexAttributeDescriptions = vdcache.attributes; + + vdcache.create_info.vertexBindingDescriptionCount = p_vertex_descriptions.size(); + vdcache.create_info.pVertexBindingDescriptions = vdcache.bindings; + + ID id = ID(vertex_description_cache.size()) | (ID(ID_TYPE_VERTEX_DESCRIPTION) << ID_BASE_SHIFT); + vdcache.E = vertex_description_cache.insert(key, id); + vertex_descriptions[id] = vdcache; + return id; +} + +RenderingDevice::ID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, ID p_vertex_description, const Vector &p_src_buffers) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(!vertex_descriptions.has(p_vertex_description), INVALID_ID); + const VertexDescriptionCache &vd = vertex_descriptions[p_vertex_description]; + + ERR_FAIL_COND_V(vd.E->key().vertex_descriptions.size() != p_src_buffers.size(), INVALID_ID); + + for (int i = 0; i < p_src_buffers.size(); i++) { + ERR_FAIL_COND_V(!vertex_buffer_owner.owns(p_src_buffers[i]), INVALID_ID); + } + + VertexArray vertex_array; + + vertex_array.vertex_count = p_vertex_count; + vertex_array.description = p_vertex_description; + vertex_array.max_instances_allowed = 0xFFFFFFFF; //by default as many as you want + for (int i = 0; i < p_src_buffers.size(); i++) { + Buffer *buffer = vertex_buffer_owner.getornull(p_src_buffers[i]); + + //validate with buffer + { + const VertexDescription &atf = vd.E->key().vertex_descriptions[i]; + uint32_t element_size = get_format_vertex_size(atf.format); + ERR_FAIL_COND_V(element_size == 0, INVALID_ID); //should never happens since this was prevalidated + + if (atf.frequency == VERTEX_FREQUENCY_VERTEX) { + //validate size for regular drawing + uint64_t total_size = uint64_t(atf.stride) * (p_vertex_count - 1) + atf.offset + element_size; + ERR_FAIL_COND_V_MSG(total_size > buffer->size, INVALID_ID, + "Attachment (" + itos(i) + ") will read past the end of the buffer."); + + } else { + //validate size for instances drawing + uint64_t available = buffer->size - atf.offset; + ERR_FAIL_COND_V_MSG(available < element_size, INVALID_ID, + "Attachment (" + itos(i) + ") uses instancing, but it's just too small."); + + uint32_t instances_allowed = available / atf.stride; + vertex_array.max_instances_allowed = MIN(instances_allowed, vertex_array.max_instances_allowed); + } + } + + vertex_array.buffers.push_back(buffer->buffer); + vertex_array.offsets.push_back(0); //offset unused, but passing anyway + } + + ID id = vertex_array_owner.make_id(vertex_array); + for (int i = 0; i < p_src_buffers.size(); i++) { + _add_dependency(id, p_src_buffers[i]); + } + + return id; +} + +RenderingDevice::ID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBufferFormat p_format, const PoolVector &p_data, bool p_use_restart_indices) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(p_index_count == 0, INVALID_ID); + + IndexBuffer index_buffer; + index_buffer.index_type = (p_format == INDEX_BUFFER_FORMAT_UINT16) ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32; + index_buffer.supports_restart_indices = p_use_restart_indices; + index_buffer.index_count = p_index_count; + uint32_t size_bytes = p_index_count * ((p_format == INDEX_BUFFER_FORMAT_UINT16) ? 2 : 4); +#ifdef DEBUG_ENABLED + if (p_data.size()) { + index_buffer.max_index = 0; + ERR_FAIL_COND_V_MSG((uint32_t)p_data.size() != size_bytes, INVALID_ID, + "Default index buffer initializer array size (" + itos(p_data.size()) + ") does not match format required size (" + itos(size_bytes) + ")."); + PoolVector::Read r = p_data.read(); + if (p_format == INDEX_BUFFER_FORMAT_UINT16) { + const uint16_t *index16 = (const uint16_t *)r.ptr(); + for (uint32_t i = 0; i < p_index_count; i++) { + if (p_use_restart_indices && index16[i] == 0xFFFF) { + continue; //restart index, ingnore + } + index_buffer.max_index = MAX(index16[i], index_buffer.max_index); + } + } else { + const uint32_t *index32 = (const uint32_t *)r.ptr(); + for (uint32_t i = 0; i < p_index_count; i++) { + if (p_use_restart_indices && index32[i] == 0xFFFFFFFF) { + continue; //restart index, ingnore + } + index_buffer.max_index = MAX(index32[i], index_buffer.max_index); + } + } + } else { + index_buffer.max_index = 0xFFFFFFFF; + } +#else + index_buffer.max_index = 0xFFFFFFFF; +#endif + _buffer_allocate(&index_buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + if (p_data.size()) { + uint64_t data_size = p_data.size(); + PoolVector::Read r = p_data.read(); + _buffer_update(&index_buffer, 0, r.ptr(), data_size); + } + return index_buffer_owner.make_id(index_buffer); +} + +RenderingDevice::ID RenderingDeviceVulkan::index_array_create(ID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(!index_buffer_owner.owns(p_index_buffer), INVALID_ID); + + IndexBuffer *index_buffer = index_buffer_owner.getornull(p_index_buffer); + + ERR_FAIL_COND_V(p_index_count == 0, INVALID_ID); + ERR_FAIL_COND_V(p_index_offset + p_index_count > index_buffer->index_count, INVALID_ID); + + IndexArray index_array; + index_array.max_index = index_buffer->max_index; + index_array.buffer = index_buffer->buffer; + index_array.offset = p_index_offset; + index_array.indices = p_index_count; + index_array.index_type = index_buffer->index_type; + index_array.supports_restart_indices = index_buffer->supports_restart_indices; + + ID id = index_array_owner.make_id(index_array); + _add_dependency(id, p_index_buffer); + return id; +} + +/****************/ +/**** SHADER ****/ +/****************/ + +static const TBuiltInResource default_builtin_resource = { + .maxLights = 32, + .maxClipPlanes = 6, + .maxTextureUnits = 32, + .maxTextureCoords = 32, + .maxVertexAttribs = 64, + .maxVertexUniformComponents = 4096, + .maxVaryingFloats = 64, + .maxVertexTextureImageUnits = 32, + .maxCombinedTextureImageUnits = 80, + .maxTextureImageUnits = 32, + .maxFragmentUniformComponents = 4096, + .maxDrawBuffers = 32, + .maxVertexUniformVectors = 128, + .maxVaryingVectors = 8, + .maxFragmentUniformVectors = 16, + .maxVertexOutputVectors = 16, + .maxFragmentInputVectors = 15, + .minProgramTexelOffset = -8, + .maxProgramTexelOffset = 7, + .maxClipDistances = 8, + .maxComputeWorkGroupCountX = 65535, + .maxComputeWorkGroupCountY = 65535, + .maxComputeWorkGroupCountZ = 65535, + .maxComputeWorkGroupSizeX = 1024, + .maxComputeWorkGroupSizeY = 1024, + .maxComputeWorkGroupSizeZ = 64, + .maxComputeUniformComponents = 1024, + .maxComputeTextureImageUnits = 16, + .maxComputeImageUniforms = 8, + .maxComputeAtomicCounters = 8, + .maxComputeAtomicCounterBuffers = 1, + .maxVaryingComponents = 60, + .maxVertexOutputComponents = 64, + .maxGeometryInputComponents = 64, + .maxGeometryOutputComponents = 128, + .maxFragmentInputComponents = 128, + .maxImageUnits = 8, + .maxCombinedImageUnitsAndFragmentOutputs = 8, + .maxCombinedShaderOutputResources = 8, + .maxImageSamples = 0, + .maxVertexImageUniforms = 0, + .maxTessControlImageUniforms = 0, + .maxTessEvaluationImageUniforms = 0, + .maxGeometryImageUniforms = 0, + .maxFragmentImageUniforms = 8, + .maxCombinedImageUniforms = 8, + .maxGeometryTextureImageUnits = 16, + .maxGeometryOutputVertices = 256, + .maxGeometryTotalOutputComponents = 1024, + .maxGeometryUniformComponents = 1024, + .maxGeometryVaryingComponents = 64, + .maxTessControlInputComponents = 128, + .maxTessControlOutputComponents = 128, + .maxTessControlTextureImageUnits = 16, + .maxTessControlUniformComponents = 1024, + .maxTessControlTotalOutputComponents = 4096, + .maxTessEvaluationInputComponents = 128, + .maxTessEvaluationOutputComponents = 128, + .maxTessEvaluationTextureImageUnits = 16, + .maxTessEvaluationUniformComponents = 1024, + .maxTessPatchComponents = 120, + .maxPatchVertices = 32, + .maxTessGenLevel = 64, + .maxViewports = 16, + .maxVertexAtomicCounters = 0, + .maxTessControlAtomicCounters = 0, + .maxTessEvaluationAtomicCounters = 0, + .maxGeometryAtomicCounters = 0, + .maxFragmentAtomicCounters = 8, + .maxCombinedAtomicCounters = 8, + .maxAtomicCounterBindings = 1, + .maxVertexAtomicCounterBuffers = 0, + .maxTessControlAtomicCounterBuffers = 0, + .maxTessEvaluationAtomicCounterBuffers = 0, + .maxGeometryAtomicCounterBuffers = 0, + .maxFragmentAtomicCounterBuffers = 1, + .maxCombinedAtomicCounterBuffers = 1, + .maxAtomicCounterBufferSize = 16384, + .maxTransformFeedbackBuffers = 4, + .maxTransformFeedbackInterleavedComponents = 64, + .maxCullDistances = 8, + .maxCombinedClipAndCullDistances = 8, + .maxSamples = 4, + .limits = { + .nonInductiveForLoops = 1, + .whileLoops = 1, + .doWhileLoops = 1, + .generalUniformIndexing = 1, + .generalAttributeMatrixVectorIndexing = 1, + .generalVaryingIndexing = 1, + .generalSamplerIndexing = 1, + .generalVariableIndexing = 1, + .generalConstantMatrixVectorIndexing = 1, + } +}; + +static const char *shader_stage_names[RenderingDevice::SHADER_STAGE_MAX] = { + "Vertex", + "Fragment", + "TesselationControl", + "TesselationEvaluation", + "Compute" +}; + +static VkShaderStageFlagBits shader_stage_masks[RenderingDevice::SHADER_STAGE_MAX] = { + VK_SHADER_STAGE_VERTEX_BIT, + VK_SHADER_STAGE_FRAGMENT_BIT, + VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, + VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, + VK_SHADER_STAGE_COMPUTE_BIT, +}; + +bool RenderingDeviceVulkan::_uniform_add_binding(Vector > &bindings, Vector > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, String *r_error) { + + VkDescriptorSetLayoutBinding layout_binding; + Shader::UniformInfo info; + + print_line("*** Stage " + itos(p_stage) + " uniform: " + reflection.name.c_str()); + + switch (reflection.getType()->getBasicType()) { + case glslang::EbtSampler: { + + print_line("DEBUG: IsSampler"); + if (reflection.getType()->getSampler().dim == glslang::EsdBuffer) { + //texture buffers + if (reflection.getType()->getSampler().isCombined()) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER; + print_line("DEBUG: texel combined"); + } else if (reflection.getType()->getSampler().isTexture()) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + info.type = UNIFORM_TYPE_TEXTURE_BUFFER; + print_line("DEBUG: texel alone"); + } else if (reflection.getType()->getSampler().isImage()) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + info.type = UNIFORM_TYPE_IMAGE_BUFFER; + print_line("DEBUG: texel buffer"); + } else { + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported buffer type."; + } + return false; + } + } else if (reflection.getType()->getSampler().isCombined()) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + print_line("DEBUG: combined"); + } else if (reflection.getType()->getSampler().isPureSampler()) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; + info.type = UNIFORM_TYPE_SAMPLER; + print_line("DEBUG: sampler"); + } else if (reflection.getType()->getSampler().isTexture()) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + info.type = UNIFORM_TYPE_TEXTURE; + print_line("DEBUG: image"); + } else if (reflection.getType()->getSampler().isImage()) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + info.type = UNIFORM_TYPE_IMAGE; + print_line("DEBUG: storage image"); + } else { + print_line("DEBUG: sampler unknown"); + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported sampler type."; + } + return false; + } + + if (reflection.getType()->isArray()) { + layout_binding.descriptorCount = reflection.getType()->getArraySizes()->getCumulativeSize(); + print_line("DEBUG: array of size: " + itos(layout_binding.descriptorCount)); + } else { + layout_binding.descriptorCount = 1; + } + + info.length = layout_binding.descriptorCount; + + } break; + /*case glslang::EbtStruct: { + print_line("DEBUG: Struct"); + + } break;*/ + case glslang::EbtBlock: { + print_line("DEBUG: Block"); + if (reflection.getType()->getQualifier().storage == glslang::EvqUniform) { + print_line("DEBUG: Uniform buffer"); + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + info.type = UNIFORM_TYPE_UNIFORM_BUFFER; + + } else if (reflection.getType()->getQualifier().storage == glslang::EvqBuffer) { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + info.type = UNIFORM_TYPE_STORAGE_BUFFER; + print_line("DEBUG: Storage buffer"); + } else { + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported block type."; + } + return false; + } + + if (reflection.getType()->isArray()) { + layout_binding.descriptorCount = reflection.getType()->getArraySizes()->getCumulativeSize(); + print_line("DEBUG: array of size: " + itos(layout_binding.descriptorCount)); + } else { + layout_binding.descriptorCount = 1; + } + + info.length = reflection.size; + + } break; + /*case glslang::EbtReference: { + + } break;*/ + /*case glslang::EbtAtomicUint: { + + } break;*/ + default: { + + if (reflection.getType()->getQualifier().hasOffset()) { + //member of uniform block? + return true; + } + + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' unsupported uniform type."; + } + return false; + } + } + + if (!reflection.getType()->getQualifier().hasBinding()) { + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' lacks a binding number."; + } + return false; + } + + uint32_t set = reflection.getType()->getQualifier().hasSet() ? reflection.getType()->getQualifier().layoutSet : 0; + + if (set >= limits.maxBoundDescriptorSets) { + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ")."; + } + return false; + } + + uint32_t binding = reflection.getType()->getQualifier().layoutBinding; + + if (set < (uint32_t)bindings.size()) { + //check if this already exists + for (int i = 0; i < bindings[set].size(); i++) { + if (bindings[set][i].binding == binding) { + //already exists, verify that it's the same type + if (bindings[set][i].descriptorType != layout_binding.descriptorType) { + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform type."; + } + return false; + } + + //also, verify that it's the same size + if (bindings[set][i].descriptorCount != layout_binding.descriptorCount || uniform_infos[set][i].length != info.length) { + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform size."; + } + return false; + } + + //just append stage mask and return + bindings.write[set].write[i].stageFlags |= shader_stage_masks[p_stage]; + uniform_infos.write[set].write[i].stages |= 1 << p_stage; + return true; + } + } + } + layout_binding.binding = binding; + layout_binding.stageFlags = shader_stage_masks[p_stage]; + layout_binding.pImmutableSamplers = NULL; //no support for this yet + + info.stages = 1 << p_stage; + info.binding = binding; + + if (set >= (uint32_t)bindings.size()) { + bindings.resize(set + 1); + uniform_infos.resize(set + 1); + } + + bindings.write[set].push_back(layout_binding); + uniform_infos.write[set].push_back(info); + + return true; +} + +RenderingDevice::ID RenderingDeviceVulkan::shader_create_from_source(const Vector &p_stages, String *r_error, bool p_allow_cache) { + + _THREAD_SAFE_METHOD_ + + // initialize in case it's not initialized. This is done once per thread + // and it's safe to call multiple times + glslang::InitializeProcess(); + EShLanguage stages[SHADER_STAGE_MAX] = { + EShLangVertex, + EShLangFragment, + EShLangTessControl, + EShLangTessEvaluation, + EShLangCompute + }; + + int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100 + glslang::EShTargetClientVersion VulkanClientVersion = glslang::EShTargetVulkan_1_0; + glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_0; + + Vector > spirv_code; + + glslang::TShader::ForbidIncluder includer; + + //descriptor layouts + Vector > bindings; + Vector > uniform_info; + Vector vertex_input_locations; + int fragment_outputs = 0; + + uint32_t stages_processed = 0; + + for (int i = 0; i < p_stages.size(); i++) { + + if (stages_processed & (1 << p_stages[i].shader_stage)) { + if (r_error) { + (*r_error) = "Stage " + String(shader_stage_names[p_stages[i].shader_stage]) + " submitted more than once."; + } + return false; + } + glslang::TShader shader(stages[p_stages[i].shader_stage]); + CharString cs = p_stages[i].shader_source.utf8(); + const char *cs_strings = cs.get_data(); + shader.setStrings(&cs_strings, 1); + shader.setEnvInput(glslang::EShSourceGlsl, stages[p_stages[i].shader_stage], glslang::EShClientVulkan, ClientInputSemanticsVersion); + shader.setEnvClient(glslang::EShClientVulkan, VulkanClientVersion); + shader.setEnvTarget(glslang::EShTargetSpv, TargetVersion); + + EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules); + const int DefaultVersion = 100; + std::string pre_processed_code; + + //preprocess + if (!shader.preprocess(&default_builtin_resource, DefaultVersion, ENoProfile, false, false, messages, &pre_processed_code, includer)) { + + if (r_error) { + (*r_error) = "Failed pre-processing on shader stage: " + String(shader_stage_names[p_stages[i].shader_stage]) + "\n"; + (*r_error) += shader.getInfoLog(); + (*r_error) += "\n"; + (*r_error) += shader.getInfoDebugLog(); + } + + return INVALID_ID; + } + //set back.. + cs_strings = pre_processed_code.c_str(); + shader.setStrings(&cs_strings, 1); + + //parse + if (!shader.parse(&default_builtin_resource, DefaultVersion, false, messages)) { + if (r_error) { + (*r_error) = "Failed parsing on shader stage: " + String(shader_stage_names[p_stages[i].shader_stage]) + "\n"; + (*r_error) += shader.getInfoLog(); + (*r_error) += "\n"; + (*r_error) += shader.getInfoDebugLog(); + } + return INVALID_ID; + } + + //link + glslang::TProgram program; + program.addShader(&shader); + + if (!program.link(messages)) { + if (r_error) { + (*r_error) = "Failed linking on shader stage: " + String(shader_stage_names[p_stages[i].shader_stage]) + "\n"; + (*r_error) += program.getInfoLog(); + (*r_error) += "\n"; + (*r_error) += program.getInfoDebugLog(); + } + return INVALID_ID; + } + + //obtain bindings for descriptor layout + program.mapIO(); + program.buildReflection(); + program.dumpReflection(); + + for (int j = 0; j < program.getNumUniformVariables(); j++) { + if (!_uniform_add_binding(bindings, uniform_info, program.getUniform(j), p_stages[i].shader_stage, r_error)) { + return INVALID_ID; + } + } + + for (int j = 0; j < program.getNumUniformBlocks(); j++) { + if (!_uniform_add_binding(bindings, uniform_info, program.getUniformBlock(j), p_stages[i].shader_stage, r_error)) { + return INVALID_ID; + } + } + + for (int j = 0; j < program.getNumBufferVariables(); j++) { + if (!_uniform_add_binding(bindings, uniform_info, program.getBufferVariable(j), p_stages[i].shader_stage, r_error)) { + return INVALID_ID; + } + } + + for (int j = 0; j < program.getNumBufferBlocks(); j++) { + if (!_uniform_add_binding(bindings, uniform_info, program.getBufferBlock(j), p_stages[i].shader_stage, r_error)) { + return INVALID_ID; + } + } + + if (p_stages[i].shader_stage == SHADER_STAGE_VERTEX) { + for (int j = 0; j < program.getNumPipeInputs(); j++) { + if (program.getPipeInput(i).getType()->getQualifier().hasLocation()) { + int location = program.getPipeInput(i).getType()->getQualifier().layoutLocation; + print_line("found vertex location: " + itos(location)); + if (vertex_input_locations.find(location) == -1) { + vertex_input_locations.push_back(location); + } + } + } + } + + if (p_stages[i].shader_stage == SHADER_STAGE_FRAGMENT) { + + fragment_outputs = program.getNumPipeOutputs(); + } + + std::vector SpirV; + spv::SpvBuildLogger logger; + glslang::SpvOptions spvOptions; + glslang::GlslangToSpv(*program.getIntermediate(stages[p_stages[i].shader_stage]), SpirV, &logger, &spvOptions); + + spirv_code.push_back(SpirV); + + stages_processed |= (1 << p_stages[i].shader_stage); + } + + //all good, let's create modules + + Shader shader; + + shader.vertex_input_locations = vertex_input_locations; + shader.fragment_outputs = fragment_outputs; + + bool success = true; + for (int i = 0; i < p_stages.size(); i++) { + VkShaderModuleCreateInfo shader_module_create_info; + shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + shader_module_create_info.pNext = NULL; + shader_module_create_info.flags = 0; + shader_module_create_info.codeSize = spirv_code[i].size() * sizeof(uint32_t); + shader_module_create_info.pCode = &spirv_code[i][0]; + + VkShaderModule module; + VkResult res = vkCreateShaderModule(device, &shader_module_create_info, NULL, &module); + if (res) { + success = false; + ERR_PRINT("Error creating shader module for stage: " + String(shader_stage_names[p_stages[i].shader_stage])); + break; + } + + const VkShaderStageFlagBits shader_stage_bits[SHADER_STAGE_MAX] = { + VK_SHADER_STAGE_VERTEX_BIT, + VK_SHADER_STAGE_FRAGMENT_BIT, + VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, + VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, + VK_SHADER_STAGE_COMPUTE_BIT, + }; + + VkPipelineShaderStageCreateInfo shader_stage; + shader_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shader_stage.pNext = NULL; + shader_stage.flags = 0; + shader_stage.stage = shader_stage_bits[p_stages[i].shader_stage]; + shader_stage.module = module; + shader_stage.pName = "main"; + shader_stage.pSpecializationInfo = NULL; + + shader.pipeline_stages.push_back(shader_stage); + } + //proceed to create descriptor sets + + if (success) { + + for (int i = 0; i < bindings.size(); i++) { + + //empty ones are fine if they were not used according to spec (binding count will be 0) + VkDescriptorSetLayoutCreateInfo layout_create_info; + layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layout_create_info.pNext = NULL; + layout_create_info.flags = 0; + layout_create_info.bindingCount = bindings[i].size(); + layout_create_info.pBindings = bindings[i].ptr(); + + VkDescriptorSetLayout layout; + VkResult res = vkCreateDescriptorSetLayout(device, &layout_create_info, NULL, &layout); + if (res) { + ERR_PRINT("Error creating descriptor set layout for set " + itos(i)); + success = false; + break; + } + + Shader::Set set; + set.descriptor_set_layout = layout; + set.uniform_info = uniform_info[i]; + //sort and hash + set.uniform_info.sort(); + + uint32_t h = set.uniform_info.size() ? hash_djb2_one_32(0) : 0; + for (int j = 0; j < set.uniform_info.size(); j++) { + const Shader::UniformInfo &ui = set.uniform_info[j]; + h = hash_djb2_one_32(ui.type, h); + h = hash_djb2_one_32(ui.binding, h); + h = hash_djb2_one_32(ui.length, h); + h = hash_djb2_one_32(ui.stages, h); + } + + shader.sets.push_back(set); + shader.set_hashes.push_back(h); + } + } + + if (success) { + //create pipeline layout + VkPipelineLayoutCreateInfo pipeline_layout_create_info; + pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_create_info.pNext = NULL; + pipeline_layout_create_info.flags = 0; + pipeline_layout_create_info.setLayoutCount = shader.sets.size(); + + Vector layouts; + layouts.resize(shader.sets.size()); + + for (int i = 0; i < layouts.size(); i++) { + layouts.write[i] = shader.sets[i].descriptor_set_layout; + } + + //unsupported for now + pipeline_layout_create_info.pSetLayouts = layouts.ptr(); + pipeline_layout_create_info.pushConstantRangeCount = 0; + pipeline_layout_create_info.pPushConstantRanges = NULL; + + VkResult err = vkCreatePipelineLayout(device, &pipeline_layout_create_info, NULL, &shader.pipeline_layout); + + if (err) { + ERR_PRINT("Error creating pipeline layout."); + success = false; + } + } + + if (!success) { + //clean up if failed + for (int i = 0; i < shader.pipeline_stages.size(); i++) { + vkDestroyShaderModule(device, shader.pipeline_stages[i].module, NULL); + } + + for (int i = 0; i < shader.sets.size(); i++) { + vkDestroyDescriptorSetLayout(device, shader.sets[i].descriptor_set_layout, NULL); + } + + return INVALID_ID; + } + + return shader_owner.make_id(shader); +} + +/******************/ +/**** UNIFORMS ****/ +/******************/ + +RenderingDevice::ID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const PoolVector &p_data) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, INVALID_ID); + + Buffer buffer; + Error err = _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + ERR_FAIL_COND_V(err != OK, INVALID_ID); + if (p_data.size()) { + uint64_t data_size = p_data.size(); + PoolVector::Read r = p_data.read(); + _buffer_update(&buffer, 0, r.ptr(), data_size); + } + return uniform_buffer_owner.make_id(buffer); +} + +RenderingDevice::ID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const PoolVector &p_data) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, INVALID_ID); + + Buffer buffer; + Error err = _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + ERR_FAIL_COND_V(err != OK, INVALID_ID); + + if (p_data.size()) { + uint64_t data_size = p_data.size(); + PoolVector::Read r = p_data.read(); + _buffer_update(&buffer, 0, r.ptr(), data_size); + } + return storage_buffer_owner.make_id(buffer); +} + +RenderingDevice::ID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const PoolVector &p_data) { + + _THREAD_SAFE_METHOD_ + + uint32_t element_size = get_format_vertex_size(p_format); + ERR_FAIL_COND_V_MSG(element_size == 0, INVALID_ID, "Format requested is not supported for texture buffers"); + uint64_t size_bytes = uint64_t(element_size) * p_size_elements; + + ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != size_bytes, INVALID_ID); + + TextureBuffer texture_buffer; + Error err = _buffer_allocate(&texture_buffer.buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + ERR_FAIL_COND_V(err != OK, INVALID_ID); + + if (p_data.size()) { + uint64_t data_size = p_data.size(); + PoolVector::Read r = p_data.read(); + _buffer_update(&texture_buffer.buffer, 0, r.ptr(), data_size); + } + + VkBufferViewCreateInfo view_create_info; + view_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; + view_create_info.pNext = NULL; + view_create_info.flags = 0; + view_create_info.buffer = texture_buffer.buffer.buffer; + view_create_info.format = vulkan_formats[p_format]; + view_create_info.offset = 0; + view_create_info.range = size_bytes; + + texture_buffer.view = VK_NULL_HANDLE; + + VkResult res = vkCreateBufferView(device, &view_create_info, NULL, &texture_buffer.view); + if (res) { + _buffer_free(&texture_buffer.buffer); + ERR_FAIL_V_MSG(INVALID_ID, "Unable to create buffer view"); + } + + //allocate the view + return texture_buffer_owner.make_id(texture_buffer); +} + +RenderingDeviceVulkan::DescriptorPool *RenderingDeviceVulkan::_descriptor_pool_allocate(const DescriptorPoolKey &p_key) { + if (!descriptor_pools.has(p_key)) { + descriptor_pools[p_key] = Set(); + } + + DescriptorPool *pool = NULL; + + for (Set::Element *E = descriptor_pools[p_key].front(); E; E = E->next()) { + if (E->get()->usage < max_descriptors_per_pool) { + pool = E->get(); + break; + } + } + + if (!pool) { + //create a new one + pool = memnew(DescriptorPool); + pool->usage = 0; + + VkDescriptorPoolCreateInfo descriptor_pool_create_info; + descriptor_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + descriptor_pool_create_info.pNext = NULL; + descriptor_pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; // can't think how somebody may NOT need this flag.. + descriptor_pool_create_info.maxSets = max_descriptors_per_pool; + Vector sizes; + //here comes more vulkan API strangeness + + if (p_key.uniform_type[UNIFORM_TYPE_SAMPLER]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_SAMPLER; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_SAMPLER] * max_descriptors_per_pool; + sizes.push_back(s); + } + if (p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE] * max_descriptors_per_pool; + sizes.push_back(s); + } + if (p_key.uniform_type[UNIFORM_TYPE_TEXTURE]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_TEXTURE] * max_descriptors_per_pool; + sizes.push_back(s); + } + if (p_key.uniform_type[UNIFORM_TYPE_IMAGE]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_IMAGE] * max_descriptors_per_pool; + sizes.push_back(s); + } + if (p_key.uniform_type[UNIFORM_TYPE_TEXTURE_BUFFER] || p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + s.descriptorCount = (p_key.uniform_type[UNIFORM_TYPE_TEXTURE_BUFFER] + p_key.uniform_type[UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER]) * max_descriptors_per_pool; + sizes.push_back(s); + } + if (p_key.uniform_type[UNIFORM_TYPE_IMAGE_BUFFER]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_IMAGE_BUFFER] * max_descriptors_per_pool; + sizes.push_back(s); + } + if (p_key.uniform_type[UNIFORM_TYPE_UNIFORM_BUFFER]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_UNIFORM_BUFFER] * max_descriptors_per_pool; + sizes.push_back(s); + } + + if (p_key.uniform_type[UNIFORM_TYPE_STORAGE_BUFFER]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_STORAGE_BUFFER] * max_descriptors_per_pool; + sizes.push_back(s); + } + + if (p_key.uniform_type[UNIFORM_TYPE_INPUT_ATTACHMENT]) { + VkDescriptorPoolSize s; + s.type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; + s.descriptorCount = p_key.uniform_type[UNIFORM_TYPE_INPUT_ATTACHMENT] * max_descriptors_per_pool; + sizes.push_back(s); + } + + descriptor_pool_create_info.poolSizeCount = sizes.size(); + descriptor_pool_create_info.pPoolSizes = sizes.ptr(); + VkResult res = vkCreateDescriptorPool(device, &descriptor_pool_create_info, NULL, &pool->pool); + ERR_FAIL_COND_V(res, NULL); + descriptor_pools[p_key].insert(pool); + } + + pool->usage++; + + return pool; +} + +void RenderingDeviceVulkan::_descriptor_pool_free(const DescriptorPoolKey &p_key, DescriptorPool *p_pool) { +#ifdef DEBUG_ENABLED + ERR_FAIL_COND(!descriptor_pools[p_key].has(p_pool)); +#endif + ERR_FAIL_COND(p_pool->usage == 0); + p_pool->usage--; + if (p_pool->usage == 0) { + vkDestroyDescriptorPool(device, p_pool->pool, NULL); + descriptor_pools[p_key].erase(p_pool); + memdelete(p_pool); + } +} + +RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, ID p_shader, uint32_t p_shader_set) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(p_uniforms.size() == 0, INVALID_ID); + + Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, INVALID_ID); + + ERR_FAIL_COND_V_MSG(p_shader_set >= (uint32_t)shader->sets.size() || shader->sets[p_shader_set].uniform_info.size() == 0, INVALID_ID, + "Desired set (" + itos(p_shader_set) + ") not used by shader."); + //see that all sets in shader are satisfied + + const Shader::Set &set = shader->sets[p_shader_set]; + + uint32_t uniform_count = p_uniforms.size(); + const Uniform *uniforms = p_uniforms.ptr(); + print_line("uniform count: " + itos(uniform_count)); + + uint32_t set_uniform_count = set.uniform_info.size(); + const Shader::UniformInfo *set_uniforms = set.uniform_info.ptr(); + + print_line("set_uniform count: " + itos(set_uniform_count)); + + Vector writes; + DescriptorPoolKey pool_key; + + //to keep them alive until update call + List > buffer_infos; + List > buffer_views; + List > image_infos; +#ifdef DEBUG_ENABLED + //used for verification to make sure a uniform set does not use a framebuffer bound texture + Vector bound_textures; +#endif + + for (uint32_t i = 0; i < set_uniform_count; i++) { + const Shader::UniformInfo &set_uniform = set_uniforms[i]; + int uniform_idx = -1; + for (int j = 0; j < (int)uniform_count; j++) { + if (uniforms[j].binding == set_uniform.binding) { + uniform_idx = j; + } + } + ERR_FAIL_COND_V_MSG(uniform_idx == -1, INVALID_ID, + "All the shader bindings for the given set must be covered by the uniforms provided."); + + const Uniform &uniform = uniforms[uniform_idx]; + + ERR_FAIL_COND_V_MSG(uniform.type != set_uniform.type, INVALID_ID, + "Mismatch uniform type for binding (" + itos(set_uniform.binding) + ")."); + + VkWriteDescriptorSet write; //common header + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.pNext = NULL; + write.dstSet = NULL; //will assign afterwards when everything is valid + write.dstBinding = set_uniform.binding; + uint32_t type_size = 1; + + switch (uniform.type) { + case UNIFORM_TYPE_SAMPLER: { + if (uniform.ids.size() != set_uniform.length) { + if (set_uniform.length > 1) { + ERR_FAIL_V_MSG(INVALID_ID, "Sampler (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler elements, so it should be provided equal number of sampler IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + } else { + ERR_FAIL_V_MSG(INVALID_ID, "Sampler (binding: " + itos(uniform.binding) + ") should provide one ID referencing a sampler (IDs provided: " + itos(uniform.ids.size()) + ")."); + } + } + + Vector image_info; + + for (int j = 0; j < uniform.ids.size(); j++) { + VkSampler *sampler = sampler_owner.getornull(uniform.ids[j]); + ERR_FAIL_COND_V_MSG(!sampler, INVALID_ID, "Sampler (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid sampler."); + + VkDescriptorImageInfo img_info; + img_info.sampler = *sampler; + img_info.imageView = VK_NULL_HANDLE; + img_info.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + image_info.push_back(img_info); + } + + write.dstArrayElement = 0; + write.descriptorCount = uniform.ids.size(); + write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; + write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); + write.pBufferInfo = NULL; + write.pTexelBufferView = NULL; + + type_size = uniform.ids.size(); + + } break; + case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: { + + if (uniform.ids.size() != set_uniform.length * 2) { + if (set_uniform.length > 1) { + ERR_FAIL_V_MSG(INVALID_ID, "SamplerTexture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler&texture elements, so it should provided twice the amount of IDs (sampler,texture pairs) to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + } else { + ERR_FAIL_V_MSG(INVALID_ID, "SamplerTexture (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture (IDs provided: " + itos(uniform.ids.size()) + ")."); + } + } + + Vector image_info; + + for (int j = 0; j < uniform.ids.size(); j += 2) { + VkSampler *sampler = sampler_owner.getornull(uniform.ids[j + 0]); + ERR_FAIL_COND_V_MSG(!sampler, INVALID_ID, "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler."); + + Texture *texture = texture_owner.getornull(uniform.ids[j + 1]); + ERR_FAIL_COND_V_MSG(!texture, INVALID_ID, "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture."); + + ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), INVALID_ID, + "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform."); + + VkDescriptorImageInfo img_info; + img_info.sampler = *sampler; + img_info.imageView = texture->view; + +#ifdef DEBUG_ENABLED + bound_textures.push_back(texture->owner != INVALID_ID ? texture->owner : uniform.ids[j + 1]); +#endif + + if (texture->owner != INVALID_ID) { + texture = texture_owner.getornull(texture->owner); + ERR_FAIL_COND_V(!texture, INVALID_ID); //bug, should never happen + } + + img_info.imageLayout = texture->reading_layout; + + image_info.push_back(img_info); + } + + write.dstArrayElement = 0; + write.descriptorCount = uniform.ids.size() / 2; + write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); + write.pBufferInfo = NULL; + write.pTexelBufferView = NULL; + + type_size = uniform.ids.size() / 2; + + } break; + case UNIFORM_TYPE_TEXTURE: { + + if (uniform.ids.size() != set_uniform.length) { + if (set_uniform.length > 1) { + ERR_FAIL_V_MSG(INVALID_ID, "Texture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + } else { + ERR_FAIL_V_MSG(INVALID_ID, "Texture (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.ids.size()) + ")."); + } + } + + Vector image_info; + + for (int j = 0; j < uniform.ids.size(); j++) { + Texture *texture = texture_owner.getornull(uniform.ids[j]); + ERR_FAIL_COND_V_MSG(!texture, INVALID_ID, "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture."); + + ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), INVALID_ID, + "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform."); + + VkDescriptorImageInfo img_info; + img_info.sampler = NULL; + img_info.imageView = texture->view; + +#ifdef DEBUG_ENABLED + bound_textures.push_back(texture->owner != INVALID_ID ? texture->owner : uniform.ids[j]); +#endif + + if (texture->owner != INVALID_ID) { + texture = texture_owner.getornull(texture->owner); + ERR_FAIL_COND_V(!texture, INVALID_ID); //bug, should never happen + } + + img_info.imageLayout = texture->reading_layout; + + image_info.push_back(img_info); + } + + write.dstArrayElement = 0; + write.descriptorCount = uniform.ids.size(); + write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); + write.pBufferInfo = NULL; + write.pTexelBufferView = NULL; + + type_size = uniform.ids.size(); + } break; + case UNIFORM_TYPE_IMAGE: { + //todo + } break; + case UNIFORM_TYPE_TEXTURE_BUFFER: { + if (uniform.ids.size() != set_uniform.length) { + if (set_uniform.length > 1) { + ERR_FAIL_V_MSG(INVALID_ID, "Buffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") texture buffer elements, so it should be provided equal number of texture buffer IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + } else { + ERR_FAIL_V_MSG(INVALID_ID, "Buffer (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture buffer (IDs provided: " + itos(uniform.ids.size()) + ")."); + } + } + + Vector buffer_info; + Vector buffer_view; + + for (int j = 0; j < uniform.ids.size(); j++) { + TextureBuffer *buffer = texture_buffer_owner.getornull(uniform.ids[j]); + ERR_FAIL_COND_V_MSG(!buffer, INVALID_ID, "Texture Buffer (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture buffer."); + + buffer_info.push_back(buffer->buffer.buffer_info); + buffer_view.push_back(buffer->view); + } + + write.dstArrayElement = 0; + write.descriptorCount = uniform.ids.size(); + write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + write.pImageInfo = NULL; + write.pBufferInfo = buffer_infos.push_back(buffer_info)->get().ptr(); + write.pTexelBufferView = buffer_views.push_back(buffer_view)->get().ptr(); + + type_size = uniform.ids.size(); + + } break; + case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER: { + + if (uniform.ids.size() != set_uniform.length * 2) { + if (set_uniform.length > 1) { + ERR_FAIL_V_MSG(INVALID_ID, "SamplerBuffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler buffer elements, so it should provided twice the amount of IDs (sampler,buffer pairs) to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + } else { + ERR_FAIL_V_MSG(INVALID_ID, "SamplerBuffer (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture buffer (IDs provided: " + itos(uniform.ids.size()) + ")."); + } + } + + Vector image_info; + Vector buffer_info; + Vector buffer_view; + + for (int j = 0; j < uniform.ids.size(); j += 2) { + VkSampler *sampler = sampler_owner.getornull(uniform.ids[j + 0]); + ERR_FAIL_COND_V_MSG(!sampler, INVALID_ID, "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler."); + + TextureBuffer *buffer = texture_buffer_owner.getornull(uniform.ids[j + 1]); + + VkDescriptorImageInfo img_info; + img_info.sampler = *sampler; + img_info.imageView = VK_NULL_HANDLE; + img_info.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + image_info.push_back(img_info); + + ERR_FAIL_COND_V_MSG(!buffer, INVALID_ID, "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid texture buffer."); + + buffer_info.push_back(buffer->buffer.buffer_info); + buffer_view.push_back(buffer->view); + } + + write.dstArrayElement = 0; + write.descriptorCount = uniform.ids.size() / 2; + write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); + write.pBufferInfo = buffer_infos.push_back(buffer_info)->get().ptr(); + write.pTexelBufferView = buffer_views.push_back(buffer_view)->get().ptr(); + + type_size = uniform.ids.size() / 2; + } break; + case UNIFORM_TYPE_IMAGE_BUFFER: { + //todo + + } break; + case UNIFORM_TYPE_UNIFORM_BUFFER: { + ERR_FAIL_COND_V_MSG(uniform.ids.size() != 1, INVALID_ID, + "Uniform buffer (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.ids.size()) + " provided)."); + + Buffer *buffer = uniform_buffer_owner.getornull(uniform.ids[0]); + ERR_FAIL_COND_V_MSG(!buffer, INVALID_ID, "Uniform buffer (binding: " + itos(uniform.binding) + ") is invalid."); + + ERR_FAIL_COND_V_MSG(buffer->size != (uint32_t)set_uniform.length, INVALID_ID, + "Uniform buffer (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ")."); + + write.dstArrayElement = 0; + write.descriptorCount = 1; + write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write.pImageInfo = NULL; + write.pBufferInfo = &buffer->buffer_info; + write.pTexelBufferView = NULL; + + } break; + case UNIFORM_TYPE_STORAGE_BUFFER: { + ERR_FAIL_COND_V_MSG(uniform.ids.size() != 1, INVALID_ID, + "Storage buffer (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.ids.size()) + " provided)."); + + Buffer *buffer = storage_buffer_owner.getornull(uniform.ids[0]); + ERR_FAIL_COND_V_MSG(!buffer, INVALID_ID, "Storage buffer (binding: " + itos(uniform.binding) + ") is invalid."); + + ERR_FAIL_COND_V_MSG(buffer->size != (uint32_t)set_uniform.length, INVALID_ID, + "Storage buffer (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ")."); + + write.dstArrayElement = 0; + write.descriptorCount = 1; + write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + write.pImageInfo = NULL; + write.pBufferInfo = &buffer->buffer_info; + write.pTexelBufferView = NULL; + } break; + case UNIFORM_TYPE_INPUT_ATTACHMENT: { + + } break; + default: { + } + } + + writes.push_back(write); + + ERR_FAIL_COND_V_MSG(pool_key.uniform_type[set_uniform.type] == MAX_DESCRIPTOR_POOL_ELEMENT, INVALID_ID, + "Uniform set reached the limit of bindings for the same type (" + itos(MAX_DESCRIPTOR_POOL_ELEMENT) + ")."); + pool_key.uniform_type[set_uniform.type] += type_size; + } + + //need a descriptor pool + DescriptorPool *pool = _descriptor_pool_allocate(pool_key); + + ERR_FAIL_COND_V(!pool, INVALID_ID); + + VkDescriptorSetAllocateInfo descriptor_set_allocate_info; + + descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptor_set_allocate_info.pNext = NULL; + descriptor_set_allocate_info.descriptorPool = pool->pool; + descriptor_set_allocate_info.descriptorSetCount = 1; + descriptor_set_allocate_info.pSetLayouts = &shader->sets[p_shader_set].descriptor_set_layout; + + VkDescriptorSet descriptor_set; + + VkResult res = vkAllocateDescriptorSets(device, &descriptor_set_allocate_info, &descriptor_set); + if (res) { + _descriptor_pool_free(pool_key, pool); // meh + ERR_FAIL_V_MSG(INVALID_ID, "Cannot allocate descriptor sets."); + } + + UniformSet uniform_set; + uniform_set.pool = pool; + uniform_set.pool_key = pool_key; + uniform_set.descriptor_set = descriptor_set; + uniform_set.pipeline_layout = shader->pipeline_layout; + uniform_set.hash = shader->set_hashes[p_shader_set]; + + ID id = uniform_set_owner.make_id(uniform_set); + //add dependencies + _add_dependency(id, p_shader); + for (uint32_t i = 0; i < uniform_count; i++) { + const Uniform &uniform = uniforms[i]; + int id_count = uniform.ids.size(); + const ID *ids = uniform.ids.ptr(); + for (int j = 0; j < id_count; j++) { + _add_dependency(id, ids[j]); + } + } + + //write the contents + if (writes.size()) { + for (int i = 0; i < writes.size(); i++) { + writes.write[i].dstSet = descriptor_set; + } + vkUpdateDescriptorSets(device, writes.size(), writes.ptr(), 0, NULL); + } + + return id; +} + +Error RenderingDeviceVulkan::buffer_update(ID p_buffer, uint32_t p_offset, uint32_t p_size, void *p_data, bool p_sync_with_draw) { + _THREAD_SAFE_METHOD_ + + Buffer *buffer = NULL; + if (vertex_buffer_owner.owns(p_buffer)) { + buffer = vertex_buffer_owner.getornull(p_buffer); + } else if (index_buffer_owner.owns(p_buffer)) { + buffer = index_buffer_owner.getornull(p_buffer); + } else if (uniform_buffer_owner.owns(p_buffer)) { + buffer = uniform_buffer_owner.getornull(p_buffer); + } else if (texture_buffer_owner.owns(p_buffer)) { + buffer = &texture_buffer_owner.getornull(p_buffer)->buffer; + } else if (storage_buffer_owner.owns(p_buffer)) { + buffer = storage_buffer_owner.getornull(p_buffer); + } else { + ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type."); + } + + ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER, + "Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end."); + + return _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, p_sync_with_draw); +} + +/*************************/ +/**** RENDER PIPELINE ****/ +/*************************/ + +RenderingDevice::ID RenderingDeviceVulkan::render_pipeline_create(ID p_shader, ID p_framebuffer_format, ID p_vertex_description, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags) { + + _THREAD_SAFE_METHOD_ + + //needs a shader + Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, INVALID_ID); + + if (p_framebuffer_format == INVALID_ID) { + //if nothing provided, use an empty one (no attachments) + p_framebuffer_format = framebuffer_format_create(Vector()); + } + ERR_FAIL_COND_V(!framebuffer_formats.has(p_framebuffer_format), INVALID_ID); + const FramebufferFormat &fb_format = framebuffer_formats[p_framebuffer_format]; + + { //validate shader vs framebuffer + + ERR_FAIL_COND_V_MSG(shader->fragment_outputs != fb_format.color_attachments, INVALID_ID, + "Mismatch fragment output bindings (" + itos(shader->fragment_outputs) + ") and framebuffer color buffers (" + itos(fb_format.color_attachments) + ") when binding both in render pipeline."); + } + //vertex + VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_state_create_info; + + if (p_vertex_description != INVALID_ID) { + //uses vertices, else it does not + ERR_FAIL_COND_V(!vertex_descriptions.has(p_vertex_description), INVALID_ID); + VertexDescriptionCache &vd = vertex_descriptions[p_vertex_description]; + + pipeline_vertex_input_state_create_info = vd.create_info; + + //validate with inputs + for (int i = 0; i < shader->vertex_input_locations.size(); i++) { + uint32_t location = shader->vertex_input_locations[i]; + const VertexDescriptionKey &k = vd.E->key(); + bool found = false; + for (int j = 0; j < k.vertex_descriptions.size(); j++) { + if (k.vertex_descriptions[j].location == location) { + found = true; + } + } + + ERR_FAIL_COND_V_MSG(!found, INVALID_ID, + "Shader vertex input location (" + itos(location) + ") not provided in vertex input description for pipeline creation."); + } + + } else { + //does not use vertices + pipeline_vertex_input_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + pipeline_vertex_input_state_create_info.pNext = NULL; + pipeline_vertex_input_state_create_info.flags = 0; + pipeline_vertex_input_state_create_info.vertexBindingDescriptionCount = 0; + pipeline_vertex_input_state_create_info.pVertexBindingDescriptions = NULL; + pipeline_vertex_input_state_create_info.vertexAttributeDescriptionCount = 0; + pipeline_vertex_input_state_create_info.pVertexAttributeDescriptions = NULL; + + ERR_FAIL_COND_V_MSG(shader->vertex_input_locations.size(), INVALID_ID, + "Shader contains vertex inputs (" + itos(shader->vertex_input_locations.size()) + ") but no vertex input description was provided for pipeline creation."); + } + //input assembly + + ERR_FAIL_INDEX_V(p_render_primitive, RENDER_PRIMITIVE_MAX, INVALID_ID); + + VkPipelineInputAssemblyStateCreateInfo input_assembly_create_info; + input_assembly_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + input_assembly_create_info.pNext = NULL; + input_assembly_create_info.flags = 0; + + static const VkPrimitiveTopology topology_list[RENDER_PRIMITIVE_MAX] = { + VK_PRIMITIVE_TOPOLOGY_POINT_LIST, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST, + VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, + VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + VK_PRIMITIVE_TOPOLOGY_PATCH_LIST + }; + + input_assembly_create_info.topology = topology_list[p_render_primitive]; + input_assembly_create_info.primitiveRestartEnable = (p_render_primitive == RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX); + + //tesselation + VkPipelineTessellationStateCreateInfo tesselation_create_info; + tesselation_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + tesselation_create_info.pNext = NULL; + tesselation_create_info.flags = 0; + ERR_FAIL_COND_V(p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > limits.maxTessellationPatchSize, INVALID_ID); + tesselation_create_info.patchControlPoints = p_rasterization_state.patch_control_points; + + VkPipelineViewportStateCreateInfo viewport_state_create_info; + viewport_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_state_create_info.pNext = NULL; + viewport_state_create_info.flags = 0; + viewport_state_create_info.viewportCount = 1; //if VR extensions are supported at some point, this will have to be customizable in the framebuffer format + viewport_state_create_info.pViewports = NULL; + viewport_state_create_info.scissorCount = 1; + viewport_state_create_info.pScissors = NULL; + + //rasterization + VkPipelineRasterizationStateCreateInfo rasterization_state_create_info; + rasterization_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterization_state_create_info.pNext = NULL; + rasterization_state_create_info.flags = 0; + rasterization_state_create_info.depthClampEnable = p_rasterization_state.enable_depth_clamp; + rasterization_state_create_info.rasterizerDiscardEnable = p_rasterization_state.discard_primitives; + rasterization_state_create_info.polygonMode = (p_rasterization_state.wireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL); + static VkCullModeFlags cull_mode[3] = { + VK_CULL_MODE_NONE, + VK_CULL_MODE_FRONT_BIT, + VK_CULL_MODE_BACK_BIT + }; + + ERR_FAIL_INDEX_V(p_rasterization_state.cull_mode, 3, INVALID_ID); + rasterization_state_create_info.cullMode = cull_mode[p_rasterization_state.cull_mode]; + rasterization_state_create_info.frontFace = (p_rasterization_state.front_face == POLYGON_FRONT_FACE_CLOCKWISE ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE); + rasterization_state_create_info.depthBiasEnable = p_rasterization_state.depth_bias_enable; + rasterization_state_create_info.depthBiasConstantFactor = p_rasterization_state.depth_bias_constant_factor; + rasterization_state_create_info.depthBiasClamp = p_rasterization_state.depth_bias_clamp; + rasterization_state_create_info.depthBiasSlopeFactor = p_rasterization_state.depth_bias_slope_factor; + rasterization_state_create_info.lineWidth = p_rasterization_state.line_width; + + //multisample + VkPipelineMultisampleStateCreateInfo multisample_state_create_info; + multisample_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisample_state_create_info.pNext = NULL; + multisample_state_create_info.flags = 0; + + multisample_state_create_info.rasterizationSamples = rasterization_sample_count[p_multisample_state.sample_count]; + multisample_state_create_info.sampleShadingEnable = p_multisample_state.enable_sample_shading; + multisample_state_create_info.minSampleShading = p_multisample_state.min_sample_shading; + Vector sample_mask; + if (p_multisample_state.sample_mask.size()) { + //use sample mask + int rasterization_sample_mask_expected_size[TEXTURE_SAMPLES_MAX] = { + 1, 2, 4, 8, 16, 32, 64 + }; + ERR_FAIL_COND_V(rasterization_sample_mask_expected_size[p_multisample_state.sample_count] != p_multisample_state.sample_mask.size(), INVALID_ID); + sample_mask.resize(p_multisample_state.sample_mask.size()); + for (int i = 0; i < p_multisample_state.sample_mask.size(); i++) { + VkSampleMask mask = p_multisample_state.sample_mask[i]; + sample_mask.push_back(mask); + } + multisample_state_create_info.pSampleMask = sample_mask.ptr(); + } else { + multisample_state_create_info.pSampleMask = NULL; + } + + multisample_state_create_info.alphaToCoverageEnable = p_multisample_state.enable_alpha_to_coverage; + multisample_state_create_info.alphaToOneEnable = p_multisample_state.enable_alpha_to_one; + + //depth stencil + + VkPipelineDepthStencilStateCreateInfo depth_stencil_state_create_info; + depth_stencil_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depth_stencil_state_create_info.pNext = NULL; + depth_stencil_state_create_info.flags = 0; + depth_stencil_state_create_info.depthTestEnable = p_depth_stencil_state.enable_depth_test; + depth_stencil_state_create_info.depthWriteEnable = p_depth_stencil_state.enable_depth_write; + ERR_FAIL_INDEX_V(p_depth_stencil_state.depth_compare_operator, COMPARE_OP_MAX, INVALID_ID); + depth_stencil_state_create_info.depthCompareOp = compare_operators[p_depth_stencil_state.depth_compare_operator]; + depth_stencil_state_create_info.depthBoundsTestEnable = p_depth_stencil_state.enable_depth_range; + depth_stencil_state_create_info.stencilTestEnable = p_depth_stencil_state.enable_stencil; + + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.fail, STENCIL_OP_MAX, INVALID_ID); + depth_stencil_state_create_info.front.failOp = stencil_operations[p_depth_stencil_state.stencil_operation_front.fail]; + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.pass, STENCIL_OP_MAX, INVALID_ID); + depth_stencil_state_create_info.front.passOp = stencil_operations[p_depth_stencil_state.stencil_operation_front.pass]; + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.depth_fail, STENCIL_OP_MAX, INVALID_ID); + depth_stencil_state_create_info.front.depthFailOp = stencil_operations[p_depth_stencil_state.stencil_operation_front.depth_fail]; + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.compare, COMPARE_OP_MAX, INVALID_ID); + depth_stencil_state_create_info.front.compareOp = compare_operators[p_depth_stencil_state.stencil_operation_front.compare]; + depth_stencil_state_create_info.front.compareMask = p_depth_stencil_state.stencil_operation_front.compare_mask; + depth_stencil_state_create_info.front.writeMask = p_depth_stencil_state.stencil_operation_front.write_mask; + depth_stencil_state_create_info.front.reference = p_depth_stencil_state.stencil_operation_front.reference; + + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.fail, STENCIL_OP_MAX, INVALID_ID); + depth_stencil_state_create_info.back.failOp = stencil_operations[p_depth_stencil_state.stencil_operation_back.fail]; + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.pass, STENCIL_OP_MAX, INVALID_ID); + depth_stencil_state_create_info.back.passOp = stencil_operations[p_depth_stencil_state.stencil_operation_back.pass]; + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.depth_fail, STENCIL_OP_MAX, INVALID_ID); + depth_stencil_state_create_info.back.depthFailOp = stencil_operations[p_depth_stencil_state.stencil_operation_back.depth_fail]; + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.compare, COMPARE_OP_MAX, INVALID_ID); + depth_stencil_state_create_info.back.compareOp = compare_operators[p_depth_stencil_state.stencil_operation_back.compare]; + depth_stencil_state_create_info.back.compareMask = p_depth_stencil_state.stencil_operation_back.compare_mask; + depth_stencil_state_create_info.back.writeMask = p_depth_stencil_state.stencil_operation_back.write_mask; + depth_stencil_state_create_info.back.reference = p_depth_stencil_state.stencil_operation_back.reference; + + depth_stencil_state_create_info.minDepthBounds = p_depth_stencil_state.depth_range_min; + depth_stencil_state_create_info.maxDepthBounds = p_depth_stencil_state.depth_range_max; + + //blend state + VkPipelineColorBlendStateCreateInfo color_blend_state_create_info; + color_blend_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + color_blend_state_create_info.pNext = NULL; + color_blend_state_create_info.flags = 0; + color_blend_state_create_info.logicOpEnable = p_blend_state.enable_logic_op; + ERR_FAIL_INDEX_V(p_blend_state.logic_op, LOGIC_OP_MAX, INVALID_ID); + color_blend_state_create_info.logicOp = logic_operations[p_blend_state.logic_op]; + + ERR_FAIL_COND_V(fb_format.color_attachments != p_blend_state.attachments.size(), INVALID_ID); + + Vector attachment_states; + + for (int i = 0; i < p_blend_state.attachments.size(); i++) { + VkPipelineColorBlendAttachmentState state; + state.blendEnable = p_blend_state.attachments[i].enable_blend; + + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_color_blend_factor, BLEND_FACTOR_MAX, INVALID_ID); + state.srcColorBlendFactor = blend_factors[p_blend_state.attachments[i].src_color_blend_factor]; + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_color_blend_factor, BLEND_FACTOR_MAX, INVALID_ID); + state.dstColorBlendFactor = blend_factors[p_blend_state.attachments[i].dst_color_blend_factor]; + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].color_blend_op, BLEND_OP_MAX, INVALID_ID); + state.colorBlendOp = blend_operations[p_blend_state.attachments[i].color_blend_op]; + + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_alpha_blend_factor, BLEND_FACTOR_MAX, INVALID_ID); + state.srcAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].src_alpha_blend_factor]; + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_alpha_blend_factor, BLEND_FACTOR_MAX, INVALID_ID); + state.dstAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].dst_alpha_blend_factor]; + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].alpha_blend_op, BLEND_OP_MAX, INVALID_ID); + state.alphaBlendOp = blend_operations[p_blend_state.attachments[i].alpha_blend_op]; + + state.colorWriteMask = 0; + if (p_blend_state.attachments[i].write_r) { + state.colorWriteMask |= VK_COLOR_COMPONENT_R_BIT; + } + if (p_blend_state.attachments[i].write_g) { + state.colorWriteMask |= VK_COLOR_COMPONENT_G_BIT; + } + if (p_blend_state.attachments[i].write_b) { + state.colorWriteMask |= VK_COLOR_COMPONENT_B_BIT; + } + if (p_blend_state.attachments[i].write_a) { + state.colorWriteMask |= VK_COLOR_COMPONENT_A_BIT; + } + + attachment_states.push_back(state); + }; + + color_blend_state_create_info.attachmentCount = attachment_states.size(); + color_blend_state_create_info.pAttachments = attachment_states.ptr(); + + color_blend_state_create_info.blendConstants[0] = p_blend_state.blend_constant.r; + color_blend_state_create_info.blendConstants[1] = p_blend_state.blend_constant.g; + color_blend_state_create_info.blendConstants[2] = p_blend_state.blend_constant.b; + color_blend_state_create_info.blendConstants[3] = p_blend_state.blend_constant.a; + + //dynamic state + + VkPipelineDynamicStateCreateInfo dynamic_state_create_info; + dynamic_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state_create_info.pNext = NULL; + dynamic_state_create_info.flags = 0; + Vector dynamic_states; //vulkan is weird.. + + dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT); //viewport and scissor are always dynamic + dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR); + + if (p_dynamic_state_flags & DYNAMIC_STATE_LINE_WIDTH) { + dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_WIDTH); + } + + if (p_dynamic_state_flags & DYNAMIC_STATE_DEPTH_BIAS) { + dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BIAS); + } + + if (p_dynamic_state_flags & DYNAMIC_STATE_BLEND_CONSTANTS) { + dynamic_states.push_back(VK_DYNAMIC_STATE_BLEND_CONSTANTS); + } + + if (p_dynamic_state_flags & DYNAMIC_STATE_DEPTH_BOUNDS) { + dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS); + } + + if (p_dynamic_state_flags & DYNAMIC_STATE_STENCIL_COMPARE_MASK) { + dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK); + } + + if (p_dynamic_state_flags & DYNAMIC_STATE_STENCIL_WRITE_MASK) { + dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK); + } + + if (p_dynamic_state_flags & DYNAMIC_STATE_STENCIL_REFERENCE) { + dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE); + } + + dynamic_state_create_info.dynamicStateCount = dynamic_states.size(); + dynamic_state_create_info.pDynamicStates = dynamic_states.ptr(); + + //finally, pipeline create info + VkGraphicsPipelineCreateInfo graphics_pipeline_create_info; + + graphics_pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + graphics_pipeline_create_info.pNext = NULL; + + graphics_pipeline_create_info.stageCount = shader->pipeline_stages.size(); + graphics_pipeline_create_info.pStages = shader->pipeline_stages.ptr(); + graphics_pipeline_create_info.pVertexInputState = &pipeline_vertex_input_state_create_info; + graphics_pipeline_create_info.pInputAssemblyState = &input_assembly_create_info; + graphics_pipeline_create_info.pTessellationState = &tesselation_create_info; + graphics_pipeline_create_info.pViewportState = &viewport_state_create_info; + graphics_pipeline_create_info.pRasterizationState = &rasterization_state_create_info; + graphics_pipeline_create_info.pMultisampleState = &multisample_state_create_info; + graphics_pipeline_create_info.pDepthStencilState = &depth_stencil_state_create_info; + graphics_pipeline_create_info.pColorBlendState = &color_blend_state_create_info; + graphics_pipeline_create_info.pDynamicState = &dynamic_state_create_info; + graphics_pipeline_create_info.layout = shader->pipeline_layout; + graphics_pipeline_create_info.renderPass = fb_format.render_pass; + + graphics_pipeline_create_info.subpass = 0; + graphics_pipeline_create_info.basePipelineHandle = NULL; + graphics_pipeline_create_info.basePipelineIndex = 0; + + RenderPipeline pipeline; + VkResult err = vkCreateGraphicsPipelines(device, NULL, 1, &graphics_pipeline_create_info, NULL, &pipeline.pipeline); + ERR_FAIL_COND_V(err, INVALID_ID); + + pipeline.dynamic_state = p_dynamic_state_flags; + pipeline.framebuffer_format = p_framebuffer_format; + pipeline.vertex_format = p_vertex_description; + pipeline.uses_restart_indices = input_assembly_create_info.primitiveRestartEnable; + pipeline.set_hashes = shader->set_hashes; + + static const uint32_t primitive_divisor[RENDER_PRIMITIVE_MAX] = { + 1, 2, 1, 1, 1, 3, 1, 1, 1, 1, 1 + }; + pipeline.primitive_divisor = primitive_divisor[p_render_primitive]; + static const uint32_t primitive_minimum[RENDER_PRIMITIVE_MAX] = { + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 1, + }; + pipeline.primitive_minimum = primitive_minimum[p_render_primitive]; + + //create ID to associate with this pipeline + ID id = pipeline_owner.make_id(pipeline); + //now add aall the dependencies + _add_dependency(id, p_shader); + return id; +} + +/****************/ +/**** SCREEN ****/ +/****************/ + +int RenderingDeviceVulkan::screen_get_width(int p_screen) const { + _THREAD_SAFE_METHOD_ + + return context->get_screen_width(p_screen); +} +int RenderingDeviceVulkan::screen_get_height(int p_screen) const { + _THREAD_SAFE_METHOD_ + + return context->get_screen_height(p_screen); +} +RenderingDevice::ID RenderingDeviceVulkan::screen_get_framebuffer_format() const { + + _THREAD_SAFE_METHOD_ + + //very hacky, but not used often per frame so I guess ok + VkFormat vkformat = context->get_screen_format(); + DataFormat format = DATA_FORMAT_MAX; + for (int i = 0; i < DATA_FORMAT_MAX; i++) { + if (vkformat == vulkan_formats[i]) { + format = DataFormat(i); + break; + } + } + + ERR_FAIL_COND_V(format == DATA_FORMAT_MAX, INVALID_ID); + + AttachmentFormat attachment; + attachment.format = format; + attachment.samples = TEXTURE_SAMPLES_1; + attachment.usage_flags = TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + Vector screen_attachment; + screen_attachment.push_back(attachment); + return const_cast(this)->framebuffer_format_create(screen_attachment); +} + +/*******************/ +/**** DRAW LIST ****/ +/*******************/ + +RenderingDevice::ID RenderingDeviceVulkan::draw_list_begin_for_screen(int p_screen, const Color &p_clear_color) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V_MSG(draw_list != NULL, INVALID_ID, "Only one draw list can be active at the same time."); + VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; + draw_list = memnew(DrawList); + draw_list->command_buffer = command_buffer; + draw_list->validation.framebuffer_format = screen_get_framebuffer_format(); + draw_list_count = 0; + draw_list_split = false; + + VkRenderPassBeginInfo render_pass_begin; + render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + render_pass_begin.pNext = NULL; + render_pass_begin.renderPass = context->get_render_pass(); + render_pass_begin.framebuffer = context->get_frame_framebuffer(frame); + + render_pass_begin.renderArea.extent.width = context->get_screen_width(p_screen); + render_pass_begin.renderArea.extent.height = context->get_screen_height(p_screen); + render_pass_begin.renderArea.offset.x = 0; + render_pass_begin.renderArea.offset.y = 0; + + render_pass_begin.clearValueCount = 1; + + VkClearValue clear_value; + clear_value.color.float32[0] = p_clear_color.r; + clear_value.color.float32[1] = p_clear_color.g; + clear_value.color.float32[2] = p_clear_color.b; + clear_value.color.float32[3] = p_clear_color.a; + + render_pass_begin.pClearValues = &clear_value; + + vkCmdBeginRenderPass(command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); + + uint32_t size_x = screen_get_width(p_screen); + uint32_t size_y = screen_get_height(p_screen); + + VkViewport viewport; + viewport.x = 0; + viewport.y = 0; + viewport.width = size_x; + viewport.height = size_y; + viewport.minDepth = 0; + viewport.maxDepth = 1.0; + + vkCmdSetViewport(command_buffer, 0, 1, &viewport); + + VkRect2D scissor; + scissor.offset.x = 0; + scissor.offset.y = 0; + scissor.extent.width = size_x; + scissor.extent.height = size_x; + + vkCmdSetScissor(command_buffer, 0, 1, &scissor); + + return ID_TYPE_DRAW_LIST; +} + +Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_action, FinalAction p_final_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass) { + + Framebuffer::VersionKey vk; + vk.initial_action = p_initial_action; + vk.final_action = p_final_action; + + if (!p_framebuffer->framebuffers.has(vk)) { + //need to create this version + Framebuffer::Version version; + + version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, p_initial_action, p_final_action); + + VkFramebufferCreateInfo framebuffer_create_info; + framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebuffer_create_info.pNext = NULL; + framebuffer_create_info.flags = 0; + framebuffer_create_info.renderPass = version.render_pass; + Vector attachments; + for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) { + Texture *texture = texture_owner.getornull(p_framebuffer->texture_ids[i]); + ERR_FAIL_COND_V(!texture, ERR_BUG); + attachments.push_back(texture->view); + } + framebuffer_create_info.attachmentCount = attachments.size(); + framebuffer_create_info.pAttachments = attachments.ptr(); + framebuffer_create_info.width = p_framebuffer->size.width; + framebuffer_create_info.height = p_framebuffer->size.height; + framebuffer_create_info.layers = 1; + + VkResult err = vkCreateFramebuffer(device, &framebuffer_create_info, NULL, &version.framebuffer); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + p_framebuffer->framebuffers.insert(vk, version); + } + const Framebuffer::Version &version = p_framebuffer->framebuffers[vk]; + *r_framebuffer = version.framebuffer; + *r_render_pass = version.render_pass; + + return OK; +} + +Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents) { + + VkRenderPassBeginInfo render_pass_begin; + render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + render_pass_begin.pNext = NULL; + render_pass_begin.renderPass = render_pass; + render_pass_begin.framebuffer = vkframebuffer; + + render_pass_begin.renderArea.extent.width = viewport_size.width; + render_pass_begin.renderArea.extent.height = viewport_size.height; + render_pass_begin.renderArea.offset.x = viewport_offset.x; + render_pass_begin.renderArea.offset.y = viewport_offset.y; + + Vector clear_values; + if (p_initial_action == INITIAL_ACTION_CLEAR) { + int color_index = 0; + for (int i = 0; i < framebuffer->texture_ids.size(); i++) { + Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]); + VkClearValue clear_value; + if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); //a bug + Color clear_color = p_clear_colors[color_index]; + clear_value.color.float32[0] = clear_color.r; + clear_value.color.float32[1] = clear_color.g; + clear_value.color.float32[2] = clear_color.b; + clear_value.color.float32[3] = clear_color.a; + color_index++; + } else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + clear_value.depthStencil.depth = 1.0; + clear_value.depthStencil.stencil = 0; + } else { + clear_value.color.float32[0] = 0; + clear_value.color.float32[1] = 0; + clear_value.color.float32[2] = 0; + clear_value.color.float32[3] = 0; + } + clear_values.push_back(clear_value); + } + } + + render_pass_begin.clearValueCount = clear_values.size(); + render_pass_begin.pClearValues = clear_values.ptr(); + + vkCmdBeginRenderPass(command_buffer, &render_pass_begin, subpass_contents); + + //mark textures as bound + draw_list_bound_textures.clear(); + draw_list_unbind_textures = p_final_action != FINAL_ACTION_CONTINUE; + for (int i = 0; i < framebuffer->texture_ids.size(); i++) { + Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]); + texture->bound = true; + draw_list_bound_textures.push_back(framebuffer->texture_ids[i]); + } + + return OK; +} + +RenderingDevice::ID RenderingDeviceVulkan::draw_list_begin(ID p_framebuffer, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors, const Rect2 &p_region) { + + _THREAD_SAFE_METHOD_ + + Framebuffer *framebuffer = framebuffer_owner.getornull(p_framebuffer); + ERR_FAIL_COND_V(!framebuffer, INVALID_ID); + + Point2i viewport_offset; + Point2i viewport_size = framebuffer->size; + + if (p_region != Rect2()) { //check custom region + Rect2i viewport(viewport_offset, viewport_size); + Rect2i regioni = p_region; + if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) && + ((regioni.position.x + regioni.size.x) <= (viewport.position.x + viewport.size.x)) && + ((regioni.position.y + regioni.size.y) <= (viewport.position.y + viewport.size.y))) { + ERR_FAIL_V_MSG(INVALID_ID, "When supplying a custom region, it must be contained within the framebuffer rectangle"); + } + + viewport_offset = regioni.position; + viewport_size = regioni.size; + } + + if (p_initial_action == INITIAL_ACTION_CLEAR) { //check clear values + + int color_attachments = framebuffer_formats[framebuffer->format_id].color_attachments; + ERR_FAIL_COND_V_MSG(p_clear_colors.size() != color_attachments, INVALID_ID, + "Clear color values supplied (" + itos(p_clear_colors.size()) + ") differ from the amount required for framebuffer (" + itos(color_attachments) + ")."); + } + + VkFramebuffer vkframebuffer; + VkRenderPass render_pass; + + Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_action, p_final_action, &vkframebuffer, &render_pass); + ERR_FAIL_COND_V(err != OK, INVALID_ID); + + VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; + err = _draw_list_render_pass_begin(framebuffer, p_initial_action, p_final_action, p_clear_colors, viewport_offset, viewport_size, vkframebuffer, render_pass, command_buffer, VK_SUBPASS_CONTENTS_INLINE); + + if (err != OK) { + return INVALID_ID; + } + + draw_list = memnew(DrawList); + draw_list->command_buffer = command_buffer; + draw_list->validation.framebuffer_format = framebuffer->format_id; + draw_list_count = 0; + draw_list_split = false; + + VkViewport viewport; + viewport.x = viewport_offset.x; + viewport.y = viewport_offset.y; + viewport.width = viewport_size.width; + viewport.height = viewport_size.height; + viewport.minDepth = 0; + viewport.maxDepth = 1.0; + + vkCmdSetViewport(command_buffer, 0, 1, &viewport); + + VkRect2D scissor; + scissor.offset.x = viewport_offset.x; + scissor.offset.y = viewport_offset.y; + scissor.extent.width = viewport_size.width; + scissor.extent.height = viewport_size.height; + + vkCmdSetScissor(command_buffer, 0, 1, &scissor); + + return ID_TYPE_DRAW_LIST; +} + +Error RenderingDeviceVulkan::draw_list_begin_split(ID p_framebuffer, uint32_t p_splits, ID *r_split_ids, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors, const Rect2 &p_region) { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(p_splits < 1, ERR_INVALID_DECLARATION); + + Framebuffer *framebuffer = framebuffer_owner.getornull(p_framebuffer); + ERR_FAIL_COND_V(!framebuffer, ERR_INVALID_DECLARATION); + + Point2i viewport_offset; + Point2i viewport_size = framebuffer->size; + + if (p_region != Rect2()) { //check custom region + Rect2i viewport(viewport_offset, viewport_size); + Rect2i regioni = p_region; + if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) && + ((regioni.position.x + regioni.size.x) <= (viewport.position.x + viewport.size.x)) && + ((regioni.position.y + regioni.size.y) <= (viewport.position.y + viewport.size.y))) { + ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "When supplying a custom region, it must be contained within the framebuffer rectangle"); + } + + viewport_offset = regioni.position; + viewport_size = regioni.size; + } + + if (p_initial_action == INITIAL_ACTION_CLEAR) { //check clear values + + int color_attachments = framebuffer_formats[framebuffer->format_id].color_attachments; + ERR_FAIL_COND_V_MSG(p_clear_colors.size() != color_attachments, ERR_INVALID_PARAMETER, + "Clear color values supplied (" + itos(p_clear_colors.size()) + ") differ from the amount required for framebuffer (" + itos(color_attachments) + ")."); + } + + if (p_splits > (uint32_t)split_draw_list_allocators.size()) { + uint32_t from = split_draw_list_allocators.size(); + split_draw_list_allocators.resize(p_splits); + for (uint32_t i = from; i < p_splits; i++) { + + VkCommandPoolCreateInfo cmd_pool_info; + cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + cmd_pool_info.pNext = NULL; + cmd_pool_info.queueFamilyIndex = context->get_graphics_queue(); + cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + VkResult res = vkCreateCommandPool(device, &cmd_pool_info, NULL, &split_draw_list_allocators.write[i].command_pool); + ERR_FAIL_COND_V(res, ERR_CANT_CREATE); + + for (int j = 0; j < frame_count; j++) { + + VkCommandBuffer command_buffer; + + VkCommandBufferAllocateInfo cmdbuf; + //no command buffer exists, create it. + cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + cmdbuf.pNext = NULL; + cmdbuf.commandPool = split_draw_list_allocators[i].command_pool; + cmdbuf.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; + cmdbuf.commandBufferCount = 1; + + VkResult err = vkAllocateCommandBuffers(device, &cmdbuf, &command_buffer); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + split_draw_list_allocators.write[i].command_buffers.push_back(command_buffer); + } + } + } + + VkFramebuffer vkframebuffer; + VkRenderPass render_pass; + + Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_action, p_final_action, &vkframebuffer, &render_pass); + ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); + + VkCommandBuffer frame_command_buffer = frames[frame].draw_command_buffer; + err = _draw_list_render_pass_begin(framebuffer, p_initial_action, p_final_action, p_clear_colors, viewport_offset, viewport_size, vkframebuffer, render_pass, frame_command_buffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + + if (err != OK) { + return ERR_CANT_CREATE; + } + + draw_list = memnew_arr(DrawList, p_splits); + draw_list_count = p_splits; + draw_list_split = true; + + for (uint32_t i = 0; i < p_splits; i++) { + + //take a command buffer and initialize it + VkCommandBuffer command_buffer = split_draw_list_allocators[p_splits].command_buffers[frame]; + + VkCommandBufferInheritanceInfo inheritance_info; + inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; + inheritance_info.pNext = NULL; + inheritance_info.renderPass = render_pass; + inheritance_info.subpass = 0; + inheritance_info.framebuffer = vkframebuffer; + inheritance_info.occlusionQueryEnable = false; + inheritance_info.queryFlags = 0; //? + inheritance_info.pipelineStatistics = 0; + + VkCommandBufferBeginInfo cmdbuf_begin; + cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdbuf_begin.pNext = NULL; + cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; + cmdbuf_begin.pInheritanceInfo = &inheritance_info; + + VkResult res = vkResetCommandBuffer(command_buffer, 0); + if (res) { + memdelete_arr(draw_list); + draw_list = NULL; + ERR_FAIL_V(ERR_CANT_CREATE); + } + + res = vkBeginCommandBuffer(command_buffer, &cmdbuf_begin); + if (res) { + memdelete_arr(draw_list); + draw_list = NULL; + ERR_FAIL_V(ERR_CANT_CREATE); + } + + draw_list[i].command_buffer = command_buffer; + draw_list[i].validation.framebuffer_format = framebuffer->format_id; + + VkViewport viewport; + viewport.x = viewport_offset.x; + viewport.y = viewport_offset.y; + viewport.width = viewport_size.width; + viewport.height = viewport_size.height; + viewport.minDepth = 0; + viewport.maxDepth = 1.0; + + vkCmdSetViewport(command_buffer, 0, 1, &viewport); + + VkRect2D scissor; + scissor.offset.x = viewport_offset.x; + scissor.offset.y = viewport_offset.y; + scissor.extent.width = viewport_size.width; + scissor.extent.height = viewport_size.height; + + vkCmdSetScissor(command_buffer, 0, 1, &scissor); + r_split_ids[i] = (ID(1) << ID(ID_TYPE_SPLIT_DRAW_LIST)) + i; + } + + return OK; +} + +RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(ID p_id) { + if (p_id < 0) { + return NULL; + } + + if (!draw_list) { + return NULL; + } else if (p_id == ID_TYPE_DRAW_LIST) { + if (draw_list_split) { + return NULL; + } + return draw_list; + } else if (p_id >> ID(ID_BASE_SHIFT) == ID_TYPE_SPLIT_DRAW_LIST) { + if (!draw_list_split) { + return NULL; + } + + uint64_t index = p_id & ((ID(1) << ID(ID_BASE_SHIFT)) - 1); //mask + + if (index >= draw_list_count) { + return NULL; + } + + return &draw_list[index]; + } else { + return NULL; + } +} + +void RenderingDeviceVulkan::draw_list_bind_render_pipeline(ID p_list, ID p_render_pipeline) { + + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); + + const RenderPipeline *pipeline = pipeline_owner.getornull(p_render_pipeline); + ERR_FAIL_COND(!pipeline); + + ERR_FAIL_COND(pipeline->framebuffer_format != dl->validation.framebuffer_format); + + vkCmdBindPipeline(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline); + + //update render pass pipeline info + dl->validation.pipeline_active = true; + dl->validation.pipeline_dynamic_state = pipeline->dynamic_state; + dl->validation.pipeline_vertex_format = pipeline->vertex_format; + dl->validation.pipeline_uses_restart_indices = pipeline->uses_restart_indices; + dl->validation.pipeline_primitive_divisor = pipeline->primitive_divisor; + + dl->validation.pipeline_primitive_minimum = pipeline->primitive_minimum; + dl->validation.pipeline_set_hashes = pipeline->set_hashes; +} + +void RenderingDeviceVulkan::draw_list_bind_uniform_set(ID p_list, ID p_uniform_set, uint32_t p_index) { + ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets, + "Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ")."); + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); + + const UniformSet *uniform_set = uniform_set_owner.getornull(p_uniform_set); + ERR_FAIL_COND(!uniform_set); + + if ((uint32_t)dl->validation.set_hashes.size() <= p_index) { + uint32_t csize = dl->validation.set_hashes.size(); + uint32_t new_size = p_uniform_set + 1; + dl->validation.set_hashes.resize(new_size); + for (uint32_t i = csize; i < new_size; i++) { + dl->validation.set_hashes.write[i] = 0; + } + } +#ifdef DEBUG_ENABLED + //validate that textures used are not bound + //this can be a bit slow in large descriptor sets, + //so it's disabled on release + uint32_t tb_count = uniform_set->textures.size(); + const ID *tb_ptr = uniform_set->textures.ptr(); + uint32_t bound_count = draw_list_bound_textures.size(); + const ID *bound_ptr = draw_list_bound_textures.ptr(); + for (uint32_t i = 0; i < tb_count; i++) { + for (uint32_t j = 0; j < bound_count; j++) { + ERR_FAIL_COND_MSG(tb_ptr[i] == bound_ptr[j], + "Attempted to use the same texture in framebuffer attachment and a uniform set, this is not allowed."); + } + } +#endif + dl->validation.set_hashes.write[p_index] = uniform_set->hash; + + vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, uniform_set->pipeline_layout, p_index, 1, &uniform_set->descriptor_set, 0, NULL); +} + +void RenderingDeviceVulkan::draw_list_bind_vertex_array(ID p_list, ID p_vertex_array) { + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); + + const VertexArray *vertex_array = vertex_array_owner.getornull(p_vertex_array); + ERR_FAIL_COND(!vertex_array); + dl->validation.vertex_format = vertex_array->description; + dl->validation.vertex_array_size = vertex_array->vertex_count; + dl->validation.vertex_max_instances_allowed = vertex_array->max_instances_allowed; + + vkCmdBindVertexBuffers(dl->command_buffer, 0, vertex_array->buffers.size(), vertex_array->buffers.ptr(), vertex_array->offsets.ptr()); +} +void RenderingDeviceVulkan::draw_list_bind_index_array(ID p_list, ID p_index_array) { + + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); + + const IndexArray *index_array = index_array_owner.getornull(p_index_array); + ERR_FAIL_COND(!index_array); + + dl->validation.index_array_size = index_array->indices; + dl->validation.index_array_max_index = index_array->max_index; + dl->validation.index_array_offset = index_array->offset; + + vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, index_array->offset, index_array->index_type); +} + +void RenderingDeviceVulkan::draw_list_draw(ID p_list, bool p_use_indices, uint32_t p_instances) { + + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); + + ERR_FAIL_COND_MSG(!dl->validation.pipeline_active, + "No render pipeline was set before attempting to draw."); + if (dl->validation.pipeline_vertex_format != INVALID_ID) { + //pipeline uses vertices, validate format + ERR_FAIL_COND_MSG(dl->validation.vertex_format == INVALID_ID, + "No vertex array was bound, and render pipeline expects vertices."); + //make sure format is right + ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format != dl->validation.vertex_format, + "The vertex format used to create the pipeline does not match the vertex format bound."); + //make sure amount of instances is valid + ERR_FAIL_COND_MSG(p_instances > dl->validation.vertex_max_instances_allowed, + "Amount of instances requested (" + itos(p_instances) + " is larger than the maximum amount suported by the bound vertex array (" + itos(dl->validation.vertex_max_instances_allowed) + ")."); + } + //compare hashes + if (dl->validation.pipeline_set_hashes.size()) { + ERR_FAIL_COND_MSG(dl->validation.pipeline_set_hashes.size() > dl->validation.set_hashes.size(), + "Render pipeline requires uniform sets which were not set at the time of drawing."); + + uint32_t hash_count = dl->validation.pipeline_set_hashes.size(); + const uint32_t *phashes = dl->validation.pipeline_set_hashes.ptr(); + const uint32_t *shashes = dl->validation.set_hashes.ptr(); + + for (uint32_t i = 0; i < hash_count; i++) { + if (phashes[i] == 0) { + continue; //not used by pipeline, no need to check + } + if (phashes[i] != shashes[i]) { + if (shashes[i] == 0) { + ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline"); + } else { + ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ") are not the same format as required by the pipeline shader."); + } + } + } + } + + if (p_use_indices) { + ERR_FAIL_COND_MSG(!dl->validation.index_array_size, + "Draw command requested indices, but no index buffer was set."); + if (dl->validation.pipeline_vertex_format != INVALID_ID) { + //uses vertices, do some vertex validations + ERR_FAIL_COND_MSG(dl->validation.vertex_array_size < dl->validation.index_array_max_index, + "Index array references (max index: " + itos(dl->validation.index_array_max_index) + ") indices beyond the vertex array size (" + itos(dl->validation.vertex_array_size) + ")."); + } + + ERR_FAIL_COND_MSG(dl->validation.pipeline_uses_restart_indices != dl->validation.index_buffer_uses_restart_indices, + "The usage of restart indices in index buffer does not match the render primitive in the pipeline."); + + uint32_t to_draw = dl->validation.index_array_size; + + ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum, + "Too few indices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ")."); + + ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0, + "Index amount (" + itos(to_draw) + ") must be a multiple of the amount of indices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ")."); + + vkCmdDrawIndexed(dl->command_buffer, to_draw, p_instances, dl->validation.index_array_offset, 0, 0); + } else { + ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID, + "Draw command lacks indices, but pipeline format does not use vertices."); + + uint32_t to_draw = dl->validation.vertex_array_size; + + ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum, + "Too few vertices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ")."); + + ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0, + "Vertex amount (" + itos(to_draw) + ") must be a multiple of the amount of vertices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ")."); + + vkCmdDraw(dl->command_buffer, to_draw, p_instances, 0, 0); + } +} + +void RenderingDeviceVulkan::draw_list_enable_scissor(ID p_list, const Rect2 &p_rect) { +} +void RenderingDeviceVulkan::draw_list_disable_scissor(ID p_list) { +} + +void RenderingDeviceVulkan::draw_list_end() { + + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_MSG(!draw_list, "Immediate draw list is already inactive."); + + if (draw_list_split) { + //send all command buffers + VkCommandBuffer *command_buffers = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer) * draw_list_count); + for (uint32_t i = 0; i < draw_list_count; i++) { + vkEndCommandBuffer(draw_list->command_buffer); + command_buffers[i] = draw_list->command_buffer; + } + + vkCmdExecuteCommands(frames[frame].draw_command_buffer, draw_list_count, command_buffers); + vkCmdEndRenderPass(frames[frame].draw_command_buffer); + memdelete_arr(draw_list); + draw_list = NULL; + + } else { + //just end the list + vkCmdEndRenderPass(draw_list->command_buffer); + memdelete(draw_list); + draw_list = NULL; + } + + if (draw_list_unbind_textures) { + for (int i = 0; i < draw_list_bound_textures.size(); i++) { + Texture *texture = texture_owner.getornull(draw_list_bound_textures[i]); + ERR_CONTINUE(!texture); //wtf + texture->bound = false; + } + } + draw_list_bound_textures.clear(); +} +#if 0 +void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_framebuffer, ID *p_draw_lists, uint32_t p_draw_list_count, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors) { + + VkCommandBuffer frame_cmdbuf = frames[frame].frame_buffer; + ERR_FAIL_COND(!frame_cmdbuf); + + VkRenderPassBeginInfo render_pass_begin; + render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + render_pass_begin.pNext = NULL; + render_pass_begin.renderPass = context->get_render_pass(); + render_pass_begin.framebuffer = context->get_frame_framebuffer(frame); + + render_pass_begin.renderArea.extent.width = context->get_screen_width(p_screen); + render_pass_begin.renderArea.extent.height = context->get_screen_height(p_screen); + render_pass_begin.renderArea.offset.x = 0; + render_pass_begin.renderArea.offset.y = 0; + + render_pass_begin.clearValueCount = 1; + + VkClearValue clear_value; + clear_value.color.float32[0] = p_clear_color.r; + clear_value.color.float32[1] = p_clear_color.g; + clear_value.color.float32[2] = p_clear_color.b; + clear_value.color.float32[3] = p_clear_color.a; + + render_pass_begin.pClearValues = &clear_value; + + vkCmdBeginRenderPass(frame_cmdbuf, &render_pass_begin, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + + ID screen_format = screen_get_framebuffer_format(); + { + + VkCommandBuffer *command_buffers = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer) * p_draw_list_count); + uint32_t command_buffer_count = 0; + + for (uint32_t i = 0; i < p_draw_list_count; i++) { + DrawList *dl = _get_draw_list_ptr(p_draw_lists[i]); + ERR_CONTINUE_MSG(!dl, "Draw list index (" + itos(i) + ") is not a valid draw list ID."); + ERR_CONTINUE_MSG(dl->validation.framebuffer_format != p_format_check, + "Draw list index (" + itos(i) + ") is created with a framebuffer format incompatible with this render pass."); + + if (dl->validation.active) { + //needs to be closed, so close it. + vkEndCommandBuffer(dl->command_buffer); + dl->validation.active = false; + } + + command_buffers[command_buffer_count++] = dl->command_buffer; + } + + print_line("to draw: " + itos(command_buffer_count)); + vkCmdExecuteCommands(p_primary, command_buffer_count, command_buffers); + } + + vkCmdEndRenderPass(frame_cmdbuf); + +} +#endif + +void RenderingDeviceVulkan::_free_internal(ID p_id) { + + //push everything so it's disposed of next time this frame index is processed (means, it's safe to do it) + if (texture_owner.owns(p_id)) { + Texture *texture = texture_owner.getornull(p_id); + frames[frame].textures_to_dispose_of.push_back(*texture); + texture_owner.free(p_id); + } else if (framebuffer_owner.owns(p_id)) { + Framebuffer *framebuffer = framebuffer_owner.getornull(p_id); + frames[frame].framebuffers_to_dispose_of.push_back(*framebuffer); + framebuffer_owner.free(p_id); + } else if (sampler_owner.owns(p_id)) { + VkSampler *sampler = sampler_owner.getornull(p_id); + frames[frame].samplers_to_dispose_of.push_back(*sampler); + sampler_owner.free(p_id); + } else if (vertex_buffer_owner.owns(p_id)) { + Buffer *vertex_buffer = vertex_buffer_owner.getornull(p_id); + frames[frame].buffers_to_dispose_of.push_back(*vertex_buffer); + vertex_buffer_owner.free(p_id); + } else if (vertex_array_owner.owns(p_id)) { + vertex_array_owner.free(p_id); + } else if (index_buffer_owner.owns(p_id)) { + IndexBuffer *index_buffer = index_buffer_owner.getornull(p_id); + Buffer b; + b.allocation = index_buffer->allocation; + b.buffer = index_buffer->buffer; + frames[frame].buffers_to_dispose_of.push_back(b); + index_buffer_owner.free(p_id); + } else if (index_array_owner.owns(p_id)) { + index_array_owner.free(p_id); + } else if (shader_owner.owns(p_id)) { + Shader *shader = shader_owner.getornull(p_id); + frames[frame].shaders_to_dispose_of.push_back(*shader); + shader_owner.free(p_id); + } else if (uniform_buffer_owner.owns(p_id)) { + Buffer *uniform_buffer = uniform_buffer_owner.getornull(p_id); + frames[frame].buffers_to_dispose_of.push_back(*uniform_buffer); + uniform_buffer_owner.free(p_id); + } else if (texture_buffer_owner.owns(p_id)) { + TextureBuffer *texture_buffer = texture_buffer_owner.getornull(p_id); + frames[frame].buffers_to_dispose_of.push_back(texture_buffer->buffer); + frames[frame].buffer_views_to_dispose_of.push_back(texture_buffer->view); + texture_buffer_owner.free(p_id); + } else if (storage_buffer_owner.owns(p_id)) { + Buffer *storage_buffer = storage_buffer_owner.getornull(p_id); + frames[frame].buffers_to_dispose_of.push_back(*storage_buffer); + storage_buffer_owner.free(p_id); + } else if (uniform_set_owner.owns(p_id)) { + UniformSet *uniform_set = uniform_set_owner.getornull(p_id); + frames[frame].uniform_sets_to_dispose_of.push_back(*uniform_set); + uniform_set_owner.free(p_id); + } else if (pipeline_owner.owns(p_id)) { + RenderPipeline *pipeline = pipeline_owner.getornull(p_id); + frames[frame].pipelines_to_dispose_of.push_back(*pipeline); + pipeline_owner.free(p_id); + } else { + ERR_PRINT("Attempted to free invalid ID: " + itos(p_id)); + } +} +void RenderingDeviceVulkan::free(ID p_id) { + + _THREAD_SAFE_METHOD_ + + _free_dependencies(p_id); //recursively erase dependencies first, to avoid potential API problems + _free_internal(p_id); +} + +void RenderingDeviceVulkan::finalize_frame() { + + _THREAD_SAFE_METHOD_ + + if (draw_list) { + ERR_PRINT("Found open draw list at the end of the frame, this should never happen (further drawing will likely not work)."); + } + + { //complete the setup buffer (that needs to be processed before anything else) + vkEndCommandBuffer(frames[frame].setup_command_buffer); + vkEndCommandBuffer(frames[frame].draw_command_buffer); + } +} + +void RenderingDeviceVulkan::_free_pending_resources() { + //free in dependency usage order, so nothing weird happens + + //pipelines + while (frames[frame].pipelines_to_dispose_of.front()) { + RenderPipeline *pipeline = &frames[frame].pipelines_to_dispose_of.front()->get(); + + vkDestroyPipeline(device, pipeline->pipeline, NULL); + + frames[frame].pipelines_to_dispose_of.pop_front(); + } + + //uniform sets + while (frames[frame].uniform_sets_to_dispose_of.front()) { + UniformSet *uniform_set = &frames[frame].uniform_sets_to_dispose_of.front()->get(); + + vkFreeDescriptorSets(device, uniform_set->pool->pool, 1, &uniform_set->descriptor_set); + _descriptor_pool_free(uniform_set->pool_key, uniform_set->pool); + + frames[frame].uniform_sets_to_dispose_of.pop_front(); + } + + //buffer views + while (frames[frame].buffer_views_to_dispose_of.front()) { + VkBufferView buffer_view = frames[frame].buffer_views_to_dispose_of.front()->get(); + + vkDestroyBufferView(device, buffer_view, NULL); + + frames[frame].buffer_views_to_dispose_of.pop_front(); + } + + //shaders + while (frames[frame].shaders_to_dispose_of.front()) { + Shader *shader = &frames[frame].shaders_to_dispose_of.front()->get(); + + //descriptor set layout for each set + for (int i = 0; i < shader->sets.size(); i++) { + vkDestroyDescriptorSetLayout(device, shader->sets[i].descriptor_set_layout, NULL); + } + + //pipeline layout + vkDestroyPipelineLayout(device, shader->pipeline_layout, NULL); + + //shaders themselves + for (int i = 0; i < shader->pipeline_stages.size(); i++) { + vkDestroyShaderModule(device, shader->pipeline_stages[i].module, NULL); + } + + frames[frame].shaders_to_dispose_of.pop_front(); + } + + //samplers + while (frames[frame].samplers_to_dispose_of.front()) { + VkSampler sampler = frames[frame].samplers_to_dispose_of.front()->get(); + + vkDestroySampler(device, sampler, NULL); + + frames[frame].samplers_to_dispose_of.pop_front(); + } + + //framebuffers + while (frames[frame].framebuffers_to_dispose_of.front()) { + Framebuffer *framebuffer = &frames[frame].framebuffers_to_dispose_of.front()->get(); + + for (Map::Element *E = framebuffer->framebuffers.front(); E; E = E->next()) { + //first framebuffer, then render pass because it depends on it + vkDestroyFramebuffer(device, E->get().framebuffer, NULL); + vkDestroyRenderPass(device, E->get().render_pass, NULL); + } + + frames[frame].framebuffers_to_dispose_of.pop_front(); + } + + //textures + while (frames[frame].textures_to_dispose_of.front()) { + Texture *texture = &frames[frame].textures_to_dispose_of.front()->get(); + + if (texture->bound) { + WARN_PRINT("Deleted a texture while it was bound.."); + } + vkDestroyImageView(device, texture->view, NULL); + if (texture->owner == INVALID_ID) { + //actually owns the image and the allocation too + vmaDestroyImage(allocator, texture->image, texture->allocation); + vmaFreeMemory(allocator, texture->allocation); + } + frames[frame].textures_to_dispose_of.pop_front(); + } + + //buffers + while (frames[frame].buffers_to_dispose_of.front()) { + _buffer_free(&frames[frame].buffers_to_dispose_of.front()->get()); + + frames[frame].buffers_to_dispose_of.pop_front(); + } +} + +void RenderingDeviceVulkan::advance_frame() { + + _THREAD_SAFE_METHOD_ + + //advance the frame + frame = (frame + 1) % frame_count; + + //erase pending resources + _free_pending_resources(); + + //create setup command buffer and set as the setup buffer + + { + VkCommandBufferBeginInfo cmdbuf_begin; + cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdbuf_begin.pNext = NULL; + cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + cmdbuf_begin.pInheritanceInfo = NULL; + + VkResult err = vkResetCommandBuffer(frames[frame].setup_command_buffer, 0); + ERR_FAIL_COND(err); + + err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND(err); + context->set_setup_buffer(frames[frame].setup_command_buffer); //append now so it's added before everything else + err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND(err); + context->append_command_buffer(frames[frame].draw_command_buffer); + } + + //advance current frame + frames_drawn++; + //advance staging buffer if used + if (staging_buffer_used) { + staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size(); + staging_buffer_used = false; + } +} + +void RenderingDeviceVulkan::initialize(VulkanContext *p_context) { + + context = p_context; + device = p_context->get_device(); + frame_count = p_context->get_frame_count(); + limits = p_context->get_device_limits(); + + { //initialize allocator + + VmaAllocatorCreateInfo allocatorInfo; + memset(&allocatorInfo, 0, sizeof(VmaAllocatorCreateInfo)); + allocatorInfo.physicalDevice = p_context->get_physical_device(); + allocatorInfo.device = device; + vmaCreateAllocator(&allocatorInfo, &allocator); + } + + frames = memnew_arr(Frame, frame_count); + frame = 0; + //create setup and frame buffers + for (int i = 0; i < frame_count; i++) { + + { //create command pool, one per frame is recommended + VkCommandPoolCreateInfo cmd_pool_info; + cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + cmd_pool_info.pNext = NULL; + cmd_pool_info.queueFamilyIndex = p_context->get_graphics_queue(); + cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + VkResult res = vkCreateCommandPool(device, &cmd_pool_info, NULL, &frames[i].command_pool); + ERR_FAIL_COND(res); + } + + { //create command buffers + + VkCommandBufferAllocateInfo cmdbuf; + //no command buffer exists, create it. + cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + cmdbuf.pNext = NULL; + cmdbuf.commandPool = frames[i].command_pool; + cmdbuf.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + cmdbuf.commandBufferCount = 1; + + VkResult err = vkAllocateCommandBuffers(device, &cmdbuf, &frames[i].setup_command_buffer); + ERR_CONTINUE(err); + + err = vkAllocateCommandBuffers(device, &cmdbuf, &frames[i].draw_command_buffer); + ERR_CONTINUE(err); + } + } + + { + //begin the first command buffer for the first frame, so + //setting up things can be done in the meantime until finalize_frame(), which is called before advance. + VkCommandBufferBeginInfo cmdbuf_begin; + cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdbuf_begin.pNext = NULL; + cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + cmdbuf_begin.pInheritanceInfo = NULL; + + VkResult err = vkBeginCommandBuffer(frames[0].setup_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND(err); + context->set_setup_buffer(frames[0].setup_command_buffer); //append now so it's added before everything else + + err = vkBeginCommandBuffer(frames[0].draw_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND(err); + context->append_command_buffer(frames[0].draw_command_buffer); + } + + staging_buffer_block_size = GLOBAL_DEF("rendering/vulkan/staging_buffer/block_size_kb", 256); + staging_buffer_block_size = MAX(4, staging_buffer_block_size); + staging_buffer_block_size *= 1024; //kb -> bytes + staging_buffer_max_size = GLOBAL_DEF("rendering/vulkan/staging_buffer/max_size_mb", 128); + staging_buffer_max_size = MAX(1, staging_buffer_max_size); + staging_buffer_max_size *= 1024 * 1024; + + if (staging_buffer_max_size < staging_buffer_block_size * 4) { + //validate enough blocks + staging_buffer_max_size = staging_buffer_block_size * 4; + } + texture_upload_region_size_px = GLOBAL_DEF("rendering/vulkan/staging_buffer/texture_upload_region_size_px", 64); + texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px); + print_line("update size: " + itos(texture_upload_region_size_px)); + + frames_drawn = frame_count; //start from frame count, so everything else is immediately old + + //ensure current staging block is valid and at least one per frame exists + staging_buffer_current = 0; + staging_buffer_used = false; + + for (int i = 0; i < frame_count; i++) { + //staging was never used, create a block + Error err = _insert_staging_block(); + ERR_CONTINUE(err != OK); + } + + max_descriptors_per_pool = GLOBAL_DEF("rendering/vulkan/descriptor_pools/max_descriptors_per_pool", 64); + + //check to make sure DescriptorPoolKey is good + ERR_FAIL_COND(sizeof(uint64_t) * 3 < UNIFORM_TYPE_MAX * sizeof(uint16_t)); + + draw_list = NULL; + draw_list_count = 0; + draw_list_split = false; +} +void RenderingDeviceVulkan::finalize() { + + memdelete_arr(frames); +} + +RenderingDeviceVulkan::RenderingDeviceVulkan() { +} -- cgit v1.2.3 From edb6966024850076fc201f1a4ba785fe972f16ed Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Fri, 7 Jun 2019 15:20:01 -0300 Subject: Improved validation of attachments --- drivers/vulkan/rendering_device_vulkan.cpp | 86 +++++++++++++++++++----------- 1 file changed, 54 insertions(+), 32 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index bcd103b67b..ebc01a5863 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1654,14 +1654,30 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_create(const TextureFormat &p texture.usage_flags = p_format.usage_bits; texture.samples = p_format.samples; + //set bound and unbound layouts if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { texture.aspect_mask = TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - texture.reading_layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; + + if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) { + texture.unbound_layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; + } else { + texture.unbound_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } texture.bound_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - } else { + + } else if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + texture.aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; - texture.reading_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) { + texture.unbound_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } else { + texture.unbound_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } texture.bound_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } else { + texture.aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; + texture.unbound_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + texture.bound_layout = VK_IMAGE_LAYOUT_UNDEFINED; //will never be bound } texture.bound = false; @@ -1733,7 +1749,7 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_create(const TextureFormat &p image_memory_barrier.srcAccessMask = 0; image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - image_memory_barrier.newLayout = texture.reading_layout; + image_memory_barrier.newLayout = texture.unbound_layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = texture.image; @@ -1888,7 +1904,7 @@ Error RenderingDeviceVulkan::texture_update(ID p_texture, uint32_t p_mipmap, uin image_memory_barrier.pNext = NULL; image_memory_barrier.srcAccessMask = 0; image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - image_memory_barrier.oldLayout = texture->reading_layout; + image_memory_barrier.oldLayout = texture->unbound_layout; image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -2017,7 +2033,7 @@ Error RenderingDeviceVulkan::texture_update(ID p_texture, uint32_t p_mipmap, uin image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - image_memory_barrier.newLayout = texture->reading_layout; + image_memory_barrier.newLayout = texture->unbound_layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = texture->image; @@ -2093,6 +2109,8 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector 1, VK_NULL_HANDLE); - ERR_FAIL_COND_V(resolve_references.size() > 1, VK_NULL_HANDLE); + ERR_FAIL_COND_V_MSG(depth_stencil_references.size() > 1, VK_NULL_HANDLE, + "Formats can only have one depth/stencil attachment, supplied (" + itos(depth_stencil_references.size()) + ")."); + + ERR_FAIL_COND_V_MSG(resolve_references.size() > 1, VK_NULL_HANDLE, + "Formats can only have one resolve attachment, supplied (" + itos(resolve_references.size()) + ")."); VkSubpassDescription subpass; subpass.flags = 0; @@ -2295,6 +2316,9 @@ RenderingDevice::ID RenderingDeviceVulkan::framebuffer_format_create(const Vecto int color_references; VkRenderPass render_pass = _render_pass_create(p_format, INITIAL_ACTION_CLEAR, FINAL_ACTION_DISCARD, &color_references); //actions don't matter for this use case + if (render_pass == VK_NULL_HANDLE) { //was likely invalid + return INVALID_ID; + } ID id = ID(framebuffer_format_cache.size()) | (ID(ID_TYPE_FRAMEBUFFER_FORMAT) << ID(ID_BASE_SHIFT)); E = framebuffer_format_cache.insert(key, id); @@ -3406,10 +3430,8 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vector > buffer_infos; List > buffer_views; List > image_infos; -#ifdef DEBUG_ENABLED //used for verification to make sure a uniform set does not use a framebuffer bound texture - Vector bound_textures; -#endif + Vector attachable_textures; for (uint32_t i = 0; i < set_uniform_count; i++) { const Shader::UniformInfo &set_uniform = set_uniforms[i]; @@ -3494,16 +3516,16 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vectorview; -#ifdef DEBUG_ENABLED - bound_textures.push_back(texture->owner != INVALID_ID ? texture->owner : uniform.ids[j + 1]); -#endif + if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)) { + attachable_textures.push_back(texture->owner != INVALID_ID ? texture->owner : uniform.ids[j + 1]); + } if (texture->owner != INVALID_ID) { texture = texture_owner.getornull(texture->owner); ERR_FAIL_COND_V(!texture, INVALID_ID); //bug, should never happen } - img_info.imageLayout = texture->reading_layout; + img_info.imageLayout = texture->unbound_layout; image_info.push_back(img_info); } @@ -3541,16 +3563,16 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vectorview; -#ifdef DEBUG_ENABLED - bound_textures.push_back(texture->owner != INVALID_ID ? texture->owner : uniform.ids[j]); -#endif + if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)) { + attachable_textures.push_back(texture->owner != INVALID_ID ? texture->owner : uniform.ids[j]); + } if (texture->owner != INVALID_ID) { texture = texture_owner.getornull(texture->owner); ERR_FAIL_COND_V(!texture, INVALID_ID); //bug, should never happen } - img_info.imageLayout = texture->reading_layout; + img_info.imageLayout = texture->unbound_layout; image_info.push_back(img_info); } @@ -3719,6 +3741,7 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vectorpipeline_layout; uniform_set.hash = shader->set_hashes[p_shader_set]; + uniform_set.attachable_textures = attachable_textures; ID id = uniform_set_owner.make_id(uniform_set); //add dependencies @@ -4607,21 +4630,20 @@ void RenderingDeviceVulkan::draw_list_bind_uniform_set(ID p_list, ID p_uniform_s dl->validation.set_hashes.write[i] = 0; } } -#ifdef DEBUG_ENABLED - //validate that textures used are not bound - //this can be a bit slow in large descriptor sets, - //so it's disabled on release - uint32_t tb_count = uniform_set->textures.size(); - const ID *tb_ptr = uniform_set->textures.ptr(); - uint32_t bound_count = draw_list_bound_textures.size(); - const ID *bound_ptr = draw_list_bound_textures.ptr(); - for (uint32_t i = 0; i < tb_count; i++) { - for (uint32_t j = 0; j < bound_count; j++) { - ERR_FAIL_COND_MSG(tb_ptr[i] == bound_ptr[j], - "Attempted to use the same texture in framebuffer attachment and a uniform set, this is not allowed."); + + { //validate that textures bound are not attached as framebuffer bindings + uint32_t attachable_count = uniform_set->attachable_textures.size(); + const ID *attachable_ptr = uniform_set->attachable_textures.ptr(); + uint32_t bound_count = draw_list_bound_textures.size(); + const ID *bound_ptr = draw_list_bound_textures.ptr(); + for (uint32_t i = 0; i < attachable_count; i++) { + for (uint32_t j = 0; j < bound_count; j++) { + ERR_FAIL_COND_MSG(attachable_ptr[i] == bound_ptr[j], + "Attempted to use the same texture in framebuffer attachment and a uniform set, this is not allowed."); + } } } -#endif + dl->validation.set_hashes.write[p_index] = uniform_set->hash; vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, uniform_set->pipeline_layout, p_index, 1, &uniform_set->descriptor_set, 0, NULL); -- cgit v1.2.3 From 1522d8c3ee6ddf43267f124940f4e43612058407 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sat, 8 Jun 2019 17:10:52 -0300 Subject: Added support for push constants --- drivers/vulkan/rendering_device_vulkan.cpp | 69 +++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 10 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index ebc01a5863..d78d3e2570 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -2753,7 +2753,7 @@ static VkShaderStageFlagBits shader_stage_masks[RenderingDevice::SHADER_STAGE_MA VK_SHADER_STAGE_COMPUTE_BIT, }; -bool RenderingDeviceVulkan::_uniform_add_binding(Vector > &bindings, Vector > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, String *r_error) { +bool RenderingDeviceVulkan::_uniform_add_binding(Vector > &bindings, Vector > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, Shader::PushConstant &push_constant, String *r_error) { VkDescriptorSetLayoutBinding layout_binding; Shader::UniformInfo info; @@ -2825,17 +2825,26 @@ bool RenderingDeviceVulkan::_uniform_add_binding(VectorgetQualifier().storage == glslang::EvqUniform) { + if (reflection.getType()->getQualifier().layoutPushConstant) { + uint32_t len = reflection.size; + if (push_constant.push_constant_size != 0 && push_constant.push_constant_size != len) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' push constants for different stages should all be the same size."; + return false; + } + push_constant.push_constant_size = len; + push_constant.push_constants_vk_stage |= shader_stage_masks[p_stage]; + return true; + } print_line("DEBUG: Uniform buffer"); layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; info.type = UNIFORM_TYPE_UNIFORM_BUFFER; - } else if (reflection.getType()->getQualifier().storage == glslang::EvqBuffer) { layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; info.type = UNIFORM_TYPE_STORAGE_BUFFER; print_line("DEBUG: Storage buffer"); } else { if (r_error) { - *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported block type."; + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported block type: (" + itos(reflection.getType()->getQualifier().storage) + ")."; } return false; } @@ -2959,6 +2968,10 @@ RenderingDevice::ID RenderingDeviceVulkan::shader_create_from_source(const Vecto //descriptor layouts Vector > bindings; Vector > uniform_info; + Shader::PushConstant push_constant; + push_constant.push_constant_size = 0; + push_constant.push_constants_vk_stage = 0; + Vector vertex_input_locations; int fragment_outputs = 0; @@ -3031,25 +3044,25 @@ RenderingDevice::ID RenderingDeviceVulkan::shader_create_from_source(const Vecto program.dumpReflection(); for (int j = 0; j < program.getNumUniformVariables(); j++) { - if (!_uniform_add_binding(bindings, uniform_info, program.getUniform(j), p_stages[i].shader_stage, r_error)) { + if (!_uniform_add_binding(bindings, uniform_info, program.getUniform(j), p_stages[i].shader_stage, push_constant, r_error)) { return INVALID_ID; } } for (int j = 0; j < program.getNumUniformBlocks(); j++) { - if (!_uniform_add_binding(bindings, uniform_info, program.getUniformBlock(j), p_stages[i].shader_stage, r_error)) { + if (!_uniform_add_binding(bindings, uniform_info, program.getUniformBlock(j), p_stages[i].shader_stage, push_constant, r_error)) { return INVALID_ID; } } for (int j = 0; j < program.getNumBufferVariables(); j++) { - if (!_uniform_add_binding(bindings, uniform_info, program.getBufferVariable(j), p_stages[i].shader_stage, r_error)) { + if (!_uniform_add_binding(bindings, uniform_info, program.getBufferVariable(j), p_stages[i].shader_stage, push_constant, r_error)) { return INVALID_ID; } } for (int j = 0; j < program.getNumBufferBlocks(); j++) { - if (!_uniform_add_binding(bindings, uniform_info, program.getBufferBlock(j), p_stages[i].shader_stage, r_error)) { + if (!_uniform_add_binding(bindings, uniform_info, program.getBufferBlock(j), p_stages[i].shader_stage, push_constant, r_error)) { return INVALID_ID; } } @@ -3087,6 +3100,7 @@ RenderingDevice::ID RenderingDeviceVulkan::shader_create_from_source(const Vecto shader.vertex_input_locations = vertex_input_locations; shader.fragment_outputs = fragment_outputs; + shader.push_constant = push_constant; bool success = true; for (int i = 0; i < p_stages.size(); i++) { @@ -3181,10 +3195,19 @@ RenderingDevice::ID RenderingDeviceVulkan::shader_create_from_source(const Vecto layouts.write[i] = shader.sets[i].descriptor_set_layout; } - //unsupported for now pipeline_layout_create_info.pSetLayouts = layouts.ptr(); - pipeline_layout_create_info.pushConstantRangeCount = 0; - pipeline_layout_create_info.pPushConstantRanges = NULL; + if (push_constant.push_constant_size) { + VkPushConstantRange push_constant_range; + push_constant_range.stageFlags = push_constant.push_constants_vk_stage; + push_constant_range.offset = 0; + push_constant_range.size = push_constant.push_constant_size; + + pipeline_layout_create_info.pushConstantRangeCount = 1; + pipeline_layout_create_info.pPushConstantRanges = &push_constant_range; + } else { + pipeline_layout_create_info.pushConstantRangeCount = 0; + pipeline_layout_create_info.pPushConstantRanges = NULL; + } VkResult err = vkCreatePipelineLayout(device, &pipeline_layout_create_info, NULL, &shader.pipeline_layout); @@ -4118,6 +4141,9 @@ RenderingDevice::ID RenderingDeviceVulkan::render_pipeline_create(ID p_shader, I pipeline.vertex_format = p_vertex_description; pipeline.uses_restart_indices = input_assembly_create_info.primitiveRestartEnable; pipeline.set_hashes = shader->set_hashes; + pipeline.push_constant_size = shader->push_constant.push_constant_size; + pipeline.push_constant_stages = shader->push_constant.push_constants_vk_stage; + pipeline.pipeline_layout = shader->pipeline_layout; static const uint32_t primitive_divisor[RENDER_PRIMITIVE_MAX] = { 1, 2, 1, 1, 1, 3, 1, 1, 1, 1, 1 @@ -4610,6 +4636,12 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(ID p_list, ID p_rende dl->validation.pipeline_primitive_minimum = pipeline->primitive_minimum; dl->validation.pipeline_set_hashes = pipeline->set_hashes; + dl->validation.pipeline_push_constant_size = pipeline->push_constant_size; + if (pipeline->push_constant_size) { + dl->validation.pipeline_push_constant_stages = pipeline->push_constant_stages; + dl->validation.pipeline_push_constant_suppplied = false; + dl->validation.pipeline_push_constant_layout = pipeline->pipeline_layout; + } } void RenderingDeviceVulkan::draw_list_bind_uniform_set(ID p_list, ID p_uniform_set, uint32_t p_index) { @@ -4678,6 +4710,17 @@ void RenderingDeviceVulkan::draw_list_bind_index_array(ID p_list, ID p_index_arr vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, index_array->offset, index_array->index_type); } +void RenderingDeviceVulkan::draw_list_set_push_constant(ID p_list, void *p_data, uint32_t p_data_size) { + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); + + ERR_FAIL_COND_MSG(p_data_size != dl->validation.pipeline_push_constant_size, + "This render pipeline requires (" + itos(dl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")"); + + vkCmdPushConstants(dl->command_buffer, dl->validation.pipeline_push_constant_layout, dl->validation.pipeline_push_constant_stages, 0, p_data_size, p_data); + dl->validation.pipeline_push_constant_suppplied = true; +} + void RenderingDeviceVulkan::draw_list_draw(ID p_list, bool p_use_indices, uint32_t p_instances) { DrawList *dl = _get_draw_list_ptr(p_list); @@ -4697,6 +4740,12 @@ void RenderingDeviceVulkan::draw_list_draw(ID p_list, bool p_use_indices, uint32 ERR_FAIL_COND_MSG(p_instances > dl->validation.vertex_max_instances_allowed, "Amount of instances requested (" + itos(p_instances) + " is larger than the maximum amount suported by the bound vertex array (" + itos(dl->validation.vertex_max_instances_allowed) + ")."); } + + if (dl->validation.pipeline_push_constant_size > 0) { + //using push constants, check that they were supplied + ERR_FAIL_COND_MSG(!dl->validation.pipeline_push_constant_suppplied, + "The shader in this pipeline requires a push constant to be set before drawing, but it's not present."); + } //compare hashes if (dl->validation.pipeline_set_hashes.size()) { ERR_FAIL_COND_MSG(dl->validation.pipeline_set_hashes.size() > dl->validation.set_hashes.size(), -- cgit v1.2.3 From 9ffe57a10eecf79ab8df2f0497d0387383755df3 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Mon, 10 Jun 2019 14:12:24 -0300 Subject: Modify RenderingDevice to use RIDs, now that they are O(1) --- drivers/vulkan/rendering_device_vulkan.cpp | 470 ++++++++++++++--------------- 1 file changed, 234 insertions(+), 236 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index d78d3e2570..6466c8a19b 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -6,29 +6,29 @@ #include "thirdparty/glslang/SPIRV/GlslangToSpv.h" #include "thirdparty/glslang/glslang/Include/Types.h" -void RenderingDeviceVulkan::_add_dependency(ID p_id, ID p_depends_on) { +void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) { if (!dependency_map.has(p_depends_on)) { - dependency_map[p_depends_on] = Set(); + dependency_map[p_depends_on] = Set(); } dependency_map[p_depends_on].insert(p_id); if (!reverse_dependency_map.has(p_id)) { - reverse_dependency_map[p_id] = Set(); + reverse_dependency_map[p_id] = Set(); } reverse_dependency_map[p_id].insert(p_depends_on); } -void RenderingDeviceVulkan::_free_dependencies(ID p_id) { +void RenderingDeviceVulkan::_free_dependencies(RID p_id) { //direct dependencies must be freed - List to_free; - Map >::Element *E = dependency_map.find(p_id); + List to_free; + Map >::Element *E = dependency_map.find(p_id); if (E) { - for (Set::Element *F = E->get().front(); F; F = F->next()) { + for (Set::Element *F = E->get().front(); F; F = F->next()) { to_free.push_back(F->get()); } @@ -45,8 +45,8 @@ void RenderingDeviceVulkan::_free_dependencies(ID p_id) { if (E) { - for (Set::Element *F = E->get().front(); F; F = F->next()) { - Map >::Element *G = dependency_map.find(F->get()); + for (Set::Element *F = E->get().front(); F; F = F->next()) { + Map >::Element *G = dependency_map.find(F->get()); if (G) { G->get().erase(p_id); } @@ -1457,7 +1457,7 @@ Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, c /**** TEXTURE ****/ /*****************/ -RenderingDevice::ID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector > &p_data) { +RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector > &p_data) { _THREAD_SAFE_METHOD_ @@ -1483,30 +1483,30 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_create(const TextureFormat &p VK_IMAGE_TYPE_3D }; - ERR_FAIL_INDEX_V(p_format.type, TEXTURE_TYPE_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_format.type, TEXTURE_TYPE_MAX, RID()); image_create_info.imageType = image_type[p_format.type]; - ERR_FAIL_COND_V_MSG(p_format.width < 1, INVALID_ID, "Width must be equal or greater than 1 for all textures"); + ERR_FAIL_COND_V_MSG(p_format.width < 1, RID(), "Width must be equal or greater than 1 for all textures"); image_create_info.format = vulkan_formats[p_format.format]; image_create_info.extent.width = p_format.width; if (image_create_info.imageType == VK_IMAGE_TYPE_3D || image_create_info.imageType == VK_IMAGE_TYPE_2D) { - ERR_FAIL_COND_V_MSG(p_format.height < 1, INVALID_ID, "Height must be equal or greater than 1 for 2D and 3D textures"); + ERR_FAIL_COND_V_MSG(p_format.height < 1, RID(), "Height must be equal or greater than 1 for 2D and 3D textures"); image_create_info.extent.height = p_format.height; } else { image_create_info.extent.height = 1; } if (image_create_info.imageType == VK_IMAGE_TYPE_3D) { - ERR_FAIL_COND_V_MSG(p_format.depth < 1, INVALID_ID, "Depth must be equal or greater than 1 for 3D textures"); + ERR_FAIL_COND_V_MSG(p_format.depth < 1, RID(), "Depth must be equal or greater than 1 for 3D textures"); image_create_info.extent.depth = p_format.depth; } else { image_create_info.extent.depth = 1; } - ERR_FAIL_COND_V(p_format.mipmaps < 1, INVALID_ID); + ERR_FAIL_COND_V(p_format.mipmaps < 1, RID()); image_create_info.mipLevels = p_format.mipmaps; @@ -1515,11 +1515,10 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_create(const TextureFormat &p array_layer_multiplier = 6; } if (p_format.type == TEXTURE_TYPE_1D_ARRAY || p_format.type == TEXTURE_TYPE_2D_ARRAY || p_format.type == TEXTURE_TYPE_CUBE_ARRAY || p_format.type == TEXTURE_TYPE_CUBE) { - ERR_FAIL_COND_V_MSG(p_format.array_layers < 1, INVALID_ID, + ERR_FAIL_COND_V_MSG(p_format.array_layers < 1, RID(), "Amount of layers must be equal or greater than 1 for arrays and cubemaps."); - if ((p_format.type == TEXTURE_TYPE_CUBE_ARRAY || p_format.type == TEXTURE_TYPE_CUBE) && (p_format.array_layers % 6) != 0) { - ERR_FAIL_V_MSG(INVALID_ID, "Cubemap and cubemap array textures must provide a layer number that is multiple of 6"); - } + ERR_FAIL_COND_V_MSG((p_format.type == TEXTURE_TYPE_CUBE_ARRAY || p_format.type == TEXTURE_TYPE_CUBE) && (p_format.array_layers % 6) != 0, RID(), + "Cubemap and cubemap array textures must provide a layer number that is multiple of 6"); image_create_info.arrayLayers = p_format.array_layers; } else { image_create_info.arrayLayers = 1; @@ -1527,7 +1526,7 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_create(const TextureFormat &p image_create_info.arrayLayers = p_format.array_layers; - ERR_FAIL_INDEX_V(p_format.samples, TEXTURE_SAMPLES_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_format.samples, TEXTURE_SAMPLES_MAX, RID()); image_create_info.samples = rasterization_sample_count[p_format.samples]; image_create_info.tiling = (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL; @@ -1558,16 +1557,16 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_create(const TextureFormat &p uint32_t required_mipmaps = get_image_required_mipmaps(image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth); - ERR_FAIL_COND_V_MSG(required_mipmaps < image_create_info.mipLevels, INVALID_ID, + ERR_FAIL_COND_V_MSG(required_mipmaps < image_create_info.mipLevels, RID(), "Too many mipmaps requested for texture format and dimensions (" + itos(image_create_info.mipLevels) + "), maximum allowed: (" + itos(required_mipmaps) + ")."); if (p_data.size()) { - ERR_FAIL_COND_V_MSG(!(p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT), INVALID_ID, + ERR_FAIL_COND_V_MSG(!(p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT), RID(), "Texture needs the TEXTURE_USAGE_CAN_UPDATE_BIT usage flag in order to be updated at initialization or later"); int expected_images = image_create_info.mipLevels * image_create_info.arrayLayers * array_layer_multiplier; - ERR_FAIL_COND_V_MSG(p_data.size() != expected_images, INVALID_ID, + ERR_FAIL_COND_V_MSG(p_data.size() != expected_images, RID(), "Default supplied data for image format is of invalid length (" + itos(p_data.size()) + "), should be (" + itos(expected_images) + ")."); int idx = 0; @@ -1575,7 +1574,7 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_create(const TextureFormat &p for (uint32_t j = 0; j < image_create_info.mipLevels; j++) { print_line("computed size from " + Vector3(image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth)); uint32_t required_size = get_image_format_required_size(p_format.format, image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth, j); - ERR_FAIL_COND_V_MSG((uint32_t)p_data[idx].size() != required_size, INVALID_ID, + ERR_FAIL_COND_V_MSG((uint32_t)p_data[idx].size() != required_size, RID(), "Data for slice index " + itos(idx) + " (mapped to layer " + itos(i) + ", mipmap " + itos(j) + ") differs in size (supplied: " + itos(p_data[idx].size()) + ") than what is required by the format (" + itos(required_size) + ")."); idx++; } @@ -1598,35 +1597,35 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_create(const TextureFormat &p } if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT && !(flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { - ERR_FAIL_V_MSG(INVALID_ID, "Format " + format_text + " does not support usage as sampling texture."); + ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as sampling texture."); } if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) { - ERR_FAIL_V_MSG(INVALID_ID, "Format " + format_text + " does not support usage as color attachment."); + ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as color attachment."); } if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - ERR_FAIL_V_MSG(INVALID_ID, "Format " + format_text + " does not support usage as depth-stencil attachment."); + ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as depth-stencil attachment."); } if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) { - ERR_FAIL_V_MSG(INVALID_ID, "Format " + format_text + " does not support usage as storage image."); + ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as storage image."); } if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_ATOMIC_BIT && !(flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)) { - ERR_FAIL_V_MSG(INVALID_ID, "Format " + format_text + " does not support usage as atomic storage image."); + ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as atomic storage image."); } } //some view validation if (p_view.format_override != DATA_FORMAT_MAX) { - ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID()); } - ERR_FAIL_INDEX_V(p_view.swizzle_r, TEXTURE_SWIZZLE_MAX, INVALID_ID); - ERR_FAIL_INDEX_V(p_view.swizzle_g, TEXTURE_SWIZZLE_MAX, INVALID_ID); - ERR_FAIL_INDEX_V(p_view.swizzle_b, TEXTURE_SWIZZLE_MAX, INVALID_ID); - ERR_FAIL_INDEX_V(p_view.swizzle_a, TEXTURE_SWIZZLE_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_view.swizzle_r, TEXTURE_SWIZZLE_MAX, RID()); + ERR_FAIL_INDEX_V(p_view.swizzle_g, TEXTURE_SWIZZLE_MAX, RID()); + ERR_FAIL_INDEX_V(p_view.swizzle_b, TEXTURE_SWIZZLE_MAX, RID()); + ERR_FAIL_INDEX_V(p_view.swizzle_a, TEXTURE_SWIZZLE_MAX, RID()); //allocate memory @@ -1642,7 +1641,7 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_create(const TextureFormat &p Texture texture; VkResult err = vmaCreateImage(allocator, &image_create_info, &allocInfo, &texture.image, &texture.allocation, &texture.allocation_info); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + ERR_FAIL_COND_V(err, RID()); texture.type = p_format.type; texture.format = p_format.format; @@ -1681,7 +1680,6 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_create(const TextureFormat &p } texture.bound = false; - texture.owner = INVALID_ID; //create view @@ -1738,7 +1736,7 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_create(const TextureFormat &p if (err) { vmaDestroyImage(allocator, texture.image, texture.allocation); vmaFreeMemory(allocator, texture.allocation); - ERR_FAIL_V(INVALID_ID); + ERR_FAIL_V(RID()); } //barrier to set layout @@ -1762,7 +1760,7 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_create(const TextureFormat &p vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); } - ID id = texture_owner.make_id(texture); + RID id = texture_owner.make_rid(texture); if (p_data.size()) { @@ -1775,15 +1773,15 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_create(const TextureFormat &p return id; } -RenderingDevice::ID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, ID p_with_texture) { +RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID p_with_texture) { Texture *src_texture = texture_owner.getornull(p_with_texture); - ERR_FAIL_COND_V(!src_texture, INVALID_ID); + ERR_FAIL_COND_V(!src_texture, RID()); - if (src_texture->owner != INVALID_ID) { //ahh this is a share + if (src_texture->owner.is_valid()) { //ahh this is a share p_with_texture = src_texture->owner; src_texture = texture_owner.getornull(src_texture->owner); - ERR_FAIL_COND_V(!src_texture, INVALID_ID); //this is a bug + ERR_FAIL_COND_V(!src_texture, RID()); //this is a bug } //create view @@ -1815,7 +1813,7 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_create_shared(const TextureVi if (p_view.format_override == DATA_FORMAT_MAX) { image_view_create_info.format = vulkan_formats[texture.format]; } else { - ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID()); image_view_create_info.format = vulkan_formats[p_view.format_override]; } @@ -1848,24 +1846,24 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_create_shared(const TextureVi VkResult err = vkCreateImageView(device, &image_view_create_info, NULL, &texture.view); if (err) { - ERR_FAIL_V(INVALID_ID); + ERR_FAIL_V(RID()); } texture.owner = p_with_texture; - ID id = texture_owner.make_id(texture); + RID id = texture_owner.make_rid(texture); _add_dependency(id, p_with_texture); return id; } -Error RenderingDeviceVulkan::texture_update(ID p_texture, uint32_t p_mipmap, uint32_t p_layer, const PoolVector &p_data, bool p_sync_with_draw) { +Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_mipmap, uint32_t p_layer, const PoolVector &p_data, bool p_sync_with_draw) { _THREAD_SAFE_METHOD_ Texture *texture = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!texture, ERR_INVALID_PARAMETER); - if (texture->owner != INVALID_ID) { + if (texture->owner != RID()) { p_texture = texture->owner; texture = texture_owner.getornull(texture->owner); ERR_FAIL_COND_V(!texture, ERR_BUG); //this is a bug @@ -2300,14 +2298,14 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector &p_format) { +RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create(const Vector &p_format) { _THREAD_SAFE_METHOD_ FramebufferFormatKey key; key.attachments = p_format; - const Map::Element *E = framebuffer_format_cache.find(key); + const Map::Element *E = framebuffer_format_cache.find(key); if (E) { //exists, return return E->get(); @@ -2319,7 +2317,7 @@ RenderingDevice::ID RenderingDeviceVulkan::framebuffer_format_create(const Vecto if (render_pass == VK_NULL_HANDLE) { //was likely invalid return INVALID_ID; } - ID id = ID(framebuffer_format_cache.size()) | (ID(ID_TYPE_FRAMEBUFFER_FORMAT) << ID(ID_BASE_SHIFT)); + FramebufferFormatID id = FramebufferFormatID(framebuffer_format_cache.size()) | (FramebufferFormatID(ID_TYPE_FRAMEBUFFER_FORMAT) << FramebufferFormatID(ID_BASE_SHIFT)); E = framebuffer_format_cache.insert(key, id); FramebufferFormat fb_format; @@ -2334,7 +2332,7 @@ RenderingDevice::ID RenderingDeviceVulkan::framebuffer_format_create(const Vecto /**** RENDER TARGET ****/ /***********************/ -RenderingDevice::ID RenderingDeviceVulkan::framebuffer_create(const Vector &p_texture_attachments, ID p_format_check) { +RID RenderingDeviceVulkan::framebuffer_create(const Vector &p_texture_attachments, FramebufferFormatID p_format_check) { _THREAD_SAFE_METHOD_ @@ -2343,13 +2341,13 @@ RenderingDevice::ID RenderingDeviceVulkan::framebuffer_create(const Vector & for (int i = 0; i < p_texture_attachments.size(); i++) { Texture *texture = texture_owner.getornull(p_texture_attachments[i]); - ERR_FAIL_COND_V_MSG(!texture, INVALID_ID, "Texture index supplied for framebuffer (" + itos(i) + ") is not a valid texture."); + ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture index supplied for framebuffer (" + itos(i) + ") is not a valid texture."); if (i == 0) { size.width = texture->width; size.height = texture->height; } else { - ERR_FAIL_COND_V_MSG((uint32_t)size.width != texture->width || (uint32_t)size.height != texture->height, INVALID_ID, + ERR_FAIL_COND_V_MSG((uint32_t)size.width != texture->width || (uint32_t)size.height != texture->height, RID(), "All textures in a framebuffer should be the same size."); } @@ -2360,12 +2358,12 @@ RenderingDevice::ID RenderingDeviceVulkan::framebuffer_create(const Vector & attachments.push_back(af); } - ID format_id = framebuffer_format_create(attachments); + FramebufferFormatID format_id = framebuffer_format_create(attachments); if (format_id == INVALID_ID) { - return INVALID_ID; + return RID(); } - ERR_FAIL_COND_V_MSG(p_format_check != INVALID_ID && format_id != p_format_check, INVALID_ID, + ERR_FAIL_COND_V_MSG(p_format_check != INVALID_ID && format_id != p_format_check, RID(), "The format used to check this framebuffer differs from the intended framebuffer format."); Framebuffer framebuffer; @@ -2373,7 +2371,7 @@ RenderingDevice::ID RenderingDeviceVulkan::framebuffer_create(const Vector & framebuffer.texture_ids = p_texture_attachments; framebuffer.size = size; - ID id = framebuffer_owner.make_id(framebuffer); + RID id = framebuffer_owner.make_rid(framebuffer); for (int i = 0; i < p_texture_attachments.size(); i++) { _add_dependency(id, p_texture_attachments[i]); @@ -2382,7 +2380,7 @@ RenderingDevice::ID RenderingDeviceVulkan::framebuffer_create(const Vector & return id; } -RenderingDevice::ID RenderingDeviceVulkan::framebuffer_get_format(ID p_framebuffer) { +RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_get_format(RID p_framebuffer) { _THREAD_SAFE_METHOD_ @@ -2396,7 +2394,7 @@ RenderingDevice::ID RenderingDeviceVulkan::framebuffer_get_format(ID p_framebuff /**** SAMPLER ****/ /*****************/ -RenderingDevice::ID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) { +RID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) { _THREAD_SAFE_METHOD_ @@ -2408,11 +2406,11 @@ RenderingDevice::ID RenderingDeviceVulkan::sampler_create(const SamplerState &p_ sampler_create_info.minFilter = p_state.min_filter == SAMPLER_FILTER_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; sampler_create_info.mipmapMode = p_state.mip_filter == SAMPLER_FILTER_LINEAR ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST; - ERR_FAIL_INDEX_V(p_state.repeat_u, SAMPLER_REPEAT_MODE_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_state.repeat_u, SAMPLER_REPEAT_MODE_MAX, RID()); sampler_create_info.addressModeU = address_modes[p_state.repeat_u]; - ERR_FAIL_INDEX_V(p_state.repeat_v, SAMPLER_REPEAT_MODE_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_state.repeat_v, SAMPLER_REPEAT_MODE_MAX, RID()); sampler_create_info.addressModeV = address_modes[p_state.repeat_v]; - ERR_FAIL_INDEX_V(p_state.repeat_w, SAMPLER_REPEAT_MODE_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_state.repeat_w, SAMPLER_REPEAT_MODE_MAX, RID()); sampler_create_info.addressModeW = address_modes[p_state.repeat_w]; sampler_create_info.mipLodBias = p_state.lod_bias; @@ -2420,33 +2418,33 @@ RenderingDevice::ID RenderingDeviceVulkan::sampler_create(const SamplerState &p_ sampler_create_info.maxAnisotropy = p_state.anisotropy_max; sampler_create_info.compareEnable = p_state.enable_compare; - ERR_FAIL_INDEX_V(p_state.compare_op, COMPARE_OP_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_state.compare_op, COMPARE_OP_MAX, RID()); sampler_create_info.compareOp = compare_operators[p_state.compare_op]; sampler_create_info.minLod = p_state.min_lod; sampler_create_info.maxLod = p_state.max_lod; - ERR_FAIL_INDEX_V(p_state.border_color, SAMPLER_BORDER_COLOR_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_state.border_color, SAMPLER_BORDER_COLOR_MAX, RID()); sampler_create_info.borderColor = sampler_border_colors[p_state.border_color]; sampler_create_info.unnormalizedCoordinates = p_state.unnormalized_uvw; VkSampler sampler; VkResult res = vkCreateSampler(device, &sampler_create_info, NULL, &sampler); - ERR_FAIL_COND_V(res, INVALID_ID); + ERR_FAIL_COND_V(res, RID()); - return sampler_owner.make_id(sampler); + return sampler_owner.make_rid(sampler); } /**********************/ /**** VERTEX ARRAY ****/ /**********************/ -RenderingDevice::ID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const PoolVector &p_data) { +RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const PoolVector &p_data) { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, INVALID_ID); + ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); Buffer buffer; _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); @@ -2455,95 +2453,95 @@ RenderingDevice::ID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_ PoolVector::Read r = p_data.read(); _buffer_update(&buffer, 0, r.ptr(), data_size); } - return vertex_buffer_owner.make_id(buffer); + return vertex_buffer_owner.make_rid(buffer); } // Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated -RenderingDevice::ID RenderingDeviceVulkan::vertex_description_create(const Vector &p_vertex_descriptions) { +RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(const Vector &p_vertex_formats) { _THREAD_SAFE_METHOD_ VertexDescriptionKey key; - key.vertex_descriptions = p_vertex_descriptions; - const Map::Element *E = vertex_description_cache.find(key); + key.vertex_formats = p_vertex_formats; + const Map::Element *E = vertex_format_cache.find(key); if (E) { return E->get(); } //does not exist, create one and cache it VertexDescriptionCache vdcache; - vdcache.bindings = memnew_arr(VkVertexInputBindingDescription, p_vertex_descriptions.size()); - vdcache.attributes = memnew_arr(VkVertexInputAttributeDescription, p_vertex_descriptions.size()); + vdcache.bindings = memnew_arr(VkVertexInputBindingDescription, p_vertex_formats.size()); + vdcache.attributes = memnew_arr(VkVertexInputAttributeDescription, p_vertex_formats.size()); Set used_locations; - for (int i = 0; i < p_vertex_descriptions.size(); i++) { - ERR_CONTINUE(p_vertex_descriptions[i].format >= DATA_FORMAT_MAX); - ERR_FAIL_COND_V(used_locations.has(p_vertex_descriptions[i].location), INVALID_ID); + for (int i = 0; i < p_vertex_formats.size(); i++) { + ERR_CONTINUE(p_vertex_formats[i].format >= DATA_FORMAT_MAX); + ERR_FAIL_COND_V(used_locations.has(p_vertex_formats[i].location), INVALID_ID); - ERR_FAIL_COND_V_MSG(get_format_vertex_size(p_vertex_descriptions[i].format) == 0, INVALID_ID, + ERR_FAIL_COND_V_MSG(get_format_vertex_size(p_vertex_formats[i].format) == 0, INVALID_ID, "Data format for attachment (" + itos(i) + ") is not valid for a vertex array."); vdcache.bindings[i].binding = i; - vdcache.bindings[i].stride = p_vertex_descriptions[i].stride; - vdcache.bindings[i].inputRate = p_vertex_descriptions[i].frequency == VERTEX_FREQUENCY_INSTANCE ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; + vdcache.bindings[i].stride = p_vertex_formats[i].stride; + vdcache.bindings[i].inputRate = p_vertex_formats[i].frequency == VERTEX_FREQUENCY_INSTANCE ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; vdcache.attributes[i].binding = i; - vdcache.attributes[i].location = p_vertex_descriptions[i].location; - vdcache.attributes[i].format = vulkan_formats[p_vertex_descriptions[i].format]; - vdcache.attributes[i].offset = p_vertex_descriptions[i].offset; - used_locations.insert(p_vertex_descriptions[i].location); + vdcache.attributes[i].location = p_vertex_formats[i].location; + vdcache.attributes[i].format = vulkan_formats[p_vertex_formats[i].format]; + vdcache.attributes[i].offset = p_vertex_formats[i].offset; + used_locations.insert(p_vertex_formats[i].location); } vdcache.create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vdcache.create_info.pNext = NULL; vdcache.create_info.flags = 0; - vdcache.create_info.vertexAttributeDescriptionCount = p_vertex_descriptions.size(); + vdcache.create_info.vertexAttributeDescriptionCount = p_vertex_formats.size(); vdcache.create_info.pVertexAttributeDescriptions = vdcache.attributes; - vdcache.create_info.vertexBindingDescriptionCount = p_vertex_descriptions.size(); + vdcache.create_info.vertexBindingDescriptionCount = p_vertex_formats.size(); vdcache.create_info.pVertexBindingDescriptions = vdcache.bindings; - ID id = ID(vertex_description_cache.size()) | (ID(ID_TYPE_VERTEX_DESCRIPTION) << ID_BASE_SHIFT); - vdcache.E = vertex_description_cache.insert(key, id); - vertex_descriptions[id] = vdcache; + VertexFormatID id = VertexFormatID(vertex_format_cache.size()) | (VertexFormatID(ID_TYPE_VERTEX_FORMAT) << ID_BASE_SHIFT); + vdcache.E = vertex_format_cache.insert(key, id); + vertex_formats[id] = vdcache; return id; } -RenderingDevice::ID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, ID p_vertex_description, const Vector &p_src_buffers) { +RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector &p_src_buffers) { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND_V(!vertex_descriptions.has(p_vertex_description), INVALID_ID); - const VertexDescriptionCache &vd = vertex_descriptions[p_vertex_description]; + ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID()); + const VertexDescriptionCache &vd = vertex_formats[p_vertex_format]; - ERR_FAIL_COND_V(vd.E->key().vertex_descriptions.size() != p_src_buffers.size(), INVALID_ID); + ERR_FAIL_COND_V(vd.E->key().vertex_formats.size() != p_src_buffers.size(), RID()); for (int i = 0; i < p_src_buffers.size(); i++) { - ERR_FAIL_COND_V(!vertex_buffer_owner.owns(p_src_buffers[i]), INVALID_ID); + ERR_FAIL_COND_V(!vertex_buffer_owner.owns(p_src_buffers[i]), RID()); } VertexArray vertex_array; vertex_array.vertex_count = p_vertex_count; - vertex_array.description = p_vertex_description; + vertex_array.description = p_vertex_format; vertex_array.max_instances_allowed = 0xFFFFFFFF; //by default as many as you want for (int i = 0; i < p_src_buffers.size(); i++) { Buffer *buffer = vertex_buffer_owner.getornull(p_src_buffers[i]); //validate with buffer { - const VertexDescription &atf = vd.E->key().vertex_descriptions[i]; + const VertexDescription &atf = vd.E->key().vertex_formats[i]; uint32_t element_size = get_format_vertex_size(atf.format); - ERR_FAIL_COND_V(element_size == 0, INVALID_ID); //should never happens since this was prevalidated + ERR_FAIL_COND_V(element_size == 0, RID()); //should never happens since this was prevalidated if (atf.frequency == VERTEX_FREQUENCY_VERTEX) { //validate size for regular drawing uint64_t total_size = uint64_t(atf.stride) * (p_vertex_count - 1) + atf.offset + element_size; - ERR_FAIL_COND_V_MSG(total_size > buffer->size, INVALID_ID, + ERR_FAIL_COND_V_MSG(total_size > buffer->size, RID(), "Attachment (" + itos(i) + ") will read past the end of the buffer."); } else { //validate size for instances drawing uint64_t available = buffer->size - atf.offset; - ERR_FAIL_COND_V_MSG(available < element_size, INVALID_ID, + ERR_FAIL_COND_V_MSG(available < element_size, RID(), "Attachment (" + itos(i) + ") uses instancing, but it's just too small."); uint32_t instances_allowed = available / atf.stride; @@ -2555,7 +2553,7 @@ RenderingDevice::ID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex vertex_array.offsets.push_back(0); //offset unused, but passing anyway } - ID id = vertex_array_owner.make_id(vertex_array); + RID id = vertex_array_owner.make_rid(vertex_array); for (int i = 0; i < p_src_buffers.size(); i++) { _add_dependency(id, p_src_buffers[i]); } @@ -2563,11 +2561,11 @@ RenderingDevice::ID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex return id; } -RenderingDevice::ID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBufferFormat p_format, const PoolVector &p_data, bool p_use_restart_indices) { +RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBufferFormat p_format, const PoolVector &p_data, bool p_use_restart_indices) { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND_V(p_index_count == 0, INVALID_ID); + ERR_FAIL_COND_V(p_index_count == 0, RID()); IndexBuffer index_buffer; index_buffer.index_type = (p_format == INDEX_BUFFER_FORMAT_UINT16) ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32; @@ -2577,7 +2575,7 @@ RenderingDevice::ID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_ #ifdef DEBUG_ENABLED if (p_data.size()) { index_buffer.max_index = 0; - ERR_FAIL_COND_V_MSG((uint32_t)p_data.size() != size_bytes, INVALID_ID, + ERR_FAIL_COND_V_MSG((uint32_t)p_data.size() != size_bytes, RID(), "Default index buffer initializer array size (" + itos(p_data.size()) + ") does not match format required size (" + itos(size_bytes) + ")."); PoolVector::Read r = p_data.read(); if (p_format == INDEX_BUFFER_FORMAT_UINT16) { @@ -2609,19 +2607,19 @@ RenderingDevice::ID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_ PoolVector::Read r = p_data.read(); _buffer_update(&index_buffer, 0, r.ptr(), data_size); } - return index_buffer_owner.make_id(index_buffer); + return index_buffer_owner.make_rid(index_buffer); } -RenderingDevice::ID RenderingDeviceVulkan::index_array_create(ID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) { +RID RenderingDeviceVulkan::index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND_V(!index_buffer_owner.owns(p_index_buffer), INVALID_ID); + ERR_FAIL_COND_V(!index_buffer_owner.owns(p_index_buffer), RID()); IndexBuffer *index_buffer = index_buffer_owner.getornull(p_index_buffer); - ERR_FAIL_COND_V(p_index_count == 0, INVALID_ID); - ERR_FAIL_COND_V(p_index_offset + p_index_count > index_buffer->index_count, INVALID_ID); + ERR_FAIL_COND_V(p_index_count == 0, RID()); + ERR_FAIL_COND_V(p_index_offset + p_index_count > index_buffer->index_count, RID()); IndexArray index_array; index_array.max_index = index_buffer->max_index; @@ -2631,7 +2629,7 @@ RenderingDevice::ID RenderingDeviceVulkan::index_array_create(ID p_index_buffer, index_array.index_type = index_buffer->index_type; index_array.supports_restart_indices = index_buffer->supports_restart_indices; - ID id = index_array_owner.make_id(index_array); + RID id = index_array_owner.make_rid(index_array); _add_dependency(id, p_index_buffer); return id; } @@ -2942,7 +2940,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector &p_stages, String *r_error, bool p_allow_cache) { +RID RenderingDeviceVulkan::shader_create_from_source(const Vector &p_stages, String *r_error, bool p_allow_cache) { _THREAD_SAFE_METHOD_ @@ -2983,7 +2981,7 @@ RenderingDevice::ID RenderingDeviceVulkan::shader_create_from_source(const Vecto if (r_error) { (*r_error) = "Stage " + String(shader_stage_names[p_stages[i].shader_stage]) + " submitted more than once."; } - return false; + return RID(); } glslang::TShader shader(stages[p_stages[i].shader_stage]); CharString cs = p_stages[i].shader_source.utf8(); @@ -3007,7 +3005,7 @@ RenderingDevice::ID RenderingDeviceVulkan::shader_create_from_source(const Vecto (*r_error) += shader.getInfoDebugLog(); } - return INVALID_ID; + return RID(); } //set back.. cs_strings = pre_processed_code.c_str(); @@ -3021,7 +3019,7 @@ RenderingDevice::ID RenderingDeviceVulkan::shader_create_from_source(const Vecto (*r_error) += "\n"; (*r_error) += shader.getInfoDebugLog(); } - return INVALID_ID; + return RID(); } //link @@ -3035,7 +3033,7 @@ RenderingDevice::ID RenderingDeviceVulkan::shader_create_from_source(const Vecto (*r_error) += "\n"; (*r_error) += program.getInfoDebugLog(); } - return INVALID_ID; + return RID(); } //obtain bindings for descriptor layout @@ -3045,25 +3043,25 @@ RenderingDevice::ID RenderingDeviceVulkan::shader_create_from_source(const Vecto for (int j = 0; j < program.getNumUniformVariables(); j++) { if (!_uniform_add_binding(bindings, uniform_info, program.getUniform(j), p_stages[i].shader_stage, push_constant, r_error)) { - return INVALID_ID; + return RID(); } } for (int j = 0; j < program.getNumUniformBlocks(); j++) { if (!_uniform_add_binding(bindings, uniform_info, program.getUniformBlock(j), p_stages[i].shader_stage, push_constant, r_error)) { - return INVALID_ID; + return RID(); } } for (int j = 0; j < program.getNumBufferVariables(); j++) { if (!_uniform_add_binding(bindings, uniform_info, program.getBufferVariable(j), p_stages[i].shader_stage, push_constant, r_error)) { - return INVALID_ID; + return RID(); } } for (int j = 0; j < program.getNumBufferBlocks(); j++) { if (!_uniform_add_binding(bindings, uniform_info, program.getBufferBlock(j), p_stages[i].shader_stage, push_constant, r_error)) { - return INVALID_ID; + return RID(); } } @@ -3227,64 +3225,64 @@ RenderingDevice::ID RenderingDeviceVulkan::shader_create_from_source(const Vecto vkDestroyDescriptorSetLayout(device, shader.sets[i].descriptor_set_layout, NULL); } - return INVALID_ID; + return RID(); } - return shader_owner.make_id(shader); + return shader_owner.make_rid(shader); } /******************/ /**** UNIFORMS ****/ /******************/ -RenderingDevice::ID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const PoolVector &p_data) { +RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const PoolVector &p_data) { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, INVALID_ID); + ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); Buffer buffer; Error err = _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); - ERR_FAIL_COND_V(err != OK, INVALID_ID); + ERR_FAIL_COND_V(err != OK, RID()); if (p_data.size()) { uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); _buffer_update(&buffer, 0, r.ptr(), data_size); } - return uniform_buffer_owner.make_id(buffer); + return uniform_buffer_owner.make_rid(buffer); } -RenderingDevice::ID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const PoolVector &p_data) { +RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const PoolVector &p_data) { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, INVALID_ID); + ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); Buffer buffer; Error err = _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); - ERR_FAIL_COND_V(err != OK, INVALID_ID); + ERR_FAIL_COND_V(err != OK, RID()); if (p_data.size()) { uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); _buffer_update(&buffer, 0, r.ptr(), data_size); } - return storage_buffer_owner.make_id(buffer); + return storage_buffer_owner.make_rid(buffer); } -RenderingDevice::ID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const PoolVector &p_data) { +RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataFormat p_format, const PoolVector &p_data) { _THREAD_SAFE_METHOD_ uint32_t element_size = get_format_vertex_size(p_format); - ERR_FAIL_COND_V_MSG(element_size == 0, INVALID_ID, "Format requested is not supported for texture buffers"); + ERR_FAIL_COND_V_MSG(element_size == 0, RID(), "Format requested is not supported for texture buffers"); uint64_t size_bytes = uint64_t(element_size) * p_size_elements; - ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != size_bytes, INVALID_ID); + ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != size_bytes, RID()); TextureBuffer texture_buffer; Error err = _buffer_allocate(&texture_buffer.buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); - ERR_FAIL_COND_V(err != OK, INVALID_ID); + ERR_FAIL_COND_V(err != OK, RID()); if (p_data.size()) { uint64_t data_size = p_data.size(); @@ -3306,11 +3304,11 @@ RenderingDevice::ID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size VkResult res = vkCreateBufferView(device, &view_create_info, NULL, &texture_buffer.view); if (res) { _buffer_free(&texture_buffer.buffer); - ERR_FAIL_V_MSG(INVALID_ID, "Unable to create buffer view"); + ERR_FAIL_V_MSG(RID(), "Unable to create buffer view"); } //allocate the view - return texture_buffer_owner.make_id(texture_buffer); + return texture_buffer_owner.make_rid(texture_buffer); } RenderingDeviceVulkan::DescriptorPool *RenderingDeviceVulkan::_descriptor_pool_allocate(const DescriptorPoolKey &p_key) { @@ -3422,16 +3420,16 @@ void RenderingDeviceVulkan::_descriptor_pool_free(const DescriptorPoolKey &p_key } } -RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, ID p_shader, uint32_t p_shader_set) { +RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, RID p_shader, uint32_t p_shader_set) { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND_V(p_uniforms.size() == 0, INVALID_ID); + ERR_FAIL_COND_V(p_uniforms.size() == 0, RID()); Shader *shader = shader_owner.getornull(p_shader); - ERR_FAIL_COND_V(!shader, INVALID_ID); + ERR_FAIL_COND_V(!shader, RID()); - ERR_FAIL_COND_V_MSG(p_shader_set >= (uint32_t)shader->sets.size() || shader->sets[p_shader_set].uniform_info.size() == 0, INVALID_ID, + ERR_FAIL_COND_V_MSG(p_shader_set >= (uint32_t)shader->sets.size() || shader->sets[p_shader_set].uniform_info.size() == 0, RID(), "Desired set (" + itos(p_shader_set) + ") not used by shader."); //see that all sets in shader are satisfied @@ -3454,7 +3452,7 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vector > buffer_views; List > image_infos; //used for verification to make sure a uniform set does not use a framebuffer bound texture - Vector attachable_textures; + Vector attachable_textures; for (uint32_t i = 0; i < set_uniform_count; i++) { const Shader::UniformInfo &set_uniform = set_uniforms[i]; @@ -3464,12 +3462,12 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vector 1) { - ERR_FAIL_V_MSG(INVALID_ID, "Sampler (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler elements, so it should be provided equal number of sampler IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler elements, so it should be provided equal number of sampler IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); } else { - ERR_FAIL_V_MSG(INVALID_ID, "Sampler (binding: " + itos(uniform.binding) + ") should provide one ID referencing a sampler (IDs provided: " + itos(uniform.ids.size()) + ")."); + ERR_FAIL_V_MSG(RID(), "Sampler (binding: " + itos(uniform.binding) + ") should provide one ID referencing a sampler (IDs provided: " + itos(uniform.ids.size()) + ")."); } } @@ -3493,7 +3491,7 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vector 1) { - ERR_FAIL_V_MSG(INVALID_ID, "SamplerTexture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler&texture elements, so it should provided twice the amount of IDs (sampler,texture pairs) to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + ERR_FAIL_V_MSG(RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler&texture elements, so it should provided twice the amount of IDs (sampler,texture pairs) to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); } else { - ERR_FAIL_V_MSG(INVALID_ID, "SamplerTexture (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture (IDs provided: " + itos(uniform.ids.size()) + ")."); + ERR_FAIL_V_MSG(RID(), "SamplerTexture (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture (IDs provided: " + itos(uniform.ids.size()) + ")."); } } @@ -3527,12 +3525,12 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vectorusage_flags & TEXTURE_USAGE_SAMPLING_BIT), INVALID_ID, + ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform."); VkDescriptorImageInfo img_info; @@ -3540,12 +3538,12 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vectorview; if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)) { - attachable_textures.push_back(texture->owner != INVALID_ID ? texture->owner : uniform.ids[j + 1]); + attachable_textures.push_back(texture->owner.is_valid() ? texture->owner : uniform.ids[j + 1]); } - if (texture->owner != INVALID_ID) { + if (texture->owner.is_valid()) { texture = texture_owner.getornull(texture->owner); - ERR_FAIL_COND_V(!texture, INVALID_ID); //bug, should never happen + ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen } img_info.imageLayout = texture->unbound_layout; @@ -3567,9 +3565,9 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vector 1) { - ERR_FAIL_V_MSG(INVALID_ID, "Texture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + ERR_FAIL_V_MSG(RID(), "Texture (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); } else { - ERR_FAIL_V_MSG(INVALID_ID, "Texture (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.ids.size()) + ")."); + ERR_FAIL_V_MSG(RID(), "Texture (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.ids.size()) + ")."); } } @@ -3577,9 +3575,9 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vectorusage_flags & TEXTURE_USAGE_SAMPLING_BIT), INVALID_ID, + ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform."); VkDescriptorImageInfo img_info; @@ -3587,12 +3585,12 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vectorview; if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)) { - attachable_textures.push_back(texture->owner != INVALID_ID ? texture->owner : uniform.ids[j]); + attachable_textures.push_back(texture->owner.is_valid() ? texture->owner : uniform.ids[j]); } - if (texture->owner != INVALID_ID) { + if (texture->owner.is_valid()) { texture = texture_owner.getornull(texture->owner); - ERR_FAIL_COND_V(!texture, INVALID_ID); //bug, should never happen + ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen } img_info.imageLayout = texture->unbound_layout; @@ -3615,9 +3613,9 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vector 1) { - ERR_FAIL_V_MSG(INVALID_ID, "Buffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") texture buffer elements, so it should be provided equal number of texture buffer IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") texture buffer elements, so it should be provided equal number of texture buffer IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); } else { - ERR_FAIL_V_MSG(INVALID_ID, "Buffer (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture buffer (IDs provided: " + itos(uniform.ids.size()) + ")."); + ERR_FAIL_V_MSG(RID(), "Buffer (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture buffer (IDs provided: " + itos(uniform.ids.size()) + ")."); } } @@ -3626,7 +3624,7 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vectorbuffer.buffer_info); buffer_view.push_back(buffer->view); @@ -3646,9 +3644,9 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vector 1) { - ERR_FAIL_V_MSG(INVALID_ID, "SamplerBuffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler buffer elements, so it should provided twice the amount of IDs (sampler,buffer pairs) to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + ERR_FAIL_V_MSG(RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") sampler buffer elements, so it should provided twice the amount of IDs (sampler,buffer pairs) to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); } else { - ERR_FAIL_V_MSG(INVALID_ID, "SamplerBuffer (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture buffer (IDs provided: " + itos(uniform.ids.size()) + ")."); + ERR_FAIL_V_MSG(RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ") should provide two IDs referencing a sampler and then a texture buffer (IDs provided: " + itos(uniform.ids.size()) + ")."); } } @@ -3658,7 +3656,7 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vectorbuffer.buffer_info); buffer_view.push_back(buffer->view); @@ -3689,13 +3687,13 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vectorsize != (uint32_t)set_uniform.length, INVALID_ID, + ERR_FAIL_COND_V_MSG(buffer->size != (uint32_t)set_uniform.length, RID(), "Uniform buffer (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ")."); write.dstArrayElement = 0; @@ -3707,13 +3705,13 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vectorsize != (uint32_t)set_uniform.length, INVALID_ID, + ERR_FAIL_COND_V_MSG(buffer->size != (uint32_t)set_uniform.length, RID(), "Storage buffer (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ")."); write.dstArrayElement = 0; @@ -3732,7 +3730,7 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vectorset_hashes[p_shader_set]; uniform_set.attachable_textures = attachable_textures; - ID id = uniform_set_owner.make_id(uniform_set); + RID id = uniform_set_owner.make_rid(uniform_set); //add dependencies _add_dependency(id, p_shader); for (uint32_t i = 0; i < uniform_count; i++) { const Uniform &uniform = uniforms[i]; int id_count = uniform.ids.size(); - const ID *ids = uniform.ids.ptr(); + const RID *ids = uniform.ids.ptr(); for (int j = 0; j < id_count; j++) { _add_dependency(id, ids[j]); } @@ -3789,7 +3787,7 @@ RenderingDevice::ID RenderingDeviceVulkan::uniform_set_create(const Vector()); } - ERR_FAIL_COND_V(!framebuffer_formats.has(p_framebuffer_format), INVALID_ID); + ERR_FAIL_COND_V(!framebuffer_formats.has(p_framebuffer_format), RID()); const FramebufferFormat &fb_format = framebuffer_formats[p_framebuffer_format]; { //validate shader vs framebuffer - ERR_FAIL_COND_V_MSG(shader->fragment_outputs != fb_format.color_attachments, INVALID_ID, + ERR_FAIL_COND_V_MSG(shader->fragment_outputs != fb_format.color_attachments, RID(), "Mismatch fragment output bindings (" + itos(shader->fragment_outputs) + ") and framebuffer color buffers (" + itos(fb_format.color_attachments) + ") when binding both in render pipeline."); } //vertex VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_state_create_info; - if (p_vertex_description != INVALID_ID) { + if (p_vertex_format != INVALID_ID) { //uses vertices, else it does not - ERR_FAIL_COND_V(!vertex_descriptions.has(p_vertex_description), INVALID_ID); - VertexDescriptionCache &vd = vertex_descriptions[p_vertex_description]; + ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID()); + VertexDescriptionCache &vd = vertex_formats[p_vertex_format]; pipeline_vertex_input_state_create_info = vd.create_info; @@ -3852,13 +3850,13 @@ RenderingDevice::ID RenderingDeviceVulkan::render_pipeline_create(ID p_shader, I uint32_t location = shader->vertex_input_locations[i]; const VertexDescriptionKey &k = vd.E->key(); bool found = false; - for (int j = 0; j < k.vertex_descriptions.size(); j++) { - if (k.vertex_descriptions[j].location == location) { + for (int j = 0; j < k.vertex_formats.size(); j++) { + if (k.vertex_formats[j].location == location) { found = true; } } - ERR_FAIL_COND_V_MSG(!found, INVALID_ID, + ERR_FAIL_COND_V_MSG(!found, RID(), "Shader vertex input location (" + itos(location) + ") not provided in vertex input description for pipeline creation."); } @@ -3872,12 +3870,12 @@ RenderingDevice::ID RenderingDeviceVulkan::render_pipeline_create(ID p_shader, I pipeline_vertex_input_state_create_info.vertexAttributeDescriptionCount = 0; pipeline_vertex_input_state_create_info.pVertexAttributeDescriptions = NULL; - ERR_FAIL_COND_V_MSG(shader->vertex_input_locations.size(), INVALID_ID, + ERR_FAIL_COND_V_MSG(shader->vertex_input_locations.size(), RID(), "Shader contains vertex inputs (" + itos(shader->vertex_input_locations.size()) + ") but no vertex input description was provided for pipeline creation."); } //input assembly - ERR_FAIL_INDEX_V(p_render_primitive, RENDER_PRIMITIVE_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_render_primitive, RENDER_PRIMITIVE_MAX, RID()); VkPipelineInputAssemblyStateCreateInfo input_assembly_create_info; input_assembly_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; @@ -3906,7 +3904,7 @@ RenderingDevice::ID RenderingDeviceVulkan::render_pipeline_create(ID p_shader, I tesselation_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; tesselation_create_info.pNext = NULL; tesselation_create_info.flags = 0; - ERR_FAIL_COND_V(p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > limits.maxTessellationPatchSize, INVALID_ID); + ERR_FAIL_COND_V(p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > limits.maxTessellationPatchSize, RID()); tesselation_create_info.patchControlPoints = p_rasterization_state.patch_control_points; VkPipelineViewportStateCreateInfo viewport_state_create_info; @@ -3932,7 +3930,7 @@ RenderingDevice::ID RenderingDeviceVulkan::render_pipeline_create(ID p_shader, I VK_CULL_MODE_BACK_BIT }; - ERR_FAIL_INDEX_V(p_rasterization_state.cull_mode, 3, INVALID_ID); + ERR_FAIL_INDEX_V(p_rasterization_state.cull_mode, 3, RID()); rasterization_state_create_info.cullMode = cull_mode[p_rasterization_state.cull_mode]; rasterization_state_create_info.frontFace = (p_rasterization_state.front_face == POLYGON_FRONT_FACE_CLOCKWISE ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE); rasterization_state_create_info.depthBiasEnable = p_rasterization_state.depth_bias_enable; @@ -3956,7 +3954,7 @@ RenderingDevice::ID RenderingDeviceVulkan::render_pipeline_create(ID p_shader, I int rasterization_sample_mask_expected_size[TEXTURE_SAMPLES_MAX] = { 1, 2, 4, 8, 16, 32, 64 }; - ERR_FAIL_COND_V(rasterization_sample_mask_expected_size[p_multisample_state.sample_count] != p_multisample_state.sample_mask.size(), INVALID_ID); + ERR_FAIL_COND_V(rasterization_sample_mask_expected_size[p_multisample_state.sample_count] != p_multisample_state.sample_mask.size(), RID()); sample_mask.resize(p_multisample_state.sample_mask.size()); for (int i = 0; i < p_multisample_state.sample_mask.size(); i++) { VkSampleMask mask = p_multisample_state.sample_mask[i]; @@ -3978,30 +3976,30 @@ RenderingDevice::ID RenderingDeviceVulkan::render_pipeline_create(ID p_shader, I depth_stencil_state_create_info.flags = 0; depth_stencil_state_create_info.depthTestEnable = p_depth_stencil_state.enable_depth_test; depth_stencil_state_create_info.depthWriteEnable = p_depth_stencil_state.enable_depth_write; - ERR_FAIL_INDEX_V(p_depth_stencil_state.depth_compare_operator, COMPARE_OP_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_depth_stencil_state.depth_compare_operator, COMPARE_OP_MAX, RID()); depth_stencil_state_create_info.depthCompareOp = compare_operators[p_depth_stencil_state.depth_compare_operator]; depth_stencil_state_create_info.depthBoundsTestEnable = p_depth_stencil_state.enable_depth_range; depth_stencil_state_create_info.stencilTestEnable = p_depth_stencil_state.enable_stencil; - ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.fail, STENCIL_OP_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.fail, STENCIL_OP_MAX, RID()); depth_stencil_state_create_info.front.failOp = stencil_operations[p_depth_stencil_state.stencil_operation_front.fail]; - ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.pass, STENCIL_OP_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.pass, STENCIL_OP_MAX, RID()); depth_stencil_state_create_info.front.passOp = stencil_operations[p_depth_stencil_state.stencil_operation_front.pass]; - ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.depth_fail, STENCIL_OP_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.depth_fail, STENCIL_OP_MAX, RID()); depth_stencil_state_create_info.front.depthFailOp = stencil_operations[p_depth_stencil_state.stencil_operation_front.depth_fail]; - ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.compare, COMPARE_OP_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_front.compare, COMPARE_OP_MAX, RID()); depth_stencil_state_create_info.front.compareOp = compare_operators[p_depth_stencil_state.stencil_operation_front.compare]; depth_stencil_state_create_info.front.compareMask = p_depth_stencil_state.stencil_operation_front.compare_mask; depth_stencil_state_create_info.front.writeMask = p_depth_stencil_state.stencil_operation_front.write_mask; depth_stencil_state_create_info.front.reference = p_depth_stencil_state.stencil_operation_front.reference; - ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.fail, STENCIL_OP_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.fail, STENCIL_OP_MAX, RID()); depth_stencil_state_create_info.back.failOp = stencil_operations[p_depth_stencil_state.stencil_operation_back.fail]; - ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.pass, STENCIL_OP_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.pass, STENCIL_OP_MAX, RID()); depth_stencil_state_create_info.back.passOp = stencil_operations[p_depth_stencil_state.stencil_operation_back.pass]; - ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.depth_fail, STENCIL_OP_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.depth_fail, STENCIL_OP_MAX, RID()); depth_stencil_state_create_info.back.depthFailOp = stencil_operations[p_depth_stencil_state.stencil_operation_back.depth_fail]; - ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.compare, COMPARE_OP_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_depth_stencil_state.stencil_operation_back.compare, COMPARE_OP_MAX, RID()); depth_stencil_state_create_info.back.compareOp = compare_operators[p_depth_stencil_state.stencil_operation_back.compare]; depth_stencil_state_create_info.back.compareMask = p_depth_stencil_state.stencil_operation_back.compare_mask; depth_stencil_state_create_info.back.writeMask = p_depth_stencil_state.stencil_operation_back.write_mask; @@ -4016,10 +4014,10 @@ RenderingDevice::ID RenderingDeviceVulkan::render_pipeline_create(ID p_shader, I color_blend_state_create_info.pNext = NULL; color_blend_state_create_info.flags = 0; color_blend_state_create_info.logicOpEnable = p_blend_state.enable_logic_op; - ERR_FAIL_INDEX_V(p_blend_state.logic_op, LOGIC_OP_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_blend_state.logic_op, LOGIC_OP_MAX, RID()); color_blend_state_create_info.logicOp = logic_operations[p_blend_state.logic_op]; - ERR_FAIL_COND_V(fb_format.color_attachments != p_blend_state.attachments.size(), INVALID_ID); + ERR_FAIL_COND_V(fb_format.color_attachments != p_blend_state.attachments.size(), RID()); Vector attachment_states; @@ -4027,18 +4025,18 @@ RenderingDevice::ID RenderingDeviceVulkan::render_pipeline_create(ID p_shader, I VkPipelineColorBlendAttachmentState state; state.blendEnable = p_blend_state.attachments[i].enable_blend; - ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_color_blend_factor, BLEND_FACTOR_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_color_blend_factor, BLEND_FACTOR_MAX, RID()); state.srcColorBlendFactor = blend_factors[p_blend_state.attachments[i].src_color_blend_factor]; - ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_color_blend_factor, BLEND_FACTOR_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_color_blend_factor, BLEND_FACTOR_MAX, RID()); state.dstColorBlendFactor = blend_factors[p_blend_state.attachments[i].dst_color_blend_factor]; - ERR_FAIL_INDEX_V(p_blend_state.attachments[i].color_blend_op, BLEND_OP_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].color_blend_op, BLEND_OP_MAX, RID()); state.colorBlendOp = blend_operations[p_blend_state.attachments[i].color_blend_op]; - ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_alpha_blend_factor, BLEND_FACTOR_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_alpha_blend_factor, BLEND_FACTOR_MAX, RID()); state.srcAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].src_alpha_blend_factor]; - ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_alpha_blend_factor, BLEND_FACTOR_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_alpha_blend_factor, BLEND_FACTOR_MAX, RID()); state.dstAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].dst_alpha_blend_factor]; - ERR_FAIL_INDEX_V(p_blend_state.attachments[i].alpha_blend_op, BLEND_OP_MAX, INVALID_ID); + ERR_FAIL_INDEX_V(p_blend_state.attachments[i].alpha_blend_op, BLEND_OP_MAX, RID()); state.alphaBlendOp = blend_operations[p_blend_state.attachments[i].alpha_blend_op]; state.colorWriteMask = 0; @@ -4134,11 +4132,11 @@ RenderingDevice::ID RenderingDeviceVulkan::render_pipeline_create(ID p_shader, I RenderPipeline pipeline; VkResult err = vkCreateGraphicsPipelines(device, NULL, 1, &graphics_pipeline_create_info, NULL, &pipeline.pipeline); - ERR_FAIL_COND_V(err, INVALID_ID); + ERR_FAIL_COND_V(err, RID()); pipeline.dynamic_state = p_dynamic_state_flags; pipeline.framebuffer_format = p_framebuffer_format; - pipeline.vertex_format = p_vertex_description; + pipeline.vertex_format = p_vertex_format; pipeline.uses_restart_indices = input_assembly_create_info.primitiveRestartEnable; pipeline.set_hashes = shader->set_hashes; pipeline.push_constant_size = shader->push_constant.push_constant_size; @@ -4165,7 +4163,7 @@ RenderingDevice::ID RenderingDeviceVulkan::render_pipeline_create(ID p_shader, I pipeline.primitive_minimum = primitive_minimum[p_render_primitive]; //create ID to associate with this pipeline - ID id = pipeline_owner.make_id(pipeline); + RID id = pipeline_owner.make_rid(pipeline); //now add aall the dependencies _add_dependency(id, p_shader); return id; @@ -4185,7 +4183,7 @@ int RenderingDeviceVulkan::screen_get_height(int p_screen) const { return context->get_screen_height(p_screen); } -RenderingDevice::ID RenderingDeviceVulkan::screen_get_framebuffer_format() const { +RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::screen_get_framebuffer_format() const { _THREAD_SAFE_METHOD_ @@ -4214,7 +4212,7 @@ RenderingDevice::ID RenderingDeviceVulkan::screen_get_framebuffer_format() const /**** DRAW LIST ****/ /*******************/ -RenderingDevice::ID RenderingDeviceVulkan::draw_list_begin_for_screen(int p_screen, const Color &p_clear_color) { +RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(int p_screen, const Color &p_clear_color) { _THREAD_SAFE_METHOD_ @@ -4371,7 +4369,7 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff return OK; } -RenderingDevice::ID RenderingDeviceVulkan::draw_list_begin(ID p_framebuffer, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors, const Rect2 &p_region) { +RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebuffer, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors, const Rect2 &p_region) { _THREAD_SAFE_METHOD_ @@ -4441,7 +4439,7 @@ RenderingDevice::ID RenderingDeviceVulkan::draw_list_begin(ID p_framebuffer, Ini return ID_TYPE_DRAW_LIST; } -Error RenderingDeviceVulkan::draw_list_begin_split(ID p_framebuffer, uint32_t p_splits, ID *r_split_ids, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors, const Rect2 &p_region) { +Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors, const Rect2 &p_region) { _THREAD_SAFE_METHOD_ @@ -4579,13 +4577,13 @@ Error RenderingDeviceVulkan::draw_list_begin_split(ID p_framebuffer, uint32_t p_ scissor.extent.height = viewport_size.height; vkCmdSetScissor(command_buffer, 0, 1, &scissor); - r_split_ids[i] = (ID(1) << ID(ID_TYPE_SPLIT_DRAW_LIST)) + i; + r_split_ids[i] = (DrawListID(1) << DrawListID(ID_TYPE_SPLIT_DRAW_LIST)) + i; } return OK; } -RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(ID p_id) { +RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(DrawListID p_id) { if (p_id < 0) { return NULL; } @@ -4597,12 +4595,12 @@ RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(ID p_ return NULL; } return draw_list; - } else if (p_id >> ID(ID_BASE_SHIFT) == ID_TYPE_SPLIT_DRAW_LIST) { + } else if (p_id >> DrawListID(ID_BASE_SHIFT) == ID_TYPE_SPLIT_DRAW_LIST) { if (!draw_list_split) { return NULL; } - uint64_t index = p_id & ((ID(1) << ID(ID_BASE_SHIFT)) - 1); //mask + uint64_t index = p_id & ((DrawListID(1) << DrawListID(ID_BASE_SHIFT)) - 1); //mask if (index >= draw_list_count) { return NULL; @@ -4614,7 +4612,7 @@ RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(ID p_ } } -void RenderingDeviceVulkan::draw_list_bind_render_pipeline(ID p_list, ID p_render_pipeline) { +void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); @@ -4644,7 +4642,7 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(ID p_list, ID p_rende } } -void RenderingDeviceVulkan::draw_list_bind_uniform_set(ID p_list, ID p_uniform_set, uint32_t p_index) { +void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) { ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets, "Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ")."); DrawList *dl = _get_draw_list_ptr(p_list); @@ -4656,7 +4654,7 @@ void RenderingDeviceVulkan::draw_list_bind_uniform_set(ID p_list, ID p_uniform_s if ((uint32_t)dl->validation.set_hashes.size() <= p_index) { uint32_t csize = dl->validation.set_hashes.size(); - uint32_t new_size = p_uniform_set + 1; + uint32_t new_size = p_index + 1; dl->validation.set_hashes.resize(new_size); for (uint32_t i = csize; i < new_size; i++) { dl->validation.set_hashes.write[i] = 0; @@ -4665,9 +4663,9 @@ void RenderingDeviceVulkan::draw_list_bind_uniform_set(ID p_list, ID p_uniform_s { //validate that textures bound are not attached as framebuffer bindings uint32_t attachable_count = uniform_set->attachable_textures.size(); - const ID *attachable_ptr = uniform_set->attachable_textures.ptr(); + const RID *attachable_ptr = uniform_set->attachable_textures.ptr(); uint32_t bound_count = draw_list_bound_textures.size(); - const ID *bound_ptr = draw_list_bound_textures.ptr(); + const RID *bound_ptr = draw_list_bound_textures.ptr(); for (uint32_t i = 0; i < attachable_count; i++) { for (uint32_t j = 0; j < bound_count; j++) { ERR_FAIL_COND_MSG(attachable_ptr[i] == bound_ptr[j], @@ -4681,7 +4679,7 @@ void RenderingDeviceVulkan::draw_list_bind_uniform_set(ID p_list, ID p_uniform_s vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, uniform_set->pipeline_layout, p_index, 1, &uniform_set->descriptor_set, 0, NULL); } -void RenderingDeviceVulkan::draw_list_bind_vertex_array(ID p_list, ID p_vertex_array) { +void RenderingDeviceVulkan::draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); @@ -4694,7 +4692,7 @@ void RenderingDeviceVulkan::draw_list_bind_vertex_array(ID p_list, ID p_vertex_a vkCmdBindVertexBuffers(dl->command_buffer, 0, vertex_array->buffers.size(), vertex_array->buffers.ptr(), vertex_array->offsets.ptr()); } -void RenderingDeviceVulkan::draw_list_bind_index_array(ID p_list, ID p_index_array) { +void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); @@ -4710,7 +4708,7 @@ void RenderingDeviceVulkan::draw_list_bind_index_array(ID p_list, ID p_index_arr vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, index_array->offset, index_array->index_type); } -void RenderingDeviceVulkan::draw_list_set_push_constant(ID p_list, void *p_data, uint32_t p_data_size) { +void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); @@ -4721,7 +4719,7 @@ void RenderingDeviceVulkan::draw_list_set_push_constant(ID p_list, void *p_data, dl->validation.pipeline_push_constant_suppplied = true; } -void RenderingDeviceVulkan::draw_list_draw(ID p_list, bool p_use_indices, uint32_t p_instances) { +void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); @@ -4806,9 +4804,9 @@ void RenderingDeviceVulkan::draw_list_draw(ID p_list, bool p_use_indices, uint32 } } -void RenderingDeviceVulkan::draw_list_enable_scissor(ID p_list, const Rect2 &p_rect) { +void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) { } -void RenderingDeviceVulkan::draw_list_disable_scissor(ID p_list) { +void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) { } void RenderingDeviceVulkan::draw_list_end() { @@ -4905,7 +4903,7 @@ void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_frame } #endif -void RenderingDeviceVulkan::_free_internal(ID p_id) { +void RenderingDeviceVulkan::_free_internal(RID p_id) { //push everything so it's disposed of next time this frame index is processed (means, it's safe to do it) if (texture_owner.owns(p_id)) { @@ -4961,10 +4959,10 @@ void RenderingDeviceVulkan::_free_internal(ID p_id) { frames[frame].pipelines_to_dispose_of.push_back(*pipeline); pipeline_owner.free(p_id); } else { - ERR_PRINT("Attempted to free invalid ID: " + itos(p_id)); + ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id())); } } -void RenderingDeviceVulkan::free(ID p_id) { +void RenderingDeviceVulkan::free(RID p_id) { _THREAD_SAFE_METHOD_ @@ -5067,7 +5065,7 @@ void RenderingDeviceVulkan::_free_pending_resources() { WARN_PRINT("Deleted a texture while it was bound.."); } vkDestroyImageView(device, texture->view, NULL); - if (texture->owner == INVALID_ID) { + if (texture->owner.is_null()) { //actually owns the image and the allocation too vmaDestroyImage(allocator, texture->image, texture->allocation); vmaFreeMemory(allocator, texture->allocation); -- cgit v1.2.3 From 836c2109a0b1371653e3c82100199dfdabd47da9 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Tue, 11 Jun 2019 17:21:39 -0300 Subject: Changed my mind on Vulkan image API, images should now include mipmaps This should make it easier to obtain the data directly from an Image --- drivers/vulkan/rendering_device_vulkan.cpp | 202 +++++++++++++++-------------- 1 file changed, 102 insertions(+), 100 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 6466c8a19b..7e9d40df19 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1010,7 +1010,7 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFor return 0; } -uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmap, uint32_t *r_blockw, uint32_t *r_blockh) { +uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh) { uint32_t w = p_width; uint32_t h = p_height; @@ -1023,7 +1023,7 @@ uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_form uint32_t blockw, blockh; get_compressed_image_format_block_dimensions(p_format, blockw, blockh); - for (uint32_t i = 0; i <= p_mipmap; i++) { + for (uint32_t i = 0; i <= p_mipmaps; i++) { uint32_t bw = w % blockw != 0 ? w + (blockw - w % blockw) : w; uint32_t bh = h % blockh != 0 ? h + (blockh - h % blockh) : h; @@ -1032,7 +1032,7 @@ uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_form s *= pixel_size; s >>= pixel_rshift; - size = s * d; + size += s * d; if (r_blockw) { *r_blockw = bw; } @@ -1565,19 +1565,14 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T ERR_FAIL_COND_V_MSG(!(p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT), RID(), "Texture needs the TEXTURE_USAGE_CAN_UPDATE_BIT usage flag in order to be updated at initialization or later"); - int expected_images = image_create_info.mipLevels * image_create_info.arrayLayers * array_layer_multiplier; + int expected_images = image_create_info.arrayLayers * array_layer_multiplier; ERR_FAIL_COND_V_MSG(p_data.size() != expected_images, RID(), "Default supplied data for image format is of invalid length (" + itos(p_data.size()) + "), should be (" + itos(expected_images) + ")."); - int idx = 0; for (uint32_t i = 0; i < image_create_info.arrayLayers * array_layer_multiplier; i++) { - for (uint32_t j = 0; j < image_create_info.mipLevels; j++) { - print_line("computed size from " + Vector3(image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth)); - uint32_t required_size = get_image_format_required_size(p_format.format, image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth, j); - ERR_FAIL_COND_V_MSG((uint32_t)p_data[idx].size() != required_size, RID(), - "Data for slice index " + itos(idx) + " (mapped to layer " + itos(i) + ", mipmap " + itos(j) + ") differs in size (supplied: " + itos(p_data[idx].size()) + ") than what is required by the format (" + itos(required_size) + ")."); - idx++; - } + uint32_t required_size = get_image_format_required_size(p_format.format, image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth, image_create_info.mipLevels); + ERR_FAIL_COND_V_MSG((uint32_t)p_data[i].size() != required_size, RID(), + "Data for slice index " + itos(i) + " (mapped to layer " + itos(i) + ") differs in size (supplied: " + itos(p_data[i].size()) + ") than what is required by the format (" + itos(required_size) + ")."); } } @@ -1765,9 +1760,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T if (p_data.size()) { for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) { - for (uint32_t j = 0; j < image_create_info.mipLevels; j++) { - texture_update(id, j, i, p_data[i * image_create_info.mipLevels + j], true); - } + texture_update(id, i, p_data[i], true); } } return id; @@ -1856,7 +1849,7 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID return id; } -Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_mipmap, uint32_t p_layer, const PoolVector &p_data, bool p_sync_with_draw) { +Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, const PoolVector &p_data, bool p_sync_with_draw) { _THREAD_SAFE_METHOD_ @@ -1875,7 +1868,6 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_mipmap, ui ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_CAN_UPDATE_BIT), ERR_INVALID_PARAMETER, "Texture requires the TEXTURE_USAGE_CAN_UPDATE_BIT in order to be updatable."); - ERR_FAIL_COND_V(p_mipmap >= texture->mipmaps, ERR_INVALID_PARAMETER); uint32_t layer_count = texture->layers; if (texture->type == TEXTURE_TYPE_CUBE || texture->type == TEXTURE_TYPE_CUBE_ARRAY) { layer_count *= 6; @@ -1883,7 +1875,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_mipmap, ui ERR_FAIL_COND_V(p_layer >= layer_count, ERR_INVALID_PARAMETER); uint32_t width, height; - uint32_t image_size = get_image_format_required_size(texture->format, texture->width, texture->height, 1, p_mipmap, &width, &height); + uint32_t image_size = get_image_format_required_size(texture->format, texture->width, texture->height, 1, texture->mipmaps, &width, &height); uint32_t required_size = image_size * texture->depth; ERR_FAIL_COND_V_MSG(required_size != (uint32_t)p_data.size(), ERR_INVALID_PARAMETER, @@ -1909,118 +1901,128 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_mipmap, ui image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = texture->image; image_memory_barrier.subresourceRange.aspectMask = texture->aspect_mask; - image_memory_barrier.subresourceRange.baseMipLevel = p_mipmap; - image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = texture->mipmaps; image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; image_memory_barrier.subresourceRange.layerCount = 1; vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); } - for (uint32_t z = 0; z < texture->depth; z++) { //for 3D textures, depth may be > 0 + uint32_t mipmap_offset = 0; + for (uint32_t mm_i = 0; mm_i < texture->mipmaps; mm_i++) { - const uint8_t *read_ptr = r.ptr(); - read_ptr += image_size * z; + uint32_t image_total = get_image_format_required_size(texture->format, texture->width, texture->height, 1, mm_i + 1, &width, &height); - for (uint32_t x = 0; x < width; x += region_size) { - for (uint32_t y = 0; y < height; y += region_size) { + const uint8_t *read_ptr = r.ptr() + mipmap_offset; + image_size = image_total - mipmap_offset; - uint32_t region_w = MIN(region_size, width - x); - uint32_t region_h = MIN(region_size, height - y); + for (uint32_t z = 0; z < texture->depth; z++) { //for 3D textures, depth may be > 0 - uint32_t pixel_size = get_image_format_pixel_size(texture->format); - uint32_t to_allocate = region_w * region_h * pixel_size; - to_allocate >>= get_compressed_image_format_pixel_rshift(texture->format); + read_ptr += image_size; - uint32_t alloc_offset, alloc_size; - Error err = _staging_buffer_allocate(to_allocate, 32, alloc_offset, alloc_size, false, p_sync_with_draw); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + for (uint32_t x = 0; x < width; x += region_size) { + for (uint32_t y = 0; y < height; y += region_size) { + + uint32_t region_w = MIN(region_size, width - x); + uint32_t region_h = MIN(region_size, height - y); - uint8_t *write_ptr; + uint32_t pixel_size = get_image_format_pixel_size(texture->format); + uint32_t to_allocate = region_w * region_h * pixel_size; + to_allocate >>= get_compressed_image_format_pixel_rshift(texture->format); - { //map - void *data_ptr = NULL; - VkResult vkerr = vmaMapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation, &data_ptr); - if (vkerr) { - ERR_FAIL_V(ERR_CANT_CREATE); + uint32_t alloc_offset, alloc_size; + Error err = _staging_buffer_allocate(to_allocate, 32, alloc_offset, alloc_size, false, p_sync_with_draw); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + uint8_t *write_ptr; + + { //map + void *data_ptr = NULL; + VkResult vkerr = vmaMapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation, &data_ptr); + if (vkerr) { + ERR_FAIL_V(ERR_CANT_CREATE); + } + write_ptr = (uint8_t *)data_ptr; + write_ptr += alloc_offset; } - write_ptr = (uint8_t *)data_ptr; - write_ptr += alloc_offset; - } - uint32_t block_w, block_h; - get_compressed_image_format_block_dimensions(texture->format, block_w, block_h); - - ERR_FAIL_COND_V(region_w % block_w, ERR_BUG); - ERR_FAIL_COND_V(region_h % block_h, ERR_BUG); - - if (block_w != 1 || block_h != 1) { - //compressed image (blocks) - //must copy a block region - - uint32_t block_size = get_compressed_image_format_block_byte_size(texture->format); - //re-create current variables in blocky format - uint32_t xb = x / block_w; - uint32_t yb = y / block_h; - uint32_t wb = width / block_w; - //uint32_t hb = height / block_h; - uint32_t region_wb = region_w / block_w; - uint32_t region_hb = region_h / block_h; - for (uint32_t xr = 0; xr < region_wb; xr++) { - for (uint32_t yr = 0; yr < region_hb; yr++) { - uint32_t src_offset = ((yr + yb) * wb + xr + xb) * block_size; - uint32_t dst_offset = (yr * region_wb + xr) * block_size; - //copy block - for (uint32_t i = 0; i < block_size; i++) { - write_ptr[dst_offset + i] = read_ptr[src_offset + i]; + uint32_t block_w, block_h; + get_compressed_image_format_block_dimensions(texture->format, block_w, block_h); + + ERR_FAIL_COND_V(region_w % block_w, ERR_BUG); + ERR_FAIL_COND_V(region_h % block_h, ERR_BUG); + + if (block_w != 1 || block_h != 1) { + //compressed image (blocks) + //must copy a block region + + uint32_t block_size = get_compressed_image_format_block_byte_size(texture->format); + //re-create current variables in blocky format + uint32_t xb = x / block_w; + uint32_t yb = y / block_h; + uint32_t wb = width / block_w; + //uint32_t hb = height / block_h; + uint32_t region_wb = region_w / block_w; + uint32_t region_hb = region_h / block_h; + for (uint32_t xr = 0; xr < region_wb; xr++) { + for (uint32_t yr = 0; yr < region_hb; yr++) { + uint32_t src_offset = ((yr + yb) * wb + xr + xb) * block_size; + uint32_t dst_offset = (yr * region_wb + xr) * block_size; + //copy block + for (uint32_t i = 0; i < block_size; i++) { + write_ptr[dst_offset + i] = read_ptr[src_offset + i]; + } } } - } - } else { - //regular image (pixels) - //must copy a pixel region + } else { + //regular image (pixels) + //must copy a pixel region - for (uint32_t xr = 0; xr < region_w; xr++) { - for (uint32_t yr = 0; yr < region_h; yr++) { - uint32_t src_offset = ((yr + y) * width + xr + x) * pixel_size; - uint32_t dst_offset = (yr * region_w + xr) * pixel_size; - //copy block - for (uint32_t i = 0; i < pixel_size; i++) { + for (uint32_t xr = 0; xr < region_w; xr++) { + for (uint32_t yr = 0; yr < region_h; yr++) { + uint32_t src_offset = ((yr + y) * width + xr + x) * pixel_size; + uint32_t dst_offset = (yr * region_w + xr) * pixel_size; + //copy block + for (uint32_t i = 0; i < pixel_size; i++) { - write_ptr[dst_offset + i] = read_ptr[src_offset + i]; + write_ptr[dst_offset + i] = read_ptr[src_offset + i]; + } } } } - } - { //unmap - vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation); - } + { //unmap + vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation); + } - VkBufferImageCopy buffer_image_copy; - buffer_image_copy.bufferOffset = alloc_offset; - buffer_image_copy.bufferRowLength = 0; //tigthly packed - buffer_image_copy.bufferImageHeight = 0; //tigthly packed + VkBufferImageCopy buffer_image_copy; + buffer_image_copy.bufferOffset = alloc_offset; + buffer_image_copy.bufferRowLength = 0; //tigthly packed + buffer_image_copy.bufferImageHeight = 0; //tigthly packed - buffer_image_copy.imageSubresource.aspectMask = texture->aspect_mask; - buffer_image_copy.imageSubresource.baseArrayLayer = p_layer; - buffer_image_copy.imageSubresource.mipLevel = p_mipmap; - buffer_image_copy.imageSubresource.layerCount = 1; + buffer_image_copy.imageSubresource.aspectMask = texture->aspect_mask; + buffer_image_copy.imageSubresource.mipLevel = mm_i; + buffer_image_copy.imageSubresource.baseArrayLayer = p_layer; + buffer_image_copy.imageSubresource.layerCount = 1; - buffer_image_copy.imageOffset.x = x; - buffer_image_copy.imageOffset.y = y; - buffer_image_copy.imageOffset.z = z; + buffer_image_copy.imageOffset.x = x; + buffer_image_copy.imageOffset.y = y; + buffer_image_copy.imageOffset.z = z; - buffer_image_copy.imageExtent.width = region_w; - buffer_image_copy.imageExtent.height = region_h; - buffer_image_copy.imageExtent.depth = 1; + buffer_image_copy.imageExtent.width = region_w; + buffer_image_copy.imageExtent.height = region_h; + buffer_image_copy.imageExtent.depth = 1; - vkCmdCopyBufferToImage(command_buffer, staging_buffer_blocks[staging_buffer_current].buffer, texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_image_copy); + vkCmdCopyBufferToImage(command_buffer, staging_buffer_blocks[staging_buffer_current].buffer, texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_image_copy); - staging_buffer_blocks.write[staging_buffer_current].fill_amount += alloc_size; + staging_buffer_blocks.write[staging_buffer_current].fill_amount += alloc_size; + } } } + + mipmap_offset = image_total; } //barrier to restore layout @@ -2036,8 +2038,8 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_mipmap, ui image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = texture->image; image_memory_barrier.subresourceRange.aspectMask = texture->aspect_mask; - image_memory_barrier.subresourceRange.baseMipLevel = p_mipmap; - image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = texture->mipmaps; image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; image_memory_barrier.subresourceRange.layerCount = 1; -- cgit v1.2.3 From 9b0dd4f571ff431e23b9097e7f29746f4157be12 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sat, 15 Jun 2019 23:45:24 -0300 Subject: A lot of progress with canvas rendering, still far from working. --- drivers/vulkan/rendering_device_vulkan.cpp | 84 +++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 24 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 7e9d40df19..d3ab21c43d 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1023,7 +1023,7 @@ uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_form uint32_t blockw, blockh; get_compressed_image_format_block_dimensions(p_format, blockw, blockh); - for (uint32_t i = 0; i <= p_mipmaps; i++) { + for (uint32_t i = 0; i < p_mipmaps; i++) { uint32_t bw = w % blockw != 0 ? w + (blockw - w % blockw) : w; uint32_t bh = h % blockh != 0 ? h + (blockh - h % blockh) : h; @@ -2049,7 +2049,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con return OK; } -bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_format, TextureUsageBits p_usage) const { +bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const { ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false); _THREAD_SAFE_METHOD_ @@ -2745,6 +2745,10 @@ static const char *shader_stage_names[RenderingDevice::SHADER_STAGE_MAX] = { "Compute" }; +static const char *shader_uniform_names[RenderingDevice::UNIFORM_TYPE_MAX] = { + "Sampler", "CombinedSampler", "Texture", "Image", "TextureBuffer", "SamplerTextureBuffer", "ImageBuffer", "UniformBuffer", "StorageBuffer", "InputAttachment" +}; + static VkShaderStageFlagBits shader_stage_masks[RenderingDevice::SHADER_STAGE_MAX] = { VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT, @@ -2758,26 +2762,24 @@ bool RenderingDeviceVulkan::_uniform_add_binding(VectorgetBasicType()) { case glslang::EbtSampler: { - print_line("DEBUG: IsSampler"); + //print_line("DEBUG: IsSampler"); if (reflection.getType()->getSampler().dim == glslang::EsdBuffer) { //texture buffers if (reflection.getType()->getSampler().isCombined()) { layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER; - print_line("DEBUG: texel combined"); + //print_line("DEBUG: SAMPLER: texel combined"); } else if (reflection.getType()->getSampler().isTexture()) { layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; info.type = UNIFORM_TYPE_TEXTURE_BUFFER; - print_line("DEBUG: texel alone"); + //print_line("DEBUG: SAMPLER: texel alone"); } else if (reflection.getType()->getSampler().isImage()) { layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; info.type = UNIFORM_TYPE_IMAGE_BUFFER; - print_line("DEBUG: texel buffer"); + //print_line("DEBUG: SAMPLER: texel buffer"); } else { if (r_error) { *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported buffer type."; @@ -2787,21 +2789,21 @@ bool RenderingDeviceVulkan::_uniform_add_binding(VectorgetSampler().isCombined()) { layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; - print_line("DEBUG: combined"); + //print_line("DEBUG: SAMPLER: combined"); } else if (reflection.getType()->getSampler().isPureSampler()) { layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; info.type = UNIFORM_TYPE_SAMPLER; - print_line("DEBUG: sampler"); + //print_line("DEBUG: SAMPLER: sampler"); } else if (reflection.getType()->getSampler().isTexture()) { layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; info.type = UNIFORM_TYPE_TEXTURE; - print_line("DEBUG: image"); + //print_line("DEBUG: SAMPLER: image"); } else if (reflection.getType()->getSampler().isImage()) { layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; info.type = UNIFORM_TYPE_IMAGE; - print_line("DEBUG: storage image"); + //print_line("DEBUG: SAMPLER: storage image"); } else { - print_line("DEBUG: sampler unknown"); + //print_line("DEBUG: sampler unknown"); if (r_error) { *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported sampler type."; } @@ -2810,7 +2812,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(VectorisArray()) { layout_binding.descriptorCount = reflection.getType()->getArraySizes()->getCumulativeSize(); - print_line("DEBUG: array of size: " + itos(layout_binding.descriptorCount)); + //print_line("DEBUG: array of size: " + itos(layout_binding.descriptorCount)); } else { layout_binding.descriptorCount = 1; } @@ -2823,7 +2825,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(VectorgetQualifier().storage == glslang::EvqUniform) { if (reflection.getType()->getQualifier().layoutPushConstant) { uint32_t len = reflection.size; @@ -2835,13 +2837,13 @@ bool RenderingDeviceVulkan::_uniform_add_binding(VectorgetQualifier().storage == glslang::EvqBuffer) { layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; info.type = UNIFORM_TYPE_STORAGE_BUFFER; - print_line("DEBUG: Storage buffer"); + //print_line("DEBUG: Storage buffer"); } else { if (r_error) { *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported block type: (" + itos(reflection.getType()->getQualifier().storage) + ")."; @@ -2851,7 +2853,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(VectorisArray()) { layout_binding.descriptorCount = reflection.getType()->getArraySizes()->getCumulativeSize(); - print_line("DEBUG: array of size: " + itos(layout_binding.descriptorCount)); + //print_line("DEBUG: array of size: " + itos(layout_binding.descriptorCount)); } else { layout_binding.descriptorCount = 1; } @@ -2935,14 +2937,16 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector &p_stages, String *r_error, bool p_allow_cache) { +RID RenderingDeviceVulkan::shader_create_from_source(const Vector &p_stages, String *r_error, ShaderStage *r_error_stage, bool p_allow_cache) { _THREAD_SAFE_METHOD_ @@ -3007,6 +3011,10 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector RenderingDeviceVulkan::shader_get_vertex_input_locations_used(RID p_shader) { + const Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, Vector()); + return shader->vertex_input_locations; +} + /******************/ /**** UNIFORMS ****/ /******************/ @@ -3789,6 +3820,10 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, return id; } +bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) { + return uniform_set_owner.owns(p_uniform_set); +} + Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, void *p_data, bool p_sync_with_draw) { _THREAD_SAFE_METHOD_ @@ -4113,6 +4148,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma graphics_pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; graphics_pipeline_create_info.pNext = NULL; + graphics_pipeline_create_info.flags = 0; graphics_pipeline_create_info.stageCount = shader->pipeline_stages.size(); graphics_pipeline_create_info.pStages = shader->pipeline_stages.ptr(); -- cgit v1.2.3 From 42b44f43ee52eb664d3610d0fdae0eff14c00f0a Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Wed, 19 Jun 2019 17:03:19 -0300 Subject: Basic 2D engine is more or less working, needs more work for editor to be usable. --- drivers/vulkan/rendering_device_vulkan.cpp | 56 +++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 13 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index d3ab21c43d..ed044ceb05 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -721,7 +721,8 @@ uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format) case DATA_FORMAT_S8_UINT: return 1; case DATA_FORMAT_D16_UNORM_S8_UINT: return 4; case DATA_FORMAT_D24_UNORM_S8_UINT: return 4; - case DATA_FORMAT_D32_SFLOAT_S8_UINT: return 5; //? + case DATA_FORMAT_D32_SFLOAT_S8_UINT: + return 5; //? case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK: @@ -965,7 +966,8 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_block_byte_size(Data case DATA_FORMAT_ASTC_12x10_UNORM_BLOCK: case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK: case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK: - case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK: return 8; //wrong + case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK: + return 8; //wrong case DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: case DATA_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: case DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: @@ -973,7 +975,8 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_block_byte_size(Data case DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: case DATA_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: case DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: - case DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: return 8; //what varies is resolution + case DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: + return 8; //what varies is resolution default: { } } @@ -1027,7 +1030,6 @@ uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_form uint32_t bw = w % blockw != 0 ? w + (blockw - w % blockw) : w; uint32_t bh = h % blockh != 0 ? h + (blockh - h % blockh) : h; - print_line("bw " + itos(bw) + " bh " + itos(bh) + " pixsize " + itos(pixel_size) + " shift " + itos(pixel_rshift)); uint32_t s = bw * bh; s *= pixel_size; @@ -1466,6 +1468,26 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T image_create_info.pNext = NULL; image_create_info.flags = 0; + VkImageFormatListCreateInfoKHR format_list_create_info; + Vector allowed_formats; + + if (p_format.shareable_formats.size()) { + image_create_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + for (int i = 0; i < p_format.shareable_formats.size(); i++) { + allowed_formats.push_back(vulkan_formats[p_format.shareable_formats[i]]); + } + + format_list_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR; + format_list_create_info.pNext = NULL; + format_list_create_info.viewFormatCount = allowed_formats.size(); + format_list_create_info.pViewFormats = allowed_formats.ptr(); + image_create_info.pNext = &format_list_create_info; + + ERR_FAIL_COND_V_MSG(p_format.shareable_formats.find(p_format.format) == -1, RID(), + "If supplied a list of shareable formats, the current format must be present in the list"); + ERR_FAIL_COND_V_MSG(p_view.format_override != DATA_FORMAT_MAX && p_format.shareable_formats.find(p_view.format_override) == -1, RID(), + "If supplied a list of shareable formats, the current view format override must be present in the list"); + } if (p_format.type == TEXTURE_TYPE_CUBE || p_format.type == TEXTURE_TYPE_CUBE_ARRAY) { image_create_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; } @@ -1647,6 +1669,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T texture.mipmaps = image_create_info.mipLevels; texture.usage_flags = p_format.usage_bits; texture.samples = p_format.samples; + texture.allowed_shared_formats = p_format.shareable_formats; //set bound and unbound layouts if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { @@ -1803,10 +1826,13 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID }; image_view_create_info.viewType = view_types[texture.type]; - if (p_view.format_override == DATA_FORMAT_MAX) { + if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) { image_view_create_info.format = vulkan_formats[texture.format]; } else { ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID()); + + ERR_FAIL_COND_V_MSG(texture.allowed_shared_formats.find(p_view.format_override) == -1, RID(), + "Format override is not in the list of allowed shareable formats for original texture."); image_view_create_info.format = vulkan_formats[p_view.format_override]; } @@ -1877,6 +1903,13 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con uint32_t width, height; uint32_t image_size = get_image_format_required_size(texture->format, texture->width, texture->height, 1, texture->mipmaps, &width, &height); uint32_t required_size = image_size * texture->depth; + uint32_t required_align = get_compressed_image_format_block_byte_size(texture->format); + if (required_align == 1) { + required_align = get_image_format_pixel_size(texture->format); + } + if ((required_align % 4) != 0) { //alignment rules are really strange + required_align *= 4; + } ERR_FAIL_COND_V_MSG(required_size != (uint32_t)p_data.size(), ERR_INVALID_PARAMETER, "Required size for texture update (" + itos(required_size) + ") does not match data supplied size (" + itos(p_data.size()) + ")."); @@ -1914,12 +1947,12 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con uint32_t image_total = get_image_format_required_size(texture->format, texture->width, texture->height, 1, mm_i + 1, &width, &height); - const uint8_t *read_ptr = r.ptr() + mipmap_offset; + const uint8_t *read_ptr_mipmap = r.ptr() + mipmap_offset; image_size = image_total - mipmap_offset; for (uint32_t z = 0; z < texture->depth; z++) { //for 3D textures, depth may be > 0 - read_ptr += image_size; + const uint8_t *read_ptr = read_ptr_mipmap + image_size * z; for (uint32_t x = 0; x < width; x += region_size) { for (uint32_t y = 0; y < height; y += region_size) { @@ -1932,7 +1965,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con to_allocate >>= get_compressed_image_format_pixel_rshift(texture->format); uint32_t alloc_offset, alloc_size; - Error err = _staging_buffer_allocate(to_allocate, 32, alloc_offset, alloc_size, false, p_sync_with_draw); + Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, false, p_sync_with_draw); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); uint8_t *write_ptr; @@ -2937,7 +2970,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(VectorgetQualifier().hasLocation()) { int location = program.getPipeInput(i).getType()->getQualifier().layoutLocation; - print_line("found vertex location: " + itos(location)); + if (vertex_input_locations.find(location) == -1) { vertex_input_locations.push_back(location); } @@ -3470,13 +3503,10 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, uint32_t uniform_count = p_uniforms.size(); const Uniform *uniforms = p_uniforms.ptr(); - print_line("uniform count: " + itos(uniform_count)); uint32_t set_uniform_count = set.uniform_info.size(); const Shader::UniformInfo *set_uniforms = set.uniform_info.ptr(); - print_line("set_uniform count: " + itos(set_uniform_count)); - Vector writes; DescriptorPoolKey pool_key; -- cgit v1.2.3 From 1b4281b895f3046ea972256182b18696a25f8316 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Mon, 24 Jun 2019 16:13:06 -0300 Subject: basic 2D engine is more or less working with Vulkan, including editor. Still a lot to do --- drivers/vulkan/rendering_device_vulkan.cpp | 291 +++++++++++++++++++++++------ 1 file changed, 231 insertions(+), 60 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index ed044ceb05..516853a64e 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -24,20 +24,14 @@ void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) { void RenderingDeviceVulkan::_free_dependencies(RID p_id) { //direct dependencies must be freed - List to_free; + Map >::Element *E = dependency_map.find(p_id); if (E) { - for (Set::Element *F = E->get().front(); F; F = F->next()) { - to_free.push_back(F->get()); + while (E->get().size()) { + free(E->get().front()->get()); } - dependency_map.erase(E); - - while (to_free.front()) { - free(to_free.front()->get()); - to_free.pop_front(); - } } //reverse depenencies must be unreferenced @@ -47,9 +41,9 @@ void RenderingDeviceVulkan::_free_dependencies(RID p_id) { for (Set::Element *F = E->get().front(); F; F = F->next()) { Map >::Element *G = dependency_map.find(F->get()); - if (G) { - G->get().erase(p_id); - } + ERR_CONTINUE(!G); + ERR_CONTINUE(!G->get().has(p_id)); + G->get().erase(p_id); } reverse_dependency_map.erase(E); @@ -1210,7 +1204,6 @@ Error RenderingDeviceVulkan::_buffer_free(Buffer *p_buffer) { ERR_FAIL_COND_V(p_buffer->size == 0, ERR_INVALID_PARAMETER); vmaDestroyBuffer(allocator, p_buffer->buffer, p_buffer->allocation); - vmaFreeMemory(allocator, p_buffer->allocation); p_buffer->buffer = NULL; p_buffer->allocation = NULL; p_buffer->size = 0; @@ -1455,6 +1448,16 @@ Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, c return OK; } +void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw) { + + VkMemoryBarrier mem_barrier; + mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + mem_barrier.pNext = NULL; + mem_barrier.srcAccessMask = p_src_access; + mem_barrier.dstAccessMask = p_dst_sccess; + + vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 1, &mem_barrier, 0, NULL, 0, NULL); +} /*****************/ /**** TEXTURE ****/ /*****************/ @@ -1753,7 +1756,6 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T if (err) { vmaDestroyImage(allocator, texture.image, texture.allocation); - vmaFreeMemory(allocator, texture.allocation); ERR_FAIL_V(RID()); } @@ -2082,6 +2084,16 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con return OK; } +bool RenderingDeviceVulkan::texture_is_shared(RID p_texture) { + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND_V(!tex, false); + return tex->owner.is_valid(); +} + +bool RenderingDeviceVulkan::texture_is_valid(RID p_texture) { + return texture_owner.owns(p_texture); +} + bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const { ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false); @@ -2487,7 +2499,9 @@ RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Poo uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); _buffer_update(&buffer, 0, r.ptr(), data_size); + _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, false); } + return vertex_buffer_owner.make_rid(buffer); } @@ -2498,14 +2512,17 @@ RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(cons VertexDescriptionKey key; key.vertex_formats = p_vertex_formats; - const Map::Element *E = vertex_format_cache.find(key); - if (E) { - return E->get(); + + VertexFormatID *idptr = vertex_format_cache.getptr(key); + if (idptr) { + return *idptr; } + //does not exist, create one and cache it VertexDescriptionCache vdcache; vdcache.bindings = memnew_arr(VkVertexInputBindingDescription, p_vertex_formats.size()); vdcache.attributes = memnew_arr(VkVertexInputAttributeDescription, p_vertex_formats.size()); + Set used_locations; for (int i = 0; i < p_vertex_formats.size(); i++) { ERR_CONTINUE(p_vertex_formats[i].format >= DATA_FORMAT_MAX); @@ -2533,9 +2550,10 @@ RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(cons vdcache.create_info.vertexBindingDescriptionCount = p_vertex_formats.size(); vdcache.create_info.pVertexBindingDescriptions = vdcache.bindings; + vdcache.vertex_formats = p_vertex_formats; VertexFormatID id = VertexFormatID(vertex_format_cache.size()) | (VertexFormatID(ID_TYPE_VERTEX_FORMAT) << ID_BASE_SHIFT); - vdcache.E = vertex_format_cache.insert(key, id); + vertex_format_cache[key] = id; vertex_formats[id] = vdcache; return id; } @@ -2547,7 +2565,7 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID()); const VertexDescriptionCache &vd = vertex_formats[p_vertex_format]; - ERR_FAIL_COND_V(vd.E->key().vertex_formats.size() != p_src_buffers.size(), RID()); + ERR_FAIL_COND_V(vd.vertex_formats.size() != p_src_buffers.size(), RID()); for (int i = 0; i < p_src_buffers.size(); i++) { ERR_FAIL_COND_V(!vertex_buffer_owner.owns(p_src_buffers[i]), RID()); @@ -2563,7 +2581,8 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo //validate with buffer { - const VertexDescription &atf = vd.E->key().vertex_formats[i]; + const VertexDescription &atf = vd.vertex_formats[i]; + uint32_t element_size = get_format_vertex_size(atf.format); ERR_FAIL_COND_V(element_size == 0, RID()); //should never happens since this was prevalidated @@ -2641,6 +2660,7 @@ RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBuff uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); _buffer_update(&index_buffer, 0, r.ptr(), data_size); + _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, false); } return index_buffer_owner.make_rid(index_buffer); } @@ -3314,6 +3334,7 @@ RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Po uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); _buffer_update(&buffer, 0, r.ptr(), data_size); + _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT, false); } return uniform_buffer_owner.make_rid(buffer); } @@ -3332,6 +3353,7 @@ RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Po uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); _buffer_update(&buffer, 0, r.ptr(), data_size); + _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, false); } return storage_buffer_owner.make_rid(buffer); } @@ -3354,6 +3376,7 @@ RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataF uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); _buffer_update(&texture_buffer.buffer, 0, r.ptr(), data_size); + _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, false); } VkBufferViewCreateInfo view_create_info; @@ -3483,6 +3506,9 @@ void RenderingDeviceVulkan::_descriptor_pool_free(const DescriptorPoolKey &p_key vkDestroyDescriptorPool(device, p_pool->pool, NULL); descriptor_pools[p_key].erase(p_pool); memdelete(p_pool); + if (descriptor_pools[p_key].empty()) { + descriptor_pools.erase(p_key); + } } } @@ -3857,16 +3883,29 @@ bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) { Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, void *p_data, bool p_sync_with_draw) { _THREAD_SAFE_METHOD_ + VkPipelineStageFlags dst_stage_mask; + VkAccessFlags dst_access; + Buffer *buffer = NULL; if (vertex_buffer_owner.owns(p_buffer)) { + dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + dst_access = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; buffer = vertex_buffer_owner.getornull(p_buffer); } else if (index_buffer_owner.owns(p_buffer)) { + dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + dst_access = VK_ACCESS_INDEX_READ_BIT; buffer = index_buffer_owner.getornull(p_buffer); } else if (uniform_buffer_owner.owns(p_buffer)) { + dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + dst_access = VK_ACCESS_UNIFORM_READ_BIT; buffer = uniform_buffer_owner.getornull(p_buffer); } else if (texture_buffer_owner.owns(p_buffer)) { + dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + dst_access = VK_ACCESS_SHADER_READ_BIT; buffer = &texture_buffer_owner.getornull(p_buffer)->buffer; } else if (storage_buffer_owner.owns(p_buffer)) { + dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + dst_access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; buffer = storage_buffer_owner.getornull(p_buffer); } else { ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type."); @@ -3875,7 +3914,14 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER, "Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end."); - return _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, p_sync_with_draw); + Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, p_sync_with_draw); + if (err) { + return err; + } + + _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, p_sync_with_draw); + + return err; } /*************************/ @@ -3908,17 +3954,16 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma if (p_vertex_format != INVALID_ID) { //uses vertices, else it does not ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID()); - VertexDescriptionCache &vd = vertex_formats[p_vertex_format]; + const VertexDescriptionCache &vd = vertex_formats[p_vertex_format]; pipeline_vertex_input_state_create_info = vd.create_info; //validate with inputs for (int i = 0; i < shader->vertex_input_locations.size(); i++) { uint32_t location = shader->vertex_input_locations[i]; - const VertexDescriptionKey &k = vd.E->key(); bool found = false; - for (int j = 0; j < k.vertex_formats.size(); j++) { - if (k.vertex_formats[j].location == location) { + for (int j = 0; j < vd.vertex_formats.size(); j++) { + if (vd.vertex_formats[j].location == location) { found = true; } } @@ -4237,6 +4282,11 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma return id; } +bool RenderingDeviceVulkan::render_pipeline_is_valid(RID p_pipeline) { + _THREAD_SAFE_METHOD_ + return pipeline_owner.owns(p_pipeline); +} + /****************/ /**** SCREEN ****/ /****************/ @@ -4244,12 +4294,12 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma int RenderingDeviceVulkan::screen_get_width(int p_screen) const { _THREAD_SAFE_METHOD_ - return context->get_screen_width(p_screen); + return context->window_get_width(p_screen); } int RenderingDeviceVulkan::screen_get_height(int p_screen) const { _THREAD_SAFE_METHOD_ - return context->get_screen_height(p_screen); + return context->window_get_height(p_screen); } RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::screen_get_framebuffer_format() const { @@ -4295,11 +4345,11 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(in VkRenderPassBeginInfo render_pass_begin; render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; render_pass_begin.pNext = NULL; - render_pass_begin.renderPass = context->get_render_pass(); - render_pass_begin.framebuffer = context->get_frame_framebuffer(frame); + render_pass_begin.renderPass = context->window_get_render_pass(p_screen); + render_pass_begin.framebuffer = context->window_get_framebuffer(p_screen); - render_pass_begin.renderArea.extent.width = context->get_screen_width(p_screen); - render_pass_begin.renderArea.extent.height = context->get_screen_height(p_screen); + render_pass_begin.renderArea.extent.width = context->window_get_width(p_screen); + render_pass_begin.renderArea.extent.height = context->window_get_height(p_screen); render_pass_begin.renderArea.offset.x = 0; render_pass_begin.renderArea.offset.y = 0; @@ -4504,6 +4554,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu vkCmdSetScissor(command_buffer, 0, 1, &scissor); + draw_list->viewport = Rect2i(viewport_offset, viewport_size); return ID_TYPE_DRAW_LIST; } @@ -4646,6 +4697,8 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p vkCmdSetScissor(command_buffer, 0, 1, &scissor); r_split_ids[i] = (DrawListID(1) << DrawListID(ID_TYPE_SPLIT_DRAW_LIST)) + i; + + draw_list[i].viewport = Rect2i(viewport_offset, viewport_size); } return OK; @@ -4776,6 +4829,15 @@ void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_ vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, index_array->offset, index_array->index_type); } +void RenderingDeviceVulkan::draw_list_set_line_width(DrawListID p_list, float p_width) { + + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); + + vkCmdSetLineWidth(dl->command_buffer, p_width); +} + void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); @@ -4873,8 +4935,37 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices } void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) { + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); + + Rect2i rect = p_rect; + rect.position += dl->viewport.position; + + rect = dl->viewport.clip(rect); + + if (rect.get_area() == 0) { + return; + } + VkRect2D scissor; + scissor.offset.x = rect.position.x; + scissor.offset.y = rect.position.y; + scissor.extent.width = rect.size.width; + scissor.extent.height = rect.size.height; + + vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor); } void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) { + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); + + VkRect2D scissor; + scissor.offset.x = dl->viewport.position.x; + scissor.offset.y = dl->viewport.position.y; + scissor.extent.width = dl->viewport.size.width; + scissor.extent.height = dl->viewport.size.height; + vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor); } void RenderingDeviceVulkan::draw_list_end() { @@ -4997,6 +5088,7 @@ void RenderingDeviceVulkan::_free_internal(RID p_id) { Buffer b; b.allocation = index_buffer->allocation; b.buffer = index_buffer->buffer; + b.size = index_buffer->size; frames[frame].buffers_to_dispose_of.push_back(b); index_buffer_owner.free(p_id); } else if (index_array_owner.owns(p_id)) { @@ -5050,42 +5142,42 @@ void RenderingDeviceVulkan::finalize_frame() { vkEndCommandBuffer(frames[frame].setup_command_buffer); vkEndCommandBuffer(frames[frame].draw_command_buffer); } + screen_prepared = false; } -void RenderingDeviceVulkan::_free_pending_resources() { +void RenderingDeviceVulkan::_free_pending_resources(int p_frame) { //free in dependency usage order, so nothing weird happens - //pipelines - while (frames[frame].pipelines_to_dispose_of.front()) { - RenderPipeline *pipeline = &frames[frame].pipelines_to_dispose_of.front()->get(); + while (frames[p_frame].pipelines_to_dispose_of.front()) { + RenderPipeline *pipeline = &frames[p_frame].pipelines_to_dispose_of.front()->get(); vkDestroyPipeline(device, pipeline->pipeline, NULL); - frames[frame].pipelines_to_dispose_of.pop_front(); + frames[p_frame].pipelines_to_dispose_of.pop_front(); } //uniform sets - while (frames[frame].uniform_sets_to_dispose_of.front()) { - UniformSet *uniform_set = &frames[frame].uniform_sets_to_dispose_of.front()->get(); + while (frames[p_frame].uniform_sets_to_dispose_of.front()) { + UniformSet *uniform_set = &frames[p_frame].uniform_sets_to_dispose_of.front()->get(); vkFreeDescriptorSets(device, uniform_set->pool->pool, 1, &uniform_set->descriptor_set); _descriptor_pool_free(uniform_set->pool_key, uniform_set->pool); - frames[frame].uniform_sets_to_dispose_of.pop_front(); + frames[p_frame].uniform_sets_to_dispose_of.pop_front(); } //buffer views - while (frames[frame].buffer_views_to_dispose_of.front()) { - VkBufferView buffer_view = frames[frame].buffer_views_to_dispose_of.front()->get(); + while (frames[p_frame].buffer_views_to_dispose_of.front()) { + VkBufferView buffer_view = frames[p_frame].buffer_views_to_dispose_of.front()->get(); vkDestroyBufferView(device, buffer_view, NULL); - frames[frame].buffer_views_to_dispose_of.pop_front(); + frames[p_frame].buffer_views_to_dispose_of.pop_front(); } //shaders - while (frames[frame].shaders_to_dispose_of.front()) { - Shader *shader = &frames[frame].shaders_to_dispose_of.front()->get(); + while (frames[p_frame].shaders_to_dispose_of.front()) { + Shader *shader = &frames[p_frame].shaders_to_dispose_of.front()->get(); //descriptor set layout for each set for (int i = 0; i < shader->sets.size(); i++) { @@ -5100,21 +5192,21 @@ void RenderingDeviceVulkan::_free_pending_resources() { vkDestroyShaderModule(device, shader->pipeline_stages[i].module, NULL); } - frames[frame].shaders_to_dispose_of.pop_front(); + frames[p_frame].shaders_to_dispose_of.pop_front(); } //samplers - while (frames[frame].samplers_to_dispose_of.front()) { - VkSampler sampler = frames[frame].samplers_to_dispose_of.front()->get(); + while (frames[p_frame].samplers_to_dispose_of.front()) { + VkSampler sampler = frames[p_frame].samplers_to_dispose_of.front()->get(); vkDestroySampler(device, sampler, NULL); - frames[frame].samplers_to_dispose_of.pop_front(); + frames[p_frame].samplers_to_dispose_of.pop_front(); } //framebuffers - while (frames[frame].framebuffers_to_dispose_of.front()) { - Framebuffer *framebuffer = &frames[frame].framebuffers_to_dispose_of.front()->get(); + while (frames[p_frame].framebuffers_to_dispose_of.front()) { + Framebuffer *framebuffer = &frames[p_frame].framebuffers_to_dispose_of.front()->get(); for (Map::Element *E = framebuffer->framebuffers.front(); E; E = E->next()) { //first framebuffer, then render pass because it depends on it @@ -5122,12 +5214,12 @@ void RenderingDeviceVulkan::_free_pending_resources() { vkDestroyRenderPass(device, E->get().render_pass, NULL); } - frames[frame].framebuffers_to_dispose_of.pop_front(); + frames[p_frame].framebuffers_to_dispose_of.pop_front(); } //textures - while (frames[frame].textures_to_dispose_of.front()) { - Texture *texture = &frames[frame].textures_to_dispose_of.front()->get(); + while (frames[p_frame].textures_to_dispose_of.front()) { + Texture *texture = &frames[p_frame].textures_to_dispose_of.front()->get(); if (texture->bound) { WARN_PRINT("Deleted a texture while it was bound.."); @@ -5136,19 +5228,25 @@ void RenderingDeviceVulkan::_free_pending_resources() { if (texture->owner.is_null()) { //actually owns the image and the allocation too vmaDestroyImage(allocator, texture->image, texture->allocation); - vmaFreeMemory(allocator, texture->allocation); } - frames[frame].textures_to_dispose_of.pop_front(); + frames[p_frame].textures_to_dispose_of.pop_front(); } //buffers - while (frames[frame].buffers_to_dispose_of.front()) { - _buffer_free(&frames[frame].buffers_to_dispose_of.front()->get()); + while (frames[p_frame].buffers_to_dispose_of.front()) { + + _buffer_free(&frames[p_frame].buffers_to_dispose_of.front()->get()); - frames[frame].buffers_to_dispose_of.pop_front(); + frames[p_frame].buffers_to_dispose_of.pop_front(); } } +void RenderingDeviceVulkan::prepare_screen_for_drawing() { + _THREAD_SAFE_METHOD_ + context->prepare_buffers(); + screen_prepared = true; +} + void RenderingDeviceVulkan::advance_frame() { _THREAD_SAFE_METHOD_ @@ -5157,7 +5255,7 @@ void RenderingDeviceVulkan::advance_frame() { frame = (frame + 1) % frame_count; //erase pending resources - _free_pending_resources(); + _free_pending_resources(frame); //create setup command buffer and set as the setup buffer @@ -5192,7 +5290,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) { context = p_context; device = p_context->get_device(); - frame_count = p_context->get_frame_count(); + frame_count = p_context->get_swapchain_image_count() + 1; //always need one extra to ensure it's unused at any time, without having to use a fence for this. limits = p_context->get_device_limits(); { //initialize allocator @@ -5292,10 +5390,83 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) { draw_list_count = 0; draw_list_split = false; } + +template +void RenderingDeviceVulkan::_free_rids(T &p_owner, const char *p_type) { + List owned; + p_owner.get_owned_list(&owned); + if (owned.size()) { + WARN_PRINT(itos(owned.size()) + " RIDs of type '" + p_type + "' were leaked."); + for (List::Element *E = owned.front(); E; E = E->next()) { + free(E->get()); + } + } +} + void RenderingDeviceVulkan::finalize() { + //free all resources + + context->flush(false, false); + + _free_rids(pipeline_owner, "Pipeline"); + _free_rids(uniform_set_owner, "UniformSet"); + _free_rids(texture_buffer_owner, "TextureBuffer"); + _free_rids(storage_buffer_owner, "StorageBuffer"); + _free_rids(uniform_buffer_owner, "UniformBuffer"); + _free_rids(shader_owner, "Shader"); + _free_rids(index_array_owner, "IndexArray"); + _free_rids(index_buffer_owner, "IndexBuffer"); + _free_rids(vertex_array_owner, "VertexArray"); + _free_rids(vertex_buffer_owner, "VertexBuffer"); + _free_rids(framebuffer_owner, "Framebuffer"); + _free_rids(sampler_owner, "Sampler"); + { + //for textures it's a bit more difficult because they may be shared + List owned; + texture_owner.get_owned_list(&owned); + if (owned.size()) { + WARN_PRINT(itos(owned.size()) + " RIDs of type 'Texture' were leaked."); + //free shared first + for (List::Element *E = owned.front(); E;) { + + List::Element *N = E->next(); + if (texture_is_shared(E->get())) { + free(E->get()); + owned.erase(E->get()); + } + E = N; + } + //free non shared second, this will avoid an error trying to free unexisting textures due to dependencies. + for (List::Element *E = owned.front(); E; E = E->next()) { + free(E->get()); + } + } + } + + //free everything pending + for (int i = 0; i < frame_count; i++) { + int f = (frame + i) % frame_count; + _free_pending_resources(f); + vkDestroyCommandPool(device, frames[i].command_pool, NULL); + } + + for (int i = 0; i < split_draw_list_allocators.size(); i++) { + vkDestroyCommandPool(device, split_draw_list_allocators[i].command_pool, NULL); + } + memdelete_arr(frames); + + for (int i = 0; i < staging_buffer_blocks.size(); i++) { + vmaDestroyBuffer(allocator, staging_buffer_blocks[i].buffer, staging_buffer_blocks[i].allocation); + } + + //all these should be clear at this point + ERR_FAIL_COND(descriptor_pools.size()); + ERR_FAIL_COND(dependency_map.size()); + ERR_FAIL_COND(reverse_dependency_map.size()); } RenderingDeviceVulkan::RenderingDeviceVulkan() { + screen_prepared = false; } -- cgit v1.2.3 From e1b3444415054c21b274546876642af7292c0937 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Mon, 24 Jun 2019 22:24:07 -0300 Subject: Bugfixes and ability to better specify filter and repeat modes everywhere. Removes antialiased flag for draw_* methods. --- drivers/vulkan/rendering_device_vulkan.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 516853a64e..3ea0cb3664 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1785,7 +1785,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T if (p_data.size()) { for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) { - texture_update(id, i, p_data[i], true); + texture_update(id, i, p_data[i]); } } return id; @@ -1881,6 +1881,9 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con _THREAD_SAFE_METHOD_ + ERR_FAIL_COND_V_MSG(draw_list && p_sync_with_draw, ERR_INVALID_PARAMETER, + "Updating textures in 'sync to draw' mode is forbidden during creation of a draw list"); + Texture *texture = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!texture, ERR_INVALID_PARAMETER); @@ -3883,6 +3886,9 @@ bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) { Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, void *p_data, bool p_sync_with_draw) { _THREAD_SAFE_METHOD_ + ERR_FAIL_COND_V_MSG(draw_list && p_sync_with_draw, ERR_INVALID_PARAMETER, + "Updating buffers in 'sync to draw' mode is forbidden during creation of a draw list"); + VkPipelineStageFlags dst_stage_mask; VkAccessFlags dst_access; -- cgit v1.2.3 From e3905f9af3d2261a395ef2ae8e708f33edc115b6 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Tue, 25 Jun 2019 19:49:52 -0300 Subject: Added ability to retrieve back textures stored on GPU --- drivers/vulkan/rendering_device_vulkan.cpp | 359 +++++++++++++++++++++++++---- 1 file changed, 319 insertions(+), 40 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 3ea0cb3664..3354454fce 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1007,7 +1007,7 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFor return 0; } -uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh) { +uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh, uint32_t *r_depth) { uint32_t w = p_width; uint32_t h = p_height; @@ -1035,6 +1035,9 @@ uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_form if (r_blockh) { *r_blockh = bh; } + if (r_depth) { + *r_depth = d; + } w = MAX(blockw, w >> 1); h = MAX(blockh, h >> 1); d = MAX(1, d >> 1); @@ -1166,6 +1169,17 @@ const VkBorderColor RenderingDeviceVulkan::sampler_border_colors[RenderingDevice VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, VK_BORDER_COLOR_INT_OPAQUE_WHITE }; + +const VkImageType RenderingDeviceVulkan::vulkan_image_type[RenderingDevice::TEXTURE_TYPE_MAX] = { + VK_IMAGE_TYPE_1D, + VK_IMAGE_TYPE_2D, + VK_IMAGE_TYPE_3D, + VK_IMAGE_TYPE_2D, + VK_IMAGE_TYPE_1D, + VK_IMAGE_TYPE_2D, + VK_IMAGE_TYPE_3D +}; + /***************************/ /**** BUFFER MANAGEMENT ****/ /***************************/ @@ -1308,26 +1322,7 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_ } else { //flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands - context->flush(true, p_on_draw_command_buffer); - //re-create the setup command - { - VkCommandBufferBeginInfo cmdbuf_begin; - cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmdbuf_begin.pNext = NULL; - cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - cmdbuf_begin.pInheritanceInfo = NULL; - - VkResult err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - context->set_setup_buffer(frames[frame].setup_command_buffer); //append now so it's added before everything else - - if (p_on_draw_command_buffer) { - - err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - context->append_command_buffer(frames[frame].draw_command_buffer); - } - } + _flush(true, p_on_draw_command_buffer); //clear the whole staging buffer for (int i = 0; i < staging_buffer_blocks.size(); i++) { @@ -1371,7 +1366,7 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_ continue; //and try again } else { - context->flush(false); // flush previous frames (but don't touch setup command, so this frame) + _flush(false, false); for (int i = 0; i < staging_buffer_blocks.size(); i++) { //clear all blocks but the ones from this frame @@ -1498,19 +1493,9 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T image_create_info.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; }*/ - const VkImageType image_type[TEXTURE_TYPE_MAX] = { - VK_IMAGE_TYPE_1D, - VK_IMAGE_TYPE_2D, - VK_IMAGE_TYPE_3D, - VK_IMAGE_TYPE_2D, - VK_IMAGE_TYPE_1D, - VK_IMAGE_TYPE_2D, - VK_IMAGE_TYPE_3D - }; - ERR_FAIL_INDEX_V(p_format.type, TEXTURE_TYPE_MAX, RID()); - image_create_info.imageType = image_type[p_format.type]; + image_create_info.imageType = vulkan_image_type[p_format.type]; ERR_FAIL_COND_V_MSG(p_format.width < 1, RID(), "Width must be equal or greater than 1 for all textures"); @@ -1574,6 +1559,9 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T if (p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT) { image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; } + if (p_format.usage_bits & TEXTURE_USAGE_CAN_RETRIEVE_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + } image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; image_create_info.queueFamilyIndexCount = 0; @@ -1651,7 +1639,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T VmaAllocationCreateInfo allocInfo; allocInfo.flags = 0; - allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + allocInfo.usage = p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT ? VMA_MEMORY_USAGE_CPU_ONLY : VMA_MEMORY_USAGE_GPU_ONLY; allocInfo.requiredFlags = 0; allocInfo.preferredFlags = 0; allocInfo.memoryTypeBits = 0; @@ -1906,8 +1894,8 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con ERR_FAIL_COND_V(p_layer >= layer_count, ERR_INVALID_PARAMETER); uint32_t width, height; - uint32_t image_size = get_image_format_required_size(texture->format, texture->width, texture->height, 1, texture->mipmaps, &width, &height); - uint32_t required_size = image_size * texture->depth; + uint32_t image_size = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, texture->mipmaps, &width, &height); + uint32_t required_size = image_size; uint32_t required_align = get_compressed_image_format_block_byte_size(texture->format); if (required_align == 1) { required_align = get_image_format_pixel_size(texture->format); @@ -1950,14 +1938,15 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con uint32_t mipmap_offset = 0; for (uint32_t mm_i = 0; mm_i < texture->mipmaps; mm_i++) { - uint32_t image_total = get_image_format_required_size(texture->format, texture->width, texture->height, 1, mm_i + 1, &width, &height); + uint32_t depth; + uint32_t image_total = get_image_format_required_size(texture->format, texture->width, texture->height, texture->depth, mm_i + 1, &width, &height, &depth); const uint8_t *read_ptr_mipmap = r.ptr() + mipmap_offset; image_size = image_total - mipmap_offset; - for (uint32_t z = 0; z < texture->depth; z++) { //for 3D textures, depth may be > 0 + for (uint32_t z = 0; z < depth; z++) { //for 3D textures, depth may be > 0 - const uint8_t *read_ptr = read_ptr_mipmap + image_size * z; + const uint8_t *read_ptr = read_ptr_mipmap + image_size * z / depth; for (uint32_t x = 0; x < width; x += region_size) { for (uint32_t y = 0; y < height; y += region_size) { @@ -2087,6 +2076,260 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con return OK; } +PoolVector RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer) { + + uint32_t width, height, depth; + uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps, &width, &height, &depth); + + PoolVector image_data; + image_data.resize(image_size); + + void *img_mem; + vmaMapMemory(allocator, p_allocation, &img_mem); + + uint32_t blockw, blockh; + get_compressed_image_format_block_dimensions(tex->format, blockw, blockh); + uint32_t block_size = get_compressed_image_format_block_byte_size(tex->format); + uint32_t pixel_size = get_image_format_pixel_size(tex->format); + + { + PoolVector::Write w = image_data.write(); + + uint32_t mipmap_offset = 0; + for (uint32_t mm_i = 0; mm_i < tex->mipmaps; mm_i++) { + + uint32_t image_total = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, mm_i + 1, &width, &height, &depth); + + uint8_t *write_ptr_mipmap = w.ptr() + mipmap_offset; + image_size = image_total - mipmap_offset; + + VkImageSubresource image_sub_resorce; + image_sub_resorce.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_sub_resorce.arrayLayer = p_layer; + image_sub_resorce.mipLevel = mm_i; + VkSubresourceLayout layout; + vkGetImageSubresourceLayout(device, p_image, &image_sub_resorce, &layout); + + for (uint32_t z = 0; z < depth; z++) { + uint8_t *write_ptr = write_ptr_mipmap + z * image_size / depth; + const uint8_t *slice_read_ptr = ((uint8_t *)img_mem) + layout.offset + z * layout.depthPitch; + + if (block_size > 1) { + //compressed + uint32_t line_width = (block_size * (width / blockw)); + for (uint32_t y = 0; y < height / blockh; y++) { + const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch; + uint8_t *wptr = write_ptr + y * line_width; + + copymem(wptr, rptr, line_width); + } + + } else { + //uncompressed + for (uint32_t y = 0; y < height; y++) { + const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch; + uint8_t *wptr = write_ptr + y * pixel_size * width; + copymem(wptr, rptr, pixel_size * width); + } + } + } + + mipmap_offset = image_total; + } + } + + vmaUnmapMemory(allocator, p_allocation); + + return image_data; +} + +PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t p_layer) { + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND_V(!tex, PoolVector()); + + ERR_FAIL_COND_V_MSG(tex->bound, PoolVector(), + "Texture can't be retrieved while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); + ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_RETRIEVE_BIT), PoolVector(), + "Texture requires the TEXTURE_USAGE_CAN_RETRIEVE_BIT in order to be retrieved."); + + uint32_t layer_count = tex->layers; + if (tex->type == TEXTURE_TYPE_CUBE || tex->type == TEXTURE_TYPE_CUBE_ARRAY) { + layer_count *= 6; + } + ERR_FAIL_COND_V(p_layer >= layer_count, PoolVector()); + + if (tex->usage_flags & TEXTURE_USAGE_CPU_READ_BIT) { + //does not need anything fancy, map and read. + return _texture_get_data_from_image(tex, tex->image, tex->allocation, p_layer); + } else { + VkImageCreateInfo image_create_info; + image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_create_info.pNext = NULL; + image_create_info.flags = 0; + image_create_info.imageType = vulkan_image_type[tex->type]; + image_create_info.format = vulkan_formats[tex->format]; + image_create_info.extent.width = tex->width; + image_create_info.extent.height = tex->height; + image_create_info.extent.depth = tex->depth; + image_create_info.mipLevels = tex->mipmaps; + image_create_info.arrayLayers = 1; //for retrieving, only one layer + image_create_info.samples = rasterization_sample_count[tex->samples]; + image_create_info.tiling = VK_IMAGE_TILING_LINEAR; // for retrieving, linear is recommended + image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; + image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_create_info.queueFamilyIndexCount = 0; + image_create_info.pQueueFamilyIndices = NULL; + image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + VmaAllocationCreateInfo allocInfo; + allocInfo.flags = 0; + allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; + allocInfo.requiredFlags = 0; + allocInfo.preferredFlags = 0; + allocInfo.memoryTypeBits = 0; + allocInfo.pool = NULL; + allocInfo.pUserData = NULL; + + VkImage image; + VmaAllocation allocation; + VmaAllocationInfo allocation_info; + + //Allocate the image + VkResult err = vmaCreateImage(allocator, &image_create_info, &allocInfo, &image, &allocation, &allocation_info); + ERR_FAIL_COND_V(err, PoolVector()); + + VkCommandBuffer command_buffer = frames[frame].setup_command_buffer; + //PRE Copy the image + + { //Source + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + image_memory_barrier.oldLayout = tex->unbound_layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = tex->image; + image_memory_barrier.subresourceRange.aspectMask = tex->aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = tex->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + { //Dest + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + 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.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = tex->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + //COPY + + { + + for (uint32_t i = 0; i < tex->mipmaps; i++) { + + uint32_t mm_width, mm_height, mm_depth; + get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, i + 1, &mm_width, &mm_height, &mm_depth); + + VkImageCopy image_copy_region; + image_copy_region.srcSubresource.aspectMask = tex->aspect_mask; + image_copy_region.srcSubresource.baseArrayLayer = p_layer; + image_copy_region.srcSubresource.layerCount = 1; + image_copy_region.srcSubresource.mipLevel = i; + image_copy_region.srcOffset.x = 0; + image_copy_region.srcOffset.y = 0; + image_copy_region.srcOffset.z = 0; + + image_copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_copy_region.dstSubresource.baseArrayLayer = p_layer; + image_copy_region.dstSubresource.layerCount = 1; + image_copy_region.dstSubresource.mipLevel = i; + image_copy_region.dstOffset.x = 0; + image_copy_region.dstOffset.y = 0; + image_copy_region.dstOffset.z = 0; + + image_copy_region.extent.width = mm_width; + image_copy_region.extent.height = mm_height; + image_copy_region.extent.depth = mm_depth; + + vkCmdCopyImage(command_buffer, tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region); + print_line("copying mipmap " + itos(i) + " w: " + itos(mm_width) + " h " + itos(mm_height) + " d " + itos(mm_depth)); + } + } + + // RESTORE LAYOUT for SRC and DST + + { //restore src + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + image_memory_barrier.newLayout = tex->unbound_layout; + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = tex->image; + image_memory_barrier.subresourceRange.aspectMask = tex->aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = tex->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + { //make dst readable + + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_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.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = tex->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + //flush everything so memory can be safely mapped + _flush(true, false); + + PoolVector ret = _texture_get_data_from_image(tex, image, allocation, p_layer); + vmaDestroyImage(allocator, image, allocation); + return ret; + } +} + bool RenderingDeviceVulkan::texture_is_shared(RID p_texture) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!tex, false); @@ -5292,6 +5535,42 @@ void RenderingDeviceVulkan::advance_frame() { } } +void RenderingDeviceVulkan::_flush(bool p_setup, bool p_draw) { + + //not doing this crashes RADV (undefined behavior) + if (p_setup) { + vkEndCommandBuffer(frames[frame].setup_command_buffer); + } + if (p_draw) { + vkEndCommandBuffer(frames[frame].draw_command_buffer); + } + context->flush(p_setup, p_draw); + //re-create the setup command + if (p_setup) { + VkCommandBufferBeginInfo cmdbuf_begin; + cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdbuf_begin.pNext = NULL; + cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + cmdbuf_begin.pInheritanceInfo = NULL; + + VkResult err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND(err); + context->set_setup_buffer(frames[frame].setup_command_buffer); //append now so it's added before everything else + } + + if (p_draw) { + VkCommandBufferBeginInfo cmdbuf_begin; + cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdbuf_begin.pNext = NULL; + cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + cmdbuf_begin.pInheritanceInfo = NULL; + + VkResult err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND(err); + context->append_command_buffer(frames[frame].draw_command_buffer); + } +} + void RenderingDeviceVulkan::initialize(VulkanContext *p_context) { context = p_context; @@ -5413,7 +5692,7 @@ void RenderingDeviceVulkan::finalize() { //free all resources - context->flush(false, false); + _flush(false, false); _free_rids(pipeline_owner, "Pipeline"); _free_rids(uniform_set_owner, "UniformSet"); -- cgit v1.2.3 From a7b2ac7bb1b5f9155866382f14138e86e52efded Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Thu, 4 Jul 2019 22:54:32 -0300 Subject: Normalmapping and Specularmapping working in 2D engine Added support for Sprite, AnimatedSprite and Polygon2D (should add for tileset eventually). --- drivers/vulkan/rendering_device_vulkan.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 3354454fce..eef6cf0086 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1613,6 +1613,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T } if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT && !(flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + printf("vkformat: %x\n", image_create_info.format); ERR_FAIL_V_MSG(RID(), "Format " + format_text + " does not support usage as depth-stencil attachment."); } @@ -1664,7 +1665,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T //set bound and unbound layouts if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - texture.aspect_mask = TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + texture.aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) { texture.unbound_layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; @@ -3168,7 +3169,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(VectorgetQualifier().hasOffset()) { + if (reflection.getType()->getQualifier().hasOffset() || reflection.name.find(".") != std::string::npos) { //member of uniform block? return true; } @@ -4126,7 +4127,7 @@ bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) { return uniform_set_owner.owns(p_uniform_set); } -Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, void *p_data, bool p_sync_with_draw) { +Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, bool p_sync_with_draw) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG(draw_list && p_sync_with_draw, ERR_INVALID_PARAMETER, -- cgit v1.2.3 From ef083a583b3bd833d36fadb80a9ee8e9081d394e Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Wed, 10 Jul 2019 17:44:55 -0300 Subject: Modified light rendering to make it more compatible. Modified polygon management to make it more compatible with MoltenVK --- drivers/vulkan/rendering_device_vulkan.cpp | 130 +++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index eef6cf0086..7ed87bf1fe 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1866,6 +1866,93 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID return id; } +RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, int p_layer, int p_mipmap) { + + Texture *src_texture = texture_owner.getornull(p_with_texture); + ERR_FAIL_COND_V(!src_texture, RID()); + + if (src_texture->owner.is_valid()) { //ahh this is a share + p_with_texture = src_texture->owner; + src_texture = texture_owner.getornull(src_texture->owner); + ERR_FAIL_COND_V(!src_texture, RID()); //this is a bug + } + + //create view + + Texture texture = *src_texture; + + uint32_t array_layer_multiplier = 1; + if (texture.type == TEXTURE_TYPE_CUBE_ARRAY || texture.type == TEXTURE_TYPE_CUBE) { + array_layer_multiplier = 6; + } + + VkImageViewCreateInfo image_view_create_info; + image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + image_view_create_info.pNext = NULL; + image_view_create_info.flags = 0; + image_view_create_info.image = texture.image; + + static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = { + VK_IMAGE_VIEW_TYPE_1D, + VK_IMAGE_VIEW_TYPE_2D, + VK_IMAGE_VIEW_TYPE_2D, + VK_IMAGE_VIEW_TYPE_2D, + VK_IMAGE_VIEW_TYPE_1D, + VK_IMAGE_VIEW_TYPE_2D, + VK_IMAGE_VIEW_TYPE_2D, + }; + + image_view_create_info.viewType = view_types[texture.type]; + if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) { + image_view_create_info.format = vulkan_formats[texture.format]; + } else { + ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID()); + + ERR_FAIL_COND_V_MSG(texture.allowed_shared_formats.find(p_view.format_override) == -1, RID(), + "Format override is not in the list of allowed shareable formats for original texture."); + image_view_create_info.format = vulkan_formats[p_view.format_override]; + } + + static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = { + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_ZERO, + VK_COMPONENT_SWIZZLE_ONE, + VK_COMPONENT_SWIZZLE_R, + VK_COMPONENT_SWIZZLE_G, + VK_COMPONENT_SWIZZLE_B, + VK_COMPONENT_SWIZZLE_A + }; + + image_view_create_info.components.r = component_swizzles[p_view.swizzle_r]; + image_view_create_info.components.g = component_swizzles[p_view.swizzle_g]; + image_view_create_info.components.b = component_swizzles[p_view.swizzle_b]; + image_view_create_info.components.a = component_swizzles[p_view.swizzle_a]; + + ERR_FAIL_INDEX_V(p_mipmap, texture.mipmaps, RID()); + image_view_create_info.subresourceRange.baseMipLevel = p_mipmap; + image_view_create_info.subresourceRange.levelCount = 1; + image_view_create_info.subresourceRange.layerCount = 1; + image_view_create_info.subresourceRange.baseArrayLayer = p_layer; + + if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + } else { + image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } + + VkResult err = vkCreateImageView(device, &image_view_create_info, NULL, &texture.view); + + if (err) { + ERR_FAIL_V(RID()); + } + + texture.owner = p_with_texture; + RID id = texture_owner.make_rid(texture); + _add_dependency(id, p_with_texture); + + return id; +} + Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, const PoolVector &p_data, bool p_sync_with_draw) { _THREAD_SAFE_METHOD_ @@ -2618,10 +2705,18 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c fb_format.E = E; fb_format.color_attachments = color_references; fb_format.render_pass = render_pass; + fb_format.samples = p_format[0].samples; framebuffer_formats[id] = fb_format; return id; } +RenderingDevice::TextureSamples RenderingDeviceVulkan::framebuffer_format_get_texture_samples(FramebufferFormatID p_format) { + Map::Element *E = framebuffer_formats.find(p_format); + ERR_FAIL_COND_V(!E, TEXTURE_SAMPLES_1); + + return E->get().samples; +} + /***********************/ /**** RENDER TARGET ****/ /***********************/ @@ -5689,6 +5784,41 @@ void RenderingDeviceVulkan::_free_rids(T &p_owner, const char *p_type) { } } +int RenderingDeviceVulkan::limit_get(Limit p_limit) { + switch (p_limit) { + case LIMIT_MAX_BOUND_UNIFORM_SETS: return limits.maxBoundDescriptorSets; + case LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS: return limits.maxColorAttachments; + case LIMIT_MAX_TEXTURES_PER_UNIFORM_SET: return limits.maxDescriptorSetSampledImages; + case LIMIT_MAX_SAMPLERS_PER_UNIFORM_SET: return limits.maxDescriptorSetSamplers; + case LIMIT_MAX_STORAGE_BUFFERS_PER_UNIFORM_SET: return limits.maxDescriptorSetStorageBuffers; + case LIMIT_MAX_STORAGE_IMAGES_PER_UNIFORM_SET: return limits.maxDescriptorSetStorageImages; + case LIMIT_MAX_UNIFORM_BUFFERS_PER_UNIFORM_SET: return limits.maxDescriptorSetUniformBuffers; + case LIMIT_MAX_DRAW_INDEXED_INDEX: return limits.maxDrawIndexedIndexValue; + case LIMIT_MAX_FRAMEBUFFER_HEIGHT: return limits.maxFramebufferHeight; + case LIMIT_MAX_FRAMEBUFFER_WIDTH: return limits.maxFramebufferWidth; + case LIMIT_MAX_TEXTURE_ARRAY_LAYERS: return limits.maxImageArrayLayers; + case LIMIT_MAX_TEXTURE_SIZE_1D: return limits.maxImageDimension1D; + case LIMIT_MAX_TEXTURE_SIZE_2D: return limits.maxImageDimension2D; + case LIMIT_MAX_TEXTURE_SIZE_3D: return limits.maxImageDimension3D; + case LIMIT_MAX_TEXTURE_SIZE_CUBE: return limits.maxImageDimensionCube; + case LIMIT_MAX_TEXTURES_PER_SHADER_STAGE: return limits.maxPerStageDescriptorSampledImages; + case LIMIT_MAX_SAMPLERS_PER_SHADER_STAGE: return limits.maxPerStageDescriptorSamplers; + case LIMIT_MAX_STORAGE_BUFFERS_PER_SHADER_STAGE: return limits.maxPerStageDescriptorStorageBuffers; + case LIMIT_MAX_STORAGE_IMAGES_PER_SHADER_STAGE: return limits.maxPerStageDescriptorStorageImages; + case LIMIT_MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE: return limits.maxPerStageDescriptorUniformBuffers; + case LIMIT_MAX_PUSH_CONSTANT_SIZE: return limits.maxPushConstantsSize; + case LIMIT_MAX_UNIFORM_BUFFER_SIZE: return limits.maxUniformBufferRange; + case LIMIT_MAX_VERTEX_INPUT_ATTRIBUTE_OFFSET: return limits.maxVertexInputAttributeOffset; + case LIMIT_MAX_VERTEX_INPUT_ATTRIBUTES: return limits.maxVertexInputAttributes; + case LIMIT_MAX_VERTEX_INPUT_BINDINGS: return limits.maxVertexInputBindings; + case LIMIT_MAX_VERTEX_INPUT_BINDING_STRIDE: return limits.maxVertexInputBindingStride; + case LIMIT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT: return limits.minUniformBufferOffsetAlignment; + default: ERR_FAIL_V(0); + } + + return 0; +} + void RenderingDeviceVulkan::finalize() { //free all resources -- cgit v1.2.3 From 8bbbb973361f367a4888629c571fb6f43581269d Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sun, 21 Jul 2019 11:31:30 -0300 Subject: Completed material/2D shader support (missing SCREEN_TEXTURE) --- drivers/vulkan/rendering_device_vulkan.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 7ed87bf1fe..abbfde0b59 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -4119,13 +4119,13 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, } break; case UNIFORM_TYPE_UNIFORM_BUFFER: { ERR_FAIL_COND_V_MSG(uniform.ids.size() != 1, RID(), - "Uniform buffer (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.ids.size()) + " provided)."); + "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.ids.size()) + " provided)."); Buffer *buffer = uniform_buffer_owner.getornull(uniform.ids[0]); - ERR_FAIL_COND_V_MSG(!buffer, RID(), "Uniform buffer (binding: " + itos(uniform.binding) + ") is invalid."); + ERR_FAIL_COND_V_MSG(!buffer, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") is invalid."); ERR_FAIL_COND_V_MSG(buffer->size != (uint32_t)set_uniform.length, RID(), - "Uniform buffer (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ")."); + "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ")."); write.dstArrayElement = 0; write.descriptorCount = 1; @@ -4137,13 +4137,13 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, } break; case UNIFORM_TYPE_STORAGE_BUFFER: { ERR_FAIL_COND_V_MSG(uniform.ids.size() != 1, RID(), - "Storage buffer (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.ids.size()) + " provided)."); + "Storage buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.ids.size()) + " provided)."); Buffer *buffer = storage_buffer_owner.getornull(uniform.ids[0]); - ERR_FAIL_COND_V_MSG(!buffer, RID(), "Storage buffer (binding: " + itos(uniform.binding) + ") is invalid."); + ERR_FAIL_COND_V_MSG(!buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid."); ERR_FAIL_COND_V_MSG(buffer->size != (uint32_t)set_uniform.length, RID(), - "Storage buffer (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ")."); + "Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ")."); write.dstArrayElement = 0; write.descriptorCount = 1; -- cgit v1.2.3 From 0586e184490fd132f99acb1a67c788959cfdbade Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sat, 27 Jul 2019 10:23:24 -0300 Subject: Custom material support seems complete. --- drivers/vulkan/rendering_device_vulkan.cpp | 466 ++++++++++++++++++++++++----- 1 file changed, 383 insertions(+), 83 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index abbfde0b59..b2d5a3781c 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1009,6 +1009,7 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFor uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh, uint32_t *r_depth) { + ERR_FAIL_COND_V(p_mipmaps == 0, 0); uint32_t w = p_width; uint32_t h = p_height; uint32_t d = p_depth; @@ -1559,10 +1560,14 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T if (p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT) { image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; } - if (p_format.usage_bits & TEXTURE_USAGE_CAN_RETRIEVE_BIT) { + if (p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_FROM_BIT) { image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; } + if (p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_TO_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } + image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; image_create_info.queueFamilyIndexCount = 0; image_create_info.pQueueFamilyIndices = NULL; @@ -1866,7 +1871,7 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID return id; } -RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, int p_layer, int p_mipmap) { +RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap) { Texture *src_texture = texture_owner.getornull(p_with_texture); ERR_FAIL_COND_V(!src_texture, RID()); @@ -1879,12 +1884,18 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p //create view - Texture texture = *src_texture; + ERR_FAIL_INDEX_V(p_mipmap, src_texture->mipmaps, RID()); uint32_t array_layer_multiplier = 1; - if (texture.type == TEXTURE_TYPE_CUBE_ARRAY || texture.type == TEXTURE_TYPE_CUBE) { + if (src_texture->type == TEXTURE_TYPE_CUBE_ARRAY || src_texture->type == TEXTURE_TYPE_CUBE) { array_layer_multiplier = 6; } + ERR_FAIL_INDEX_V(p_layer, src_texture->layers * array_layer_multiplier, RID()); + + Texture texture = *src_texture; + get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height); + texture.mipmaps = 1; + texture.layers = 1; VkImageViewCreateInfo image_view_create_info; image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; @@ -1928,7 +1939,6 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p image_view_create_info.components.b = component_swizzles[p_view.swizzle_b]; image_view_create_info.components.a = component_swizzles[p_view.swizzle_a]; - ERR_FAIL_INDEX_V(p_mipmap, texture.mipmaps, RID()); image_view_create_info.subresourceRange.baseMipLevel = p_mipmap; image_view_create_info.subresourceRange.levelCount = 1; image_view_create_info.subresourceRange.layerCount = 1; @@ -2237,8 +2247,8 @@ PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 ERR_FAIL_COND_V_MSG(tex->bound, PoolVector(), "Texture can't be retrieved while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); - ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_RETRIEVE_BIT), PoolVector(), - "Texture requires the TEXTURE_USAGE_CAN_RETRIEVE_BIT in order to be retrieved."); + ERR_FAIL_COND_V_MSG(!(tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), PoolVector(), + "Texture requires the TEXTURE_USAGE_CAN_COPY_FROM_BIT in order to be retrieved."); uint32_t layer_count = tex->layers; if (tex->type == TEXTURE_TYPE_CUBE || tex->type == TEXTURE_TYPE_CUBE_ARRAY) { @@ -2428,6 +2438,173 @@ bool RenderingDeviceVulkan::texture_is_valid(RID p_texture) { return texture_owner.owns(p_texture); } +Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw) { + + Texture *src_tex = texture_owner.getornull(p_from_texture); + ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER); + + ERR_FAIL_COND_V_MSG(p_sync_with_draw && src_tex->bound, ERR_INVALID_PARAMETER, + "Source texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); + ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT), ERR_INVALID_PARAMETER, + "Source texture requires the TEXTURE_USAGE_CAN_COPY_FROM_BIT in order to be retrieved."); + + uint32_t src_layer_count = src_tex->layers; + uint32_t src_width, src_height, src_depth; + get_image_format_required_size(src_tex->format, src_tex->width, src_tex->height, src_tex->depth, p_src_mipmap + 1, &src_width, &src_height, &src_depth); + if (src_tex->type == TEXTURE_TYPE_CUBE || src_tex->type == TEXTURE_TYPE_CUBE_ARRAY) { + src_layer_count *= 6; + } + + ERR_FAIL_COND_V(p_from.x < 0 || p_from.x + p_size.x > src_width, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_from.y < 0 || p_from.y + p_size.y > src_height, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_from.z < 0 || p_from.z + p_size.z > src_depth, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_src_mipmap >= src_tex->mipmaps, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_src_layer >= src_layer_count, ERR_INVALID_PARAMETER); + + Texture *dst_tex = texture_owner.getornull(p_to_texture); + ERR_FAIL_COND_V(!dst_tex, ERR_INVALID_PARAMETER); + + ERR_FAIL_COND_V_MSG(p_sync_with_draw && dst_tex->bound, ERR_INVALID_PARAMETER, + "Destination texture can't be copied while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); + ERR_FAIL_COND_V_MSG(!(dst_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER, + "Destination texture requires the TEXTURE_USAGE_CAN_COPY_TO_BIT in order to be retrieved."); + + uint32_t dst_layer_count = dst_tex->layers; + uint32_t dst_width, dst_height, dst_depth; + get_image_format_required_size(dst_tex->format, dst_tex->width, dst_tex->height, dst_tex->depth, p_dst_mipmap + 1, &dst_width, &dst_height, &dst_depth); + if (dst_tex->type == TEXTURE_TYPE_CUBE || dst_tex->type == TEXTURE_TYPE_CUBE_ARRAY) { + dst_layer_count *= 6; + } + + ERR_FAIL_COND_V(p_to.x < 0 || p_to.x + p_size.x > dst_width, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_to.y < 0 || p_to.y + p_size.y > dst_height, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_to.z < 0 || p_to.z + p_size.z > dst_depth, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_dst_mipmap >= dst_tex->mipmaps, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_dst_layer >= dst_layer_count, ERR_INVALID_PARAMETER); + + VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; + + { + + //PRE Copy the image + + { //Source + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + image_memory_barrier.oldLayout = src_tex->unbound_layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = src_tex->image; + image_memory_barrier.subresourceRange.aspectMask = src_tex->aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + { //Dest + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.oldLayout = dst_tex->unbound_layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = dst_tex->image; + image_memory_barrier.subresourceRange.aspectMask = dst_tex->aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = p_dst_mipmap; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = p_dst_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + //COPY + + { + + VkImageCopy image_copy_region; + image_copy_region.srcSubresource.aspectMask = src_tex->aspect_mask; + image_copy_region.srcSubresource.baseArrayLayer = p_src_layer; + image_copy_region.srcSubresource.layerCount = 1; + image_copy_region.srcSubresource.mipLevel = p_src_mipmap; + image_copy_region.srcOffset.x = p_from.x; + image_copy_region.srcOffset.y = p_from.y; + image_copy_region.srcOffset.z = p_from.z; + + image_copy_region.dstSubresource.aspectMask = src_tex->aspect_mask; + image_copy_region.dstSubresource.baseArrayLayer = p_dst_layer; + image_copy_region.dstSubresource.layerCount = 1; + image_copy_region.dstSubresource.mipLevel = p_dst_mipmap; + image_copy_region.dstOffset.x = p_to.x; + image_copy_region.dstOffset.y = p_to.y; + image_copy_region.dstOffset.z = p_to.z; + + image_copy_region.extent.width = p_size.x; + image_copy_region.extent.height = p_size.y; + image_copy_region.extent.depth = p_size.z; + + vkCmdCopyImage(command_buffer, src_tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region); + } + + // RESTORE LAYOUT for SRC and DST + + { //restore src + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + image_memory_barrier.newLayout = src_tex->unbound_layout; + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = src_tex->image; + image_memory_barrier.subresourceRange.aspectMask = src_tex->aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap; + image_memory_barrier.subresourceRange.levelCount = src_tex->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + { //make dst readable + + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_memory_barrier.newLayout = dst_tex->unbound_layout; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = dst_tex->image; + image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap; + image_memory_barrier.subresourceRange.levelCount = 1; + image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; + image_memory_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + } + + return OK; +} + bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const { ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false); @@ -3152,10 +3329,29 @@ static VkShaderStageFlagBits shader_stage_masks[RenderingDevice::SHADER_STAGE_MA VK_SHADER_STAGE_COMPUTE_BIT, }; -bool RenderingDeviceVulkan::_uniform_add_binding(Vector > &bindings, Vector > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, Shader::PushConstant &push_constant, String *r_error) { +String RenderingDeviceVulkan::_shader_uniform_debug(RID p_shader, int p_set) { + String ret; + const Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, String()); + for (int i = 0; i < shader->sets.size(); i++) { + if (p_set >= 0 && i != p_set) { + continue; + } + for (int j = 0; j < shader->sets[i].uniform_info.size(); j++) { + const UniformInfo &ui = shader->sets[i].uniform_info[j]; + if (ret != String()) { + ret += "\n"; + } + ret += "Set: " + itos(i) + " Binding: " + itos(ui.binding) + " Type: " + shader_uniform_names[ui.type] + " Length: " + itos(ui.length); + } + } + return ret; +} + +bool RenderingDeviceVulkan::_uniform_add_binding(Vector > &bindings, Vector > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, Shader::PushConstant &push_constant, String *r_error) { VkDescriptorSetLayoutBinding layout_binding; - Shader::UniformInfo info; + UniformInfo info; switch (reflection.getType()->getBasicType()) { case glslang::EbtSampler: { @@ -3285,6 +3481,13 @@ bool RenderingDeviceVulkan::_uniform_add_binding(VectorgetQualifier().hasSet() ? reflection.getType()->getQualifier().layoutSet : 0; + if (set >= MAX_UNIFORM_SETS) { + if (r_error) { + *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ")."; + } + return false; + } + if (set >= limits.maxBoundDescriptorSets) { if (r_error) { *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ")."; @@ -3366,7 +3569,7 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector > bindings; - Vector > uniform_info; + Vector > uniform_info; Shader::PushConstant push_constant; push_constant.push_constant_size = 0; push_constant.push_constants_vk_stage = 0; @@ -3451,7 +3654,7 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector::Element *E = uniform_set_format_cache.find(usformat); + if (E) { + format = E->get(); + } else { + format = uniform_set_format_cache.size() + 1; + uniform_set_format_cache.insert(usformat, format); + } } shader.sets.push_back(set); - shader.set_hashes.push_back(h); + shader.set_formats.push_back(format); } } @@ -3873,7 +4082,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, const Uniform *uniforms = p_uniforms.ptr(); uint32_t set_uniform_count = set.uniform_info.size(); - const Shader::UniformInfo *set_uniforms = set.uniform_info.ptr(); + const UniformInfo *set_uniforms = set.uniform_info.ptr(); Vector writes; DescriptorPoolKey pool_key; @@ -3886,7 +4095,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, Vector attachable_textures; for (uint32_t i = 0; i < set_uniform_count; i++) { - const Shader::UniformInfo &set_uniform = set_uniforms[i]; + const UniformInfo &set_uniform = set_uniforms[i]; int uniform_idx = -1; for (int j = 0; j < (int)uniform_count; j++) { if (uniforms[j].binding == set_uniform.binding) { @@ -4191,9 +4400,10 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, uniform_set.pool = pool; uniform_set.pool_key = pool_key; uniform_set.descriptor_set = descriptor_set; - uniform_set.pipeline_layout = shader->pipeline_layout; - uniform_set.hash = shader->set_hashes[p_shader_set]; + uniform_set.format = shader->set_formats[p_shader_set]; uniform_set.attachable_textures = attachable_textures; + uniform_set.shader_set = p_shader_set; + uniform_set.shader_id = p_shader; RID id = uniform_set_owner.make_rid(uniform_set); //add dependencies @@ -4592,19 +4802,22 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma VkResult err = vkCreateGraphicsPipelines(device, NULL, 1, &graphics_pipeline_create_info, NULL, &pipeline.pipeline); ERR_FAIL_COND_V(err, RID()); - pipeline.dynamic_state = p_dynamic_state_flags; - pipeline.framebuffer_format = p_framebuffer_format; - pipeline.vertex_format = p_vertex_format; - pipeline.uses_restart_indices = input_assembly_create_info.primitiveRestartEnable; - pipeline.set_hashes = shader->set_hashes; - pipeline.push_constant_size = shader->push_constant.push_constant_size; + pipeline.set_formats = shader->set_formats; pipeline.push_constant_stages = shader->push_constant.push_constants_vk_stage; pipeline.pipeline_layout = shader->pipeline_layout; + pipeline.shader = p_shader; + pipeline.push_constant_size = shader->push_constant.push_constant_size; + +#ifdef DEBUG_ENABLED + pipeline.validation.dynamic_state = p_dynamic_state_flags; + pipeline.validation.framebuffer_format = p_framebuffer_format; + pipeline.validation.vertex_format = p_vertex_format; + pipeline.validation.uses_restart_indices = input_assembly_create_info.primitiveRestartEnable; static const uint32_t primitive_divisor[RENDER_PRIMITIVE_MAX] = { 1, 2, 1, 1, 1, 3, 1, 1, 1, 1, 1 }; - pipeline.primitive_divisor = primitive_divisor[p_render_primitive]; + pipeline.validation.primitive_divisor = primitive_divisor[p_render_primitive]; static const uint32_t primitive_minimum[RENDER_PRIMITIVE_MAX] = { 1, 2, @@ -4618,8 +4831,8 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma 3, 1, }; - pipeline.primitive_minimum = primitive_minimum[p_render_primitive]; - + pipeline.validation.primitive_minimum = primitive_minimum[p_render_primitive]; +#endif //create ID to associate with this pipeline RID id = pipeline_owner.make_rid(pipeline); //now add aall the dependencies @@ -4756,6 +4969,8 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu Texture *texture = texture_owner.getornull(p_framebuffer->texture_ids[i]); ERR_FAIL_COND_V(!texture, ERR_BUG); attachments.push_back(texture->view); + ERR_FAIL_COND_V(texture->width != p_framebuffer->size.width, ERR_BUG); + ERR_FAIL_COND_V(texture->height != p_framebuffer->size.height, ERR_BUG); } framebuffer_create_info.attachmentCount = attachments.size(); framebuffer_create_info.pAttachments = attachments.ptr(); @@ -5082,51 +5297,97 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif const RenderPipeline *pipeline = pipeline_owner.getornull(p_render_pipeline); ERR_FAIL_COND(!pipeline); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND(pipeline->validation.framebuffer_format != dl->validation.framebuffer_format); +#endif + + if (p_render_pipeline == dl->state.pipeline) { + return; //redundant state, return. + } - ERR_FAIL_COND(pipeline->framebuffer_format != dl->validation.framebuffer_format); + dl->state.pipeline = p_render_pipeline; + dl->state.pipeline_layout = pipeline->pipeline_layout; vkCmdBindPipeline(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline); + if (dl->state.pipeline_shader != pipeline->shader) { + // shader changed, so descriptor sets may become incompatible. + + //go through ALL sets, and unbind them (and all those above) if the format is different + + uint32_t pcount = pipeline->set_formats.size(); //formats count in this pipeline + dl->state.set_count = MAX(dl->state.set_count, pcount); + const uint32_t *pformats = pipeline->set_formats.ptr(); //pipeline set formats + + bool sets_valid = true; //once invalid, all above become invalid + for (uint32_t i = 0; i < pcount; i++) { + //if a part of the format is different, invalidate it (and the rest) + if (!sets_valid || dl->state.sets[i].pipeline_expected_format != pformats[i]) { + dl->state.sets[i].bound = false; + dl->state.sets[i].pipeline_expected_format = pformats[i]; + sets_valid = false; + } + } + + for (uint32_t i = pcount; i < dl->state.set_count; i++) { + //unbind the ones above (not used) if exist + dl->state.sets[i].bound = false; + } + + dl->state.set_count = pcount; //update set count + + if (pipeline->push_constant_size) { + dl->state.pipeline_push_constant_stages = pipeline->push_constant_stages; +#ifdef DEBUG_ENABLED + dl->validation.pipeline_push_constant_suppplied = false; +#endif + } + } + +#ifdef DEBUG_ENABLED //update render pass pipeline info dl->validation.pipeline_active = true; - dl->validation.pipeline_dynamic_state = pipeline->dynamic_state; - dl->validation.pipeline_vertex_format = pipeline->vertex_format; - dl->validation.pipeline_uses_restart_indices = pipeline->uses_restart_indices; - dl->validation.pipeline_primitive_divisor = pipeline->primitive_divisor; - - dl->validation.pipeline_primitive_minimum = pipeline->primitive_minimum; - dl->validation.pipeline_set_hashes = pipeline->set_hashes; + dl->validation.pipeline_dynamic_state = pipeline->validation.dynamic_state; + dl->validation.pipeline_vertex_format = pipeline->validation.vertex_format; + dl->validation.pipeline_uses_restart_indices = pipeline->validation.uses_restart_indices; + dl->validation.pipeline_primitive_divisor = pipeline->validation.primitive_divisor; + dl->validation.pipeline_primitive_minimum = pipeline->validation.primitive_minimum; dl->validation.pipeline_push_constant_size = pipeline->push_constant_size; - if (pipeline->push_constant_size) { - dl->validation.pipeline_push_constant_stages = pipeline->push_constant_stages; - dl->validation.pipeline_push_constant_suppplied = false; - dl->validation.pipeline_push_constant_layout = pipeline->pipeline_layout; - } +#endif } void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) { - ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets, + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index > MAX_UNIFORM_SETS, "Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ")."); +#endif DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); + +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif const UniformSet *uniform_set = uniform_set_owner.getornull(p_uniform_set); ERR_FAIL_COND(!uniform_set); - if ((uint32_t)dl->validation.set_hashes.size() <= p_index) { - uint32_t csize = dl->validation.set_hashes.size(); - uint32_t new_size = p_index + 1; - dl->validation.set_hashes.resize(new_size); - for (uint32_t i = csize; i < new_size; i++) { - dl->validation.set_hashes.write[i] = 0; - } + if (p_index > dl->state.set_count) { + dl->state.set_count = p_index; } + dl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; //update set pointer + dl->state.sets[p_index].bound = false; //needs rebind + dl->state.sets[p_index].uniform_set_format = uniform_set->format; + dl->state.sets[p_index].uniform_set = p_uniform_set; + +#ifdef DEBUG_ENABLED { //validate that textures bound are not attached as framebuffer bindings uint32_t attachable_count = uniform_set->attachable_textures.size(); const RID *attachable_ptr = uniform_set->attachable_textures.ptr(); @@ -5139,38 +5400,53 @@ void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_ } } } - - dl->validation.set_hashes.write[p_index] = uniform_set->hash; - - vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, uniform_set->pipeline_layout, p_index, 1, &uniform_set->descriptor_set, 0, NULL); +#endif } void RenderingDeviceVulkan::draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif const VertexArray *vertex_array = vertex_array_owner.getornull(p_vertex_array); ERR_FAIL_COND(!vertex_array); + + if (dl->state.vertex_array == p_vertex_array) { + return; //already set + } + + dl->state.vertex_array = p_vertex_array; + +#ifdef DEBUG_ENABLED dl->validation.vertex_format = vertex_array->description; dl->validation.vertex_array_size = vertex_array->vertex_count; dl->validation.vertex_max_instances_allowed = vertex_array->max_instances_allowed; - +#endif vkCmdBindVertexBuffers(dl->command_buffer, 0, vertex_array->buffers.size(), vertex_array->buffers.ptr(), vertex_array->offsets.ptr()); } void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif const IndexArray *index_array = index_array_owner.getornull(p_index_array); ERR_FAIL_COND(!index_array); + if (dl->state.index_array == p_index_array) { + return; //already set + } + + dl->state.index_array = p_index_array; +#ifdef DEBUG_ENABLED dl->validation.index_array_size = index_array->indices; dl->validation.index_array_max_index = index_array->max_index; dl->validation.index_array_offset = index_array->offset; - +#endif vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, index_array->offset, index_array->index_type); } @@ -5187,10 +5463,15 @@ void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, void DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif + +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(p_data_size != dl->validation.pipeline_push_constant_size, "This render pipeline requires (" + itos(dl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")"); - - vkCmdPushConstants(dl->command_buffer, dl->validation.pipeline_push_constant_layout, dl->validation.pipeline_push_constant_stages, 0, p_data_size, p_data); +#endif + vkCmdPushConstants(dl->command_buffer, dl->state.pipeline_layout, dl->state.pipeline_push_constant_stages, 0, p_data_size, p_data); dl->validation.pipeline_push_constant_suppplied = true; } @@ -5198,8 +5479,11 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.pipeline_active, "No render pipeline was set before attempting to draw."); if (dl->validation.pipeline_vertex_format != INVALID_ID) { @@ -5219,30 +5503,39 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices ERR_FAIL_COND_MSG(!dl->validation.pipeline_push_constant_suppplied, "The shader in this pipeline requires a push constant to be set before drawing, but it's not present."); } - //compare hashes - if (dl->validation.pipeline_set_hashes.size()) { - ERR_FAIL_COND_MSG(dl->validation.pipeline_set_hashes.size() > dl->validation.set_hashes.size(), - "Render pipeline requires uniform sets which were not set at the time of drawing."); - uint32_t hash_count = dl->validation.pipeline_set_hashes.size(); - const uint32_t *phashes = dl->validation.pipeline_set_hashes.ptr(); - const uint32_t *shashes = dl->validation.set_hashes.ptr(); +#endif - for (uint32_t i = 0; i < hash_count; i++) { - if (phashes[i] == 0) { - continue; //not used by pipeline, no need to check - } - if (phashes[i] != shashes[i]) { - if (shashes[i] == 0) { - ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline"); - } else { - ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ") are not the same format as required by the pipeline shader."); - } + //Bind descriptor sets + + for (uint32_t i = 0; i < dl->state.set_count; i++) { + + if (dl->state.sets[i].pipeline_expected_format == 0) { + continue; //nothing expected by this pipeline + } +#ifdef DEBUG_ENABLED + if (dl->state.sets[i].pipeline_expected_format != dl->state.sets[i].uniform_set_format) { + + if (dl->state.sets[i].uniform_set_format == 0) { + ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline"); + } else if (uniform_set_owner.owns(dl->state.sets[i].uniform_set)) { + UniformSet *us = uniform_set_owner.getornull(dl->state.sets[i].uniform_set); + ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader)); + } else { + ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(dl->state.pipeline_shader)); } } +#endif + if (!dl->state.sets[i].bound) { + //All good, see if this requires re-binding + vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, dl->state.pipeline_layout, i, 1, &dl->state.sets[i].descriptor_set, 0, NULL); + dl->state.sets[i].bound = true; + } } if (p_use_indices) { + +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.index_array_size, "Draw command requested indices, but no index buffer was set."); if (dl->validation.pipeline_vertex_format != INVALID_ID) { @@ -5253,37 +5546,42 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices ERR_FAIL_COND_MSG(dl->validation.pipeline_uses_restart_indices != dl->validation.index_buffer_uses_restart_indices, "The usage of restart indices in index buffer does not match the render primitive in the pipeline."); - +#endif uint32_t to_draw = dl->validation.index_array_size; +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum, "Too few indices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ")."); ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0, "Index amount (" + itos(to_draw) + ") must be a multiple of the amount of indices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ")."); - +#endif vkCmdDrawIndexed(dl->command_buffer, to_draw, p_instances, dl->validation.index_array_offset, 0, 0); } else { +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID, "Draw command lacks indices, but pipeline format does not use vertices."); - +#endif uint32_t to_draw = dl->validation.vertex_array_size; +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum, "Too few vertices (" + itos(to_draw) + ") for the render primitive set in the render pipeline (" + itos(dl->validation.pipeline_primitive_minimum) + ")."); ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0, "Vertex amount (" + itos(to_draw) + ") must be a multiple of the amount of vertices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ")."); - +#endif vkCmdDraw(dl->command_buffer, to_draw, p_instances, 0, 0); } } void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) { DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); - +#endif Rect2i rect = p_rect; rect.position += dl->viewport.position; @@ -5303,7 +5601,9 @@ void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Re void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif VkRect2D scissor; scissor.offset.x = dl->viewport.position.x; -- cgit v1.2.3 From 60c7498cee169b2cd652045ec19bb526d76f9d61 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sun, 28 Jul 2019 13:42:15 -0300 Subject: Replaced GLSLang reflection by SPIRV-Reflect, eventually allowing to move GLSLang out. --- drivers/vulkan/rendering_device_vulkan.cpp | 255 ++++++++++++++++++++++++++++- 1 file changed, 246 insertions(+), 9 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index b2d5a3781c..7f4ebd5134 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1,10 +1,11 @@ #include "rendering_device_vulkan.h" -#include "drivers/vulkan/vulkan_context.h" - #include "core/hashfuncs.h" +#include "core/os/file_access.h" #include "core/project_settings.h" +#include "drivers/vulkan/vulkan_context.h" #include "thirdparty/glslang/SPIRV/GlslangToSpv.h" #include "thirdparty/glslang/glslang/Include/Types.h" +#include "thirdparty/spirv-reflect/spirv_reflect.h" void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) { @@ -2371,7 +2372,6 @@ PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 image_copy_region.extent.depth = mm_depth; vkCmdCopyImage(command_buffer, tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region); - print_line("copying mipmap " + itos(i) + " w: " + itos(mm_width) + " h " + itos(mm_height) + " d " + itos(mm_depth)); } } @@ -3568,7 +3568,7 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector > bindings; + Vector > set_bindings; Vector > uniform_info; Shader::PushConstant push_constant; push_constant.push_constant_size = 0; @@ -3652,11 +3652,27 @@ RID RenderingDeviceVulkan::shader_create_from_source(const VectorgetBasicType() == glslang::EbtBlock && reflection.getType()->getQualifier().storage == glslang::EvqUniform && reflection.getType()->getQualifier().layoutPushConstant) { + uint32_t len = reflection.size; + if (push_constant_debug.push_constant_size != 0 && push_constant_debug.push_constant_size != len) { + print_line("eep"); + } + + push_constant_debug.push_constant_size = len; + push_constant_debug.push_constants_vk_stage |= shader_stage_masks[p_stages[i].shader_stage]; + //print_line("Debug stage " + String(shader_stage_names[p_stages[i].shader_stage]) + " push constant size: " + itos(push_constant_debug.push_constant_size)); + } + } + + for (int j = 0; j < program.getNumUniformVariables(); j++) { if (!_uniform_add_binding(bindings, uniform_info, program.getUniform(j), p_stages[i].shader_stage, push_constant, r_error)) { return RID(); @@ -3698,11 +3714,233 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector SpirV; spv::SpvBuildLogger logger; glslang::SpvOptions spvOptions; glslang::GlslangToSpv(*program.getIntermediate(stages[p_stages[i].shader_stage]), SpirV, &logger, &spvOptions); + { + SpvReflectShaderModule module; + SpvReflectResult result = spvReflectCreateShaderModule(SpirV.size() * sizeof(uint32_t), &SpirV[0], &module); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed parsing shader."); + + uint32_t binding_count = 0; + result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, NULL); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating descriptor bindings."); + + uint32_t stage = p_stages[i].shader_stage; + + if (binding_count > 0) { + + //Parse bindings + + Vector bindings; + bindings.resize(binding_count); + result = spvReflectEnumerateDescriptorBindings(&module, &binding_count, bindings.ptrw()); + + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed getting descriptor bindings."); + + for (uint32_t j = 0; j < binding_count; j++) { + const SpvReflectDescriptorBinding &binding = *bindings[j]; + + VkDescriptorSetLayoutBinding layout_binding; + UniformInfo info; + + bool need_array_dimensions = false; + bool need_block_size = false; + + switch (binding.descriptor_type) { + case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; + info.type = UNIFORM_TYPE_SAMPLER; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + info.type = UNIFORM_TYPE_TEXTURE; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + info.type = UNIFORM_TYPE_IMAGE; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + info.type = UNIFORM_TYPE_TEXTURE_BUFFER; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + info.type = UNIFORM_TYPE_IMAGE_BUFFER; + need_array_dimensions = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + info.type = UNIFORM_TYPE_UNIFORM_BUFFER; + need_block_size = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + info.type = UNIFORM_TYPE_STORAGE_BUFFER; + need_block_size = true; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: { + ERR_PRINT("Dynamic uniform buffer not supported."); + continue; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: { + ERR_PRINT("Dynamic storage buffer not supported."); + continue; + } break; + case SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: { + layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; + info.type = UNIFORM_TYPE_INPUT_ATTACHMENT; + } break; + } + + if (need_array_dimensions) { + if (binding.array.dims_count == 0) { + info.length = 1; + } else { + for (uint32_t k = 0; k < binding.array.dims_count; k++) { + if (k == 0) { + info.length = binding.array.dims[0]; + } else { + info.length *= binding.array.dims[k]; + } + } + } + + layout_binding.descriptorCount = info.length; + + } else if (need_block_size) { + info.length = binding.block.size; + layout_binding.descriptorCount = 1; + } else { + info.length = 0; + layout_binding.descriptorCount = 1; + } + + info.binding = binding.binding; + uint32_t set = binding.set; + + //print_line("Stage: " + String(shader_stage_names[stage]) + " set=" + itos(set) + " binding=" + itos(info.binding) + " type=" + shader_uniform_names[info.type] + " length=" + itos(info.length)); + + ERR_FAIL_COND_V_MSG(set >= MAX_UNIFORM_SETS, RID(), + "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ")."); + + ERR_FAIL_COND_V_MSG(set >= limits.maxBoundDescriptorSets, RID(), + "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ")."); + + if (set < (uint32_t)set_bindings.size()) { + //check if this already exists + bool exists = false; + for (int k = 0; k < set_bindings[set].size(); k++) { + if (set_bindings[set][k].binding == (uint32_t)info.binding) { + //already exists, verify that it's the same type + ERR_FAIL_COND_V_MSG(set_bindings[set][k].descriptorType != layout_binding.descriptorType, RID(), + "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform type."); + + //also, verify that it's the same size + ERR_FAIL_COND_V_MSG(set_bindings[set][k].descriptorCount != layout_binding.descriptorCount || uniform_info[set][k].length != info.length, RID(), + "On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform size."); + + //just append stage mask and return + set_bindings.write[set].write[k].stageFlags |= shader_stage_masks[stage]; + uniform_info.write[set].write[k].stages |= 1 << stage; + exists = true; + } + } + + if (exists) { + continue; //merged + } + } + + layout_binding.binding = info.binding; + layout_binding.stageFlags = shader_stage_masks[stage]; + layout_binding.pImmutableSamplers = NULL; //no support for this yet + + info.stages = 1 << stage; + info.binding = info.binding; + + if (set >= (uint32_t)set_bindings.size()) { + set_bindings.resize(set + 1); + uniform_info.resize(set + 1); + } + + set_bindings.write[set].push_back(layout_binding); + uniform_info.write[set].push_back(info); + } + } + + if (stage == SHADER_STAGE_FRAGMENT) { + + uint32_t ov_count = 0; + result = spvReflectEnumerateOutputVariables(&module, &ov_count, NULL); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating output variables."); + + if (ov_count) { + Vector output_vars; + output_vars.resize(ov_count); + + result = spvReflectEnumerateOutputVariables(&module, &ov_count, output_vars.ptrw()); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining output variables."); + + for (uint32_t j = 0; j < ov_count; j++) { + if (output_vars[j]) { + fragment_outputs = MAX(fragment_outputs, output_vars[j]->location + 1); + } + } + } + } + uint32_t pc_count = 0; + result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, NULL); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating push constants."); + + if (pc_count) { + ERR_FAIL_COND_V_MSG(pc_count > 1, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "': Only one push constant is supported, which should be the same across shader stages."); + + Vector pconstants; + pconstants.resize(pc_count); + result = spvReflectEnumeratePushConstantBlocks(&module, &pc_count, pconstants.ptrw()); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining push constants."); +#if 0 + if (pconstants[0] == NULL) { + FileAccess *f = FileAccess::open("res://popo.spv", FileAccess::WRITE); + f->store_buffer((const uint8_t *)&SpirV[0], SpirV.size() * sizeof(uint32_t)); + memdelete(f); + } +#endif + + ERR_FAIL_COND_V_MSG(push_constant.push_constant_size && push_constant.push_constant_size != pconstants[0]->size, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "': Push constant block must be the same across shader stages."); + + push_constant.push_constant_size = pconstants[0]->size; + push_constant.push_constants_vk_stage |= shader_stage_masks[stage]; + + //print_line("Stage: " + String(shader_stage_names[stage]) + " push constant of size=" + itos(push_constant.push_constant_size)); + } + + // Destroy the reflection data when no longer required. + spvReflectDestroyShaderModule(&module); + } + spirv_code.push_back(SpirV); stages_processed |= (1 << p_stages[i].shader_stage); @@ -3758,15 +3996,15 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector &p_uniforms, const Uniform &uniform = uniforms[uniform_idx]; ERR_FAIL_COND_V_MSG(uniform.type != set_uniform.type, RID(), - "Mismatch uniform type for binding (" + itos(set_uniform.binding) + ")."); + "Mismatch uniform type for binding (" + itos(set_uniform.binding) + "). Expected '" + shader_uniform_names[set_uniform.type] + "', supplied: '" + shader_uniform_names[uniform.type] + "'."); VkWriteDescriptorSet write; //common header write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -6048,7 +6286,6 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) { } texture_upload_region_size_px = GLOBAL_DEF("rendering/vulkan/staging_buffer/texture_upload_region_size_px", 64); texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px); - print_line("update size: " + itos(texture_upload_region_size_px)); frames_drawn = frame_count; //start from frame count, so everything else is immediately old -- cgit v1.2.3 From c613ead5fa2361296cf8d9a80d4648492ff4e16f Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Mon, 29 Jul 2019 12:59:18 -0300 Subject: Added a spinlock template as well as a thread work pool class. Also, optimized shader compilation to happen on threads. --- drivers/vulkan/rendering_device_vulkan.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index f6154a3cbd..a14d45067a 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -3448,8 +3448,6 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector &p_stages) { - _THREAD_SAFE_METHOD_ - //descriptor layouts Vector > set_bindings; Vector > uniform_info; @@ -3694,6 +3692,8 @@ RID RenderingDeviceVulkan::shader_create(const Vector &p_stages //all good, let's create modules + _THREAD_SAFE_METHOD_ + Shader shader; shader.vertex_input_locations = vertex_input_locations; -- cgit v1.2.3 From 4fe3ee1730167b90ec8ae70c871c1dad032981d5 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sun, 28 Jul 2019 19:58:32 -0300 Subject: Moved the shader source compilation code outside RenderingDevice and Vulkan --- drivers/vulkan/rendering_device_vulkan.cpp | 283 ++--------------------------- 1 file changed, 12 insertions(+), 271 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 7f4ebd5134..f6154a3cbd 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -3,8 +3,6 @@ #include "core/os/file_access.h" #include "core/project_settings.h" #include "drivers/vulkan/vulkan_context.h" -#include "thirdparty/glslang/SPIRV/GlslangToSpv.h" -#include "thirdparty/glslang/glslang/Include/Types.h" #include "thirdparty/spirv-reflect/spirv_reflect.h" void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) { @@ -3212,103 +3210,6 @@ RID RenderingDeviceVulkan::index_array_create(RID p_index_buffer, uint32_t p_ind /**** SHADER ****/ /****************/ -static const TBuiltInResource default_builtin_resource = { - .maxLights = 32, - .maxClipPlanes = 6, - .maxTextureUnits = 32, - .maxTextureCoords = 32, - .maxVertexAttribs = 64, - .maxVertexUniformComponents = 4096, - .maxVaryingFloats = 64, - .maxVertexTextureImageUnits = 32, - .maxCombinedTextureImageUnits = 80, - .maxTextureImageUnits = 32, - .maxFragmentUniformComponents = 4096, - .maxDrawBuffers = 32, - .maxVertexUniformVectors = 128, - .maxVaryingVectors = 8, - .maxFragmentUniformVectors = 16, - .maxVertexOutputVectors = 16, - .maxFragmentInputVectors = 15, - .minProgramTexelOffset = -8, - .maxProgramTexelOffset = 7, - .maxClipDistances = 8, - .maxComputeWorkGroupCountX = 65535, - .maxComputeWorkGroupCountY = 65535, - .maxComputeWorkGroupCountZ = 65535, - .maxComputeWorkGroupSizeX = 1024, - .maxComputeWorkGroupSizeY = 1024, - .maxComputeWorkGroupSizeZ = 64, - .maxComputeUniformComponents = 1024, - .maxComputeTextureImageUnits = 16, - .maxComputeImageUniforms = 8, - .maxComputeAtomicCounters = 8, - .maxComputeAtomicCounterBuffers = 1, - .maxVaryingComponents = 60, - .maxVertexOutputComponents = 64, - .maxGeometryInputComponents = 64, - .maxGeometryOutputComponents = 128, - .maxFragmentInputComponents = 128, - .maxImageUnits = 8, - .maxCombinedImageUnitsAndFragmentOutputs = 8, - .maxCombinedShaderOutputResources = 8, - .maxImageSamples = 0, - .maxVertexImageUniforms = 0, - .maxTessControlImageUniforms = 0, - .maxTessEvaluationImageUniforms = 0, - .maxGeometryImageUniforms = 0, - .maxFragmentImageUniforms = 8, - .maxCombinedImageUniforms = 8, - .maxGeometryTextureImageUnits = 16, - .maxGeometryOutputVertices = 256, - .maxGeometryTotalOutputComponents = 1024, - .maxGeometryUniformComponents = 1024, - .maxGeometryVaryingComponents = 64, - .maxTessControlInputComponents = 128, - .maxTessControlOutputComponents = 128, - .maxTessControlTextureImageUnits = 16, - .maxTessControlUniformComponents = 1024, - .maxTessControlTotalOutputComponents = 4096, - .maxTessEvaluationInputComponents = 128, - .maxTessEvaluationOutputComponents = 128, - .maxTessEvaluationTextureImageUnits = 16, - .maxTessEvaluationUniformComponents = 1024, - .maxTessPatchComponents = 120, - .maxPatchVertices = 32, - .maxTessGenLevel = 64, - .maxViewports = 16, - .maxVertexAtomicCounters = 0, - .maxTessControlAtomicCounters = 0, - .maxTessEvaluationAtomicCounters = 0, - .maxGeometryAtomicCounters = 0, - .maxFragmentAtomicCounters = 8, - .maxCombinedAtomicCounters = 8, - .maxAtomicCounterBindings = 1, - .maxVertexAtomicCounterBuffers = 0, - .maxTessControlAtomicCounterBuffers = 0, - .maxTessEvaluationAtomicCounterBuffers = 0, - .maxGeometryAtomicCounterBuffers = 0, - .maxFragmentAtomicCounterBuffers = 1, - .maxCombinedAtomicCounterBuffers = 1, - .maxAtomicCounterBufferSize = 16384, - .maxTransformFeedbackBuffers = 4, - .maxTransformFeedbackInterleavedComponents = 64, - .maxCullDistances = 8, - .maxCombinedClipAndCullDistances = 8, - .maxSamples = 4, - .limits = { - .nonInductiveForLoops = 1, - .whileLoops = 1, - .doWhileLoops = 1, - .generalUniformIndexing = 1, - .generalAttributeMatrixVectorIndexing = 1, - .generalVaryingIndexing = 1, - .generalSamplerIndexing = 1, - .generalVariableIndexing = 1, - .generalConstantMatrixVectorIndexing = 1, - } -}; - static const char *shader_stage_names[RenderingDevice::SHADER_STAGE_MAX] = { "Vertex", "Fragment", @@ -3347,7 +3248,7 @@ String RenderingDeviceVulkan::_shader_uniform_debug(RID p_shader, int p_set) { } return ret; } - +#if 0 bool RenderingDeviceVulkan::_uniform_add_binding(Vector > &bindings, Vector > &uniform_infos, const glslang::TObjectReflection &reflection, RenderingDevice::ShaderStage p_stage, Shader::PushConstant &push_constant, String *r_error) { VkDescriptorSetLayoutBinding layout_binding; @@ -3543,30 +3444,12 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector &p_stages, String *r_error, ShaderStage *r_error_stage, bool p_allow_cache) { +RID RenderingDeviceVulkan::shader_create(const Vector &p_stages) { _THREAD_SAFE_METHOD_ - // initialize in case it's not initialized. This is done once per thread - // and it's safe to call multiple times - glslang::InitializeProcess(); - EShLanguage stages[SHADER_STAGE_MAX] = { - EShLangVertex, - EShLangFragment, - EShLangTessControl, - EShLangTessEvaluation, - EShLangCompute - }; - - int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100 - glslang::EShTargetClientVersion VulkanClientVersion = glslang::EShTargetVulkan_1_0; - glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_0; - - Vector > spirv_code; - - glslang::TShader::ForbidIncluder includer; - //descriptor layouts Vector > set_bindings; Vector > uniform_info; @@ -3581,148 +3464,13 @@ RID RenderingDeviceVulkan::shader_create_from_source(const VectorgetBasicType() == glslang::EbtBlock && reflection.getType()->getQualifier().storage == glslang::EvqUniform && reflection.getType()->getQualifier().layoutPushConstant) { - uint32_t len = reflection.size; - if (push_constant_debug.push_constant_size != 0 && push_constant_debug.push_constant_size != len) { - print_line("eep"); - } - - push_constant_debug.push_constant_size = len; - push_constant_debug.push_constants_vk_stage |= shader_stage_masks[p_stages[i].shader_stage]; - //print_line("Debug stage " + String(shader_stage_names[p_stages[i].shader_stage]) + " push constant size: " + itos(push_constant_debug.push_constant_size)); - } - } - - - for (int j = 0; j < program.getNumUniformVariables(); j++) { - if (!_uniform_add_binding(bindings, uniform_info, program.getUniform(j), p_stages[i].shader_stage, push_constant, r_error)) { - return RID(); - } - } - - for (int j = 0; j < program.getNumUniformBlocks(); j++) { - if (!_uniform_add_binding(bindings, uniform_info, program.getUniformBlock(j), p_stages[i].shader_stage, push_constant, r_error)) { - return RID(); - } - } - - for (int j = 0; j < program.getNumBufferVariables(); j++) { - if (!_uniform_add_binding(bindings, uniform_info, program.getBufferVariable(j), p_stages[i].shader_stage, push_constant, r_error)) { - return RID(); - } - } - - for (int j = 0; j < program.getNumBufferBlocks(); j++) { - if (!_uniform_add_binding(bindings, uniform_info, program.getBufferBlock(j), p_stages[i].shader_stage, push_constant, r_error)) { - return RID(); - } - } - - if (p_stages[i].shader_stage == SHADER_STAGE_VERTEX) { - for (int j = 0; j < program.getNumPipeInputs(); j++) { - if (program.getPipeInput(i).getType()->getQualifier().hasLocation()) { - int location = program.getPipeInput(i).getType()->getQualifier().layoutLocation; - - if (vertex_input_locations.find(location) == -1) { - vertex_input_locations.push_back(location); - } - } - } - } - - if (p_stages[i].shader_stage == SHADER_STAGE_FRAGMENT) { - - fragment_outputs = program.getNumPipeOutputs(); - } - -#endif - std::vector SpirV; - spv::SpvBuildLogger logger; - glslang::SpvOptions spvOptions; - glslang::GlslangToSpv(*program.getIntermediate(stages[p_stages[i].shader_stage]), SpirV, &logger, &spvOptions); + ERR_FAIL_COND_V_MSG(stages_processed & (1 << p_stages[i].shader_stage), RID(), + "Stage " + String(shader_stage_names[p_stages[i].shader_stage]) + " submitted more than once."); { SpvReflectShaderModule module; - SpvReflectResult result = spvReflectCreateShaderModule(SpirV.size() * sizeof(uint32_t), &SpirV[0], &module); + PoolVector::Read spirv = p_stages[i].spir_v.read(); + SpvReflectResult result = spvReflectCreateShaderModule(p_stages[i].spir_v.size(), spirv.ptr(), &module); ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed parsing shader."); @@ -3941,8 +3689,6 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector::Read r = p_stages[i].spir_v.read(); + + shader_module_create_info.pCode = (const uint32_t *)r.ptr(); VkShaderModule module; VkResult res = vkCreateShaderModule(device, &shader_module_create_info, NULL, &module); @@ -4087,14 +3835,7 @@ RID RenderingDeviceVulkan::shader_create_from_source(const Vector Date: Sat, 22 Jun 2019 19:34:26 +0300 Subject: Add static Vulkan loader. Initial Vulkan support for Windows. Initial Vulkan support for macOS. --- drivers/vulkan/rendering_device_vulkan.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index f6154a3cbd..4ca44283a3 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* rendering_device_vulkan.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + #include "rendering_device_vulkan.h" #include "core/hashfuncs.h" #include "core/os/file_access.h" -- cgit v1.2.3 From b456bfad5cee3922f55621bf7c133cc67337636a Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Fri, 12 Jul 2019 16:18:30 +0300 Subject: Add runtime GLES2 / Vulkan context selection. --- drivers/vulkan/rendering_device_vulkan.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 4ca44283a3..77f4a294fa 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -4905,7 +4905,9 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(in VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; draw_list = memnew(DrawList); draw_list->command_buffer = command_buffer; +#ifdef DEBUG_ENABLED draw_list->validation.framebuffer_format = screen_get_framebuffer_format(); +#endif draw_list_count = 0; draw_list_split = false; @@ -5101,7 +5103,9 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu draw_list = memnew(DrawList); draw_list->command_buffer = command_buffer; +#ifdef DEBUG_ENABLED draw_list->validation.framebuffer_format = framebuffer->format_id; +#endif draw_list_count = 0; draw_list_split = false; @@ -5246,7 +5250,9 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p } draw_list[i].command_buffer = command_buffer; +#ifdef DEBUG_ENABLED draw_list[i].validation.framebuffer_format = framebuffer->format_id; +#endif VkViewport viewport; viewport.x = viewport_offset.x; @@ -5430,9 +5436,9 @@ void RenderingDeviceVulkan::draw_list_bind_vertex_array(DrawListID p_list, RID p #ifdef DEBUG_ENABLED dl->validation.vertex_format = vertex_array->description; - dl->validation.vertex_array_size = vertex_array->vertex_count; dl->validation.vertex_max_instances_allowed = vertex_array->max_instances_allowed; #endif + dl->validation.vertex_array_size = vertex_array->vertex_count; vkCmdBindVertexBuffers(dl->command_buffer, 0, vertex_array->buffers.size(), vertex_array->buffers.ptr(), vertex_array->offsets.ptr()); } void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) { @@ -5452,10 +5458,11 @@ void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_ dl->state.index_array = p_index_array; #ifdef DEBUG_ENABLED - dl->validation.index_array_size = index_array->indices; dl->validation.index_array_max_index = index_array->max_index; - dl->validation.index_array_offset = index_array->offset; #endif + dl->validation.index_array_size = index_array->indices; + dl->validation.index_array_offset = index_array->offset; + vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, index_array->offset, index_array->index_type); } @@ -5463,7 +5470,9 @@ void RenderingDeviceVulkan::draw_list_set_line_width(DrawListID p_list, float p_ DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); +#ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); +#endif vkCmdSetLineWidth(dl->command_buffer, p_width); } @@ -5481,7 +5490,9 @@ void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, void "This render pipeline requires (" + itos(dl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")"); #endif vkCmdPushConstants(dl->command_buffer, dl->state.pipeline_layout, dl->state.pipeline_push_constant_stages, 0, p_data_size, p_data); +#ifdef DEBUG_ENABLED dl->validation.pipeline_push_constant_suppplied = true; +#endif } void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances) { -- cgit v1.2.3 From 449df8f688080c02bfbbfafc45421875b77deb1b Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sun, 18 Aug 2019 19:40:52 -0300 Subject: Base 3D engine done, still untested, though. --- drivers/vulkan/rendering_device_vulkan.cpp | 99 +++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 15 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 265dfc69d4..82ab8d6c2f 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -3041,7 +3041,7 @@ RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Poo ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); Buffer buffer; - _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); if (p_data.size()) { uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); @@ -3202,7 +3202,7 @@ RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBuff #else index_buffer.max_index = 0xFFFFFFFF; #endif - _buffer_allocate(&index_buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + _buffer_allocate(&index_buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); if (p_data.size()) { uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); @@ -3485,8 +3485,9 @@ RID RenderingDeviceVulkan::shader_create(const Vector &p_stages push_constant.push_constant_size = 0; push_constant.push_constants_vk_stage = 0; - Vector vertex_input_locations; - int fragment_outputs = 0; + uint32_t vertex_input_mask = 0; + + uint32_t fragment_outputs = 0; uint32_t stages_processed = 0; @@ -3660,6 +3661,29 @@ RID RenderingDeviceVulkan::shader_create(const Vector &p_stages } } + if (stage == SHADER_STAGE_VERTEX) { + + uint32_t iv_count = 0; + result = spvReflectEnumerateInputVariables(&module, &iv_count, NULL); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating input variables."); + + if (iv_count) { + Vector input_vars; + input_vars.resize(iv_count); + + result = spvReflectEnumerateOutputVariables(&module, &iv_count, input_vars.ptrw()); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining input variables."); + + for (uint32_t j = 0; j < iv_count; j++) { + if (input_vars[j]) { + vertex_input_mask |= (1 << uint32_t(input_vars[j]->location)); + } + } + } + } + if (stage == SHADER_STAGE_FRAGMENT) { uint32_t ov_count = 0; @@ -3726,7 +3750,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector &p_stages Shader shader; - shader.vertex_input_locations = vertex_input_locations; + shader.vertex_input_mask = vertex_input_mask; shader.fragment_outputs = fragment_outputs; shader.push_constant = push_constant; @@ -3871,10 +3895,10 @@ RID RenderingDeviceVulkan::shader_create(const Vector &p_stages return shader_owner.make_rid(shader); } -Vector RenderingDeviceVulkan::shader_get_vertex_input_locations_used(RID p_shader) { +uint32_t RenderingDeviceVulkan::shader_get_vertex_input_attribute_mask(RID p_shader) { const Shader *shader = shader_owner.getornull(p_shader); - ERR_FAIL_COND_V(!shader, Vector()); - return shader->vertex_input_locations; + ERR_FAIL_COND_V(!shader, 0); + return shader->vertex_input_mask; } /******************/ @@ -3929,7 +3953,7 @@ RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataF ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != size_bytes, RID()); TextureBuffer texture_buffer; - Error err = _buffer_allocate(&texture_buffer.buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + Error err = _buffer_allocate(&texture_buffer.buffer, size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); ERR_FAIL_COND_V(err != OK, RID()); if (p_data.size()) { @@ -4488,6 +4512,49 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint return err; } +PoolVector RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { + + Buffer *buffer = NULL; + if (vertex_buffer_owner.owns(p_buffer)) { + buffer = vertex_buffer_owner.getornull(p_buffer); + } else if (index_buffer_owner.owns(p_buffer)) { + buffer = index_buffer_owner.getornull(p_buffer); + } else if (texture_buffer_owner.owns(p_buffer)) { + buffer = &texture_buffer_owner.getornull(p_buffer)->buffer; + } else { + ERR_FAIL_V_MSG(PoolVector(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving."); + } + + VkCommandBuffer command_buffer = frames[frame].setup_command_buffer; + Buffer tmp_buffer; + _buffer_allocate(&tmp_buffer, buffer->size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_CPU_ONLY); + VkBufferCopy region; + region.srcOffset = 0; + region.dstOffset = 0; + region.size = buffer->size; + vkCmdCopyBuffer(command_buffer, buffer->buffer, tmp_buffer.buffer, 1, ®ion); //dst buffer is in CPU, but I wonder if src buffer needs a barrier for this.. + //flush everything so memory can be safely mapped + _flush(true, false); + + void *buffer_mem; + VkResult vkerr = vmaMapMemory(allocator, tmp_buffer.allocation, &buffer_mem); + if (vkerr) { + ERR_FAIL_V(PoolVector()); + } + + PoolVector buffer_data; + { + + buffer_data.resize(buffer->size); + PoolVector::Write w = buffer_data.write(); + copymem(w.ptr(), buffer_mem, buffer->size); + } + + _buffer_free(&tmp_buffer); + + return buffer_data; +} + /*************************/ /**** RENDER PIPELINE ****/ /*************************/ @@ -4523,17 +4590,19 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma pipeline_vertex_input_state_create_info = vd.create_info; //validate with inputs - for (int i = 0; i < shader->vertex_input_locations.size(); i++) { - uint32_t location = shader->vertex_input_locations[i]; + for (uint32_t i = 0; i < 32; i++) { + if (!(shader->vertex_input_mask & (1 << i))) { + continue; + } bool found = false; for (int j = 0; j < vd.vertex_formats.size(); j++) { - if (vd.vertex_formats[j].location == location) { + if (vd.vertex_formats[j].location == i) { found = true; } } ERR_FAIL_COND_V_MSG(!found, RID(), - "Shader vertex input location (" + itos(location) + ") not provided in vertex input description for pipeline creation."); + "Shader vertex input location (" + itos(i) + ") not provided in vertex input description for pipeline creation."); } } else { @@ -4546,8 +4615,8 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma pipeline_vertex_input_state_create_info.vertexAttributeDescriptionCount = 0; pipeline_vertex_input_state_create_info.pVertexAttributeDescriptions = NULL; - ERR_FAIL_COND_V_MSG(shader->vertex_input_locations.size(), RID(), - "Shader contains vertex inputs (" + itos(shader->vertex_input_locations.size()) + ") but no vertex input description was provided for pipeline creation."); + ERR_FAIL_COND_V_MSG(shader->vertex_input_mask != 0, RID(), + "Shader contains vertex inputs, but no vertex input description was provided for pipeline creation."); } //input assembly -- cgit v1.2.3 From 8cee7703a6673f9505332de1581055c821b756f0 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Tue, 20 Aug 2019 17:54:03 -0300 Subject: Yay very basic 3D (only white) finally shows. --- drivers/vulkan/rendering_device_vulkan.cpp | 55 +++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 17 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 82ab8d6c2f..93e1b09cfd 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1036,6 +1036,18 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFor return 0; } +bool RenderingDeviceVulkan::format_has_stencil(DataFormat p_format) { + switch (p_format) { + case DATA_FORMAT_S8_UINT: + case DATA_FORMAT_D16_UNORM_S8_UINT: + case DATA_FORMAT_D24_UNORM_S8_UINT: + case DATA_FORMAT_D32_SFLOAT_S8_UINT: { + return true; + } + } + return false; +} + uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh, uint32_t *r_depth) { ERR_FAIL_COND_V(p_mipmaps == 0, 0); @@ -1699,7 +1711,12 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T //set bound and unbound layouts if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - texture.aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; + + texture.read_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; + texture.barrier_aspect_mask = texture.read_aspect_mask; + if (format_has_stencil(p_format.format)) { + texture.barrier_aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) { texture.unbound_layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; @@ -1710,7 +1727,9 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T } else if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { - texture.aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; + texture.read_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; + texture.barrier_aspect_mask = texture.read_aspect_mask; + if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) { texture.unbound_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; } else { @@ -1718,7 +1737,9 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T } texture.bound_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } else { - texture.aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; + texture.read_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; + texture.barrier_aspect_mask = texture.read_aspect_mask; + texture.unbound_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; texture.bound_layout = VK_IMAGE_LAYOUT_UNDEFINED; //will never be bound } @@ -1794,7 +1815,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = texture.image; - image_memory_barrier.subresourceRange.aspectMask = texture.aspect_mask; + image_memory_barrier.subresourceRange.aspectMask = texture.barrier_aspect_mask; image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = image_create_info.mipLevels; image_memory_barrier.subresourceRange.baseArrayLayer = 0; @@ -2053,7 +2074,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = texture->image; - image_memory_barrier.subresourceRange.aspectMask = texture->aspect_mask; + image_memory_barrier.subresourceRange.aspectMask = texture->barrier_aspect_mask; image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = texture->mipmaps; image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; @@ -2156,7 +2177,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con buffer_image_copy.bufferRowLength = 0; //tigthly packed buffer_image_copy.bufferImageHeight = 0; //tigthly packed - buffer_image_copy.imageSubresource.aspectMask = texture->aspect_mask; + buffer_image_copy.imageSubresource.aspectMask = texture->read_aspect_mask; buffer_image_copy.imageSubresource.mipLevel = mm_i; buffer_image_copy.imageSubresource.baseArrayLayer = p_layer; buffer_image_copy.imageSubresource.layerCount = 1; @@ -2191,7 +2212,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = texture->image; - image_memory_barrier.subresourceRange.aspectMask = texture->aspect_mask; + image_memory_barrier.subresourceRange.aspectMask = texture->barrier_aspect_mask; image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = texture->mipmaps; image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; @@ -2340,7 +2361,7 @@ PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = tex->image; - image_memory_barrier.subresourceRange.aspectMask = tex->aspect_mask; + image_memory_barrier.subresourceRange.aspectMask = tex->barrier_aspect_mask; image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = tex->mipmaps; image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; @@ -2379,7 +2400,7 @@ PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, i + 1, &mm_width, &mm_height, &mm_depth); VkImageCopy image_copy_region; - image_copy_region.srcSubresource.aspectMask = tex->aspect_mask; + image_copy_region.srcSubresource.aspectMask = tex->read_aspect_mask; image_copy_region.srcSubresource.baseArrayLayer = p_layer; image_copy_region.srcSubresource.layerCount = 1; image_copy_region.srcSubresource.mipLevel = i; @@ -2416,7 +2437,7 @@ PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = tex->image; - image_memory_barrier.subresourceRange.aspectMask = tex->aspect_mask; + image_memory_barrier.subresourceRange.aspectMask = tex->barrier_aspect_mask; image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = tex->mipmaps; image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; @@ -2528,7 +2549,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = src_tex->image; - image_memory_barrier.subresourceRange.aspectMask = src_tex->aspect_mask; + image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask; image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap; image_memory_barrier.subresourceRange.levelCount = 1; image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; @@ -2548,7 +2569,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = dst_tex->image; - image_memory_barrier.subresourceRange.aspectMask = dst_tex->aspect_mask; + image_memory_barrier.subresourceRange.aspectMask = dst_tex->read_aspect_mask; image_memory_barrier.subresourceRange.baseMipLevel = p_dst_mipmap; image_memory_barrier.subresourceRange.levelCount = 1; image_memory_barrier.subresourceRange.baseArrayLayer = p_dst_layer; @@ -2562,7 +2583,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, { VkImageCopy image_copy_region; - image_copy_region.srcSubresource.aspectMask = src_tex->aspect_mask; + image_copy_region.srcSubresource.aspectMask = src_tex->read_aspect_mask; image_copy_region.srcSubresource.baseArrayLayer = p_src_layer; image_copy_region.srcSubresource.layerCount = 1; image_copy_region.srcSubresource.mipLevel = p_src_mipmap; @@ -2570,7 +2591,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_copy_region.srcOffset.y = p_from.y; image_copy_region.srcOffset.z = p_from.z; - image_copy_region.dstSubresource.aspectMask = src_tex->aspect_mask; + image_copy_region.dstSubresource.aspectMask = src_tex->barrier_aspect_mask; image_copy_region.dstSubresource.baseArrayLayer = p_dst_layer; image_copy_region.dstSubresource.layerCount = 1; image_copy_region.dstSubresource.mipLevel = p_dst_mipmap; @@ -2598,7 +2619,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = src_tex->image; - image_memory_barrier.subresourceRange.aspectMask = src_tex->aspect_mask; + image_memory_barrier.subresourceRange.aspectMask = src_tex->barrier_aspect_mask; image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap; image_memory_barrier.subresourceRange.levelCount = src_tex->mipmaps; image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; @@ -3672,12 +3693,12 @@ RID RenderingDeviceVulkan::shader_create(const Vector &p_stages Vector input_vars; input_vars.resize(iv_count); - result = spvReflectEnumerateOutputVariables(&module, &iv_count, input_vars.ptrw()); + result = spvReflectEnumerateInputVariables(&module, &iv_count, input_vars.ptrw()); ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining input variables."); for (uint32_t j = 0; j < iv_count; j++) { - if (input_vars[j]) { + if (input_vars[j] && input_vars[j]->decoration_flags == 0) { //regular input vertex_input_mask |= (1 << uint32_t(input_vars[j]->location)); } } -- cgit v1.2.3 From 2d6a916835bd851b2ea03a2e887ba83f0065dae4 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Mon, 26 Aug 2019 17:43:58 -0300 Subject: Environment sky more or less working. --- drivers/vulkan/rendering_device_vulkan.cpp | 73 ++++++++++++++---------------- 1 file changed, 34 insertions(+), 39 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 93e1b09cfd..a89183d1cc 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1044,6 +1044,8 @@ bool RenderingDeviceVulkan::format_has_stencil(DataFormat p_format) { case DATA_FORMAT_D32_SFLOAT_S8_UINT: { return true; } + default: { + } } return false; } @@ -1219,7 +1221,7 @@ const VkImageType RenderingDeviceVulkan::vulkan_image_type[RenderingDevice::TEXT VK_IMAGE_TYPE_2D, VK_IMAGE_TYPE_1D, VK_IMAGE_TYPE_2D, - VK_IMAGE_TYPE_3D + VK_IMAGE_TYPE_2D }; /***************************/ @@ -1364,7 +1366,7 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_ } else { //flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands - _flush(true, p_on_draw_command_buffer); + _flush(true); //clear the whole staging buffer for (int i = 0; i < staging_buffer_blocks.size(); i++) { @@ -1408,7 +1410,7 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_ continue; //and try again } else { - _flush(false, false); + _flush(false); for (int i = 0; i < staging_buffer_blocks.size(); i++) { //clear all blocks but the ones from this frame @@ -1562,10 +1564,6 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T image_create_info.mipLevels = p_format.mipmaps; - uint32_t array_layer_multiplier = 1; - if (p_format.type == TEXTURE_TYPE_CUBE_ARRAY || p_format.type == TEXTURE_TYPE_CUBE) { - array_layer_multiplier = 6; - } if (p_format.type == TEXTURE_TYPE_1D_ARRAY || p_format.type == TEXTURE_TYPE_2D_ARRAY || p_format.type == TEXTURE_TYPE_CUBE_ARRAY || p_format.type == TEXTURE_TYPE_CUBE) { ERR_FAIL_COND_V_MSG(p_format.array_layers < 1, RID(), "Amount of layers must be equal or greater than 1 for arrays and cubemaps."); @@ -1576,8 +1574,6 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T image_create_info.arrayLayers = 1; } - image_create_info.arrayLayers = p_format.array_layers; - ERR_FAIL_INDEX_V(p_format.samples, TEXTURE_SAMPLES_MAX, RID()); image_create_info.samples = rasterization_sample_count[p_format.samples]; @@ -1624,11 +1620,11 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T ERR_FAIL_COND_V_MSG(!(p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT), RID(), "Texture needs the TEXTURE_USAGE_CAN_UPDATE_BIT usage flag in order to be updated at initialization or later"); - int expected_images = image_create_info.arrayLayers * array_layer_multiplier; + int expected_images = image_create_info.arrayLayers; ERR_FAIL_COND_V_MSG(p_data.size() != expected_images, RID(), "Default supplied data for image format is of invalid length (" + itos(p_data.size()) + "), should be (" + itos(expected_images) + ")."); - for (uint32_t i = 0; i < image_create_info.arrayLayers * array_layer_multiplier; i++) { + for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) { uint32_t required_size = get_image_format_required_size(p_format.format, image_create_info.extent.width, image_create_info.extent.height, image_create_info.extent.depth, image_create_info.mipLevels); ERR_FAIL_COND_V_MSG((uint32_t)p_data[i].size() != required_size, RID(), "Data for slice index " + itos(i) + " (mapped to layer " + itos(i) + ") differs in size (supplied: " + itos(p_data[i].size()) + ") than what is required by the format (" + itos(required_size) + ")."); @@ -1789,7 +1785,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T image_view_create_info.subresourceRange.baseMipLevel = 0; image_view_create_info.subresourceRange.levelCount = image_create_info.mipLevels; image_view_create_info.subresourceRange.baseArrayLayer = 0; - image_view_create_info.subresourceRange.layerCount = array_layer_multiplier * image_create_info.arrayLayers; + image_view_create_info.subresourceRange.layerCount = image_create_info.arrayLayers; if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; } else { @@ -1819,7 +1815,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = image_create_info.mipLevels; image_memory_barrier.subresourceRange.baseArrayLayer = 0; - image_memory_barrier.subresourceRange.layerCount = image_create_info.arrayLayers * array_layer_multiplier; + image_memory_barrier.subresourceRange.layerCount = image_create_info.arrayLayers; vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); } @@ -1850,11 +1846,6 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID Texture texture = *src_texture; - uint32_t array_layer_multiplier = 1; - if (texture.type == TEXTURE_TYPE_CUBE_ARRAY || texture.type == TEXTURE_TYPE_CUBE) { - array_layer_multiplier = 6; - } - VkImageViewCreateInfo image_view_create_info; image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; image_view_create_info.pNext = NULL; @@ -1899,7 +1890,7 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID image_view_create_info.subresourceRange.baseMipLevel = 0; image_view_create_info.subresourceRange.levelCount = texture.mipmaps; - image_view_create_info.subresourceRange.layerCount = array_layer_multiplier * texture.layers; + image_view_create_info.subresourceRange.layerCount = texture.layers; image_view_create_info.subresourceRange.baseArrayLayer = 0; if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { @@ -1921,7 +1912,7 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID return id; } -RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap) { +RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type) { Texture *src_texture = texture_owner.getornull(p_with_texture); ERR_FAIL_COND_V(!src_texture, RID()); @@ -1932,20 +1923,18 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p ERR_FAIL_COND_V(!src_texture, RID()); //this is a bug } + ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_CUBEMAP && (src_texture->type != TEXTURE_TYPE_CUBE && src_texture->type != TEXTURE_TYPE_CUBE_ARRAY), RID(), + "Can only create a cubemap slice from a cubemap or cubemap array mipmap"); + //create view ERR_FAIL_INDEX_V(p_mipmap, src_texture->mipmaps, RID()); - - uint32_t array_layer_multiplier = 1; - if (src_texture->type == TEXTURE_TYPE_CUBE_ARRAY || src_texture->type == TEXTURE_TYPE_CUBE) { - array_layer_multiplier = 6; - } - ERR_FAIL_INDEX_V(p_layer, src_texture->layers * array_layer_multiplier, RID()); + ERR_FAIL_INDEX_V(p_layer, src_texture->layers, RID()); Texture texture = *src_texture; get_image_format_required_size(texture.format, texture.width, texture.height, texture.depth, p_mipmap + 1, &texture.width, &texture.height); texture.mipmaps = 1; - texture.layers = 1; + texture.layers = p_slice_type == TEXTURE_SLICE_CUBEMAP ? 6 : 1; VkImageViewCreateInfo image_view_create_info; image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; @@ -1963,7 +1952,7 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p VK_IMAGE_VIEW_TYPE_2D, }; - image_view_create_info.viewType = view_types[texture.type]; + image_view_create_info.viewType = p_slice_type == TEXTURE_SLICE_CUBEMAP ? VK_IMAGE_VIEW_TYPE_CUBE : view_types[texture.type]; if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) { image_view_create_info.format = vulkan_formats[texture.format]; } else { @@ -1989,9 +1978,15 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p image_view_create_info.components.b = component_swizzles[p_view.swizzle_b]; image_view_create_info.components.a = component_swizzles[p_view.swizzle_a]; + if (p_slice_type == TEXTURE_SLICE_CUBEMAP) { + ERR_FAIL_COND_V_MSG(p_layer >= src_texture->layers, RID(), + "Specified layer is invalid for cubemap"); + ERR_FAIL_COND_V_MSG((p_layer % 6) != 0, RID(), + "Specified layer must be a multiple of 6."); + } image_view_create_info.subresourceRange.baseMipLevel = p_mipmap; image_view_create_info.subresourceRange.levelCount = 1; - image_view_create_info.subresourceRange.layerCount = 1; + image_view_create_info.subresourceRange.layerCount = p_slice_type == TEXTURE_SLICE_CUBEMAP ? 6 : 1; image_view_create_info.subresourceRange.baseArrayLayer = p_layer; if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { @@ -2469,7 +2464,7 @@ PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 } //flush everything so memory can be safely mapped - _flush(true, false); + _flush(true); PoolVector ret = _texture_get_data_from_image(tex, image, allocation, p_layer); vmaDestroyImage(allocator, image, allocation); @@ -4555,7 +4550,7 @@ PoolVector RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { region.size = buffer->size; vkCmdCopyBuffer(command_buffer, buffer->buffer, tmp_buffer.buffer, 1, ®ion); //dst buffer is in CPU, but I wonder if src buffer needs a barrier for this.. //flush everything so memory can be safely mapped - _flush(true, false); + _flush(true); void *buffer_mem; VkResult vkerr = vmaMapMemory(allocator, tmp_buffer.allocation, &buffer_mem); @@ -4571,6 +4566,8 @@ PoolVector RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { copymem(w.ptr(), buffer_mem, buffer->size); } + vmaUnmapMemory(allocator, tmp_buffer.allocation); + _buffer_free(&tmp_buffer); return buffer_data; @@ -6041,18 +6038,16 @@ void RenderingDeviceVulkan::advance_frame() { } } -void RenderingDeviceVulkan::_flush(bool p_setup, bool p_draw) { +void RenderingDeviceVulkan::_flush(bool p_current_frame) { //not doing this crashes RADV (undefined behavior) - if (p_setup) { + if (p_current_frame) { vkEndCommandBuffer(frames[frame].setup_command_buffer); - } - if (p_draw) { vkEndCommandBuffer(frames[frame].draw_command_buffer); } - context->flush(p_setup, p_draw); + context->flush(p_current_frame, p_current_frame); //re-create the setup command - if (p_setup) { + if (p_current_frame) { VkCommandBufferBeginInfo cmdbuf_begin; cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; cmdbuf_begin.pNext = NULL; @@ -6064,7 +6059,7 @@ void RenderingDeviceVulkan::_flush(bool p_setup, bool p_draw) { context->set_setup_buffer(frames[frame].setup_command_buffer); //append now so it's added before everything else } - if (p_draw) { + if (p_current_frame) { VkCommandBufferBeginInfo cmdbuf_begin; cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; cmdbuf_begin.pNext = NULL; @@ -6232,7 +6227,7 @@ void RenderingDeviceVulkan::finalize() { //free all resources - _flush(false, false); + _flush(false); _free_rids(pipeline_owner, "Pipeline"); _free_rids(uniform_set_owner, "UniformSet"); -- cgit v1.2.3 From 920db604d26e2e82b6289807ad8a0607b310eef6 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Fri, 6 Sep 2019 22:51:27 -0300 Subject: Rewrote large part of rendering, omni and spot shadows now work. --- drivers/vulkan/rendering_device_vulkan.cpp | 171 +++++++++++++++++++++++++---- 1 file changed, 150 insertions(+), 21 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index a89183d1cc..8cc07c59b1 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1497,6 +1497,23 @@ void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mas vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 1, &mem_barrier, 0, NULL, 0, NULL); } + +void RenderingDeviceVulkan::_buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw) { + + VkBufferMemoryBarrier buffer_mem_barrier; + buffer_mem_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + buffer_mem_barrier.pNext = NULL; + buffer_mem_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + buffer_mem_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + buffer_mem_barrier.srcAccessMask = p_src_access; + buffer_mem_barrier.dstAccessMask = p_dst_sccess; + buffer_mem_barrier.buffer = buffer; + buffer_mem_barrier.offset = p_from; + buffer_mem_barrier.size = p_size; + + vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 0, NULL, 1, &buffer_mem_barrier, 0, NULL); +} + /*****************/ /**** TEXTURE ****/ /*****************/ @@ -1715,7 +1732,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T } if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) { - texture.unbound_layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; + texture.unbound_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; } else { texture.unbound_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } @@ -2526,6 +2543,9 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, ERR_FAIL_COND_V(p_dst_mipmap >= dst_tex->mipmaps, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_dst_layer >= dst_layer_count, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V_MSG(src_tex->read_aspect_mask != dst_tex->read_aspect_mask, ERR_INVALID_PARAMETER, + "Source and destination texture must be of the same type (color or depth)."); + VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; { @@ -2586,7 +2606,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_copy_region.srcOffset.y = p_from.y; image_copy_region.srcOffset.z = p_from.z; - image_copy_region.dstSubresource.aspectMask = src_tex->barrier_aspect_mask; + image_copy_region.dstSubresource.aspectMask = dst_tex->read_aspect_mask; image_copy_region.dstSubresource.baseArrayLayer = p_dst_layer; image_copy_region.dstSubresource.layerCount = 1; image_copy_region.dstSubresource.mipLevel = p_dst_mipmap; @@ -2712,6 +2732,8 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector::Read r = p_data.read(); _buffer_update(&buffer, 0, r.ptr(), data_size); - _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, false); + _buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, false); } return vertex_buffer_owner.make_rid(buffer); @@ -3223,7 +3246,7 @@ RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBuff uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); _buffer_update(&index_buffer, 0, r.ptr(), data_size); - _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, false); + _buffer_memory_barrier(index_buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, false); } return index_buffer_owner.make_rid(index_buffer); } @@ -3934,7 +3957,7 @@ RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Po uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); _buffer_update(&buffer, 0, r.ptr(), data_size); - _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT, false); + _buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT, false); } return uniform_buffer_owner.make_rid(buffer); } @@ -3953,7 +3976,7 @@ RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Po uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); _buffer_update(&buffer, 0, r.ptr(), data_size); - _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, false); + _buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, false); } return storage_buffer_owner.make_rid(buffer); } @@ -3976,7 +3999,7 @@ RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataF uint64_t data_size = p_data.size(); PoolVector::Read r = p_data.read(); _buffer_update(&texture_buffer.buffer, 0, r.ptr(), data_size); - _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, false); + _buffer_memory_barrier(texture_buffer.buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, false); } VkBufferViewCreateInfo view_create_info; @@ -4400,7 +4423,8 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, Buffer *buffer = storage_buffer_owner.getornull(uniform.ids[0]); ERR_FAIL_COND_V_MSG(!buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid."); - ERR_FAIL_COND_V_MSG(buffer->size != (uint32_t)set_uniform.length, RID(), + //if 0, then its sized on link time + ERR_FAIL_COND_V_MSG(set_uniform.length > 0 && buffer->size != (uint32_t)set_uniform.length, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ")."); write.dstArrayElement = 0; @@ -4523,8 +4547,47 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint return err; } - _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, p_sync_with_draw); - + _buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, p_sync_with_draw); +#if 0 + if (p_sync_with_draw) { + VkMemoryBarrier memoryBarrier; + + memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + memoryBarrier.pNext = NULL; + memoryBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT | + VK_ACCESS_HOST_WRITE_BIT; + memoryBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT | + VK_ACCESS_HOST_WRITE_BIT; + + vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &memoryBarrier, 0, NULL, 0, NULL); + } +#endif return err; } @@ -5145,6 +5208,47 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff return OK; } +void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, const Vector &p_clear_colors) { + Vector clear_attachments; + int color_index = 0; + for (int i = 0; i < framebuffer->texture_ids.size(); i++) { + Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]); + VkClearAttachment clear_at; + if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + ERR_FAIL_INDEX(color_index, p_clear_colors.size()); //a bug + Color clear_color = p_clear_colors[color_index]; + clear_at.clearValue.color.float32[0] = clear_color.r; + clear_at.clearValue.color.float32[1] = clear_color.g; + clear_at.clearValue.color.float32[2] = clear_color.b; + clear_at.clearValue.color.float32[3] = clear_color.a; + clear_at.colorAttachment = color_index++; + clear_at.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + } else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + + clear_at.clearValue.depthStencil.depth = 1.0; + clear_at.clearValue.depthStencil.stencil = 0; + clear_at.colorAttachment = 0; + clear_at.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + if (format_has_stencil(texture->format)) { + clear_at.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + } else { + ERR_CONTINUE(true); + } + clear_attachments.push_back(clear_at); + } + + VkClearRect cr; + cr.baseArrayLayer = 0; + cr.layerCount = 1; + cr.rect.offset.x = viewport_offset.x; + cr.rect.offset.y = viewport_offset.y; + cr.rect.extent.width = viewport_size.width; + cr.rect.extent.height = viewport_size.height; + + vkCmdClearAttachments(draw_list->command_buffer, clear_attachments.size(), clear_attachments.ptr(), 1, &cr); +} + RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebuffer, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors, const Rect2 &p_region) { _THREAD_SAFE_METHOD_ @@ -5154,8 +5258,9 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu Point2i viewport_offset; Point2i viewport_size = framebuffer->size; + bool needs_clear_region = false; - if (p_region != Rect2()) { //check custom region + if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { //check custom region Rect2i viewport(viewport_offset, viewport_size); Rect2i regioni = p_region; if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) && @@ -5166,6 +5271,11 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu viewport_offset = regioni.position; viewport_size = regioni.size; + + if (p_initial_action == INITIAL_ACTION_CLEAR) { + p_initial_action = INITIAL_ACTION_KEEP_COLOR_AND_DEPTH; + needs_clear_region = true; + } } if (p_initial_action == INITIAL_ACTION_CLEAR) { //check clear values @@ -5196,6 +5306,10 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu draw_list_count = 0; draw_list_split = false; + if (needs_clear_region) { + _draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, p_clear_colors); + } + VkViewport viewport; viewport.x = viewport_offset.x; viewport.y = viewport_offset.y; @@ -5230,7 +5344,9 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p Point2i viewport_offset; Point2i viewport_size = framebuffer->size; - if (p_region != Rect2()) { //check custom region + bool needs_clear_region = false; + + if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { //check custom region Rect2i viewport(viewport_offset, viewport_size); Rect2i regioni = p_region; if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) && @@ -5241,6 +5357,11 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p viewport_offset = regioni.position; viewport_size = regioni.size; + + if (p_initial_action == INITIAL_ACTION_CLEAR) { + p_initial_action = INITIAL_ACTION_KEEP_COLOR_AND_DEPTH; + needs_clear_region = true; + } } if (p_initial_action == INITIAL_ACTION_CLEAR) { //check clear values @@ -5340,6 +5461,9 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p #ifdef DEBUG_ENABLED draw_list[i].validation.framebuffer_format = framebuffer->format_id; #endif + if (i == 0 && needs_clear_region) { + _draw_list_insert_clear_region(&draw_list[i], framebuffer, viewport_offset, viewport_size, p_clear_colors); + } VkViewport viewport; viewport.x = viewport_offset.x; @@ -5754,6 +5878,11 @@ void RenderingDeviceVulkan::draw_list_end() { } } draw_list_bound_textures.clear(); + + // To ensure proper synchronization, we must make sure rendering is done before: + // * Some buffer is copied + // * Another render pass happens (since we may be done + _memory_barrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT, true); } #if 0 void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_framebuffer, ID *p_draw_lists, uint32_t p_draw_list_count, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors) { -- cgit v1.2.3 From 6deffa62fbd1e91873afa663630b788b9ffabee3 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sat, 14 Sep 2019 00:37:42 -0300 Subject: Several fixes to 3D rendering, and multimesh implementation. --- drivers/vulkan/rendering_device_vulkan.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 8cc07c59b1..09b0f7113e 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -3969,7 +3969,7 @@ RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Po ERR_FAIL_COND_V(p_data.size() && (uint32_t)p_data.size() != p_size_bytes, RID()); Buffer buffer; - Error err = _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); + Error err = _buffer_allocate(&buffer, p_size_bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY); ERR_FAIL_COND_V(err != OK, RID()); if (p_data.size()) { @@ -4600,6 +4600,8 @@ PoolVector RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { buffer = index_buffer_owner.getornull(p_buffer); } else if (texture_buffer_owner.owns(p_buffer)) { buffer = &texture_buffer_owner.getornull(p_buffer)->buffer; + } else if (storage_buffer_owner.owns(p_buffer)) { + buffer = storage_buffer_owner.getornull(p_buffer); } else { ERR_FAIL_V_MSG(PoolVector(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving."); } -- cgit v1.2.3 From 123ee5995c989d7c2f0bb320fe94ef1702a48c13 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Fri, 20 Sep 2019 17:58:06 -0300 Subject: Visual GPU profiler and related profiling support in Vulkan. --- drivers/vulkan/rendering_device_vulkan.cpp | 76 ++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 09b0f7113e..dd638bb7ba 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -31,6 +31,7 @@ #include "rendering_device_vulkan.h" #include "core/hashfuncs.h" #include "core/os/file_access.h" +#include "core/os/os.h" #include "core/project_settings.h" #include "drivers/vulkan/vulkan_context.h" #include "thirdparty/spirv-reflect/spirv_reflect.h" @@ -6167,6 +6168,20 @@ void RenderingDeviceVulkan::advance_frame() { staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size(); staging_buffer_used = false; } + + if (frames[frame].timestamp_count) { + vkGetQueryPoolResults(device, frames[frame].timestamp_pool, 0, frames[frame].timestamp_count, sizeof(uint64_t) * max_timestamp_query_elements, frames[frame].timestamp_result_values, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); + SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names); + SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values); + } + + frames[frame].timestamp_result_count = frames[frame].timestamp_count; + frames[frame].timestamp_count = 0; + frames[frame].index = Engine::get_singleton()->get_frames_drawn(); +} + +uint32_t RenderingDeviceVulkan::get_frame_delay() const { + return frame_count; } void RenderingDeviceVulkan::_flush(bool p_current_frame) { @@ -6209,6 +6224,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) { device = p_context->get_device(); frame_count = p_context->get_swapchain_image_count() + 1; //always need one extra to ensure it's unused at any time, without having to use a fence for this. limits = p_context->get_device_limits(); + max_timestamp_query_elements = 256; { //initialize allocator @@ -6224,6 +6240,8 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) { //create setup and frame buffers for (int i = 0; i < frame_count; i++) { + frames[i].index = 0; + { //create command pool, one per frame is recommended VkCommandPoolCreateInfo cmd_pool_info; cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; @@ -6251,6 +6269,27 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) { err = vkAllocateCommandBuffers(device, &cmdbuf, &frames[i].draw_command_buffer); ERR_CONTINUE(err); } + + { + //create query pool + VkQueryPoolCreateInfo query_pool_create_info; + query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; + query_pool_create_info.flags = 0; + query_pool_create_info.pNext = NULL; + query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP; + query_pool_create_info.queryCount = max_timestamp_query_elements; + query_pool_create_info.pipelineStatistics = 0; + + vkCreateQueryPool(device, &query_pool_create_info, NULL, &frames[i].timestamp_pool); + + frames[i].timestamp_names = memnew_arr(String, max_timestamp_query_elements); + frames[i].timestamp_cpu_values = memnew_arr(uint64_t, max_timestamp_query_elements); + frames[i].timestamp_count = 0; + frames[i].timestamp_result_names = memnew_arr(String, max_timestamp_query_elements); + frames[i].timestamp_cpu_result_values = memnew_arr(uint64_t, max_timestamp_query_elements); + frames[i].timestamp_result_values = memnew_arr(uint64_t, max_timestamp_query_elements); + frames[i].timestamp_result_count = 0; + } } { @@ -6319,6 +6358,37 @@ void RenderingDeviceVulkan::_free_rids(T &p_owner, const char *p_type) { } } +void RenderingDeviceVulkan::capture_timestamp(const String &p_name, bool p_sync_to_draw) { + + ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements); + + vkCmdWriteTimestamp(p_sync_to_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, frames[frame].timestamp_pool, frames[frame].timestamp_count); + frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name; + frames[frame].timestamp_cpu_values[frames[frame].timestamp_count] = OS::get_singleton()->get_ticks_usec(); + frames[frame].timestamp_count++; +} + +uint32_t RenderingDeviceVulkan::get_captured_timestamps_count() const { + return frames[frame].timestamp_result_count; +} + +uint64_t RenderingDeviceVulkan::get_captured_timestamps_frame() const { + return frames[frame].index; +} + +uint64_t RenderingDeviceVulkan::get_captured_timestamp_gpu_time(uint32_t p_index) const { + ERR_FAIL_INDEX_V(p_index, frames[frame].timestamp_result_count, 0); + return frames[frame].timestamp_result_values[p_index]; +} +uint64_t RenderingDeviceVulkan::get_captured_timestamp_cpu_time(uint32_t p_index) const { + ERR_FAIL_INDEX_V(p_index, frames[frame].timestamp_result_count, 0); + return frames[frame].timestamp_cpu_result_values[p_index]; +} +String RenderingDeviceVulkan::get_captured_timestamp_name(uint32_t p_index) const { + ERR_FAIL_INDEX_V(p_index, frames[frame].timestamp_result_count, String()); + return frames[frame].timestamp_result_names[p_index]; +} + int RenderingDeviceVulkan::limit_get(Limit p_limit) { switch (p_limit) { case LIMIT_MAX_BOUND_UNIFORM_SETS: return limits.maxBoundDescriptorSets; @@ -6400,6 +6470,12 @@ void RenderingDeviceVulkan::finalize() { int f = (frame + i) % frame_count; _free_pending_resources(f); vkDestroyCommandPool(device, frames[i].command_pool, NULL); + vkDestroyQueryPool(device, frames[i].timestamp_pool, NULL); + memdelete_arr(frames[i].timestamp_names); + memdelete_arr(frames[i].timestamp_cpu_values); + memdelete_arr(frames[i].timestamp_result_names); + memdelete_arr(frames[i].timestamp_result_values); + memdelete_arr(frames[i].timestamp_cpu_result_values); } for (int i = 0; i < split_draw_list_allocators.size(); i++) { -- cgit v1.2.3 From 263bebe0237b85b1343ba17b117c8c43287ecc57 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Wed, 25 Sep 2019 16:44:44 -0300 Subject: Untested support for compute shaders --- drivers/vulkan/rendering_device_vulkan.cpp | 553 +++++++++++++++++++++++++---- 1 file changed, 491 insertions(+), 62 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index dd638bb7ba..7e9d11137e 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1604,6 +1604,10 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T image_create_info.usage |= VK_IMAGE_USAGE_SAMPLED_BIT; } + if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_STORAGE_BIT; + } + if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { image_create_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; } @@ -1723,39 +1727,41 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T texture.samples = p_format.samples; texture.allowed_shared_formats = p_format.shareable_formats; - //set bound and unbound layouts - if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + //set base layout based on usage priority - texture.read_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; - texture.barrier_aspect_mask = texture.read_aspect_mask; - if (format_has_stencil(p_format.format)) { - texture.barrier_aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT; - } + if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) { + //first priority, readable + texture.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) { - texture.unbound_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } else { - texture.unbound_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - } - texture.bound_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } else if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT) { + //second priority, storage + + texture.layout = VK_IMAGE_LAYOUT_GENERAL; } else if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + //third priority, color or depth - texture.read_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; - texture.barrier_aspect_mask = texture.read_aspect_mask; + texture.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) { - texture.unbound_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } else { - texture.unbound_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } else if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + + texture.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + } else { + texture.layout = VK_IMAGE_LAYOUT_GENERAL; + } + + if (p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + + texture.read_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; + texture.barrier_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT; + + if (format_has_stencil(p_format.format)) { + texture.barrier_aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT; } - texture.bound_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } else { texture.read_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; - texture.barrier_aspect_mask = texture.read_aspect_mask; - - texture.unbound_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - texture.bound_layout = VK_IMAGE_LAYOUT_UNDEFINED; //will never be bound + texture.barrier_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; } texture.bound = false; @@ -1825,7 +1831,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T image_memory_barrier.srcAccessMask = 0; image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - image_memory_barrier.newLayout = texture.unbound_layout; + image_memory_barrier.newLayout = texture.layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = texture.image; @@ -1835,7 +1841,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T image_memory_barrier.subresourceRange.baseArrayLayer = 0; image_memory_barrier.subresourceRange.layerCount = image_create_info.arrayLayers; - vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); } RID id = texture_owner.make_rid(texture); @@ -2081,7 +2087,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con image_memory_barrier.pNext = NULL; image_memory_barrier.srcAccessMask = 0; image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - image_memory_barrier.oldLayout = texture->unbound_layout; + image_memory_barrier.oldLayout = texture->layout; image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -2221,7 +2227,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - image_memory_barrier.newLayout = texture->unbound_layout; + image_memory_barrier.newLayout = texture->layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = texture->image; @@ -2231,7 +2237,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; image_memory_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); } return OK; @@ -2368,7 +2374,7 @@ PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 image_memory_barrier.pNext = NULL; image_memory_barrier.srcAccessMask = 0; image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - image_memory_barrier.oldLayout = tex->unbound_layout; + image_memory_barrier.oldLayout = tex->layout; image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -2446,7 +2452,7 @@ PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - image_memory_barrier.newLayout = tex->unbound_layout; + image_memory_barrier.newLayout = tex->layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = tex->image; @@ -2456,7 +2462,7 @@ PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 image_memory_barrier.subresourceRange.baseArrayLayer = p_layer; image_memory_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); } { //make dst readable @@ -2559,7 +2565,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.pNext = NULL; image_memory_barrier.srcAccessMask = 0; image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - image_memory_barrier.oldLayout = src_tex->unbound_layout; + image_memory_barrier.oldLayout = src_tex->layout; image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -2579,7 +2585,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.pNext = NULL; image_memory_barrier.srcAccessMask = 0; image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - image_memory_barrier.oldLayout = dst_tex->unbound_layout; + image_memory_barrier.oldLayout = dst_tex->layout; image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -2631,7 +2637,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - image_memory_barrier.newLayout = src_tex->unbound_layout; + image_memory_barrier.newLayout = src_tex->layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = src_tex->image; @@ -2641,7 +2647,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; image_memory_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); } { //make dst readable @@ -2652,7 +2658,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - image_memory_barrier.newLayout = dst_tex->unbound_layout; + image_memory_barrier.newLayout = dst_tex->layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -2663,7 +2669,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer; image_memory_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); } } @@ -2733,7 +2739,8 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector &p_stages uint32_t stages_processed = 0; + bool is_compute = false; + for (int i = 0; i < p_stages.size(); i++) { + if (p_stages[i].shader_stage == SHADER_STAGE_COMPUTE) { + is_compute = true; + ERR_FAIL_COND_V_MSG(p_stages.size() != 1, RID(), + "Compute shaders can only receive one stage, dedicated to compute."); + } ERR_FAIL_COND_V_MSG(stages_processed & (1 << p_stages[i].shader_stage), RID(), "Stage " + String(shader_stage_names[p_stages[i].shader_stage]) + " submitted more than once."); @@ -3793,6 +3807,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector &p_stages shader.vertex_input_mask = vertex_input_mask; shader.fragment_outputs = fragment_outputs; shader.push_constant = push_constant; + shader.is_compute = is_compute; String error_text; @@ -4166,6 +4181,8 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, List > image_infos; //used for verification to make sure a uniform set does not use a framebuffer bound texture Vector attachable_textures; + Vector mutable_sampled_textures; + Vector mutable_storage_textures; for (uint32_t i = 0; i < set_uniform_count; i++) { const UniformInfo &set_uniform = set_uniforms[i]; @@ -4259,9 +4276,14 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen } - img_info.imageLayout = texture->unbound_layout; + img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; image_info.push_back(img_info); + + if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) { + //can also be used as storage, add to mutable sampled + mutable_sampled_textures.push_back(texture); + } } write.dstArrayElement = 0; @@ -4306,9 +4328,14 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen } - img_info.imageLayout = texture->unbound_layout; + img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; image_info.push_back(img_info); + + if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) { + //can also be used as storage, add to mutable sampled + mutable_sampled_textures.push_back(texture); + } } write.dstArrayElement = 0; @@ -4321,7 +4348,54 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, type_size = uniform.ids.size(); } break; case UNIFORM_TYPE_IMAGE: { - //todo + + if (uniform.ids.size() != set_uniform.length) { + if (set_uniform.length > 1) { + ERR_FAIL_V_MSG(RID(), "Image (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + } else { + ERR_FAIL_V_MSG(RID(), "Image (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.ids.size()) + ")."); + } + } + + Vector image_info; + + for (int j = 0; j < uniform.ids.size(); j++) { + Texture *texture = texture_owner.getornull(uniform.ids[j]); + + ERR_FAIL_COND_V_MSG(!texture, RID(), + "Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture."); + + ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), RID(), + "Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_STORAGE_BIT usage flag set in order to be used as uniform."); + + VkDescriptorImageInfo img_info; + img_info.sampler = NULL; + img_info.imageView = texture->view; + + if (texture->owner.is_valid()) { + texture = texture_owner.getornull(texture->owner); + ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen + } + + img_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + + image_info.push_back(img_info); + + if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) { + //can also be used as storage, add to mutable sampled + mutable_storage_textures.push_back(texture); + } + } + + write.dstArrayElement = 0; + write.descriptorCount = uniform.ids.size(); + write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); + write.pBufferInfo = NULL; + write.pTexelBufferView = NULL; + + type_size = uniform.ids.size(); + } break; case UNIFORM_TYPE_TEXTURE_BUFFER: { if (uniform.ids.size() != set_uniform.length) { @@ -4476,6 +4550,8 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector &p_uniforms, uniform_set.descriptor_set = descriptor_set; uniform_set.format = shader->set_formats[p_shader_set]; uniform_set.attachable_textures = attachable_textures; + uniform_set.mutable_sampled_textures = mutable_sampled_textures; + uniform_set.mutable_storage_textures = mutable_storage_textures; uniform_set.shader_set = p_shader_set; uniform_set.shader_id = p_shader; @@ -4651,6 +4727,9 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND_V(!shader, RID()); + ERR_FAIL_COND_V_MSG(shader->is_compute, RID(), + "Compute shaders can't be used in render pipelines"); + if (p_framebuffer_format == INVALID_ID) { //if nothing provided, use an empty one (no attachments) p_framebuffer_format = framebuffer_format_create(Vector()); @@ -4996,7 +5075,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma pipeline.validation.primitive_minimum = primitive_minimum[p_render_primitive]; #endif //create ID to associate with this pipeline - RID id = pipeline_owner.make_rid(pipeline); + RID id = render_pipeline_owner.make_rid(pipeline); //now add aall the dependencies _add_dependency(id, p_shader); return id; @@ -5004,7 +5083,55 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma bool RenderingDeviceVulkan::render_pipeline_is_valid(RID p_pipeline) { _THREAD_SAFE_METHOD_ - return pipeline_owner.owns(p_pipeline); + return render_pipeline_owner.owns(p_pipeline); +} + +/**************************/ +/**** COMPUTE PIPELINE ****/ +/**************************/ + +RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader) { + _THREAD_SAFE_METHOD_ + + //needs a shader + Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, RID()); + + ERR_FAIL_COND_V_MSG(!shader->is_compute, RID(), + "Non-compute shaders can't be used in compute pipelines"); + + //finally, pipeline create info + VkComputePipelineCreateInfo compute_pipeline_create_info; + + compute_pipeline_create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + compute_pipeline_create_info.pNext = NULL; + compute_pipeline_create_info.flags = 0; + + compute_pipeline_create_info.stage = shader->pipeline_stages[0]; + compute_pipeline_create_info.layout = shader->pipeline_layout; + compute_pipeline_create_info.basePipelineHandle = NULL; + compute_pipeline_create_info.basePipelineIndex = 0; + + ComputePipeline pipeline; + VkResult err = vkCreateComputePipelines(device, NULL, 1, &compute_pipeline_create_info, NULL, &pipeline.pipeline); + ERR_FAIL_COND_V(err, RID()); + + pipeline.set_formats = shader->set_formats; + pipeline.push_constant_stages = shader->push_constant.push_constants_vk_stage; + pipeline.pipeline_layout = shader->pipeline_layout; + pipeline.shader = p_shader; + pipeline.push_constant_size = shader->push_constant.push_constant_size; + + //create ID to associate with this pipeline + RID id = compute_pipeline_owner.make_rid(pipeline); + //now add aall the dependencies + _add_dependency(id, p_shader); + return id; +} + +bool RenderingDeviceVulkan::compute_pipeline_is_valid(RID p_pipeline) { + + return compute_pipeline_owner.owns(p_pipeline); } /****************/ @@ -5055,6 +5182,8 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(in _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V_MSG(draw_list != NULL, INVALID_ID, "Only one draw list can be active at the same time."); + ERR_FAIL_COND_V_MSG(compute_list != NULL, INVALID_ID, "Only one draw/compute list can be active at the same time."); + VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; draw_list = memnew(DrawList); draw_list->command_buffer = command_buffer; @@ -5256,6 +5385,9 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu _THREAD_SAFE_METHOD_ + ERR_FAIL_COND_V_MSG(draw_list != NULL, INVALID_ID, "Only one draw list can be active at the same time."); + ERR_FAIL_COND_V_MSG(compute_list != NULL, INVALID_ID, "Only one draw/compute list can be active at the same time."); + Framebuffer *framebuffer = framebuffer_owner.getornull(p_framebuffer); ERR_FAIL_COND_V(!framebuffer, INVALID_ID); @@ -5530,7 +5662,7 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); #endif - const RenderPipeline *pipeline = pipeline_owner.getornull(p_render_pipeline); + const RenderPipeline *pipeline = render_pipeline_owner.getornull(p_render_pipeline); ERR_FAIL_COND(!pipeline); #ifdef DEBUG_ENABLED ERR_FAIL_COND(pipeline->validation.framebuffer_format != dl->validation.framebuffer_format); @@ -5887,6 +6019,284 @@ void RenderingDeviceVulkan::draw_list_end() { // * Another render pass happens (since we may be done _memory_barrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT, true); } + +/***********************/ +/**** COMPUTE LISTS ****/ +/***********************/ + +RenderingDevice::ComputeListID RenderingDeviceVulkan::compute_list_begin() { + + ERR_FAIL_COND_V_MSG(draw_list != NULL, INVALID_ID, "Only one draw list can be active at the same time."); + ERR_FAIL_COND_V_MSG(compute_list != NULL, INVALID_ID, "Only one draw/compute list can be active at the same time."); + + compute_list = memnew(ComputeList); + compute_list->command_buffer = frames[frame].draw_command_buffer; + + return ID_TYPE_COMPUTE_LIST; +} + +void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_list, RID p_compute_pipeline) { + ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); + ERR_FAIL_COND(!compute_list); + + ComputeList *cl = compute_list; + + const ComputePipeline *pipeline = compute_pipeline_owner.getornull(p_compute_pipeline); + ERR_FAIL_COND(!pipeline); + + if (p_compute_pipeline == cl->state.pipeline) { + return; //redundant state, return. + } + + cl->state.pipeline = p_compute_pipeline; + cl->state.pipeline_layout = pipeline->pipeline_layout; + + vkCmdBindPipeline(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->pipeline); + + if (cl->state.pipeline_shader != pipeline->shader) { + // shader changed, so descriptor sets may become incompatible. + + //go through ALL sets, and unbind them (and all those above) if the format is different + + uint32_t pcount = pipeline->set_formats.size(); //formats count in this pipeline + cl->state.set_count = MAX(cl->state.set_count, pcount); + const uint32_t *pformats = pipeline->set_formats.ptr(); //pipeline set formats + + bool sets_valid = true; //once invalid, all above become invalid + for (uint32_t i = 0; i < pcount; i++) { + //if a part of the format is different, invalidate it (and the rest) + if (!sets_valid || cl->state.sets[i].pipeline_expected_format != pformats[i]) { + cl->state.sets[i].bound = false; + cl->state.sets[i].pipeline_expected_format = pformats[i]; + sets_valid = false; + } + } + + for (uint32_t i = pcount; i < cl->state.set_count; i++) { + //unbind the ones above (not used) if exist + cl->state.sets[i].bound = false; + } + + cl->state.set_count = pcount; //update set count + + if (pipeline->push_constant_size) { + cl->state.pipeline_push_constant_stages = pipeline->push_constant_stages; +#ifdef DEBUG_ENABLED + cl->validation.pipeline_push_constant_suppplied = false; +#endif + } + } + +#ifdef DEBUG_ENABLED + //update compute pass pipeline info + cl->validation.pipeline_active = true; + cl->validation.pipeline_push_constant_size = pipeline->push_constant_size; +#endif +} +void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list, RID p_uniform_set, uint32_t p_index) { + ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); + ERR_FAIL_COND(!compute_list); + + ComputeList *cl = compute_list; + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(p_index >= limits.maxBoundDescriptorSets || p_index > MAX_UNIFORM_SETS, + "Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ")."); +#endif + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified."); +#endif + + UniformSet *uniform_set = uniform_set_owner.getornull(p_uniform_set); + ERR_FAIL_COND(!uniform_set); + + if (p_index > cl->state.set_count) { + cl->state.set_count = p_index; + } + + cl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; //update set pointer + cl->state.sets[p_index].bound = false; //needs rebind + cl->state.sets[p_index].uniform_set_format = uniform_set->format; + cl->state.sets[p_index].uniform_set = p_uniform_set; + + uint32_t textures_to_sampled_count = uniform_set->mutable_sampled_textures.size(); + Texture **textures_to_sampled = uniform_set->mutable_sampled_textures.ptrw(); + + for (uint32_t i = 0; i < textures_to_sampled_count; i++) { + if (textures_to_sampled[i]->layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.oldLayout = textures_to_sampled[i]->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = textures_to_sampled[i]->image; + image_memory_barrier.subresourceRange.aspectMask = textures_to_sampled[i]->read_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = textures_to_sampled[i]->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.layerCount = textures_to_sampled[i]->layers; + + vkCmdPipelineBarrier(cl->command_buffer, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + + textures_to_sampled[i]->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + cl->state.textures_to_sampled_layout.erase(textures_to_sampled[i]); + } + } + + uint32_t textures_to_storage_count = uniform_set->mutable_storage_textures.size(); + Texture **textures_to_storage = uniform_set->mutable_storage_textures.ptrw(); + + for (uint32_t i = 0; i < textures_to_storage_count; i++) { + if (textures_to_storage[i]->layout != VK_IMAGE_LAYOUT_GENERAL) { + + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.oldLayout = textures_to_storage[i]->layout; + 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 = textures_to_storage[i]->image; + image_memory_barrier.subresourceRange.aspectMask = textures_to_sampled[i]->read_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = textures_to_storage[i]->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.layerCount = textures_to_storage[i]->layers; + + vkCmdPipelineBarrier(cl->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + + textures_to_storage[i]->layout = VK_IMAGE_LAYOUT_GENERAL; + + cl->state.textures_to_sampled_layout.insert(textures_to_storage[i]); //needs to go back to sampled layout afterwards + } + } + +#if 0 + { //validate that textures bound are not attached as framebuffer bindings + uint32_t attachable_count = uniform_set->attachable_textures.size(); + const RID *attachable_ptr = uniform_set->attachable_textures.ptr(); + uint32_t bound_count = draw_list_bound_textures.size(); + const RID *bound_ptr = draw_list_bound_textures.ptr(); + for (uint32_t i = 0; i < attachable_count; i++) { + for (uint32_t j = 0; j < bound_count; j++) { + ERR_FAIL_COND_MSG(attachable_ptr[i] == bound_ptr[j], + "Attempted to use the same texture in framebuffer attachment and a uniform set, this is not allowed."); + } + } + } +#endif +} +void RenderingDeviceVulkan::compute_list_set_push_constant(ComputeListID p_list, void *p_data, uint32_t p_data_size) { + ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); + ERR_FAIL_COND(!compute_list); + + ComputeList *cl = compute_list; + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified."); +#endif + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(p_data_size != cl->validation.pipeline_push_constant_size, + "This compute pipeline requires (" + itos(cl->validation.pipeline_push_constant_size) + ") bytes of push constant data, supplied: (" + itos(p_data_size) + ")"); +#endif + vkCmdPushConstants(cl->command_buffer, cl->state.pipeline_layout, cl->state.pipeline_push_constant_stages, 0, p_data_size, p_data); +#ifdef DEBUG_ENABLED + cl->validation.pipeline_push_constant_suppplied = true; +#endif +} +void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) { + ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); + ERR_FAIL_COND(!compute_list); + + ComputeList *cl = compute_list; + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified."); +#endif + +#ifdef DEBUG_ENABLED + + ERR_FAIL_COND_MSG(!cl->validation.pipeline_active, "No compute pipeline was set before attempting to draw."); + + if (cl->validation.pipeline_push_constant_size > 0) { + //using push constants, check that they were supplied + ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_suppplied, + "The shader in this pipeline requires a push constant to be set before drawing, but it's not present."); + } + +#endif + + //Bind descriptor sets + + for (uint32_t i = 0; i < cl->state.set_count; i++) { + + if (cl->state.sets[i].pipeline_expected_format == 0) { + continue; //nothing expected by this pipeline + } +#ifdef DEBUG_ENABLED + if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) { + + if (cl->state.sets[i].uniform_set_format == 0) { + ERR_FAIL_MSG("Uniforms were never supplied for set (" + itos(i) + ") at the time of drawing, which are required by the pipeline"); + } else if (uniform_set_owner.owns(cl->state.sets[i].uniform_set)) { + UniformSet *us = uniform_set_owner.getornull(cl->state.sets[i].uniform_set); + ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + "):\n" + _shader_uniform_debug(us->shader_id, us->shader_set) + "\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader)); + } else { + ERR_FAIL_MSG("Uniforms supplied for set (" + itos(i) + ", which was was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n" + _shader_uniform_debug(cl->state.pipeline_shader)); + } + } +#endif + if (!cl->state.sets[i].bound) { + //All good, see if this requires re-binding + vkCmdBindDescriptorSets(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, cl->state.pipeline_layout, i, 1, &cl->state.sets[i].descriptor_set, 0, NULL); + cl->state.sets[i].bound = true; + } + } + + vkCmdDispatch(cl->command_buffer, p_x_groups, p_y_groups, p_z_groups); +} +void RenderingDeviceVulkan::compute_list_end() { + ERR_FAIL_COND(!compute_list); + + for (Set::Element *E = compute_list->state.textures_to_sampled_layout.front(); E; E = E->next()) { + + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = E->get()->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = E->get()->image; + image_memory_barrier.subresourceRange.aspectMask = E->get()->read_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = 0; + image_memory_barrier.subresourceRange.levelCount = E->get()->mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = 0; + image_memory_barrier.subresourceRange.layerCount = E->get()->layers; + + vkCmdPipelineBarrier(compute_list->command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + + E->get()->layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + + memdelete(compute_list); +} + #if 0 void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_framebuffer, ID *p_draw_lists, uint32_t p_draw_list_count, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors) { @@ -5998,10 +6408,14 @@ void RenderingDeviceVulkan::_free_internal(RID p_id) { UniformSet *uniform_set = uniform_set_owner.getornull(p_id); frames[frame].uniform_sets_to_dispose_of.push_back(*uniform_set); uniform_set_owner.free(p_id); - } else if (pipeline_owner.owns(p_id)) { - RenderPipeline *pipeline = pipeline_owner.getornull(p_id); - frames[frame].pipelines_to_dispose_of.push_back(*pipeline); - pipeline_owner.free(p_id); + } else if (render_pipeline_owner.owns(p_id)) { + RenderPipeline *pipeline = render_pipeline_owner.getornull(p_id); + frames[frame].render_pipelines_to_dispose_of.push_back(*pipeline); + render_pipeline_owner.free(p_id); + } else if (compute_pipeline_owner.owns(p_id)) { + ComputePipeline *pipeline = compute_pipeline_owner.getornull(p_id); + frames[frame].compute_pipelines_to_dispose_of.push_back(*pipeline); + compute_pipeline_owner.free(p_id); } else { ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id())); } @@ -6022,6 +6436,10 @@ void RenderingDeviceVulkan::finalize_frame() { ERR_PRINT("Found open draw list at the end of the frame, this should never happen (further drawing will likely not work)."); } + if (compute_list) { + ERR_PRINT("Found open compute list at the end of the frame, this should never happen (further compute will likely not work)."); + } + { //complete the setup buffer (that needs to be processed before anything else) vkEndCommandBuffer(frames[frame].setup_command_buffer); vkEndCommandBuffer(frames[frame].draw_command_buffer); @@ -6032,12 +6450,20 @@ void RenderingDeviceVulkan::finalize_frame() { void RenderingDeviceVulkan::_free_pending_resources(int p_frame) { //free in dependency usage order, so nothing weird happens //pipelines - while (frames[p_frame].pipelines_to_dispose_of.front()) { - RenderPipeline *pipeline = &frames[p_frame].pipelines_to_dispose_of.front()->get(); + while (frames[p_frame].render_pipelines_to_dispose_of.front()) { + RenderPipeline *pipeline = &frames[p_frame].render_pipelines_to_dispose_of.front()->get(); + + vkDestroyPipeline(device, pipeline->pipeline, NULL); + + frames[p_frame].render_pipelines_to_dispose_of.pop_front(); + } + + while (frames[p_frame].compute_pipelines_to_dispose_of.front()) { + ComputePipeline *pipeline = &frames[p_frame].compute_pipelines_to_dispose_of.front()->get(); vkDestroyPipeline(device, pipeline->pipeline, NULL); - frames[p_frame].pipelines_to_dispose_of.pop_front(); + frames[p_frame].compute_pipelines_to_dispose_of.pop_front(); } //uniform sets @@ -6344,6 +6770,8 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) { draw_list = NULL; draw_list_count = 0; draw_list_split = false; + + compute_list = NULL; } template @@ -6430,7 +6858,8 @@ void RenderingDeviceVulkan::finalize() { _flush(false); - _free_rids(pipeline_owner, "Pipeline"); + _free_rids(render_pipeline_owner, "Pipeline"); + _free_rids(compute_pipeline_owner, "Compute"); _free_rids(uniform_set_owner, "UniformSet"); _free_rids(texture_buffer_owner, "TextureBuffer"); _free_rids(storage_buffer_owner, "StorageBuffer"); -- cgit v1.2.3 From acf0f6c8a7955517ef71ec95c683a6ff7bd5f437 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Thu, 3 Oct 2019 17:39:08 -0300 Subject: GIProbes working. --- drivers/vulkan/rendering_device_vulkan.cpp | 356 +++++++++++++++++++---------- 1 file changed, 234 insertions(+), 122 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 7e9d11137e..118679a8b5 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1950,6 +1950,9 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_CUBEMAP && (src_texture->type != TEXTURE_TYPE_CUBE && src_texture->type != TEXTURE_TYPE_CUBE_ARRAY), RID(), "Can only create a cubemap slice from a cubemap or cubemap array mipmap"); + ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_3D && src_texture->type != TEXTURE_TYPE_3D, RID(), + "Can only create a 3D slice from a 3D texture"); + //create view ERR_FAIL_INDEX_V(p_mipmap, src_texture->mipmaps, RID()); @@ -1976,7 +1979,7 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p VK_IMAGE_VIEW_TYPE_2D, }; - image_view_create_info.viewType = p_slice_type == TEXTURE_SLICE_CUBEMAP ? VK_IMAGE_VIEW_TYPE_CUBE : view_types[texture.type]; + image_view_create_info.viewType = p_slice_type == TEXTURE_SLICE_CUBEMAP ? VK_IMAGE_VIEW_TYPE_CUBE : (p_slice_type == TEXTURE_SLICE_3D ? VK_IMAGE_VIEW_TYPE_3D : view_types[texture.type]); if (p_view.format_override == DATA_FORMAT_MAX || p_view.format_override == texture.format) { image_view_create_info.format = vulkan_formats[texture.format]; } else { @@ -2676,6 +2679,94 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, return OK; } +Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw) { + + Texture *src_tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER); + + ERR_FAIL_COND_V_MSG(p_sync_with_draw && src_tex->bound, ERR_INVALID_PARAMETER, + "Source texture can't be cleared while a render pass that uses it is being created. Ensure render pass is finalized (and that it was created with RENDER_PASS_CONTENTS_FINISH) to unbind this texture."); + + ERR_FAIL_COND_V(p_layers == 0, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_mipmaps == 0, ERR_INVALID_PARAMETER); + + ERR_FAIL_COND_V_MSG(!(src_tex->usage_flags & TEXTURE_USAGE_CAN_COPY_TO_BIT), ERR_INVALID_PARAMETER, + "Source texture requires the TEXTURE_USAGE_CAN_COPY_TO_BIT in order to be cleared."); + + uint32_t src_layer_count = src_tex->layers; + if (src_tex->type == TEXTURE_TYPE_CUBE || src_tex->type == TEXTURE_TYPE_CUBE_ARRAY) { + src_layer_count *= 6; + } + + ERR_FAIL_COND_V(p_base_mipmap + p_mipmaps > src_tex->mipmaps, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_base_layer + p_layers > src_layer_count, ERR_INVALID_PARAMETER); + + VkCommandBuffer command_buffer = p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; + + VkImageLayout layout = src_tex->layout; + + if (src_tex->layout != VK_IMAGE_LAYOUT_GENERAL) { //storage may be in general state + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = 0; + image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.oldLayout = src_tex->layout; + image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = src_tex->image; + image_memory_barrier.subresourceRange.aspectMask = src_tex->read_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = p_base_mipmap; + image_memory_barrier.subresourceRange.levelCount = p_mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = p_base_layer; + image_memory_barrier.subresourceRange.layerCount = p_layers; + + layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + VkClearColorValue clear_color; + clear_color.float32[0] = p_color.r; + clear_color.float32[1] = p_color.g; + clear_color.float32[2] = p_color.b; + clear_color.float32[3] = p_color.a; + + VkImageSubresourceRange range; + range.aspectMask = src_tex->read_aspect_mask; + range.baseArrayLayer = p_base_layer; + range.layerCount = p_layers; + range.baseMipLevel = p_base_mipmap; + range.levelCount = p_mipmaps; + + vkCmdClearColorImage(command_buffer, src_tex->image, layout, &clear_color, 1, &range); + + if (src_tex->layout != VK_IMAGE_LAYOUT_GENERAL) { //storage may be in general state + + VkImageMemoryBarrier image_memory_barrier; + image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_memory_barrier.pNext = NULL; + image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_memory_barrier.newLayout = src_tex->layout; + + image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_memory_barrier.image = src_tex->image; + image_memory_barrier.subresourceRange.aspectMask = src_tex->read_aspect_mask; + image_memory_barrier.subresourceRange.baseMipLevel = p_base_mipmap; + image_memory_barrier.subresourceRange.levelCount = p_mipmaps; + image_memory_barrier.subresourceRange.baseArrayLayer = p_base_layer; + image_memory_barrier.subresourceRange.layerCount = p_layers; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + } + + return OK; +} + bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const { ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false); @@ -2719,7 +2810,7 @@ bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_f /**** ATTACHMENT ****/ /********************/ -VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector &p_format, InitialAction p_initial_action, FinalAction p_final_action, int *r_color_attachment_count) { +VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector &p_format, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, int *r_color_attachment_count) { Vector attachments; Vector color_references; @@ -2739,17 +2830,18 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vectorframebuffers.has(vk)) { //need to create this version Framebuffer::Version version; - version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, p_initial_action, p_final_action); + version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action); VkFramebufferCreateInfo framebuffer_create_info; framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; @@ -5283,7 +5344,7 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu return OK; } -Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents) { +Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents) { VkRenderPassBeginInfo render_pass_begin; render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; @@ -5297,12 +5358,15 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff render_pass_begin.renderArea.offset.y = viewport_offset.y; Vector clear_values; - if (p_initial_action == INITIAL_ACTION_CLEAR) { + clear_values.resize(framebuffer->texture_ids.size()); + + { int color_index = 0; for (int i = 0; i < framebuffer->texture_ids.size(); i++) { Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]); VkClearValue clear_value; - if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + + if (color_index < p_clear_colors.size() && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); //a bug Color clear_color = p_clear_colors[color_index]; clear_value.color.float32[0] = clear_color.r; @@ -5311,15 +5375,15 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff clear_value.color.float32[3] = clear_color.a; color_index++; } else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - clear_value.depthStencil.depth = 1.0; - clear_value.depthStencil.stencil = 0; + clear_value.depthStencil.depth = p_clear_depth; + clear_value.depthStencil.stencil = p_clear_stencil; } else { clear_value.color.float32[0] = 0; clear_value.color.float32[1] = 0; clear_value.color.float32[2] = 0; clear_value.color.float32[3] = 0; } - clear_values.push_back(clear_value); + clear_values.write[i] = clear_value; } } @@ -5330,7 +5394,9 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff //mark textures as bound draw_list_bound_textures.clear(); - draw_list_unbind_textures = p_final_action != FINAL_ACTION_CONTINUE; + draw_list_unbind_color_textures = p_final_color_action != FINAL_ACTION_CONTINUE; + draw_list_unbind_depth_textures = p_final_depth_action != FINAL_ACTION_CONTINUE; + for (int i = 0; i < framebuffer->texture_ids.size(); i++) { Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]); texture->bound = true; @@ -5340,13 +5406,13 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff return OK; } -void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, const Vector &p_clear_colors) { +void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, bool p_clear_color, const Vector &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil) { Vector clear_attachments; int color_index = 0; for (int i = 0; i < framebuffer->texture_ids.size(); i++) { Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]); VkClearAttachment clear_at; - if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + if (p_clear_color && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { ERR_FAIL_INDEX(color_index, p_clear_colors.size()); //a bug Color clear_color = p_clear_colors[color_index]; clear_at.clearValue.color.float32[0] = clear_color.r; @@ -5355,10 +5421,10 @@ void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list, clear_at.clearValue.color.float32[3] = clear_color.a; clear_at.colorAttachment = color_index++; clear_at.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - } else if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + } else if (p_clear_depth && texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - clear_at.clearValue.depthStencil.depth = 1.0; - clear_at.clearValue.depthStencil.stencil = 0; + clear_at.clearValue.depthStencil.depth = p_depth; + clear_at.clearValue.depthStencil.stencil = p_stencil; clear_at.colorAttachment = 0; clear_at.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; if (format_has_stencil(texture->format)) { @@ -5381,7 +5447,7 @@ void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list, vkCmdClearAttachments(draw_list->command_buffer, clear_attachments.size(), clear_attachments.ptr(), 1, &cr); } -RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebuffer, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors, const Rect2 &p_region) { +RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region) { _THREAD_SAFE_METHOD_ @@ -5393,7 +5459,8 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu Point2i viewport_offset; Point2i viewport_size = framebuffer->size; - bool needs_clear_region = false; + bool needs_clear_color = false; + bool needs_clear_depth = false; if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { //check custom region Rect2i viewport(viewport_offset, viewport_size); @@ -5407,27 +5474,31 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu viewport_offset = regioni.position; viewport_size = regioni.size; - if (p_initial_action == INITIAL_ACTION_CLEAR) { - p_initial_action = INITIAL_ACTION_KEEP_COLOR_AND_DEPTH; - needs_clear_region = true; + if (p_initial_color_action == INITIAL_ACTION_CLEAR) { + needs_clear_color = true; + p_initial_color_action = INITIAL_ACTION_KEEP; + } + if (p_initial_depth_action == INITIAL_ACTION_CLEAR) { + needs_clear_depth = true; + p_initial_depth_action = INITIAL_ACTION_KEEP; } } - if (p_initial_action == INITIAL_ACTION_CLEAR) { //check clear values + if (p_initial_color_action == INITIAL_ACTION_CLEAR) { //check clear values int color_attachments = framebuffer_formats[framebuffer->format_id].color_attachments; - ERR_FAIL_COND_V_MSG(p_clear_colors.size() != color_attachments, INVALID_ID, - "Clear color values supplied (" + itos(p_clear_colors.size()) + ") differ from the amount required for framebuffer (" + itos(color_attachments) + ")."); + ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_attachments, INVALID_ID, + "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer (" + itos(color_attachments) + ")."); } VkFramebuffer vkframebuffer; VkRenderPass render_pass; - Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_action, p_final_action, &vkframebuffer, &render_pass); + Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &vkframebuffer, &render_pass); ERR_FAIL_COND_V(err != OK, INVALID_ID); VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; - err = _draw_list_render_pass_begin(framebuffer, p_initial_action, p_final_action, p_clear_colors, viewport_offset, viewport_size, vkframebuffer, render_pass, command_buffer, VK_SUBPASS_CONTENTS_INLINE); + err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, vkframebuffer, render_pass, command_buffer, VK_SUBPASS_CONTENTS_INLINE); if (err != OK) { return INVALID_ID; @@ -5441,8 +5512,8 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu draw_list_count = 0; draw_list_split = false; - if (needs_clear_region) { - _draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, p_clear_colors); + if (needs_clear_color || needs_clear_depth) { + _draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil); } VkViewport viewport; @@ -5467,7 +5538,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu return ID_TYPE_DRAW_LIST; } -Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_action, FinalAction p_final_action, const Vector &p_clear_colors, const Rect2 &p_region) { +Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region) { _THREAD_SAFE_METHOD_ @@ -5479,7 +5550,8 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p Point2i viewport_offset; Point2i viewport_size = framebuffer->size; - bool needs_clear_region = false; + bool needs_clear_color = false; + bool needs_clear_depth = false; if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { //check custom region Rect2i viewport(viewport_offset, viewport_size); @@ -5493,17 +5565,21 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p viewport_offset = regioni.position; viewport_size = regioni.size; - if (p_initial_action == INITIAL_ACTION_CLEAR) { - p_initial_action = INITIAL_ACTION_KEEP_COLOR_AND_DEPTH; - needs_clear_region = true; + if (p_initial_color_action == INITIAL_ACTION_CLEAR) { + needs_clear_color = true; + p_initial_color_action = INITIAL_ACTION_KEEP; + } + if (p_initial_depth_action == INITIAL_ACTION_CLEAR) { + needs_clear_depth = true; + p_initial_depth_action = INITIAL_ACTION_KEEP; } } - if (p_initial_action == INITIAL_ACTION_CLEAR) { //check clear values + if (p_initial_color_action == INITIAL_ACTION_CLEAR) { //check clear values int color_attachments = framebuffer_formats[framebuffer->format_id].color_attachments; - ERR_FAIL_COND_V_MSG(p_clear_colors.size() != color_attachments, ERR_INVALID_PARAMETER, - "Clear color values supplied (" + itos(p_clear_colors.size()) + ") differ from the amount required for framebuffer (" + itos(color_attachments) + ")."); + ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_attachments, ERR_INVALID_PARAMETER, + "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer (" + itos(color_attachments) + ")."); } if (p_splits > (uint32_t)split_draw_list_allocators.size()) { @@ -5543,11 +5619,11 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p VkFramebuffer vkframebuffer; VkRenderPass render_pass; - Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_action, p_final_action, &vkframebuffer, &render_pass); + Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &vkframebuffer, &render_pass); ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); VkCommandBuffer frame_command_buffer = frames[frame].draw_command_buffer; - err = _draw_list_render_pass_begin(framebuffer, p_initial_action, p_final_action, p_clear_colors, viewport_offset, viewport_size, vkframebuffer, render_pass, frame_command_buffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + err = _draw_list_render_pass_begin(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, viewport_offset, viewport_size, vkframebuffer, render_pass, frame_command_buffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); if (err != OK) { return ERR_CANT_CREATE; @@ -5596,8 +5672,9 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p #ifdef DEBUG_ENABLED draw_list[i].validation.framebuffer_format = framebuffer->format_id; #endif - if (i == 0 && needs_clear_region) { - _draw_list_insert_clear_region(&draw_list[i], framebuffer, viewport_offset, viewport_size, p_clear_colors); + + if (i == 0 && (needs_clear_color || needs_clear_depth)) { + _draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil); } VkViewport viewport; @@ -5626,6 +5703,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p } RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(DrawListID p_id) { + if (p_id < 0) { return NULL; } @@ -5841,7 +5919,7 @@ void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, void #endif } -void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances) { +void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances, uint32_t p_procedural_vertices) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); @@ -5902,8 +5980,12 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices if (p_use_indices) { #ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(p_procedural_vertices > 0, + "Procedural vertices can't be used together with indices."); + ERR_FAIL_COND_MSG(!dl->validation.index_array_size, "Draw command requested indices, but no index buffer was set."); + if (dl->validation.pipeline_vertex_format != INVALID_ID) { //uses vertices, do some vertex validations ERR_FAIL_COND_MSG(dl->validation.vertex_array_size < dl->validation.index_array_max_index, @@ -5924,11 +6006,23 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices #endif vkCmdDrawIndexed(dl->command_buffer, to_draw, p_instances, dl->validation.index_array_offset, 0, 0); } else { + + uint32_t to_draw; + + if (p_procedural_vertices > 0) { #ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID, - "Draw command lacks indices, but pipeline format does not use vertices."); + "Procedural vertices requested, but pipeline expects a vertex array."); #endif - uint32_t to_draw = dl->validation.vertex_array_size; + to_draw = p_procedural_vertices; + } else { + +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID, + "Draw command lacks indices, but pipeline format does not use vertices."); +#endif + to_draw = dl->validation.vertex_array_size; + } #ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(to_draw < dl->validation.pipeline_primitive_minimum, @@ -5937,6 +6031,7 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices ERR_FAIL_COND_MSG((to_draw % dl->validation.pipeline_primitive_divisor) != 0, "Vertex amount (" + itos(to_draw) + ") must be a multiple of the amount of vertices required by the render primitive (" + itos(dl->validation.pipeline_primitive_divisor) + ")."); #endif + vkCmdDraw(dl->command_buffer, to_draw, p_instances, 0, 0); } } @@ -6005,13 +6100,17 @@ void RenderingDeviceVulkan::draw_list_end() { draw_list = NULL; } - if (draw_list_unbind_textures) { - for (int i = 0; i < draw_list_bound_textures.size(); i++) { - Texture *texture = texture_owner.getornull(draw_list_bound_textures[i]); - ERR_CONTINUE(!texture); //wtf + for (int i = 0; i < draw_list_bound_textures.size(); i++) { + Texture *texture = texture_owner.getornull(draw_list_bound_textures[i]); + ERR_CONTINUE(!texture); //wtf + if (draw_list_unbind_color_textures && (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) { + texture->bound = false; + } + if (draw_list_unbind_depth_textures && (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { texture->bound = false; } } + draw_list_bound_textures.clear(); // To ensure proper synchronization, we must make sure rendering is done before: @@ -6168,7 +6267,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list, image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = textures_to_storage[i]->image; - image_memory_barrier.subresourceRange.aspectMask = textures_to_sampled[i]->read_aspect_mask; + image_memory_barrier.subresourceRange.aspectMask = textures_to_storage[i]->read_aspect_mask; image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = textures_to_storage[i]->mipmaps; image_memory_barrier.subresourceRange.baseArrayLayer = 0; @@ -6197,6 +6296,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list, } #endif } + void RenderingDeviceVulkan::compute_list_set_push_constant(ComputeListID p_list, void *p_data, uint32_t p_data_size) { ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST); ERR_FAIL_COND(!compute_list); @@ -6223,6 +6323,10 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t ComputeList *cl = compute_list; #ifdef DEBUG_ENABLED + ERR_FAIL_COND(p_x_groups > limits.maxComputeWorkGroupCount[0]); + ERR_FAIL_COND(p_y_groups > limits.maxComputeWorkGroupCount[1]); + ERR_FAIL_COND(p_z_groups > limits.maxComputeWorkGroupCount[2]); + ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified."); #endif @@ -6267,6 +6371,11 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t vkCmdDispatch(cl->command_buffer, p_x_groups, p_y_groups, p_z_groups); } + +void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) { + _memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, true); +} + void RenderingDeviceVulkan::compute_list_end() { ERR_FAIL_COND(!compute_list); @@ -6295,6 +6404,9 @@ void RenderingDeviceVulkan::compute_list_end() { } memdelete(compute_list); + compute_list = NULL; + + _memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT, true); } #if 0 -- cgit v1.2.3 From 965185c765bf5d17f0f035b7685dbaf4611e5288 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Thu, 3 Oct 2019 20:15:38 -0300 Subject: Better GIProbe quality settings. --- drivers/vulkan/rendering_device_vulkan.cpp | 79 +++++++++++++++--------------- 1 file changed, 39 insertions(+), 40 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 118679a8b5..f644acc3be 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -4684,46 +4684,7 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint } _buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, p_sync_with_draw); -#if 0 - if (p_sync_with_draw) { - VkMemoryBarrier memoryBarrier; - memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; - memoryBarrier.pNext = NULL; - memoryBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | - VK_ACCESS_INDEX_READ_BIT | - VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | - VK_ACCESS_UNIFORM_READ_BIT | - VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | - VK_ACCESS_SHADER_READ_BIT | - VK_ACCESS_SHADER_WRITE_BIT | - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - VK_ACCESS_TRANSFER_READ_BIT | - VK_ACCESS_TRANSFER_WRITE_BIT | - VK_ACCESS_HOST_READ_BIT | - VK_ACCESS_HOST_WRITE_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | - VK_ACCESS_INDEX_READ_BIT | - VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | - VK_ACCESS_UNIFORM_READ_BIT | - VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | - VK_ACCESS_SHADER_READ_BIT | - VK_ACCESS_SHADER_WRITE_BIT | - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - VK_ACCESS_TRANSFER_READ_BIT | - VK_ACCESS_TRANSFER_WRITE_BIT | - VK_ACCESS_HOST_READ_BIT | - VK_ACCESS_HOST_WRITE_BIT; - - vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &memoryBarrier, 0, NULL, 0, NULL); - } -#endif return err; } @@ -6902,6 +6863,44 @@ void RenderingDeviceVulkan::capture_timestamp(const String &p_name, bool p_sync_ ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements); + { + VkMemoryBarrier memoryBarrier; + + memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + memoryBarrier.pNext = NULL; + memoryBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT | + VK_ACCESS_HOST_WRITE_BIT; + memoryBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT | + VK_ACCESS_HOST_WRITE_BIT; + + vkCmdPipelineBarrier(p_sync_to_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &memoryBarrier, 0, NULL, 0, NULL); + } vkCmdWriteTimestamp(p_sync_to_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, frames[frame].timestamp_pool, frames[frame].timestamp_count); frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name; frames[frame].timestamp_cpu_values[frames[frame].timestamp_count] = OS::get_singleton()->get_ticks_usec(); @@ -6918,7 +6917,7 @@ uint64_t RenderingDeviceVulkan::get_captured_timestamps_frame() const { uint64_t RenderingDeviceVulkan::get_captured_timestamp_gpu_time(uint32_t p_index) const { ERR_FAIL_INDEX_V(p_index, frames[frame].timestamp_result_count, 0); - return frames[frame].timestamp_result_values[p_index]; + return frames[frame].timestamp_result_values[p_index] * limits.timestampPeriod; } uint64_t RenderingDeviceVulkan::get_captured_timestamp_cpu_time(uint32_t p_index) const { ERR_FAIL_INDEX_V(p_index, frames[frame].timestamp_result_count, 0); -- cgit v1.2.3 From 6ee2f5e6b6663f5a4987954d43bb6df6d1f62d2a Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sat, 5 Oct 2019 10:27:43 -0300 Subject: More GIProbe work and fixes --- drivers/vulkan/rendering_device_vulkan.cpp | 175 +++++++++++++++++------------ 1 file changed, 106 insertions(+), 69 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index f644acc3be..16e25039f8 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1250,7 +1250,7 @@ Error RenderingDeviceVulkan::_buffer_allocate(Buffer *p_buffer, uint32_t p_size, allocInfo.pUserData = NULL; VkResult err = vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &p_buffer->buffer, &p_buffer->allocation, NULL); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Can't create buffer of size: " + itos(p_size)); p_buffer->size = p_size; p_buffer->buffer_info.buffer = p_buffer->buffer; p_buffer->buffer_info.offset = 0; @@ -1857,6 +1857,8 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID p_with_texture) { + _THREAD_SAFE_METHOD_ + Texture *src_texture = texture_owner.getornull(p_with_texture); ERR_FAIL_COND_V(!src_texture, RID()); @@ -1938,6 +1940,8 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type) { + _THREAD_SAFE_METHOD_ + Texture *src_texture = texture_owner.getornull(p_with_texture); ERR_FAIL_COND_V(!src_texture, RID()); @@ -2314,6 +2318,9 @@ PoolVector RenderingDeviceVulkan::_texture_get_data_from_image(Texture } PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t p_layer) { + + _THREAD_SAFE_METHOD_ + Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!tex, PoolVector()); @@ -2416,6 +2423,10 @@ PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 { + //despite textures being in block sizes, spec requiers they are in pixel sizes (?) + uint32_t computed_w = tex->width; + uint32_t computed_h = tex->height; + for (uint32_t i = 0; i < tex->mipmaps; i++) { uint32_t mm_width, mm_height, mm_depth; @@ -2438,11 +2449,14 @@ PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 image_copy_region.dstOffset.y = 0; image_copy_region.dstOffset.z = 0; - image_copy_region.extent.width = mm_width; - image_copy_region.extent.height = mm_height; - image_copy_region.extent.depth = mm_depth; + image_copy_region.extent.width = computed_w; + image_copy_region.extent.height = computed_h; + image_copy_region.extent.depth = mm_depth; //block is only x,y so this is fine anyway vkCmdCopyImage(command_buffer, tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region); + + computed_w = MAX(1, computed_w >> 1); + computed_h = MAX(1, computed_h >> 1); } } @@ -2500,6 +2514,8 @@ PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 } bool RenderingDeviceVulkan::texture_is_shared(RID p_texture) { + _THREAD_SAFE_METHOD_ + Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!tex, false); return tex->owner.is_valid(); @@ -2511,6 +2527,8 @@ bool RenderingDeviceVulkan::texture_is_valid(RID p_texture) { Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_size, uint32_t p_src_mipmap, uint32_t p_dst_mipmap, uint32_t p_src_layer, uint32_t p_dst_layer, bool p_sync_with_draw) { + _THREAD_SAFE_METHOD_ + Texture *src_tex = texture_owner.getornull(p_from_texture); ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER); @@ -2681,6 +2699,8 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color, uint32_t p_base_mipmap, uint32_t p_mipmaps, uint32_t p_base_layer, uint32_t p_layers, bool p_sync_with_draw) { + _THREAD_SAFE_METHOD_ + Texture *src_tex = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER); @@ -4010,6 +4030,8 @@ RID RenderingDeviceVulkan::shader_create(const Vector &p_stages } uint32_t RenderingDeviceVulkan::shader_get_vertex_input_attribute_mask(RID p_shader) { + _THREAD_SAFE_METHOD_ + const Shader *shader = shader_owner.getornull(p_shader); ERR_FAIL_COND_V(!shader, 0); return shader->vertex_input_mask; @@ -4690,6 +4712,8 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint PoolVector RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { + _THREAD_SAFE_METHOD_ + Buffer *buffer = NULL; if (vertex_buffer_owner.owns(p_buffer)) { buffer = vertex_buffer_owner.getornull(p_buffer); @@ -6077,7 +6101,7 @@ void RenderingDeviceVulkan::draw_list_end() { // To ensure proper synchronization, we must make sure rendering is done before: // * Some buffer is copied // * Another render pass happens (since we may be done - _memory_barrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT, true); + _memory_barrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, true); } /***********************/ @@ -6284,9 +6308,12 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t ComputeList *cl = compute_list; #ifdef DEBUG_ENABLED - ERR_FAIL_COND(p_x_groups > limits.maxComputeWorkGroupCount[0]); - ERR_FAIL_COND(p_y_groups > limits.maxComputeWorkGroupCount[1]); - ERR_FAIL_COND(p_z_groups > limits.maxComputeWorkGroupCount[2]); + ERR_FAIL_COND_MSG(p_x_groups > limits.maxComputeWorkGroupCount[0], + "Dispatch amount of X compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[0]) + ")"); + ERR_FAIL_COND_MSG(p_y_groups > limits.maxComputeWorkGroupCount[1], + "Dispatch amount of Y compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[0]) + ")"); + ERR_FAIL_COND_MSG(p_z_groups > limits.maxComputeWorkGroupCount[2], + "Dispatch amount of Z compute groups (" + itos(p_x_groups) + ") is larger than device limit (" + itos(limits.maxComputeWorkGroupCount[0]) + ")"); ERR_FAIL_COND_MSG(!cl->validation.active, "Submitted Compute Lists can no longer be modified."); #endif @@ -6500,24 +6527,75 @@ void RenderingDeviceVulkan::free(RID p_id) { _free_dependencies(p_id); //recursively erase dependencies first, to avoid potential API problems _free_internal(p_id); } - -void RenderingDeviceVulkan::finalize_frame() { +void RenderingDeviceVulkan::swap_buffers() { _THREAD_SAFE_METHOD_ - if (draw_list) { - ERR_PRINT("Found open draw list at the end of the frame, this should never happen (further drawing will likely not work)."); - } + { //finalize frame - if (compute_list) { - ERR_PRINT("Found open compute list at the end of the frame, this should never happen (further compute will likely not work)."); + if (draw_list) { + ERR_PRINT("Found open draw list at the end of the frame, this should never happen (further drawing will likely not work)."); + } + + if (compute_list) { + ERR_PRINT("Found open compute list at the end of the frame, this should never happen (further compute will likely not work)."); + } + + { //complete the setup buffer (that needs to be processed before anything else) + vkEndCommandBuffer(frames[frame].setup_command_buffer); + vkEndCommandBuffer(frames[frame].draw_command_buffer); + } + screen_prepared = false; } - { //complete the setup buffer (that needs to be processed before anything else) - vkEndCommandBuffer(frames[frame].setup_command_buffer); - vkEndCommandBuffer(frames[frame].draw_command_buffer); + //swap buffers + context->swap_buffers(); + + { //advance frame + + frame = (frame + 1) % frame_count; + + //erase pending resources + _free_pending_resources(frame); + + //create setup command buffer and set as the setup buffer + + { + VkCommandBufferBeginInfo cmdbuf_begin; + cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdbuf_begin.pNext = NULL; + cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + cmdbuf_begin.pInheritanceInfo = NULL; + + VkResult err = vkResetCommandBuffer(frames[frame].setup_command_buffer, 0); + ERR_FAIL_COND(err); + + err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND(err); + context->set_setup_buffer(frames[frame].setup_command_buffer); //append now so it's added before everything else + err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin); + ERR_FAIL_COND(err); + context->append_command_buffer(frames[frame].draw_command_buffer); + } + + //advance current frame + frames_drawn++; + //advance staging buffer if used + if (staging_buffer_used) { + staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size(); + staging_buffer_used = false; + } + + if (frames[frame].timestamp_count) { + vkGetQueryPoolResults(device, frames[frame].timestamp_pool, 0, frames[frame].timestamp_count, sizeof(uint64_t) * max_timestamp_query_elements, frames[frame].timestamp_result_values, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); + SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names); + SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values); + } + + frames[frame].timestamp_result_count = frames[frame].timestamp_count; + frames[frame].timestamp_count = 0; + frames[frame].index = Engine::get_singleton()->get_frames_drawn(); } - screen_prepared = false; } void RenderingDeviceVulkan::_free_pending_resources(int p_frame) { @@ -6630,55 +6708,6 @@ void RenderingDeviceVulkan::prepare_screen_for_drawing() { screen_prepared = true; } -void RenderingDeviceVulkan::advance_frame() { - - _THREAD_SAFE_METHOD_ - - //advance the frame - frame = (frame + 1) % frame_count; - - //erase pending resources - _free_pending_resources(frame); - - //create setup command buffer and set as the setup buffer - - { - VkCommandBufferBeginInfo cmdbuf_begin; - cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmdbuf_begin.pNext = NULL; - cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - cmdbuf_begin.pInheritanceInfo = NULL; - - VkResult err = vkResetCommandBuffer(frames[frame].setup_command_buffer, 0); - ERR_FAIL_COND(err); - - err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin); - ERR_FAIL_COND(err); - context->set_setup_buffer(frames[frame].setup_command_buffer); //append now so it's added before everything else - err = vkBeginCommandBuffer(frames[frame].draw_command_buffer, &cmdbuf_begin); - ERR_FAIL_COND(err); - context->append_command_buffer(frames[frame].draw_command_buffer); - } - - //advance current frame - frames_drawn++; - //advance staging buffer if used - if (staging_buffer_used) { - staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size(); - staging_buffer_used = false; - } - - if (frames[frame].timestamp_count) { - vkGetQueryPoolResults(device, frames[frame].timestamp_pool, 0, frames[frame].timestamp_count, sizeof(uint64_t) * max_timestamp_query_elements, frames[frame].timestamp_result_values, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); - SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names); - SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values); - } - - frames[frame].timestamp_result_count = frames[frame].timestamp_count; - frames[frame].timestamp_count = 0; - frames[frame].index = Engine::get_singleton()->get_frames_drawn(); -} - uint32_t RenderingDeviceVulkan::get_frame_delay() const { return frame_count; } @@ -6793,7 +6822,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) { { //begin the first command buffer for the first frame, so - //setting up things can be done in the meantime until finalize_frame(), which is called before advance. + //setting up things can be done in the meantime until swap_buffers(), which is called before advance. VkCommandBufferBeginInfo cmdbuf_begin; cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; cmdbuf_begin.pNext = NULL; @@ -6957,6 +6986,14 @@ int RenderingDeviceVulkan::limit_get(Limit p_limit) { case LIMIT_MAX_VERTEX_INPUT_BINDINGS: return limits.maxVertexInputBindings; case LIMIT_MAX_VERTEX_INPUT_BINDING_STRIDE: return limits.maxVertexInputBindingStride; case LIMIT_MIN_UNIFORM_BUFFER_OFFSET_ALIGNMENT: return limits.minUniformBufferOffsetAlignment; + case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X: return limits.maxComputeWorkGroupCount[0]; + case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y: return limits.maxComputeWorkGroupCount[1]; + case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z: return limits.maxComputeWorkGroupCount[2]; + case LIMIT_MAX_COMPUTE_WORKGROUP_INVOCATIONS: return limits.maxComputeWorkGroupInvocations; + case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X: return limits.maxComputeWorkGroupSize[0]; + case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y: return limits.maxComputeWorkGroupSize[1]; + case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z: return limits.maxComputeWorkGroupSize[2]; + default: ERR_FAIL_V(0); } -- cgit v1.2.3 From 561b431d85314000fe70d42e39713e5da394c3b5 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Thu, 10 Oct 2019 23:14:56 -0300 Subject: Dynamic object support for GI Probes (a bit buggy still) --- drivers/vulkan/rendering_device_vulkan.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 16e25039f8..b85641e48f 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -2656,7 +2656,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_memory_barrier.pNext = NULL; image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; image_memory_barrier.newLayout = src_tex->layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -2677,7 +2677,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture, image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_memory_barrier.pNext = NULL; image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; image_memory_barrier.newLayout = dst_tex->layout; -- cgit v1.2.3 From d5df1b651c9f2c21a38ceb4fd00e8844e66ef01c Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Mon, 14 Oct 2019 11:30:27 +0300 Subject: Improve HiDPI handling, fix incorrect window viewport clipping. --- drivers/vulkan/rendering_device_vulkan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index b85641e48f..d74f77c328 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -5277,7 +5277,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(in scissor.offset.x = 0; scissor.offset.y = 0; scissor.extent.width = size_x; - scissor.extent.height = size_x; + scissor.extent.height = size_y; vkCmdSetScissor(command_buffer, 0, 1, &scissor); -- cgit v1.2.3 From 2af701fa03037aed2cd544cc4fa4fe6ec81510bf Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Fri, 25 Oct 2019 11:22:19 -0300 Subject: Use a different strategy to get textures from GPU (via buffers), for more compatibility. --- drivers/vulkan/rendering_device_vulkan.cpp | 171 +++++++++-------------------- 1 file changed, 54 insertions(+), 117 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index d74f77c328..cc538593b5 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -2250,10 +2250,10 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con return OK; } -PoolVector RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer) { +PoolVector RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer, bool p_2d) { uint32_t width, height, depth; - uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps, &width, &height, &depth); + uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, tex->mipmaps, &width, &height, &depth); PoolVector image_data; image_data.resize(image_size); @@ -2272,7 +2272,7 @@ PoolVector RenderingDeviceVulkan::_texture_get_data_from_image(Texture uint32_t mipmap_offset = 0; for (uint32_t mm_i = 0; mm_i < tex->mipmaps; mm_i++) { - uint32_t image_total = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, mm_i + 1, &width, &height, &depth); + uint32_t image_total = get_image_format_required_size(tex->format, tex->width, tex->height, p_2d ? 1 : tex->depth, mm_i + 1, &width, &height, &depth); uint8_t *write_ptr_mipmap = w.ptr() + mipmap_offset; image_size = image_total - mipmap_offset; @@ -2339,46 +2339,17 @@ PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 //does not need anything fancy, map and read. return _texture_get_data_from_image(tex, tex->image, tex->allocation, p_layer); } else { - VkImageCreateInfo image_create_info; - image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - image_create_info.pNext = NULL; - image_create_info.flags = 0; - image_create_info.imageType = vulkan_image_type[tex->type]; - image_create_info.format = vulkan_formats[tex->format]; - image_create_info.extent.width = tex->width; - image_create_info.extent.height = tex->height; - image_create_info.extent.depth = tex->depth; - image_create_info.mipLevels = tex->mipmaps; - image_create_info.arrayLayers = 1; //for retrieving, only one layer - image_create_info.samples = rasterization_sample_count[tex->samples]; - image_create_info.tiling = VK_IMAGE_TILING_LINEAR; // for retrieving, linear is recommended - image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; - image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - image_create_info.queueFamilyIndexCount = 0; - image_create_info.pQueueFamilyIndices = NULL; - image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - VmaAllocationCreateInfo allocInfo; - allocInfo.flags = 0; - allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; - allocInfo.requiredFlags = 0; - allocInfo.preferredFlags = 0; - allocInfo.memoryTypeBits = 0; - allocInfo.pool = NULL; - allocInfo.pUserData = NULL; - - VkImage image; - VmaAllocation allocation; - VmaAllocationInfo allocation_info; - - //Allocate the image - VkResult err = vmaCreateImage(allocator, &image_create_info, &allocInfo, &image, &allocation, &allocation_info); - ERR_FAIL_COND_V(err, PoolVector()); + //compute total image size + uint32_t width, height, depth; + uint32_t buffer_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps, &width, &height, &depth); + + //allocate buffer VkCommandBuffer command_buffer = frames[frame].setup_command_buffer; - //PRE Copy the image + Buffer tmp_buffer; + _buffer_allocate(&tmp_buffer, buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_CPU_ONLY); - { //Source + { //Source image barrier VkImageMemoryBarrier image_memory_barrier; image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_memory_barrier.pNext = NULL; @@ -2398,70 +2369,43 @@ PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); } - { //Dest - VkImageMemoryBarrier image_memory_barrier; - image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - image_memory_barrier.pNext = NULL; - image_memory_barrier.srcAccessMask = 0; - image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - - 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.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - image_memory_barrier.subresourceRange.baseMipLevel = 0; - image_memory_barrier.subresourceRange.levelCount = tex->mipmaps; - image_memory_barrier.subresourceRange.baseArrayLayer = 0; - image_memory_barrier.subresourceRange.layerCount = 1; - - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); - } - - //COPY - - { - - //despite textures being in block sizes, spec requiers they are in pixel sizes (?) - uint32_t computed_w = tex->width; - uint32_t computed_h = tex->height; - for (uint32_t i = 0; i < tex->mipmaps; i++) { + uint32_t computed_w = tex->width; + uint32_t computed_h = tex->height; + uint32_t computed_d = tex->depth; - uint32_t mm_width, mm_height, mm_depth; - get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, i + 1, &mm_width, &mm_height, &mm_depth); + uint32_t prev_size = 0; + uint32_t offset = 0; + for (uint32_t i = 0; i < tex->mipmaps; i++) { - VkImageCopy image_copy_region; - image_copy_region.srcSubresource.aspectMask = tex->read_aspect_mask; - image_copy_region.srcSubresource.baseArrayLayer = p_layer; - image_copy_region.srcSubresource.layerCount = 1; - image_copy_region.srcSubresource.mipLevel = i; - image_copy_region.srcOffset.x = 0; - image_copy_region.srcOffset.y = 0; - image_copy_region.srcOffset.z = 0; + VkBufferImageCopy buffer_image_copy; - image_copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - image_copy_region.dstSubresource.baseArrayLayer = p_layer; - image_copy_region.dstSubresource.layerCount = 1; - image_copy_region.dstSubresource.mipLevel = i; - image_copy_region.dstOffset.x = 0; - image_copy_region.dstOffset.y = 0; - image_copy_region.dstOffset.z = 0; + uint32_t image_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, i + 1); + uint32_t size = image_size - prev_size; + prev_size = image_size; - image_copy_region.extent.width = computed_w; - image_copy_region.extent.height = computed_h; - image_copy_region.extent.depth = mm_depth; //block is only x,y so this is fine anyway + buffer_image_copy.bufferOffset = offset; + buffer_image_copy.bufferImageHeight = 0; + buffer_image_copy.bufferRowLength = 0; + buffer_image_copy.imageSubresource.aspectMask = tex->read_aspect_mask; + buffer_image_copy.imageSubresource.baseArrayLayer = p_layer; + buffer_image_copy.imageSubresource.layerCount = 1; + buffer_image_copy.imageSubresource.mipLevel = i; + buffer_image_copy.imageOffset.x = 0; + buffer_image_copy.imageOffset.y = 0; + buffer_image_copy.imageOffset.z = 0; + buffer_image_copy.imageExtent.width = computed_w; + buffer_image_copy.imageExtent.height = computed_h; + buffer_image_copy.imageExtent.depth = computed_d; - vkCmdCopyImage(command_buffer, tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region); + vkCmdCopyImageToBuffer(command_buffer, tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, tmp_buffer.buffer, 1, &buffer_image_copy); - computed_w = MAX(1, computed_w >> 1); - computed_h = MAX(1, computed_h >> 1); - } + computed_w = MAX(1, computed_w >> 1); + computed_h = MAX(1, computed_h >> 1); + computed_d = MAX(1, computed_d >> 1); + offset += size; } - // RESTORE LAYOUT for SRC and DST - { //restore src VkImageMemoryBarrier image_memory_barrier; image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -2482,34 +2426,27 @@ PoolVector RenderingDeviceVulkan::texture_get_data(RID p_texture, uint3 vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); } - { //make dst readable + _flush(true); - VkImageMemoryBarrier image_memory_barrier; - image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - image_memory_barrier.pNext = NULL; - image_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - image_memory_barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; - image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + void *buffer_mem; + VkResult vkerr = vmaMapMemory(allocator, tmp_buffer.allocation, &buffer_mem); + if (vkerr) { + ERR_FAIL_V(PoolVector()); + } - 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.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - image_memory_barrier.subresourceRange.baseMipLevel = 0; - image_memory_barrier.subresourceRange.levelCount = tex->mipmaps; - image_memory_barrier.subresourceRange.baseArrayLayer = 0; - image_memory_barrier.subresourceRange.layerCount = 1; + PoolVector buffer_data; + { - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier); + buffer_data.resize(buffer_size); + PoolVector::Write w = buffer_data.write(); + copymem(w.ptr(), buffer_mem, buffer_size); } - //flush everything so memory can be safely mapped - _flush(true); + vmaUnmapMemory(allocator, tmp_buffer.allocation); + + _buffer_free(&tmp_buffer); - PoolVector ret = _texture_get_data_from_image(tex, image, allocation, p_layer); - vmaDestroyImage(allocator, image, allocation); - return ret; + return buffer_data; } } -- cgit v1.2.3 From da0457fa29e1ea63f89b1e1d73e72c4dc80a9966 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Thu, 31 Oct 2019 19:54:21 -0300 Subject: Several fixes to GIProbes --- drivers/vulkan/rendering_device_vulkan.cpp | 58 ++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index cc538593b5..98b1bc1115 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -36,6 +36,8 @@ #include "drivers/vulkan/vulkan_context.h" #include "thirdparty/spirv-reflect/spirv_reflect.h" +//#define FORCE_FULL_BARRIER + void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) { if (!dependency_map.has(p_depends_on)) { @@ -1499,6 +1501,42 @@ void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mas vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 1, &mem_barrier, 0, NULL, 0, NULL); } +void RenderingDeviceVulkan::_full_barrier(bool p_sync_with_draw) { + //used for debug + _memory_barrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT | + VK_ACCESS_HOST_WRITE_BIT, + VK_ACCESS_INDIRECT_COMMAND_READ_BIT | + VK_ACCESS_INDEX_READ_BIT | + VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | + VK_ACCESS_UNIFORM_READ_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_TRANSFER_READ_BIT | + VK_ACCESS_TRANSFER_WRITE_BIT | + VK_ACCESS_HOST_READ_BIT | + VK_ACCESS_HOST_WRITE_BIT, + p_sync_with_draw); +} + void RenderingDeviceVulkan::_buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw) { VkBufferMemoryBarrier buffer_mem_barrier; @@ -4643,7 +4681,11 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint } _buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, p_sync_with_draw); - +#ifdef FORCE_FULL_BARRIER + _full_barrier(p_sync_with_draw); +#else + _buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, p_sync_with_draw); +#endif return err; } @@ -6038,7 +6080,12 @@ void RenderingDeviceVulkan::draw_list_end() { // To ensure proper synchronization, we must make sure rendering is done before: // * Some buffer is copied // * Another render pass happens (since we may be done + +#ifdef FORCE_FULL_BARRIER + _full_barrier(true); +#else _memory_barrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, true); +#endif } /***********************/ @@ -6298,7 +6345,11 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t } void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) { +#ifdef FORCE_FULL_BARRIER + _full_barrier(true); +#else _memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, true); +#endif } void RenderingDeviceVulkan::compute_list_end() { @@ -6330,8 +6381,11 @@ void RenderingDeviceVulkan::compute_list_end() { memdelete(compute_list); compute_list = NULL; - +#ifdef FORCE_FULL_BARRIER + _full_barrier(true); +#else _memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT, true); +#endif } #if 0 -- cgit v1.2.3 From bd364d1447ea3b745299c6460d6d90acd8637ab5 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sat, 11 Jan 2020 22:26:52 -0300 Subject: Auto exposure re-implemented in Vulkan --- drivers/vulkan/rendering_device_vulkan.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 98b1bc1115..13a0948687 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -5751,6 +5751,8 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI dl->validation.pipeline_push_constant_suppplied = false; #endif } + + dl->state.pipeline_shader = pipeline->shader; } #ifdef DEBUG_ENABLED @@ -5975,8 +5977,8 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices if (p_procedural_vertices > 0) { #ifdef DEBUG_ENABLED - ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID, - "Procedural vertices requested, but pipeline expects a vertex array."); + ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format == INVALID_ID, + "Procedural vertices requested, but pipeline expects a vertex array."); #endif to_draw = p_procedural_vertices; } else { @@ -6153,6 +6155,8 @@ void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_l cl->validation.pipeline_push_constant_suppplied = false; #endif } + + cl->state.pipeline_shader = pipeline->shader; } #ifdef DEBUG_ENABLED -- cgit v1.2.3 From db81928e08cb58d5f67908c6dfcf9433e572ffe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Tue, 11 Feb 2020 14:01:43 +0100 Subject: Vulkan: Move thirdparty code out of drivers, style fixes - `vk_enum_string_helper.h` is a generated file taken from the SDK (Vulkan-ValidationLayers). - `vk_mem_alloc.h` is a library from GPUOpen: https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator --- drivers/vulkan/rendering_device_vulkan.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/vulkan/rendering_device_vulkan.cpp') diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 13a0948687..4582f1c2c1 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ -- cgit v1.2.3