1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
|
'''OpenGL extension ARB.gl_spirv
This module customises the behaviour of the
OpenGL.raw.GL.ARB.gl_spirv to provide a more
Python-friendly API
Overview (from the spec)
This is version 100 of the GL_ARB_gl_spirv extension.
This extension does two things:
1. Allows a SPIR-V module to be specified as containing a programmable
shader stage, rather than using GLSL, whatever the source language
was used to create the SPIR-V module.
2. Modifies GLSL to be a source language for creating SPIR-V modules
for OpenGL consumption. Such GLSL can be used to create such SPIR-V
modules, outside of the OpenGL runtime.
Enabling GLSL SPIR-V Features
-----------------------------
This extension is not enabled with a #extension as other extensions are.
It is also not enabled through use of a profile or #version. The intended
level of GLSL features comes from the traditional use of #version, profile,
and #extension.
Instead, use of this extension is an effect of using a GLSL front-end in a
mode that has it generate SPIR-V for OpenGL. Such tool use is outside the
scope of using the OpenGL API and outside the definition of GLSL and this
extension. See the documentation of the compiler to see how to request
generation of SPIR-V for OpenGL.
When a front-end is used to accept the GLSL features in this extension, it
must error check and reject shaders not adhering to this specification, and
accept those that do. Implementation-dependent maximums and capabilities
are supplied to, or part of, the front-end, so it can do error checking
against them.
A shader can query the level of GLSL SPIR-V support available, using the
predefined
#define GL_SPIRV 100
This allows shader code to say, for example,
#ifdef GL_SPIRV
layout(constant_id = 11) const int count = 4;
#if GL_SPIRV > 100
...
#endif
#else
const int count = 6;
#endif
SPIR-V Modules
--------------
An entire stage is held in a single SPIR-V module. The SPIR-V model is
that multiple (e.g., GLSL) compilation units forming a single stage
in a high-level language are all compiled and linked together to form a
single entry point (and its call tree) in a SPIR-V module. This would be
done prior to using the OpenGL API to create a program object containing the
stage.
The OpenGL API expects the SPIR-V module to have already been validated,
and can return an error if it discovers anything invalid in
the module. An invalid SPIR-V module is allowed to result in undefined
behavior.
Specialization Constants
------------------------
SPIR-V specialization constants, which can be set later by the client API,
can be declared using "layout(constant_id=...)". For example, to make a
specialization constant with a default value of 12:
layout(constant_id = 17) const int arraySize = 12;
Above, "17" is the ID by which the API or other tools can later refer to
this specific specialization constant. The API or an intermediate tool can
then change its value to another constant integer before it is fully
lowered to executable code. If it is never changed before final lowering,
it will retain the value of 12.
Specialization constants have const semantics, except they don't fold.
Hence, an array can be declared with 'arraySize' from above:
vec4 data[arraySize]; // legal, even though arraySize might change
Specialization constants can be in expressions:
vec4 data2[arraySize + 2];
This will make data2 be sized by 2 more than whatever constant value
'arraySize' has when it is time to lower the shader to executable code.
An expression formed with specialization constants also behaves in the
shader like a specialization constant, not a like a constant.
arraySize + 2 // a specialization constant (with no constant_id)
Such expressions can be used in the same places as a constant.
The constant_id can only be applied to a scalar *int*, a scalar *float*
or a scalar *bool*.
Only basic operators and constructors can be applied to a specialization
constant and still result in a specialization constant:
layout(constant_id = 17) const int arraySize = 12;
sin(float(arraySize)); // result is not a specialization constant
While SPIR-V specialization constants are only for scalars, a vector
can be made by operations on scalars:
layout(constant_id = 18) const int scX = 1;
layout(constant_id = 19) const int scZ = 1;
const vec3 scVec = vec3(scX, 1, scZ); // partially specialized vector
A built-in variable can have a 'constant_id' attached to it:
layout(constant_id = 18) gl_MaxImageUnits;
This makes it behave as a specialization constant. It is not a full
redeclaration; all other characteristics are left intact from the
original built-in declaration.
The built-in vector gl_WorkGroupSize can be specialized using special
layout local_size_{xyz}_id's applied to the "in" qualifier. For example:
layout(local_size_x_id = 18, local_size_z_id = 19) in;
This leaves gl_WorkGroupSize.y as a non-specialization constant, with
gl_WorkGroupSize being a partially specialized vector. Its x and z
components can be later specialized using the ID's 18 and 19.
gl_FragColor
------------
The fragment-stage built-in gl_FragColor, which implies a broadcast to all
outputs, is not present in SPIR-V. Shaders where writing to gl_FragColor
is allowed can still write to it, but it only means to write to an output:
- of the same type as gl_FragColor
- decorated with location 0
- not decorated as a built-in variable.
There is no implicit broadcast.
Mapping to SPIR-V
-----------------
For informational purposes (non-specification), the following is an
expected way for an implementation to map GLSL constructs to SPIR-V
constructs:
Mapping of Storage Classes:
uniform sampler2D...; -> UniformConstant
uniform variable (non-block) -> UniformConstant
uniform blockN { ... } ...; -> Uniform, with Block decoration
in / out variable -> Input/Output, possibly with block (below)
in / out block... -> Input/Output, with Block decoration
buffer blockN { ... } ...; -> Uniform, with BufferBlock decoration
... uniform atomic_uint ... -> AtomicCounter
shared -> Workgroup
<normal global> -> Private
Mapping of input/output blocks or variables is the same for all versions
of GLSL. To the extent variables or members are available in a
version and a stage, its location is as follows:
These are mapped to SPIR-V individual variables, with similarly spelled
built-in decorations (except as noted):
General:
in gl_VertexID
in gl_InstanceID
in gl_InvocationID
in gl_PatchVerticesIn (PatchVertices)
in gl_PrimitiveIDIn (PrimitiveID)
in/out gl_PrimitiveID (in/out based only on storage qualifier)
in gl_TessCoord
in/out gl_Layer
in/out gl_ViewportIndex
patch in/out gl_TessLevelOuter (uses Patch decoration)
patch in/out gl_TessLevelInner (uses Patch decoration)
Compute stage only:
in gl_NumWorkGroups
in gl_WorkGroupSize
in gl_WorkGroupID
in gl_LocalInvocationID
in gl_GlobalInvocationID
in gl_LocalInvocationIndex
Fragment stage only:
in gl_FragCoord
in gl_FrontFacing
in gl_ClipDistance
in gl_CullDistance
in gl_PointCoord
in gl_SampleID
in gl_SamplePosition
in gl_HelperInvocation
out gl_FragDepth
in gl_SampleMaskIn (SampleMask)
out gl_SampleMask (in/out based only on storage qualifier)
These are mapped to SPIR-V blocks, as implied by the pseudo code, with
the members decorated with similarly spelled built-in decorations:
Non-fragment stage:
in/out gl_PerVertex { // some subset of these members will be used
gl_Position
gl_PointSize
gl_ClipDistance
gl_CullDistance
} // name of block is for debug only
There is at most one input and one output block per stage in SPIR-V.
The subset and order of members will match between stages sharing an
interface.
Mapping of precise:
precise -> NoContraction
Mapping of atomic_uint /offset/ layout qualifier
offset -> Offset (decoration)
Mapping of images
imageLoad() -> OpImageRead
imageStore() -> OpImageWrite
texelFetch() -> OpImageFetch
imageAtomicXXX(params, data) -> %ptr = OpImageTexelPointer params
OpAtomicXXX %ptr, data
XXXQueryXXX(combined) -> %image = OpImage combined
OpXXXQueryXXX %image
Mapping of layouts
std140/std430 -> explicit *Offset*, *ArrayStride*, and *MatrixStride*
Decoration on struct members
shared/packed -> not allowed
<default> -> not shared, but std140 or std430
xfb_offset -> *Offset* Decoration on the object or struct member
xfb_buffer -> *XfbBuffer* Decoration on the object
xfb_stride -> *XfbStride* Decoration on the object
any xfb_* -> the *Xfb* Execution Mode is set
captured XFB -> has both *XfbBuffer* and *Offset*
non-captured -> lacking *XfbBuffer* or *Offset*
max_vertices -> OutputVertices
Mapping of barriers
barrier() (compute) -> OpControlBarrier(/*Execution*/Workgroup,
/*Memory*/Workgroup,
/*Semantics*/AcquireRelease |
WorkgroupMemory)
barrier() (tess control) -> OpControlBarrier(/*Execution*/Workgroup,
/*Memory*/Invocation,
/*Semantics*/None)
memoryBarrier() -> OpMemoryBarrier(/*Memory*/Device,
/*Semantics*/AcquireRelease |
UniformMemory |
WorkgroupMemory |
ImageMemory)
memoryBarrierBuffer() -> OpMemoryBarrier(/*Memory*/Device,
/*Semantics*/AcquireRelease |
UniformMemory)
memoryBarrierShared() -> OpMemoryBarrier(/*Memory*/Device,
/*Semantics*/AcquireRelease |
WorkgroupMemory)
memoryBarrierImage() -> OpMemoryBarrier(/*Memory*/Device,
/*Semantics*/AcquireRelease |
ImageMemory)
groupMemoryBarrier() -> OpMemoryBarrier(/*Memory*/Workgroup,
/*Semantics*/AcquireRelease |
UniformMemory |
WorkgroupMemory |
ImageMemory)
Mapping of atomics
all atomic builtin functions -> Semantics = None(Relaxed)
atomicExchange() -> OpAtomicExchange
imageAtomicExchange() -> OpAtomicExchange
atomicCompSwap() -> OpAtomicCompareExchange
imageAtomicCompSwap() -> OpAtomicCompareExchange
NA -> OpAtomicCompareExchangeWeak
atomicCounterIncrement -> OpAtomicIIncrement
atomicCounterDecrement -> OpAtomicIDecrement (with post decrement)
atomicCounter -> OpAtomicLoad
Mapping of uniform initializers
Using the OpVariable initializer logic, but only from a constant
instruction (not a global one).
Mapping of other instructions
% -> OpUMod/OpSMod
mod() -> OpFMod
NA -> OpSRem/OpFRem
pack/unpack (conversion) -> pack/unpack in GLSL extended instructions
pack/unpack (no conversion) -> OpBitcast
Differences Relative to Other Specifications
--------------------------------------------
The following summarizes the set of differences to existing specifications.
Additional use of existing SPIR-V features, relative to Vulkan:
+ The *UniformConstant* Storage Class can be used on individual
variables at global scope. (That is, uniforms don't have to be in a
block, unless they are built-in members that are in block in GLSL
version 4.5.)
+ *AtomicCounter* Storage Class can use the *Offset* decoration
+ OriginLowerLeft
+ Uniforms support constant initializers.
Corresponding features that GLSL keeps, despite GL_KHR_vulkan_glsl removal:
. default uniforms (those not inside a uniform block)
. atomic-counter bindings have the /offset/ layout qualifier
. special rules for locations for input doubles in the vertex shader
. origin_lower_left
Addition of features to GLSL:
+ specialization constants, as per GL_KHR_vulkan_glsl
+ #define GL_SPIRV 100, when compiled for OpenGL and SPIR-V generation
+ offset can organize members in a different order than declaration order
Non-acceptance of SPIR-V features, relative to Vulkan:
- VertexIndex and InstanceIndex built-in decorations cannot be used
- Push-constant buffers cannot be used
- *DescriptorSet* must always be 0, if present
- input targets and input attachments
- OpTypeSampler
Corresponding features not added to GLSL that GL_KHR_vulkan_glsl added:
. gl_VertexIndex and gl_InstanceIndex
(gl_VertexID and gl_InstanceID have same semantics as in GLSL)
. push_constant buffers
. descriptor sets
. input_attachment_index and accessing input targets
. shader-combining of textures and samplers
Removal of features from GLSL, as removed by GL_KHR_vulkan_glsl:
- subroutines
- the already deprecated texturing functions (e.g., texture2D())
- the already deprecated noise functions (e.g., noise1())
- compatibility profile features
- gl_DepthRangeParameters and gl_NumSamples
- *shared* and *packed* block layouts
Addition of features to The OpenGL Graphics System:
+ a command to associate a SPIR-V module with a program (ShaderBinary)
+ a command to select a SPIR-V entry point and set specialization
constants in a SPIR-V module (SpecializeShaderARB)
+ a new appendix for SPIR-V validation rules, precision, etc.
Changes of system features, relative to Vulkan:
. Vulkan uses only one binding point for a resource array, while OpenGL
still uses multiple binding points, so binding numbers are counted
differently for SPIR-V used in Vulkan and OpenGL
. gl_FragColor can be written to, but it won't broadcast, for versions of
OpenGL that support gl_FragColor
. Vulkan does not allow multi-dimensional arrays of resources like
UBOs and SSBOs in its SPIR-V environment spec. SPIR-V supports
it and OpenGL already allows this for GLSL shaders. SPIR-V
for OpenGL also allows it.
Additions to the SPIR-V specification:
+ *Offset* can also apply to an object, for transform feedback.
+ *Offset* can also apply to a default uniform, for atomic_uint offset.
The official definition of this extension is available here:
http://www.opengl.org/registry/specs/ARB/gl_spirv.txt
'''
from OpenGL import platform, constant, arrays
from OpenGL import extensions, wrapper
import ctypes
from OpenGL.raw.GL import _types, _glgets
from OpenGL.raw.GL.ARB.gl_spirv import *
from OpenGL.raw.GL.ARB.gl_spirv import _EXTENSION_NAME
def glInitGlSpirvARB():
'''Return boolean indicating whether this extension is available'''
from OpenGL import extensions
return extensions.hasGLExtension( _EXTENSION_NAME )
### END AUTOGENERATED SECTION
|