24bit depth buffer with WebGL 1.0 - webgl

I've found that there's no GL_DEPTH_COMPONENT24_OES renderbuffer storage equivalent in WebGL. But there's WEBGL_depth_texture extension that I can use to make a 24_8 or 32bit depth texture. Are those the DEPTH_COMPONENT24/DEPTH_COMPONENT32 renderbuffer equivalent? It would work the same as the screen buffer?
Is this the reason why they didn't make 24/32bit depth renderbuffer for WebGL?

There's a way to allocate 24 bit depth buffer in WebGL 1: DEPTH_STENCIL. Here's a test: http://jsbin.com/tadikibidi/edit?js,output. That's not actually true. The whereas the spec doesn't explicitly specifies sizes of components of DEPTH_STENCIL buffer, conformance tests suggest that the only requirement is for DEPTH to have >= 16 bit and >= 8 bit for STENCIL. It seems that the only way (at least w/o extensions) would be to allocate a DEPTH_STENCIL attachment and check DEPTH_BITS parameter of a framebuffer the attachment's attached to.
AFAIK, 32bit depth buffers a harder to get on mobile devices, thus WebGL doesn't have them (only with extensions).

What the spec doesn't also say about is that DEPTH_STENCIL is just an abstraction. WebGL implementations, especially the older ones, can implement DEPTH_STENCIL by bundling one depth buffer and one stencil buffer under the hood. So a DEPTH_STENCIL renderbuffer can be anything: 16/8(if 24 is not supported), 24/8(with extension) and so on. And the conformance test implies that the depth buffer is at least 16bit.
They came up with this abstraction and didn't even give a simple anatomy of what it is. Just this line pops out of nowhere:
WebGL adds DEPTH_STENCIL renderbuffer
The mailing list archive.

Related

WebGL: does using a single-channel texture format actually save (texture) memory?

