diff options
author | Juan Linietsky <reduzio@gmail.com> | 2019-07-27 10:23:24 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2020-02-11 11:53:29 +0100 |
commit | 0586e184490fd132f99acb1a67c788959cfdbade (patch) | |
tree | 194972ba608705445c9ee084f908e183a9792760 /servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp | |
parent | 8bbbb973361f367a4888629c571fb6f43581269d (diff) |
Custom material support seems complete.
Diffstat (limited to 'servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp')
-rw-r--r-- | servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp | 2217 |
1 files changed, 2217 insertions, 0 deletions
diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp new file mode 100644 index 0000000000..fef3418d53 --- /dev/null +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp @@ -0,0 +1,2217 @@ +#include "rasterizer_storage_rd.h" +#include "core/engine.h" +#include "core/project_settings.h" +#include "servers/visual/shader_language.h" + +Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) { + + Ref<Image> image = p_image->duplicate(); + + switch (p_image->get_format()) { + case Image::FORMAT_L8: { + r_format.format = RD::DATA_FORMAT_R8_UNORM; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; //luminance + case Image::FORMAT_LA8: { + r_format.format = RD::DATA_FORMAT_R8G8_UNORM; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_G; + } break; //luminance-alpha + case Image::FORMAT_R8: { + r_format.format = RD::DATA_FORMAT_R8_UNORM; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_RG8: { + r_format.format = RD::DATA_FORMAT_R8G8_UNORM; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_RGB8: { + //this format is not mandatory for specification, check if supported first + if (false && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R8G8B8_UNORM, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT) && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R8G8B8_SRGB, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_R8G8B8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8_SRGB; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; + case Image::FORMAT_RGBA8: { + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case Image::FORMAT_RGBA4444: { + r_format.format = RD::DATA_FORMAT_B4G4R4A4_UNORM_PACK16; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_B; //needs swizzle + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case Image::FORMAT_RGBA5551: { + r_format.format = RD::DATA_FORMAT_A1R5G5B5_UNORM_PACK16; +#warning TODO needs something in Texture to convert to this format internally + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case Image::FORMAT_RF: { + r_format.format = RD::DATA_FORMAT_R32_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; //float + case Image::FORMAT_RGF: { + r_format.format = RD::DATA_FORMAT_R32G32_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_RGBF: { + //this format is not mandatory for specification, check if supported first + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R32G32B32_SFLOAT, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + image->convert(Image::FORMAT_RGBAF); + } + + r_format.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_RGBAF: { + r_format.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + + } break; + case Image::FORMAT_RH: { + r_format.format = RD::DATA_FORMAT_R16_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; //half float + case Image::FORMAT_RGH: { + r_format.format = RD::DATA_FORMAT_R16G16_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; + case Image::FORMAT_RGBH: { + //this format is not mandatory for specification, check if supported first + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_R16G16B16_SFLOAT, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_R16G16B16_SFLOAT; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + image->convert(Image::FORMAT_RGBAH); + } + + r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_RGBAH: { + r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + + } break; + case Image::FORMAT_RGBE9995: { + r_format.format = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32; +#warning TODO need to make a function in Image to swap bits for this + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_IDENTITY; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_IDENTITY; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_IDENTITY; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_IDENTITY; + } break; + case Image::FORMAT_DXT1: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_BC1_RGBA_SRGB_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; //s3tc bc1 + case Image::FORMAT_DXT3: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC2_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC2_UNORM_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_BC2_SRGB_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + + } break; //bc2 + case Image::FORMAT_DXT5: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC3_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC3_UNORM_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_BC3_SRGB_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; //bc3 + case Image::FORMAT_RGTC_R: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC4_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC4_UNORM_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8_UNORM; + image->decompress(); + image->convert(Image::FORMAT_R8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; + case Image::FORMAT_RGTC_RG: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC5_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC5_UNORM_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8_UNORM; + image->decompress(); + image->convert(Image::FORMAT_RG8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; + case Image::FORMAT_BPTC_RGBA: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC7_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC7_UNORM_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_BC7_SRGB_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + + } break; //btpc bc7 + case Image::FORMAT_BPTC_RGBF: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC6H_SFLOAT_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC6H_SFLOAT_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + image->decompress(); + image->convert(Image::FORMAT_RGBAH); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; //float bc6h + case Image::FORMAT_BPTC_RGBFU: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC6H_UFLOAT_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_BC6H_UFLOAT_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + image->decompress(); + image->convert(Image::FORMAT_RGBAH); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; //unsigned float bc6hu + case Image::FORMAT_PVRTC2: { + //this is not properly supported by MoltekVK it seems, so best to use ETC2 + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; + r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; //pvrtc + case Image::FORMAT_PVRTC2A: { + //this is not properly supported by MoltekVK it seems, so best to use ETC2 + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; + r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case Image::FORMAT_PVRTC4: { + //this is not properly supported by MoltekVK it seems, so best to use ETC2 + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; + r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_PVRTC4A: { + //this is not properly supported by MoltekVK it seems, so best to use ETC2 + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; + r_format.format_srgb = RD::DATA_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case Image::FORMAT_ETC2_R11: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_EAC_R11_UNORM_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8_UNORM; + image->decompress(); + image->convert(Image::FORMAT_R8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; //etc2 + case Image::FORMAT_ETC2_R11S: { + + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11_SNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_EAC_R11_SNORM_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8_SNORM; + image->decompress(); + image->convert(Image::FORMAT_R8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; //signed: {} break; NOT srgb. + case Image::FORMAT_ETC2_RG11: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11G11_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_EAC_R11G11_UNORM_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8_UNORM; + image->decompress(); + image->convert(Image::FORMAT_RG8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_ETC2_RG11S: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_EAC_R11G11_SNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_EAC_R11G11_SNORM_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8_SNORM; + image->decompress(); + image->convert(Image::FORMAT_RG8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } break; + case Image::FORMAT_ETC: + case Image::FORMAT_ETC2_RGB8: { + //ETC2 is backwards compatible with ETC1, and all modern platforms support it + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + + } break; + case Image::FORMAT_ETC2_RGBA8: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case Image::FORMAT_ETC2_RGB8A1: { + + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK; + } else { + //not supported, reconvert + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->decompress(); + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + default: { + } + } + + return image; +} + +RID RasterizerStorageRD::texture_2d_create(const Ref<Image> &p_image) { + ERR_FAIL_COND_V(p_image.is_null(), RID()); + ERR_FAIL_COND_V(p_image->empty(), RID()); + + TextureToRDFormat ret_format; + Ref<Image> image = _validate_texture_format(p_image, ret_format); + + Texture texture; + + texture.type = Texture::TYPE_2D; + + texture.width = p_image->get_width(); + texture.height = p_image->get_height(); + texture.layers = 1; + texture.mipmaps = p_image->get_mipmap_count() + 1; + texture.depth = 1; + texture.format = p_image->get_format(); + texture.validated_format = image->get_format(); + + texture.rd_type = RD::TEXTURE_TYPE_2D; + texture.rd_format = ret_format.format; + texture.rd_format_srgb = ret_format.format_srgb; + + RD::TextureFormat rd_format; + RD::TextureView rd_view; + { //attempt register + rd_format.format = texture.rd_format; + rd_format.width = texture.width; + rd_format.height = texture.height; + rd_format.depth = 1; + rd_format.array_layers = 1; + rd_format.mipmaps = texture.mipmaps; + rd_format.type = texture.rd_type; + rd_format.samples = RD::TEXTURE_SAMPLES_1; + rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { + rd_format.shareable_formats.push_back(texture.rd_format); + rd_format.shareable_formats.push_back(texture.rd_format_srgb); + } + } + { + rd_view.swizzle_r = ret_format.swizzle_r; + rd_view.swizzle_g = ret_format.swizzle_g; + rd_view.swizzle_b = ret_format.swizzle_b; + rd_view.swizzle_a = ret_format.swizzle_a; + } + PoolVector<uint8_t> data = image->get_data(); //use image data + Vector<PoolVector<uint8_t> > data_slices; + data_slices.push_back(data); + texture.rd_texture = RD::get_singleton()->texture_create(rd_format, rd_view, data_slices); + ERR_FAIL_COND_V(texture.rd_texture.is_null(), RID()); + if (texture.rd_format_srgb != RD::DATA_FORMAT_MAX) { + rd_view.format_override = texture.rd_format_srgb; + texture.rd_texture_srgb = RD::get_singleton()->texture_create_shared(rd_view, texture.rd_texture); + if (texture.rd_texture_srgb.is_null()) { + RD::get_singleton()->free(texture.rd_texture); + ERR_FAIL_COND_V(texture.rd_texture_srgb.is_null(), RID()); + } + } + + //used for 2D, overridable + texture.width_2d = texture.width; + texture.height_2d = texture.height; + texture.is_render_target = false; + texture.rd_view = rd_view; + texture.is_proxy = false; + +#warning texture owner needs a spinlock to make this really callable from any thread + return texture_owner.make_rid(texture); +} + +RID RasterizerStorageRD::texture_2d_layered_create(const Vector<Ref<Image> > &p_layers, VS::TextureLayeredType p_layered_type) { + + return RID(); +} +RID RasterizerStorageRD::texture_3d_create(const Vector<Ref<Image> > &p_slices) { + + return RID(); +} + +RID RasterizerStorageRD::texture_proxy_create(RID p_base) { + Texture *tex = texture_owner.getornull(p_base); + ERR_FAIL_COND_V(!tex, RID()); + Texture proxy_tex = *tex; + + proxy_tex.rd_view.format_override = tex->rd_format; + proxy_tex.rd_texture = RD::get_singleton()->texture_create_shared(proxy_tex.rd_view, tex->rd_texture); + if (proxy_tex.rd_texture_srgb.is_valid()) { + proxy_tex.rd_view.format_override = tex->rd_format_srgb; + proxy_tex.rd_texture_srgb = RD::get_singleton()->texture_create_shared(proxy_tex.rd_view, tex->rd_texture); + } + proxy_tex.proxy_to = p_base; + proxy_tex.is_render_target = false; + proxy_tex.is_proxy = true; + proxy_tex.proxies.clear(); + + RID rid = texture_owner.make_rid(proxy_tex); + + tex->proxies.push_back(rid); + return rid; +} + +void RasterizerStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate) { + + ERR_FAIL_COND(p_image.is_null() || p_image->empty()); + + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND(!tex); + ERR_FAIL_COND(tex->is_render_target); + ERR_FAIL_COND(p_image->get_width() != tex->width || p_image->get_height() != tex->height); + ERR_FAIL_COND(p_image->get_format() != tex->format); + + if (tex->type == Texture::TYPE_LAYERED) { + ERR_FAIL_INDEX(p_layer, tex->layers); + } + +#ifdef TOOLS_ENABLED + tex->image_cache_2d.unref(); +#endif + TextureToRDFormat f; + Ref<Image> validated = _validate_texture_format(p_image, f); + + RD::get_singleton()->texture_update(tex->rd_texture, p_layer, validated->get_data(), !p_immediate); +} + +void RasterizerStorageRD::texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer) { + _texture_2d_update(p_texture, p_image, p_layer, true); +} +void RasterizerStorageRD::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) { + _texture_2d_update(p_texture, p_image, p_layer, false); +} +void RasterizerStorageRD::texture_3d_update(RID p_texture, const Ref<Image> &p_image, int p_depth, int p_mipmap) { +} + +void RasterizerStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) { + + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND(!tex); + ERR_FAIL_COND(!tex->is_proxy); + Texture *proxy_to = texture_owner.getornull(p_proxy_to); + ERR_FAIL_COND(!proxy_to); + ERR_FAIL_COND(proxy_to->is_proxy); + + if (tex->proxy_to.is_valid()) { + //unlink proxy + if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) { + RD::get_singleton()->free(tex->rd_texture); + tex->rd_texture = RID(); + } + if (RD::get_singleton()->texture_is_valid(tex->rd_texture_srgb)) { + RD::get_singleton()->free(tex->rd_texture_srgb); + tex->rd_texture_srgb = RID(); + } + Texture *prev_tex = texture_owner.getornull(tex->proxy_to); + ERR_FAIL_COND(!prev_tex); + prev_tex->proxies.erase(p_texture); + } + + *tex = *proxy_to; + + tex->proxy_to = p_proxy_to; + tex->is_render_target = false; + tex->is_proxy = true; + tex->proxies.clear(); + proxy_to->proxies.push_back(p_texture); + + tex->rd_view.format_override = tex->rd_format; + tex->rd_texture = RD::get_singleton()->texture_create_shared(tex->rd_view, proxy_to->rd_texture); + if (tex->rd_texture_srgb.is_valid()) { + tex->rd_view.format_override = tex->rd_format_srgb; + tex->rd_texture_srgb = RD::get_singleton()->texture_create_shared(tex->rd_view, proxy_to->rd_texture); + } +} + +//these two APIs can be used together or in combination with the others. +RID RasterizerStorageRD::texture_2d_placeholder_create() { + + //this could be better optimized to reuse an existing image , done this way + //for now to get it working + Ref<Image> image; + image.instance(); + image->create(4, 4, false, Image::FORMAT_RGBA8); + image->lock(); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + image->set_pixel(i, j, Color(1, 0, 1, 1)); + } + } + image->unlock(); + + return texture_2d_create(image); +} +RID RasterizerStorageRD::texture_2d_layered_placeholder_create() { + + return RID(); +} +RID RasterizerStorageRD::texture_3d_placeholder_create() { + + return RID(); +} + +Ref<Image> RasterizerStorageRD::texture_2d_get(RID p_texture) const { + + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND_V(!tex, Ref<Image>()); + +#ifdef TOOLS_ENABLED + if (tex->image_cache_2d.is_valid()) { + return tex->image_cache_2d; + } +#endif + PoolVector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0); + ERR_FAIL_COND_V(data.size() == 0, Ref<Image>()); + Ref<Image> image; + image.instance(); + image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data); + ERR_FAIL_COND_V(image->empty(), Ref<Image>()); + if (tex->format != tex->validated_format) { + image->convert(tex->format); + } + +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + tex->image_cache_2d = image; + } +#endif + + return image; +} +Ref<Image> RasterizerStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) const { + + return Ref<Image>(); +} +Ref<Image> RasterizerStorageRD::texture_3d_slice_get(RID p_texture, int p_depth, int p_mipmap) const { + + return Ref<Image>(); +} + +void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) { + + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND(!tex); + ERR_FAIL_COND(tex->proxy_to.is_valid()); //cant replace proxy + Texture *by_tex = texture_owner.getornull(p_by_texture); + ERR_FAIL_COND(!by_tex); + ERR_FAIL_COND(by_tex->proxy_to.is_valid()); //cant replace proxy + + if (tex == by_tex) { + return; + } + + if (tex->rd_texture_srgb.is_valid()) { + RD::get_singleton()->free(tex->rd_texture_srgb); + } + RD::get_singleton()->free(tex->rd_texture); + + Vector<RID> proxies_to_update = tex->proxies; + Vector<RID> proxies_to_redirect = by_tex->proxies; + + *tex = *by_tex; + + tex->proxies = proxies_to_update; //restore proxies, so they can be updated + + for (int i = 0; i < proxies_to_update.size(); i++) { + texture_proxy_update(proxies_to_update[i], p_texture); + } + for (int i = 0; i < proxies_to_redirect.size(); i++) { + texture_proxy_update(proxies_to_redirect[i], p_texture); + } + //delete last, so proxies can be updated + texture_owner.free(p_by_texture); +} +void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, int p_height) { + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND(!tex); + ERR_FAIL_COND(tex->type != Texture::TYPE_2D); + tex->width_2d = p_width; + tex->height_2d = p_height; +} + +void RasterizerStorageRD::texture_set_path(RID p_texture, const String &p_path) { +} +String RasterizerStorageRD::texture_get_path(RID p_texture) const { + return String(); +} + +void RasterizerStorageRD::texture_set_detect_3d_callback(RID p_texture, VS::TextureDetectCallback p_callback, void *p_userdata) { +} +void RasterizerStorageRD::texture_set_detect_normal_callback(RID p_texture, VS::TextureDetectCallback p_callback, void *p_userdata) { +} +void RasterizerStorageRD::texture_set_detect_roughness_callback(RID p_texture, VS::TextureDetectRoughnessCallback p_callback, void *p_userdata) { +} +void RasterizerStorageRD::texture_debug_usage(List<VS::TextureInfo> *r_info) { +} + +void RasterizerStorageRD::texture_set_proxy(RID p_proxy, RID p_base) { +} +void RasterizerStorageRD::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) { +} + +Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) { + return texture_2d_get_size(p_proxy); +} + +/* SHADER API */ + +RID RasterizerStorageRD::shader_create() { + + Shader shader; + shader.data = NULL; + shader.type = SHADER_TYPE_MAX; + + return shader_owner.make_rid(shader); +} + +void RasterizerStorageRD::shader_set_code(RID p_shader, const String &p_code) { + Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND(!shader); + + shader->code = p_code; + String mode_string = ShaderLanguage::get_shader_type(p_code); + + ShaderType new_type; + if (mode_string == "canvas_item") + new_type = SHADER_TYPE_2D; + else if (mode_string == "particles") + new_type = SHADER_TYPE_PARTICLES; + else if (mode_string == "spatial") + new_type = SHADER_TYPE_3D; + else + new_type = SHADER_TYPE_MAX; + + if (new_type != shader->type) { + if (shader->data) { + memdelete(shader->data); + shader->data = NULL; + } + + for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) { + + Material *material = E->get(); + material->shader_type = new_type; + if (material->data) { + memdelete(material->data); + material->data = NULL; + } + } + + shader->type = new_type; + + if (new_type < SHADER_TYPE_MAX && shader_data_request_func[new_type]) { + shader->data = shader_data_request_func[new_type](); + } else { + shader->type = SHADER_TYPE_MAX; //invalid + } + + for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) { + Material *material = E->get(); + if (shader->data) { + material->data = material_data_request_func[new_type](shader->data); + material->data->set_next_pass(material->next_pass); + material->data->set_render_priority(material->priority); + } + material->shader_type = new_type; + } + } + + if (shader->data) { + shader->data->set_code(p_code); + } + + for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) { + Material *material = E->get(); + material->instance_dependency.instance_notify_changed(false, true); + _material_queue_update(material, true, true); + } +} + +String RasterizerStorageRD::shader_get_code(RID p_shader) const { + Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, String()); + return shader->code; +} +void RasterizerStorageRD::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const { + + Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND(!shader); + if (shader->data) { + return shader->data->get_param_list(p_param_list); + } +} + +void RasterizerStorageRD::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) { + + Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND(!shader); + + if (p_texture.is_valid() && texture_owner.owns(p_texture)) { + shader->default_texture_parameter[p_name] = p_texture; + } else { + shader->default_texture_parameter.erase(p_name); + } + + for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) { + Material *material = E->get(); + _material_queue_update(material, false, true); + } +} + +RID RasterizerStorageRD::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const { + Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, RID()); + if (shader->default_texture_parameter.has(p_name)) { + return shader->default_texture_parameter[p_name]; + } + + return RID(); +} +Variant RasterizerStorageRD::shader_get_param_default(RID p_shader, const StringName &p_param) const { + Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND_V(!shader, Variant()); + if (shader->data) { + return shader->data->get_default_parameter(p_param); + } + return Variant(); +} +void RasterizerStorageRD::shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function) { + ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX); + shader_data_request_func[p_shader_type] = p_function; +} + +/* COMMON MATERIAL API */ + +RID RasterizerStorageRD::material_create() { + Material material; + material.data = NULL; + material.shader = NULL; + material.shader_type = SHADER_TYPE_MAX; + material.update_next = NULL; + material.update_requested = false; + material.uniform_dirty = false; + material.texture_dirty = false; + material.priority = 0; + RID id = material_owner.make_rid(material); + { + Material *material_ptr = material_owner.getornull(id); + material_ptr->self = id; + } + return id; +} + +void RasterizerStorageRD::_material_queue_update(Material *material, bool p_uniform, bool p_texture) { + if (material->update_requested) { + return; + } + + material->update_next = material_update_list; + material_update_list = material; + material->update_requested = true; + material->uniform_dirty = p_uniform; + material->texture_dirty = p_texture; +} + +void RasterizerStorageRD::material_set_shader(RID p_material, RID p_shader) { + + Material *material = material_owner.getornull(p_material); + ERR_FAIL_COND(!material); + + if (material->data) { + memdelete(material->data); + material->data = NULL; + } + + if (material->shader) { + material->shader->owners.erase(material); + material->shader = NULL; + material->shader_type = SHADER_TYPE_MAX; + } + + if (p_shader.is_null()) { + material->instance_dependency.instance_notify_changed(false, true); + return; + } + + Shader *shader = shader_owner.getornull(p_shader); + ERR_FAIL_COND(!shader); + material->shader = shader; + material->shader_type = shader->type; + shader->owners.insert(material); + + if (shader->type == SHADER_TYPE_MAX) { + return; + } + + ERR_FAIL_COND(shader->data == NULL); + + material->data = material_data_request_func[shader->type](shader->data); + material->data->set_next_pass(material->next_pass); + material->data->set_render_priority(material->priority); + //updating happens later + material->instance_dependency.instance_notify_changed(false, true); + _material_queue_update(material, true, true); +} + +void RasterizerStorageRD::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) { + + Material *material = material_owner.getornull(p_material); + ERR_FAIL_COND(!material); + + if (p_value.get_type() == Variant::NIL) { + material->params.erase(p_param); + } else { + material->params[p_param] = p_value; + } + + if (material->shader && material->shader->data) { //shader is valid + bool is_texture = material->shader->data->is_param_texture(p_param); + _material_queue_update(material, !is_texture, is_texture); + } else { + _material_queue_update(material, true, true); + } +} + +Variant RasterizerStorageRD::material_get_param(RID p_material, const StringName &p_param) const { + Material *material = material_owner.getornull(p_material); + ERR_FAIL_COND_V(!material, Variant()); + if (material->params.has(p_param)) { + return material->params[p_param]; + } else { + return Variant(); + } +} + +void RasterizerStorageRD::material_set_next_pass(RID p_material, RID p_next_material) { + Material *material = material_owner.getornull(p_material); + ERR_FAIL_COND(!material); + + if (material->next_pass == p_next_material) { + return; + } + + material->next_pass = p_next_material; + if (material->data) { + material->data->set_next_pass(p_next_material); + } + + material->instance_dependency.instance_notify_changed(false, true); +} +void RasterizerStorageRD::material_set_render_priority(RID p_material, int priority) { + Material *material = material_owner.getornull(p_material); + ERR_FAIL_COND(!material); + material->priority = priority; + if (material->data) { + material->data->set_render_priority(priority); + } +} + +bool RasterizerStorageRD::material_is_animated(RID p_material) { + Material *material = material_owner.getornull(p_material); + ERR_FAIL_COND_V(!material, false); + if (material->shader && material->shader->data) { + if (material->shader->data->is_animated()) { + return true; + } else if (material->next_pass.is_valid()) { + return material_is_animated(material->next_pass); + } + } + return false; //by default nothing is animated +} +bool RasterizerStorageRD::material_casts_shadows(RID p_material) { + Material *material = material_owner.getornull(p_material); + ERR_FAIL_COND_V(!material, true); + if (material->shader && material->shader->data) { + if (material->shader->data->casts_shadows()) { + return true; + } else if (material->next_pass.is_valid()) { + return material_casts_shadows(material->next_pass); + } + } + return true; //by default everything casts shadows +} + +void RasterizerStorageRD::material_update_dependency(RID p_material, RasterizerScene::InstanceBase *p_instance) { + Material *material = material_owner.getornull(p_material); + ERR_FAIL_COND(!material); + p_instance->update_dependency(&material->instance_dependency); + if (material->next_pass.is_valid()) { + material_update_dependency(material->next_pass, p_instance); + } +} + +void RasterizerStorageRD::material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function) { + ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX); + material_data_request_func[p_shader_type] = p_function; +} + +_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant &value, uint8_t *data, bool p_linear_color) { + switch (type) { + case ShaderLanguage::TYPE_BOOL: { + + bool v = value; + + uint32_t *gui = (uint32_t *)data; + *gui = v ? 1 : 0; + } break; + case ShaderLanguage::TYPE_BVEC2: { + + int v = value; + uint32_t *gui = (uint32_t *)data; + gui[0] = v & 1 ? 1 : 0; + gui[1] = v & 2 ? 1 : 0; + + } break; + case ShaderLanguage::TYPE_BVEC3: { + + int v = value; + uint32_t *gui = (uint32_t *)data; + gui[0] = (v & 1) ? 1 : 0; + gui[1] = (v & 2) ? 1 : 0; + gui[2] = (v & 4) ? 1 : 0; + + } break; + case ShaderLanguage::TYPE_BVEC4: { + + int v = value; + uint32_t *gui = (uint32_t *)data; + gui[0] = (v & 1) ? 1 : 0; + gui[1] = (v & 2) ? 1 : 0; + gui[2] = (v & 4) ? 1 : 0; + gui[3] = (v & 8) ? 1 : 0; + + } break; + case ShaderLanguage::TYPE_INT: { + + int v = value; + int32_t *gui = (int32_t *)data; + gui[0] = v; + + } break; + case ShaderLanguage::TYPE_IVEC2: { + + PoolVector<int> iv = value; + int s = iv.size(); + int32_t *gui = (int32_t *)data; + + PoolVector<int>::Read r = iv.read(); + + for (int i = 0; i < 2; i++) { + if (i < s) + gui[i] = r[i]; + else + gui[i] = 0; + } + + } break; + case ShaderLanguage::TYPE_IVEC3: { + + PoolVector<int> iv = value; + int s = iv.size(); + int32_t *gui = (int32_t *)data; + + PoolVector<int>::Read r = iv.read(); + + for (int i = 0; i < 3; i++) { + if (i < s) + gui[i] = r[i]; + else + gui[i] = 0; + } + } break; + case ShaderLanguage::TYPE_IVEC4: { + + PoolVector<int> iv = value; + int s = iv.size(); + int32_t *gui = (int32_t *)data; + + PoolVector<int>::Read r = iv.read(); + + for (int i = 0; i < 4; i++) { + if (i < s) + gui[i] = r[i]; + else + gui[i] = 0; + } + } break; + case ShaderLanguage::TYPE_UINT: { + + int v = value; + uint32_t *gui = (uint32_t *)data; + gui[0] = v; + + } break; + case ShaderLanguage::TYPE_UVEC2: { + + PoolVector<int> iv = value; + int s = iv.size(); + uint32_t *gui = (uint32_t *)data; + + PoolVector<int>::Read r = iv.read(); + + for (int i = 0; i < 2; i++) { + if (i < s) + gui[i] = r[i]; + else + gui[i] = 0; + } + } break; + case ShaderLanguage::TYPE_UVEC3: { + PoolVector<int> iv = value; + int s = iv.size(); + uint32_t *gui = (uint32_t *)data; + + PoolVector<int>::Read r = iv.read(); + + for (int i = 0; i < 3; i++) { + if (i < s) + gui[i] = r[i]; + else + gui[i] = 0; + } + + } break; + case ShaderLanguage::TYPE_UVEC4: { + PoolVector<int> iv = value; + int s = iv.size(); + uint32_t *gui = (uint32_t *)data; + + PoolVector<int>::Read r = iv.read(); + + for (int i = 0; i < 4; i++) { + if (i < s) + gui[i] = r[i]; + else + gui[i] = 0; + } + } break; + case ShaderLanguage::TYPE_FLOAT: { + float v = value; + float *gui = (float *)data; + gui[0] = v; + + } break; + case ShaderLanguage::TYPE_VEC2: { + Vector2 v = value; + float *gui = (float *)data; + gui[0] = v.x; + gui[1] = v.y; + + } break; + case ShaderLanguage::TYPE_VEC3: { + Vector3 v = value; + float *gui = (float *)data; + gui[0] = v.x; + gui[1] = v.y; + gui[2] = v.z; + + } break; + case ShaderLanguage::TYPE_VEC4: { + + float *gui = (float *)data; + + if (value.get_type() == Variant::COLOR) { + Color v = value; + + if (p_linear_color) { + v = v.to_linear(); + } + + gui[0] = v.r; + gui[1] = v.g; + gui[2] = v.b; + gui[3] = v.a; + } else if (value.get_type() == Variant::RECT2) { + Rect2 v = value; + + gui[0] = v.position.x; + gui[1] = v.position.y; + gui[2] = v.size.x; + gui[3] = v.size.y; + } else if (value.get_type() == Variant::QUAT) { + Quat v = value; + + gui[0] = v.x; + gui[1] = v.y; + gui[2] = v.z; + gui[3] = v.w; + } else { + Plane v = value; + + gui[0] = v.normal.x; + gui[1] = v.normal.y; + gui[2] = v.normal.z; + gui[3] = v.d; + } + } break; + case ShaderLanguage::TYPE_MAT2: { + Transform2D v = value; + float *gui = (float *)data; + + //in std140 members of mat2 are treated as vec4s + gui[0] = v.elements[0][0]; + gui[1] = v.elements[0][1]; + gui[2] = 0; + gui[3] = 0; + gui[4] = v.elements[1][0]; + gui[5] = v.elements[1][1]; + gui[6] = 0; + gui[7] = 0; + } break; + case ShaderLanguage::TYPE_MAT3: { + + Basis v = value; + float *gui = (float *)data; + + gui[0] = v.elements[0][0]; + gui[1] = v.elements[1][0]; + gui[2] = v.elements[2][0]; + gui[3] = 0; + gui[4] = v.elements[0][1]; + gui[5] = v.elements[1][1]; + gui[6] = v.elements[2][1]; + gui[7] = 0; + gui[8] = v.elements[0][2]; + gui[9] = v.elements[1][2]; + gui[10] = v.elements[2][2]; + gui[11] = 0; + } break; + case ShaderLanguage::TYPE_MAT4: { + + Transform v = value; + float *gui = (float *)data; + + gui[0] = v.basis.elements[0][0]; + gui[1] = v.basis.elements[1][0]; + gui[2] = v.basis.elements[2][0]; + gui[3] = 0; + gui[4] = v.basis.elements[0][1]; + gui[5] = v.basis.elements[1][1]; + gui[6] = v.basis.elements[2][1]; + gui[7] = 0; + gui[8] = v.basis.elements[0][2]; + gui[9] = v.basis.elements[1][2]; + gui[10] = v.basis.elements[2][2]; + gui[11] = 0; + gui[12] = v.origin.x; + gui[13] = v.origin.y; + gui[14] = v.origin.z; + gui[15] = 1; + } break; + default: { + } + } +} + +_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::ConstantNode::Value> &value, uint8_t *data) { + + switch (type) { + case ShaderLanguage::TYPE_BOOL: { + + uint32_t *gui = (uint32_t *)data; + *gui = value[0].boolean ? 1 : 0; + } break; + case ShaderLanguage::TYPE_BVEC2: { + + uint32_t *gui = (uint32_t *)data; + gui[0] = value[0].boolean ? 1 : 0; + gui[1] = value[1].boolean ? 1 : 0; + + } break; + case ShaderLanguage::TYPE_BVEC3: { + + uint32_t *gui = (uint32_t *)data; + gui[0] = value[0].boolean ? 1 : 0; + gui[1] = value[1].boolean ? 1 : 0; + gui[2] = value[2].boolean ? 1 : 0; + + } break; + case ShaderLanguage::TYPE_BVEC4: { + + uint32_t *gui = (uint32_t *)data; + gui[0] = value[0].boolean ? 1 : 0; + gui[1] = value[1].boolean ? 1 : 0; + gui[2] = value[2].boolean ? 1 : 0; + gui[3] = value[3].boolean ? 1 : 0; + + } break; + case ShaderLanguage::TYPE_INT: { + + int32_t *gui = (int32_t *)data; + gui[0] = value[0].sint; + + } break; + case ShaderLanguage::TYPE_IVEC2: { + + int32_t *gui = (int32_t *)data; + + for (int i = 0; i < 2; i++) { + gui[i] = value[i].sint; + } + + } break; + case ShaderLanguage::TYPE_IVEC3: { + + int32_t *gui = (int32_t *)data; + + for (int i = 0; i < 3; i++) { + gui[i] = value[i].sint; + } + + } break; + case ShaderLanguage::TYPE_IVEC4: { + + int32_t *gui = (int32_t *)data; + + for (int i = 0; i < 4; i++) { + gui[i] = value[i].sint; + } + + } break; + case ShaderLanguage::TYPE_UINT: { + + uint32_t *gui = (uint32_t *)data; + gui[0] = value[0].uint; + + } break; + case ShaderLanguage::TYPE_UVEC2: { + + int32_t *gui = (int32_t *)data; + + for (int i = 0; i < 2; i++) { + gui[i] = value[i].uint; + } + } break; + case ShaderLanguage::TYPE_UVEC3: { + int32_t *gui = (int32_t *)data; + + for (int i = 0; i < 3; i++) { + gui[i] = value[i].uint; + } + + } break; + case ShaderLanguage::TYPE_UVEC4: { + int32_t *gui = (int32_t *)data; + + for (int i = 0; i < 4; i++) { + gui[i] = value[i].uint; + } + } break; + case ShaderLanguage::TYPE_FLOAT: { + + float *gui = (float *)data; + gui[0] = value[0].real; + + } break; + case ShaderLanguage::TYPE_VEC2: { + + float *gui = (float *)data; + + for (int i = 0; i < 2; i++) { + gui[i] = value[i].real; + } + + } break; + case ShaderLanguage::TYPE_VEC3: { + + float *gui = (float *)data; + + for (int i = 0; i < 3; i++) { + gui[i] = value[i].real; + } + + } break; + case ShaderLanguage::TYPE_VEC4: { + + float *gui = (float *)data; + + for (int i = 0; i < 4; i++) { + gui[i] = value[i].real; + } + } break; + case ShaderLanguage::TYPE_MAT2: { + float *gui = (float *)data; + + //in std140 members of mat2 are treated as vec4s + gui[0] = value[0].real; + gui[1] = value[1].real; + gui[2] = 0; + gui[3] = 0; + gui[4] = value[2].real; + gui[5] = value[3].real; + gui[6] = 0; + gui[7] = 0; + } break; + case ShaderLanguage::TYPE_MAT3: { + + float *gui = (float *)data; + + gui[0] = value[0].real; + gui[1] = value[1].real; + gui[2] = value[2].real; + gui[3] = 0; + gui[4] = value[3].real; + gui[5] = value[4].real; + gui[6] = value[5].real; + gui[7] = 0; + gui[8] = value[6].real; + gui[9] = value[7].real; + gui[10] = value[8].real; + gui[11] = 0; + } break; + case ShaderLanguage::TYPE_MAT4: { + + float *gui = (float *)data; + + for (int i = 0; i < 16; i++) { + gui[i] = value[i].real; + } + } break; + default: { + } + } +} + +_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, uint8_t *data) { + + switch (type) { + + case ShaderLanguage::TYPE_BOOL: + case ShaderLanguage::TYPE_INT: + case ShaderLanguage::TYPE_UINT: + case ShaderLanguage::TYPE_FLOAT: { + zeromem(data, 4); + } break; + case ShaderLanguage::TYPE_BVEC2: + case ShaderLanguage::TYPE_IVEC2: + case ShaderLanguage::TYPE_UVEC2: + case ShaderLanguage::TYPE_VEC2: { + zeromem(data, 8); + } break; + case ShaderLanguage::TYPE_BVEC3: + case ShaderLanguage::TYPE_IVEC3: + case ShaderLanguage::TYPE_UVEC3: + case ShaderLanguage::TYPE_VEC3: + case ShaderLanguage::TYPE_BVEC4: + case ShaderLanguage::TYPE_IVEC4: + case ShaderLanguage::TYPE_UVEC4: + case ShaderLanguage::TYPE_VEC4: { + + zeromem(data, 16); + } break; + case ShaderLanguage::TYPE_MAT2: { + + zeromem(data, 32); + } break; + case ShaderLanguage::TYPE_MAT3: { + + zeromem(data, 48); + } break; + case ShaderLanguage::TYPE_MAT4: { + zeromem(data, 64); + } break; + + default: { + } + } +} + +void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) { + + for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = p_uniforms.front(); E; E = E->next()) { + + if (E->get().order < 0) + continue; // texture, does not go here + + //regular uniform + uint32_t offset = p_uniform_offsets[E->get().order]; +#ifdef DEBUG_ENABLED + uint32_t size = ShaderLanguage::get_type_size(E->get().type); + ERR_CONTINUE(offset + size > p_buffer_size); +#endif + uint8_t *data = &p_buffer[offset]; + const Map<StringName, Variant>::Element *V = p_parameters.find(E->key()); + + if (V) { + //user provided + _fill_std140_variant_ubo_value(E->get().type, V->get(), data, p_use_linear_color); + + } else if (E->get().default_value.size()) { + //default value + _fill_std140_ubo_value(E->get().type, E->get().default_value, data); + //value=E->get().default_value; + } else { + //zero because it was not provided + if (E->get().type == ShaderLanguage::TYPE_VEC4 && E->get().hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { + //colors must be set as black, with alpha as 1.0 + _fill_std140_variant_ubo_value(E->get().type, Color(0, 0, 0, 1), data, p_use_linear_color); + } else { + //else just zero it out + _fill_std140_ubo_empty(E->get().type, data); + } + } + } +} + +void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures) { + + RasterizerStorageRD *singleton = (RasterizerStorageRD *)RasterizerStorage::base_singleton; + + for (int i = 0; i < p_texture_uniforms.size(); i++) { + + const StringName &uniform_name = p_texture_uniforms[i].name; + + RID texture; + + const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name); + if (V) { + texture = V->get(); + } + + if (!texture.is_valid()) { + const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name); + if (W) { + texture = W->get(); + } + } + + RID rd_texture; + + if (texture.is_null()) { + //check default usage + switch (p_texture_uniforms[i].hint) { + case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: + case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_BLACK); + } break; + case ShaderLanguage::ShaderNode::Uniform::HINT_NONE: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL); + } break; + case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO); + } break; + default: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); + } break; + } + } else { + bool srgb = p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ALBEDO || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO; + rd_texture = singleton->texture_get_rd_texture(texture, srgb); + if (rd_texture.is_null()) { + //wtf + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); + } + } + + p_textures[i] = rd_texture; + } +} + +void RasterizerStorageRD::_update_queued_materials() { + Material *material = material_update_list; + while (material) { + Material *next = material->update_next; + + if (material->data) { + material->data->update_parameters(material->params, material->uniform_dirty, material->texture_dirty); + } + material->update_requested = false; + material->texture_dirty = false; + material->uniform_dirty = false; + material->update_next = NULL; + material = next; + } + material_update_list = NULL; +} + +/* RENDER TARGET API */ + +void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { + + //free in reverse dependency order + if (rt->framebuffer.is_valid()) { + RD::get_singleton()->free(rt->framebuffer); + } + + if (rt->color.is_valid()) { + RD::get_singleton()->free(rt->color); + } + + if (rt->backbuffer.is_valid()) { + RD::get_singleton()->free(rt->backbuffer); + rt->backbuffer = RID(); + rt->backbuffer_fb = RID(); + for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) { + //just erase copies, since the rest are erased by dependency + RD::get_singleton()->free(rt->backbuffer_mipmaps[i].mipmap_copy); + } + rt->backbuffer_mipmaps.clear(); + if (rt->backbuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->backbuffer_uniform_set)) { + RD::get_singleton()->free(rt->backbuffer_uniform_set); + } + rt->backbuffer_uniform_set = RID(); + } + + rt->framebuffer = RID(); + rt->color = RID(); +} + +void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { + + if (rt->texture.is_null()) { + //create a placeholder until updated + rt->texture = texture_2d_placeholder_create(); + Texture *tex = texture_owner.getornull(rt->texture); + tex->is_render_target = true; + } + + _clear_render_target(rt); + + if (rt->size.width == 0 || rt->size.height == 0) { + return; + } + //until we implement suport for HDR monitors (and render target is attached to screen), this is enough. + rt->color_format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + rt->image_format = rt->flags[RENDER_TARGET_TRANSPARENT] ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8; + + RD::TextureFormat rd_format; + RD::TextureView rd_view; + { //attempt register + rd_format.format = rt->color_format; + rd_format.width = rt->size.width; + rd_format.height = rt->size.height; + rd_format.depth = 1; + rd_format.array_layers = 1; + rd_format.mipmaps = 1; + rd_format.type = RD::TEXTURE_TYPE_2D; + rd_format.samples = RD::TEXTURE_SAMPLES_1; + rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + rd_format.shareable_formats.push_back(rt->color_format); + rd_format.shareable_formats.push_back(rt->color_format_srgb); + } + + rt->color = RD::get_singleton()->texture_create(rd_format, rd_view); + ERR_FAIL_COND(rt->color.is_null()); + + Vector<RID> fb_textures; + fb_textures.push_back(rt->color); + rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures); + if (rt->framebuffer.is_null()) { + _clear_render_target(rt); + ERR_FAIL_COND(rt->framebuffer.is_null()); + } + + { //update texture + + Texture *tex = texture_owner.getornull(rt->texture); + + //free existing textures + if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) { + RD::get_singleton()->free(tex->rd_texture); + } + if (RD::get_singleton()->texture_is_valid(tex->rd_texture_srgb)) { + RD::get_singleton()->free(tex->rd_texture_srgb); + } + + tex->rd_texture = RID(); + tex->rd_texture_srgb = RID(); + + //create shared textures to the color buffer, + //so transparent can be supported + RD::TextureView view; + view.format_override = rt->color_format; + if (!rt->flags[RENDER_TARGET_TRANSPARENT]) { + view.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } + tex->rd_texture = RD::get_singleton()->texture_create_shared(view, rt->color); + if (rt->color_format_srgb != RD::DATA_FORMAT_MAX) { + view.format_override = rt->color_format_srgb; + tex->rd_texture_srgb = RD::get_singleton()->texture_create_shared(view, rt->color); + } + tex->rd_view = view; + tex->width = rt->size.width; + tex->height = rt->size.height; + tex->width_2d = rt->size.width; + tex->height_2d = rt->size.height; + tex->rd_format = rt->color_format; + tex->rd_format_srgb = rt->color_format_srgb; + tex->format = rt->image_format; + + Vector<RID> proxies = tex->proxies; //make a copy, since update may change it + for (int i = 0; i < proxies.size(); i++) { + texture_proxy_update(proxies[i], rt->texture); + } + } +} + +void RasterizerStorageRD::_create_render_target_backbuffer(RenderTarget *rt) { + ERR_FAIL_COND(rt->backbuffer.is_valid()); + + uint32_t mipmaps_required = Image::get_image_required_mipmaps(rt->size.width, rt->size.height, Image::FORMAT_RGBA8); + RD::TextureFormat tf; + tf.format = rt->color_format; + tf.width = rt->size.width; + tf.height = rt->size.height; + tf.type = RD::TEXTURE_TYPE_2D; + tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + tf.mipmaps = mipmaps_required; + + rt->backbuffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + { + Vector<RID> backbuffer_att; + RID backbuffer_fb_tex = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, 0); + backbuffer_att.push_back(backbuffer_fb_tex); + rt->backbuffer_fb = RD::get_singleton()->framebuffer_create(backbuffer_att); + } + + //create mipmaps + for (uint32_t i = 1; i < mipmaps_required; i++) { + + RenderTarget::BackbufferMipmap mm; + { + mm.mipmap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->backbuffer, 0, i); + Vector<RID> mm_fb_at; + mm_fb_at.push_back(mm.mipmap); + mm.mipmap_fb = RD::get_singleton()->framebuffer_create(mm_fb_at); + } + + { + Size2 mm_size = Image::get_image_mipmap_size(tf.width, tf.height, Image::FORMAT_RGBA8, i); + + RD::TextureFormat mmtf = tf; + mmtf.width = mm_size.width; + mmtf.height = mm_size.height; + mmtf.mipmaps = 1; + + mm.mipmap_copy = RD::get_singleton()->texture_create(mmtf, RD::TextureView()); + Vector<RID> mm_fb_at; + mm_fb_at.push_back(mm.mipmap_copy); + mm.mipmap_copy_fb = RD::get_singleton()->framebuffer_create(mm_fb_at); + } + + rt->backbuffer_mipmaps.push_back(mm); + } +} + +RID RasterizerStorageRD::render_target_create() { + RenderTarget render_target; + + render_target.was_used = false; + render_target.clear_requested = false; + + for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) { + render_target.flags[i] = false; + } + _update_render_target(&render_target); + return render_target_owner.make_rid(render_target); +} + +void RasterizerStorageRD::render_target_set_position(RID p_render_target, int p_x, int p_y) { + //unused for this render target +} + +void RasterizerStorageRD::render_target_set_size(RID p_render_target, int p_width, int p_height) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + rt->size.x = p_width; + rt->size.y = p_height; + _update_render_target(rt); +} + +RID RasterizerStorageRD::render_target_get_texture(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + return rt->texture; +} + +void RasterizerStorageRD::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { +} + +void RasterizerStorageRD::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + rt->flags[p_flag] = p_value; + _update_render_target(rt); +} + +bool RasterizerStorageRD::render_target_was_used(RID p_render_target) { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, false); + return rt->was_used; +} + +void RasterizerStorageRD::render_target_set_as_unused(RID p_render_target) { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + rt->was_used = false; +} + +Size2 RasterizerStorageRD::render_target_get_size(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, Size2()); + + return rt->size; +} + +RID RasterizerStorageRD::render_target_get_rd_framebuffer(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + return rt->framebuffer; +} + +void RasterizerStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + rt->clear_requested = true; + rt->clear_color = p_clear_color; +} + +bool RasterizerStorageRD::render_target_is_clear_requested(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, false); + return rt->clear_requested; +} + +Color RasterizerStorageRD::render_target_get_clear_request_color(RID p_render_target) { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, Color()); + return rt->clear_color; +} + +void RasterizerStorageRD::render_target_disable_clear_request(RID p_render_target) { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + rt->clear_requested = false; +} + +void RasterizerStorageRD::render_target_do_clear_request(RID p_render_target) { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + if (!rt->clear_requested) { + return; + } + Vector<Color> clear_colors; + clear_colors.push_back(rt->clear_color); + RD::get_singleton()->draw_list_begin(rt->framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, clear_colors); + RD::get_singleton()->draw_list_end(); + rt->clear_requested = false; +} + +void RasterizerStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + if (!rt->backbuffer.is_valid()) { + _create_render_target_backbuffer(rt); + } + + Rect2i region = p_region; + Rect2 blur_region; + if (region == Rect2i()) { + region.size = rt->size; + } else { + blur_region = region; + blur_region.position /= rt->size; + blur_region.size /= rt->size; + } + + //single texture copy for backbuffer + RD::get_singleton()->texture_copy(rt->color, rt->backbuffer, Vector3(region.position.x, region.position.y, 0), Vector3(region.position.x, region.position.y, 0), Vector3(region.size.x, region.size.y, 1), 0, 0, 0, 0, true); + //effects.copy(rt->color, rt->backbuffer_fb, blur_region); + + //then mipmap blur + RID prev_texture = rt->color; //use color, not backbuffer, as bb has mipmaps. + Vector2 pixel_size = Vector2(1.0 / rt->size.width, 1.0 / rt->size.height); + + for (int i = 0; i < rt->backbuffer_mipmaps.size(); i++) { + pixel_size *= 2.0; //go halfway + const RenderTarget::BackbufferMipmap &mm = rt->backbuffer_mipmaps[i]; + effects.gaussian_blur(prev_texture, mm.mipmap_copy_fb, mm.mipmap_copy, mm.mipmap_fb, pixel_size, blur_region); + prev_texture = mm.mipmap; + } +} + +RID RasterizerStorageRD::render_target_get_back_buffer_uniform_set(RID p_render_target, RID p_base_shader) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + if (!rt->backbuffer.is_valid()) { + _create_render_target_backbuffer(rt); + } + + if (rt->backbuffer_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rt->backbuffer_uniform_set)) { + return rt->backbuffer_uniform_set; //if still valid, return/reuse it. + } + + //create otherwise + Vector<RD::Uniform> uniforms; + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 0; + u.ids.push_back(rt->backbuffer); + uniforms.push_back(u); + + rt->backbuffer_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_base_shader, 3); + ERR_FAIL_COND_V(!rt->backbuffer_uniform_set.is_valid(), RID()); + + return rt->backbuffer_uniform_set; +} + +void RasterizerStorageRD::update_dirty_resources() { + _update_queued_materials(); +} + +bool RasterizerStorageRD::free(RID p_rid) { + + if (texture_owner.owns(p_rid)) { + Texture *t = texture_owner.getornull(p_rid); + + ERR_FAIL_COND_V(t->is_render_target, false); + + if (t->rd_texture_srgb.is_valid()) { + //erase this first, as it's a dependency of the one below + RD::get_singleton()->free(t->rd_texture_srgb); + } + RD::get_singleton()->free(t->rd_texture); + + for (int i = 0; i < t->proxies.size(); i++) { + Texture *p = texture_owner.getornull(t->proxies[i]); + ERR_CONTINUE(!p); + p->proxy_to = RID(); + p->rd_texture = RID(); + p->rd_texture_srgb = RID(); + } + texture_owner.free(p_rid); + + } else if (shader_owner.owns(p_rid)) { + Shader *shader = shader_owner.getornull(p_rid); + //make material unreference this + while (shader->owners.size()) { + material_set_shader(shader->owners.front()->get()->self, RID()); + } + //clear data if exists + if (shader->data) { + memdelete(shader->data); + } + shader_owner.free(p_rid); + + } else if (material_owner.owns(p_rid)) { + Material *material = material_owner.getornull(p_rid); + if (material->update_requested) { + _update_queued_materials(); + } + material_set_shader(p_rid, RID()); //clean up shader + material->instance_dependency.instance_notify_deleted(p_rid); + } else if (render_target_owner.owns(p_rid)) { + RenderTarget *rt = render_target_owner.getornull(p_rid); + + _clear_render_target(rt); + + if (rt->texture.is_valid()) { + Texture *tex = texture_owner.getornull(rt->texture); + tex->is_render_target = false; + free(rt->texture); + } + + render_target_owner.free(p_rid); + } else { + return false; + } + + return true; +} + +EffectsRD *RasterizerStorageRD::get_effects() { + return &effects; +} + +RasterizerStorageRD::RasterizerStorageRD() { + + material_update_list = NULL; + { //create default textures + + RD::TextureFormat tformat; + tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + tformat.width = 4; + tformat.height = 4; + tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT; + tformat.type = RD::TEXTURE_TYPE_2D; + + PoolVector<uint8_t> pv; + pv.resize(16 * 4); + for (int i = 0; i < 16; i++) { + pv.set(i * 4 + 0, 255); + pv.set(i * 4 + 1, 255); + pv.set(i * 4 + 2, 255); + pv.set(i * 4 + 3, 255); + } + + { + Vector<PoolVector<uint8_t> > vpv; + vpv.push_back(pv); + default_rd_textures[DEFAULT_RD_TEXTURE_WHITE] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + + for (int i = 0; i < 16; i++) { + pv.set(i * 4 + 0, 0); + pv.set(i * 4 + 1, 0); + pv.set(i * 4 + 2, 0); + pv.set(i * 4 + 3, 255); + } + + { + Vector<PoolVector<uint8_t> > vpv; + vpv.push_back(pv); + default_rd_textures[DEFAULT_RD_TEXTURE_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + + for (int i = 0; i < 16; i++) { + pv.set(i * 4 + 0, 128); + pv.set(i * 4 + 1, 128); + pv.set(i * 4 + 2, 255); + pv.set(i * 4 + 3, 255); + } + + { + Vector<PoolVector<uint8_t> > vpv; + vpv.push_back(pv); + default_rd_textures[DEFAULT_RD_TEXTURE_NORMAL] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + + for (int i = 0; i < 16; i++) { + pv.set(i * 4 + 0, 255); + pv.set(i * 4 + 1, 128); + pv.set(i * 4 + 2, 255); + pv.set(i * 4 + 3, 255); + } + + { + Vector<PoolVector<uint8_t> > vpv; + vpv.push_back(pv); + default_rd_textures[DEFAULT_RD_TEXTURE_ANISO] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + + for (int i = 0; i < 16; i++) { + pv.set(i * 4 + 0, 0); + pv.set(i * 4 + 1, 0); + pv.set(i * 4 + 2, 0); + pv.set(i * 4 + 3, 0); + } + + default_rd_textures[DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER] = RD::get_singleton()->texture_buffer_create(16, RD::DATA_FORMAT_R8G8B8A8_UNORM, pv); + } + + //default samplers + for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) { + for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) { + RD::SamplerState sampler_state; + switch (i) { + case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST; + sampler_state.max_lod = 0; + } break; + case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: { + + sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.max_lod = 0; + } break; + case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; + } break; + case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; + + } break; + case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS_ANISOTROPIC: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.use_anisotropy = true; + sampler_state.anisotropy_max = GLOBAL_GET("rendering/quality/filters/max_anisotropy"); + } break; + case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.use_anisotropy = true; + sampler_state.anisotropy_max = GLOBAL_GET("rendering/quality/filters/max_anisotropy"); + + } break; + default: { + } + } + switch (j) { + case VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: { + + sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE; + sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE; + + } break; + case VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: { + sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT; + sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT; + } break; + case VS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: { + sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + } break; + default: { + } + } + + default_rd_samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state); + } + } +} + +RasterizerStorageRD::~RasterizerStorageRD() { + //def textures + for (int i = 0; i < DEFAULT_RD_TEXTURE_MAX; i++) { + RD::get_singleton()->free(default_rd_textures[i]); + } + + //def samplers + for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) { + for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) { + RD::get_singleton()->free(default_rd_samplers[i][j]); + } + } +} |