Feedback: SPIR-V

SPIR (Standard Portable Intermediate Representation) was initially developed for use by OpenCL and SPIR versions 1.2 and 2.0 were based on LLVM. SPIR has now evolved into a true cross-API standard that is fully defined by Khronos with native support for shader and kernel features – called SPIR-V.

SPIR-V is the first open standard, cross-API intermediate language for natively representing parallel compute and graphics and will be incorporated as part of the core specification of both OpenCL 2.1 and the new Vulkan graphics and compute API. SPIR-V exposes the machine model for OpenCL 1.2, 2.0, 2.1 and Vulkan - including full flow control, and graphics and parallel constructs not supported in LLVM. SPIR-V also supports OpenCL 1.2, 2.0, 2.1 kernel languages as well as the GLSL shader language for Vulkan (under development).

SPIR-V is catalyzing a revolution in the language compiler ecosystem - it can split the compiler chain across multiple vendors’ products, enabling high-level language front-ends to emit programs in a standardized intermediate form to be ingested by Vulkan or OpenCL drivers. For hardware vendors, ingesting SPIR-V eliminate the need to build a high-level language source compiler into device drivers, significantly reducing driver complexity, and will enable a broad range of language and framework front-ends to run on diverse hardware architectures.

For developers, using SPIR-V means that kernel source code no longer has to be directly exposed, kernel load times can be accelerated and developers can choose the use of a common language front-end, improving kernel reliability and portability across multiple hardware implementations.

All feedback that is posted to this topic thread will be considered by the working group. We greatly appreciate what you have to say and the time you spent preparing your feedback.

The first thing I looked for was the definitions for dynamically uniform and so forth. And then I found this:

Invocation Group: The complete set of invocations collectively processing a particular compute workgroup or graphical operation, where the scope of a “graphical operation” is implementation dependent, but at least as large as a single triangle or patch, and at most as large as a single rendering command, as defined by the client API.

So you’re telling me I can’t know how it actually works for rendering until Vulkan ships? sigh On the plus side, it’s a lot more rigorous than the equivalent OpenGL/GLSL definitions. It only has one unknown factor, and we know that this factor must be defined by the client API.

I’m a bit non-plussed to see the massive explosion in the capabilities section. Before, capabilities were pretty simple and broad. Now, they’re down to individual features, to the point of specifying micro-details of implementations. I can understand the need for ClipDistance (not required for any OpenGL ES implementation, despite being in desktop GL since at least GLSL 1.30 or so) and CullDistance (newer OpenGL stuff). But why are there separate items for each form of dynamic addressing: UBOs, samplers, SSBOs, and images? GLSL 4.0 and GLSL ES 3.2 both require that all opaque types are dynamically uniformitively addressable, while prior versions only permit constant addressing. Is there hardware out there that allows dynamically uniform UBO array addressing, but not for samplers?

On the plus side, it’s good to see that physical addressing is a full-fledged capability that does not require the Kernel execution model. So it becomes possible for an implementation to allow physical addressing with shaders.

I can’t find anything about matrix addition. There is no OpMatrixAndMatrix, OpFAdd accepts scalars and vectors but matrices. Tested matrix addition with GLSLang reference compiler, it simply prints an error message.
Did I miss something? Matrix addition is very important for GPU skinning shaders.

Matrix multiplication is a complex affair, which could be optimized with specialized code depending on the various hardware involved. Matrix addition… is not. There’s really only one way to do that.

Remember: SPIR-V is low level. It only provides convenience features where hardware abstractions are important. It’s important for the compiler to see that you’re doing vector additions rather than 4 scalar additions. That makes it easy for the compiler to see what you’re doing and emit the proper hardware opcodes. But a matrix addition instead of 4 vector additions is not a case for which most hardware has some special opcode (generally speaking).

The reference compiler should have no problem synthesizing 4 vector additions from a matrix addition. If it hasn’t done that, then that’s a bug in their compiler.

[QUOTE=Alfonse Reinheart;39648]Matrix multiplication is a complex affair, which could be optimized with specialized code depending on the various hardware involved. Matrix addition… is not. There’s really only one way to do that.

Remember: SPIR-V is low level. It only provides convenience features where hardware abstractions are important. It’s important for the compiler to see that you’re doing vector additions rather than 4 scalar additions. That makes it easy for the compiler to see what you’re doing and emit the proper hardware opcodes. But a matrix addition instead of 4 vector additions is not a case for which most hardware has some special opcode (generally speaking).

The reference compiler should have no problem synthesizing 4 vector additions from a matrix addition. If it hasn’t done that, then that’s a bug in their compiler.[/QUOTE]

But it’s no reason to not allow matrices into the opFAdd instruction.

But it not being there doesn’t mean that SPIR-V is broken. I was responding in particular to this statement: “Matrix addition is very important for GPU skinning shaders.” You can still do matrix addition, just not with a single opcode. So SPIR-V is still functional in this regard, and the lack of a matrix addition function should not impact the quality of the generated machine code.

That was my point: that SPIR-V 1.0 lacking an explicit opcode doesn’t make it unusable for GPU skinning. Just inconvenient.

And there is a reason not to allow it: SPIR-V is already at 1.0. Nobody noticed this before now (despite having a good 6+ months to look at it), so it’s locked in. You can’t just back-port it into SPIR-V 1.0; that’d be a breaking change. This isn’t a specification bugfix; this is observable behavior.

Now for the next version? Sure, fine, whatever. But the ship has sailed on 1.0.

On the plus side, the OpenCL 2.1 specification does state that a 2.1 implementation must suport SPIR-V “at version 1.0 or above”. Which means going to version 1.1 would not require a corresponding OpenCL version change (unlike OpenGL and GLSL). And OpenCL implementations even provide a list of SPIR-V versions that it supports.

[QUOTE=Alfonse Reinheart;39650]But it not being there doesn’t mean that SPIR-V is broken. I was responding in particular to this statement: “Matrix addition is very important for GPU skinning shaders.” You can still do matrix addition, just not with a single opcode. So SPIR-V is still functional in this regard, and the lack of a matrix addition function should not impact the quality of the generated machine code.

That was my point: that SPIR-V 1.0 lacking an explicit opcode doesn’t make it unusable for GPU skinning. Just inconvenient.

And there is a reason not to allow it: SPIR-V is already at 1.0. Nobody noticed this before now (despite having a good 6+ months to look at it), so it’s locked in. You can’t just back-port it into SPIR-V 1.0; that’d be a breaking change. This isn’t a specification bugfix; this is observable behavior.

Now for the next version? Sure, fine, whatever. But the ship has sailed on 1.0.

On the plus side, the OpenCL 2.1 specification does state that a 2.1 implementation must suport SPIR-V “at version 1.0 or above”. Which means going to version 1.1 would not require a corresponding OpenCL version change (unlike OpenGL and GLSL). And OpenCL implementations even provide a list of SPIR-V versions that it supports.[/QUOTE]

the ship hasn’t officially sailed until vulkan is released. And they have already made a revision change from 1.0 (the current version is 1.0 revision 2).

It’s hardly going to be breaking anything to change “Result Type must be a scalar or vector of floating-point type.” to “Result Type must be a scalar, vector or matrix of floating-point type.” Same for the other opF* arithmetic operands

SPIR-V is just as much a citizen of the OpenCL ecosystem as the Vulkan ecosystem. It must serve the needs of both. So yes, the ship has officially sailed.

But revision 1 was never released; only revision 2 saw the light of day. It’s not just being a 1.0 version; it’s about being released.

You can fix bugs in a released revision, but you shouldn’t add features. And this qualifies as a feature, not a bug.

It means that released versions of OpenCL 2.1 that claim to support SPIR-V 1.0 won’t actually support adding matrices. Every validator for SPIR-V 1.0 made right now expects to not be able to add matrices. So if someone’s using an old tool and feeds it a 1.0 shader, it will fail. That’s bad.

This is exactly the sort of thing that point releases were made for. If you add this in SPIR-V 1.1, then when you send a 1.1 program through a validator for 1.0, it will fail with a much more reasonable error: that it does not support 1.0.

[QUOTE=Alfonse Reinheart;39652]
It means that released versions of OpenCL 2.1 that claim to support SPIR-V 1.0 won’t actually support adding matrices. Every validator for SPIR-V 1.0 made right now expects to not be able to add matrices. So if someone’s using an old tool and feeds it a 1.0 shader, it will fail. That’s bad.

This is exactly the sort of thing that point releases were made for. If you add this in SPIR-V 1.1, then when you send a 1.1 program through a validator for 1.0, it will fail with a much more reasonable error: that it does not support 1.0.[/QUOTE]

Only those that claim to support the matrix capability.