On desktop, GL_RGB16F works fine, but in the iOS SDK I have to move to the _EXT version. This call throws GL_INVALID_OPERATION. The glTexImage2D docs only generates that error in situations when loading image data (which I'm not, hence the NULL parameter to data), depth textures and when playing with pixel unpackings. Looked into texture_storage and float_texture extension docs, but nope...

I can't find any (correct) docs on setting up float FBO:s on iOS, and I don't know how to dig deeper into the error state than this.

Ah, that's it. Just to clarify something I've been wondering about and can't seem to get my head around: how does type and format factor into the storage? Before this, I was under the impression that those described the data in, eh, data, but I'm mistaken, right?

I really just need a single signed half-float component for this effect, but without memory savings, and from what I hear, no performance savings, there's no point in pursuing GL_R/GL_RED/GL_LUMINANCE?

Hm, GL_RED_EXT does seem to bring be from 15 FPS up to around 22 FPS, but I'm seeing badly botched rendering. I'm rendering from a GL_RGB FBO into a GL_RED_EXT FBO (a vector-to-value operation, think particle sim).

EDIT: I just found out about glBindFragDataLocation, but it doesn't seem to be available in ES. It does suggest that writing four values into gl_FragColor is causing the repetition, and the pattern is broken by the tiler?

I'm drawing a single splat in the center of the screen, but I also get a smattering of smaller splats all over.

There seems to be some sort of pattern but I can't really make it out. Can this be caused by mixing 3-channel and 1-channel texture samplers in a single shader? Am I doing something wrong when writing four values into gl_FragColor on a 1-channel FBO?

I haven't done my homework on this one, just a braindump, so please to point me to docs or similar if it works as intended.

Yes, 0x8d61 is GL_HALF_FLOAT_OES, and why does my 0 for data turn up as 0x3e2eb3c2 in this error? I use the exact same code path for all texture setup. No other GL errors (through glGetError at least).

(Jan 9, 2013 03:15 PM)Fenris Wrote: how does type and format factor into the storage? Before this, I was under the impression that those described the data in, eh, data, but I'm mistaken, right?

<format> and <type> describe <data>. The data that your app is passing to the GL. <internalformat> is your request for how you want the GL to store the data.

In desktop GL, this transfer of data during TexImage can be pretty complicated. There is a state machine of the glPixelStore and glPixelTransfer state describing how to unpack each pixel, optionally process (scale, bias, map, convolve, histogram etc) and store the pixel (in, presumably, "VRAM".) There are zillions of possible conversions here, both in format (i.e. RGB -> LUMINANCE) and type (i.e. FLOAT -> UNSIGNED_BYTE).

Desktop GL supports this stuff because, as a "graphics library" it is providing common image processing utility. For example getting RGBA, UNSIGNED_BYTE data from your jpg/png/tiff loader, and converting it to RGB 565 for a texture. Or runtime-compressing it to DXT, RGTC, etc to save even more memory. Another reason is that <internalformat> is just a request; there are a bunch of internalformats like GL_LUMINANCE6_ALPHA2 which are unlikely to really be supported in hardware (perhaps they were on SGI workstations, 20 years ago). The driver is free to choose a similar format (like GL_LUMINANCE8_ALPHA8) instead, and conversions might be required.

However in many applications, there are no conversions, and in GLES, this functionality was deleted along with a bunch of the other desktop API. So the meaning of the arguments changes somewhat. ES1 changed the specification so that <internalformat> has to "match" <format>; no sized <internalformats> are allowed, and the valid combinations of <format> and <type> are strictly limited. So the effective internalformat chosen by the driver is supposed to be derived from <format> and <type>.

Reading between the lines, the intent of this was to eliminate all format conversions, serving two purposes: 1) all potentially "slow" conversion is shifted out of run-time to your app compile-time (you are expected to pre-process data and ship it in a "fast" format), and 2) the complexity (engineering and testing) of the image state machine can be deleted out of the driver, reducing bugs etc.

Of course that intent falls short in practice: 1) there are usage patterns where you need run-time conversion (like streaming pngs from a url; you might really want 565 or 4444 textures for memory savings) and that means every app gets to re-implement this functionality instead of the driver implementing it once (with multithreading and vector optimizations appropriate for every device; the OS/driver provider can do a better job at this than average developers) and 2) ES1 left a big gaping hole in the spec: CopyTexImage still requires format conversions to be supported in the driver, so that complexity is still there.

Then ES2 added sized <internalformat> for renderbuffers. But left TexImage the same as ES1, so is self-inconsistent and confusing.

The recently announced ES3 spec re-adds sized <internalformat> for TexImage, and the pile of new texture formats (integer, RGB9_E5 etc) are only available that way. This is a pretty clear recant of the broken ES1/ES2 changes. ES3 also allows a limited set of <type> conversions during TexImage, catering to cases like streaming images over the web. But the ES3 spec is still self-inconsistent, as BlitFramebuffer (and to a lesser degree CopyTexImage) allow any <format>,<type> conversion while TexImage is artificially constrained.

Quote:I really just need a single signed half-float component for this effect, but without memory savings, and from what I hear, no performance savings, there's no point in pursuing GL_R/GL_RED/GL_LUMINANCE?

On iOS devices, RED and RG really will save memory compared to RGB or RGBA.
(Hardware likes to have power-of-two byte sizes for texels, so RGB is typically stored internally as RGBX.) Performance wins from RED or RG will simply be due to bandwidth reductions during sampling or framebuffer writes.

Quote:glBindFragDataLocation...doesn't seem to be available in ES. It does suggest that writing four values into gl_FragColor is causing the repetition, and the pattern is broken by the tiler?

BindFragDataLocation is only meaningful for MRT where you need to direct multiple fragment outputs to multiple FBO attachments. ES2 does not support MRT (there is no DrawBuffer API) and all fragment outputs default to FragDataLocation zero at program link time, i.e the single COLOR_ATTACHMENT0.

In ES2, gl_FragColor is a vec4. If your COLOR_ATTACHMENT0 has fewer than four components, the rules in "Conversion to Framebuffer-Attachable Image Components" apply. In your case, gl_FragColor.r will be written to a RED attachment. (gl_FragColor.a is still meaningful for raster operations like blending or alpha-to-coverage. gl_FragColor.gb will be ignored.)

Is that actually throwing INVALID_ENUM? That seems like a bug in the dev tools. The GL ultimately is mallocing storage for your NULL request, so perhaps the devtool is showing that pointer. But you'd hope it shows your original API arguments, so that also seems like a bug.

Wow, what a reply! :o
Thanks for taking the time. I still can't get it to run properly, but I'm fairly sure it's my fault again.

So, now I get why I was confused about teximage, quite a bit of stuff to track, and it explains why it worked here but not there and vice versa. I think I've got that part under control now, but a bit of history is always illuminating.

Quote:Performance wins from RED or RG will simply be due to bandwidth reductions during sampling or framebuffer writes.

...and yeah, quite a bit of performance - an extra 40% since I'm hitting those single-channel FBO:s quite a few times per frame.

Quote:In this case, gl_FragColor.r will be written to a RED attachment.
...I'm seeing badly botched rendering.

Yeah, I figured that one out. I was doing gl_FragColor = tex2D(...) + <float> when I should have done gl_FragColor = tex2D(...) + vec4.x; Not sure why it caused the splattering, but it works and I can see I was wrong.

Quote:Is that actually throwing INVALID_ENUM?

Turns out it wasn't. I'll see if I can replicate in a smaller example, and I'll radar it.

Again, thanks. I think this is sorted, and I'll come back if the current problems aren't obvious mistakes.

Quote:Yeah, I figured that one out. I was doing gl_FragColor = tex2D(...) + <float> when I should have done gl_FragColor = tex2D(...) + vec4.x; Not sure why it caused the splattering, but it works and I can see I was wrong.

OK, now I've spent a couple of days digging. I had an interesting bug where a number of black squares appeared randomly in one of my framebuffers and grew with every render pass. I clamped down a value that might have gone NaN (or whatever the shader equivalent is) and that seems to have fixed it. If this seems serious, I can probably provide a pretty reproduction case.

OSC: I can't exactly remember my earlier configuration, but there was a difference:

I embrace that the latter version will add f to all channels of the texture. However, if the texture is HALF_FLOAT, GL_RED_EXT, then I got the spattered rendering above. I can sort of see it happen, but I'm not sure it's koscher.

Quote:If the framebuffer is used to perform offscreen image processing, attach a renderbuffer. [...] If the framebuffer image is used as an input to a later rendering step, attach a texture.

I'm doing both, I guess. I'm running a multi-stage shader effect that does, well, image processing offscreen. However, each stage is an input to a later render stage (I render quads with the previous stage's texture as input). I should still use texture attachments, right?

If you need the image afterward, you should use a texture attachment. If you don't (eg. it's a depth or stencil buffer you never need again), you should use a renderbuffer attachment.

The EXT_texture_rg spec seems clear that x will be from the texture, y and z will be 0, and w will be 1, so if you think you're not seeing that, or think that specific instructions in the shader are voiding that guarantee, it is worth filing a bug.