mirror of
https://github.com/godotengine/godot.git
synced 2024-12-21 10:25:24 +08:00
2218 lines
70 KiB
C++
2218 lines
70 KiB
C++
#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]);
|
|
}
|
|
}
|
|
}
|