From the Khronos ref pages:
GL_LUMINANCE: Each element is a single luminance value. The GL
converts it to floating point, then assembles it into an RGBA element
by replicating the luminance value three times for red, green, and
blue and attaching 1 for alpha.
Does this apply to WebGL too? If so, does this imply that using textures formatted with less channels such as LUMINANCE does not save VRAM compared to using RGBA?
And how about RAM?
Does this apply to WebGL too?
Yes it does
does this imply that using textures formatted with less channels such as LUMINANCE does not save VRAM compared to using RGBA
No, while this is implementation specific(and some implementations do actually choose to expand the data to RGBA before uploading) the expansion ought to happen on the fly, basically just providing one and the same value for every color component when sampling from such a texture within a shader.
And how about RAM?
Once you call texImage2D the data is uploaded to VRAM and not kept in RAM as long as you don't do so(e.g. by holding on to a reference of the data).
GL_LUMINANCE was deprecated and removed in OpenGL 3.2. Nowadays you specify the internal format explicitly with enums like GL_R8. Implementations allocate their internal storage with the specified format (even though this guarantee isn't there in the OpenGL spec, as per the as-if rule). I recommend not to use GL_LUMINANCE in WebGL either. Just use the explicit internal format and expand it in the shader as needed, or though texture swizzles.

in-place processing of a Metal texture

Is it possible to process an MTLTexture in-place without osx_ReadWriteTextureTier2?
It seems like I can set two texture arguments to be the same texture. Is this supported behavior?
Specifically, I don't mind not having texture caching update after a write. I just want to in-place (and sparsely) modify a 3d texture. It's memory prohibitive to have two textures. And it's computationally expensive to copy the entire texture, especially when I might only be updating a small portion of it.
Per the documentation, regardless of feature availability, it is invalid to declare two separate texture arguments (one read, one write) in a function signature and then set the same texture for both.
Any Mac that supports osx_GPUFamily1_v2 supports function texture read-writes (by declaring the texture with access::read_write).
The distinction between "Tier 1" (which has no explicit constant) and osx_ReadWriteTextureTier2 is that the latter supports additional pixel formats for read-write textures.
If you determine that your target Macs don't support the kind of texture read-writes you need (because you need to deploy to OS X 10.11 or because you're using an incompatible pixel format for the tier of machine you're deploying to), you could operate on your texture one plane at a time, reading from your 3D texture, writing to a 2D texture, and then blitting the result back into the corresponding region in your 3D texture. It's more work, but it'll use much less than double the memory.

Speed difference between updating texture or updating buffers

I'm interesting about speed of updating a texture or buffer in WebGL.
(I think this performance would be mostly same with OpenGLES2)
If I needs to update texture or buffer one time per frame which contains same amount of data in byte size, which is good for performance?
Buffer usage would be DRAW_DYNAMIC and these buffer should be drawed by index buffers.
This would be really up to the device/driver/browser. There's no general answer. One device or driver might be faster for buffers, another for textures. There's also the actual access. Buffers don't have random access, textures do. Do if you need random access your only option is a texture.
One example of a driver optimization is if you replace the entire buffer or texture it's possible for the driver to just create a new buffer or texture internally and then start using it when appropriate. If it doesn't do this and you update a buffer or texture that is currently being used, as in commands have already been issued to draw something using the buffer or texture but those commands have not yet been executed, then the driver would have to stall your program, wait for the buffer or texture to be used, so it can then replace it with the new contents. This also suggests that gl.bufferData can be faster than gl.bufferSubData and gl.texImage2D can be faster than gl.texSubImage2D but it's only can be. Again, it's up to the driver what it does, what optimizations it can and can't, does and doesn't do.
As for WebGL vs OpenGL ES 2, WebGL is more strict. You mentioned index buffers. Well, WebGL has to validate index buffers. When you draw it has to check that all the indices in your buffer are in range for the currently bound and used attribute buffers. WebGL implementations cache this info so they don't have to do it again but if you update an index buffer the cache for that buffer is cleared so in that case updating textures would probably be faster than updating index buffers. On the other hand it comes back to usage. If you're putting vertex positions in a texture and looking them up in the vertex shader from the texture vs using them in a buffer I while updating the texture might be faster rendering vertices doing texture lookups is likely slower. Too slow is again up to your app and the device/driver etc...

sRGB on iOS OpenGL ES 2.0

According to very few related topics that I could find I am gathering that the exponentiation step to obtain proper lighting computations perhaps must be done within the final fragment shader on an iOS app.
I have been profiling with the latest and greatest Xcode 5 OpenGL debugger and the exponentiation of the fragment accounts for a significant amount of computation. It was the line that took the longest time in the entire shader (the rest of the performance got sucked out by the various norm calls needed for point-lights).
glEnable(GL_FRAMEBUFFER_SRGB); unfortunately does not work as GL_FRAMEBUFFER_SRGB is not declared.
Of course the actual enum I should be using for GL ES may be different.
According to Apple:
The following extensions are supported for the SGX 543 and 554
processors only:
EXT_color_buffer_half_float
EXT_occlusion_query_boolean
EXT_pvrtc_sRGB
EXT_shadow_samplers
EXT_sRGB
EXT_texture_rg
OES_texture_half_float_linear
Well, that's nice, the newest device that does not have a 543 or 554 is the iPhone 4.
From the extension's text file it looks like I can set SRGB8_ALPHA8_EXT to the internalformat parameter of RenderbufferStorage, but nothing is said of how to get the normal final framebuffer to apply sRGB for us for free.
Now the sRGB correction seems like the missing step to get the correct colors. What I've been doing in my app to deal with the horrible "underexposed" colors is manually applying gamma correction like this in the fragment shader:
mediump float gammaf = 1.0/1.8; // this line declared outside of `main()`
// it specifies a constant 1.8 gamma
mediump vec4 gamma = vec4(gammaf, gammaf, gammaf, 1.0);
gl_FragColor = pow(color, gamma); // last line of `main()`
Now I recognize that the typical render pipeline involves one or more renders to a texture followed by a FS quad draw, which will afford me the opportunity to make use of an SRGB8_ALPHA_EXT renderbuffer, but what am I supposed to do without one? Am I SOL?
If that is the case, the pow call is sucking up so much time that it almost seems like I can squeeze some more perf out of it by building a 1D texture to sample and use as a gamma lookup table. This texture could then be used to tweak the output color intensities in custom ways (and get a much better approximation to sRGB compared to just the raw exponentiation). But it just all seems kind of wrong because supposedly sRGB is free.
Also somewhat alarming is the absence of any mention of the string srgb anywhere in the GL ES 2.0 spec. According to the makers of glm GL ES simply ignores sRGB entirely.
I know that I have used my code to render textures (I made a basic OpenGL powered image viewer that renders PVRTC textures) and they did not get "dimmed". I think what is happening there is that due to GL ES 2's lack of sRGB awareness, the textures are loaded in as being in linear space and written back out in the same way. In that situation, since no lighting gets applied (all colors got multiplied by 1.0) nothing bad happened to the results.
iOS 7.0 adds the new color format kEAGLColorFormatSRGBA8, which you can set instead of kEAGLColorFormatRGBA8 (the default value) for the kEAGLDrawablePropertyColorFormat key in the drawableProperties dictionary of a CAEAGLLayer. If you’re using GLKit to manage your main framebuffer for you, you can get GLKView to create a sRGB renderbuffer by setting its drawableColorFormat property to GLKViewDrawableColorFormatSRGBA8888.
Note that the OpenGL ES version of EXT_sRGB behaves as if GL_FRAMEBUFFER_SRGB is always enabled. If you want to render without sRGB conversion to/from the destination framebuffer, you’ll need to use a different attachment with a non-sRGB internal format.
I think you are getting confused between the EXT_sRGB and the ARB_framebuffer_sRGB extensions. The EXT_sRGB is the more recent extension, and is the one supported by iOS devices. This differs from ARB_framebuffer_sRGB in one important way, it is not necessary to call glEnable(GL_FRAMEBUFFER_SRGB) on the framebuffer to enable gamma correction, it is always enabled. All you need to do is create the framebuffer with an sRGB internal format and render linear textures to it.
This is not hugely useful on its own, as textures are rarely in a linear colour space. Fortunately the extension also includes the ability to convert sRGB textures to linear space. By uploading your textures with an internal format of sRGB8_ALPHA8_EXT, they will be converted into linear space when sampled in a shader for free. This allows you to use sRGB textures with a better perception encoded colour range, blend in higher precision linear space, then encode the result back to sRGB in the render buffer without any shader cost and accurate gamma correction.
Here are my test results. My only iOS7 device is an A7-powered iPad5, and in order to test fillrate I had to tweak my test app a bit to enable blending. That was sufficient on iOS 6.1 to prevent fragment-discarding optimizations on opaque geometry, but for iOS 7 I also needed to write gl_FragColor.w != 1.0 in the shader. Not a problem.
Using the GLKViewDrawableColorFormatSRGBA8888 does indeed appear to be free or close to free in terms of performance. I do not have a proper timedemo style benchmark setup so I am just testing "similar" scenes and the removal of the pow shaved around 2ms off the frame time (which would e.g. take 43ms to 41ms, 22 fps to 24 fps). Then, setting the sRGB framebuffer color format did not introduce a noticeable increase in the frame time as reported by the debugger, but this isn't very scientific and it certainly could have slowed it by a half a millisecond or so. I can't actually tell if it is completely free (i.e. fully utilizing a hardware path to perform final sRGB transformation) without first building more benching software, but I already have the problem solved so more rigorous testing will have to wait.

Multisampling on iOS can't get depth texture?

I have set up rendering to a framebuffer with color and depth textures on iOS, all works ok. I then tried to add multisampling via APPLE extensions (I used this code Rendering to texture on iOS OpenGL ES—works on simulator, but not on device ) but there's a catch apparently.
After resolving the multisampled buffer into my original framebuffer (which I use for post processing effects), I only have the color buffer resolved. glResolveMultisampleFramebufferAPPLE() apparently does not touch my depth texture at all, so if I use multisampling I have to give up on my depth texture effects. Is there no way to get the depth texture if I use multisampling ? I know how multisampling works, I just want a depth texture alongside the color texture.
Spec on APPLE_framebuffer_multisample tells that glResolveMultisampleFramebufferApple resolves color attachment, this means that you will have to write depth to color renderbuffer in additional render pass and resolve it to get depth information.
Ok, so after a couple more days of looking into this matter, I got my answer.
So the APPLE extension exists (and is different from the EXT one) just because it only resolves color. The GL ES 3.0 Standard (Probably coming to iOS 7.1) or DesktopGL says that in order to resolve Color or Depth you use glBlitFramebuffer which copies and resolves things. I tried it with DesktopGL 4.2 and blitting the depth buffer works.
I also went back to my DirectX11 renderer and tried the same thing with a GPU that Supports DirectX 11.1 level features and I was surprised that leading edge hardware can't do that in a single resolve call. ID3D11DeviceContext::ResolveSubresource throws errors when you try to resolve textures bound as depth. The workaround is to either have a special shader pass that does the depth resolving, but that implies using Texture2DMS ( A DirectX 10_1 level feature ) or to ping-pong the texture through 2 separate textures that are not bound to depth (implies 1 resolve call and 2 full depth texture copies).
Using the same counterpart in GL means using glTexImage2DMultisample images instead of multisampled renderbuffers (part of Desktop OpenGL 3.1) and then using sampler2DMS in a pixel shader for the actual shader texel fetch.
EDIT: Whether or not glBlitFramebuffer resolves depth seems to be marked as implementation dependent. On desktop GL (HD7850) it works, on GLES3 it still doesn't resolve it.

Resources