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

Textures not divided by four are crashing in Chromium #154

Closed
talentlessguy opened this issue Jun 28, 2020 · 14 comments
Closed

Textures not divided by four are crashing in Chromium #154

talentlessguy opened this issue Jun 28, 2020 · 14 comments

Comments

@talentlessguy
Copy link

talentlessguy commented Jun 28, 2020

General question

I need to set compression format to S3TC with basisu CLI but I don't know which flag I should pass in order to enable only s3tc compression.

Detailed quetion

Hello, I want to use basis on my site for loading textures (using BasisTextureLoader from THREE.js). And in order to use it I need the textures to work on all popular webgl engines using s3tc format. I don't know how I should compile my assets with CLI using only s3tc compression.

Reproduction

Firefox 70 + NVIDIA GT740M

They load successfully on Firefox 70 with NVIDIA GT740M card (and OpenGL ES 1.0):

image

And in console there are these warnings (but the texture still loads):

THREE.WebGLRenderer: WEBGL_compressed_texture_astc extension not supported.
THREE.WebGLRenderer: WEBGL_compressed_texture_etc1 extension not supported.
THREE.WebGLRenderer: WEBGL_compressed_texture_pvrtc extension not supported.
THREE.WebGLRenderer: WEBKIT_WEBGL_compressed_texture_pvrtc extension not supported.

MAX Parameters test reports that Firefox rendererer support these things:

EXT_texture_compression_bptc
EXT_texture_compression_rgtc
WEBGL_compressed_texture_etc
WEBGL_compressed_texture_s3tc
WEBGL_compressed_texture_s3tc_srgb

But fails to load in other browsers with other different webgl engines.

WebKit + NVIDIA GT740M

for instance, WebKit (same card) (OpenGL ES 2.0) outputs this:

image

with these warnings:

THREE.WebGLRenderer: WEBGL_compressed_texture_astc extension not supported.
THREE.WebGLRenderer: WEBGL_compressed_texture_etc1 extension not supported.
THREE.WebGLRenderer: WEBGL_compressed_texture_pvrtc extension not supported.
THREE.WebGLRenderer: WEBKIT_WEBGL_compressed_texture_pvrtc extension not supported.

And from MAX Parameters test it supports these:

EXT_texture_compression_bptc
EXT_texture_compression_rgtc
WEBGL_compressed_texture_s3tc
WEBKIT_WEBGL_compressed_texture_s3tc
WEBGL_compressed_texture_s3tc_srgb

Chromium 81 + Intel 4000

Same black screen with these warnings:

THREE.WebGLRenderer: WEBGL_compressed_texture_astc extension not supported.
THREE.WebGLRenderer: EXT_texture_compression_bptc extension not supported.
THREE.WebGLRenderer: WEBGL_compressed_texture_etc1 extension not supported.
THREE.WebGLRenderer: WEBGL_compressed_texture_pvrtc extension not supported.
THREE.WebGLRenderer: WEBKIT_WEBGL_compressed_texture_pvrtc extension not supported.

While these extensions are supported:

EXT_texture_compression_rgtc
WEBGL_compressed_texture_s3tc
WEBKIT_WEBGL_compressed_texture_s3tc
WEBGL_compressed_texture_s3tc_srgb

I noticed however, that WEBGL_compressed_texture_s3tc is the most supported webgl extension in popular browsers.

What I want to do is to compile a png image to basis only with s3tc compression. I couldn't find how to do it in readme (sorry if it is written how but I didn't find it).

I would be thankful if someone showed me a way to do it.

Additional Context

live example: https://v1rtl.site/
source code: https://github.com/talentlessguy/v1rtl_site
Three.js BasisTextureLoader docs: https://threejs.org/docs/#examples/en/loaders/BasisTextureLoader

@donmccurdy
Copy link

When the CLI tool creates a Basis texture, it's in an intermediate "universal" format. That format can be transcoded — at runtime, by THREE.BasisTextureLoader — to any compatible format, including S3TC / DXT. If this transcoding works on some devices and not others, it's likely to be a bug in the loader (or, perhaps, a very rare device / GPU issue).

Could you create a standalone example of this (i.e. a three.js demo that just loads the texture and no more) and start a thread on https://discourse.threejs.org/? It may be a bug, but I can't really tell from the website you shared.

@talentlessguy
Copy link
Author

@donmccurdy thanks for the response!

Here is the code where I load my texture:

const { gl } = useThree() // WebGL context

  const texture = useLoader(BasisTextureLoader, `/basis-sites/pic.basis`, (loader) => {
    loader.setTranscoderPath('/basis/')
    // detect browser support
    loader.detectSupport(gl)
  })

  useEffect(() => {
    // set texture wrapping on mount
    texture.wrapS = texture.wrapT = RepeatWrapping
  }, [texture])

I will setup a THREE.js demo soon and post it here in the thread, and will also ask on 3js forum

@talentlessguy
Copy link
Author

@donmccurdy here is a THREE.js only demo:

var loader = new BasisTextureLoader()
loader.setTranscoderPath('/basis/')
loader.detectSupport(renderer)
loader.load(
  '/provalwiki.basis',
  texture => {
    texture.encoding = THREE.sRGBEncoding
    material.map = texture
    material.needsUpdate = true
  },
  undefined,
  error => console.error(error)
)

code: https://github.com/talentlessguy/three-basis

demo: https://three-basis.vercel.app/

I've sent the demo to 2 people, here's what we have:

Intel HD 3000

output:

image

console:

image

Intel UHD 630

output:

jikv

console:

image

Now I will open the issue on THREE.js forum

@kenrussell
Copy link
Contributor

Submitter, could you please post the link to the Three.js discourse forum thread once it's posted there?

Is this related to the bug that was filed recently against Chromium: http://crbug.com/1100834 ? It looks like some of Chromium's validation of compressed textures' sizes is too strict. This will be fixed.

This can probably be worked around by resizing the textures so the width and height are each divisible by 4.

I think this specific issue against Basis Universal should be closed.

@talentlessguy
Copy link
Author

@kenrussell yes I was busy a little bit and will create an issue on 3js forum tomorrow

about the Chromium bug - hm yeah probably this is the reason

I will resize my images for width and height to be divisible by 4 and see if it persists and in case it does, I will write to the thread

@talentlessguy
Copy link
Author

talentlessguy commented Jul 2, 2020

Update: I resized all my images and now they seem to be working even in Chromium

demo: https://three-basis.vercel.app/

Solution

Resize textures to be divided by four.

and also another update, I've created the issue on 3js forum: https://discourse.threejs.org/t/basistextureloader-crashes-on-textures-divided-by-four-in-chromium/16728

@talentlessguy talentlessguy changed the title [Question] Set compression format in CLI Textures not divided by four are crashing in Chromium Jul 2, 2020
@zeux
Copy link
Contributor

zeux commented Jul 2, 2020

Is this related to the bug that was filed recently against Chromium: http://crbug.com/1100834 ? It looks like some of Chromium's validation of compressed textures' sizes is too strict. This will be fixed.

Please note that as per D3D11 specification, this restriction can not be lifted assuming ANGLE is targeting D3D11 (unless ANGLE does some sort of fixup, resizing the texture to meet this requirement dynamically):

https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#19.5.1%20Overview

BC format surfaces are always multiples of full blocks, each block representing 4x4 pixels. For mipmaps, the top level map is required to be a multiple of 4 size in all dimensions.

@zeux
Copy link
Contributor

zeux commented Jul 2, 2020

Since the sample from the crbug worked for me on Windows I was curious as to how this is possible and decided to look into what ANGLE actually is doing.

Based on reading the source code, it looks like trying to load a texture with width/height not divisible by 4 may require up to 16x more memory, e.g. 513x513 BCn texture would be backed by a 2052x2052 BCn texture? (and mips 0 & 1 would be skipped during texture sampling).

See d3d11::MakeValidSize function: https://github.com/google/angle/blob/master/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp#L2124-L2149

@kenrussell
Copy link
Contributor

Thanks @zeux for pointing that out. Added that information to http://crbug.com/1100834 . If this is a restriction imposed by D3D11 then yes, WebGL will have to enforce it on all platforms, and further, the WebGL extensions will need to be updated to explicitly call out that restriction.

@kenrussell
Copy link
Contributor

@zeux ANGLE's really scaling up the texture that hugely? Please comment on http://crbug.com/1100834 . We'll make sure to do all the necessary follow-ups there, including filing follow-on issues here about warning/erroring if compressing textures intended for transcoding into a WebGL app.

@zeux
Copy link
Contributor

zeux commented Jul 2, 2020

@kenrussell Yup, thanks - left a comment there. My findings need to be validated since I'm not an expert in ANGLE, but if this all is confirmed then lifting the requirements in Chrome may be dangerous and a better route would be to round the sizes in basisu itself during encoding, since otherwise some textures won't be loadable efficiently in ANGLE, or at all in native applications...

@zeux
Copy link
Contributor

zeux commented Jul 2, 2020

@kenrussell Ok I've read all of this more carefully and I believe there's conflation between this issue and the crbug.

crbug says that right now, it's impossible to load a BPTC texture with a full mip chain because of the overly strict validation. This is because in a power-of-two texture, the small mip levels will necessarily go down to 1xX or 2xX. This is why S3TC extension says:

When level equals zero width and height must be a multiple of 4. When level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4.

Which enforces the restriction of divisibility by 4 on the top level (which is the only restriction D3D11 has), and additionally enforces a restriction that every level has to be divisible by 4 or 1/2 (how can width/height be 0 is beyond me, might be a spec bug). This effectively says that these textures must be power of two in size if they were to have mip levels.

This issue seems to talk about cases where the top level isn't divisible by 4. Indeed, I confirmed that when trying to encode a texture like this, it can't be loaded (via three.js) by Chrome on Windows, and likely any other browsers that do correct spec validation using S3TC because of the restriction above.

Now, there's a separate problem with BPTC where the spec (https://www.khronos.org/registry/webgl/extensions/EXT_texture_compression_bptc/) doesn't have any restrictions on the size which means it's not implementable in D3D11, but that's orthogonal to the issue here.

@kenrussell
Copy link
Contributor

@zeux thanks for your detailed feedback here and on http://crbug.com/1100834 - progress has been made on the Chromium bug.

If more restrictions should be added to basisu to ensure that its output is more compatible with the web (via WebGL, anyway) - let's please file more follow-on issues here.

@zeux
Copy link
Contributor

zeux commented Jul 14, 2020

I've filed an issue for this on KTX-Software repository, see KhronosGroup/KTX-Software#254.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants