godot icon indicating copy to clipboard operation
godot copied to clipboard

Texture2DRD thumbnail preview fails to generate

Open DDarby-Lewis opened this issue 1 year ago • 1 comments

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 image

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

DDarby-Lewis avatar Sep 29 '24 19:09 DDarby-Lewis

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 avatar Oct 05 '24 23:10 flcoder

@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:

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:

		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.

DDarby-Lewis avatar Feb 12 '25 19:02 DDarby-Lewis

Found the culprit:


		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;

DDarby-Lewis avatar Feb 12 '25 19:02 DDarby-Lewis

Tested a fix:

		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.

DDarby-Lewis avatar Feb 12 '25 23:02 DDarby-Lewis

CC @BlueCube3310

akien-mga avatar Feb 13 '25 07:02 akien-mga