summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/basis_universal/SCsub4
-rw-r--r--modules/basis_universal/image_compress_basisu.cpp206
-rw-r--r--modules/basis_universal/image_compress_basisu.h9
-rw-r--r--modules/basis_universal/patches/external-jpgd.patch13
-rw-r--r--modules/betsy/SCsub1
-rw-r--r--modules/betsy/bc4.glsl151
-rw-r--r--modules/betsy/image_compress_betsy.cpp80
-rw-r--r--modules/betsy/image_compress_betsy.h7
-rw-r--r--modules/gltf/gltf_document.cpp6
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs13
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs2
-rw-r--r--modules/navigation/nav_map.cpp22
12 files changed, 394 insertions, 120 deletions
diff --git a/modules/basis_universal/SCsub b/modules/basis_universal/SCsub
index 9bea0a0ca9..e201452385 100644
--- a/modules/basis_universal/SCsub
+++ b/modules/basis_universal/SCsub
@@ -14,6 +14,8 @@ thirdparty_obj = []
thirdparty_dir = "#thirdparty/basis_universal/"
# Sync list with upstream CMakeLists.txt
encoder_sources = [
+ "3rdparty/android_astc_decomp.cpp",
+ "basisu_astc_hdr_enc.cpp",
"basisu_backend.cpp",
"basisu_basis_file.cpp",
"basisu_bc7enc.cpp",
@@ -45,6 +47,8 @@ else:
if env["builtin_zstd"]:
env_basisu.Prepend(CPPPATH=["#thirdparty/zstd"])
+env_basisu.Prepend(CPPPATH=["#thirdparty/tinyexr"])
+
if env.dev_build:
env_basisu.Append(CPPDEFINES=[("BASISU_DEVEL_MESSAGES", 1), ("BASISD_ENABLE_DEBUG_FLAGS", 1)])
diff --git a/modules/basis_universal/image_compress_basisu.cpp b/modules/basis_universal/image_compress_basisu.cpp
index ab20d00b5b..d48ea363a7 100644
--- a/modules/basis_universal/image_compress_basisu.cpp
+++ b/modules/basis_universal/image_compress_basisu.cpp
@@ -30,6 +30,8 @@
#include "image_compress_basisu.h"
+#include "core/os/os.h"
+#include "core/string/print_string.h"
#include "servers/rendering_server.h"
#include <transcoder/basisu_transcoder.h>
@@ -46,9 +48,48 @@ void basis_universal_init() {
}
#ifdef TOOLS_ENABLED
+template <typename T>
+inline void _basisu_pad_mipmap(const uint8_t *p_image_mip_data, Vector<uint8_t> &r_mip_data_padded, int p_next_width, int p_next_height, int p_width, int p_height, int64_t p_size) {
+ // Source mip's data interpreted as 32-bit RGBA blocks to help with copying pixel data.
+ const T *mip_src_data = reinterpret_cast<const T *>(p_image_mip_data);
+
+ // Reserve space in the padded buffer.
+ r_mip_data_padded.resize(p_next_width * p_next_height * sizeof(T));
+ T *data_padded_ptr = reinterpret_cast<T *>(r_mip_data_padded.ptrw());
+
+ // Pad mipmap to the nearest block by smearing.
+ int x = 0, y = 0;
+ for (y = 0; y < p_height; y++) {
+ for (x = 0; x < p_width; x++) {
+ data_padded_ptr[p_next_width * y + x] = mip_src_data[p_width * y + x];
+ }
+
+ // First, smear in x.
+ for (; x < p_next_width; x++) {
+ data_padded_ptr[p_next_width * y + x] = data_padded_ptr[p_next_width * y + x - 1];
+ }
+ }
+
+ // Then, smear in y.
+ for (; y < p_next_height; y++) {
+ for (x = 0; x < p_next_width; x++) {
+ data_padded_ptr[p_next_width * y + x] = data_padded_ptr[p_next_width * y + x - p_next_width];
+ }
+ }
+}
+
Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedChannels p_channels) {
+ uint64_t start_time = OS::get_singleton()->get_ticks_msec();
+
Ref<Image> image = p_image->duplicate();
- image->convert(Image::FORMAT_RGBA8);
+ bool is_hdr = false;
+
+ if (image->get_format() <= Image::FORMAT_RGB565) {
+ image->convert(Image::FORMAT_RGBA8);
+ } else if (image->get_format() <= Image::FORMAT_RGBE9995) {
+ image->convert(Image::FORMAT_RGBAF);
+ is_hdr = true;
+ }
basisu::basis_compressor_params params;
@@ -74,32 +115,42 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
basisu::job_pool job_pool(OS::get_singleton()->get_processor_count());
params.m_pJob_pool = &job_pool;
- BasisDecompressFormat decompress_format = BASIS_DECOMPRESS_RG;
- switch (p_channels) {
- case Image::USED_CHANNELS_L: {
- decompress_format = BASIS_DECOMPRESS_RGB;
- } break;
- case Image::USED_CHANNELS_LA: {
- params.m_force_alpha = true;
- decompress_format = BASIS_DECOMPRESS_RGBA;
- } break;
- case Image::USED_CHANNELS_R: {
- decompress_format = BASIS_DECOMPRESS_R;
- } break;
- case Image::USED_CHANNELS_RG: {
- params.m_force_alpha = true;
- image->convert_rg_to_ra_rgba8();
- decompress_format = BASIS_DECOMPRESS_RG;
- } break;
- case Image::USED_CHANNELS_RGB: {
- decompress_format = BASIS_DECOMPRESS_RGB;
- } break;
- case Image::USED_CHANNELS_RGBA: {
- params.m_force_alpha = true;
- decompress_format = BASIS_DECOMPRESS_RGBA;
- } break;
+ BasisDecompressFormat decompress_format = BASIS_DECOMPRESS_MAX;
+
+ if (is_hdr) {
+ decompress_format = BASIS_DECOMPRESS_HDR_RGB;
+ params.m_hdr = true;
+ params.m_uastc_hdr_options.set_quality_level(0);
+
+ } else {
+ switch (p_channels) {
+ case Image::USED_CHANNELS_L: {
+ decompress_format = BASIS_DECOMPRESS_RGB;
+ } break;
+ case Image::USED_CHANNELS_LA: {
+ params.m_force_alpha = true;
+ decompress_format = BASIS_DECOMPRESS_RGBA;
+ } break;
+ case Image::USED_CHANNELS_R: {
+ decompress_format = BASIS_DECOMPRESS_R;
+ } break;
+ case Image::USED_CHANNELS_RG: {
+ params.m_force_alpha = true;
+ image->convert_rg_to_ra_rgba8();
+ decompress_format = BASIS_DECOMPRESS_RG;
+ } break;
+ case Image::USED_CHANNELS_RGB: {
+ decompress_format = BASIS_DECOMPRESS_RGB;
+ } break;
+ case Image::USED_CHANNELS_RGBA: {
+ params.m_force_alpha = true;
+ decompress_format = BASIS_DECOMPRESS_RGBA;
+ } break;
+ }
}
+ ERR_FAIL_COND_V(decompress_format == BASIS_DECOMPRESS_MAX, Vector<uint8_t>());
+
// Copy the source image data with mipmaps into BasisU.
{
const int orig_width = image->get_width();
@@ -113,9 +164,10 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
Vector<uint8_t> image_data = image->get_data();
basisu::vector<basisu::image> basisu_mipmaps;
+ basisu::vector<basisu::imagef> basisu_mipmaps_hdr;
// Buffer for storing padded mipmap data.
- Vector<uint32_t> mip_data_padded;
+ Vector<uint8_t> mip_data_padded;
for (int32_t i = 0; i <= image->get_mipmap_count(); i++) {
int64_t ofs, size;
@@ -126,31 +178,10 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
// Pad the mipmap's data if its resolution isn't divisible by 4.
if (image->has_mipmaps() && !is_res_div_4 && (width > 2 && height > 2) && (width != next_width || height != next_height)) {
- // Source mip's data interpreted as 32-bit RGBA blocks to help with copying pixel data.
- const uint32_t *mip_src_data = reinterpret_cast<const uint32_t *>(image_mip_data);
-
- // Reserve space in the padded buffer.
- mip_data_padded.resize(next_width * next_height);
- uint32_t *data_padded_ptr = mip_data_padded.ptrw();
-
- // Pad mipmap to the nearest block by smearing.
- int x = 0, y = 0;
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- data_padded_ptr[next_width * y + x] = mip_src_data[width * y + x];
- }
-
- // First, smear in x.
- for (; x < next_width; x++) {
- data_padded_ptr[next_width * y + x] = data_padded_ptr[next_width * y + x - 1];
- }
- }
-
- // Then, smear in y.
- for (; y < next_height; y++) {
- for (x = 0; x < next_width; x++) {
- data_padded_ptr[next_width * y + x] = data_padded_ptr[next_width * y + x - next_width];
- }
+ if (is_hdr) {
+ _basisu_pad_mipmap<BasisRGBAF>(image_mip_data, mip_data_padded, next_width, next_height, width, height, size);
+ } else {
+ _basisu_pad_mipmap<uint32_t>(image_mip_data, mip_data_padded, next_width, next_height, width, height, size);
}
// Override the image_mip_data pointer with our temporary Vector.
@@ -159,7 +190,7 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
// Override the mipmap's properties.
width = next_width;
height = next_height;
- size = mip_data_padded.size() * 4;
+ size = mip_data_padded.size();
}
// Get the next mipmap's resolution.
@@ -167,44 +198,61 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
next_height /= 2;
// Copy the source mipmap's data to a BasisU image.
- basisu::image basisu_image(width, height);
- memcpy(basisu_image.get_ptr(), image_mip_data, size);
+ if (is_hdr) {
+ basisu::imagef basisu_image(width, height);
+ memcpy(reinterpret_cast<uint8_t *>(basisu_image.get_ptr()), image_mip_data, size);
+
+ if (i == 0) {
+ params.m_source_images_hdr.push_back(basisu_image);
+ } else {
+ basisu_mipmaps_hdr.push_back(basisu_image);
+ }
- if (i == 0) {
- params.m_source_images.push_back(basisu_image);
} else {
- basisu_mipmaps.push_back(basisu_image);
+ basisu::image basisu_image(width, height);
+ memcpy(basisu_image.get_ptr(), image_mip_data, size);
+
+ if (i == 0) {
+ params.m_source_images.push_back(basisu_image);
+ } else {
+ basisu_mipmaps.push_back(basisu_image);
+ }
}
}
- params.m_source_mipmap_images.push_back(basisu_mipmaps);
+ if (is_hdr) {
+ params.m_source_mipmap_images_hdr.push_back(basisu_mipmaps_hdr);
+ } else {
+ params.m_source_mipmap_images.push_back(basisu_mipmaps);
+ }
}
// Encode the image data.
- Vector<uint8_t> basisu_data;
-
basisu::basis_compressor compressor;
compressor.init(params);
int basisu_err = compressor.process();
- ERR_FAIL_COND_V(basisu_err != basisu::basis_compressor::cECSuccess, basisu_data);
+ ERR_FAIL_COND_V(basisu_err != basisu::basis_compressor::cECSuccess, Vector<uint8_t>());
- const basisu::uint8_vec &basisu_out = compressor.get_output_basis_file();
- basisu_data.resize(basisu_out.size() + 4);
+ const basisu::uint8_vec &basisu_encoded = compressor.get_output_basis_file();
- // Copy the encoded data to the buffer.
- {
- uint8_t *wb = basisu_data.ptrw();
- *(uint32_t *)wb = decompress_format;
+ Vector<uint8_t> basisu_data;
+ basisu_data.resize(basisu_encoded.size() + 4);
+ uint8_t *basisu_data_ptr = basisu_data.ptrw();
- memcpy(wb + 4, basisu_out.get_ptr(), basisu_out.size());
- }
+ // Copy the encoded BasisU data into the output buffer.
+ *(uint32_t *)basisu_data_ptr = decompress_format;
+ memcpy(basisu_data_ptr + 4, basisu_encoded.get_ptr(), basisu_encoded.size());
+
+ print_verbose(vformat("BasisU: Encoding a %dx%d image with %d mipmaps took %d ms.", p_image->get_width(), p_image->get_height(), p_image->get_mipmap_count(), OS::get_singleton()->get_ticks_msec() - start_time));
return basisu_data;
}
#endif // TOOLS_ENABLED
Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) {
+ uint64_t start_time = OS::get_singleton()->get_ticks_msec();
+
Ref<Image> image;
ERR_FAIL_NULL_V_MSG(p_data, image, "Cannot unpack invalid BasisUniversal data.");
@@ -320,6 +368,23 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) {
}
} break;
+ case BASIS_DECOMPRESS_HDR_RGB: {
+ if (bptc_supported) {
+ basisu_format = basist::transcoder_texture_format::cTFBC6H;
+ image_format = Image::FORMAT_BPTC_RGBFU;
+ } else if (astc_supported) {
+ basisu_format = basist::transcoder_texture_format::cTFASTC_HDR_4x4_RGBA;
+ image_format = Image::FORMAT_ASTC_4x4_HDR;
+ } else {
+ // No supported VRAM compression formats, decompress.
+ basisu_format = basist::transcoder_texture_format::cTFRGB_9E5;
+ image_format = Image::FORMAT_RGBE9995;
+ }
+
+ } break;
+ default: {
+ ERR_FAIL_V(image);
+ } break;
}
src_ptr += 4;
@@ -371,6 +436,9 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) {
}
}
+ print_verbose(vformat("BasisU: Transcoding a %dx%d image with %d mipmaps into %s took %d ms.",
+ image->get_width(), image->get_height(), image->get_mipmap_count(), Image::get_format_name(image_format), OS::get_singleton()->get_ticks_msec() - start_time));
+
return image;
}
diff --git a/modules/basis_universal/image_compress_basisu.h b/modules/basis_universal/image_compress_basisu.h
index 5e36d448f6..81c8511f60 100644
--- a/modules/basis_universal/image_compress_basisu.h
+++ b/modules/basis_universal/image_compress_basisu.h
@@ -39,11 +39,20 @@ enum BasisDecompressFormat {
BASIS_DECOMPRESS_RGBA,
BASIS_DECOMPRESS_RG_AS_RA,
BASIS_DECOMPRESS_R,
+ BASIS_DECOMPRESS_HDR_RGB,
+ BASIS_DECOMPRESS_MAX
};
void basis_universal_init();
#ifdef TOOLS_ENABLED
+struct BasisRGBAF {
+ uint32_t r;
+ uint32_t g;
+ uint32_t b;
+ uint32_t a;
+};
+
Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedChannels p_channels);
#endif
diff --git a/modules/basis_universal/patches/external-jpgd.patch b/modules/basis_universal/patches/external-jpgd.patch
deleted file mode 100644
index 7a805d00cb..0000000000
--- a/modules/basis_universal/patches/external-jpgd.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/thirdparty/basis_universal/encoder/basisu_enc.cpp b/thirdparty/basis_universal/encoder/basisu_enc.cpp
-index c431ceaf12..e87dd636a2 100644
---- a/thirdparty/basis_universal/encoder/basisu_enc.cpp
-+++ b/thirdparty/basis_universal/encoder/basisu_enc.cpp
-@@ -409,7 +409,7 @@ namespace basisu
- bool load_jpg(const char *pFilename, image& img)
- {
- int width = 0, height = 0, actual_comps = 0;
-- uint8_t *pImage_data = jpgd::decompress_jpeg_image_from_file(pFilename, &width, &height, &actual_comps, 4, jpgd::jpeg_decoder::cFlagLinearChromaFiltering);
-+ uint8_t *pImage_data = jpgd::decompress_jpeg_image_from_file(pFilename, &width, &height, &actual_comps, 4, jpgd::jpeg_decoder::cFlagBoxChromaFiltering);
- if (!pImage_data)
- return false;
-
diff --git a/modules/betsy/SCsub b/modules/betsy/SCsub
index 2735116cc3..621ba58ae3 100644
--- a/modules/betsy/SCsub
+++ b/modules/betsy/SCsub
@@ -7,6 +7,7 @@ Import("env_modules")
env_betsy = env_modules.Clone()
env_betsy.GLSL_HEADER("bc6h.glsl")
env_betsy.GLSL_HEADER("bc1.glsl")
+env_betsy.GLSL_HEADER("bc4.glsl")
env_betsy.Depends(Glob("*.glsl.gen.h"), ["#glsl_builders.py"])
# Thirdparty source files
diff --git a/modules/betsy/bc4.glsl b/modules/betsy/bc4.glsl
new file mode 100644
index 0000000000..b7a5f6a686
--- /dev/null
+++ b/modules/betsy/bc4.glsl
@@ -0,0 +1,151 @@
+#[versions]
+
+unsigned = "";
+signed = "#define SNORM";
+
+#[compute]
+#version 450
+
+#include "CrossPlatformSettings_piece_all.glsl"
+#include "UavCrossPlatform_piece_all.glsl"
+
+#VERSION_DEFINES
+
+shared float2 g_minMaxValues[4u * 4u * 4u];
+shared uint2 g_mask[4u * 4u];
+
+layout(binding = 0) uniform sampler2D srcTex;
+layout(binding = 1, rg32ui) uniform restrict writeonly uimage2D dstTexture;
+
+layout(push_constant, std430) uniform Params {
+ uint p_channelIdx;
+ uint p_padding[3];
+}
+params;
+
+layout(local_size_x = 4, //
+ local_size_y = 4, //
+ local_size_z = 4) in;
+
+/// Each block is 16 pixels
+/// Each thread works on 4 pixels
+/// Therefore each block needs 4 threads, generating 8 masks
+/// At the end these 8 masks get merged into 2 and results written to output
+///
+/// **Q: Why 4 pixels per thread? Why not 1 pixel per thread? Why not 2? Why not 16?**
+///
+/// A: It's a sweetspot.
+/// - Very short threads cannot fill expensive GPUs with enough work (dispatch bound)
+/// - Lots of threads means lots of synchronization (e.g. evaluating min/max, merging masks)
+/// overhead, and also more LDS usage which reduces occupancy.
+/// - Long threads (e.g. 1 thread per block) misses parallelism opportunities
+void main() {
+ float minVal, maxVal;
+ float4 srcPixel;
+
+ const uint blockThreadId = gl_LocalInvocationID.x;
+
+ const uint2 pixelsToLoadBase = gl_GlobalInvocationID.yz << 2u;
+
+ for (uint i = 0u; i < 4u; ++i) {
+ const uint2 pixelsToLoad = pixelsToLoadBase + uint2(i, blockThreadId);
+
+ const float4 value = OGRE_Load2D(srcTex, int2(pixelsToLoad), 0).xyzw;
+ srcPixel[i] = params.p_channelIdx == 0 ? value.x : (params.p_channelIdx == 1 ? value.y : value.w);
+ srcPixel[i] *= 255.0f;
+ }
+
+ minVal = min3(srcPixel.x, srcPixel.y, srcPixel.z);
+ maxVal = max3(srcPixel.x, srcPixel.y, srcPixel.z);
+ minVal = min(minVal, srcPixel.w);
+ maxVal = max(maxVal, srcPixel.w);
+
+ const uint minMaxIdxBase = (gl_LocalInvocationID.z << 4u) + (gl_LocalInvocationID.y << 2u);
+ const uint maskIdxBase = (gl_LocalInvocationID.z << 2u) + gl_LocalInvocationID.y;
+
+ g_minMaxValues[minMaxIdxBase + blockThreadId] = float2(minVal, maxVal);
+ g_mask[maskIdxBase] = uint2(0u, 0u);
+
+ memoryBarrierShared();
+ barrier();
+
+ // Have all 4 threads in the block grab the min/max value by comparing what all 4 threads uploaded
+ for (uint i = 0u; i < 4u; ++i) {
+ minVal = min(g_minMaxValues[minMaxIdxBase + i].x, minVal);
+ maxVal = max(g_minMaxValues[minMaxIdxBase + i].y, maxVal);
+ }
+
+ // determine bias and emit color indices
+ // given the choice of maxVal/minVal, these indices are optimal:
+ // http://fgiesen.wordpress.com/2009/12/15/dxt5-alpha-block-index-determination/
+ float dist = maxVal - minVal;
+ float dist4 = dist * 4.0f;
+ float dist2 = dist * 2.0f;
+ float bias = (dist < 8) ? (dist - 1) : (trunc(dist * 0.5f) + 2);
+ bias -= minVal * 7;
+
+ uint mask0 = 0u, mask1 = 0u;
+
+ for (uint i = 0u; i < 4u; ++i) {
+ float a = srcPixel[i] * 7.0f + bias;
+
+ int ind = 0;
+
+ // select index. this is a "linear scale" lerp factor between 0 (val=min) and 7 (val=max).
+ if (a >= dist4) {
+ ind = 4;
+ a -= dist4;
+ }
+
+ if (a >= dist2) {
+ ind += 2;
+ a -= dist2;
+ }
+
+ if (a >= dist)
+ ind += 1;
+
+ // turn linear scale into DXT index (0/1 are extremal pts)
+ ind = -ind & 7;
+ ind ^= (2 > ind) ? 1 : 0;
+
+ // write index
+ const uint bits = 16u + ((blockThreadId << 2u) + i) * 3u;
+ if (bits < 32u) {
+ mask0 |= uint(ind) << bits;
+ if (bits + 3u > 32u) {
+ mask1 |= uint(ind) >> (32u - bits);
+ }
+ } else {
+ mask1 |= uint(ind) << (bits - 32u);
+ }
+ }
+
+ if (mask0 != 0u)
+ atomicOr(g_mask[maskIdxBase].x, mask0);
+ if (mask1 != 0u)
+ atomicOr(g_mask[maskIdxBase].y, mask1);
+
+ memoryBarrierShared();
+ barrier();
+
+ if (blockThreadId == 0u) {
+ // Save data
+ uint2 outputBytes;
+
+#ifdef SNORM
+ outputBytes.x =
+ packSnorm4x8(float4(maxVal * (1.0f / 255.0f) * 2.0f - 1.0f,
+ minVal * (1.0f / 255.0f) * 2.0f - 1.0f, 0.0f, 0.0f));
+#else
+ outputBytes.x = packUnorm4x8(
+ float4(maxVal * (1.0f / 255.0f), minVal * (1.0f / 255.0f), 0.0f, 0.0f));
+#endif
+
+ outputBytes.x |= g_mask[maskIdxBase].x;
+ outputBytes.y = g_mask[maskIdxBase].y;
+
+ uint2 dstUV = gl_GlobalInvocationID.yz;
+ imageStore(dstTexture, int2(dstUV), uint4(outputBytes.xy, 0u, 0u));
+ }
+}
diff --git a/modules/betsy/image_compress_betsy.cpp b/modules/betsy/image_compress_betsy.cpp
index 7b4d8b3dfb..6bfe01f65c 100644
--- a/modules/betsy/image_compress_betsy.cpp
+++ b/modules/betsy/image_compress_betsy.cpp
@@ -35,6 +35,7 @@
#include "betsy_bc1.h"
#include "bc1.glsl.gen.h"
+#include "bc4.glsl.gen.h"
#include "bc6h.glsl.gen.h"
static Mutex betsy_mutex;
@@ -165,6 +166,10 @@ static String get_shader_name(BetsyFormat p_format) {
case BETSY_FORMAT_BC3:
return "BC3";
+ case BETSY_FORMAT_BC4_SIGNED:
+ case BETSY_FORMAT_BC4_UNSIGNED:
+ return "BC4";
+
case BETSY_FORMAT_BC6_SIGNED:
case BETSY_FORMAT_BC6_UNSIGNED:
return "BC6";
@@ -202,6 +207,12 @@ Error BetsyCompressor::_compress(BetsyFormat p_format, Image *r_img) {
dest_format = Image::FORMAT_DXT1;
break;
+ case BETSY_FORMAT_BC4_UNSIGNED:
+ version = "unsigned";
+ dst_rd_format = RD::DATA_FORMAT_R32G32_UINT;
+ dest_format = Image::FORMAT_RGTC_R;
+ break;
+
case BETSY_FORMAT_BC6_SIGNED:
version = "signed";
dst_rd_format = RD::DATA_FORMAT_R32G32B32A32_UINT;
@@ -235,8 +246,13 @@ Error BetsyCompressor::_compress(BetsyFormat p_format, Image *r_img) {
err = source->parse_versions_from_text(bc1_shader_glsl);
break;
- case BETSY_FORMAT_BC6_UNSIGNED:
+ case BETSY_FORMAT_BC4_SIGNED:
+ case BETSY_FORMAT_BC4_UNSIGNED:
+ err = source->parse_versions_from_text(bc4_shader_glsl);
+ break;
+
case BETSY_FORMAT_BC6_SIGNED:
+ case BETSY_FORMAT_BC6_UNSIGNED:
err = source->parse_versions_from_text(bc6h_shader_glsl);
break;
@@ -430,26 +446,45 @@ Error BetsyCompressor::_compress(BetsyFormat p_format, Image *r_img) {
compress_rd->compute_list_bind_compute_pipeline(compute_list, shader.pipeline);
compress_rd->compute_list_bind_uniform_set(compute_list, uniform_set, 0);
- if (dest_format == Image::FORMAT_BPTC_RGBFU || dest_format == Image::FORMAT_BPTC_RGBF) {
- BC6PushConstant push_constant;
- push_constant.sizeX = 1.0f / width;
- push_constant.sizeY = 1.0f / height;
- push_constant.padding[0] = 0;
- push_constant.padding[1] = 0;
-
- compress_rd->compute_list_set_push_constant(compute_list, &push_constant, sizeof(BC6PushConstant));
-
- } else {
- BC1PushConstant push_constant;
- push_constant.num_refines = 2;
- push_constant.padding[0] = 0;
- push_constant.padding[1] = 0;
- push_constant.padding[2] = 0;
-
- compress_rd->compute_list_set_push_constant(compute_list, &push_constant, sizeof(BC1PushConstant));
+ switch (dest_format) {
+ case Image::FORMAT_BPTC_RGBFU:
+ case Image::FORMAT_BPTC_RGBF: {
+ BC6PushConstant push_constant;
+ push_constant.sizeX = 1.0f / width;
+ push_constant.sizeY = 1.0f / height;
+ push_constant.padding[0] = 0;
+ push_constant.padding[1] = 0;
+
+ compress_rd->compute_list_set_push_constant(compute_list, &push_constant, sizeof(BC6PushConstant));
+ compress_rd->compute_list_dispatch(compute_list, get_next_multiple(width, 32) / 32, get_next_multiple(height, 32) / 32, 1);
+ } break;
+
+ case Image::FORMAT_DXT1: {
+ BC1PushConstant push_constant;
+ push_constant.num_refines = 2;
+ push_constant.padding[0] = 0;
+ push_constant.padding[1] = 0;
+ push_constant.padding[2] = 0;
+
+ compress_rd->compute_list_set_push_constant(compute_list, &push_constant, sizeof(BC1PushConstant));
+ compress_rd->compute_list_dispatch(compute_list, get_next_multiple(width, 32) / 32, get_next_multiple(height, 32) / 32, 1);
+ } break;
+
+ case Image::FORMAT_RGTC_R: {
+ BC4PushConstant push_constant;
+ push_constant.channel_idx = 0;
+ push_constant.padding[0] = 0;
+ push_constant.padding[1] = 0;
+ push_constant.padding[2] = 0;
+
+ compress_rd->compute_list_set_push_constant(compute_list, &push_constant, sizeof(BC4PushConstant));
+ compress_rd->compute_list_dispatch(compute_list, 1, get_next_multiple(width, 16) / 16, get_next_multiple(height, 16) / 16);
+ } break;
+
+ default: {
+ } break;
}
- compress_rd->compute_list_dispatch(compute_list, get_next_multiple(width, 32) / 32, get_next_multiple(height, 32) / 32, 1);
compress_rd->compute_list_end();
compress_rd->submit();
@@ -511,13 +546,14 @@ Error _betsy_compress_s3tc(Image *r_img, Image::UsedChannels p_channels) {
switch (p_channels) {
case Image::USED_CHANNELS_RGB:
- result = betsy->compress(BETSY_FORMAT_BC1_DITHER, r_img);
- break;
-
case Image::USED_CHANNELS_L:
result = betsy->compress(BETSY_FORMAT_BC1, r_img);
break;
+ case Image::USED_CHANNELS_R:
+ result = betsy->compress(BETSY_FORMAT_BC4_UNSIGNED, r_img);
+ break;
+
default:
break;
}
diff --git a/modules/betsy/image_compress_betsy.h b/modules/betsy/image_compress_betsy.h
index 70e4ae85ed..4e0bf0538f 100644
--- a/modules/betsy/image_compress_betsy.h
+++ b/modules/betsy/image_compress_betsy.h
@@ -50,6 +50,8 @@ enum BetsyFormat {
BETSY_FORMAT_BC1,
BETSY_FORMAT_BC1_DITHER,
BETSY_FORMAT_BC3,
+ BETSY_FORMAT_BC4_SIGNED,
+ BETSY_FORMAT_BC4_UNSIGNED,
BETSY_FORMAT_BC6_SIGNED,
BETSY_FORMAT_BC6_UNSIGNED,
};
@@ -65,6 +67,11 @@ struct BC1PushConstant {
uint32_t padding[3];
};
+struct BC4PushConstant {
+ uint32_t channel_idx;
+ uint32_t padding[3];
+};
+
void free_device();
Error _betsy_compress_bptc(Image *r_img, Image::UsedChannels p_channels);
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 992075e980..0a487430a3 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -613,12 +613,8 @@ Error GLTFDocument::_parse_nodes(Ref<GLTFState> p_state) {
if (n.has("scale")) {
node->set_scale(_arr_to_vec3(n["scale"]));
}
-
- Transform3D godot_rest_transform;
- godot_rest_transform.basis.set_quaternion_scale(node->transform.basis.get_rotation_quaternion(), node->transform.basis.get_scale());
- godot_rest_transform.origin = node->transform.origin;
- node->set_additional_data("GODOT_rest_transform", godot_rest_transform);
}
+ node->set_additional_data("GODOT_rest_transform", node->transform);
if (n.has("extensions")) {
Dictionary extensions = n["extensions"];
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs
index 053ae36ae7..5654060d38 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs
@@ -395,6 +395,11 @@ public class MustBeVariantAnnotatedMethods
public void MethodWithWrongAttribute()
{
}
+
+ [NestedGenericTypeAttributeContainer.NestedGenericTypeAttribute<bool>()]
+ public void MethodWithNestedAttribute()
+ {
+ }
}
[GenericTypeAttribute<bool>()]
@@ -657,3 +662,11 @@ public class ClassNonVariantAnnotated
public class GenericTypeAttribute<[MustBeVariant] T> : Attribute
{
}
+
+public class NestedGenericTypeAttributeContainer
+{
+ [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
+ public class NestedGenericTypeAttribute<[MustBeVariant] T> : Attribute
+ {
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs
index e894e7a86c..a72a8c5880 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs
@@ -135,7 +135,7 @@ namespace Godot.SourceGenerators
{
ITypeParameterSymbol? typeParamSymbol = parentSymbol switch
{
- IMethodSymbol methodSymbol when parentSyntax.Parent is AttributeSyntax &&
+ IMethodSymbol methodSymbol when parentSyntax.Ancestors().Any(s => s is AttributeSyntax) &&
methodSymbol.ContainingType.TypeParameters.Length > 0
=> methodSymbol.ContainingType.TypeParameters[typeArgumentIndex],
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index dd77e81b45..8df1db533d 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -480,6 +480,8 @@ void NavMap::sync() {
// connection, integration and path finding.
_new_pm_edge_free_count = free_edges.size();
+ real_t sqr_edge_connection_margin = edge_connection_margin * edge_connection_margin;
+
for (int i = 0; i < free_edges.size(); i++) {
const gd::Edge::Connection &free_edge = free_edges[i];
Vector3 edge_p1 = free_edge.polygon->points[free_edge.edge].pos;
@@ -510,7 +512,7 @@ void NavMap::sync() {
} else {
other1 = other_edge_p1.lerp(other_edge_p2, (1.0 - projected_p1_ratio) / (projected_p2_ratio - projected_p1_ratio));
}
- if (other1.distance_to(self1) > edge_connection_margin) {
+ if (other1.distance_squared_to(self1) > sqr_edge_connection_margin) {
continue;
}
@@ -521,7 +523,7 @@ void NavMap::sync() {
} else {
other2 = other_edge_p1.lerp(other_edge_p2, (0.0 - projected_p1_ratio) / (projected_p2_ratio - projected_p1_ratio));
}
- if (other2.distance_to(self2) > edge_connection_margin) {
+ if (other2.distance_squared_to(self2) > sqr_edge_connection_margin) {
continue;
}
@@ -549,11 +551,11 @@ void NavMap::sync() {
const Vector3 end = link->get_end_position();
gd::Polygon *closest_start_polygon = nullptr;
- real_t closest_start_distance = link_connection_radius;
+ real_t closest_start_sqr_dist = link_connection_radius * link_connection_radius;
Vector3 closest_start_point;
gd::Polygon *closest_end_polygon = nullptr;
- real_t closest_end_distance = link_connection_radius;
+ real_t closest_end_sqr_dist = link_connection_radius * link_connection_radius;
Vector3 closest_end_point;
// Create link to any polygons within the search radius of the start point.
@@ -564,11 +566,11 @@ void NavMap::sync() {
for (uint32_t start_point_id = 2; start_point_id < start_poly.points.size(); start_point_id += 1) {
const Face3 start_face(start_poly.points[0].pos, start_poly.points[start_point_id - 1].pos, start_poly.points[start_point_id].pos);
const Vector3 start_point = start_face.get_closest_point_to(start);
- const real_t start_distance = start_point.distance_to(start);
+ const real_t sqr_dist = start_point.distance_squared_to(start);
// Pick the polygon that is within our radius and is closer than anything we've seen yet.
- if (start_distance <= link_connection_radius && start_distance < closest_start_distance) {
- closest_start_distance = start_distance;
+ if (sqr_dist < closest_start_sqr_dist) {
+ closest_start_sqr_dist = sqr_dist;
closest_start_point = start_point;
closest_start_polygon = &start_poly;
}
@@ -581,11 +583,11 @@ void NavMap::sync() {
for (uint32_t end_point_id = 2; end_point_id < end_poly.points.size(); end_point_id += 1) {
const Face3 end_face(end_poly.points[0].pos, end_poly.points[end_point_id - 1].pos, end_poly.points[end_point_id].pos);
const Vector3 end_point = end_face.get_closest_point_to(end);
- const real_t end_distance = end_point.distance_to(end);
+ const real_t sqr_dist = end_point.distance_squared_to(end);
// Pick the polygon that is within our radius and is closer than anything we've seen yet.
- if (end_distance <= link_connection_radius && end_distance < closest_end_distance) {
- closest_end_distance = end_distance;
+ if (sqr_dist < closest_end_sqr_dist) {
+ closest_end_sqr_dist = sqr_dist;
closest_end_point = end_point;
closest_end_polygon = &end_poly;
}