2019-06-22 18:34:26 +02:00
/*************************************************************************/
/* 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. */
/*************************************************************************/
2019-06-07 18:07:57 +02:00
# include "rendering_device_vulkan.h"
# include "core/hashfuncs.h"
2019-07-28 18:42:15 +02:00
# include "core/os/file_access.h"
2019-06-07 18:07:57 +02:00
# include "core/project_settings.h"
2019-07-28 18:42:15 +02:00
# include "drivers/vulkan/vulkan_context.h"
# include "thirdparty/spirv-reflect/spirv_reflect.h"
2019-06-07 18:07:57 +02:00
2019-06-10 19:12:24 +02:00
void RenderingDeviceVulkan : : _add_dependency ( RID p_id , RID p_depends_on ) {
2019-06-07 18:07:57 +02:00
if ( ! dependency_map . has ( p_depends_on ) ) {
2019-06-10 19:12:24 +02:00
dependency_map [ p_depends_on ] = Set < RID > ( ) ;
2019-06-07 18:07:57 +02:00
}
dependency_map [ p_depends_on ] . insert ( p_id ) ;
if ( ! reverse_dependency_map . has ( p_id ) ) {
2019-06-10 19:12:24 +02:00
reverse_dependency_map [ p_id ] = Set < RID > ( ) ;
2019-06-07 18:07:57 +02:00
}
reverse_dependency_map [ p_id ] . insert ( p_depends_on ) ;
}
2019-06-10 19:12:24 +02:00
void RenderingDeviceVulkan : : _free_dependencies ( RID p_id ) {
2019-06-07 18:07:57 +02:00
//direct dependencies must be freed
2019-06-24 21:13:06 +02:00
2019-06-10 19:12:24 +02:00
Map < RID , Set < RID > > : : Element * E = dependency_map . find ( p_id ) ;
2019-06-07 18:07:57 +02:00
if ( E ) {
2019-06-24 21:13:06 +02:00
while ( E - > get ( ) . size ( ) ) {
free ( E - > get ( ) . front ( ) - > get ( ) ) ;
2019-06-07 18:07:57 +02:00
}
dependency_map . erase ( E ) ;
}
//reverse depenencies must be unreferenced
E = reverse_dependency_map . find ( p_id ) ;
if ( E ) {
2019-06-10 19:12:24 +02:00
for ( Set < RID > : : Element * F = E - > get ( ) . front ( ) ; F ; F = F - > next ( ) ) {
Map < RID , Set < RID > > : : Element * G = dependency_map . find ( F - > get ( ) ) ;
2019-06-24 21:13:06 +02:00
ERR_CONTINUE ( ! G ) ;
ERR_CONTINUE ( ! G - > get ( ) . has ( p_id ) ) ;
G - > get ( ) . erase ( p_id ) ;
2019-06-07 18:07:57 +02:00
}
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 ;
2019-06-19 22:03:19 +02:00
case DATA_FORMAT_D32_SFLOAT_S8_UINT :
return 5 ; //?
2019-06-07 18:07:57 +02:00
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 :
2019-06-19 22:03:19 +02:00
case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK :
return 8 ; //wrong
2019-06-07 18:07:57 +02:00
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 :
2019-06-19 22:03:19 +02:00
case DATA_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG :
return 8 ; //what varies is resolution
2019-06-07 18:07:57 +02:00
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 ;
}
2019-06-26 00:49:52 +02:00
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 ) {
2019-06-07 18:07:57 +02:00
2019-07-27 15:23:24 +02:00
ERR_FAIL_COND_V ( p_mipmaps = = 0 , 0 ) ;
2019-06-07 18:07:57 +02:00
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 ) ;
2019-06-16 04:45:24 +02:00
for ( uint32_t i = 0 ; i < p_mipmaps ; i + + ) {
2019-06-07 18:07:57 +02:00
uint32_t bw = w % blockw ! = 0 ? w + ( blockw - w % blockw ) : w ;
uint32_t bh = h % blockh ! = 0 ? h + ( blockh - h % blockh ) : h ;
uint32_t s = bw * bh ;
s * = pixel_size ;
s > > = pixel_rshift ;
2019-06-11 22:21:39 +02:00
size + = s * d ;
2019-06-07 18:07:57 +02:00
if ( r_blockw ) {
* r_blockw = bw ;
}
if ( r_blockh ) {
* r_blockh = bh ;
}
2019-06-26 00:49:52 +02:00
if ( r_depth ) {
* r_depth = d ;
}
2019-06-07 18:07:57 +02:00
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
} ;
2019-06-26 00:49:52 +02:00
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
} ;
2019-06-07 18:07:57 +02:00
/***************************/
/**** 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 ) ;
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
2019-06-26 00:49:52 +02:00
_flush ( true , p_on_draw_command_buffer ) ;
2019-06-07 18:07:57 +02:00
//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 {
2019-06-26 00:49:52 +02:00
_flush ( false , false ) ;
2019-06-07 18:07:57 +02:00
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 , & region ) ;
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 ;
}
2019-06-24 21:13:06 +02:00
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 ) ;
}
2019-06-07 18:07:57 +02:00
/*****************/
/**** TEXTURE ****/
/*****************/
2019-06-10 19:12:24 +02:00
RID RenderingDeviceVulkan : : texture_create ( const TextureFormat & p_format , const TextureView & p_view , const Vector < PoolVector < uint8_t > > & p_data ) {
2019-06-07 18:07:57 +02:00
_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 ;
2019-06-19 22:03:19 +02:00
VkImageFormatListCreateInfoKHR format_list_create_info ;
Vector < VkFormat > 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 " ) ;
}
2019-06-07 18:07:57 +02:00
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 ;
} */
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_format . type , TEXTURE_TYPE_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
2019-06-26 00:49:52 +02:00
image_create_info . imageType = vulkan_image_type [ p_format . type ] ;
2019-06-07 18:07:57 +02:00
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( p_format . width < 1 , RID ( ) , " Width must be equal or greater than 1 for all textures " ) ;
2019-06-07 18:07:57 +02:00
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 ) {
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( p_format . height < 1 , RID ( ) , " Height must be equal or greater than 1 for 2D and 3D textures " ) ;
2019-06-07 18:07:57 +02:00
image_create_info . extent . height = p_format . height ;
} else {
image_create_info . extent . height = 1 ;
}
if ( image_create_info . imageType = = VK_IMAGE_TYPE_3D ) {
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( p_format . depth < 1 , RID ( ) , " Depth must be equal or greater than 1 for 3D textures " ) ;
2019-06-07 18:07:57 +02:00
image_create_info . extent . depth = p_format . depth ;
} else {
image_create_info . extent . depth = 1 ;
}
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( p_format . mipmaps < 1 , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ) {
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( p_format . array_layers < 1 , RID ( ) ,
2019-06-07 18:07:57 +02:00
" Amount of layers must be equal or greater than 1 for arrays and cubemaps. " ) ;
2019-06-10 19:12:24 +02:00
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 " ) ;
2019-06-07 18:07:57 +02:00
image_create_info . arrayLayers = p_format . array_layers ;
} else {
image_create_info . arrayLayers = 1 ;
}
image_create_info . arrayLayers = p_format . array_layers ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_format . samples , TEXTURE_SAMPLES_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ;
}
2019-07-27 15:23:24 +02:00
if ( p_format . usage_bits & TEXTURE_USAGE_CAN_COPY_FROM_BIT ) {
2019-06-26 00:49:52 +02:00
image_create_info . usage | = VK_IMAGE_USAGE_TRANSFER_SRC_BIT ;
}
2019-06-07 18:07:57 +02:00
2019-07-27 15:23:24 +02:00
if ( p_format . usage_bits & TEXTURE_USAGE_CAN_COPY_TO_BIT ) {
image_create_info . usage | = VK_IMAGE_USAGE_TRANSFER_DST_BIT ;
}
2019-06-07 18:07:57 +02:00
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 ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( required_mipmaps < image_create_info . mipLevels , RID ( ) ,
2019-06-07 18:07:57 +02:00
" Too many mipmaps requested for texture format and dimensions ( " + itos ( image_create_info . mipLevels ) + " ), maximum allowed: ( " + itos ( required_mipmaps ) + " ). " ) ;
if ( p_data . size ( ) ) {
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( ! ( p_format . usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT ) , RID ( ) ,
2019-06-07 18:07:57 +02:00
" Texture needs the TEXTURE_USAGE_CAN_UPDATE_BIT usage flag in order to be updated at initialization or later " ) ;
2019-06-11 22:21:39 +02:00
int expected_images = image_create_info . arrayLayers * array_layer_multiplier ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( p_data . size ( ) ! = expected_images , RID ( ) ,
2019-06-07 18:07:57 +02:00
" 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 + + ) {
2019-06-11 22:21:39 +02:00
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 ) + " ). " ) ;
2019-06-07 18:07:57 +02:00
}
}
{
//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 ) ) {
2019-06-10 19:12:24 +02:00
ERR_FAIL_V_MSG ( RID ( ) , " Format " + format_text + " does not support usage as sampling texture. " ) ;
2019-06-07 18:07:57 +02:00
}
if ( p_format . usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT & & ! ( flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT ) ) {
2019-06-10 19:12:24 +02:00
ERR_FAIL_V_MSG ( RID ( ) , " Format " + format_text + " does not support usage as color attachment. " ) ;
2019-06-07 18:07:57 +02:00
}
if ( p_format . usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT & & ! ( flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT ) ) {
2019-07-05 03:54:32 +02:00
printf ( " vkformat: %x \n " , image_create_info . format ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_V_MSG ( RID ( ) , " Format " + format_text + " does not support usage as depth-stencil attachment. " ) ;
2019-06-07 18:07:57 +02:00
}
if ( p_format . usage_bits & TEXTURE_USAGE_STORAGE_BIT & & ! ( flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT ) ) {
2019-06-10 19:12:24 +02:00
ERR_FAIL_V_MSG ( RID ( ) , " Format " + format_text + " does not support usage as storage image. " ) ;
2019-06-07 18:07:57 +02:00
}
if ( p_format . usage_bits & TEXTURE_USAGE_STORAGE_ATOMIC_BIT & & ! ( flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT ) ) {
2019-06-10 19:12:24 +02:00
ERR_FAIL_V_MSG ( RID ( ) , " Format " + format_text + " does not support usage as atomic storage image. " ) ;
2019-06-07 18:07:57 +02:00
}
}
//some view validation
if ( p_view . format_override ! = DATA_FORMAT_MAX ) {
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_view . format_override , DATA_FORMAT_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
}
2019-06-10 19:12:24 +02:00
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 ( ) ) ;
2019-06-07 18:07:57 +02:00
//allocate memory
VmaAllocationCreateInfo allocInfo ;
allocInfo . flags = 0 ;
2019-06-26 00:49:52 +02:00
allocInfo . usage = p_format . usage_bits & TEXTURE_USAGE_CPU_READ_BIT ? VMA_MEMORY_USAGE_CPU_ONLY : VMA_MEMORY_USAGE_GPU_ONLY ;
2019-06-07 18:07:57 +02:00
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 ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( err , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ;
2019-06-19 22:03:19 +02:00
texture . allowed_shared_formats = p_format . shareable_formats ;
2019-06-07 18:07:57 +02:00
2019-06-07 20:20:01 +02:00
//set bound and unbound layouts
2019-06-07 18:07:57 +02:00
if ( p_format . usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) {
2019-07-05 03:54:32 +02:00
texture . aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT ;
2019-06-07 20:20:01 +02:00
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 ;
}
2019-06-07 18:07:57 +02:00
texture . bound_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ;
2019-06-07 20:20:01 +02:00
} else if ( p_format . usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT ) {
2019-06-07 18:07:57 +02:00
texture . aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT ;
2019-06-07 20:20:01 +02:00
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 ;
}
2019-06-07 18:07:57 +02:00
texture . bound_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ;
2019-06-07 20:20:01 +02:00
} 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
2019-06-07 18:07:57 +02:00
}
texture . bound = false ;
//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 ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_V ( RID ( ) ) ;
2019-06-07 18:07:57 +02:00
}
//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 ;
2019-06-07 20:20:01 +02:00
image_memory_barrier . newLayout = texture . unbound_layout ;
2019-06-07 18:07:57 +02:00
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 ) ;
}
2019-06-10 19:12:24 +02:00
RID id = texture_owner . make_rid ( texture ) ;
2019-06-07 18:07:57 +02:00
if ( p_data . size ( ) ) {
for ( uint32_t i = 0 ; i < image_create_info . arrayLayers ; i + + ) {
2019-06-25 03:24:07 +02:00
texture_update ( id , i , p_data [ i ] ) ;
2019-06-07 18:07:57 +02:00
}
}
return id ;
}
2019-06-10 19:12:24 +02:00
RID RenderingDeviceVulkan : : texture_create_shared ( const TextureView & p_view , RID p_with_texture ) {
2019-06-07 18:07:57 +02:00
Texture * src_texture = texture_owner . getornull ( p_with_texture ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( ! src_texture , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
2019-06-10 19:12:24 +02:00
if ( src_texture - > owner . is_valid ( ) ) { //ahh this is a share
2019-06-07 18:07:57 +02:00
p_with_texture = src_texture - > owner ;
src_texture = texture_owner . getornull ( src_texture - > owner ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( ! src_texture , RID ( ) ) ; //this is a bug
2019-06-07 18:07:57 +02:00
}
//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 ] ;
2019-06-19 22:03:19 +02:00
if ( p_view . format_override = = DATA_FORMAT_MAX | | p_view . format_override = = texture . format ) {
2019-06-07 18:07:57 +02:00
image_view_create_info . format = vulkan_formats [ texture . format ] ;
} else {
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_view . format_override , DATA_FORMAT_MAX , RID ( ) ) ;
2019-06-19 22:03:19 +02:00
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. " ) ;
2019-06-07 18:07:57 +02:00
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 ) {
2019-06-10 19:12:24 +02:00
ERR_FAIL_V ( RID ( ) ) ;
2019-06-07 18:07:57 +02:00
}
texture . owner = p_with_texture ;
2019-06-10 19:12:24 +02:00
RID id = texture_owner . make_rid ( texture ) ;
2019-06-07 18:07:57 +02:00
_add_dependency ( id , p_with_texture ) ;
return id ;
}
2019-07-27 15:23:24 +02:00
RID RenderingDeviceVulkan : : texture_create_shared_from_slice ( const TextureView & p_view , RID p_with_texture , uint32_t p_layer , uint32_t p_mipmap ) {
2019-07-10 22:44:55 +02:00
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
2019-07-27 15:23:24 +02:00
ERR_FAIL_INDEX_V ( p_mipmap , src_texture - > mipmaps , RID ( ) ) ;
2019-07-10 22:44:55 +02:00
uint32_t array_layer_multiplier = 1 ;
2019-07-27 15:23:24 +02:00
if ( src_texture - > type = = TEXTURE_TYPE_CUBE_ARRAY | | src_texture - > type = = TEXTURE_TYPE_CUBE ) {
2019-07-10 22:44:55 +02:00
array_layer_multiplier = 6 ;
}
2019-07-27 15:23:24 +02:00
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 ;
2019-07-10 22:44:55 +02:00
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 ] ;
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 ;
}
2019-06-11 22:21:39 +02:00
Error RenderingDeviceVulkan : : texture_update ( RID p_texture , uint32_t p_layer , const PoolVector < uint8_t > & p_data , bool p_sync_with_draw ) {
2019-06-07 18:07:57 +02:00
_THREAD_SAFE_METHOD_
2019-06-25 03:24:07 +02:00
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 " ) ;
2019-06-07 18:07:57 +02:00
Texture * texture = texture_owner . getornull ( p_texture ) ;
ERR_FAIL_COND_V ( ! texture , ERR_INVALID_PARAMETER ) ;
2019-06-10 19:12:24 +02:00
if ( texture - > owner ! = RID ( ) ) {
2019-06-07 18:07:57 +02:00
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. " ) ;
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 ;
2019-06-26 00:49:52 +02:00
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 ;
2019-06-19 22:03:19 +02:00
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 ;
}
2019-06-07 18:07:57 +02:00
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 < uint8_t > : : 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 ;
2019-06-07 20:20:01 +02:00
image_memory_barrier . oldLayout = texture - > unbound_layout ;
2019-06-07 18:07:57 +02:00
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 ;
2019-06-11 22:21:39 +02:00
image_memory_barrier . subresourceRange . baseMipLevel = 0 ;
image_memory_barrier . subresourceRange . levelCount = texture - > mipmaps ;
2019-06-07 18:07:57 +02:00
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 ) ;
}
2019-06-11 22:21:39 +02:00
uint32_t mipmap_offset = 0 ;
for ( uint32_t mm_i = 0 ; mm_i < texture - > mipmaps ; mm_i + + ) {
2019-06-26 00:49:52 +02:00
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 ) ;
2019-06-11 22:21:39 +02:00
2019-06-19 22:03:19 +02:00
const uint8_t * read_ptr_mipmap = r . ptr ( ) + mipmap_offset ;
2019-06-11 22:21:39 +02:00
image_size = image_total - mipmap_offset ;
2019-06-07 18:07:57 +02:00
2019-06-26 00:49:52 +02:00
for ( uint32_t z = 0 ; z < depth ; z + + ) { //for 3D textures, depth may be > 0
2019-06-07 18:07:57 +02:00
2019-06-26 00:49:52 +02:00
const uint8_t * read_ptr = read_ptr_mipmap + image_size * z / depth ;
2019-06-07 18:07:57 +02:00
2019-06-11 22:21:39 +02:00
for ( uint32_t x = 0 ; x < width ; x + = region_size ) {
for ( uint32_t y = 0 ; y < height ; y + = region_size ) {
2019-06-07 18:07:57 +02:00
2019-06-11 22:21:39 +02:00
uint32_t region_w = MIN ( region_size , width - x ) ;
uint32_t region_h = MIN ( region_size , height - y ) ;
2019-06-07 18:07:57 +02:00
2019-06-11 22:21:39 +02:00
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 ) ;
2019-06-07 18:07:57 +02:00
2019-06-11 22:21:39 +02:00
uint32_t alloc_offset , alloc_size ;
2019-06-19 22:03:19 +02:00
Error err = _staging_buffer_allocate ( to_allocate , required_align , alloc_offset , alloc_size , false , p_sync_with_draw ) ;
2019-06-11 22:21:39 +02:00
ERR_FAIL_COND_V ( err , ERR_CANT_CREATE ) ;
2019-06-07 18:07:57 +02:00
2019-06-11 22:21:39 +02:00
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 ;
2019-06-07 18:07:57 +02:00
}
2019-06-11 22:21:39 +02:00
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 ] ;
}
2019-06-07 18:07:57 +02:00
}
}
2019-06-11 22:21:39 +02:00
} else {
//regular image (pixels)
//must copy a pixel region
2019-06-07 18:07:57 +02:00
2019-06-11 22:21:39 +02:00
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 + + ) {
2019-06-07 18:07:57 +02:00
2019-06-11 22:21:39 +02:00
write_ptr [ dst_offset + i ] = read_ptr [ src_offset + i ] ;
}
2019-06-07 18:07:57 +02:00
}
}
}
2019-06-11 22:21:39 +02:00
{ //unmap
vmaUnmapMemory ( allocator , staging_buffer_blocks [ staging_buffer_current ] . allocation ) ;
}
2019-06-07 18:07:57 +02:00
2019-06-11 22:21:39 +02:00
VkBufferImageCopy buffer_image_copy ;
buffer_image_copy . bufferOffset = alloc_offset ;
buffer_image_copy . bufferRowLength = 0 ; //tigthly packed
buffer_image_copy . bufferImageHeight = 0 ; //tigthly packed
2019-06-07 18:07:57 +02:00
2019-06-11 22:21:39 +02:00
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 ;
2019-06-07 18:07:57 +02:00
2019-06-11 22:21:39 +02:00
buffer_image_copy . imageOffset . x = x ;
buffer_image_copy . imageOffset . y = y ;
buffer_image_copy . imageOffset . z = z ;
2019-06-07 18:07:57 +02:00
2019-06-11 22:21:39 +02:00
buffer_image_copy . imageExtent . width = region_w ;
buffer_image_copy . imageExtent . height = region_h ;
buffer_image_copy . imageExtent . depth = 1 ;
2019-06-07 18:07:57 +02:00
2019-06-11 22:21:39 +02:00
vkCmdCopyBufferToImage ( command_buffer , staging_buffer_blocks [ staging_buffer_current ] . buffer , texture - > image , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL , 1 , & buffer_image_copy ) ;
2019-06-07 18:07:57 +02:00
2019-06-11 22:21:39 +02:00
staging_buffer_blocks . write [ staging_buffer_current ] . fill_amount + = alloc_size ;
}
2019-06-07 18:07:57 +02:00
}
}
2019-06-11 22:21:39 +02:00
mipmap_offset = image_total ;
2019-06-07 18:07:57 +02:00
}
//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 ;
2019-06-07 20:20:01 +02:00
image_memory_barrier . newLayout = texture - > unbound_layout ;
2019-06-07 18:07:57 +02:00
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 ;
2019-06-11 22:21:39 +02:00
image_memory_barrier . subresourceRange . baseMipLevel = 0 ;
image_memory_barrier . subresourceRange . levelCount = texture - > mipmaps ;
2019-06-07 18:07:57 +02:00
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 ;
}
2019-06-26 00:49:52 +02:00
PoolVector < uint8_t > 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 < uint8_t > 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 < uint8_t > : : 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 < uint8_t > RenderingDeviceVulkan : : texture_get_data ( RID p_texture , uint32_t p_layer ) {
Texture * tex = texture_owner . getornull ( p_texture ) ;
ERR_FAIL_COND_V ( ! tex , PoolVector < uint8_t > ( ) ) ;
ERR_FAIL_COND_V_MSG ( tex - > bound , PoolVector < uint8_t > ( ) ,
" 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. " ) ;
2019-07-27 15:23:24 +02:00
ERR_FAIL_COND_V_MSG ( ! ( tex - > usage_flags & TEXTURE_USAGE_CAN_COPY_FROM_BIT ) , PoolVector < uint8_t > ( ) ,
" Texture requires the TEXTURE_USAGE_CAN_COPY_FROM_BIT in order to be retrieved. " ) ;
2019-06-26 00:49:52 +02:00
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 < uint8_t > ( ) ) ;
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 < uint8_t > ( ) ) ;
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 ) ;
}
}
// 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 < uint8_t > ret = _texture_get_data_from_image ( tex , image , allocation , p_layer ) ;
vmaDestroyImage ( allocator , image , allocation ) ;
return ret ;
}
}
2019-06-24 21:13:06 +02:00
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 ) ;
}
2019-07-27 15:23:24 +02:00
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 ;
}
2019-06-16 04:45:24 +02:00
bool RenderingDeviceVulkan : : texture_is_format_supported_for_usage ( DataFormat p_format , uint32_t p_usage ) const {
2019-06-07 18:07:57 +02:00
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 < AttachmentFormat > & p_format , InitialAction p_initial_action , FinalAction p_final_action , int * r_color_attachment_count ) {
Vector < VkAttachmentDescription > attachments ;
Vector < VkAttachmentReference > color_references ;
Vector < VkAttachmentReference > depth_stencil_references ;
Vector < VkAttachmentReference > 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
2019-06-07 20:20:01 +02:00
ERR_FAIL_COND_V_MSG ( ! ( p_format [ i ] . usage_flags & ( TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT ) ) , VK_NULL_HANDLE ,
" Texture format for index ( " + itos ( i ) + " ) requires an attachment (depth, stencil or resolve) bit set. " ) ;
2019-06-07 18:07:57 +02:00
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. " ) ;
}
}
2019-06-07 20:20:01 +02:00
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 ( ) ) + " ). " ) ;
2019-06-07 18:07:57 +02:00
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 ;
}
2019-06-10 19:12:24 +02:00
RenderingDevice : : FramebufferFormatID RenderingDeviceVulkan : : framebuffer_format_create ( const Vector < AttachmentFormat > & p_format ) {
2019-06-07 18:07:57 +02:00
_THREAD_SAFE_METHOD_
FramebufferFormatKey key ;
key . attachments = p_format ;
2019-06-10 19:12:24 +02:00
const Map < FramebufferFormatKey , FramebufferFormatID > : : Element * E = framebuffer_format_cache . find ( key ) ;
2019-06-07 18:07:57 +02:00
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
2019-06-07 20:20:01 +02:00
if ( render_pass = = VK_NULL_HANDLE ) { //was likely invalid
return INVALID_ID ;
}
2019-06-10 19:12:24 +02:00
FramebufferFormatID id = FramebufferFormatID ( framebuffer_format_cache . size ( ) ) | ( FramebufferFormatID ( ID_TYPE_FRAMEBUFFER_FORMAT ) < < FramebufferFormatID ( ID_BASE_SHIFT ) ) ;
2019-06-07 18:07:57 +02:00
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 ;
2019-07-10 22:44:55 +02:00
fb_format . samples = p_format [ 0 ] . samples ;
2019-06-07 18:07:57 +02:00
framebuffer_formats [ id ] = fb_format ;
return id ;
}
2019-07-10 22:44:55 +02:00
RenderingDevice : : TextureSamples RenderingDeviceVulkan : : framebuffer_format_get_texture_samples ( FramebufferFormatID p_format ) {
Map < FramebufferFormatID , FramebufferFormat > : : Element * E = framebuffer_formats . find ( p_format ) ;
ERR_FAIL_COND_V ( ! E , TEXTURE_SAMPLES_1 ) ;
return E - > get ( ) . samples ;
}
2019-06-07 18:07:57 +02:00
/***********************/
/**** RENDER TARGET ****/
/***********************/
2019-06-10 19:12:24 +02:00
RID RenderingDeviceVulkan : : framebuffer_create ( const Vector < RID > & p_texture_attachments , FramebufferFormatID p_format_check ) {
2019-06-07 18:07:57 +02:00
_THREAD_SAFE_METHOD_
Vector < AttachmentFormat > attachments ;
Size2i size ;
for ( int i = 0 ; i < p_texture_attachments . size ( ) ; i + + ) {
Texture * texture = texture_owner . getornull ( p_texture_attachments [ i ] ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( ! texture , RID ( ) , " Texture index supplied for framebuffer ( " + itos ( i ) + " ) is not a valid texture. " ) ;
2019-06-07 18:07:57 +02:00
if ( i = = 0 ) {
size . width = texture - > width ;
size . height = texture - > height ;
} else {
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( ( uint32_t ) size . width ! = texture - > width | | ( uint32_t ) size . height ! = texture - > height , RID ( ) ,
2019-06-07 18:07:57 +02:00
" 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 ) ;
}
2019-06-10 19:12:24 +02:00
FramebufferFormatID format_id = framebuffer_format_create ( attachments ) ;
2019-06-07 18:07:57 +02:00
if ( format_id = = INVALID_ID ) {
2019-06-10 19:12:24 +02:00
return RID ( ) ;
2019-06-07 18:07:57 +02:00
}
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( p_format_check ! = INVALID_ID & & format_id ! = p_format_check , RID ( ) ,
2019-06-07 18:07:57 +02:00
" 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 ;
2019-06-10 19:12:24 +02:00
RID id = framebuffer_owner . make_rid ( framebuffer ) ;
2019-06-07 18:07:57 +02:00
for ( int i = 0 ; i < p_texture_attachments . size ( ) ; i + + ) {
_add_dependency ( id , p_texture_attachments [ i ] ) ;
}
return id ;
}
2019-06-10 19:12:24 +02:00
RenderingDevice : : FramebufferFormatID RenderingDeviceVulkan : : framebuffer_get_format ( RID p_framebuffer ) {
2019-06-07 18:07:57 +02:00
_THREAD_SAFE_METHOD_
Framebuffer * framebuffer = framebuffer_owner . getornull ( p_framebuffer ) ;
ERR_FAIL_COND_V ( ! framebuffer , INVALID_ID ) ;
return framebuffer - > format_id ;
}
/*****************/
/**** SAMPLER ****/
/*****************/
2019-06-10 19:12:24 +02:00
RID RenderingDeviceVulkan : : sampler_create ( const SamplerState & p_state ) {
2019-06-07 18:07:57 +02:00
_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 ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_state . repeat_u , SAMPLER_REPEAT_MODE_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
sampler_create_info . addressModeU = address_modes [ p_state . repeat_u ] ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_state . repeat_v , SAMPLER_REPEAT_MODE_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
sampler_create_info . addressModeV = address_modes [ p_state . repeat_v ] ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_state . repeat_w , SAMPLER_REPEAT_MODE_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_state . compare_op , COMPARE_OP_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_state . border_color , SAMPLER_BORDER_COLOR_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( res , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
2019-06-10 19:12:24 +02:00
return sampler_owner . make_rid ( sampler ) ;
2019-06-07 18:07:57 +02:00
}
/**********************/
/**** VERTEX ARRAY ****/
/**********************/
2019-06-10 19:12:24 +02:00
RID RenderingDeviceVulkan : : vertex_buffer_create ( uint32_t p_size_bytes , const PoolVector < uint8_t > & p_data ) {
2019-06-07 18:07:57 +02:00
_THREAD_SAFE_METHOD_
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( p_data . size ( ) & & ( uint32_t ) p_data . size ( ) ! = p_size_bytes , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 < uint8_t > : : Read r = p_data . read ( ) ;
_buffer_update ( & buffer , 0 , r . ptr ( ) , data_size ) ;
2019-06-24 21:13:06 +02:00
_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 ) ;
2019-06-07 18:07:57 +02:00
}
2019-06-24 21:13:06 +02:00
2019-06-10 19:12:24 +02:00
return vertex_buffer_owner . make_rid ( buffer ) ;
2019-06-07 18:07:57 +02:00
}
// 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
2019-06-10 19:12:24 +02:00
RenderingDevice : : VertexFormatID RenderingDeviceVulkan : : vertex_format_create ( const Vector < VertexDescription > & p_vertex_formats ) {
2019-06-07 18:07:57 +02:00
_THREAD_SAFE_METHOD_
VertexDescriptionKey key ;
2019-06-10 19:12:24 +02:00
key . vertex_formats = p_vertex_formats ;
2019-06-24 21:13:06 +02:00
VertexFormatID * idptr = vertex_format_cache . getptr ( key ) ;
if ( idptr ) {
return * idptr ;
2019-06-07 18:07:57 +02:00
}
2019-06-24 21:13:06 +02:00
2019-06-07 18:07:57 +02:00
//does not exist, create one and cache it
VertexDescriptionCache vdcache ;
2019-06-10 19:12:24 +02:00
vdcache . bindings = memnew_arr ( VkVertexInputBindingDescription , p_vertex_formats . size ( ) ) ;
vdcache . attributes = memnew_arr ( VkVertexInputAttributeDescription , p_vertex_formats . size ( ) ) ;
2019-06-24 21:13:06 +02:00
2019-06-07 18:07:57 +02:00
Set < int > used_locations ;
2019-06-10 19:12:24 +02:00
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 ) ;
2019-06-07 18:07:57 +02:00
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( get_format_vertex_size ( p_vertex_formats [ i ] . format ) = = 0 , INVALID_ID ,
2019-06-07 18:07:57 +02:00
" Data format for attachment ( " + itos ( i ) + " ) is not valid for a vertex array. " ) ;
vdcache . bindings [ i ] . binding = i ;
2019-06-10 19:12:24 +02:00
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 ;
2019-06-07 18:07:57 +02:00
vdcache . attributes [ i ] . binding = i ;
2019-06-10 19:12:24 +02:00
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 ) ;
2019-06-07 18:07:57 +02:00
}
vdcache . create_info . sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO ;
vdcache . create_info . pNext = NULL ;
vdcache . create_info . flags = 0 ;
2019-06-10 19:12:24 +02:00
vdcache . create_info . vertexAttributeDescriptionCount = p_vertex_formats . size ( ) ;
2019-06-07 18:07:57 +02:00
vdcache . create_info . pVertexAttributeDescriptions = vdcache . attributes ;
2019-06-10 19:12:24 +02:00
vdcache . create_info . vertexBindingDescriptionCount = p_vertex_formats . size ( ) ;
2019-06-07 18:07:57 +02:00
vdcache . create_info . pVertexBindingDescriptions = vdcache . bindings ;
2019-06-24 21:13:06 +02:00
vdcache . vertex_formats = p_vertex_formats ;
2019-06-07 18:07:57 +02:00
2019-06-10 19:12:24 +02:00
VertexFormatID id = VertexFormatID ( vertex_format_cache . size ( ) ) | ( VertexFormatID ( ID_TYPE_VERTEX_FORMAT ) < < ID_BASE_SHIFT ) ;
2019-06-24 21:13:06 +02:00
vertex_format_cache [ key ] = id ;
2019-06-10 19:12:24 +02:00
vertex_formats [ id ] = vdcache ;
2019-06-07 18:07:57 +02:00
return id ;
}
2019-06-10 19:12:24 +02:00
RID RenderingDeviceVulkan : : vertex_array_create ( uint32_t p_vertex_count , VertexFormatID p_vertex_format , const Vector < RID > & p_src_buffers ) {
2019-06-07 18:07:57 +02:00
_THREAD_SAFE_METHOD_
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( ! vertex_formats . has ( p_vertex_format ) , RID ( ) ) ;
const VertexDescriptionCache & vd = vertex_formats [ p_vertex_format ] ;
2019-06-07 18:07:57 +02:00
2019-06-24 21:13:06 +02:00
ERR_FAIL_COND_V ( vd . vertex_formats . size ( ) ! = p_src_buffers . size ( ) , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
for ( int i = 0 ; i < p_src_buffers . size ( ) ; i + + ) {
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( ! vertex_buffer_owner . owns ( p_src_buffers [ i ] ) , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
}
VertexArray vertex_array ;
vertex_array . vertex_count = p_vertex_count ;
2019-06-10 19:12:24 +02:00
vertex_array . description = p_vertex_format ;
2019-06-07 18:07:57 +02:00
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
{
2019-06-24 21:13:06 +02:00
const VertexDescription & atf = vd . vertex_formats [ i ] ;
2019-06-07 18:07:57 +02:00
uint32_t element_size = get_format_vertex_size ( atf . format ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( element_size = = 0 , RID ( ) ) ; //should never happens since this was prevalidated
2019-06-07 18:07:57 +02:00
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 ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( total_size > buffer - > size , RID ( ) ,
2019-06-07 18:07:57 +02:00
" Attachment ( " + itos ( i ) + " ) will read past the end of the buffer. " ) ;
} else {
//validate size for instances drawing
uint64_t available = buffer - > size - atf . offset ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( available < element_size , RID ( ) ,
2019-06-07 18:07:57 +02:00
" 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
}
2019-06-10 19:12:24 +02:00
RID id = vertex_array_owner . make_rid ( vertex_array ) ;
2019-06-07 18:07:57 +02:00
for ( int i = 0 ; i < p_src_buffers . size ( ) ; i + + ) {
_add_dependency ( id , p_src_buffers [ i ] ) ;
}
return id ;
}
2019-06-10 19:12:24 +02:00
RID RenderingDeviceVulkan : : index_buffer_create ( uint32_t p_index_count , IndexBufferFormat p_format , const PoolVector < uint8_t > & p_data , bool p_use_restart_indices ) {
2019-06-07 18:07:57 +02:00
_THREAD_SAFE_METHOD_
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( p_index_count = = 0 , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( ( uint32_t ) p_data . size ( ) ! = size_bytes , RID ( ) ,
2019-06-07 18:07:57 +02:00
" Default index buffer initializer array size ( " + itos ( p_data . size ( ) ) + " ) does not match format required size ( " + itos ( size_bytes ) + " ). " ) ;
PoolVector < uint8_t > : : 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 < uint8_t > : : Read r = p_data . read ( ) ;
_buffer_update ( & index_buffer , 0 , r . ptr ( ) , data_size ) ;
2019-06-24 21:13:06 +02:00
_memory_barrier ( VK_PIPELINE_STAGE_TRANSFER_BIT , VK_PIPELINE_STAGE_VERTEX_INPUT_BIT , VK_ACCESS_TRANSFER_WRITE_BIT , VK_ACCESS_INDEX_READ_BIT , false ) ;
2019-06-07 18:07:57 +02:00
}
2019-06-10 19:12:24 +02:00
return index_buffer_owner . make_rid ( index_buffer ) ;
2019-06-07 18:07:57 +02:00
}
2019-06-10 19:12:24 +02:00
RID RenderingDeviceVulkan : : index_array_create ( RID p_index_buffer , uint32_t p_index_offset , uint32_t p_index_count ) {
2019-06-07 18:07:57 +02:00
_THREAD_SAFE_METHOD_
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( ! index_buffer_owner . owns ( p_index_buffer ) , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
IndexBuffer * index_buffer = index_buffer_owner . getornull ( p_index_buffer ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( p_index_count = = 0 , RID ( ) ) ;
ERR_FAIL_COND_V ( p_index_offset + p_index_count > index_buffer - > index_count , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ;
2019-06-10 19:12:24 +02:00
RID id = index_array_owner . make_rid ( index_array ) ;
2019-06-07 18:07:57 +02:00
_add_dependency ( id , p_index_buffer ) ;
return id ;
}
/****************/
/**** SHADER ****/
/****************/
static const char * shader_stage_names [ RenderingDevice : : SHADER_STAGE_MAX ] = {
" Vertex " ,
" Fragment " ,
" TesselationControl " ,
" TesselationEvaluation " ,
" Compute "
} ;
2019-06-16 04:45:24 +02:00
static const char * shader_uniform_names [ RenderingDevice : : UNIFORM_TYPE_MAX ] = {
" Sampler " , " CombinedSampler " , " Texture " , " Image " , " TextureBuffer " , " SamplerTextureBuffer " , " ImageBuffer " , " UniformBuffer " , " StorageBuffer " , " InputAttachment "
} ;
2019-06-07 18:07:57 +02:00
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 ,
} ;
2019-07-27 15:23:24 +02:00
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 ;
}
2019-07-29 00:58:32 +02:00
#if 0
2019-07-27 15:23:24 +02:00
bool RenderingDeviceVulkan : : _uniform_add_binding ( Vector < Vector < VkDescriptorSetLayoutBinding > > & bindings , Vector < Vector < UniformInfo > > & uniform_infos , const glslang : : TObjectReflection & reflection , RenderingDevice : : ShaderStage p_stage , Shader : : PushConstant & push_constant , String * r_error ) {
2019-06-07 18:07:57 +02:00
VkDescriptorSetLayoutBinding layout_binding ;
2019-07-27 15:23:24 +02:00
UniformInfo info ;
2019-06-07 18:07:57 +02:00
switch ( reflection . getType ( ) - > getBasicType ( ) ) {
case glslang : : EbtSampler : {
2019-06-16 04:45:24 +02:00
//print_line("DEBUG: IsSampler");
2019-06-07 18:07:57 +02:00
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 ;
2019-06-16 04:45:24 +02:00
//print_line("DEBUG: SAMPLER: texel combined");
2019-06-07 18:07:57 +02:00
} else if ( reflection . getType ( ) - > getSampler ( ) . isTexture ( ) ) {
layout_binding . descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ;
info . type = UNIFORM_TYPE_TEXTURE_BUFFER ;
2019-06-16 04:45:24 +02:00
//print_line("DEBUG: SAMPLER: texel alone");
2019-06-07 18:07:57 +02:00
} else if ( reflection . getType ( ) - > getSampler ( ) . isImage ( ) ) {
layout_binding . descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER ;
info . type = UNIFORM_TYPE_IMAGE_BUFFER ;
2019-06-16 04:45:24 +02:00
//print_line("DEBUG: SAMPLER: texel buffer");
2019-06-07 18:07:57 +02:00
} 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 ;
2019-06-16 04:45:24 +02:00
//print_line("DEBUG: SAMPLER: combined");
2019-06-07 18:07:57 +02:00
} else if ( reflection . getType ( ) - > getSampler ( ) . isPureSampler ( ) ) {
layout_binding . descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER ;
info . type = UNIFORM_TYPE_SAMPLER ;
2019-06-16 04:45:24 +02:00
//print_line("DEBUG: SAMPLER: sampler");
2019-06-07 18:07:57 +02:00
} else if ( reflection . getType ( ) - > getSampler ( ) . isTexture ( ) ) {
layout_binding . descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ;
info . type = UNIFORM_TYPE_TEXTURE ;
2019-06-16 04:45:24 +02:00
//print_line("DEBUG: SAMPLER: image");
2019-06-07 18:07:57 +02:00
} else if ( reflection . getType ( ) - > getSampler ( ) . isImage ( ) ) {
layout_binding . descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ;
info . type = UNIFORM_TYPE_IMAGE ;
2019-06-16 04:45:24 +02:00
//print_line("DEBUG: SAMPLER: storage image");
2019-06-07 18:07:57 +02:00
} else {
2019-06-16 04:45:24 +02:00
//print_line("DEBUG: sampler unknown");
2019-06-07 18:07:57 +02:00
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 ( ) ;
2019-06-16 04:45:24 +02:00
//print_line("DEBUG: array of size: " + itos(layout_binding.descriptorCount));
2019-06-07 18:07:57 +02:00
} else {
layout_binding . descriptorCount = 1 ;
}
info . length = layout_binding . descriptorCount ;
} break ;
/*case glslang::EbtStruct: {
print_line ( " DEBUG: Struct " ) ;
} break ; */
case glslang : : EbtBlock : {
2019-06-16 04:45:24 +02:00
//print_line("DEBUG: Block");
2019-06-07 18:07:57 +02:00
if ( reflection . getType ( ) - > getQualifier ( ) . storage = = glslang : : EvqUniform ) {
2019-06-08 22:10:52 +02:00
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 ;
}
2019-06-16 04:45:24 +02:00
//print_line("DEBUG: Uniform buffer");
2019-06-07 18:07:57 +02:00
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 ;
2019-06-16 04:45:24 +02:00
//print_line("DEBUG: Storage buffer");
2019-06-07 18:07:57 +02:00
} else {
if ( r_error ) {
2019-06-08 22:10:52 +02:00
* 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 ) + " ). " ;
2019-06-07 18:07:57 +02:00
}
return false ;
}
if ( reflection . getType ( ) - > isArray ( ) ) {
layout_binding . descriptorCount = reflection . getType ( ) - > getArraySizes ( ) - > getCumulativeSize ( ) ;
2019-06-16 04:45:24 +02:00
//print_line("DEBUG: array of size: " + itos(layout_binding.descriptorCount));
2019-06-07 18:07:57 +02:00
} else {
layout_binding . descriptorCount = 1 ;
}
info . length = reflection . size ;
} break ;
/*case glslang::EbtReference: {
} break ; */
/*case glslang::EbtAtomicUint: {
} break ; */
default : {
2019-07-05 03:54:32 +02:00
if ( reflection . getType ( ) - > getQualifier ( ) . hasOffset ( ) | | reflection . name . find ( " . " ) ! = std : : string : : npos ) {
2019-06-07 18:07:57 +02:00
//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 ;
2019-07-27 15:23:24 +02:00
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 ;
}
2019-06-07 18:07:57 +02:00
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 ) ;
}
2019-06-19 22:03:19 +02:00
#if 0
2019-06-16 04:45:24 +02:00
print_line ( " stage: " + String ( shader_stage_names [ p_stage ] ) + " set: " + itos ( set ) + " binding: " + itos ( info . binding ) + " type: " + shader_uniform_names [ info . type ] + " length: " + itos ( info . length ) ) ;
# endif
2019-06-07 18:07:57 +02:00
bindings . write [ set ] . push_back ( layout_binding ) ;
uniform_infos . write [ set ] . push_back ( info ) ;
return true ;
}
2019-07-29 00:58:32 +02:00
# endif
2019-06-07 18:07:57 +02:00
2019-07-29 00:58:32 +02:00
RID RenderingDeviceVulkan : : shader_create ( const Vector < ShaderStageData > & p_stages ) {
2019-06-07 18:07:57 +02:00
//descriptor layouts
2019-07-28 18:42:15 +02:00
Vector < Vector < VkDescriptorSetLayoutBinding > > set_bindings ;
2019-07-27 15:23:24 +02:00
Vector < Vector < UniformInfo > > uniform_info ;
2019-06-08 22:10:52 +02:00
Shader : : PushConstant push_constant ;
push_constant . push_constant_size = 0 ;
push_constant . push_constants_vk_stage = 0 ;
2019-06-07 18:07:57 +02:00
Vector < int > vertex_input_locations ;
int fragment_outputs = 0 ;
uint32_t stages_processed = 0 ;
for ( int i = 0 ; i < p_stages . size ( ) ; i + + ) {
2019-07-29 00:58:32 +02:00
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. " ) ;
2019-06-07 18:07:57 +02:00
2019-07-28 18:42:15 +02:00
{
SpvReflectShaderModule module ;
2019-07-29 00:58:32 +02:00
PoolVector < uint8_t > : : Read spirv = p_stages [ i ] . spir_v . read ( ) ;
SpvReflectResult result = spvReflectCreateShaderModule ( p_stages [ i ] . spir_v . size ( ) , spirv . ptr ( ) , & module ) ;
2019-07-28 18:42:15 +02:00
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 < SpvReflectDescriptorBinding * > 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 < SpvReflectInterfaceVariable * > 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 < SpvReflectBlockVariable * > 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 ) ;
}
2019-06-07 18:07:57 +02:00
stages_processed | = ( 1 < < p_stages [ i ] . shader_stage ) ;
}
//all good, let's create modules
2019-07-29 17:59:18 +02:00
_THREAD_SAFE_METHOD_
2019-06-07 18:07:57 +02:00
Shader shader ;
shader . vertex_input_locations = vertex_input_locations ;
shader . fragment_outputs = fragment_outputs ;
2019-06-08 22:10:52 +02:00
shader . push_constant = push_constant ;
2019-06-07 18:07:57 +02:00
2019-06-16 04:45:24 +02:00
String error_text ;
2019-06-07 18:07:57 +02:00
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 ;
2019-07-29 00:58:32 +02:00
shader_module_create_info . codeSize = p_stages [ i ] . spir_v . size ( ) ;
PoolVector < uint8_t > : : Read r = p_stages [ i ] . spir_v . read ( ) ;
shader_module_create_info . pCode = ( const uint32_t * ) r . ptr ( ) ;
2019-06-07 18:07:57 +02:00
VkShaderModule module ;
VkResult res = vkCreateShaderModule ( device , & shader_module_create_info , NULL , & module ) ;
if ( res ) {
success = false ;
2019-06-16 04:45:24 +02:00
error_text = " Error creating shader module for stage: " + String ( shader_stage_names [ p_stages [ i ] . shader_stage ] ) ;
2019-06-07 18:07:57 +02:00
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 ) {
2019-07-28 18:42:15 +02:00
for ( int i = 0 ; i < set_bindings . size ( ) ; i + + ) {
2019-06-07 18:07:57 +02:00
//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 ;
2019-07-28 18:42:15 +02:00
layout_create_info . bindingCount = set_bindings [ i ] . size ( ) ;
layout_create_info . pBindings = set_bindings [ i ] . ptr ( ) ;
2019-06-07 18:07:57 +02:00
VkDescriptorSetLayout layout ;
VkResult res = vkCreateDescriptorSetLayout ( device , & layout_create_info , NULL , & layout ) ;
if ( res ) {
2019-06-16 04:45:24 +02:00
error_text = " Error creating descriptor set layout for set " + itos ( i ) ;
2019-06-07 18:07:57 +02:00
success = false ;
break ;
}
Shader : : Set set ;
set . descriptor_set_layout = layout ;
set . uniform_info = uniform_info [ i ] ;
//sort and hash
set . uniform_info . sort ( ) ;
2019-07-27 15:23:24 +02:00
uint32_t format = 0 ; //no format, default
if ( set . uniform_info . size ( ) ) {
//has data, needs an actual format;
UniformSetFormat usformat ;
usformat . uniform_info = set . uniform_info ;
Map < UniformSetFormat , uint32_t > : : 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 ) ;
}
2019-06-07 18:07:57 +02:00
}
shader . sets . push_back ( set ) ;
2019-07-27 15:23:24 +02:00
shader . set_formats . push_back ( format ) ;
2019-06-07 18:07:57 +02:00
}
}
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 < VkDescriptorSetLayout > layouts ;
layouts . resize ( shader . sets . size ( ) ) ;
for ( int i = 0 ; i < layouts . size ( ) ; i + + ) {
layouts . write [ i ] = shader . sets [ i ] . descriptor_set_layout ;
}
pipeline_layout_create_info . pSetLayouts = layouts . ptr ( ) ;
2019-06-08 22:10:52 +02:00
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 ;
}
2019-06-07 18:07:57 +02:00
VkResult err = vkCreatePipelineLayout ( device , & pipeline_layout_create_info , NULL , & shader . pipeline_layout ) ;
if ( err ) {
2019-06-16 04:45:24 +02:00
error_text = " Error creating pipeline layout. " ;
2019-06-07 18:07:57 +02:00
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 ) ;
}
2019-07-29 00:58:32 +02:00
ERR_FAIL_V_MSG ( RID ( ) , error_text ) ;
2019-06-07 18:07:57 +02:00
}
2019-06-10 19:12:24 +02:00
return shader_owner . make_rid ( shader ) ;
2019-06-07 18:07:57 +02:00
}
2019-06-16 04:45:24 +02:00
Vector < int > RenderingDeviceVulkan : : shader_get_vertex_input_locations_used ( RID p_shader ) {
const Shader * shader = shader_owner . getornull ( p_shader ) ;
ERR_FAIL_COND_V ( ! shader , Vector < int > ( ) ) ;
return shader - > vertex_input_locations ;
}
2019-06-07 18:07:57 +02:00
/******************/
/**** UNIFORMS ****/
/******************/
2019-06-10 19:12:24 +02:00
RID RenderingDeviceVulkan : : uniform_buffer_create ( uint32_t p_size_bytes , const PoolVector < uint8_t > & p_data ) {
2019-06-07 18:07:57 +02:00
_THREAD_SAFE_METHOD_
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( p_data . size ( ) & & ( uint32_t ) p_data . size ( ) ! = p_size_bytes , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( err ! = OK , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
if ( p_data . size ( ) ) {
uint64_t data_size = p_data . size ( ) ;
PoolVector < uint8_t > : : Read r = p_data . read ( ) ;
_buffer_update ( & buffer , 0 , r . ptr ( ) , data_size ) ;
2019-06-24 21:13:06 +02:00
_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 ) ;
2019-06-07 18:07:57 +02:00
}
2019-06-10 19:12:24 +02:00
return uniform_buffer_owner . make_rid ( buffer ) ;
2019-06-07 18:07:57 +02:00
}
2019-06-10 19:12:24 +02:00
RID RenderingDeviceVulkan : : storage_buffer_create ( uint32_t p_size_bytes , const PoolVector < uint8_t > & p_data ) {
2019-06-07 18:07:57 +02:00
_THREAD_SAFE_METHOD_
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( p_data . size ( ) & & ( uint32_t ) p_data . size ( ) ! = p_size_bytes , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( err ! = OK , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
if ( p_data . size ( ) ) {
uint64_t data_size = p_data . size ( ) ;
PoolVector < uint8_t > : : Read r = p_data . read ( ) ;
_buffer_update ( & buffer , 0 , r . ptr ( ) , data_size ) ;
2019-06-24 21:13:06 +02:00
_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 ) ;
2019-06-07 18:07:57 +02:00
}
2019-06-10 19:12:24 +02:00
return storage_buffer_owner . make_rid ( buffer ) ;
2019-06-07 18:07:57 +02:00
}
2019-06-10 19:12:24 +02:00
RID RenderingDeviceVulkan : : texture_buffer_create ( uint32_t p_size_elements , DataFormat p_format , const PoolVector < uint8_t > & p_data ) {
2019-06-07 18:07:57 +02:00
_THREAD_SAFE_METHOD_
uint32_t element_size = get_format_vertex_size ( p_format ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( element_size = = 0 , RID ( ) , " Format requested is not supported for texture buffers " ) ;
2019-06-07 18:07:57 +02:00
uint64_t size_bytes = uint64_t ( element_size ) * p_size_elements ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( p_data . size ( ) & & ( uint32_t ) p_data . size ( ) ! = size_bytes , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( err ! = OK , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
if ( p_data . size ( ) ) {
uint64_t data_size = p_data . size ( ) ;
PoolVector < uint8_t > : : Read r = p_data . read ( ) ;
_buffer_update ( & texture_buffer . buffer , 0 , r . ptr ( ) , data_size ) ;
2019-06-24 21:13:06 +02:00
_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 ) ;
2019-06-07 18:07:57 +02:00
}
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 ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_V_MSG ( RID ( ) , " Unable to create buffer view " ) ;
2019-06-07 18:07:57 +02:00
}
//allocate the view
2019-06-10 19:12:24 +02:00
return texture_buffer_owner . make_rid ( texture_buffer ) ;
2019-06-07 18:07:57 +02:00
}
RenderingDeviceVulkan : : DescriptorPool * RenderingDeviceVulkan : : _descriptor_pool_allocate ( const DescriptorPoolKey & p_key ) {
if ( ! descriptor_pools . has ( p_key ) ) {
descriptor_pools [ p_key ] = Set < DescriptorPool * > ( ) ;
}
DescriptorPool * pool = NULL ;
for ( Set < DescriptorPool * > : : 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 < VkDescriptorPoolSize > 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 ) ;
2019-06-24 21:13:06 +02:00
if ( descriptor_pools [ p_key ] . empty ( ) ) {
descriptor_pools . erase ( p_key ) ;
}
2019-06-07 18:07:57 +02:00
}
}
2019-06-10 19:12:24 +02:00
RID RenderingDeviceVulkan : : uniform_set_create ( const Vector < Uniform > & p_uniforms , RID p_shader , uint32_t p_shader_set ) {
2019-06-07 18:07:57 +02:00
_THREAD_SAFE_METHOD_
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( p_uniforms . size ( ) = = 0 , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
Shader * shader = shader_owner . getornull ( p_shader ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( ! shader , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( p_shader_set > = ( uint32_t ) shader - > sets . size ( ) | | shader - > sets [ p_shader_set ] . uniform_info . size ( ) = = 0 , RID ( ) ,
2019-06-07 18:07:57 +02:00
" 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 ( ) ;
uint32_t set_uniform_count = set . uniform_info . size ( ) ;
2019-07-27 15:23:24 +02:00
const UniformInfo * set_uniforms = set . uniform_info . ptr ( ) ;
2019-06-07 18:07:57 +02:00
Vector < VkWriteDescriptorSet > writes ;
DescriptorPoolKey pool_key ;
//to keep them alive until update call
List < Vector < VkDescriptorBufferInfo > > buffer_infos ;
List < Vector < VkBufferView > > buffer_views ;
List < Vector < VkDescriptorImageInfo > > image_infos ;
//used for verification to make sure a uniform set does not use a framebuffer bound texture
2019-06-10 19:12:24 +02:00
Vector < RID > attachable_textures ;
2019-06-07 18:07:57 +02:00
for ( uint32_t i = 0 ; i < set_uniform_count ; i + + ) {
2019-07-27 15:23:24 +02:00
const UniformInfo & set_uniform = set_uniforms [ i ] ;
2019-06-07 18:07:57 +02:00
int uniform_idx = - 1 ;
for ( int j = 0 ; j < ( int ) uniform_count ; j + + ) {
if ( uniforms [ j ] . binding = = set_uniform . binding ) {
uniform_idx = j ;
}
}
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( uniform_idx = = - 1 , RID ( ) ,
2019-06-07 18:07:57 +02:00
" All the shader bindings for the given set must be covered by the uniforms provided. " ) ;
const Uniform & uniform = uniforms [ uniform_idx ] ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( uniform . type ! = set_uniform . type , RID ( ) ,
2019-07-28 18:42:15 +02:00
" Mismatch uniform type for binding ( " + itos ( set_uniform . binding ) + " ). Expected ' " + shader_uniform_names [ set_uniform . type ] + " ', supplied: ' " + shader_uniform_names [ uniform . type ] + " '. " ) ;
2019-06-07 18:07:57 +02:00
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 ) {
2019-06-10 19:12:24 +02:00
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 ( ) ) + " ). " ) ;
2019-06-07 18:07:57 +02:00
} else {
2019-06-10 19:12:24 +02:00
ERR_FAIL_V_MSG ( RID ( ) , " Sampler (binding: " + itos ( uniform . binding ) + " ) should provide one ID referencing a sampler (IDs provided: " + itos ( uniform . ids . size ( ) ) + " ). " ) ;
2019-06-07 18:07:57 +02:00
}
}
Vector < VkDescriptorImageInfo > image_info ;
for ( int j = 0 ; j < uniform . ids . size ( ) ; j + + ) {
VkSampler * sampler = sampler_owner . getornull ( uniform . ids [ j ] ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( ! sampler , RID ( ) , " Sampler (binding: " + itos ( uniform . binding ) + " , index " + itos ( j ) + " ) is not a valid sampler. " ) ;
2019-06-07 18:07:57 +02:00
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 ) {
2019-06-10 19:12:24 +02:00
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 ( ) ) + " ). " ) ;
2019-06-07 18:07:57 +02:00
} else {
2019-06-10 19:12:24 +02:00
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 ( ) ) + " ). " ) ;
2019-06-07 18:07:57 +02:00
}
}
Vector < VkDescriptorImageInfo > image_info ;
for ( int j = 0 ; j < uniform . ids . size ( ) ; j + = 2 ) {
VkSampler * sampler = sampler_owner . getornull ( uniform . ids [ j + 0 ] ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( ! sampler , RID ( ) , " SamplerBuffer (binding: " + itos ( uniform . binding ) + " , index " + itos ( j + 1 ) + " ) is not a valid sampler. " ) ;
2019-06-07 18:07:57 +02:00
Texture * texture = texture_owner . getornull ( uniform . ids [ j + 1 ] ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( ! texture , RID ( ) , " Texture (binding: " + itos ( uniform . binding ) + " , index " + itos ( j ) + " ) is not a valid texture. " ) ;
2019-06-07 18:07:57 +02:00
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( ! ( texture - > usage_flags & TEXTURE_USAGE_SAMPLING_BIT ) , RID ( ) ,
2019-06-07 18:07:57 +02:00
" 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 ;
2019-06-07 20:20:01 +02:00
if ( texture - > usage_flags & ( TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT ) ) {
2019-06-10 19:12:24 +02:00
attachable_textures . push_back ( texture - > owner . is_valid ( ) ? texture - > owner : uniform . ids [ j + 1 ] ) ;
2019-06-07 20:20:01 +02:00
}
2019-06-07 18:07:57 +02:00
2019-06-10 19:12:24 +02:00
if ( texture - > owner . is_valid ( ) ) {
2019-06-07 18:07:57 +02:00
texture = texture_owner . getornull ( texture - > owner ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( ! texture , RID ( ) ) ; //bug, should never happen
2019-06-07 18:07:57 +02:00
}
2019-06-07 20:20:01 +02:00
img_info . imageLayout = texture - > unbound_layout ;
2019-06-07 18:07:57 +02:00
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 ) {
2019-06-10 19:12:24 +02:00
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 ( ) ) + " ). " ) ;
2019-06-07 18:07:57 +02:00
} else {
2019-06-10 19:12:24 +02:00
ERR_FAIL_V_MSG ( RID ( ) , " Texture (binding: " + itos ( uniform . binding ) + " ) should provide one ID referencing a texture (IDs provided: " + itos ( uniform . ids . size ( ) ) + " ). " ) ;
2019-06-07 18:07:57 +02:00
}
}
Vector < VkDescriptorImageInfo > image_info ;
for ( int j = 0 ; j < uniform . ids . size ( ) ; j + + ) {
Texture * texture = texture_owner . getornull ( uniform . ids [ j ] ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( ! texture , RID ( ) , " Texture (binding: " + itos ( uniform . binding ) + " , index " + itos ( j ) + " ) is not a valid texture. " ) ;
2019-06-07 18:07:57 +02:00
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( ! ( texture - > usage_flags & TEXTURE_USAGE_SAMPLING_BIT ) , RID ( ) ,
2019-06-07 18:07:57 +02:00
" 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 ;
2019-06-07 20:20:01 +02:00
if ( texture - > usage_flags & ( TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT ) ) {
2019-06-10 19:12:24 +02:00
attachable_textures . push_back ( texture - > owner . is_valid ( ) ? texture - > owner : uniform . ids [ j ] ) ;
2019-06-07 20:20:01 +02:00
}
2019-06-07 18:07:57 +02:00
2019-06-10 19:12:24 +02:00
if ( texture - > owner . is_valid ( ) ) {
2019-06-07 18:07:57 +02:00
texture = texture_owner . getornull ( texture - > owner ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( ! texture , RID ( ) ) ; //bug, should never happen
2019-06-07 18:07:57 +02:00
}
2019-06-07 20:20:01 +02:00
img_info . imageLayout = texture - > unbound_layout ;
2019-06-07 18:07:57 +02:00
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 ) {
2019-06-10 19:12:24 +02:00
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 ( ) ) + " ). " ) ;
2019-06-07 18:07:57 +02:00
} else {
2019-06-10 19:12:24 +02:00
ERR_FAIL_V_MSG ( RID ( ) , " Buffer (binding: " + itos ( uniform . binding ) + " ) should provide one ID referencing a texture buffer (IDs provided: " + itos ( uniform . ids . size ( ) ) + " ). " ) ;
2019-06-07 18:07:57 +02:00
}
}
Vector < VkDescriptorBufferInfo > buffer_info ;
Vector < VkBufferView > buffer_view ;
for ( int j = 0 ; j < uniform . ids . size ( ) ; j + + ) {
TextureBuffer * buffer = texture_buffer_owner . getornull ( uniform . ids [ j ] ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( ! buffer , RID ( ) , " Texture Buffer (binding: " + itos ( uniform . binding ) + " , index " + itos ( j ) + " ) is not a valid texture buffer. " ) ;
2019-06-07 18:07:57 +02:00
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 ) {
2019-06-10 19:12:24 +02:00
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 ( ) ) + " ). " ) ;
2019-06-07 18:07:57 +02:00
} else {
2019-06-10 19:12:24 +02:00
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 ( ) ) + " ). " ) ;
2019-06-07 18:07:57 +02:00
}
}
Vector < VkDescriptorImageInfo > image_info ;
Vector < VkDescriptorBufferInfo > buffer_info ;
Vector < VkBufferView > buffer_view ;
for ( int j = 0 ; j < uniform . ids . size ( ) ; j + = 2 ) {
VkSampler * sampler = sampler_owner . getornull ( uniform . ids [ j + 0 ] ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( ! sampler , RID ( ) , " SamplerBuffer (binding: " + itos ( uniform . binding ) + " , index " + itos ( j + 1 ) + " ) is not a valid sampler. " ) ;
2019-06-07 18:07:57 +02:00
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 ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( ! buffer , RID ( ) , " SamplerBuffer (binding: " + itos ( uniform . binding ) + " , index " + itos ( j + 1 ) + " ) is not a valid texture buffer. " ) ;
2019-06-07 18:07:57 +02:00
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 : {
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( uniform . ids . size ( ) ! = 1 , RID ( ) ,
2019-07-21 16:31:30 +02:00
" Uniform buffer supplied (binding: " + itos ( uniform . binding ) + " ) must provide one ID ( " + itos ( uniform . ids . size ( ) ) + " provided). " ) ;
2019-06-07 18:07:57 +02:00
Buffer * buffer = uniform_buffer_owner . getornull ( uniform . ids [ 0 ] ) ;
2019-07-21 16:31:30 +02:00
ERR_FAIL_COND_V_MSG ( ! buffer , RID ( ) , " Uniform buffer supplied (binding: " + itos ( uniform . binding ) + " ) is invalid. " ) ;
2019-06-07 18:07:57 +02:00
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( buffer - > size ! = ( uint32_t ) set_uniform . length , RID ( ) ,
2019-07-21 16:31:30 +02:00
" Uniform buffer supplied (binding: " + itos ( uniform . binding ) + " ) size ( " + itos ( buffer - > size ) + " does not match size of shader uniform: ( " + itos ( set_uniform . length ) + " ). " ) ;
2019-06-07 18:07:57 +02:00
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 : {
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( uniform . ids . size ( ) ! = 1 , RID ( ) ,
2019-07-21 16:31:30 +02:00
" Storage buffer supplied (binding: " + itos ( uniform . binding ) + " ) must provide one ID ( " + itos ( uniform . ids . size ( ) ) + " provided). " ) ;
2019-06-07 18:07:57 +02:00
Buffer * buffer = storage_buffer_owner . getornull ( uniform . ids [ 0 ] ) ;
2019-07-21 16:31:30 +02:00
ERR_FAIL_COND_V_MSG ( ! buffer , RID ( ) , " Storage buffer supplied (binding: " + itos ( uniform . binding ) + " ) is invalid. " ) ;
2019-06-07 18:07:57 +02:00
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( buffer - > size ! = ( uint32_t ) set_uniform . length , RID ( ) ,
2019-07-21 16:31:30 +02:00
" Storage buffer supplied (binding: " + itos ( uniform . binding ) + " ) size ( " + itos ( buffer - > size ) + " does not match size of shader uniform: ( " + itos ( set_uniform . length ) + " ). " ) ;
2019-06-07 18:07:57 +02:00
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 ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( pool_key . uniform_type [ set_uniform . type ] = = MAX_DESCRIPTOR_POOL_ELEMENT , RID ( ) ,
2019-06-07 18:07:57 +02:00
" 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 ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( ! pool , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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
2019-06-10 19:12:24 +02:00
ERR_FAIL_V_MSG ( RID ( ) , " Cannot allocate descriptor sets. " ) ;
2019-06-07 18:07:57 +02:00
}
UniformSet uniform_set ;
uniform_set . pool = pool ;
uniform_set . pool_key = pool_key ;
uniform_set . descriptor_set = descriptor_set ;
2019-07-27 15:23:24 +02:00
uniform_set . format = shader - > set_formats [ p_shader_set ] ;
2019-06-07 20:20:01 +02:00
uniform_set . attachable_textures = attachable_textures ;
2019-07-27 15:23:24 +02:00
uniform_set . shader_set = p_shader_set ;
uniform_set . shader_id = p_shader ;
2019-06-07 18:07:57 +02:00
2019-06-10 19:12:24 +02:00
RID id = uniform_set_owner . make_rid ( uniform_set ) ;
2019-06-07 18:07:57 +02:00
//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 ( ) ;
2019-06-10 19:12:24 +02:00
const RID * ids = uniform . ids . ptr ( ) ;
2019-06-07 18:07:57 +02:00
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 ;
}
2019-06-16 04:45:24 +02:00
bool RenderingDeviceVulkan : : uniform_set_is_valid ( RID p_uniform_set ) {
return uniform_set_owner . owns ( p_uniform_set ) ;
}
2019-07-05 03:54:32 +02:00
Error RenderingDeviceVulkan : : buffer_update ( RID p_buffer , uint32_t p_offset , uint32_t p_size , const void * p_data , bool p_sync_with_draw ) {
2019-06-07 18:07:57 +02:00
_THREAD_SAFE_METHOD_
2019-06-25 03:24:07 +02:00
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 " ) ;
2019-06-24 21:13:06 +02:00
VkPipelineStageFlags dst_stage_mask ;
VkAccessFlags dst_access ;
2019-06-07 18:07:57 +02:00
Buffer * buffer = NULL ;
if ( vertex_buffer_owner . owns ( p_buffer ) ) {
2019-06-24 21:13:06 +02:00
dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT ;
dst_access = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT ;
2019-06-07 18:07:57 +02:00
buffer = vertex_buffer_owner . getornull ( p_buffer ) ;
} else if ( index_buffer_owner . owns ( p_buffer ) ) {
2019-06-24 21:13:06 +02:00
dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT ;
dst_access = VK_ACCESS_INDEX_READ_BIT ;
2019-06-07 18:07:57 +02:00
buffer = index_buffer_owner . getornull ( p_buffer ) ;
} else if ( uniform_buffer_owner . owns ( p_buffer ) ) {
2019-06-24 21:13:06 +02:00
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 ;
2019-06-07 18:07:57 +02:00
buffer = uniform_buffer_owner . getornull ( p_buffer ) ;
} else if ( texture_buffer_owner . owns ( p_buffer ) ) {
2019-06-24 21:13:06 +02:00
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 ;
2019-06-07 18:07:57 +02:00
buffer = & texture_buffer_owner . getornull ( p_buffer ) - > buffer ;
} else if ( storage_buffer_owner . owns ( p_buffer ) ) {
2019-06-24 21:13:06 +02:00
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 ;
2019-06-07 18:07:57 +02:00
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. " ) ;
2019-06-24 21:13:06 +02:00
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 ;
2019-06-07 18:07:57 +02:00
}
/*************************/
/**** RENDER PIPELINE ****/
/*************************/
2019-06-10 19:12:24 +02:00
RID RenderingDeviceVulkan : : render_pipeline_create ( RID p_shader , FramebufferFormatID p_framebuffer_format , VertexFormatID p_vertex_format , 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 ) {
2019-06-07 18:07:57 +02:00
_THREAD_SAFE_METHOD_
//needs a shader
Shader * shader = shader_owner . getornull ( p_shader ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( ! shader , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
if ( p_framebuffer_format = = INVALID_ID ) {
//if nothing provided, use an empty one (no attachments)
p_framebuffer_format = framebuffer_format_create ( Vector < AttachmentFormat > ( ) ) ;
}
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( ! framebuffer_formats . has ( p_framebuffer_format ) , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
const FramebufferFormat & fb_format = framebuffer_formats [ p_framebuffer_format ] ;
{ //validate shader vs framebuffer
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( shader - > fragment_outputs ! = fb_format . color_attachments , RID ( ) ,
2019-06-07 18:07:57 +02:00
" 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 ;
2019-06-10 19:12:24 +02:00
if ( p_vertex_format ! = INVALID_ID ) {
2019-06-07 18:07:57 +02:00
//uses vertices, else it does not
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( ! vertex_formats . has ( p_vertex_format ) , RID ( ) ) ;
2019-06-24 21:13:06 +02:00
const VertexDescriptionCache & vd = vertex_formats [ p_vertex_format ] ;
2019-06-07 18:07:57 +02:00
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 ] ;
bool found = false ;
2019-06-24 21:13:06 +02:00
for ( int j = 0 ; j < vd . vertex_formats . size ( ) ; j + + ) {
if ( vd . vertex_formats [ j ] . location = = location ) {
2019-06-07 18:07:57 +02:00
found = true ;
}
}
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( ! found , RID ( ) ,
2019-06-07 18:07:57 +02:00
" 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 ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V_MSG ( shader - > vertex_input_locations . size ( ) , RID ( ) ,
2019-06-07 18:07:57 +02:00
" Shader contains vertex inputs ( " + itos ( shader - > vertex_input_locations . size ( ) ) + " ) but no vertex input description was provided for pipeline creation. " ) ;
}
//input assembly
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_render_primitive , RENDER_PRIMITIVE_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( p_rasterization_state . patch_control_points < 1 | | p_rasterization_state . patch_control_points > limits . maxTessellationPatchSize , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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
} ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_rasterization_state . cull_mode , 3 , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 < VkSampleMask > 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
} ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( rasterization_sample_mask_expected_size [ p_multisample_state . sample_count ] ! = p_multisample_state . sample_mask . size ( ) , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_depth_stencil_state . depth_compare_operator , COMPARE_OP_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_depth_stencil_state . stencil_operation_front . fail , STENCIL_OP_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
depth_stencil_state_create_info . front . failOp = stencil_operations [ p_depth_stencil_state . stencil_operation_front . fail ] ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_depth_stencil_state . stencil_operation_front . pass , STENCIL_OP_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
depth_stencil_state_create_info . front . passOp = stencil_operations [ p_depth_stencil_state . stencil_operation_front . pass ] ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_depth_stencil_state . stencil_operation_front . depth_fail , STENCIL_OP_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
depth_stencil_state_create_info . front . depthFailOp = stencil_operations [ p_depth_stencil_state . stencil_operation_front . depth_fail ] ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_depth_stencil_state . stencil_operation_front . compare , COMPARE_OP_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_depth_stencil_state . stencil_operation_back . fail , STENCIL_OP_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
depth_stencil_state_create_info . back . failOp = stencil_operations [ p_depth_stencil_state . stencil_operation_back . fail ] ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_depth_stencil_state . stencil_operation_back . pass , STENCIL_OP_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
depth_stencil_state_create_info . back . passOp = stencil_operations [ p_depth_stencil_state . stencil_operation_back . pass ] ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_depth_stencil_state . stencil_operation_back . depth_fail , STENCIL_OP_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
depth_stencil_state_create_info . back . depthFailOp = stencil_operations [ p_depth_stencil_state . stencil_operation_back . depth_fail ] ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_depth_stencil_state . stencil_operation_back . compare , COMPARE_OP_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_blend_state . logic_op , LOGIC_OP_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
color_blend_state_create_info . logicOp = logic_operations [ p_blend_state . logic_op ] ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( fb_format . color_attachments ! = p_blend_state . attachments . size ( ) , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
Vector < VkPipelineColorBlendAttachmentState > attachment_states ;
for ( int i = 0 ; i < p_blend_state . attachments . size ( ) ; i + + ) {
VkPipelineColorBlendAttachmentState state ;
state . blendEnable = p_blend_state . attachments [ i ] . enable_blend ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_blend_state . attachments [ i ] . src_color_blend_factor , BLEND_FACTOR_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
state . srcColorBlendFactor = blend_factors [ p_blend_state . attachments [ i ] . src_color_blend_factor ] ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_blend_state . attachments [ i ] . dst_color_blend_factor , BLEND_FACTOR_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
state . dstColorBlendFactor = blend_factors [ p_blend_state . attachments [ i ] . dst_color_blend_factor ] ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_blend_state . attachments [ i ] . color_blend_op , BLEND_OP_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
state . colorBlendOp = blend_operations [ p_blend_state . attachments [ i ] . color_blend_op ] ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_blend_state . attachments [ i ] . src_alpha_blend_factor , BLEND_FACTOR_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
state . srcAlphaBlendFactor = blend_factors [ p_blend_state . attachments [ i ] . src_alpha_blend_factor ] ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_blend_state . attachments [ i ] . dst_alpha_blend_factor , BLEND_FACTOR_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
state . dstAlphaBlendFactor = blend_factors [ p_blend_state . attachments [ i ] . dst_alpha_blend_factor ] ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_INDEX_V ( p_blend_state . attachments [ i ] . alpha_blend_op , BLEND_OP_MAX , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
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 < VkDynamicState > 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 ;
2019-06-16 04:45:24 +02:00
graphics_pipeline_create_info . flags = 0 ;
2019-06-07 18:07:57 +02:00
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 ) ;
2019-06-10 19:12:24 +02:00
ERR_FAIL_COND_V ( err , RID ( ) ) ;
2019-06-07 18:07:57 +02:00
2019-07-27 15:23:24 +02:00
pipeline . set_formats = shader - > set_formats ;
2019-06-08 22:10:52 +02:00
pipeline . push_constant_stages = shader - > push_constant . push_constants_vk_stage ;
pipeline . pipeline_layout = shader - > pipeline_layout ;
2019-07-27 15:23:24 +02:00
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 ;
2019-06-07 18:07:57 +02:00
static const uint32_t primitive_divisor [ RENDER_PRIMITIVE_MAX ] = {
1 , 2 , 1 , 1 , 1 , 3 , 1 , 1 , 1 , 1 , 1
} ;
2019-07-27 15:23:24 +02:00
pipeline . validation . primitive_divisor = primitive_divisor [ p_render_primitive ] ;
2019-06-07 18:07:57 +02:00
static const uint32_t primitive_minimum [ RENDER_PRIMITIVE_MAX ] = {
1 ,
2 ,
2 ,
2 ,
2 ,
3 ,
3 ,
3 ,
3 ,
3 ,
1 ,
} ;
2019-07-27 15:23:24 +02:00
pipeline . validation . primitive_minimum = primitive_minimum [ p_render_primitive ] ;
# endif
2019-06-07 18:07:57 +02:00
//create ID to associate with this pipeline
2019-06-10 19:12:24 +02:00
RID id = pipeline_owner . make_rid ( pipeline ) ;
2019-06-07 18:07:57 +02:00
//now add aall the dependencies
_add_dependency ( id , p_shader ) ;
return id ;
}
2019-06-24 21:13:06 +02:00
bool RenderingDeviceVulkan : : render_pipeline_is_valid ( RID p_pipeline ) {
_THREAD_SAFE_METHOD_
return pipeline_owner . owns ( p_pipeline ) ;
}
2019-06-07 18:07:57 +02:00
/****************/
/**** SCREEN ****/
/****************/
int RenderingDeviceVulkan : : screen_get_width ( int p_screen ) const {
_THREAD_SAFE_METHOD_
2019-06-24 21:13:06 +02:00
return context - > window_get_width ( p_screen ) ;
2019-06-07 18:07:57 +02:00
}
int RenderingDeviceVulkan : : screen_get_height ( int p_screen ) const {
_THREAD_SAFE_METHOD_
2019-06-24 21:13:06 +02:00
return context - > window_get_height ( p_screen ) ;
2019-06-07 18:07:57 +02:00
}
2019-06-10 19:12:24 +02:00
RenderingDevice : : FramebufferFormatID RenderingDeviceVulkan : : screen_get_framebuffer_format ( ) const {
2019-06-07 18:07:57 +02:00
_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 < AttachmentFormat > screen_attachment ;
screen_attachment . push_back ( attachment ) ;
return const_cast < RenderingDeviceVulkan * > ( this ) - > framebuffer_format_create ( screen_attachment ) ;
}
/*******************/
/**** DRAW LIST ****/
/*******************/
2019-06-10 19:12:24 +02:00
RenderingDevice : : DrawListID RenderingDeviceVulkan : : draw_list_begin_for_screen ( int p_screen , const Color & p_clear_color ) {
2019-06-07 18:07:57 +02:00
_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 ;
2019-07-12 15:18:30 +02:00
# ifdef DEBUG_ENABLED
2019-06-07 18:07:57 +02:00
draw_list - > validation . framebuffer_format = screen_get_framebuffer_format ( ) ;
2019-07-12 15:18:30 +02:00
# endif
2019-06-07 18:07:57 +02:00
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 ;
2019-06-24 21:13:06 +02:00
render_pass_begin . renderPass = context - > window_get_render_pass ( p_screen ) ;
render_pass_begin . framebuffer = context - > window_get_framebuffer ( p_screen ) ;
2019-06-07 18:07:57 +02:00
2019-06-24 21:13:06 +02:00
render_pass_begin . renderArea . extent . width = context - > window_get_width ( p_screen ) ;
render_pass_begin . renderArea . extent . height = context - > window_get_height ( p_screen ) ;
2019-06-07 18:07:57 +02:00
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 < VkImageView > 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 ) ;
2019-07-27 15:23:24 +02:00
ERR_FAIL_COND_V ( texture - > width ! = p_framebuffer - > size . width , ERR_BUG ) ;
ERR_FAIL_COND_V ( texture - > height ! = p_framebuffer - > size . height , ERR_BUG ) ;
2019-06-07 18:07:57 +02:00
}
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 < Color > & 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 < VkClearValue > 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 ;
}
2019-06-10 19:12:24 +02:00
RenderingDevice : : DrawListID RenderingDeviceVulkan : : draw_list_begin ( RID p_framebuffer , InitialAction p_initial_action , FinalAction p_final_action , const Vector < Color > & p_clear_colors , const Rect2 & p_region ) {
2019-06-07 18:07:57 +02:00
_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 ;
2019-07-12 15:18:30 +02:00
# ifdef DEBUG_ENABLED
2019-06-07 18:07:57 +02:00
draw_list - > validation . framebuffer_format = framebuffer - > format_id ;
2019-07-12 15:18:30 +02:00
# endif
2019-06-07 18:07:57 +02:00
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 ) ;
2019-06-24 21:13:06 +02:00
draw_list - > viewport = Rect2i ( viewport_offset , viewport_size ) ;
2019-06-07 18:07:57 +02:00
return ID_TYPE_DRAW_LIST ;
}
2019-06-10 19:12:24 +02:00
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 < Color > & p_clear_colors , const Rect2 & p_region ) {
2019-06-07 18:07:57 +02:00
_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 ;
2019-07-12 15:18:30 +02:00
# ifdef DEBUG_ENABLED
2019-06-07 18:07:57 +02:00
draw_list [ i ] . validation . framebuffer_format = framebuffer - > format_id ;
2019-07-12 15:18:30 +02:00
# endif
2019-06-07 18:07:57 +02:00
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 ) ;
2019-06-10 19:12:24 +02:00
r_split_ids [ i ] = ( DrawListID ( 1 ) < < DrawListID ( ID_TYPE_SPLIT_DRAW_LIST ) ) + i ;
2019-06-24 21:13:06 +02:00
draw_list [ i ] . viewport = Rect2i ( viewport_offset , viewport_size ) ;
2019-06-07 18:07:57 +02:00
}
return OK ;
}
2019-06-10 19:12:24 +02:00
RenderingDeviceVulkan : : DrawList * RenderingDeviceVulkan : : _get_draw_list_ptr ( DrawListID p_id ) {
2019-06-07 18:07:57 +02:00
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 ;
2019-06-10 19:12:24 +02:00
} else if ( p_id > > DrawListID ( ID_BASE_SHIFT ) = = ID_TYPE_SPLIT_DRAW_LIST ) {
2019-06-07 18:07:57 +02:00
if ( ! draw_list_split ) {
return NULL ;
}
2019-06-10 19:12:24 +02:00
uint64_t index = p_id & ( ( DrawListID ( 1 ) < < DrawListID ( ID_BASE_SHIFT ) ) - 1 ) ; //mask
2019-06-07 18:07:57 +02:00
if ( index > = draw_list_count ) {
return NULL ;
}
return & draw_list [ index ] ;
} else {
return NULL ;
}
}
2019-06-10 19:12:24 +02:00
void RenderingDeviceVulkan : : draw_list_bind_render_pipeline ( DrawListID p_list , RID p_render_pipeline ) {
2019-06-07 18:07:57 +02:00
DrawList * dl = _get_draw_list_ptr ( p_list ) ;
ERR_FAIL_COND ( ! dl ) ;
2019-07-27 15:23:24 +02:00
# ifdef DEBUG_ENABLED
2019-06-07 18:07:57 +02:00
ERR_FAIL_COND_MSG ( ! dl - > validation . active , " Submitted Draw Lists can no longer be modified. " ) ;
2019-07-27 15:23:24 +02:00
# endif
2019-06-07 18:07:57 +02:00
const RenderPipeline * pipeline = pipeline_owner . getornull ( p_render_pipeline ) ;
ERR_FAIL_COND ( ! pipeline ) ;
2019-07-27 15:23:24 +02:00
# 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.
}
2019-06-07 18:07:57 +02:00
2019-07-27 15:23:24 +02:00
dl - > state . pipeline = p_render_pipeline ;
dl - > state . pipeline_layout = pipeline - > pipeline_layout ;
2019-06-07 18:07:57 +02:00
vkCmdBindPipeline ( dl - > command_buffer , VK_PIPELINE_BIND_POINT_GRAPHICS , pipeline - > pipeline ) ;
2019-07-27 15:23:24 +02:00
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
2019-06-07 18:07:57 +02:00
//update render pass pipeline info
dl - > validation . pipeline_active = true ;
2019-07-27 15:23:24 +02:00
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 ;
2019-06-08 22:10:52 +02:00
dl - > validation . pipeline_push_constant_size = pipeline - > push_constant_size ;
2019-07-27 15:23:24 +02:00
# endif
2019-06-07 18:07:57 +02:00
}
2019-06-10 19:12:24 +02:00
void RenderingDeviceVulkan : : draw_list_bind_uniform_set ( DrawListID p_list , RID p_uniform_set , uint32_t p_index ) {
2019-07-27 15:23:24 +02:00
# ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG ( p_index > = limits . maxBoundDescriptorSets | | p_index > MAX_UNIFORM_SETS ,
2019-06-07 18:07:57 +02:00
" Attempting to bind a descriptor set ( " + itos ( p_index ) + " ) greater than what the hardware supports ( " + itos ( limits . maxBoundDescriptorSets ) + " ). " ) ;
2019-07-27 15:23:24 +02:00
# endif
2019-06-07 18:07:57 +02:00
DrawList * dl = _get_draw_list_ptr ( p_list ) ;
ERR_FAIL_COND ( ! dl ) ;
2019-07-27 15:23:24 +02:00
# ifdef DEBUG_ENABLED
2019-06-07 18:07:57 +02:00
ERR_FAIL_COND_MSG ( ! dl - > validation . active , " Submitted Draw Lists can no longer be modified. " ) ;
2019-07-27 15:23:24 +02:00
# endif
2019-06-07 18:07:57 +02:00
const UniformSet * uniform_set = uniform_set_owner . getornull ( p_uniform_set ) ;
ERR_FAIL_COND ( ! uniform_set ) ;
2019-07-27 15:23:24 +02:00
if ( p_index > dl - > state . set_count ) {
dl - > state . set_count = p_index ;
2019-06-07 18:07:57 +02:00
}
2019-06-07 20:20:01 +02:00
2019-07-27 15:23:24 +02:00
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
2019-06-07 20:20:01 +02:00
{ //validate that textures bound are not attached as framebuffer bindings
uint32_t attachable_count = uniform_set - > attachable_textures . size ( ) ;
2019-06-10 19:12:24 +02:00
const RID * attachable_ptr = uniform_set - > attachable_textures . ptr ( ) ;
2019-06-07 20:20:01 +02:00
uint32_t bound_count = draw_list_bound_textures . size ( ) ;
2019-06-10 19:12:24 +02:00
const RID * bound_ptr = draw_list_bound_textures . ptr ( ) ;
2019-06-07 20:20:01 +02:00
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. " ) ;
}
2019-06-07 18:07:57 +02:00
}
}
2019-07-27 15:23:24 +02:00
# endif
2019-06-07 18:07:57 +02:00
}
2019-06-10 19:12:24 +02:00
void RenderingDeviceVulkan : : draw_list_bind_vertex_array ( DrawListID p_list , RID p_vertex_array ) {
2019-06-07 18:07:57 +02:00
DrawList * dl = _get_draw_list_ptr ( p_list ) ;
ERR_FAIL_COND ( ! dl ) ;
2019-07-27 15:23:24 +02:00
# ifdef DEBUG_ENABLED
2019-06-07 18:07:57 +02:00
ERR_FAIL_COND_MSG ( ! dl - > validation . active , " Submitted Draw Lists can no longer be modified. " ) ;
2019-07-27 15:23:24 +02:00
# endif
2019-06-07 18:07:57 +02:00
const VertexArray * vertex_array = vertex_array_owner . getornull ( p_vertex_array ) ;
ERR_FAIL_COND ( ! vertex_array ) ;
2019-07-27 15:23:24 +02:00
if ( dl - > state . vertex_array = = p_vertex_array ) {
return ; //already set
}
dl - > state . vertex_array = p_vertex_array ;
# ifdef DEBUG_ENABLED
2019-06-07 18:07:57 +02:00
dl - > validation . vertex_format = vertex_array - > description ;
dl - > validation . vertex_max_instances_allowed = vertex_array - > max_instances_allowed ;
2019-07-27 15:23:24 +02:00
# endif
2019-07-12 15:18:30 +02:00
dl - > validation . vertex_array_size = vertex_array - > vertex_count ;
2019-06-07 18:07:57 +02:00
vkCmdBindVertexBuffers ( dl - > command_buffer , 0 , vertex_array - > buffers . size ( ) , vertex_array - > buffers . ptr ( ) , vertex_array - > offsets . ptr ( ) ) ;
}
2019-06-10 19:12:24 +02:00
void RenderingDeviceVulkan : : draw_list_bind_index_array ( DrawListID p_list , RID p_index_array ) {
2019-06-07 18:07:57 +02:00
DrawList * dl = _get_draw_list_ptr ( p_list ) ;
ERR_FAIL_COND ( ! dl ) ;
2019-07-27 15:23:24 +02:00
# ifdef DEBUG_ENABLED
2019-06-07 18:07:57 +02:00
ERR_FAIL_COND_MSG ( ! dl - > validation . active , " Submitted Draw Lists can no longer be modified. " ) ;
2019-07-27 15:23:24 +02:00
# endif
2019-06-07 18:07:57 +02:00
const IndexArray * index_array = index_array_owner . getornull ( p_index_array ) ;
ERR_FAIL_COND ( ! index_array ) ;
2019-07-27 15:23:24 +02:00
if ( dl - > state . index_array = = p_index_array ) {
return ; //already set
}
dl - > state . index_array = p_index_array ;
# ifdef DEBUG_ENABLED
2019-06-07 18:07:57 +02:00
dl - > validation . index_array_max_index = index_array - > max_index ;
2019-07-27 15:23:24 +02:00
# endif
2019-07-12 15:18:30 +02:00
dl - > validation . index_array_size = index_array - > indices ;
dl - > validation . index_array_offset = index_array - > offset ;
2019-06-07 18:07:57 +02:00
vkCmdBindIndexBuffer ( dl - > command_buffer , index_array - > buffer , index_array - > offset , index_array - > index_type ) ;
}
2019-06-24 21:13:06 +02:00
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 ) ;
2019-07-12 15:18:30 +02:00
# ifdef DEBUG_ENABLED
2019-06-24 21:13:06 +02:00
ERR_FAIL_COND_MSG ( ! dl - > validation . active , " Submitted Draw Lists can no longer be modified. " ) ;
2019-07-12 15:18:30 +02:00
# endif
2019-06-24 21:13:06 +02:00
vkCmdSetLineWidth ( dl - > command_buffer , p_width ) ;
}
2019-06-10 19:12:24 +02:00
void RenderingDeviceVulkan : : draw_list_set_push_constant ( DrawListID p_list , void * p_data , uint32_t p_data_size ) {
2019-06-08 22:10:52 +02:00
DrawList * dl = _get_draw_list_ptr ( p_list ) ;
ERR_FAIL_COND ( ! dl ) ;
2019-07-27 15:23:24 +02:00
# ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG ( ! dl - > validation . active , " Submitted Draw Lists can no longer be modified. " ) ;
# endif
# ifdef DEBUG_ENABLED
2019-06-08 22:10:52 +02:00
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 ) + " ) " ) ;
2019-07-27 15:23:24 +02:00
# endif
vkCmdPushConstants ( dl - > command_buffer , dl - > state . pipeline_layout , dl - > state . pipeline_push_constant_stages , 0 , p_data_size , p_data ) ;
2019-07-12 15:18:30 +02:00
# ifdef DEBUG_ENABLED
2019-06-08 22:10:52 +02:00
dl - > validation . pipeline_push_constant_suppplied = true ;
2019-07-12 15:18:30 +02:00
# endif
2019-06-08 22:10:52 +02:00
}
2019-06-10 19:12:24 +02:00
void RenderingDeviceVulkan : : draw_list_draw ( DrawListID p_list , bool p_use_indices , uint32_t p_instances ) {
2019-06-07 18:07:57 +02:00
DrawList * dl = _get_draw_list_ptr ( p_list ) ;
ERR_FAIL_COND ( ! dl ) ;
2019-07-27 15:23:24 +02:00
# ifdef DEBUG_ENABLED
2019-06-07 18:07:57 +02:00
ERR_FAIL_COND_MSG ( ! dl - > validation . active , " Submitted Draw Lists can no longer be modified. " ) ;
2019-07-27 15:23:24 +02:00
# endif
2019-06-07 18:07:57 +02:00
2019-07-27 15:23:24 +02:00
# ifdef DEBUG_ENABLED
2019-06-07 18:07:57 +02:00
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 ) + " ). " ) ;
}
2019-06-08 22:10:52 +02:00
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. " ) ;
}
2019-06-07 18:07:57 +02:00
2019-07-27 15:23:24 +02:00
# endif
2019-06-07 18:07:57 +02:00
2019-07-27 15:23:24 +02:00
//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 ) + " \n 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 ) ) ;
} 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 ) ) ;
2019-06-07 18:07:57 +02:00
}
}
2019-07-27 15:23:24 +02:00
# 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 ;
}
2019-06-07 18:07:57 +02:00
}
if ( p_use_indices ) {
2019-07-27 15:23:24 +02:00
# ifdef DEBUG_ENABLED
2019-06-07 18:07:57 +02:00
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. " ) ;
2019-07-27 15:23:24 +02:00
# endif
2019-06-07 18:07:57 +02:00
uint32_t to_draw = dl - > validation . index_array_size ;
2019-07-27 15:23:24 +02:00
# ifdef DEBUG_ENABLED
2019-06-07 18:07:57 +02:00
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 ) + " ). " ) ;
2019-07-27 15:23:24 +02:00
# endif
2019-06-07 18:07:57 +02:00
vkCmdDrawIndexed ( dl - > command_buffer , to_draw , p_instances , dl - > validation . index_array_offset , 0 , 0 ) ;
} else {
2019-07-27 15:23:24 +02:00
# ifdef DEBUG_ENABLED
2019-06-07 18:07:57 +02:00
ERR_FAIL_COND_MSG ( dl - > validation . pipeline_vertex_format = = INVALID_ID ,
" Draw command lacks indices, but pipeline format does not use vertices. " ) ;
2019-07-27 15:23:24 +02:00
# endif
2019-06-07 18:07:57 +02:00
uint32_t to_draw = dl - > validation . vertex_array_size ;
2019-07-27 15:23:24 +02:00
# ifdef DEBUG_ENABLED
2019-06-07 18:07:57 +02:00
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 ) + " ). " ) ;
2019-07-27 15:23:24 +02:00
# endif
2019-06-07 18:07:57 +02:00
vkCmdDraw ( dl - > command_buffer , to_draw , p_instances , 0 , 0 ) ;
}
}
2019-06-10 19:12:24 +02:00
void RenderingDeviceVulkan : : draw_list_enable_scissor ( DrawListID p_list , const Rect2 & p_rect ) {
2019-06-24 21:13:06 +02:00
DrawList * dl = _get_draw_list_ptr ( p_list ) ;
2019-07-27 15:23:24 +02:00
2019-06-24 21:13:06 +02:00
ERR_FAIL_COND ( ! dl ) ;
2019-07-27 15:23:24 +02:00
# ifdef DEBUG_ENABLED
2019-06-24 21:13:06 +02:00
ERR_FAIL_COND_MSG ( ! dl - > validation . active , " Submitted Draw Lists can no longer be modified. " ) ;
2019-07-27 15:23:24 +02:00
# endif
2019-06-24 21:13:06 +02:00
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 ) ;
2019-06-07 18:07:57 +02:00
}
2019-06-10 19:12:24 +02:00
void RenderingDeviceVulkan : : draw_list_disable_scissor ( DrawListID p_list ) {
2019-06-24 21:13:06 +02:00
DrawList * dl = _get_draw_list_ptr ( p_list ) ;
ERR_FAIL_COND ( ! dl ) ;
2019-07-27 15:23:24 +02:00
# ifdef DEBUG_ENABLED
2019-06-24 21:13:06 +02:00
ERR_FAIL_COND_MSG ( ! dl - > validation . active , " Submitted Draw Lists can no longer be modified. " ) ;
2019-07-27 15:23:24 +02:00
# endif
2019-06-24 21:13:06 +02:00
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 ) ;
2019-06-07 18:07:57 +02:00
}
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 < Variant > & 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
2019-06-10 19:12:24 +02:00
void RenderingDeviceVulkan : : _free_internal ( RID p_id ) {
2019-06-07 18:07:57 +02:00
//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 ;
2019-06-24 21:13:06 +02:00
b . size = index_buffer - > size ;
2019-06-07 18:07:57 +02:00
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 {
2019-06-10 19:12:24 +02:00
ERR_PRINT ( " Attempted to free invalid ID: " + itos ( p_id . get_id ( ) ) ) ;
2019-06-07 18:07:57 +02:00
}
}
2019-06-10 19:12:24 +02:00
void RenderingDeviceVulkan : : free ( RID p_id ) {
2019-06-07 18:07:57 +02:00
_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 ) ;
}
2019-06-24 21:13:06 +02:00
screen_prepared = false ;
2019-06-07 18:07:57 +02:00
}
2019-06-24 21:13:06 +02:00
void RenderingDeviceVulkan : : _free_pending_resources ( int p_frame ) {
2019-06-07 18:07:57 +02:00
//free in dependency usage order, so nothing weird happens
//pipelines
2019-06-24 21:13:06 +02:00
while ( frames [ p_frame ] . pipelines_to_dispose_of . front ( ) ) {
RenderPipeline * pipeline = & frames [ p_frame ] . pipelines_to_dispose_of . front ( ) - > get ( ) ;
2019-06-07 18:07:57 +02:00
vkDestroyPipeline ( device , pipeline - > pipeline , NULL ) ;
2019-06-24 21:13:06 +02:00
frames [ p_frame ] . pipelines_to_dispose_of . pop_front ( ) ;
2019-06-07 18:07:57 +02:00
}
//uniform sets
2019-06-24 21:13:06 +02:00
while ( frames [ p_frame ] . uniform_sets_to_dispose_of . front ( ) ) {
UniformSet * uniform_set = & frames [ p_frame ] . uniform_sets_to_dispose_of . front ( ) - > get ( ) ;
2019-06-07 18:07:57 +02:00
vkFreeDescriptorSets ( device , uniform_set - > pool - > pool , 1 , & uniform_set - > descriptor_set ) ;
_descriptor_pool_free ( uniform_set - > pool_key , uniform_set - > pool ) ;
2019-06-24 21:13:06 +02:00
frames [ p_frame ] . uniform_sets_to_dispose_of . pop_front ( ) ;
2019-06-07 18:07:57 +02:00
}
//buffer views
2019-06-24 21:13:06 +02:00
while ( frames [ p_frame ] . buffer_views_to_dispose_of . front ( ) ) {
VkBufferView buffer_view = frames [ p_frame ] . buffer_views_to_dispose_of . front ( ) - > get ( ) ;
2019-06-07 18:07:57 +02:00
vkDestroyBufferView ( device , buffer_view , NULL ) ;
2019-06-24 21:13:06 +02:00
frames [ p_frame ] . buffer_views_to_dispose_of . pop_front ( ) ;
2019-06-07 18:07:57 +02:00
}
//shaders
2019-06-24 21:13:06 +02:00
while ( frames [ p_frame ] . shaders_to_dispose_of . front ( ) ) {
Shader * shader = & frames [ p_frame ] . shaders_to_dispose_of . front ( ) - > get ( ) ;
2019-06-07 18:07:57 +02:00
//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 ) ;
}
2019-06-24 21:13:06 +02:00
frames [ p_frame ] . shaders_to_dispose_of . pop_front ( ) ;
2019-06-07 18:07:57 +02:00
}
//samplers
2019-06-24 21:13:06 +02:00
while ( frames [ p_frame ] . samplers_to_dispose_of . front ( ) ) {
VkSampler sampler = frames [ p_frame ] . samplers_to_dispose_of . front ( ) - > get ( ) ;
2019-06-07 18:07:57 +02:00
vkDestroySampler ( device , sampler , NULL ) ;
2019-06-24 21:13:06 +02:00
frames [ p_frame ] . samplers_to_dispose_of . pop_front ( ) ;
2019-06-07 18:07:57 +02:00
}
//framebuffers
2019-06-24 21:13:06 +02:00
while ( frames [ p_frame ] . framebuffers_to_dispose_of . front ( ) ) {
Framebuffer * framebuffer = & frames [ p_frame ] . framebuffers_to_dispose_of . front ( ) - > get ( ) ;
2019-06-07 18:07:57 +02:00
for ( Map < Framebuffer : : VersionKey , Framebuffer : : Version > : : 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 ) ;
}
2019-06-24 21:13:06 +02:00
frames [ p_frame ] . framebuffers_to_dispose_of . pop_front ( ) ;
2019-06-07 18:07:57 +02:00
}
//textures
2019-06-24 21:13:06 +02:00
while ( frames [ p_frame ] . textures_to_dispose_of . front ( ) ) {
Texture * texture = & frames [ p_frame ] . textures_to_dispose_of . front ( ) - > get ( ) ;
2019-06-07 18:07:57 +02:00
if ( texture - > bound ) {
WARN_PRINT ( " Deleted a texture while it was bound.. " ) ;
}
vkDestroyImageView ( device , texture - > view , NULL ) ;
2019-06-10 19:12:24 +02:00
if ( texture - > owner . is_null ( ) ) {
2019-06-07 18:07:57 +02:00
//actually owns the image and the allocation too
vmaDestroyImage ( allocator , texture - > image , texture - > allocation ) ;
}
2019-06-24 21:13:06 +02:00
frames [ p_frame ] . textures_to_dispose_of . pop_front ( ) ;
2019-06-07 18:07:57 +02:00
}
//buffers
2019-06-24 21:13:06 +02:00
while ( frames [ p_frame ] . buffers_to_dispose_of . front ( ) ) {
_buffer_free ( & frames [ p_frame ] . buffers_to_dispose_of . front ( ) - > get ( ) ) ;
2019-06-07 18:07:57 +02:00
2019-06-24 21:13:06 +02:00
frames [ p_frame ] . buffers_to_dispose_of . pop_front ( ) ;
2019-06-07 18:07:57 +02:00
}
}
2019-06-24 21:13:06 +02:00
void RenderingDeviceVulkan : : prepare_screen_for_drawing ( ) {
_THREAD_SAFE_METHOD_
context - > prepare_buffers ( ) ;
screen_prepared = true ;
}
2019-06-07 18:07:57 +02:00
void RenderingDeviceVulkan : : advance_frame ( ) {
_THREAD_SAFE_METHOD_
//advance the frame
frame = ( frame + 1 ) % frame_count ;
//erase pending resources
2019-06-24 21:13:06 +02:00
_free_pending_resources ( frame ) ;
2019-06-07 18:07:57 +02:00
//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 ;
}
}
2019-06-26 00:49:52 +02:00
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 ) ;
}
}
2019-06-07 18:07:57 +02:00
void RenderingDeviceVulkan : : initialize ( VulkanContext * p_context ) {
context = p_context ;
device = p_context - > get_device ( ) ;
2019-06-24 21:13:06 +02:00
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.
2019-06-07 18:07:57 +02:00
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 ) ;
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 ;
}
2019-06-24 21:13:06 +02:00
template < class T >
void RenderingDeviceVulkan : : _free_rids ( T & p_owner , const char * p_type ) {
List < RID > owned ;
p_owner . get_owned_list ( & owned ) ;
if ( owned . size ( ) ) {
WARN_PRINT ( itos ( owned . size ( ) ) + " RIDs of type ' " + p_type + " ' were leaked. " ) ;
for ( List < RID > : : Element * E = owned . front ( ) ; E ; E = E - > next ( ) ) {
free ( E - > get ( ) ) ;
}
}
}
2019-07-10 22:44:55 +02:00
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 ;
}
2019-06-07 18:07:57 +02:00
void RenderingDeviceVulkan : : finalize ( ) {
2019-06-24 21:13:06 +02:00
//free all resources
2019-06-26 00:49:52 +02:00
_flush ( false , false ) ;
2019-06-24 21:13:06 +02:00
_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 < RID > 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 < RID > : : Element * E = owned . front ( ) ; E ; ) {
List < RID > : : 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 < RID > : : 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 ) ;
}
2019-06-07 18:07:57 +02:00
memdelete_arr ( frames ) ;
2019-06-24 21:13:06 +02:00
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 ( ) ) ;
2019-06-07 18:07:57 +02:00
}
RenderingDeviceVulkan : : RenderingDeviceVulkan ( ) {
2019-06-24 21:13:06 +02:00
screen_prepared = false ;
2019-06-07 18:07:57 +02:00
}