Source browser

detail/runtime.hpp

Read the complete file below or download its original bytes. Line numbers provide stable links to a declaration or processing step.

File fingerprint
1#ifndef SHDR_RUNTIME_HPP // Skip this section if it was already included.
2#define SHDR_RUNTIME_HPP /* Mark this section as included. */
3
4/** @brief Major version of shdr. */
5#define SHDR_VERSION_MAJOR 1 // Identify the public API's major release series.
6/** @brief Minor version within the current major release. */
7#define SHDR_VERSION_MINOR 0 // Identify additions within the public API's release series.
8/** @brief Patch version within the current minor release. */
9#define SHDR_VERSION_PATCH 0 // Identify corrections within this minor release.
10/** @brief The library release version as a string. */
11#define SHDR_VERSION "1.0.0" // Expose the library release as a compile-time string.
12
13#include <algorithm> // Use standard searches, bounds, and resource copying.
14#include <cstddef> // Use portable pointer sizes and offsets.
15#include <cstdint> // Use integer widths that match GLSL values.
16#include <cctype> // Recognize characters in embedded shader declarations.
17#include <cstring> // Copy bytes and function addresses with std::memcpy.
18#include <functional> // Store GL resolvers and deferred cleanup callbacks.
19#include <initializer_list> // Accept concise resource initialization from application values.
20#include <limits> // Check arithmetic against the type limits.
21#include <map> // Find registered shader factories and shared kernel snapshots.
22#include <memory> // Retain resources while pipelines and queued jobs use them.
23#include <mutex> // Protect shared work queues and deferred deletion.
24#include <thread> // Track the context thread and start CPU workers.
25#include <sstream> // Build readable shader and driver diagnostics.
26#include <stdexcept> // Report invalid resources and failed execution.
27#include <string> // Keep embedded shader text and named interfaces.
28#include <type_traits> // Check shader storage and port types at compile time.
29#include <vector> // Store ordered stages, ports, and resource values.
30
31/** @brief Portable, header-only CPU/OpenGL compute pipelines. */
32namespace shdr { // Group these definitions in the shdr namespace.
33/** @brief A shader, resource, context or dispatch validation failure. */
34struct error : std::runtime_error { // Keep the error values and operations together.
35    explicit error(const std::string& s) : std::runtime_error(s) { // Preserve the supplied validation or driver diagnostic.
36    } // End this scope in runtime.
37}; // End this scope in runtime.
38
39/** @brief Three unsigned dimensions. dispatch dimensions count work groups. */
40struct extent { // Keep the extent values and operations together.
41    unsigned x, y, z; // Keep the three unsigned dispatch or local dimensions.
42    /** @brief Construct three workgroup counts, defaulting each dimension to one. */
43    explicit extent(unsigned x_ = 1, unsigned y_ = 1, unsigned z_ = 1) : x(x_), y(y_), z(z_) { // Initialize all three positive-or-zero dimensions supplied by the caller.
44    } // End this scope in runtime.
45}; // End this scope in runtime.
46/** @brief Minimum shader language selected independently of the context's actual version. */
47enum class profile { es31, es32, gl43, gl45, gl46 }; // Name the supported shader language profiles.
48/** @brief Automatic uses CPU execution for run() and GPU execution for run(device). */
49enum class backend { automatic, cpu, gpu }; // Select automatic, explicit CPU or explicit GPU execution.
50/** @brief Resource access qualifiers. readonly also prevents CPU writes at compile time. */
51enum class access { readonly, writeonly, readwrite }; // Express how a shader may access a bound resource.
52
53namespace detail { // Group these definitions in the detail namespace.
54inline bool identifier_char(char c) { // Recognize the letters, digits, and underscore allowed in an identifier.
55    return std::isalnum(static_cast<unsigned char>(c)) || c == '_'; // Recognize the letters, digits, and underscore allowed in an identifier.
56} // End this scope in identifier char.
57inline std::string trim(const std::string& text) { // Remove surrounding whitespace from one resource argument.
58    const std::size_t first = text.find_first_not_of(" \t\r\n"); // Set the first non-space character.
59    return first == std::string::npos // Remove surrounding whitespace from one resource argument.
60               ? std::string() // Select the value for this branch of the condition.
61               : text.substr(first, text.find_last_not_of(" \t\r\n") - first + 1); // Copy only the non-whitespace portion of this argument.
62} // End this scope in trim.
63 // ESSL forbids token-pasting macros. Expand only resource declarations in the host,
64 // preserving comments, string literals, shader statements and original line numbers.
65inline std::string expand_declarations(const std::string& source, bool es) { // Expand host resource declarations into native GLSL interfaces.
66    std::string out; // Keep the assembled shader text.
67    for (std::size_t i = 0; i < source.size();) { // Walk the embedded shader text while respecting its token boundaries.
68        const std::size_t start = i; // Set the beginning of the current token or range.
69        if (source.compare(i, 2, "//") == 0) { // Copy the line comment verbatim.
70            const std::size_t end = source.find('\n', i); // Set the end of the current range.
71            i = end == std::string::npos ? source.size() : end + 1; // Advance beyond the preserved comment or declaration.
72        } else if (source.compare(i, 2, "/*") == 0) { // Copy the block comment verbatim.
73            const std::size_t end = source.find("*/", i + 2); // Set the end of the current range.
74            i = end == std::string::npos ? source.size() : end + 2; // Advance beyond the preserved comment or declaration.
75        } else if (source[i] == '\"' || source[i] == '\'') { // Copy quoted shader text as one lexical unit.
76            const char quote = source[i++]; // Remember which quote terminates this shader literal.
77            while (i < source.size()) { // Walk the embedded shader text while respecting its token boundaries.
78                if (source[i] == '\\') { // Treat an escaped character as part of the quoted shader text.
79                    i = (std::min)(i + 2, source.size()); // Advance past the escaped character within the source bounds.
80                    continue; // Continue with the next token or work item.
81                } // End this scope in expand declarations.
82                if (source[i++] == quote) // Choose this branch when source[i++] equals quote.
83                    break; // Stop this search or loop once its current item is complete.
84            } // End this scope in expand declarations.
85        } else if (identifier_char(source[i])) { // Recognize the letters, digits, and underscore allowed in an identifier.
86            while (i < source.size() && identifier_char(source[i])) // Walk the embedded shader text while respecting its token boundaries.
87                ++i; // Expand host resource declarations into native GLSL interfaces.
88            const std::string token = source.substr(start, i - start); // Set the current shader identifier.
89            if (token == "SHDR_BUFFER" || token == "SHDR_IMAGE2D") { // Choose this branch when token equals "SHDR BUFFER" or token equals "SHDR IMAGE2D".
90                std::size_t open = i; // Set the opening parenthesis of a resource declaration.
91                while (open < source.size() && // Walk the embedded shader text while respecting its token boundaries.
92                       std::isspace(static_cast<unsigned char>(source[open]))) // Keep the opening parenthesis of a resource declaration.
93                    ++open; // Keep the opening parenthesis of a resource declaration.
94                if (open >= source.size() || source[open] != '(') // Check resource size or driver limits before accessing storage.
95                    throw error("resource declaration requires parentheses: " + token); // Report resource declaration requires parentheses: .
96                std::size_t end = open + 1, argument = end; // Set the end of the current range.
97                unsigned depth = 1; // Set the current parenthesis nesting.
98                std::vector<std::string> args; // Keep the parsed declaration arguments.
99                for (; end < source.size(); ++end) { // Walk the embedded shader text while respecting its token boundaries.
100                    if (source[end] == '(') // Choose this branch when source[end] equals '('.
101                        ++depth; // Keep the current parenthesis nesting.
102                    if (source[end] == ')') // Choose this branch when source[end] equals ')'.
103                        --depth; // Keep the current parenthesis nesting.
104                    if ((source[end] == ',' && depth == 1) || depth == 0) { // Choose this branch when (source[end] equals ',' and depth equals 1) or depth equals 0.
105                        args.push_back(trim(source.substr(argument, end - argument))); // Retain this entry in the ordered resource or work collection.
106                        argument = end + 1; // Set the beginning of the next resource argument.
107                    } // End this scope in expand declarations.
108                    if (!depth) // Finish the argument list at its matching closing parenthesis.
109                        break; // Stop this search or loop once its current item is complete.
110                } // End this scope in expand declarations.
111                const bool image = token == "SHDR_IMAGE2D"; // Choose image or storage-buffer declaration syntax.
112                if (depth || args.size() != (image ? 5u : 4u)) // Check resource size or driver limits before accessing storage.
113                    throw error("invalid resource declaration: " + token); // Report invalid resource declaration: .
114                const std::string mode = args.back(); // Set the declared shader resource access.
115                if (mode != "readonly" && mode != "writeonly" && mode != "readwrite") // Choose the branch matching this interface or resource access.
116                    throw error("invalid resource access: " + mode); // Report invalid resource access: .
117                const std::string qualifier = mode == "readwrite" ? "" : mode + " "; // Set the access qualifier emitted into GLSL.
118                if (image) { // Choose this branch when image.
119                    if (es && mode == "readwrite" && args[1].compare(0, 4, "rgba") == 0) // Choose the branch matching this interface or resource access.
120                        throw error( // Report the invalid operation.
121                            "GLES RGBA images require readonly or writeonly declarations: " + // Append this literal GLSL source fragment.
122                            args[3]); // Expand host resource declarations into native GLSL interfaces.
123                    out += "layout(" + args[1] + ",binding=" + args[0] + ") " + qualifier + // Set the assembled shader text.
124                           "uniform highp " + args[2] + " " + args[3] + ";"; // Append this literal GLSL source fragment.
125                } else // Handle the alternative resource or completion case.
126                    out += "layout(std430,binding=" + args[0] + ") " + qualifier + // Set the assembled shader text.
127                           "buffer shdr_block_" + args[2] + " { " + args[1] + " " + args[2] + // Append this literal GLSL source fragment.
128                           "[]; };"; // Append this literal GLSL source fragment.
129                out.append(static_cast<std::size_t>( // Restore the original declaration's line count after expansion.
130                               std::count(source.begin() + static_cast<std::ptrdiff_t>(start), // Keep the beginning of the current token or range.
131                                          source.begin() + static_cast<std::ptrdiff_t>(end + 1), // Stop counting at the end of the replaced resource declaration.
132                                          '\n')), // Count the newlines originally present in this declaration.
133                           '\n'); // Append one newline for each removed original newline.
134                i = end + 1; // Advance beyond the preserved comment or declaration.
135                continue; // Continue with the next token or work item.
136            } // End this scope in expand declarations.
137        } else // Handle the alternative resource or completion case.
138            ++i; // Expand host resource declarations into native GLSL interfaces.
139        out.append(source, start, i - start); // Preserve this untouched token or comment in the exported GLSL.
140    } // End this scope in expand declarations.
141    return out; // Return the assembled shader text.
142} // End this scope in expand declarations.
143} // namespace detail
144
145/** @internal Export an embedded shader as standard GLSL, with version and declaration macros.
146 * This function supplies the version directive. Guard the body's C++ include
147 * with #ifdef __cplusplus. The exported source contains the selected version
148 * and expanded declarations.
149 */
150inline std::string glsl_source(const std::string& source, profile p) { // Add the selected GLSL version and shared-declaration definitions.
151    std::istringstream lines(source); // Read the embedded shader one line at a time.
152    std::string line; // Read each embedded source line while checking version directives.
153    while (std::getline(lines, line)) { // Inspect each source line for an unsupported version directive.
154        std::size_t start = line.find_first_not_of(" \t\r"); // Set the beginning of the current token or range.
155        if (start != std::string::npos && line[start] == '#') { // Choose this branch when start differs from std::string::npos and line[start] equals '#'.
156            start = line.find_first_not_of(" \t", start + 1); // Set the beginning of the current token or range.
157            if (start != std::string::npos && line.compare(start, 7, "version") == 0) // Choose this branch when start differs from std::string::npos and line.compare(start, 7, "version") equals 0.
158                throw error("shared shaders must omit #version; glsl_source supplies it"); // Report shared shaders must omit #version. glsl_source supplies it.
159        } // End this scope in glsl source.
160    } // End this scope in glsl source.
161    const char* version = p == profile::es31   ? "310 es" // Set the current GL version text.
162                          : p == profile::es32 ? "320 es" // Select the version associated with this shader profile.
163                          : p == profile::gl43 ? "430 core" // Select the version associated with this shader profile.
164                          : p == profile::gl45 ? "450 core" // Select the version associated with this shader profile.
165                                               : "460 core"; // Select desktop GLSL 4.60 for the remaining profile.
166    std::string out = std::string("#version ") + version + "\n"; // Set the assembled shader text.
167    if (p == profile::es31 || p == profile::es32) // Choose this branch when p equals profile::es31 or p equals profile::es32.
168        out += "precision highp float;\nprecision highp int;\n"; // Set the assembled shader text.
169    out += // Set the assembled shader text.
170        "#define SHDR_BEGIN(name,x,y,z) layout(local_size_x=x,local_size_y=y,local_size_z=z) in;\n" // Emit a native workgroup declaration for this shader.
171        "#define SHDR_END()\n" // Remove the host-only shader wrapper terminator.
172        "#define SHDR_MAIN() void main()\n" // Map the shared entry-point spelling to native GLSL main.
173        "#define SHDR_UNIFORM(t,n) uniform t n;\n" // Emit a native typed uniform declaration.
174        "#define SHDR_SWIZZLE(v,s) (v).s\n" // Map shared swizzle syntax to native GLSL component selection.
175        "#define SHDR_NOT(v) not(v)\n" // Map shared boolean negation to the native GLSL builtin.
176        "#define SHDR_IN(t,n) in t n\n" // Emit a native input parameter qualifier.
177        "#define SHDR_OUT(t,n) out t n\n" // Emit a native output parameter qualifier.
178        "#define SHDR_INOUT(t,n) inout t n\n" // Emit a native input-output parameter qualifier.
179        "#line 1\n"; // Restore shader line numbering before appending the original source.
180 // Desktop GLSL accepts highp precision qualifiers from GLSL 4.10 onward.
181    return out + detail::expand_declarations(source, p == profile::es31 || p == profile::es32); // Add the selected GLSL version and shared-declaration definitions.
182} // End this scope in glsl source.
183
184namespace detail { // Group these definitions in the detail namespace.
185 // Private GL types and entry points keep the default header compatible with standard C++11.
186typedef unsigned int GLenum; // Name the representation used by this GL or shader interface.
187typedef unsigned int GLuint; // Name the representation used by this GL or shader interface.
188typedef int GLint; // Name the representation used by this GL or shader interface.
189typedef int GLsizei; // Name the representation used by this GL or shader interface.
190typedef unsigned int GLbitfield; // Name the representation used by this GL or shader interface.
191typedef unsigned char GLboolean; // Name the representation used by this GL or shader interface.
192typedef std::ptrdiff_t GLsizeiptr; // Name the representation used by this GL or shader interface.
193typedef std::ptrdiff_t GLintptr; // Name the representation used by this GL or shader interface.
194typedef std::uint64_t GLuint64; // Name the representation used by this GL or shader interface.
195typedef void* GLsync; // Name the representation used by this GL or shader interface.
196#if defined(_WIN32) // Compile this branch only when its platform or backend condition holds.
197#define SHDR_GL_CALL __stdcall /* Match the calling convention of the GL entry points. */
198#else // Use the alternative platform or backend definition.
199#define SHDR_GL_CALL /* Match the calling convention of the GL entry points. */
200#endif // Finish this conditional section.
201enum : unsigned { // Name the profile, access, or completion values accepted by this section.
202    VERSION = 0x1F02, // Use the GL numeric code for version.
203    MAJOR_VERSION = 0x821B, // Use the GL numeric code for major version.
204    MINOR_VERSION = 0x821C, // Use the GL numeric code for minor version.
205    COMPUTE_SHADER = 0x91B9, // Use the GL numeric code for compute shader.
206    COMPILE_STATUS = 0x8B81, // Use the GL numeric code for compile status.
207    LINK_STATUS = 0x8B82, // Use the GL numeric code for link status.
208    INFO_LOG_LENGTH = 0x8B84, // Use the GL numeric code for info log length.
209    COMPUTE_WORK_GROUP_SIZE = 0x8267, // Use the GL numeric code for compute work group size.
210    MAX_COMPUTE_WORK_GROUP_COUNT = 0x91BE, // Use the GL numeric code for max compute work group count.
211    MAX_COMPUTE_WORK_GROUP_SIZE = 0x91BF, // Use the GL numeric code for max compute work group size.
212    MAX_COMPUTE_WORK_GROUP_INVOCATIONS = 0x90EB, // Use the GL numeric code for max compute work group invocations.
213    MAX_SHADER_STORAGE_BUFFER_BINDINGS = 0x90DD, // Use the GL numeric code for max shader storage buffer bindings.
214    MAX_IMAGE_UNITS = 0x8F38, // Use the GL numeric code for max image units.
215    SHADER_STORAGE_BUFFER = 0x90D2, // Use the GL numeric code for shader storage buffer.
216    DYNAMIC_DRAW = 0x88E8, // Use the GL numeric code for dynamic draw.
217    MAP_READ_BIT = 1, // Use the GL numeric code for map read bit.
218    ALL_BARRIER_BITS = 0xFFFFFFFFu, // Use the GL numeric code for all barrier bits.
219    TEXTURE_2D = 0x0DE1, // Identify a two-dimensional texture target.
220    FLOAT = 0x1406, // Use the GL numeric code for float.
221    INT = 0x1404, // Use the GL numeric code for int.
222    UNSIGNED_INT = 0x1405, // Use the GL numeric code for unsigned int.
223    RED = 0x1903, // Use the GL numeric code for red.
224    RGBA = 0x1908, // Use the GL numeric code for rgba.
225    RED_INTEGER = 0x8D94, // Use the GL numeric code for red integer.
226    RGBA_INTEGER = 0x8D99, // Use the GL numeric code for rgba integer.
227    R32F = 0x822E, // Store one 32-bit floating-point component per pixel.
228    R32I = 0x8235, // Store one signed 32-bit component per pixel.
229    R32UI = 0x8236, // Store one unsigned 32-bit component per pixel.
230    RGBA32F = 0x8814, // Store four 32-bit floating-point components per pixel.
231    RGBA32I = 0x8D82, // Store four signed 32-bit components per pixel.
232    RGBA32UI = 0x8D70, // Store four unsigned 32-bit components per pixel.
233    READ_ONLY = 0x88B8, // Use the GL numeric code for read only.
234    WRITE_ONLY = 0x88B9, // Use the GL numeric code for write only.
235    READ_WRITE = 0x88BA, // Use the GL numeric code for read write.
236    UNPACK_ALIGNMENT = 0x0CF5, // Use the GL numeric code for unpack alignment.
237    UNPACK_ROW_LENGTH = 0x0CF2, // Use the GL numeric code for unpack row length.
238    UNPACK_SKIP_ROWS = 0x0CF3, // Use the GL numeric code for unpack skip rows.
239    UNPACK_SKIP_PIXELS = 0x0CF4, // Use the GL numeric code for unpack skip pixels.
240    PIXEL_UNPACK_BUFFER = 0x88EC, // Use the GL numeric code for pixel unpack buffer.
241    SYNC_GPU_COMMANDS_COMPLETE = 0x9117, // Use the GL numeric code for sync gpu commands complete.
242    ALREADY_SIGNALED = 0x911A, // Use the GL numeric code for already signaled.
243    TIMEOUT_EXPIRED = 0x911B, // Use the GL numeric code for timeout expired.
244    CONDITION_SATISFIED = 0x911C, // Use the GL numeric code for condition satisfied.
245    WAIT_FAILED = 0x911D, // Use the GL numeric code for wait failed.
246    SYNC_FLUSH_COMMANDS_BIT = 1 // Use the GL numeric code for sync flush commands bit.
247}; // End this scope in runtime.
248
249struct gl_api { // Keep the gl api values and operations together.
250#define SHDR_GL_PROC(ret, n, args) /* Declare a GL function pointer with its exact argument types. */ \
251    typedef ret(SHDR_GL_CALL* n##_type) args; /* Name the representation used by this GL or shader interface. */ \
252    n##_type n; /* Store the resolved function pointer for this GL entry point. */
253    SHDR_GL_PROC(const unsigned char*, GetString, (GLenum)) // Declare a function to read the driver version or renderer text.
254    SHDR_GL_PROC(void, GetIntegerv, (GLenum, GLint*)) // Declare a function to read a scalar device limit or current binding.
255    SHDR_GL_PROC(void, GetIntegeri_v, (GLenum, GLuint, GLint*)) // Declare a function to read the limit for a selected compute axis.
256    SHDR_GL_PROC(GLenum, GetError, ()) // Declare a function to read the pending GL error code.
257    SHDR_GL_PROC(GLuint, CreateShader, (GLenum)) // Declare a function to allocate a compute shader object.
258    SHDR_GL_PROC(void, ShaderSource, (GLuint, GLsizei, const char* const*, const GLint*)) // Declare a function to supply the embedded shader text to the driver.
259    SHDR_GL_PROC(void, CompileShader, (GLuint)) // Declare a function to ask the driver to compile the compute shader.
260    SHDR_GL_PROC(void, GetShaderiv, (GLuint, GLenum, GLint*)) // Declare a function to read shader compilation status or log length.
261    SHDR_GL_PROC(void, GetShaderInfoLog, (GLuint, GLsizei, GLsizei*, char*)) // Declare a function to read the driver explanation of a shader compilation failure.
262    SHDR_GL_PROC(void, DeleteShader, (GLuint)) // Declare a function to release the temporary shader object.
263    SHDR_GL_PROC(GLuint, CreateProgram, ()) // Declare a function to allocate the linked compute program.
264    SHDR_GL_PROC(void, AttachShader, (GLuint, GLuint)) // Declare a function to attach the compute shader before linking.
265    SHDR_GL_PROC(void, LinkProgram, (GLuint)) // Declare a function to link the compiled compute program.
266    SHDR_GL_PROC(void, GetProgramiv, (GLuint, GLenum, GLint*)) // Declare a function to read linked-program status, log length, or local dimensions.
267    SHDR_GL_PROC(void, GetProgramInfoLog, (GLuint, GLsizei, GLsizei*, char*)) // Declare a function to read the driver explanation of a program-link failure.
268    SHDR_GL_PROC(void, DeleteProgram, (GLuint)) // Declare a function to release the GL program after its owners finish using it.
269    SHDR_GL_PROC(void, UseProgram, (GLuint)) // Declare a function to select the compute program for the next dispatch.
270    SHDR_GL_PROC(GLint, GetUniformLocation, (GLuint, const char*)) // Declare a function to find a named uniform in the linked program.
271    SHDR_GL_PROC(void, Uniform1f, (GLint, float)) // Declare a function to assign a float uniform.
272    SHDR_GL_PROC(void, Uniform1i, (GLint, GLint)) // Declare a function to assign an integer or boolean uniform.
273    SHDR_GL_PROC(void, Uniform1ui, (GLint, GLuint)) // Declare a function to assign an unsigned integer uniform.
274#define SHDR_GL_UNIFORM(n) /* Define the SHDR_GL_UNIFORM helper for this group of declarations. */ \
275    SHDR_GL_PROC(void, Uniform##n##fv, (GLint, GLsizei, const float*)) /* Declare a function to send this typed uniform to GL. */ \
276    SHDR_GL_PROC(void, Uniform##n##iv, (GLint, GLsizei, const GLint*)) /* Declare a function to send this typed uniform to GL. */ \
277    SHDR_GL_PROC(void, Uniform##n##uiv, (GLint, GLsizei, const GLuint*)) /* Declare a function to send this typed uniform to GL. */
278    SHDR_GL_UNIFORM(2) // Declare the GL functions for vectors with this component count.
279    SHDR_GL_UNIFORM(3) // Declare the GL functions for vectors with this component count.
280    SHDR_GL_UNIFORM(4) // Declare the GL functions for vectors with this component count.
281#undef SHDR_GL_UNIFORM // Remove this temporary macro after its declarations are complete.
282#define SHDR_GL_MATRIX(n) /* Define the SHDR_GL_MATRIX helper for this group of declarations. */ \
283    SHDR_GL_PROC(void, UniformMatrix##n##fv, (GLint, GLsizei, GLboolean, const float*)) /* Declare a function to send this typed uniform to GL. */
284    SHDR_GL_MATRIX(2) // Declare the GL function for this column-major matrix shape.
285    SHDR_GL_MATRIX(3) // Declare the GL function for this column-major matrix shape.
286    SHDR_GL_MATRIX(4) // Declare the GL function for this column-major matrix shape.
287    SHDR_GL_MATRIX(2x3) // Declare the GL function for this column-major matrix shape.
288    SHDR_GL_MATRIX(2x4) // Declare the GL function for this column-major matrix shape.
289    SHDR_GL_MATRIX(3x2) // Declare the GL function for this column-major matrix shape.
290    SHDR_GL_MATRIX(3x4) // Declare the GL function for this column-major matrix shape.
291    SHDR_GL_MATRIX(4x2) // Declare the GL function for this column-major matrix shape.
292    SHDR_GL_MATRIX(4x3) // Declare the GL function for this column-major matrix shape.
293#undef SHDR_GL_MATRIX // Remove this temporary macro after its declarations are complete.
294    SHDR_GL_PROC(void, GenBuffers, (GLsizei, GLuint*)) // Declare a function to allocate names for GL storage buffers.
295    SHDR_GL_PROC(void, DeleteBuffers, (GLsizei, const GLuint*)) // Declare a function to release owned GL buffer names.
296    SHDR_GL_PROC(void, BindBuffer, (GLenum, GLuint)) // Declare a function to select a buffer for allocation or transfer.
297    SHDR_GL_PROC(void, BufferData, (GLenum, GLsizeiptr, const void*, GLenum)) // Declare a function to allocate buffer storage and supply its initial host values.
298    SHDR_GL_PROC(void, BufferSubData, (GLenum, GLintptr, GLsizeiptr, const void*)) // Declare a function to upload the current host buffer values.
299    SHDR_GL_PROC(void, BindBufferBase, (GLenum, GLuint, GLuint)) // Declare a function to bind storage to the shader interface index.
300    SHDR_GL_PROC(void*, MapBufferRange, (GLenum, GLintptr, GLsizeiptr, GLbitfield)) // Declare a function to map completed GPU buffer values for a host readback.
301    SHDR_GL_PROC(GLboolean, UnmapBuffer, (GLenum)) // Declare a function to finish reading the mapped GPU buffer.
302    SHDR_GL_PROC(void, DispatchCompute, (GLuint, GLuint, GLuint)) // Declare a function to queue the shader workgroups.
303    SHDR_GL_PROC(void, MemoryBarrier, (GLbitfield)) // Declare a function to make earlier resource writes visible to following GPU commands.
304    SHDR_GL_PROC(void, Finish, ()) // Declare a function to explicitly wait until queued GPU commands complete.
305    SHDR_GL_PROC(GLsync, FenceSync, (GLenum, GLbitfield)) // Declare a function to insert a completion fence after queued compute work.
306    SHDR_GL_PROC(GLenum, ClientWaitSync, (GLsync, GLbitfield, GLuint64)) // Declare a function to check a GPU fence with the caller-selected timeout.
307    SHDR_GL_PROC(void, DeleteSync, (GLsync)) // Declare the GL completion-fence deletion entry point.
308    SHDR_GL_PROC(void, Flush, ()) // Declare the GL command-flush entry point.
309    SHDR_GL_PROC(void, GenTextures, (GLsizei, GLuint*)) // Declare a function to allocate names for owned GL images.
310    SHDR_GL_PROC(void, DeleteTextures, (GLsizei, const GLuint*)) // Declare a function to release owned GL image names.
311    SHDR_GL_PROC(void, BindTexture, (GLenum, GLuint)) // Declare a function to select the image for allocation or upload.
312    SHDR_GL_PROC(void, TexStorage2D, (GLenum, GLsizei, GLenum, GLsizei, GLsizei)) // Declare a function to allocate immutable two-dimensional image storage.
313    SHDR_GL_PROC(void, // Declare the next dynamically resolved GL function signature.
314                 TexSubImage2D, // Name the function that uploads pixels into an existing texture.
315                 (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const void*)) // Match the argument order required by this GL entry point.
316    SHDR_GL_PROC(void, BindImageTexture, (GLuint, GLuint, GLint, GLboolean, GLint, GLenum, GLenum)) // Declare a function to bind a typed image to its shader interface index.
317    SHDR_GL_PROC(void, PixelStorei, (GLenum, GLint)) // Declare a function to set or restore the application pixel-transfer layout.
318#undef SHDR_GL_PROC // Remove this temporary macro after its declarations are complete.
319    explicit gl_api(const std::function<void*(const char*)>& resolver) { // Resolve the GL calls used by resource transfers and dispatches.
320#define SHDR_LOAD(n) /* Resolve one GL entry point and reject missing functions. */ \
321    { /* Begin the protected scope for this operation. */ \
322        void* p = resolver("gl" #n); /* Resolve the address of this named GL entry point. */ \
323        if (!p) /* Reject a missing dynamically resolved GL function. */ \
324            throw error("missing GL entry point: gl" #n); /* Report missing gl entry point: gl. */ \
325        static_assert(sizeof(p) == sizeof(n), "function pointer size unsupported"); /* Require a representation that matches the shader interface. */ \
326        std::memcpy(&n, &p, sizeof(n)); /* Copy the representation with the alias-safe byte-copy operation. */ \
327    } /* End this scope in gl api. */
328        SHDR_LOAD(GetString) // Load the function to read the driver version or renderer text.
329        SHDR_LOAD(GetIntegerv) // Load the function to read a scalar device limit or current binding.
330        SHDR_LOAD(GetIntegeri_v) // Load the function to read the limit for a selected compute axis.
331        SHDR_LOAD(GetError) // Load the function to read the pending GL error code.
332        SHDR_LOAD(CreateShader) // Load the function to allocate a compute shader object.
333        SHDR_LOAD(ShaderSource) // Load the function to supply the embedded shader text to the driver.
334        SHDR_LOAD(CompileShader) // Load the function to ask the driver to compile the compute shader.
335        SHDR_LOAD(GetShaderiv) // Load the function to read shader compilation status or log length.
336        SHDR_LOAD(GetShaderInfoLog) // Load the function to read the driver explanation of a shader compilation failure.
337        SHDR_LOAD(DeleteShader) // Load the function to release the temporary shader object.
338        SHDR_LOAD(CreateProgram) // Load the function to allocate the linked compute program.
339        SHDR_LOAD(AttachShader) // Load the function to attach the compute shader before linking.
340        SHDR_LOAD(LinkProgram) // Load the function to link the compiled compute program.
341        SHDR_LOAD(GetProgramiv) // Load the function to read linked-program status, log length, or local dimensions.
342        SHDR_LOAD(GetProgramInfoLog) // Load the function to read the driver explanation of a program-link failure.
343        SHDR_LOAD(DeleteProgram) // Load the function to release the GL program after its owners finish using it.
344        SHDR_LOAD(UseProgram) // Load the function to select the compute program for the next dispatch.
345        SHDR_LOAD(GetUniformLocation) // Load the function to find a named uniform in the linked program.
346        SHDR_LOAD(Uniform1f) // Load the function to assign a float uniform.
347        SHDR_LOAD(Uniform1i) // Load the function to assign an integer or boolean uniform.
348        SHDR_LOAD(Uniform1ui) // Load the function to assign an unsigned integer uniform.
349#define SHDR_LOAD_UNIFORM(n) /* Load the float, signed and unsigned uniform functions for this vector width. */ \
350    SHDR_LOAD(Uniform##n##fv) /* Load the function to send this typed uniform to GL. */ \
351    SHDR_LOAD(Uniform##n##iv) /* Load the function to send this typed uniform to GL. */ \
352    SHDR_LOAD(Uniform##n##uiv) /* Load the function to send this typed uniform to GL. */
353        SHDR_LOAD_UNIFORM(2) // Load the float, signed and unsigned uniform functions for this vector width.
354        SHDR_LOAD_UNIFORM(3) // Load the float, signed and unsigned uniform functions for this vector width.
355        SHDR_LOAD_UNIFORM(4) // Load the float, signed and unsigned uniform functions for this vector width.
356#undef SHDR_LOAD_UNIFORM // Remove this temporary macro after its declarations are complete.
357        SHDR_LOAD(UniformMatrix2fv) // Load the function to send this typed uniform to GL.
358        SHDR_LOAD(UniformMatrix3fv) // Load the function to send this typed uniform to GL.
359        SHDR_LOAD(UniformMatrix4fv) // Load the function to send this typed uniform to GL.
360        SHDR_LOAD(UniformMatrix2x3fv) // Load the function to send this typed uniform to GL.
361        SHDR_LOAD(UniformMatrix2x4fv) // Load the function to send this typed uniform to GL.
362        SHDR_LOAD(UniformMatrix3x2fv) // Load the function to send this typed uniform to GL.
363        SHDR_LOAD(UniformMatrix3x4fv) // Load the function to send this typed uniform to GL.
364        SHDR_LOAD(UniformMatrix4x2fv) // Load the function to send this typed uniform to GL.
365        SHDR_LOAD(UniformMatrix4x3fv) // Load the function to send this typed uniform to GL.
366        SHDR_LOAD(GenBuffers) // Load the function to allocate names for GL storage buffers.
367        SHDR_LOAD(DeleteBuffers) // Load the function to release owned GL buffer names.
368        SHDR_LOAD(BindBuffer) // Load the function to select a buffer for allocation or transfer.
369        SHDR_LOAD(BufferData) // Load the function to allocate buffer storage and supply its initial host values.
370        SHDR_LOAD(BufferSubData) // Load the function to upload the current host buffer values.
371        SHDR_LOAD(BindBufferBase) // Load the function to bind storage to the shader interface index.
372        SHDR_LOAD(MapBufferRange) // Load the function to map completed GPU buffer values for a host readback.
373        SHDR_LOAD(UnmapBuffer) // Load the function to finish reading the mapped GPU buffer.
374        SHDR_LOAD(DispatchCompute) // Load the function to queue the shader workgroups.
375        SHDR_LOAD(MemoryBarrier) // Load the function to make earlier resource writes visible to following GPU commands.
376        SHDR_LOAD(Finish) // Load the function to explicitly wait until queued GPU commands complete.
377        SHDR_LOAD(GenTextures) // Load the function to allocate names for owned GL images.
378        SHDR_LOAD(DeleteTextures) // Load the function to release owned GL image names.
379        SHDR_LOAD(FenceSync) // Load the function to insert a completion fence after queued compute work.
380        SHDR_LOAD(ClientWaitSync) // Load the function to check a GPU fence with the caller-selected timeout.
381        SHDR_LOAD(DeleteSync) // Resolve the GL completion-fence deletion entry point.
382        SHDR_LOAD(Flush) // Resolve the GL command-flush entry point.
383        SHDR_LOAD(BindTexture) // Load the function to select the image for allocation or upload.
384        SHDR_LOAD(TexStorage2D) // Load the function to allocate immutable two-dimensional image storage.
385        SHDR_LOAD(TexSubImage2D) // Load the function to upload the current host pixel values.
386        SHDR_LOAD(BindImageTexture) // Load the function to bind a typed image to its shader interface index.
387        SHDR_LOAD(PixelStorei) // Load the function to set or restore the application pixel-transfer layout.
388#undef SHDR_LOAD // Remove this temporary macro after its declarations are complete.
389    } // End this scope in gl api.
390    void check(const std::string& operation) const { // Check for a driver error from the preceding GL operation.
391        const unsigned code = GetError(); // Read the pending GL error code.
392        if (code) { // Choose this branch when code.
393            std::ostringstream s; // Build a readable diagnostic containing the operation and GL error.
394            s << operation << ": GL error 0x" << std::hex << code; // Combine the operation name and hexadecimal driver error.
395            throw error(s.str()); // Report the invalid operation.
396        } // End this scope in runtime.
397    } // End this scope in runtime.
398}; // End this scope in runtime.
399#undef SHDR_GL_CALL // Remove this temporary macro after its declarations are complete.
400
401struct device_state { // Retain GL functions, context ownership, limits, and pending cleanup.
402    gl_api gl; // Keep the retained GL function table.
403    profile language; // Keep the selected shader profile.
404    unsigned max_groups[3], max_local[3], max_invocations, max_buffers, max_images; // Keep work group dimensions, invocation and resource binding limits.
405    std::shared_ptr<void> context_keepalive; // Keep the retained headless context.
406    std::function<void()> activate_context; // Keep the callback that makes this device context current.
407    std::thread::id context_thread; // Keep the thread allowed to issue GL commands.
408    std::mutex retirement_mutex; // Keep the lock for deferred resource cleanup.
409    std::vector<std::function<void(gl_api&)>> retirements; // Keep GL deletions requested by another thread.
410    struct deferred { // Keep the deferred values and operations together.
411        std::function<bool(gl_api&)> poll; // Keep the zero-time completion callback.
412        std::function<void(gl_api&)> cancel; // Keep the fence-deletion callback used at shutdown.
413    }; // End this scope in runtime.
414    std::vector<deferred> pending_work; // Keep discarded submissions awaiting completion.
415    bool retirements_closed; // Keep whether device teardown has stopped retaining submissions.
416    device_state(const std::function<void*(const char*)>& resolver, profile p) // Load GL entry points and validate the selected compute profile.
417        : gl(resolver), language(p), context_thread(std::this_thread::get_id()), // Resolve GL functions and record this context's profile and owning thread.
418          retirements_closed(false) { // Allow pending completion leases until the public device is destroyed.
419        const unsigned char* version = gl.GetString(VERSION); // Read the current context version before checking the requested profile.
420        if (!version) // Require a version string from the current context.
421            throw error("device requires a current GL context"); // Report device requires a current gl context.
422        const bool es = std::string(reinterpret_cast<const char*>(version)).find("OpenGL ES") != // Set whether the current context uses OpenGL ES.
423                        std::string::npos; // Detect the GLES marker anywhere in the driver version string.
424        const bool requested_es = p == profile::es31 || p == profile::es32; // Set whether the requested profile uses GLES.
425        if (es != requested_es) // Choose this branch when es differs from requested es.
426            throw error("shader profile does not match current GL/ES context"); // Report a mismatch between the selected profile and the current context.
427        GLint major = 0, minor = 0; // Prepare both parts of the current GL version query.
428        gl.GetIntegerv(MAJOR_VERSION, &major); // Read a scalar device limit or current binding.
429        gl.GetIntegerv(MINOR_VERSION, &minor); // Read a scalar device limit or current binding.
430        const int required_major = es ? 3 : 4; // Set the minimum GL major version for this profile.
431        const int required_minor = p == profile::es31   ? 1 // Set the minimum GL minor version for this profile.
432                                   : p == profile::es32 ? 2 // Select the version associated with this shader profile.
433                                   : p == profile::gl43 ? 3 // Select the version associated with this shader profile.
434                                   : p == profile::gl45 ? 5 // Select the version associated with this shader profile.
435                                                        : 6; // Select minor version six for the desktop GL 4.6 profile.
436        if (major < required_major || (major == required_major && minor < required_minor)) // Choose this branch when major < required major or (major equals required major and minor < required minor).
437            throw error("current context is older than requested compute profile"); // Report current context is older than requested compute profile.
438        for (unsigned i = 0; i < 3; ++i) { // Validate or query each of the three compute dimensions.
439            GLint n = 0; // Set the queried GL limit or element count.
440            gl.GetIntegeri_v(MAX_COMPUTE_WORK_GROUP_COUNT, i, &n); // Read the limit for a selected compute axis.
441            max_groups[i] = static_cast<unsigned>(n); // Set the device workgroup-count limits.
442            gl.GetIntegeri_v(MAX_COMPUTE_WORK_GROUP_SIZE, i, &n); // Read the limit for a selected compute axis.
443            max_local[i] = static_cast<unsigned>(n); // Set the device local-size limits.
444        } // End this scope in device state.
445        GLint n = 0; // Set the queried GL limit or element count.
446        gl.GetIntegerv(MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &n); // Read a scalar device limit or current binding.
447        max_invocations = static_cast<unsigned>(n); // Set the maximum invocations in one workgroup.
448        gl.GetIntegerv(MAX_SHADER_STORAGE_BUFFER_BINDINGS, &n); // Read a scalar device limit or current binding.
449        max_buffers = static_cast<unsigned>(n); // Set the storage-buffer binding limit.
450        gl.GetIntegerv(MAX_IMAGE_UNITS, &n); // Read a scalar device limit or current binding.
451        max_images = static_cast<unsigned>(n); // Set the image binding limit.
452        gl.check("query compute capabilities"); // Check for a driver error from the preceding GL operation.
453    } // End this scope in device state.
454    void require_thread() { // Require the device context thread and activate its headless context.
455        if (std::this_thread::get_id() != context_thread) // Check that the operation uses the context or lifecycle thread.
456            throw error("GL operations require the device's context thread"); // Report gl operations require the device's context thread.
457        if (activate_context) // Choose this branch when activate context.
458            activate_context(); // Keep the callback that makes this device context current.
459    } // End this scope in require thread.
460    void collect() { // Run queued deletions and zero-time completion checks.
461        require_thread(); // Require the device context thread and activate its headless context.
462        std::vector<std::function<void(gl_api&)>> pending; // Keep the queued work or cleanup callbacks awaiting processing.
463        std::vector<deferred> polls, unfinished; // Keep completion polls that must be checked again.
464        { // Begin the protected scope for this operation.
465            std::lock_guard<std::mutex> lock(retirement_mutex); // Hold the mutex while this shared state is accessed.
466            pending.swap(retirements); // Take the shared entries into a local collection for unlocked processing.
467            polls.swap(pending_work); // Take the shared entries into a local collection for unlocked processing.
468        } // End this scope in collect.
469        for (std::size_t i = 0; i < pending.size(); ++i) // Process the cleanup or completion callbacks taken from the queue.
470            pending[i](gl); // Keep the retained GL function table.
471        for (std::size_t i = 0; i < polls.size(); ++i) // Process the cleanup or completion callbacks taken from the queue.
472            if (!polls[i].poll(gl)) // Retain a completion callback while its work is pending.
473                unfinished.push_back(std::move(polls[i])); // Retain this entry in the ordered resource or work collection.
474        if (!unfinished.empty()) { // Keep the remaining callbacks for the next collection pass.
475            std::lock_guard<std::mutex> lock(retirement_mutex); // Hold the mutex while this shared state is accessed.
476            pending_work.insert(pending_work.end(), // Retain this entry in the ordered resource or work collection.
477                                std::make_move_iterator(unfinished.begin()), // Supply the next value for the current call or declaration.
478                                std::make_move_iterator(unfinished.end())); // Keep the end of the current range.
479        } // End this scope in collect.
480    } // End this scope in collect.
481    void defer_poll(const std::function<bool(gl_api&)>& poll, // Retain a completion check until its fence signals.
482                    const std::function<void(gl_api&)>& cancel = std::function<void(gl_api&)>()) { // Set the fence-deletion callback used at shutdown.
483        { // Begin the protected scope for this operation.
484            std::lock_guard<std::mutex> lock(retirement_mutex); // Hold the mutex while this shared state is accessed.
485            if (!retirements_closed) { // Check whether teardown still allows retained completion callbacks.
486                pending_work.push_back(deferred{poll, cancel}); // Retain this entry in the ordered resource or work collection.
487                return; // Finish this operation.
488            } // End this scope in defer poll.
489        } // End this scope in defer poll.
490 // Handles may outlive the public device wrapper. After wrapper teardown,
491 // schedule their fence deletion directly on the context thread.
492        if (cancel) // Choose this branch when cancel.
493            retire(cancel); // Delete on the context thread or defer deletion to that thread.
494    } // End this scope in defer poll.
495    void close_retirements() { // Stop retaining new submission bundles during device teardown.
496        { // Begin the protected scope for this operation.
497            std::lock_guard<std::mutex> lock(retirement_mutex); // Hold the mutex while this shared state is accessed.
498            retirements_closed = true; // Set whether device teardown has stopped retaining submissions.
499        } // End this scope in close retirements.
500        cancel_pending(); // Schedule deferred-fence deletion on the context thread.
501    } // End this scope in close retirements.
502    void cancel_pending() { // Schedule deferred-fence deletion on the context thread.
503        require_thread(); // Require the device context thread and activate its headless context.
504        std::vector<deferred> pending; // Keep the queued work or cleanup callbacks awaiting processing.
505        { // Begin the protected scope for this operation.
506            std::lock_guard<std::mutex> lock(retirement_mutex); // Hold the mutex while this shared state is accessed.
507            pending.swap(pending_work); // Take the shared entries into a local collection for unlocked processing.
508        } // End this scope in cancel pending.
509        for (std::size_t i = 0; i < pending.size(); ++i) // Process the cleanup or completion callbacks taken from the queue.
510            if (pending[i].cancel) // Check the queue state before accepting or executing work.
511                pending[i].cancel(gl); // Keep the retained GL function table.
512        pending.clear(); // Release the retained entries after their work or cleanup is complete.
513        collect(); // Run queued deletions and zero-time completion checks.
514    } // End this scope in cancel pending.
515    void retire(const std::function<void(gl_api&)>& deletion) { // Delete on the context thread or defer deletion to that thread.
516        if (std::this_thread::get_id() == context_thread) { // Check that the operation uses the context or lifecycle thread.
517            require_thread(); // Require the device context thread and activate its headless context.
518            deletion(gl); // Keep the retained GL function table.
519        } else { // Handle the alternative resource or completion case.
520            std::lock_guard<std::mutex> lock(retirement_mutex); // Hold the mutex while this shared state is accessed.
521            retirements.push_back(deletion); // Retain this entry in the ordered resource or work collection.
522        } // End this scope in retire.
523    } // End this scope in retire.
524    ~device_state() noexcept { // Close pending retirement leases on the context thread.
525        if (std::this_thread::get_id() == context_thread) { // Check that the operation uses the context or lifecycle thread.
526            try { // Keep cleanup available if an allocation, shader, or driver operation fails.
527                close_retirements(); // Stop retaining new submission bundles during device teardown.
528            } catch (...) { // Preserve cleanup or exception propagation for this failed operation.
529            } // End this scope in device state.
530        } // End this scope in device state.
531    } // End this scope in device state.
532    GLuint compile(const std::string& source, const std::string& name) { // Compile and link the embedded compute source with driver diagnostics.
533        if (source.size() > static_cast<std::size_t>((std::numeric_limits<GLint>::max)())) // Check resource size or driver limits before accessing storage.
534            throw error("shader source too large"); // Report shader source too large.
535        GLuint shader = gl.CreateShader(COMPUTE_SHADER), program = 0; // Allocate a compute shader object.
536        if (!shader) // Check that the driver allocated a shader object.
537            throw error("cannot create compute shader"); // Report compute-shader allocation failure.
538        try { // Keep cleanup available if an allocation, shader, or driver operation fails.
539            const char* text = source.c_str(); // Give GL a pointer to the retained shader characters.
540            GLint len = static_cast<GLint>(source.size()); // Pass the validated shader character count to GL.
541            gl.ShaderSource(shader, 1, &text, &len); // Supply the embedded shader text to the driver.
542            gl.CompileShader(shader); // Ask the driver to compile the compute shader.
543            GLint success = 0; // Prepare the compile or link status returned by GL.
544            gl.GetShaderiv(shader, COMPILE_STATUS, &success); // Read shader compilation status or log length.
545            if (!success) { // Read the driver diagnostic for this failed operation.
546                GLint size = 0; // Prepare the driver diagnostic log length.
547                gl.GetShaderiv(shader, INFO_LOG_LENGTH, &size); // Read shader compilation status or log length.
548                std::vector<char> log(static_cast<std::size_t>((std::max)(size, 1)), 0); // Allocate enough characters for the driver diagnostic and terminator.
549                gl.GetShaderInfoLog(shader, size, 0, log.data()); // Read the driver explanation of a shader compilation failure.
550                throw error(name + ": shader compilation failed\n" + log.data()); // Report : shader compilation failed\n.
551            } // End this scope in compile.
552            program = gl.CreateProgram(); // Allocate the linked compute program.
553            if (!program) // Check that the driver allocated a program object.
554                throw error("cannot create compute program"); // Report compute-program allocation failure.
555            gl.AttachShader(program, shader); // Attach the compute shader before linking.
556            gl.LinkProgram(program); // Link the compiled compute program.
557            gl.GetProgramiv(program, LINK_STATUS, &success); // Read linked-program status, log length, or local dimensions.
558            if (!success) { // Read the driver diagnostic for this failed operation.
559                GLint size = 0; // Prepare the driver diagnostic log length.
560                gl.GetProgramiv(program, INFO_LOG_LENGTH, &size); // Read linked-program status, log length, or local dimensions.
561                std::vector<char> log(static_cast<std::size_t>((std::max)(size, 1)), 0); // Allocate enough characters for the driver diagnostic and terminator.
562                gl.GetProgramInfoLog(program, size, 0, log.data()); // Read the driver explanation of a program-link failure.
563                throw error(name + ": program link failed\n" + log.data()); // Report : program link failed\n.
564            } // End this scope in compile.
565            gl.DeleteShader(shader); // Release the temporary shader object.
566            shader = 0; // Set the shader used by this dispatch.
567            gl.check("link " + name); // Keep the resource or entry-point name.
568            return program; // Compile and link the embedded compute source with driver diagnostics.
569        } catch (...) { // Preserve cleanup or exception propagation for this failed operation.
570            if (shader) // Choose this branch when shader.
571                gl.DeleteShader(shader); // Release the temporary shader object.
572            if (program) // Choose this branch when program.
573                gl.DeleteProgram(program); // Release the GL program after its owners finish using it.
574            throw; // Rethrow the original failure after arranging the necessary cleanup.
575        } // End this scope in compile.
576    } // End this scope in compile.
577}; // End this scope in runtime.
578struct program_state { // Keep the program state values and operations together.
579    std::shared_ptr<device_state> owner; // Keep the device that owns the GL resource.
580    GLuint id; // Keep the compiled GL program name.
581    program_state(const std::shared_ptr<device_state>& d, GLuint id_) : owner(d), id(id_) { // Expose the retained compiled program for asynchronous ownership.
582    } // End this scope in program state.
583    ~program_state() { // Release this object's owned resources at teardown.
584        if (id) { // Choose this branch when id.
585            const GLuint name = id; // Set the resource or entry-point name.
586            owner->retire([name](gl_api& gl) { // Delete on the context thread or defer deletion to that thread.
587                gl.DeleteProgram(name); // Release the GL program after its owners finish using it.
588            }); // End this scope in program state.
589        } // End this scope in program state.
590    } // End this scope in program state.
591}; // End this scope in runtime.
592
593inline std::size_t checked_product(std::size_t a, std::size_t b) { // Reject resource-size multiplication that would overflow.
594    if (b && a > (std::numeric_limits<std::size_t>::max)() / b) // Check resource size or driver limits before accessing storage.
595        throw error("resource size overflow"); // Report resource size overflow.
596    return a * b; // Reject resource-size multiplication that would overflow.
597} // End this scope in checked product.
598inline GLsizeiptr gl_size(std::size_t size) { // Require a byte count representable by the GL buffer API.
599    if (size > static_cast<std::size_t>((std::numeric_limits<GLsizeiptr>::max)())) // Check resource size or driver limits before accessing storage.
600        throw error("resource exceeds GLsizeiptr"); // Report resource exceeds glsizeiptr.
601    return static_cast<GLsizeiptr>(size); // Require a byte count representable by the GL buffer API.
602} // End this scope in gl size.
603enum class authority { host, gpu, both }; // Name the profile, access, or completion values accepted by this section.
604enum class resource_kind { buffer, image }; // Name the profile, access, or completion values accepted by this section.
605struct resource_state { // Track shared storage and which backend has the newest values.
606    resource_kind kind; // Keep the buffer, image, or uniform interface kind.
607    authority latest; // Keep which copy contains the latest resource values.
608    std::shared_ptr<device_state> owner; // Keep the device that owns the GL resource.
609    GLuint handle; // Keep the GL buffer or texture name.
610    bool borrowed; // Keep whether the application owns the supplied GL object.
611    unsigned width, height, components, format, scalar; // Keep the GL scalar representation.
612    resource_state(resource_kind k) // Initialize ownership and synchronization for one resource.
613        : kind(k), latest(authority::host), handle(0), borrowed(false), width(0), height(0), // Start with authoritative host data and allocate GL storage on demand.
614          components(0), format(0), scalar(0) { // Initialize image layout metadata to zero.
615    } // End this scope in resource state.
616    virtual ~resource_state() { // Release this object's owned resources at teardown.
617        if (handle && !borrowed) { // Delete the resource when its GL handle is owned by this object.
618            const GLuint name = handle; // Set the resource or entry-point name.
619            if (kind == resource_kind::buffer) // Choose the branch matching this interface or resource access.
620                owner->retire([name](gl_api& gl) { // Delete on the context thread or defer deletion to that thread.
621                    gl.DeleteBuffers(1, &name); // Release owned GL buffer names.
622                }); // End this scope in resource state.
623            else // Handle the other resource, platform, or completion case.
624                owner->retire([name](gl_api& gl) { // Delete on the context thread or defer deletion to that thread.
625                    gl.DeleteTextures(1, &name); // Release owned GL image names.
626                }); // End this scope in resource state.
627        } // End this scope in resource state.
628    } // End this scope in resource state.
629    virtual void* host_pointer() = 0; // Require each resource type to expose its host storage.
630    virtual std::size_t bytes() const = 0; // Require each resource type to report its byte count.
631    void ensure_host(); // Download newer GPU values only when host access needs them.
632    void ensure_gpu(const std::shared_ptr<device_state>& d) { // Allocate or upload GPU storage when its host copy is newer.
633        d->collect(); // Run queued deletions and zero-time completion checks.
634        if (owner && owner != d) // Check that this storage belongs to the requested device.
635            throw error("resource belongs to a different device"); // Report resource belongs to a different device.
636        owner = d; // Set the device that owns the GL resource.
637        const gl_api& gl = d->gl; // Set the retained GL function table.
638        if (!handle) { // Allocate GPU storage on the first device access.
639            if (kind == resource_kind::buffer) { // Choose the branch matching this interface or resource access.
640                gl.GenBuffers(1, &handle); // Allocate names for GL storage buffers.
641                gl.BindBuffer(SHADER_STORAGE_BUFFER, handle); // Select a buffer for allocation or transfer.
642                gl.BufferData(SHADER_STORAGE_BUFFER, // Allocate buffer storage and supply its initial host values.
643                              gl_size(bytes()), // Require a byte count representable by the GL buffer API.
644                              bytes() ? host_pointer() : 0, // Supply the next value for the current call or declaration.
645                              DYNAMIC_DRAW); // Require a byte count representable by the GL buffer API.
646            } else { // Handle the alternative resource or completion case.
647                gl.GenTextures(1, &handle); // Allocate names for owned GL images.
648                gl.BindTexture(TEXTURE_2D, handle); // Select the image for allocation or upload.
649                gl.TexStorage2D(TEXTURE_2D, // Allocate immutable two-dimensional image storage.
650                                1, // Supply the next value for the current call or declaration.
651                                format, // Visit the values or interfaces needed by ensure gpu.
652                                static_cast<GLsizei>(width), // Keep the image width in pixels.
653                                static_cast<GLsizei>(height)); // Keep the image height in pixels.
654            } // End this scope in ensure gpu.
655            gl.check("allocate compute resource"); // Check for a driver error from the preceding GL operation.
656            if (kind == resource_kind::buffer) // Choose the branch matching this interface or resource access.
657                latest = authority::both; // Record which backend now owns the newest resource values.
658        } // End this scope in ensure gpu.
659        if (latest == authority::host) { // Check which resource copy must be synchronized.
660            if (kind == resource_kind::buffer) { // Choose the branch matching this interface or resource access.
661                gl.BindBuffer(SHADER_STORAGE_BUFFER, handle); // Select a buffer for allocation or transfer.
662                if (bytes()) // Check resource size or driver limits before accessing storage.
663                    gl.BufferSubData(SHADER_STORAGE_BUFFER, 0, gl_size(bytes()), host_pointer()); // Upload the current host buffer values.
664            } else { // Handle the alternative resource or completion case.
665 // Make upload independent of caller pixel unpack state and restore that state.
666                GLint alignment = 0, row = 0, skip_rows = 0, skip_pixels = 0, pbo = 0; // Save the complete pixel-unpack layout and bound transfer buffer.
667                gl.GetIntegerv(UNPACK_ALIGNMENT, &alignment); // Read a scalar device limit or current binding.
668                gl.GetIntegerv(UNPACK_ROW_LENGTH, &row); // Read a scalar device limit or current binding.
669                gl.GetIntegerv(UNPACK_SKIP_ROWS, &skip_rows); // Read a scalar device limit or current binding.
670                gl.GetIntegerv(UNPACK_SKIP_PIXELS, &skip_pixels); // Read a scalar device limit or current binding.
671                gl.GetIntegerv(0x88EF, &pbo); // GL_PIXEL_UNPACK_BUFFER_BINDING
672                gl.BindBuffer(PIXEL_UNPACK_BUFFER, 0); // Select a buffer for allocation or transfer.
673                gl.PixelStorei(UNPACK_ALIGNMENT, 1); // Set or restore the application pixel-transfer layout.
674                gl.PixelStorei(UNPACK_ROW_LENGTH, 0); // Set or restore the application pixel-transfer layout.
675                gl.PixelStorei(UNPACK_SKIP_ROWS, 0); // Set or restore the application pixel-transfer layout.
676                gl.PixelStorei(UNPACK_SKIP_PIXELS, 0); // Set or restore the application pixel-transfer layout.
677                gl.BindTexture(TEXTURE_2D, handle); // Select the image for allocation or upload.
678                const GLenum channels = scalar == FLOAT // Choose the float or integer pixel-transfer channel representation.
679                                            ? (components == 1 ? RED : RGBA) // Set the number of scalar values per pixel.
680                                            : (components == 1 ? RED_INTEGER : RGBA_INTEGER); // Choose the upload pixel format matching integer channels.
681                gl.TexSubImage2D(TEXTURE_2D, // Upload the current host pixel values.
682                                 0, // Supply the next value for the current call or declaration.
683                                 0, // Supply the next value for the current call or declaration.
684                                 0, // Supply the next value for the current call or declaration.
685                                 static_cast<GLsizei>(width), // Keep the image width in pixels.
686                                 static_cast<GLsizei>(height), // Keep the image height in pixels.
687                                 channels, // Supply the next value for the current call or declaration.
688                                 scalar, // Keep the GL scalar representation.
689                                 host_pointer()); // Expose this resource's borrowed or owned host storage.
690                gl.PixelStorei(UNPACK_ALIGNMENT, alignment); // Set or restore the application pixel-transfer layout.
691                gl.PixelStorei(UNPACK_ROW_LENGTH, row); // Set or restore the application pixel-transfer layout.
692                gl.PixelStorei(UNPACK_SKIP_ROWS, skip_rows); // Set or restore the application pixel-transfer layout.
693                gl.PixelStorei(UNPACK_SKIP_PIXELS, skip_pixels); // Set or restore the application pixel-transfer layout.
694                gl.BindBuffer(PIXEL_UNPACK_BUFFER, static_cast<GLuint>(pbo)); // Select a buffer for allocation or transfer.
695            } // End this scope in ensure gpu.
696            gl.check("upload compute resource"); // Check for a driver error from the preceding GL operation.
697            latest = authority::both; // Record which backend now owns the newest resource values.
698        } // End this scope in ensure gpu.
699    } // End this scope in ensure gpu.
700}; // End this scope in runtime.
701
702 // Image readback uses a compute copy on both desktop GL and GLES.
703inline void resource_state::ensure_host() { // Download newer GPU values only when host access needs them.
704    if (latest != authority::gpu) // Check which resource copy must be synchronized.
705        return; // Finish this operation.
706    owner->collect(); // Run queued deletions and zero-time completion checks.
707    const gl_api& gl = owner->gl; // Set the retained GL function table.
708    if (!bytes()) { // Check resource size or driver limits before accessing storage.
709        latest = authority::both; // Record which backend now owns the newest resource values.
710        return; // Finish this operation.
711    } // End this scope in ensure host.
712    GLuint staging = 0, program = 0; // Track the temporary readback buffer and copy program for cleanup.
713    try { // Keep cleanup available if an allocation, shader, or driver operation fails.
714        gl.MemoryBarrier(ALL_BARRIER_BITS); // Make earlier resource writes visible to following GPU commands.
715        if (kind == resource_kind::buffer) // Choose the branch matching this interface or resource access.
716            gl.BindBuffer(SHADER_STORAGE_BUFFER, handle); // Select a buffer for allocation or transfer.
717        else { // Handle the other resource, platform, or completion case.
718            const char* scalar_name = scalar == FLOAT ? "float" : scalar == INT ? "int" : "uint"; // Choose the GLSL scalar spelling matching these image pixels.
719            const char* vector_name = scalar == FLOAT ? "vec4" : scalar == INT ? "ivec4" : "uvec4"; // Choose the four-component GLSL value used by imageLoad.
720            const char* image_name = scalar == FLOAT ? "image2D" // Choose the matching float, signed or unsigned storage-image type.
721                                     : scalar == INT ? "iimage2D" // Choose the shader image type matching the resource's scalar representation.
722                                                     : "uimage2D"; // Choose the shader image type matching the resource's scalar representation.
723            const char* format_name = components == 1 ? (scalar == FLOAT ? "r32f" // Choose the declared storage-image format for the copy shader.
724                                                         : scalar == INT ? "r32i" // Choose the shader format matching scalar type and channel count.
725                                                                         : "r32ui") // Choose the shader format matching scalar type and channel count.
726                                                      : (scalar == FLOAT ? "rgba32f" // Choose the shader format matching scalar type and channel count.
727                                                         : scalar == INT ? "rgba32i" // Choose the shader format matching scalar type and channel count.
728                                                                         : "rgba32ui"); // Choose the shader format matching scalar type and channel count.
729            std::ostringstream body; // Download newer GPU values only when host access needs them.
730            body << "SHDR_BEGIN(shdr_readback,8,8,1)\nSHDR_IMAGE2D(0," << format_name << ',' // Download newer GPU values only when host access needs them.
731                 << image_name << ",src,readonly)\n" // Download newer GPU values only when host access needs them.
732                 << "SHDR_BUFFER(0," << scalar_name // Download newer GPU values only when host access needs them.
733                 << ",dst,writeonly)\nSHDR_MAIN(){uvec2 p=gl_GlobalInvocationID.xy;" // Download newer GPU values only when host access needs them.
734                 << "ivec2 s=imageSize(src);if(p.x>=uint(s.x)||p.y>=uint(s.y))return;" // Download newer GPU values only when host access needs them.
735                 << vector_name << " v=imageLoad(src,ivec2(p));uint i=(p.y*uint(s.x)+p.x)*" // Download newer GPU values only when host access needs them.
736                 << components << "u;"; // Download newer GPU values only when host access needs them.
737            for (unsigned c = 0; c < components; ++c) // Visit the values or interfaces needed by ensure host.
738                body << "dst[i+" << c << "u]=v[" << c << "];"; // Download newer GPU values only when host access needs them.
739            body << "} SHDR_END()\n"; // Download newer GPU values only when host access needs them.
740            program = owner->compile(glsl_source(body.str(), owner->language), "image readback"); // Compile the portable image-to-buffer readback shader.
741            gl.GenBuffers(1, &staging); // Allocate names for GL storage buffers.
742            gl.BindBuffer(SHADER_STORAGE_BUFFER, staging); // Select a buffer for allocation or transfer.
743            gl.BufferData(SHADER_STORAGE_BUFFER, gl_size(bytes()), 0, DYNAMIC_DRAW); // Allocate buffer storage and supply its initial host values.
744            gl.UseProgram(program); // Select the compute program for the next dispatch.
745            gl.BindBufferBase(SHADER_STORAGE_BUFFER, 0, staging); // Bind storage to the shader interface index.
746            gl.BindImageTexture(0, handle, 0, 0, 0, READ_ONLY, format); // Bind a typed image to its shader interface index.
747            gl.DispatchCompute((width + 7) / 8, (height + 7) / 8, 1); // Queue the shader workgroups.
748            gl.MemoryBarrier(ALL_BARRIER_BITS); // Make earlier resource writes visible to following GPU commands.
749            gl.check("copy image to host staging buffer"); // Check for a driver error from the preceding GL operation.
750            gl.BindBuffer(SHADER_STORAGE_BUFFER, staging); // Select a buffer for allocation or transfer.
751        } // End this scope in ensure host.
752        void* mapped = gl.MapBufferRange(SHADER_STORAGE_BUFFER, 0, gl_size(bytes()), MAP_READ_BIT); // Map completed GPU buffer values for a host readback.
753        if (!mapped) { // Check that GL returned a readable mapped range.
754            gl.check("map compute readback"); // Check for a driver error from the preceding GL operation.
755            throw error("cannot map compute readback"); // Report readback mapping failure.
756        } // End this scope in ensure host.
757        std::memcpy(host_pointer(), mapped, bytes()); // Copy the representation with the alias-safe byte-copy operation.
758        if (!gl.UnmapBuffer(SHADER_STORAGE_BUFFER)) // Finish reading the mapped GPU buffer.
759            throw error("compute readback buffer contents corrupted"); // Report compute readback buffer contents corrupted.
760        gl.check("read back compute resource"); // Check for a driver error from the preceding GL operation.
761        latest = authority::both; // Record which backend now owns the newest resource values.
762        if (staging) // Choose this branch when staging.
763            gl.DeleteBuffers(1, &staging); // Release owned GL buffer names.
764        if (program) // Choose this branch when program.
765            gl.DeleteProgram(program); // Release the GL program after its owners finish using it.
766    } catch (...) { // Preserve cleanup or exception propagation for this failed operation.
767        if (staging) // Choose this branch when staging.
768            gl.DeleteBuffers(1, &staging); // Release owned GL buffer names.
769        if (program) // Choose this branch when program.
770            gl.DeleteProgram(program); // Release the GL program after its owners finish using it.
771        throw; // Rethrow the original failure after arranging the necessary cleanup.
772    } // End this scope in ensure host.
773} // End this scope in ensure host.
774
775 // Only layouts identical to std430 arrays are accepted. vec3, bool and arbitrary structs need explicit packing.
776template <class T> // Select the scalar, dimension, or access type at compile time.
777struct storage_type // Keep the storage type values and operations together.
778    : std::integral_constant<bool, // Expose the following storage-layout checks as a compile-time boolean.
779                             std::is_same<T, float>::value || std::is_same<T, int>::value || // Accept the supported 32-bit float and signed integer storage types.
780                                 std::is_same<T, unsigned>::value> {}; // Also accept the supported 32-bit unsigned storage type.
781template <class T, std::size_t N> // Select the scalar, dimension, or access type at compile time.
782struct storage_type<glsl::vec<T, N>> // Keep the storage type values and operations together.
783    : std::integral_constant<bool, // Expose the following storage-layout checks as a compile-time boolean.
784                             storage_type<T>::value && (N == 2 || N == 4) && // Require a supported scalar and a two- or four-component vector.
785                                 sizeof(glsl::vec<T, N>) == sizeof(T) * N> {}; // Require a tightly packed vector that matches its std430 array stride.
786template <class T> struct buffer_state : resource_state { // Select the scalar, dimension, or access type at compile time.
787    std::vector<T> owned; // Keep host storage allocated by this resource.
788    T* external; // Point to application-owned host memory.
789    std::size_t count; // Keep the element or configuration count.
790    explicit buffer_state(std::size_t n) // Allocate owned host storage for this number of elements.
791        : resource_state(resource_kind::buffer), owned(n), external(0), count(n) { // Initialize ownership and synchronization for one resource.
792    } // End this scope in runtime.
793    buffer_state(T* p, std::size_t n) // Retain a reference to an application-owned host range.
794        : resource_state(resource_kind::buffer), external(p), count(n) { // Initialize ownership and synchronization for one resource.
795        if (!p && n) // Require a valid pointer for a nonempty borrowed range.
796            throw error("null borrowed CPU buffer"); // Report null borrowed cpu buffer.
797    } // End this scope in runtime.
798    void* host_pointer() override { // Expose this resource's borrowed or owned host storage.
799        return external ? external : owned.data(); // Use borrowed host memory when present and owned memory otherwise.
800    } // End this scope in runtime.
801    std::size_t bytes() const override { // Report this resource's byte count with overflow checking.
802        return checked_product(count, sizeof(T)); // Calculate the byte count with checked size arithmetic.
803    } // End this scope in runtime.
804}; // End this scope in runtime.
805template <class T> struct image_state : resource_state { // Select the scalar, dimension, or access type at compile time.
806    std::vector<T> owned; // Keep host storage allocated by this resource.
807    image_state(unsigned w, unsigned h, unsigned c) : resource_state(resource_kind::image) { // Initialize ownership and synchronization for one resource.
808        if (!w || !h || w > static_cast<unsigned>((std::numeric_limits<GLsizei>::max)()) || // Check resource size or driver limits before accessing storage.
809            h > static_cast<unsigned>((std::numeric_limits<GLsizei>::max)())) // Require the image height to fit the GL signed dimension type.
810            throw error("image dimensions must be positive GLsizei values"); // Report image dimensions must be positive glsizei values.
811        width = w; // Set the image width in pixels.
812        height = h; // Set the image height in pixels.
813        components = c; // Set the number of scalar values per pixel.
814        scalar = std::is_same<T, float>::value ? FLOAT // Set the GL scalar representation.
815                 : std::is_same<T, int>::value ? INT // Choose the GL scalar type matching the host pixel representation.
816                                               : UNSIGNED_INT; // Choose the GL scalar type matching the host pixel representation.
817        format = c == 1 ? (scalar == FLOAT ? R32F // Visit the values or interfaces needed by runtime.
818                           : scalar == INT ? R32I // Choose the GL internal image format matching scalar type and channel count.
819                                           : R32UI) // Choose the GL internal image format matching scalar type and channel count.
820                        : (scalar == FLOAT ? RGBA32F // Choose the GL internal image format matching scalar type and channel count.
821                           : scalar == INT ? RGBA32I // Choose the GL internal image format matching scalar type and channel count.
822                                           : RGBA32UI); // Choose the GL internal image format matching scalar type and channel count.
823        owned.resize(checked_product(checked_product(w, h), c)); // Reject resource-size multiplication that would overflow.
824    } // End this scope in runtime.
825    void* host_pointer() override { // Expose this resource's borrowed or owned host storage.
826        return owned.data(); // Expose the contiguous host storage owned by this resource.
827    } // End this scope in runtime.
828    std::size_t bytes() const override { // Report this resource's byte count with overflow checking.
829        return checked_product(owned.size(), sizeof(T)); // Calculate the byte count with checked size arithmetic.
830    } // End this scope in runtime.
831}; // End this scope in runtime.
832} // namespace detail
833
834/** @brief An application's current GL context, accessed through its function resolver.
835 * The context must remain current on this thread during operations and destruction of GL objects.
836 * The default header uses standard C++11 declarations. The optional
837 * headless_device supplies EGL context creation when SHDR_ENABLE_EGL is enabled.
838 */
839class device { // Keep the device values and operations together.
840    std::shared_ptr<detail::device_state> state_; // Keep the state shared by this wrapper and its retained owners.
841
842  public: // Expose the operations callers can use.
843    /** @brief Load GL entry points and validate the current context against a profile.
844     * @param resolver Callable returning the address of a named GL function, or null.
845     * @param p Minimum GLSL and GL/ES profile. defaults to ES 3.1.
846     * @throws error If function resolution or current-context validation fails.
847     */
848    explicit device(const std::function<void*(const char*)>& resolver, profile p = profile::es31) // Create a compute device using the caller's current context and function resolver.
849        : state_(std::make_shared<detail::device_state>(resolver, p)) { // Retain the resolved GL functions, profile and device limits.
850    } // End this scope in device.
851    /** @brief Release deferred completion handles through context-thread cleanup.
852     * Destroy devices on their context thread after CPU workers have stopped.
853     */
854    virtual ~device() noexcept { // Close pending retirement leases on the context thread.
855        if (std::this_thread::get_id() == state_->context_thread) { // Check that the operation uses the context or lifecycle thread.
856            try { // Keep cleanup available if an allocation, shader, or driver operation fails.
857                state_->close_retirements(); // Stop retaining new submission bundles during device teardown.
858            } catch (...) { // Preserve cleanup or exception propagation for this failed operation.
859            } // End this scope in device.
860        } // End this scope in device.
861    } // End this scope in device.
862    device(const device&) = delete; // Prevent copying this object and duplicating its retained identity.
863    device& operator=(const device&) = delete; // Prevent copying this object and duplicating its retained identity.
864    /** @brief Return the shader language profile selected for this device. */
865    profile shader_profile() const { // Return the device profile used to generate shader source.
866        return state_->language; // Return the device profile used to generate shader source.
867    } // End this scope in shader profile.
868    /** @brief Wait for submitted GPU work to complete, including for accurate wall-clock benchmarks. */
869    void synchronize() { // Explicitly wait for completed GPU commands.
870        state_->collect(); // Run queued deletions and zero-time completion checks.
871        state_->gl.Finish(); // Explicitly wait until queued GPU commands complete.
872        state_->gl.check("wait for GPU completion"); // Check for a driver error from the preceding GL operation.
873    } // End this scope in synchronize.
874    /** @brief Delete GL objects retired by CPU workers and poll pending completions. */
875    void collect_garbage() { // Collect deferred GL deletions and poll completion fences.
876        state_->collect(); // Run queued deletions and zero-time completion checks.
877    } // End this scope in collect garbage.
878    /** @brief Current GL renderer name, for diagnostics and reproducible benchmark reports. */
879    std::string renderer() const { // Read the current renderer name for reproducible diagnostics.
880        state_->require_thread(); // Require the device context thread and activate its headless context.
881        const unsigned char* s = state_->gl.GetString(0x1F01); // Read the driver version or renderer text.
882        if (!s) // Validate the renderer query from the current context.
883            throw error("no current GL context"); // Report that the renderer query requires a current GL context.
884        return reinterpret_cast<const char*>(s); // Read the current renderer name for reproducible diagnostics.
885    } // End this scope in renderer.
886    /** @internal Runtime access to the retained GL function table and device limits. */
887    const std::shared_ptr<detail::device_state>& state() const { // Expose retained runtime state to the resource and backend helpers.
888        return state_; // Return the storage or execution state retained by this wrapper.
889    } // End this scope in state.
890}; // End this scope in runtime.
891
892/** @brief Shared typed std430 storage, owned or borrowed, with automatic CPU/GPU synchronization.
893 * Copying a buffer shares its storage. Mutable data() marks host data authoritative.
894 * Obtain a fresh data() pointer after a GPU dispatch before accessing host values.
895 * GPU handles belong to one device.
896 */
897template <class T> class buffer { // Select the scalar, dimension, or access type at compile time.
898    static_assert(detail::storage_type<T>::value, // Require a representation that matches the shader interface.
899                  "buffer requires float/int/uint or matching vec2/vec4 std430 layout"); // Explain which element types match the supported storage-buffer layout.
900    static_assert(sizeof(float) == 4 && sizeof(int) == 4 && sizeof(unsigned) == 4, // Require a representation that matches the shader interface.
901                  "shdr requires 32-bit GLSL scalars"); // Require the host scalar representation to match GLSL storage.
902    std::shared_ptr<detail::buffer_state<T>> state_; // Keep the state shared by this wrapper and its retained owners.
903
904  public: // Expose the operations callers can use.
905    /** @brief Allocate a zero-initialized host buffer containing n elements.
906     * GPU storage is allocated lazily. Zero-length buffers are valid on the CPU.
907     * GPU storage-buffer bindings require at least one element.
908     */
909    explicit buffer(std::size_t n = 0) : state_(std::make_shared<detail::buffer_state<T>>(n)) { // Create a typed buffer with owned host storage.
910        if (n > static_cast<std::size_t>((std::numeric_limits<unsigned>::max)())) // Check resource size or driver limits before accessing storage.
911            throw error("buffer length exceeds GLSL uint"); // Report buffer length exceeds glsl uint.
912        detail::gl_size(state_->bytes()); // Require a byte count representable by the GL buffer API.
913    } // End this scope in buffer.
914    /** @brief Borrow n elements stored in application-owned host memory.
915     * Keep the memory alive while any resource copy or shader port retains it.
916     * Call mark_host_modified() after writing through the original pointer.
917     */
918    buffer(T* p, std::size_t n) : state_(std::make_shared<detail::buffer_state<T>>(p, n)) { // Initialize the typed resource storage and validate its size.
919        if (n > static_cast<std::size_t>((std::numeric_limits<unsigned>::max)())) // Check resource size or driver limits before accessing storage.
920            throw error("buffer length exceeds GLSL uint"); // Report buffer length exceeds glsl uint.
921        detail::gl_size(state_->bytes()); // Require a byte count representable by the GL buffer API.
922    } // End this scope in buffer.
923    /** @brief Allocate owned host storage and copy an initializer list into it. */
924    buffer(std::initializer_list<T> values) : buffer(values.size()) { // Initialize the typed resource storage and validate its size.
925        std::copy(values.begin(), values.end(), data()); // Access host values after bringing their resource copy up to date.
926    } // End this scope in buffer.
927    /** @brief Return the stored element count. */
928    std::size_t size() const { // Read the stored element or stage count.
929        return state_->count; // Return the result of this check or operation.
930    } // End this scope in runtime.
931    /** @brief Synchronize newer GPU contents and return mutable host elements.
932     * Marks host data modified. Reacquire this pointer after GPU work before using it.
933     */
934    T* data() { // Access host values after bringing their resource copy up to date.
935        state_->ensure_host(); // Download newer GPU values only when host access needs them.
936        state_->latest = detail::authority::host; // Record which backend now owns the newest resource values.
937        return static_cast<T*>(state_->host_pointer()); // Access host values after bringing their resource copy up to date.
938    } // End this scope in data.
939    /** @brief Synchronize newer GPU contents and return readonly host elements. */
940    const T* data() const { // Access host values after bringing their resource copy up to date.
941        state_->ensure_host(); // Download newer GPU values only when host access needs them.
942        return static_cast<const T*>(state_->host_pointer()); // Access host values after bringing their resource copy up to date.
943    } // End this scope in data.
944    /** @brief Access one host element after synchronization. reject an out-of-range index. */
945    T& operator[](std::size_t i) { // Bounds-check this host element before returning its typed reference.
946        if (i >= size()) // Check resource size or driver limits before accessing storage.
947            throw error("host buffer index out of range"); // Report host buffer index out of range.
948        return data()[i]; // Return the result of this check or operation.
949    } // End this scope in runtime.
950    /** @brief Read one host element after synchronization. reject an out-of-range index. */
951    const T& operator[](std::size_t i) const { // Bounds-check this host element before returning its typed reference.
952        if (i >= size()) // Check resource size or driver limits before accessing storage.
953            throw error("host buffer index out of range"); // Report host buffer index out of range.
954        return data()[i]; // Return the result of this check or operation.
955    } // End this scope in runtime.
956    /** @brief Ensure this device has the latest contents, allocating or uploading as needed. */
957    void upload(device& d) { // Explicitly make current host values available to the GPU.
958        state_->ensure_gpu(d.state()); // Allocate or upload GPU storage when its host copy is newer.
959    } // End this scope in upload.
960    /** @brief Download newer GPU contents. reject a different owning device. */
961    void download(device& d) { // Explicitly bring newer GPU values back to host storage.
962        if (state_->owner && state_->owner != d.state()) // Check that this storage belongs to the requested device.
963            throw error("resource belongs to a different device"); // Report resource belongs to a different device.
964        state_->ensure_host(); // Download newer GPU values only when host access needs them.
965    } // End this scope in download.
966    /** @brief Obtain the synchronized GL SSBO handle for application interop. */
967    unsigned gl_handle(device& d) { // Expose a synchronized GL resource handle for interoperation.
968        upload(d); // Explicitly make current host values available to the GPU.
969        return state_->handle; // Expose a synchronized GL resource handle for interoperation.
970    } // End this scope in gl handle.
971    /** @brief Notify shdr after the application writes the GL buffer. its context must be current. */
972    void mark_gpu_modified(device& d) { // Record a write performed by application GL commands.
973        if (state_->owner != d.state() || !state_->handle) // Check that this storage belongs to the requested device.
974            throw error("resource has no handle on this device"); // Report a mismatch between the resource handle and the device.
975        state_->latest = detail::authority::gpu; // Record which backend now owns the newest resource values.
976    } // End this scope in mark gpu modified.
977    /** @brief Notify shdr after changing previously obtained or borrowed host memory.
978     * Call data() before editing if GPU data must first be preserved.
979     */
980    void mark_host_modified() { // Record a write through retained or borrowed host memory.
981        state_->latest = detail::authority::host; // Record which backend now owns the newest resource values.
982    } // End this scope in mark host modified.
983    /** @brief Borrow an existing SSBO. Its contents initially belong to the GPU. caller retains ownership. */
984    static buffer from_gl(device& d, unsigned handle, std::size_t count) { // Borrow an application-owned GL object.
985        if (!handle) // Validate the resource handle before using it.
986            throw error("cannot borrow GL buffer zero"); // Require a nonzero GL buffer handle.
987        buffer result(count); // Keep the element or configuration count.
988        result.state_->owner = d.state(); // Set the device that owns the GL resource.
989        result.state_->handle = handle; // Set the GL buffer or texture name.
990        result.state_->borrowed = true; // Set whether the application owns the supplied GL object.
991        result.state_->latest = detail::authority::gpu; // Record which backend now owns the newest resource values.
992        return result; // Return the value returned by this operation.
993    } // End this scope in from gl.
994    /** @internal Runtime access to shared resource storage and synchronization state. */
995    const std::shared_ptr<detail::buffer_state<T>>& state() const { // Expose retained runtime state to the resource and backend helpers.
996        return state_; // Return the storage or execution state retained by this wrapper.
997    } // End this scope in state.
998}; // End this scope in runtime.
999
1000/** @brief Interleaved 32-bit scalar or RGBA image shared between CPU and GPU.
1001 * C is 1 or 4. T is float, int, or unsigned. Use matching r32f/r32i/r32ui or
1002 * rgba32f/rgba32i/rgba32ui GLSL declarations. Copies and bound ports alias storage.
1003 */
1004template <class T, unsigned C = 1> class image2d { // Select the scalar, dimension, or access type at compile time.
1005    static_assert(detail::storage_type<T>::value && std::is_arithmetic<T>::value, // Require a representation that matches the shader interface.
1006                  "image requires float/int/uint"); // Require an image scalar type supported by the runtime.
1007    static_assert(C == 1 || C == 4, "portable image formats have one or four components"); // Require a representation that matches the shader interface.
1008    std::shared_ptr<detail::image_state<T>> state_; // Keep the state shared by this wrapper and its retained owners.
1009
1010  public: // Expose the operations callers can use.
1011    /** @brief Allocate a zero-initialized image with positive width and height in pixels. */
1012    image2d(unsigned w, unsigned h) : state_(std::make_shared<detail::image_state<T>>(w, h, C)) { // Initialize the image geometry and typed pixel storage.
1013    } // End this scope in image2d.
1014    /** @brief Return the stored number of pixels in each row. */
1015    unsigned width() const { // Return the image width in pixels.
1016        return state_->width; // Return the result of this check or operation.
1017    } // End this scope in runtime.
1018    /** @brief Return the stored number of pixel rows. */
1019    unsigned height() const { // Return the image height in pixels.
1020        return state_->height; // Return the result of this check or operation.
1021    } // End this scope in runtime.
1022    /** @brief Synchronize newer GPU contents and return mutable interleaved host pixels.
1023     * Index component c at (x,y) as data()[(y*width()+x)*C+c]. Marks host data
1024     * modified. reacquire the pointer after GPU work before using it.
1025     */
1026    T* data() { // Access host values after bringing their resource copy up to date.
1027        state_->ensure_host(); // Download newer GPU values only when host access needs them.
1028        state_->latest = detail::authority::host; // Record which backend now owns the newest resource values.
1029        return static_cast<T*>(state_->host_pointer()); // Access host values after bringing their resource copy up to date.
1030    } // End this scope in data.
1031    /** @brief Synchronize newer GPU contents and return readonly interleaved host pixels. */
1032    const T* data() const { // Access host values after bringing their resource copy up to date.
1033        state_->ensure_host(); // Download newer GPU values only when host access needs them.
1034        return static_cast<const T*>(state_->host_pointer()); // Access host values after bringing their resource copy up to date.
1035    } // End this scope in data.
1036    /** @brief Ensure this device has the latest pixels, allocating or uploading as needed. */
1037    void upload(device& d) { // Explicitly make current host values available to the GPU.
1038        state_->ensure_gpu(d.state()); // Allocate or upload GPU storage when its host copy is newer.
1039    } // End this scope in upload.
1040    /** @brief Download newer GPU pixels through a portable compute-to-buffer copy. */
1041    void download(device& d) { // Explicitly bring newer GPU values back to host storage.
1042        if (state_->owner && state_->owner != d.state()) // Check that this storage belongs to the requested device.
1043            throw error("resource belongs to a different device"); // Report resource belongs to a different device.
1044        state_->ensure_host(); // Download newer GPU values only when host access needs them.
1045    } // End this scope in download.
1046    /** @brief Obtain the synchronized level-zero GL texture handle for application interop. */
1047    unsigned gl_handle(device& d) { // Expose a synchronized GL resource handle for interoperation.
1048        upload(d); // Explicitly make current host values available to the GPU.
1049        return state_->handle; // Expose a synchronized GL resource handle for interoperation.
1050    } // End this scope in gl handle.
1051    /** @brief Notify shdr after the application writes the GL texture. its context must be current. */
1052    void mark_gpu_modified(device& d) { // Record a write performed by application GL commands.
1053        if (state_->owner != d.state() || !state_->handle) // Check that this storage belongs to the requested device.
1054            throw error("resource has no handle on this device"); // Report a mismatch between the resource handle and the device.
1055        state_->latest = detail::authority::gpu; // Record which backend now owns the newest resource values.
1056    } // End this scope in mark gpu modified.
1057    /** @brief Notify shdr after changing a retained host pixel pointer. */
1058    void mark_host_modified() { // Record a write through retained or borrowed host memory.
1059        state_->latest = detail::authority::host; // Record which backend now owns the newest resource values.
1060    } // End this scope in mark host modified.
1061    /** @brief Borrow a matching immutable-format, level-zero 2D GL texture. caller retains ownership. */
1062    static image2d from_gl(device& d, unsigned handle, unsigned w, unsigned h) { // Borrow an application-owned GL object.
1063        if (!handle) // Validate the resource handle before using it.
1064            throw error("cannot borrow GL texture zero"); // Require a nonzero GL texture handle.
1065        image2d result(w, h); // Allocate host pixel storage before attaching the borrowed texture.
1066        result.state_->owner = d.state(); // Set the device that owns the GL resource.
1067        result.state_->handle = handle; // Set the GL buffer or texture name.
1068        result.state_->borrowed = true; // Set whether the application owns the supplied GL object.
1069        result.state_->latest = detail::authority::gpu; // Record which backend now owns the newest resource values.
1070        return result; // Return the value returned by this operation.
1071    } // End this scope in from gl.
1072    /** @internal Runtime access to shared image storage and synchronization state. */
1073    const std::shared_ptr<detail::image_state<T>>& state() const { // Expose retained runtime state to the resource and backend helpers.
1074        return state_; // Return the storage or execution state retained by this wrapper.
1075    } // End this scope in state.
1076}; // End this scope in runtime.
1077
1078class kernel; // Keep the kernel values and operations together.
1079namespace detail { // Group these definitions in the detail namespace.
1080enum class port_kind { buffer, image, uniform }; // Name the profile, access, or completion values accepted by this section.
1081struct port_base { // Keep the port base values and operations together.
1082    kernel& parent; // Keep the shader instance that owns this interface.
1083    std::string name; // Keep the resource or entry-point name.
1084    unsigned binding; // Keep the numeric shader resource binding.
1085    access mode; // Keep the declared shader resource access.
1086    port_kind kind; // Keep the buffer, image, or uniform interface kind.
1087    port_base(kernel&, const char*, unsigned, access, port_kind); // Register the named interface with its owning shader.
1088    virtual ~port_base() { // Allow typed interfaces to be destroyed through this base interface.
1089    } // End this scope in runtime.
1090    virtual std::shared_ptr<resource_state> resource() const { // Expose the retained storage used by this port.
1091        return std::shared_ptr<resource_state>(); // Represent a uniform-only interface with an empty resource reference.
1092    } // End this scope in runtime.
1093    virtual void bind_gpu(device_state&, GLuint) { // Bind this interface or assign its uniform before dispatch.
1094    } // End this scope in bind gpu.
1095    virtual void validate() const { // Check that this resource binding satisfies the shader declaration.
1096    } // End this scope in validate.
1097    virtual void copy_to(port_base&) const { // Copy the typed port into a matching snapshot interface.
1098        throw error("shader port does not support snapshots"); // Report that this port requires snapshot support.
1099    } // End this scope in copy to.
1100}; // End this scope in runtime.
1101} // namespace detail
1102
1103/** @brief Base for compiled shader objects, owning resource declarations and invocation builtins.
1104 * Shader objects are neither copyable nor movable because their ports refer to their instance.
1105 * CMake-generated adapters embed their native GLSL source automatically.
1106 */
1107class kernel { // Keep the kernel values and operations together.
1108    std::string name_, source_; // Keep the diagnostic shader name and its embedded GLSL text.
1109    extent local_; // Keep the fixed workgroup dimensions.
1110    std::vector<detail::port_base*> ports_; // Keep the registered resource and uniform interfaces.
1111    std::shared_ptr<detail::program_state> program_; // Keep the retained compiled compute program.
1112
1113  protected: // Allow derived kernels to initialize their embedded source.
1114 // Generated shader constructors install their build-embedded GLSL through this method.
1115    void set_embedded_source(const char* text) { // Retain the build-generated GLSL text inside the shader.
1116        source_ = text; // Set the automatically embedded shader text.
1117    } // End this scope in runtime.
1118
1119  public: // Expose the operations callers can use.
1120    glsl::uvec3 gl_GlobalInvocationID, gl_LocalInvocationID, gl_WorkGroupID, gl_NumWorkGroups, // Keep CPU global, local, group and dispatch coordinates for GLSL builtins.
1121        gl_WorkGroupSize; // Keep the fixed local dimensions exposed to CPU shader code.
1122    unsigned gl_LocalInvocationIndex; // Keep the flattened index within the current CPU work group.
1123    /** @brief Construct a kernel identity and positive local workgroup dimensions.
1124     * SHDR_BEGIN emits this constructor for shared shader classes.
1125     */
1126    kernel(const std::string& name, extent local) // Initialize the shader name, local dimensions, and invocation values.
1127        : name_(name), local_(local), gl_LocalInvocationIndex(0) { // Remember the shader name and local size with initially zero CPU invocation state.
1128        if (!local.x || !local.y || !local.z) // Require positive local dimensions on every axis.
1129            throw error("local work group dimensions must be positive"); // Report local work group dimensions must be positive.
1130        gl_WorkGroupSize = glsl::uvec3(local.x, local.y, local.z); // Publish the fixed local dimensions to CPU shader builtins.
1131    } // End this scope in kernel.
1132    virtual ~kernel() { // Allow derived shader instances to be destroyed through the base interface.
1133    } // End this scope in kernel.
1134    kernel(const kernel&) = delete; // Prevent copying this object and duplicating its retained identity.
1135    kernel& operator=(const kernel&) = delete; // Prevent copying this object and duplicating its retained identity.
1136    /** @brief Execute one CPU invocation. SHDR_MAIN supplies the override.
1137     * Dispatch through a stage or pipeline to initialize builtins and synchronize resources.
1138     */
1139    virtual void main() = 0; // Require a compiled shader to supply its CPU invocation method.
1140    /** @brief Make an independent shader instance with a snapshot of its resource bindings and uniforms. */
1141    virtual std::unique_ptr<kernel> clone() const { // Create an independent shader instance for deferred CPU execution.
1142        throw error("shader does not support snapshots"); // Report that this shader requires snapshot support.
1143    } // End this scope in runtime.
1144    /** @internal Copy registered interfaces into a newly constructed instance. */
1145    void copy_interfaces(kernel& destination) const { // Copy resource bindings and uniforms into a fresh shader clone.
1146        if (ports_.size() != destination.ports_.size()) // Check resource size or driver limits before accessing storage.
1147            throw error("shader snapshot interface mismatch"); // Report shader snapshot interface mismatch.
1148        for (std::size_t i = 0; i < ports_.size(); ++i) // Visit every registered resource and uniform interface.
1149            ports_[i]->copy_to(*destination.ports_[i]); // Copy the typed port into a matching snapshot interface.
1150    } // End this scope in copy interfaces.
1151    /** @internal Retain all resources used by an enqueued dispatch. */
1152    std::vector<std::shared_ptr<detail::resource_state>> resources() const { // Collect the shared storage used by this shader.
1153        std::vector<std::shared_ptr<detail::resource_state>> result; // Keep the value returned by this operation.
1154        for (std::size_t i = 0; i < ports_.size(); ++i) { // Visit every registered resource and uniform interface.
1155            auto r = ports_[i]->resource(); // Get the shared storage behind this resource interface.
1156            if (r) // Choose this branch when r.
1157                result.push_back(r); // Retain this entry in the ordered resource or work collection.
1158        } // End this scope in resources.
1159        return result; // Return the value returned by this operation.
1160    } // End this scope in resources.
1161    /** @internal Retain a compiled program during asynchronous execution. */
1162    const std::shared_ptr<detail::program_state>& program_state() const { // Expose the retained compiled program for asynchronous ownership.
1163        return program_; // Return the retained compiled compute program.
1164    } // End this scope in program state.
1165    /** @brief Return the kernel's diagnostic name. */
1166    const std::string& name() const { // Return the diagnostic shader name.
1167        return name_; // Return the kernel or registration name.
1168    } // End this scope in runtime.
1169    /** @brief Return the fixed local workgroup dimensions declared by SHDR_BEGIN. */
1170    extent local_size() const { // Return the fixed local work group dimensions.
1171        return local_; // Return the fixed workgroup dimensions.
1172    } // End this scope in runtime.
1173    /** @brief Export this shader's automatically embedded source for compiler diagnostics or tooling. */
1174    std::string glsl(profile p) const { // Export the embedded shader for the requested language profile.
1175        if (source_.empty()) // Choose this branch when source .empty().
1176            throw error("shader has no embedded GPU source: " + name_); // Report that this shader requires an embedded GPU program.
1177        return glsl_source(source_, p); // Return the result of this check or operation.
1178    } // End this scope in runtime.
1179    /** @internal Register declarations emitted by the shared shader macros. */
1180    void register_port(detail::port_base& port) { // Register one named resource or uniform with duplicate checks.
1181        for (std::size_t i = 0; i < ports_.size(); ++i) { // Visit every registered resource and uniform interface.
1182            if (ports_[i]->name == port.name) // Choose this branch when ports [i]->name equals port.name.
1183                throw error("duplicate shader port: " + port.name); // Report duplicate shader port: .
1184            if (port.kind != detail::port_kind::uniform && ports_[i]->kind == port.kind && // Choose the branch matching this interface or resource access.
1185                ports_[i]->binding == port.binding) // Set the numeric shader resource binding.
1186                throw error("duplicate shader resource binding: " + port.name); // Report duplicate shader resource binding: .
1187        } // End this scope in register port.
1188        ports_.push_back(&port); // Retain this entry in the ordered resource or work collection.
1189    } // End this scope in register port.
1190    /** @brief Bind by name, for runtime-selected shader modules. Type mismatches throw error. */
1191    template <class T> kernel& bind(const std::string& name, const buffer<T>& resource); // Select the scalar, dimension, or access type at compile time.
1192    /** @brief Bind an image by name. scalar type and component count must match its port. */
1193    template <class T, unsigned C> // Select the scalar, dimension, or access type at compile time.
1194    kernel& bind(const std::string& name, const image2d<T, C>& resource); // Rebind a named resource port while preserving its declared type.
1195    /** @brief Assign a uniform by name. T must exactly match its declared shader type. */
1196    template <class T> kernel& set(const std::string& name, const T& value); // Select the scalar, dimension, or access type at compile time.
1197    /** @internal Find a registered port for runtime binding and uniform assignment. */
1198    detail::port_base& find_port(const std::string& name) { // Resolve the named shader interface.
1199        for (std::size_t i = 0; i < ports_.size(); ++i) // Visit every registered resource and uniform interface.
1200            if (ports_[i]->name == name) // Choose this branch when ports [i]->name equals name.
1201                return *ports_[i]; // Resolve the named shader interface.
1202        throw error("unknown shader port: " + name); // Report unknown shader port: .
1203    } // End this scope in find port.
1204    /** @brief Execute one dispatch with workgroup counts on a device, or on the CPU if null.
1205     * Normally called by pipeline.run(). GPU work uses the embedded shader and a current context.
1206     */
1207    void run(extent groups, device* d); // Keep the target device.
1208    /** @brief Compile and allocate GPU resources before entering a latency-sensitive dispatch loop. */
1209    void prepare(device& d); // Compile the program and prepare its bound GPU resources.
1210}; // End this scope in runtime.
1211
1212namespace detail { // Group these definitions in the detail namespace.
1213inline port_base::port_base(kernel& p, const char* n, unsigned b, access a, port_kind k) // Register the named interface with its owning shader.
1214    : parent(p), name(n), binding(b), mode(a), kind(k) { // Record the owning kernel, interface name, binding, access and resource kind.
1215    parent.register_port(*this); // Register one named resource or uniform with duplicate checks.
1216} // End this scope in runtime.
1217} // namespace detail
1218
1219/** @brief Typed shader SSBO declaration. assign a buffer to bind or rebind it. */
1220template <class T, access A = access::readwrite> class buffer_port : public detail::port_base { // Select the scalar, dimension, or access type at compile time.
1221    std::shared_ptr<detail::buffer_state<T>> state_; // Keep the state shared by this wrapper and its retained owners.
1222    unsigned fixed_length_; // Keep the fixed array length declared by the shader.
1223
1224  public: // Expose the operations callers can use.
1225    /** @brief Declare a typed buffer port on a kernel, usually through SHDR_BUFFER. */
1226    buffer_port(kernel& p, unsigned b, const char* n, unsigned fixed = 0) // Register a typed buffer interface and any fixed shader array length.
1227        : port_base(p, n, b, A, detail::port_kind::buffer), fixed_length_(fixed) { // Record the buffer interface and its optional fixed shader length.
1228    } // End this scope in runtime.
1229    /** @brief Bind or rebind this port to the buffer's retained shared storage. */
1230    buffer_port& operator=(const buffer<T>& b) { // Retain the newly bound typed resource in this shader interface.
1231        state_ = b.state(); // Set the state shared by this wrapper and its retained owners.
1232        return *this; // Allow another operation to follow in the same expression.
1233    } // End this scope in runtime.
1234    void copy_to(detail::port_base& destination) const override { // Copy the typed port into a matching snapshot interface.
1235        buffer_port* p = dynamic_cast<buffer_port*>(&destination); // Require a snapshot port with the same buffer type and access qualifier.
1236        if (!p) // Validate the typed interface pointer before accessing it.
1237            throw error("buffer snapshot type mismatch: " + name); // Report buffer snapshot type mismatch: .
1238        p->state_ = state_; // Set the state shared by this wrapper and its retained owners.
1239    } // End this scope in copy to.
1240    /** @brief Return the bound buffer's element count, matching GLSL array length(). */
1241    unsigned length() const { // Return the GLSL-visible array length after validating its binding.
1242        validate(); // Check that this resource binding satisfies the shader declaration.
1243        return fixed_length_ ? fixed_length_ : static_cast<unsigned>(state_->count); // Return the GLSL-visible array length after validating its binding.
1244    } // End this scope in length.
1245    /** @brief Access an element during CPU execution, checking bounds and declared access.
1246     * Readonly ports return const references. Pipeline execution synchronizes host contents.
1247     */
1248    typename std::conditional<A == access::readonly, const T&, T&>::type operator[](std::size_t i) { // Expose a const component for readonly ports and a mutable one otherwise.
1249        validate(); // Check that this resource binding satisfies the shader declaration.
1250        const std::size_t limit = fixed_length_ ? fixed_length_ : state_->count; // Use the declared array size or the full bound buffer length.
1251        if (i >= limit) // Choose this branch when i >= limit.
1252            throw error("CPU SSBO index out of bounds: " + name); // Report cpu ssbo index out of bounds: .
1253        return static_cast<T*>(state_->host_pointer())[i]; // Return the result of this check or operation.
1254    } // End this scope in runtime.
1255    void validate() const override { // Check that this resource binding satisfies the shader declaration.
1256        if (!state_) // Require retained storage for this interface.
1257            throw error("unbound shader buffer: " + name); // Report unbound shader buffer: .
1258        if (fixed_length_ && state_->count < fixed_length_) // Check resource size or driver limits before accessing storage.
1259            throw error("buffer is smaller than the shader's fixed array: " + name); // Report buffer is smaller than the shader's fixed array: .
1260    } // End this scope in validate.
1261    std::shared_ptr<detail::resource_state> resource() const override { // Expose the retained storage used by this port.
1262        return state_; // Return the storage or execution state retained by this wrapper.
1263    } // End this scope in runtime.
1264    void bind_gpu(detail::device_state& d, unsigned) override { // Bind this interface or assign its uniform before dispatch.
1265        if (binding >= d.max_buffers) // Choose this branch when binding >= d.max buffers.
1266            throw error("SSBO binding exceeds device limit: " + name); // Report ssbo binding exceeds device limit: .
1267        if (!state_->bytes()) // Check resource size or driver limits before accessing storage.
1268            throw error("GPU SSBO bindings require a nonempty buffer: " + name); // Report gpu ssbo bindings require a nonempty buffer: .
1269        d.gl.BindBufferBase(detail::SHADER_STORAGE_BUFFER, binding, state_->handle); // Bind storage to the shader interface index.
1270    } // End this scope in bind gpu.
1271}; // End this scope in runtime.
1272
1273namespace detail { // Group these definitions in the detail namespace.
1274inline void uniform_value(gl_api& gl, GLint loc, float v) { // Send the typed uniform value through its matching GL call.
1275    gl.Uniform1f(loc, v); // Assign a float uniform.
1276} // End this scope in uniform value.
1277inline void uniform_value(gl_api& gl, GLint loc, int v) { // Send the typed uniform value through its matching GL call.
1278    gl.Uniform1i(loc, v); // Assign an integer or boolean uniform.
1279} // End this scope in uniform value.
1280inline void uniform_value(gl_api& gl, GLint loc, unsigned v) { // Send the typed uniform value through its matching GL call.
1281    gl.Uniform1ui(loc, v); // Assign an unsigned integer uniform.
1282} // End this scope in uniform value.
1283inline void uniform_value(gl_api& gl, GLint loc, bool v) { // Send the typed uniform value through its matching GL call.
1284    gl.Uniform1i(loc, v ? 1 : 0); // Assign an integer or boolean uniform.
1285} // End this scope in uniform value.
1286#define SHDR_UNIFORM_VEC(n, t, suffix) /* Define the SHDR_UNIFORM_VEC helper for this group of declarations. */ \
1287    inline void uniform_value(gl_api& gl, GLint loc, const glsl::vec<t, n>& v) { /* Send the typed uniform value through its matching GL call. */ \
1288        t packed[n]; /* Pack the vector components contiguously for the GL uniform call. */ \
1289        for (unsigned i = 0; i < n; ++i) /* Visit the values or interfaces needed by uniform value. */ \
1290            packed[i] = v[i]; /* Copy the component into the contiguous GL uniform payload. */ \
1291        gl.Uniform##n##suffix(loc, 1, packed); /* Send the packed vector components through their matching GL function. */ \
1292    } /* End this scope in uniform value. */
1293SHDR_UNIFORM_VEC(2, float, fv) // Define the listed float, signed or unsigned vector uniform overloads.
1294SHDR_UNIFORM_VEC(3, float, fv) SHDR_UNIFORM_VEC(4, float, fv) SHDR_UNIFORM_VEC(2, int, iv) // Define the listed float, signed or unsigned vector uniform overloads.
1295    SHDR_UNIFORM_VEC(3, int, iv) SHDR_UNIFORM_VEC(4, int, iv) SHDR_UNIFORM_VEC(2, unsigned, uiv) // Define the listed float, signed or unsigned vector uniform overloads.
1296        SHDR_UNIFORM_VEC(3, unsigned, uiv) SHDR_UNIFORM_VEC(4, unsigned, uiv) // Define the listed float, signed or unsigned vector uniform overloads.
1297#undef SHDR_UNIFORM_VEC // Remove this temporary macro after its declarations are complete.
1298            template <std::size_t N> // Select the scalar, dimension, or access type at compile time.
1299            inline void uniform_value(gl_api& gl, GLint loc, const glsl::vec<bool, N>& v) { // Send the typed uniform value through its matching GL call.
1300    GLint packed[N]; // Pack boolean components as the integer values expected by GL.
1301    for (unsigned i = 0; i < N; ++i) // Visit the values or interfaces needed by uniform value.
1302        packed[i] = v[i] ? 1 : 0; // Represent a boolean uniform component as a GL integer.
1303    if (N == 2) // Choose this branch when N equals 2.
1304        gl.Uniform2iv(loc, 1, packed); // Send two integer-represented boolean components to GL.
1305    else if (N == 3) // Choose this branch when N equals 3.
1306        gl.Uniform3iv(loc, 1, packed); // Send three integer-represented boolean components to GL.
1307    else // Handle the other resource, platform, or completion case.
1308        gl.Uniform4iv(loc, 1, packed); // Send four integer-represented boolean components to GL.
1309} // End this scope in uniform value.
1310#define SHDR_UNIFORM_MATRIX(c, r, n) /* Define the SHDR_UNIFORM_MATRIX helper for this group of declarations. */ \
1311    inline void uniform_value(gl_api& gl, GLint loc, const glsl::mat<float, c, r>& m) { /* Send the typed uniform value through its matching GL call. */ \
1312        float packed[c * r]; /* Send the typed uniform value through its matching GL call. */ \
1313        for (unsigned i = 0; i < c; ++i) /* Visit the values or interfaces needed by uniform value. */ \
1314            for (unsigned j = 0; j < r; ++j) /* Visit the values or interfaces needed by uniform value. */ \
1315                packed[i * r + j] = m[i][j]; /* Flatten the matrix in GLSL column order. */ \
1316        gl.UniformMatrix##n##fv(loc, 1, 0, packed); /* Upload the column-major matrix with the transpose flag set to false. */ \
1317    } /* End this scope in uniform value. */
1318SHDR_UNIFORM_MATRIX(2, 2, 2) // Define the listed column-major matrix uniform overloads.
1319SHDR_UNIFORM_MATRIX(3, 3, 3) SHDR_UNIFORM_MATRIX(4, 4, 4) SHDR_UNIFORM_MATRIX(2, 3, 2x3) // Define the listed column-major matrix uniform overloads.
1320    SHDR_UNIFORM_MATRIX(2, 4, 2x4) SHDR_UNIFORM_MATRIX(3, 2, 3x2) SHDR_UNIFORM_MATRIX(3, 4, 3x4) // Define the listed column-major matrix uniform overloads.
1321        SHDR_UNIFORM_MATRIX(4, 2, 4x2) SHDR_UNIFORM_MATRIX(4, 3, 4x3) // Define the listed column-major matrix uniform overloads.
1322#undef SHDR_UNIFORM_MATRIX // Remove this temporary macro after its declarations are complete.
1323} // namespace detail
1324
1325/** @brief A zero-initialized typed shader uniform, assigned with ordinary C++ syntax. */
1326template <class T> class uniform_port : public detail::port_base { // Select the scalar, dimension, or access type at compile time.
1327    T owned_; // Keep the uniform value stored by the port.
1328    T* value_; // Keep the current uniform field.
1329
1330  public: // Expose the operations callers can use.
1331    /** @brief Declare a zero-initialized uniform backed by this port's own value. */
1332    uniform_port(kernel& p, const char* n) // Register a typed uniform backed by this port's own zero-initialized value.
1333        : port_base(p, n, 0, access::readonly, detail::port_kind::uniform), owned_(), // Keep the uniform value stored by the port.
1334          value_(&owned_) { // Keep the uniform value stored by the port.
1335    } // End this scope in runtime.
1336    /** @brief Register an existing typed kernel field as a uniform. emitted by SHDR_UNIFORM. */
1337    uniform_port(kernel& p, const char* n, T& value) // Register a uniform and refer to its shader member value.
1338        : port_base(p, n, 0, access::readonly, detail::port_kind::uniform), owned_(), // Keep the uniform value stored by the port.
1339          value_(&value) { // Refer to the uniform member owned by this shader instance.
1340    } // End this scope in runtime.
1341    /** @brief Set the uniform value uploaded at the next dispatch. */
1342    uniform_port& operator=(const T& value) { // Assign the shader member referred to by this uniform interface.
1343        *value_ = value; // Set the current uniform field.
1344        return *this; // Allow another operation to follow in the same expression.
1345    } // End this scope in runtime.
1346    /** @brief Read the uniform as its declared shader type during CPU execution. */
1347    operator T() const { // Read the uniform member as an ordinary value of its declared type.
1348        return *value_; // Return the result of this check or operation.
1349    } // End this scope in runtime.
1350    /** @brief Return the stored uniform value. */
1351    const T& value() const { // Read the shader member referred to by this uniform port.
1352        return *value_; // Return the result of this check or operation.
1353    } // End this scope in runtime.
1354    void copy_to(detail::port_base& destination) const override { // Copy the typed port into a matching snapshot interface.
1355        uniform_port* p = dynamic_cast<uniform_port*>(&destination); // Require a snapshot port with the same uniform type.
1356        if (!p) // Validate the typed interface pointer before accessing it.
1357            throw error("uniform snapshot type mismatch: " + name); // Report uniform snapshot type mismatch: .
1358        *p->value_ = *value_; // Set the current uniform field.
1359    } // End this scope in copy to.
1360    void bind_gpu(detail::device_state& d, unsigned program) override { // Bind this interface or assign its uniform before dispatch.
1361        const int loc = d.gl.GetUniformLocation(program, name.c_str()); // Find a named uniform in the linked program.
1362        if (loc >= 0) // Choose this branch when loc >= 0.
1363            detail::uniform_value(d.gl, loc, *value_); // Send the typed uniform value through its matching GL call.
1364    } // End this scope in bind gpu.
1365}; // End this scope in runtime.
1366
1367/** @brief A typed image declaration with format/access matching its shared shader. */
1368template <class T, unsigned C, access A> class image_port : public detail::port_base { // Select the scalar, dimension, or access type at compile time.
1369    std::shared_ptr<detail::image_state<T>> state_; // Keep the state shared by this wrapper and its retained owners.
1370
1371  public: // Expose the operations callers can use.
1372    /** @brief Declare an image port, usually through SHDR_IMAGE2D. */
1373    image_port(kernel& p, unsigned b, const char* n) // Register a typed image interface at the specified binding.
1374        : port_base(p, n, b, A, detail::port_kind::image) { // Record the image interface and its declared access qualifier.
1375    } // End this scope in runtime.
1376    /** @brief Bind or rebind this port to the image's retained shared storage. */
1377    image_port& operator=(const image2d<T, C>& image) { // Retain the newly bound typed resource in this shader interface.
1378        state_ = image.state(); // Set the state shared by this wrapper and its retained owners.
1379        return *this; // Allow another operation to follow in the same expression.
1380    } // End this scope in runtime.
1381    void copy_to(detail::port_base& destination) const override { // Copy the typed port into a matching snapshot interface.
1382        image_port* p = dynamic_cast<image_port*>(&destination); // Require a snapshot port with the same image type and access qualifier.
1383        if (!p) // Validate the typed interface pointer before accessing it.
1384            throw error("image snapshot type mismatch: " + name); // Report image snapshot type mismatch: .
1385        p->state_ = state_; // Set the state shared by this wrapper and its retained owners.
1386    } // End this scope in copy to.
1387    void validate() const override { // Check that this resource binding satisfies the shader declaration.
1388        if (!state_) // Require retained storage for this interface.
1389            throw error("unbound shader image: " + name); // Report unbound shader image: .
1390    } // End this scope in validate.
1391    std::shared_ptr<detail::resource_state> resource() const override { // Expose the retained storage used by this port.
1392        return state_; // Return the storage or execution state retained by this wrapper.
1393    } // End this scope in runtime.
1394    /** @internal Read image state for the CPU imageLoad/imageStore/imageSize helpers. */
1395    const std::shared_ptr<detail::image_state<T>>& image_state() const { // Expose the validated image storage to CPU image helpers.
1396        validate(); // Check that this resource binding satisfies the shader declaration.
1397        return state_; // Return the storage or execution state retained by this wrapper.
1398    } // End this scope in runtime.
1399    void bind_gpu(detail::device_state& d, unsigned) override { // Bind this interface or assign its uniform before dispatch.
1400        if (binding >= d.max_images) // Choose this branch when binding >= d.max images.
1401            throw error("image binding exceeds device limit: " + name); // Report image binding exceeds device limit: .
1402        d.gl.BindImageTexture(binding, // Bind a typed image to its shader interface index.
1403                              state_->handle, // Keep the GL buffer or texture name.
1404                              0, // Supply the next value for the current call or declaration.
1405                              0, // Supply the next value for the current call or declaration.
1406                              0, // Supply the next value for the current call or declaration.
1407                              A == access::readonly    ? detail::READ_ONLY // Select the GL read or write qualifier matching this typed image port.
1408                              : A == access::writeonly ? detail::WRITE_ONLY // Choose the GL image access matching the shader qualifier.
1409                                                       : detail::READ_WRITE, // Choose the GL image access matching the shader qualifier.
1410                              state_->format); // Keep the image storage format.
1411    } // End this scope in bind gpu.
1412}; // End this scope in runtime.
1413
1414/** @brief GLSL image dimensions in pixels. */
1415template <class T, unsigned C, access A> // Select the scalar, dimension, or access type at compile time.
1416inline glsl::ivec2 imageSize(const image_port<T, C, A>& image) { // Return the bound image dimensions as GLSL integers.
1417    return glsl::ivec2(image.image_state()->width, image.image_state()->height); // Return the bound image dimensions as GLSL integers.
1418} // End this scope in imageSize.
1419/** @brief Load one texel. Missing RGB components are zero and missing alpha is one.
1420 * Out-of-range coordinates return zero. loading a writeonly image is a compile error.
1421 */
1422template <class T, unsigned C, access A> // Select the scalar, dimension, or access type at compile time.
1423inline glsl::vec<T, 4> imageLoad(const image_port<T, C, A>& image, glsl::ivec2 pos) { // Load one pixel while enforcing readonly access and image bounds.
1424    static_assert(A != access::writeonly, "cannot imageLoad a writeonly image"); // Require a representation that matches the shader interface.
1425    const std::shared_ptr<detail::image_state<T>>& s = image.image_state(); // Access the retained image geometry and host pixel storage.
1426    if (pos.x < 0 || pos.y < 0 || static_cast<unsigned>(pos.x) >= s->width || // Choose this branch when pos.x < 0 or pos.y < 0 or static cast<unsigned>(pos.x) >= s->width or .
1427        static_cast<unsigned>(pos.y) >= s->height) // Reject an image row outside the allocated pixel storage.
1428        return glsl::vec<T, 4>(T(0)); // Load one pixel while enforcing readonly access and image bounds.
1429    glsl::vec<T, 4> result(T(0)); // Start the loaded texel with zero components before filling its channels.
1430    result[3] = T(1); // Set the value returned by this operation.
1431    const std::size_t start = // Set the beginning of the current token or range.
1432        (static_cast<std::size_t>(pos.y) * s->width + static_cast<unsigned>(pos.x)) * C; // Load one pixel while enforcing readonly access and image bounds.
1433    for (unsigned c = 0; c < C; ++c) // Visit the values or interfaces needed by imageLoad.
1434        result[c] = s->owned[start + c]; // Set the value returned by this operation.
1435    return result; // Return the value returned by this operation.
1436} // End this scope in imageLoad.
1437/** @brief Store a texel, ignoring out-of-range coordinates. Readonly stores are a compile error. */
1438template <class T, unsigned C, access A> // Select the scalar, dimension, or access type at compile time.
1439inline void imageStore(image_port<T, C, A>& image, glsl::ivec2 pos, const glsl::vec<T, 4>& value) { // Store one pixel while enforcing writable access and image bounds.
1440    static_assert(A != access::readonly, "cannot imageStore a readonly image"); // Require a representation that matches the shader interface.
1441    const std::shared_ptr<detail::image_state<T>>& s = image.image_state(); // Access the retained image geometry and host pixel storage.
1442    if (pos.x < 0 || pos.y < 0 || static_cast<unsigned>(pos.x) >= s->width || // Choose this branch when pos.x < 0 or pos.y < 0 or static cast<unsigned>(pos.x) >= s->width or .
1443        static_cast<unsigned>(pos.y) >= s->height) // Reject an image row outside the allocated pixel storage.
1444        return; // Finish this operation.
1445    const std::size_t start = // Set the beginning of the current token or range.
1446        (static_cast<std::size_t>(pos.y) * s->width + static_cast<unsigned>(pos.x)) * C; // Store one pixel while enforcing writable access and image bounds.
1447    for (unsigned c = 0; c < C; ++c) // Visit the values or interfaces needed by imageStore.
1448        s->owned[start + c] = value[c]; // Set host storage allocated by this resource.
1449} // End this scope in imageStore.
1450
1451template <class T> inline kernel& kernel::bind(const std::string& name, const buffer<T>& b) { // Select the scalar, dimension, or access type at compile time.
1452    detail::port_base& p = find_port(name); // Find the declared shader interface with this resource name.
1453    if (buffer_port<T, access::readonly>* v = dynamic_cast<buffer_port<T, access::readonly>*>(&p)) // Choose this branch when buffer port<T, access::readonly>* v = dynamic cast<buffer port<T, access::readonly>*>(&p).
1454        *v = b; // Store the current v value for this operation.
1455    else if (buffer_port<T, access::writeonly>* v = // Choose this branch when buffer port<T, access::writeonly>* v =.
1456                 dynamic_cast<buffer_port<T, access::writeonly>*>(&p)) // Try the matching typed write-only buffer interface.
1457        *v = b; // Store the current v value for this operation.
1458    else if (buffer_port<T, access::readwrite>* v = // Choose this branch when buffer port<T, access::readwrite>* v =.
1459                 dynamic_cast<buffer_port<T, access::readwrite>*>(&p)) // Try the matching typed read-write buffer interface.
1460        *v = b; // Store the current v value for this operation.
1461    else // Handle the other resource, platform, or completion case.
1462        throw error("buffer type mismatch: " + name); // Report buffer type mismatch: .
1463    return *this; // Allow another operation to follow in the same expression.
1464} // End this scope in runtime.
1465template <class T, unsigned C> // Select the scalar, dimension, or access type at compile time.
1466inline kernel& kernel::bind(const std::string& name, const image2d<T, C>& b) { // Rebind a named resource port while preserving its declared type.
1467    detail::port_base& p = find_port(name); // Find the declared shader interface with this resource name.
1468    if (image_port<T, C, access::readonly>* v = // Choose this branch when image port<T, C, access::readonly>* v =.
1469            dynamic_cast<image_port<T, C, access::readonly>*>(&p)) // Try the matching typed read-only image interface.
1470        *v = b; // Store the current v value for this operation.
1471    else if (image_port<T, C, access::writeonly>* v = // Choose this branch when image port<T, C, access::writeonly>* v =.
1472                 dynamic_cast<image_port<T, C, access::writeonly>*>(&p)) // Try the matching typed write-only image interface.
1473        *v = b; // Store the current v value for this operation.
1474    else if (image_port<T, C, access::readwrite>* v = // Choose this branch when image port<T, C, access::readwrite>* v =.
1475                 dynamic_cast<image_port<T, C, access::readwrite>*>(&p)) // Try the matching typed read-write image interface.
1476        *v = b; // Store the current v value for this operation.
1477    else // Handle the other resource, platform, or completion case.
1478        throw error("image type mismatch: " + name); // Report image type mismatch: .
1479    return *this; // Allow another operation to follow in the same expression.
1480} // End this scope in runtime.
1481template <class T> inline kernel& kernel::set(const std::string& name, const T& value) { // Select the scalar, dimension, or access type at compile time.
1482    uniform_port<T>* p = dynamic_cast<uniform_port<T>*>(&find_port(name)); // Require the named uniform to have the supplied value's type.
1483    if (!p) // Validate the typed interface pointer before accessing it.
1484        throw error("uniform type mismatch: " + name); // Report uniform type mismatch: .
1485    *p = value; // Update the typed uniform value for subsequent dispatches.
1486    return *this; // Allow another operation to follow in the same expression.
1487} // End this scope in runtime.
1488
1489inline void kernel::prepare(device& d) { // Compile the program and prepare its bound GPU resources.
1490    const auto& state = d.state(); // Set the shared device or worker state.
1491    state->collect(); // Run queued deletions and zero-time completion checks.
1492    for (std::size_t i = 0; i < ports_.size(); ++i) // Visit every registered resource and uniform interface.
1493        ports_[i]->validate(); // Check that this resource binding satisfies the shader declaration.
1494    if (!program_) { // Compile the shader when its cached program is empty.
1495        if (source_.empty()) // Choose this branch when source .empty().
1496            throw error("shader has no embedded GPU source: " + name_); // Report that this shader requires an embedded GPU program.
1497        program_ = std::make_shared<detail::program_state>( // Set the retained compiled compute program.
1498            state, state->compile(glsl_source(source_, state->language), name_)); // Add the selected GLSL version and shared-declaration definitions.
1499        detail::GLint actual[3] = {0, 0, 0}; // Prepare all three local dimensions reported by the linked program.
1500        state->gl.GetProgramiv(program_->id, detail::COMPUTE_WORK_GROUP_SIZE, actual); // Read linked-program status, log length, or local dimensions.
1501        if (actual[0] != static_cast<int>(local_.x) || actual[1] != static_cast<int>(local_.y) || // Choose this branch when actual[0] differs from static cast<int>(local .x) or actual[1] differs from static cast<int>(local .y) or .
1502            actual[2] != static_cast<int>(local_.z)) { // Require the linked program's third local dimension to match the CPU shader.
1503            program_.reset(); // Release or replace the owned object at this lifecycle boundary.
1504            throw error("GPU source and C++ local sizes differ: " + name_); // Report gpu source and c++ local sizes differ: .
1505        } // End this scope in prepare.
1506    } // End this scope in prepare.
1507    if (program_->owner != state) // Check that this storage belongs to the requested device.
1508        throw error("shader program belongs to a different device; create a new shader instance"); // Report shader program belongs to a different device. create a new shader instance.
1509    for (std::size_t i = 0; i < ports_.size(); ++i) { // Visit every registered resource and uniform interface.
1510        auto r = ports_[i]->resource(); // Get the shared storage behind this resource interface.
1511        if (r) // Choose this branch when r.
1512            r->ensure_gpu(state); // Allocate or upload GPU storage when its host copy is newer.
1513    } // End this scope in prepare.
1514} // End this scope in prepare.
1515
1516inline void kernel::run(extent groups, device* d) { // Keep the target device.
1517    if (!groups.x || !groups.y || !groups.z) // Finish an empty dispatch before submitting GL commands.
1518        return; // Finish this operation.
1519    const unsigned g[3] = {groups.x, groups.y, groups.z}, l[3] = {local_.x, local_.y, local_.z}; // Keep dispatch counts and local dimensions for validation and CPU indexing.
1520    for (unsigned i = 0; i < 3; ++i) // Validate or query each of the three compute dimensions.
1521        if (g[i] > (std::numeric_limits<unsigned>::max)() / l[i]) // Choose this branch when g[i] > (std::numeric limits<unsigned>::max)() / l[i].
1522            throw error("global invocation index overflow"); // Report global invocation index overflow.
1523    std::vector<std::shared_ptr<detail::resource_state>> outputs; // Retain the writable resources whose authority changes after this dispatch.
1524    for (std::size_t i = 0; i < ports_.size(); ++i) { // Visit every registered resource and uniform interface.
1525        ports_[i]->validate(); // Check that this resource binding satisfies the shader declaration.
1526        std::shared_ptr<detail::resource_state> r = ports_[i]->resource(); // Get the shared storage behind this resource interface.
1527        if (r && ports_[i]->mode != access::readonly) // Choose the branch matching this interface or resource access.
1528            outputs.push_back(r); // Retain this entry in the ordered resource or work collection.
1529    } // End this scope in runtime.
1530    if (d) { // Choose this branch when d.
1531        const std::shared_ptr<detail::device_state>& state = d->state(); // Set the shared device or worker state.
1532        for (unsigned i = 0; i < 3; ++i) { // Validate or query each of the three compute dimensions.
1533            if (g[i] > state->max_groups[i]) // Choose this branch when g[i] > state->max groups[i].
1534                throw error("dispatch exceeds device work group count"); // Report dispatch exceeds device work group count.
1535            if (l[i] > state->max_local[i]) // Choose this branch when l[i] > state->max local[i].
1536                throw error("local work group dimension exceeds device limit"); // Report local work group dimension exceeds device limit.
1537        } // End this scope in runtime.
1538        const std::size_t invocations = // Count the shader invocations in one local work group.
1539            detail::checked_product(detail::checked_product(l[0], l[1]), l[2]); // Reject resource-size multiplication that would overflow.
1540        if (invocations > state->max_invocations) // Choose this branch when invocations > state->max invocations.
1541            throw error("local invocation count exceeds device limit"); // Report local invocation count exceeds device limit.
1542        prepare(*d); // Compile the program and prepare its bound GPU resources.
1543        state->gl.UseProgram(program_->id); // Select the compute program for the next dispatch.
1544        for (std::size_t i = 0; i < ports_.size(); ++i) // Visit every registered resource and uniform interface.
1545            ports_[i]->bind_gpu(*state, program_->id); // Bind this interface or assign its uniform before dispatch.
1546        state->gl.check("bind shader " + name_); // Keep the kernel or registration name.
1547        state->gl.DispatchCompute(groups.x, groups.y, groups.z); // Queue the shader workgroups.
1548        state->gl.MemoryBarrier(detail::ALL_BARRIER_BITS); // Make earlier resource writes visible to following GPU commands.
1549 // Conservatively record GPU authority even if an error follows a submitted dispatch.
1550        for (std::size_t i = 0; i < outputs.size(); ++i) // Visit this axis of the dispatch or current workgroup.
1551            outputs[i]->latest = detail::authority::gpu; // Record which backend now owns the newest resource values.
1552        state->gl.check("dispatch shader " + name_); // Keep the kernel or registration name.
1553    } else { // Handle the alternative resource or completion case.
1554        for (std::size_t i = 0; i < ports_.size(); ++i) { // Visit every registered resource and uniform interface.
1555            std::shared_ptr<detail::resource_state> r = ports_[i]->resource(); // Get the shared storage behind this resource interface.
1556            if (r) // Choose this branch when r.
1557                r->ensure_host(); // Download newer GPU values only when host access needs them.
1558        } // End this scope in runtime.
1559        gl_NumWorkGroups = glsl::uvec3(groups.x, groups.y, groups.z); // Publish the dispatch dimensions to CPU shader builtins.
1560        try { // Keep cleanup available if an allocation, shader, or driver operation fails.
1561            for (unsigned gz = 0; gz < groups.z; ++gz) // Visit this axis of the dispatch or current workgroup.
1562                for (unsigned gy = 0; gy < groups.y; ++gy) // Visit this axis of the dispatch or current workgroup.
1563                    for (unsigned gx = 0; gx < groups.x; ++gx) { // Visit this axis of the dispatch or current workgroup.
1564                        gl_WorkGroupID = glsl::uvec3(gx, gy, gz); // Publish the CPU work group currently being executed.
1565                        for (unsigned z = 0; z < local_.z; ++z) // Visit this axis of the dispatch or current workgroup.
1566                            for (unsigned y = 0; y < local_.y; ++y) // Visit this axis of the dispatch or current workgroup.
1567                                for (unsigned x = 0; x < local_.x; ++x) { // Visit this axis of the dispatch or current workgroup.
1568                                    gl_LocalInvocationID = glsl::uvec3(x, y, z); // Publish the invocation coordinates inside this work group.
1569                                    gl_GlobalInvocationID = glsl::uvec3( // Combine work group and local coordinates into global indices.
1570                                        gx * local_.x + x, gy * local_.y + y, gz * local_.z + z); // Use the local size to place this invocation in the complete dispatch.
1571                                    gl_LocalInvocationIndex = (z * local_.y + y) * local_.x + x; // Flatten the local coordinates with X changing fastest.
1572                                    main(); // Execute the shader with all CPU invocation builtins initialized.
1573                                } // End this scope in runtime.
1574                    } // End this scope in runtime.
1575        } catch (...) { // Preserve cleanup or exception propagation for this failed operation.
1576            for (std::size_t i = 0; i < outputs.size(); ++i) // Visit this axis of the dispatch or current workgroup.
1577                outputs[i]->latest = detail::authority::host; // Record which backend now owns the newest resource values.
1578            throw; // Rethrow the original failure after arranging the necessary cleanup.
1579        } // End this scope in runtime.
1580        for (std::size_t i = 0; i < outputs.size(); ++i) // Visit this axis of the dispatch or current workgroup.
1581            outputs[i]->latest = detail::authority::host; // Record which backend now owns the newest resource values.
1582    } // End this scope in runtime.
1583} // End this scope in runtime.
1584
1585/** @brief One dispatch retaining a reference to its shader. Keep that shader alive during execution. */
1586struct stage { // Keep the stage values and operations together.
1587    kernel* shader; // Keep the shader used by this dispatch.
1588    extent groups; // Keep the number of workgroups to dispatch.
1589    backend target; // Keep the chosen CPU or GPU backend.
1590    std::shared_ptr<kernel> owner; // Retain an owned kernel while this stage uses it.
1591    /** @brief Retain a kernel reference with workgroup counts and a backend override. */
1592    stage(kernel& k, extent g, backend b) : shader(&k), groups(g), target(b) { // Keep the shader reference, work group counts and backend choice.
1593    } // End this scope in runtime.
1594    stage(std::shared_ptr<kernel> k, extent g, backend b) // Keep the shader reference, work group counts and backend choice.
1595        : shader(k.get()), groups(g), target(b), owner(k) { // Retain the kernel owner together with dispatch dimensions and backend choice.
1596        if (!shader) // Require a retained kernel for this dispatch.
1597            throw error("cannot dispatch a null shader"); // Require a valid kernel for this dispatch.
1598    } // End this scope in runtime.
1599}; // End this scope in runtime.
1600/** @brief Build a dispatch using work group counts, with an optional per-stage backend override. */
1601inline stage dispatch(kernel& shader, extent groups, backend b = backend::automatic) { // Build one ordered dispatch with the requested backend choice.
1602    return stage(shader, groups, b); // Return the result of this check or operation.
1603} // End this scope in runtime.
1604/** @brief Build a dispatch that also retains ownership of its shader. */
1605inline stage // Return a dispatch value that retains its shader owner.
1606dispatch(std::shared_ptr<kernel> shader, extent groups, backend b = backend::automatic) { // Build one ordered dispatch with the requested backend choice.
1607    return stage(shader, groups, b); // Return the result of this check or operation.
1608} // End this scope in runtime.
1609
1610class submission; // Keep the submission values and operations together.
1611
1612/** @brief An ordered pipeline, composed with >> or +=. Resources link stages by shared storage.
1613 * GPU stages issue memory barriers. CPU/GPU transitions transfer authoritative resource contents.
1614 * Running again observes updated uniforms and resource bindings. CPU execution
1615 * completes each stage before returning. GPU execution queues stages in order.
1616 * Request host data or use an explicit wait to observe GPU completion.
1617 */
1618class pipeline { // Keep the pipeline values and operations together.
1619    std::vector<stage> stages_; // Keep the dispatches in execution order.
1620    void execute(device* d) const { // Run stages in order while honoring their backend choices.
1621        for (std::size_t i = 0; i < stages_.size(); ++i) { // Visit every dispatch in processing order.
1622            const stage& s = stages_[i]; // Inspect the next dispatch, its dimensions and backend choice.
1623            if (s.target == backend::gpu && !d) // Require a device for an explicitly GPU stage.
1624                throw error("GPU stage requires a device"); // Report gpu stage requires a device.
1625            s.shader->run(s.groups, s.target == backend::cpu ? 0 : d); // Dispatch this stage on its selected CPU or GPU backend.
1626        } // End this scope in execute.
1627    } // End this scope in execute.
1628
1629  public: // Expose the operations callers can use.
1630    /** @brief Construct an empty pipeline. append dispatches with operator+=. */
1631    pipeline() { // Create the ordered dispatch container.
1632    } // End this scope in runtime.
1633    /** @brief Construct a pipeline containing one dispatch. */
1634    pipeline(stage s) { // Create a pipeline containing this initial dispatch.
1635        stages_.push_back(s); // Keep this dispatch at the end of the processing order.
1636    } // End this scope in runtime.
1637    /** @brief Append a dispatch in execution order and return this pipeline. */
1638    pipeline& operator+=(stage s) { // Append one dispatch while retaining its optional kernel owner.
1639        stages_.push_back(s); // Keep this dispatch at the end of the processing order.
1640        return *this; // Allow another operation to follow in the same expression.
1641    } // End this scope in runtime.
1642    /** @brief Append every dispatch from another pipeline, including a safe copy of this pipeline. */
1643    pipeline& operator+=(const pipeline& other) { // Compose complete processing blocks in their original stage order.
1644        const std::vector<stage> additions(other.stages_); // Preserve the source range before self-append can reallocate it.
1645        stages_.insert(stages_.end(), additions.begin(), additions.end()); // Retain each dispatch's kernel ownership and backend choice.
1646        return *this; // Allow another stage or pipeline to follow in the same expression.
1647    } // Appending copies dispatch references and preserves the stages for later execution.
1648    /** @brief Return the number of stages. */
1649    std::size_t size() const { // Read the stored element or stage count.
1650        return stages_.size(); // Return the result of this check or operation.
1651    } // End this scope in runtime.
1652    /** @brief Run automatic and CPU stages on the CPU. explicit GPU stages need a device. */
1653    void run() const { // Execute the pipeline using the selected CPU or GPU backend.
1654        execute(0); // Run stages in order while honoring their backend choices.
1655    } // End this scope in runtime.
1656    /** @brief Run automatic and GPU stages on the device, respecting explicit CPU stages.
1657     * Host readback completes queued GPU writes when resource data is requested.
1658     */
1659    void run(device& d) const { // Execute the pipeline using the selected CPU or GPU backend.
1660        execute(&d); // Run stages in order while honoring their backend choices.
1661    } // End this scope in runtime.
1662    /** @brief Compile GPU programs and upload resources before steady-state submission. */
1663    void prepare(device& d) const { // Compile the program and prepare its bound GPU resources.
1664        for (std::size_t i = 0; i < stages_.size(); ++i) // Visit every dispatch in processing order.
1665            if (stages_[i].target != backend::cpu) // Precompile and upload stages that can execute on the GPU.
1666                stages_[i].shader->prepare(d); // Compile the program and prepare its bound GPU resources.
1667    } // End this scope in prepare.
1668    /** @brief Enqueue GPU stages and return a fence for zero-timeout completion polls. */
1669    submission submit(device& d) const; // Queue compute work and return its completion handle.
1670    /** @internal Access dispatches for submission and snapshot handling. */
1671    const std::vector<stage>& stages() const { // Expose the ordered dispatches for submission and snapshot handling.
1672        return stages_; // Return the dispatches in execution order.
1673    } // End this scope in runtime.
1674    /** @brief Snapshot shader instances, uniforms and bindings for deferred CPU execution. */
1675    pipeline snapshot() const { // Clone kernels and retain the current binding and uniform values.
1676        pipeline result; // Keep the value returned by this operation.
1677        std::map<kernel*, std::shared_ptr<kernel>> copies; // Keep the shader clones reused by repeated stages.
1678        for (std::size_t i = 0; i < stages_.size(); ++i) { // Visit every dispatch in processing order.
1679            const stage& s = stages_[i]; // Inspect the next dispatch, its dimensions and backend choice.
1680            auto& copy = copies[s.shader]; // Reuse one clone for every occurrence of the same source kernel.
1681            if (!copy) // Create a clone only on the source kernel's first occurrence.
1682                copy = std::shared_ptr<kernel>(s.shader->clone().release()); // Own an isolated clone of this kernel's current interfaces.
1683            result += stage(copy, s.groups, s.target); // Retain the cloned kernel with its original dimensions and backend choice.
1684        } // End this scope in snapshot.
1685        return result; // Return the value returned by this operation.
1686    } // End this scope in snapshot.
1687    /** @brief Validate CPU execution support and current host data for a deferred job. */
1688    void require_host_ready() const { // Validate CPU stages and host-ready resources.
1689        for (std::size_t i = 0; i < stages_.size(); ++i) { // Visit every dispatch in processing order.
1690            if (stages_[i].target == backend::gpu) // Reject GPU-only stages before submitting work to a CPU worker.
1691                throw error("CPU executor cannot execute a GPU-only stage"); // Require CPU-compatible stages for the CPU executor.
1692            auto resources = stages_[i].shader->resources(); // Inspect the resources bound to this stage.
1693            for (std::size_t r = 0; r < resources.size(); ++r) // Check every bound resource for data requiring GPU readback.
1694                if (resources[r]->latest == detail::authority::gpu) // Require the caller to download newer GPU contents on the context thread.
1695                    throw error( // Report the invalid operation.
1696                        "download GPU data on its context thread before submitting CPU work"); // Explain how to make this resource ready for CPU execution.
1697        } // End this scope in require host ready.
1698    } // End this scope in require host ready.
1699}; // End this scope in runtime.
1700/** @brief Compose ordered stages into a reusable pipeline. */
1701inline pipeline operator>>(stage a, stage b) { // Compose these dispatches in their execution order.
1702    pipeline p(a); // Start the pipeline with the first dispatch.
1703    p += b; // Append the following dispatch to the ordered pipeline.
1704    return p; // Return the composed pipeline for later execution.
1705} // End this scope in runtime.
1706/** @brief Append a stage to a pipeline value, retaining references to the same kernels. */
1707inline pipeline operator>>(pipeline p, stage b) { // Compose these dispatches in their execution order.
1708    p += b; // Append the following dispatch to the ordered pipeline.
1709    return p; // Return the composed pipeline for later execution.
1710} // End this scope in runtime.
1711/** @brief Prepend a stage to a pipeline while retaining the same linked shader resources. */
1712inline pipeline operator>>(stage a, const pipeline& b) { // Place the independent dispatch before all existing processing stages.
1713    pipeline result(a); // Start with the supplied dispatch and its retained kernel owner.
1714    result += b; // Append the complete processing block in its original order.
1715    return result; // Return the reusable pipeline for later execution.
1716} // The source pipeline remains available for further composition or execution.
1717/** @brief Join two complete processing pipelines in execution order. */
1718inline pipeline operator>>(pipeline a, const pipeline& b) { // Compose reusable algorithm blocks with ordinary shader dispatches.
1719    a += b; // Append a copy of the second block's dispatch references.
1720    return a; // Return the combined ordered processing plan.
1721} // Resource sharing follows the same rules as individual stage composition.
1722
1723namespace detail { // Group these definitions in the detail namespace.
1724typedef kernel* (*kernel_factory)(); // Name the representation used by this GL or shader interface.
1725inline std::map<std::string, std::vector<kernel_factory>>& shader_registry() { // Share the compiled shader factories discovered during startup.
1726    static std::map<std::string, std::vector<kernel_factory>> registry; // Keep the shared display lifetime registry.
1727    return registry; // Return the shared display lifetime registry.
1728} // End this scope in shader registry.
1729 // Generated shader translation units register factories directly in their target.
1730 // Unregistering makes plugin unload safe for future lookups. existing shader objects
1731 // still require the plugin to stay loaded through destruction.
1732class shader_registration { // Keep the shader registration values and operations together.
1733    std::string name_; // Keep the kernel or registration name.
1734    kernel_factory factory_; // Keep the compiled shader construction callback.
1735
1736  public: // Expose the operations callers can use.
1737    shader_registration(const char* name, kernel_factory factory) : name_(name), factory_(factory) { // Keep the callback used to create a registered shader.
1738        shader_registry()[name_].push_back(factory_); // Retain this entry in the ordered resource or work collection.
1739    } // End this scope in runtime.
1740    ~shader_registration() { // Unregister this factory before its dynamic module is unloaded.
1741        std::vector<kernel_factory>& entries = shader_registry()[name_]; // Find the registered factories using this shader name.
1742        const std::vector<kernel_factory>::iterator it = // Find this module's factory among the registrations.
1743            std::find(entries.begin(), entries.end(), factory_); // Keep the compiled shader construction callback.
1744        if (it != entries.end()) // Choose this branch when it differs from entries.end().
1745            entries.erase(it); // Remove this module's registration and preserve the other factories.
1746        if (entries.empty()) // Choose this branch when entries.empty().
1747            shader_registry().erase(name_); // Share the compiled shader factories discovered during startup.
1748    } // End this scope in runtime.
1749    shader_registration(const shader_registration&) = delete; // Prevent copying this object and duplicating its retained identity.
1750    shader_registration& operator=(const shader_registration&) = delete; // Prevent copying this object and duplicating its retained identity.
1751}; // End this scope in runtime.
1752} // namespace detail
1753
1754/** @brief Create a shader compiled and embedded by shdr_target_shaders during the CMake build.
1755 * A file named scale.cpp registers scale_kernel. The returned instance owns its CPU/GPU program
1756 * and exposes resource binding through bind() and set(). Both programs are part of the binary.
1757 * Unknown or ambiguous names throw error. Call from one application thread after startup.
1758 */
1759inline std::unique_ptr<kernel> make_kernel(const std::string& name) { // Create one automatically registered shader by its build-time name.
1760    const std::map<std::string, std::vector<detail::kernel_factory>>& registry = // Set the shared display lifetime registry.
1761        detail::shader_registry(); // Share the compiled shader factories discovered during startup.
1762    const std::map<std::string, std::vector<detail::kernel_factory>>::const_iterator it = // Find the unique compiled factory requested by the application.
1763        registry.find(name); // Keep the resource or entry-point name.
1764    if (it == registry.end()) // Choose this branch when it equals registry.end().
1765        throw error("unknown compiled shader: " + name); // Report unknown compiled shader: .
1766    if (it->second.size() != 1) // Check resource size or driver limits before accessing storage.
1767        throw error("ambiguous compiled shader name: " + name); // Report ambiguous compiled shader name: .
1768    return std::unique_ptr<kernel>(it->second.front()()); // Create one automatically registered shader by its build-time name.
1769} // End this scope in make kernel.
1770} // namespace shdr
1771
1772 // A short namespace alias keeps host-side mathematical expressions readable.
1773namespace glsl = shdr::glsl; // Group these definitions in the glsl namespace.
1774#endif // SHDR_RUNTIME_HPP