Repository: godotengine/godot (language: cpp)

Issue:
Texture2DRD thumbnail preview fails to generate
### Tested versions

- 4.3 release version

### System information

Godot v4.3.stable - Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 1060 with Max-Q Design (NVIDIA; 31.0.15.3161) - Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz (12 Threads)

### Issue description

I am using Texture2DRD resource as base class for a custom resource for procedural textures.
I have previously written this system using:
- ImageTexture - rather fast (1 - 30 ms) with added utility of images but unfortunately also constantly change their internal IDs thus making their use with git horrible.
- PortableCompressedTexture2D - doesn't change it's IDs - but changing the image is slow (10-100 ms)
- Texture2DRD  - my current attempt, the holy grail in the sense that they don't store any Image data on disk (no huge data arrays OR constantly changing IDs) and are fast enough that not saving the data is actually reasonable (0.1-1 ms). This makes them rather like a NoiseTexture in how they are saved to disk with just their parameters.

I have a nice little compute shader pipeline for generating procedural textures and want to extend this system.

However the use of Texture2DRD  has a couple of issues - I am struggling with formatting (see below), I haven't figured out how to create the mipmaps in the RenderingDevice yet, and have found a bug in this resource with getting errors in the console whenever the resource is edited and then the project saved (recreated by the gdscript below).

The thumbnail for Texture2DRD  fails to generate and a error appears in the console:
```
  Expected Image data size of 8x8x12 (RGBFloat without mipmaps) = 768 bytes, got 1024 bytes instead.
  servers/rendering/renderer_rd/storage_rd/texture_storage.cpp:1302 - Condition "image->is_empty()" is true. Returning: Ref<Image>()
 ```
  I believe this issue is the thumbnail attempting to generate.

You can see in the screenshots the mesh get's the texture's colour applied correctly - but the thumbnail fails to generate.

  Note even though the image RID I am attaching is RGBAFloat it always complains about RGBFloat - I suspect this is the actual issue - i.e. the size is wrong because it is expecting the wrong format.
  
 I also have another issue with this that the format DATA_FORMAT_R32G32B32A32_SFLOAT and it's equivalent image format FORMAT_RGBAF look very different from the format FORMAT_RGBA8 when applied to a material and I cannot apparently use FORMAT_RGBA8 on the rendering device because it doesn't accept the usage bits and thus cannot use it for my procedural texturing - I suspect there is something I need to do the the FORMAT_RGBAF data to make it appear the same as the FORMAT_RGBA8 but I'm not sure what so any advice would be welcome.
  
  
![image](https://github.com/user-attachments/assets/b7e8c12c-cbdb-4c5e-b2f0-191ba93f6f03)
![image](https://github.com/user-attachments/assets/f81d27a5-bc95-4b78-b3ff-d77f5c5a7b54)


### Steps to reproduce

Create a script for a resource inheriting from a Texture2DRD resource in the filesystem and assign it an RID - get the above warning. 
The GD script in MRP will do this.

### Minimal reproduction project (MRP)

```
@tool
class_name TextureRD
extends Texture2DRD

static var rd := RenderingServer.get_rendering_device()

## Build this image
@export var build := false:
    set(v):
        if v:
            _build()


func _build() -> void:
    var format := RDTextureFormat.new()
    format.width = 8
    format.height = 8
    format.usage_bits = (
        RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT
        | RenderingDevice.TEXTURE_USAGE_CAN_UPDATE_BIT
        | RenderingDevice.TEXTURE_USAGE_STORAGE_BIT
        | RenderingDevice.TEXTURE_USAGE_SAMPLING_BIT
        | RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT
    )
    format.format = rd.DATA_FORMAT_R32G32B32A32_SFLOAT
    var view := RDTextureView.new()

    var texture_rid := rd.texture_create(format, view, [])

    rd.texture_clear(texture_rid, Color.AQUA, 0, 1, 0, 1)

    texture_rd_rid = texture_rid

```


Discussion / hints:
I'm having this exact same problem.  When I try to call `Texture2DRD.get_image()` it returns null.  When I change to `R32_SFLOAT` (just red) it seems to work fine.  It would be nice if it worked with `R32G32B32A32_SFLOAT` format as I'm generating noise via compute shader and am able to use 4 channels to have 4 different results in one go, but this strange bug is limiting me to only one channel.
@flcoder that is very similar to my use case - except I am generating images in compute shaders and require the Alpha channel to be present - I think the issue is with the function:
```cpp
Ref<Image> Texture2DRD::get_image() const {
	ERR_FAIL_NULL_V(RS::get_singleton(), Ref<Image>());
	if (texture_rid.is_valid()) {
		return RS::get_singleton()->texture_2d_get(texture_rid);
	} else {
		return Ref<Image>();
	}
}
```
Where this routes to a call to:
```cpp
		image = Image::create_from_data(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data);
```
where for some reason the `validated_format` on tex is wrong (doesn't include the fact that it should have an A channel.


Found the culprit:
```cpp

		case RD::DATA_FORMAT_R32G32B32A32_SFLOAT: {
			r_format.image_format = Image::FORMAT_RGBF;
			r_format.rd_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;
```
Tested a fix: 
``` cpp
		case RD::DATA_FORMAT_R32G32B32A32_SFLOAT: {
			r_format.image_format = Image::FORMAT_RGBAF;
			r_format.rd_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;
```
1 char bug fix to the typo - adding in the missing "A" 
Checked that this is not intentionally missing the alpha channel, other cases with alpha do return the correct values.
Compiled and tested this - it works, thumbnail is now generated.
CC @BlueCube3310 

Fix patch:
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 69ae3d971a4e..5707b993afca 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -2358,7 +2358,7 @@ void TextureStorage::_texture_format_from_rd(RD::DataFormat p_rd_format, Texture
 			r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
 		} break;
 		case RD::DATA_FORMAT_R32G32B32A32_SFLOAT: {
-			r_format.image_format = Image::FORMAT_RGBF;
+			r_format.image_format = Image::FORMAT_RGBAF;
 			r_format.rd_format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
 			r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R;
 			r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G;
@@ -2531,7 +2531,6 @@ void TextureStorage::_texture_format_from_rd(RD::DataFormat p_rd_format, Texture
 			r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
 
 		} break;
-		/* already maps to FORMAT_ETC2_RGBA8
 		case RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
 		case RD::DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: {
 			r_format.image_format = Image::FORMAT_ETC2_RGBA8;
@@ -2542,7 +2541,6 @@ void TextureStorage::_texture_format_from_rd(RD::DataFormat p_rd_format, Texture
 			r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
 			r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
 		} break;
-		*/
 		case RD::DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
 		case RD::DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: {
 			r_format.image_format = Image::FORMAT_ETC2_RGB8A1;
@@ -2553,6 +2551,7 @@ void TextureStorage::_texture_format_from_rd(RD::DataFormat p_rd_format, Texture
 			r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B;
 			r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A;
 		} break;
+		/* already maps to FORMAT_ETC2_RGBA8
 		case RD::DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
 		case RD::DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: {
 			r_format.image_format = Image::FORMAT_ETC2_RA_AS_RG;
@@ -2562,7 +2561,7 @@ void TextureStorage::_texture_format_from_rd(RD::DataFormat p_rd_format, Texture
 			r_format.swizzle_g = RD::TEXTURE_SWIZZLE_A;
 			r_format.swizzle_b = RD::TEXTURE_SWIZZLE_ZERO;
 			r_format.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
-		} break;
+		} break;*/
 		/* already maps to FORMAT_DXT5
 		case RD::DATA_FORMAT_BC3_UNORM_BLOCK:
 		case RD::DATA_FORMAT_BC3_SRGB_BLOCK: {
@@ -2598,6 +2597,10 @@ void TextureStorage::_texture_format_from_rd(RD::DataFormat p_rd_format, Texture
 			// Q: Do we do as we do below, just create the sRGB variant?
 			r_format.image_format = Image::FORMAT_ASTC_8x8;
 			r_format.rd_format = RD::DATA_FORMAT_ASTC_8x8_UNORM_BLOCK;
+			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 RD::DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: {
 			r_format.image_format = Image::FORMAT_ASTC_8x8_HDR;


Test patch: