4.4 Collection of "improvable" wordings

Hello, a while ago I stated that I find the specification unclear in certain passages but I wouldn’t give a concise description of what exactly I find unclear as a whole. I still can’t, but I figured what I could do is collect those passages which a) I find unclear/ambiguously written and of which b) I still think they are unclear after their intended meaning has been explained to me (credits go to the fellow developers on IRC which patiently answer all of the many questions which I find). I’ll refer to them as they appear in the 4.4 core spec and add a short commentary on each and what I think should be done better/differently.

As far as the forum permits it, I’ll edit this post. Otherwise I’ll just add new posts.

Please note that (although I do have my share of problems with how the API is designed by itself) my points attempt not to address design but just how the API (as it is) is described. If you think that at points I’m to blame for not understanding the meaning properly or that what I suggest is not suitable, please let me know.

Starting with…

4.4.1 WaitSync - Bug 1071 - It is unclear what exactly it means if the “server waits”. Naively (and that’s what I understood at first), one could interpret this as that everything on the “server side” (=== not client side) completely “freezes” until a condition is met (say, a FenceSync is passed). If one iterprets it like that, we could construct the following situation:

Client issues commands a( ), b( ), c( ), d( ), e( ), FenceSync( ), g( ) - they enter the server’s command queue and are processed in order. When the server has reached, say, c( ) (it is currently processing c( )), the client issues a WaitSync( ) for the Fence after e( ). If the interpretation were correct, the server would now “hang” somewhere at c( ), waiting for itself to reach the FenceSync( ). Consequently the server would deadlock (or rather, timeout the wait). In either case, the WaitSync( ) would have no real purpose. As I was told, the meaning of WaitSync( ) relies on a specific notion of the hardware/driver processing commands (it continues to do so even after the WaitSync( ) was executed) and the server “stopping” (i.e. not feeding further instructions into the GPU). The fact that this notion is somewhat vague in itself aside, the spec should not require notion of these implementation-specific details.

6.2 Immutable vs. mutable storage as by BufferStorage vs. BufferData - The section does properly specify the restriction of BufferStorage( ), that is, one is not able to call that or BufferData( ) on the same buffer again. However, there is mention of “immutable” vs. “mutable” and it’s neglected to specify that “mutability” in this context does not refer to the buffer’s contents but only to their initial state (Table 6.3) as it is established by their creation.

2.6.1 Notion of buffer objects being “marked” - I understand that often the perspective of the implementer rather than that of the programmer/user of the API is reflected in the way the API is designed so although I’d rather have prefered a simple notion of “Defining a buffer object” and then “using it” like one does with variables in a language (“Define/declare an integer n”), I can understand that perhaps it’s easier to use that concept of “Define a name” and only then “Define its usage” and then “Define its contents”. However, it will probably help from the programmer’s perspective if at least the notion of “a name being marked as used” could be removed. Why not simply speak of GenBuffers( ) creating buffer names and BindBuffer( ) creating their contents, instead of the cumbersome notion of “Creating unmarked names to buffer objects which only acquire state” (or something along those lines)?

6.3 Mapped pointer being passed to GL commands - It should be clarified how the demand that pointers returned MapBufferRange( ) must not be passed to GL commands is in accordance with 2.1 Execution model. It is explicitly stated that “Data binding occurs on call. This means that data passed to a GL command are interpreted when that command is received.”. This is inconsistent because if it were like that, it musn’t make any difference whether the data is some pointer returned by MapBufferRange( ) or not.

The WaitSync specification uses some not well-defined notions like ‘server’ that leaves the function’s purpose unclear.
For comparison, ClientWaitSync blocks the calling thread - we all know what this means and when one would use it. But what is to block the server? When/why would one want to do such thing and what would be the effect from the point of view of the gl applicataion? They’d better either improve the spec or just remove this function (because who would use a function with unknown purpose).

If we had a type of sync object that is triggered on display vertical retrace, that would give a good purpose of WaitSync. That would be very useful feature too.

Another possible use of WaitSync may be co-operation between 2 or more gl contexts.

8.1 Textures - The introduction to this section leaves it largely unclear what exactly is the relation between “Texture Units” and “Texture Objects”. I understand that things are the way they are because of “historical reasons”, but that makes it only even more important to fill those terms with some semantic meaning. The introduction uses different terms for the same thing (“texture unit” and “texture image unit”) speaks of “binding texture to targets” one one page and “binding textures to texture image units” on the next. It probably can’t get much worse as far as understandability is concerned. Instead, the section should start with an explanation of what roles a “Texture Unit” and a “Texture Target” play and only then use those terms to specify the behaviour.
Many pages into the section it is still completely unclear whether binding multiple texture objects to multiple texture targets “in the same texture unit” is possible or makes any sense. Let alone the section fails to establish any connection between texture targets and texture units: “Each texture image unit consist of all the texture state defined in chapter 8” is too vague to understand that each target is associated with a unit.

10.5 Indirect drawing - Bug 1082 - The description of indirect drawing doesn’t give the slightest clue as to where the data are taken from, it should reference 10.3.10 for clarity or, better, 10.3.10 should be moved into 10.5. Worse, the paragraphs even seem to built upon the misleading API “void* instead of uint for legacy reasons” design which is found in, among others, DrawArraysIndirect, and establish the impression that the “void* indirect” parameter points to client memory whence the data are taken. 10.3.10 even says the data for Draw*Indirect may be stored in buffer objects, as if there were an alternative (but there is not).

The command

void DrawArraysIndirect( enum mode,const void* indirect )

is equivalent to

typedef struct { uint count; uint instanceCount; uint first; uint baseInstance;  } DrawArraysIndirectCommand;
DrawArraysIndirectCommand *cmd = (DrawArraysIndirectCommand *)indirect;
DrawArraysInstancedBaseInstance( mode,cmd->first,cmd->count,cmd->instanceCount,cmd->baseInstance );

14.3.1 Multisampling - I find the whole beginning of the chapter incomprehensible. Even if you know how MSAA works, after reading it you’re likely as confused as not to know it any more. The original extension specification gives an adequate description of MSAA. 14.3.1 in the 4.4. Core specification, on the other hand, wildly mixes the notion of “pixels”, “fragments” and “pixels” in a completely incomprehensible manner. On top of that, it uses vague, mostly undefined terms like “resolve color sample values” (what’s “resolve”?), “appear automatic”, “buffer added to the framebuffer” (what’s “a buffer” and what does it mean to “add it to the framebuffer”, which “framebuffer” and is it a logical buffer?), “separate color values for each fragment color” (what’s "each fragment color), and so forth - to list only the first few. Bottom line, the supposed introduction has no point, for neither implementers nor users, the way it is phrased.
What should be done is specify the result (or operation, as required) of multisampling in terms of fragments - and in terms of fragments only (similar to the original specification).

Also, the way the terms “pixel” and “fragment” are used is very confusing to me. To quote an exemplary piece from 14.3.1 which illustrates how the two terms seem to appear at random:

The location […] can be anywhere within the pixel including fragment center […]. Each pixel fragment thus […]

It would perhaps help if the relation between pixel and fragments were clearly specified. Almost everywhere it appears to be understood that a fragment coincides with a pixel (“Rasterization only produces fragments corresponding to pixels in the framebufer”) but other passages indicate it is not (“the portion of [fragment] f1 covered […] is a subset of […] f2”)

11.2.2 What are the generated primitives, what is tesselated - It remains completely unspecified where the notion of “triangles” or “edges” comes from. Compared to primitives like, say, triangle strips, where we have explicitly given how there are triangles created between the given vertices, tesselation gives no such information. From the point where we specify a patch as a set of “geometrically unordered” (compare 10.1.15) vertices on, there is nothing which says how these are turned into the triangles which the tesselation generator presumably tesselates as by 11.2.2.