Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KTX2Loader: Return DataTexture for uncompressed formats #29922

Closed
ligaofeng0901 opened this issue Nov 19, 2024 · 11 comments
Closed

KTX2Loader: Return DataTexture for uncompressed formats #29922

ligaofeng0901 opened this issue Nov 19, 2024 · 11 comments

Comments

@ligaofeng0901
Copy link
Contributor

Description

So far, KTX2Loader doesn't work with WebGPURenderer. If we forcely use it in WebGPURenderer. some errors occur.

WebGPUTextureUtils.js:642 Uncaught TypeError: Cannot read properties of undefined (reading 'width')
    at WebGPUTextureUtils._copyCompressedBufferToTexture (WebGPUTextureUtils.js:642:1)
    at WebGPUTextureUtils.updateTexture (WebGPUTextureUtils.js:370:1)
    at WebGPUBackend.updateTexture (WebGPUBackend.js:1146:1)
    at Textures.updateTexture (Textures.js:243:1)
    at Bindings._init (Bindings.js:99:1)
    at Bindings.getForRender (Bindings.js:33:1)
    at Bindings.updateForRender (Bindings.js:79:1)
    at WebGPURenderer._renderObjectDirect (Renderer.js:1714:1)
    at WebGPURenderer.renderObject (Renderer.js:1658:1)
    at WebGPURenderer._renderObjects (Renderer.js:1597:1)

Solution

Maybe there is another way to load ktx2?

Alternatives

Additional context

No response

@Mugen87
Copy link
Collaborator

Mugen87 commented Nov 19, 2024

KTX2Loader does in general work with WebGPURenderer (see https://threejs.org/examples/webgpu_loader_gltf_compressed) but it seems you are trying to load a KTX2 texture that holds uncompressed RGBA data.

The root cause of the runtime error is explained in #29904 (comment).

My preferred solution is that loaders return instances of DataTexture in this case. CompressedTexture should only hold compressed data.

We handled compressed textures differently in WebGLRenderer but this might be a good opportunity to change the behavior. In general, we try to adapt better approaches in WebGPURenderer even if that means it takes longer to support all existing use cases.

@ligaofeng0901
Copy link
Contributor Author

KTX2Loader does in general work with WebGPURenderer (see https://threejs.org/examples/webgpu_loader_gltf_compressed) but it seems you are trying to load a KTX2 texture that holds uncompressed RGBA data.

The root cause of the runtime error is explained in #29904 (comment).

My preferred solution is that loaders return instances of DataTexture in this case. CompressedTexture should only hold compressed data.

Thanks! I will dive deeper into it and try to find it out.

@donmccurdy donmccurdy changed the title Ktx2 support for WebGPURenderer KTX2Loader: Support WebGPURenderer when transcoding to uncompressed format Nov 19, 2024
@donmccurdy
Copy link
Collaborator

donmccurdy commented Nov 19, 2024

@Mugen87 I plan to fix the case you're describing, see #29926.

However, are you sure that's what's happening here, and can we reproduce that? I'm not sure what device that supports WebGPU would not also support at least one of the possible compressed target formats for Basis Universal, such that it would fall back to the final option, RGBAFormat.

If the data in the KTX2 was uncompressed to begin with (not Basis Universal) then it should already be creating a DataTexture here:

if ( UNCOMPRESSED_FORMATS.has( FORMAT_MAP[ vkFormat ] ) ) {
texture = container.pixelDepth === 0
? new DataTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight )
: new Data3DTexture( mipmaps[ 0 ].data, container.pixelWidth, container.pixelHeight, container.pixelDepth );
} else {
if ( container.pixelDepth > 0 ) throw new Error( 'THREE.KTX2Loader: Unsupported pixelDepth.' );
texture = new CompressedTexture( mipmaps, container.pixelWidth, container.pixelHeight );
texture.minFilter = mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter;
texture.magFilter = LinearFilter;
}

But maybe I've missed something, I'm not sure how to reproduce this.

@donmccurdy donmccurdy changed the title KTX2Loader: Support WebGPURenderer when transcoding to uncompressed format KTX2Loader: Return DataTexture for uncompressed formats Nov 19, 2024
@ligaofeng0901
Copy link
Contributor Author

@Mugen87 @donmccurdy Sorry, the issue I met is cased by there code in my app:

const ktx2Loader = new KTX2Loader();
const renderer = new WebGPURenderer();
ktx2Loader.detectSupport(renderer);

The main reason is we invoke ktx2Loader.detectSupport before the renderer inited. After changing detectSupport to detectSupportAsync, it works. I hope my mistake didn’t mislead you.

We handled compressed textures differently in WebGLRenderer but this might be a good opportunity to change the behavior. In general, we try to adapt better approaches in WebGPURenderer even if that means it takes longer to support all existing use cases.

KTX2Loader is good in my use case. This may be an another issue.

@Mugen87
Copy link
Collaborator

Mugen87 commented Nov 20, 2024

Without a correct usage of detectSupport(), things can be indeed misleading since the loader does not work as expected to begin with. If you are not encountering any issues anymore when using the method correctly, that's great.

@ligaofeng0901
Copy link
Contributor Author

Thing goes good now, close the issue.

@ligaofeng0901
Copy link
Contributor Author

Also, It may be better If we add a warning here If rendered is not inited.
https://github.com/mrdoob/three.js/blob/dev/examples/jsm/loaders/KTX2Loader.js#L144
This can help users who migrating from WebGL version, like render method in WebGPURenderer.

@Mugen87
Copy link
Collaborator

Mugen87 commented Nov 20, 2024

It is not yet possible to check with a public API whether the renderer has been initialized or not. The _initialized property is private.

@ligaofeng0901
Copy link
Contributor Author

ligaofeng0901 commented Nov 20, 2024

The _initialized property is private.

It really is, I think it should be an open API. One case we met is, we invoke dispose of WebGPURenderer before it is inited, it casues some errors. So I use _initialized to check the state of renderer

@Mugen87
Copy link
Collaborator

Mugen87 commented Nov 20, 2024

@sunag How about adding a hasInitialized() method to Renderer (since we already have hasFeature()).

It would allow apps to check the state of the renderer without accessing the private _initialized which is for internal use only. When we switch to real private properties at some point, #initialized won't be accessible anymore.

@sunag
Copy link
Collaborator

sunag commented Nov 20, 2024

@sunag How about adding a hasInitialized() method to Renderer (since we already have hasFeature()).

Yes, it can be useful.👍

@Mugen87 Mugen87 added this to the r171 milestone Nov 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants