This repository was archived by the owner on Sep 3, 2026. It is now read-only.

Repository files navigation

GPUEngine

A fancy name for a simple library.

GPUEngine is a collection of classes designed to make it easier to work with Metal on macOS and iOS. It hides away the usual boilerplate of setting up the Metal library objects that you need, and the work of connecting them together, and with your own code.

The essential idea is that there is an Engine that runs Tasks: classes that conform to GPUETask. There are three kinds of specialized task (two on iOS): Blit (macOS only), Compute, and Render. These are implemented abstractly by the classes GPUEBlitTask, GPUEComputeTask, and GPUERenderTask, respectively.

The simplest way to use GPUEngine is to create a custom Compute task. That is, a class that inherits from GPUEComputeTask . Instantiate an instace of GPUEEngine, an instance of your task class, and then submit it to the engine by wrapping it in an array, and sending a -runTasks: message with the array as the sole argument.

If you want to draw to the screen, you would create a class that conforms to GPUERenderTask, and use runTasks:withDrawable:.

Tasks are meant to be chained together. There are specialized protocols which define whether a task consumes or produces output resources. Resources, as defined by Metal, are of two kinds: MTLBuffer and MTLTexture. A GPUEBufferProducer declares an outBuffer property. This can be used an input to a GPUEBufferConsumer. Similarly for GPUETextureProducer and GPUETextureConsumer.

GPUEBufferMap takes a MTLBuffer and produces another MTLBuffer. GPUEBufferTransformer takes a MTLBuffer and produces a MTLTexture. These are all just protocols, however. In effect, they are just suggestions for how to organize a sequence of simple GPU functions.

Each compute and render task requires associated Metal functions: a compute kernel, or a pair of vertex and fragment functions, respectively. The job of the task is quite simple: it declares the function names, and it submits encoded commands on demand, in -encodeTaskWithCommandBuffer:. The abstract task classes already implement this method. Subclassers are encouraged to instead implement -configureEncoderReources:, and append their resources to the provided encoder.

The Task pattern is extended by the Process pattern, defined by the GPUEProcess protocol. A process takes over more of the work of managing a group of tasks, submitting them to the engine, and triggering refresh and completion blocks when necessary. (There is still no reference implementation of GPUEProcess. Should be coming soon.) A process should be able to descriminate between which tasks need to run, based on what dependencies have been modified.

Finally, the last piece of the puzzle is the GPUERenderer. As its name suggests, it expects to work with render tasks. There is no need for a renderer when using only compute and blit tasks. Like the other classes in the library, it's quite simple. It's purpose is to abstract away tedious glue code that otherwise might get mixed up in controller classes, where it doesn't really belong. It provides a connection between the GPUEEngine—via a GPUEProcess—and a MTKView. It acts as the view's delegate, running the process each time a new frame is requested by the view.

The library also includes a few basic tasks.

  • GPUEComputePyramid demonstrates a simple compute task that fills a buffer with rectangles that are reminiscent of pyramid shapes on a plane.
  • GPUEBufferToTexture demonstrates a buffer transformer; it converts a buffer of floating point values into a texture.
  • GPUEDrawTexture demonstrates a simple texture consumer; it draws a full-screen quad with the given texture applied.
  • GPUEDrawFlatMesh demonstrates a buffer consumer; it draws a GPUEMesh. (See below)
  • GPUETexturePresent demonstrates a blit task; it draws a texture directly into a render buffer without the need for geometry. (TODO: verify it works!)

A GPUEMesh is a trivial container for vertices and indices held in MTLBuffer objects.

GPUECGImageUtilities contains a set of functions for converting raw data blobs into bitmaps, instances of CGContextRef objects. There are also convenience categories on NSImage and UIImage for converting bitmaps into instances of those classes. (Using these interfaces might result in superfluous data copying, but for one-shot operations, this should not be an issue.)

There are sample applications for both macOS (in Objective-C) and iOS (in Swift).

About

Easier workflows with Metal shaders.

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
This repository was archived by the owner on Sep 3, 2026. It is now read-only.

Repository files navigation

GPUEngine

A fancy name for a simple library.

GPUEngine is a collection of classes designed to make it easier to work with Metal on macOS and iOS. It hides away the usual boilerplate of setting up the Metal library objects that you need, and the work of connecting them together, and with your own code.

The essential idea is that there is an Engine that runs Tasks: classes that conform to GPUETask. There are three kinds of specialized task (two on iOS): Blit (macOS only), Compute, and Render. These are implemented abstractly by the classes GPUEBlitTask, GPUEComputeTask, and GPUERenderTask, respectively.

The simplest way to use GPUEngine is to create a custom Compute task. That is, a class that inherits from GPUEComputeTask . Instantiate an instace of GPUEEngine, an instance of your task class, and then submit it to the engine by wrapping it in an array, and sending a -runTasks: message with the array as the sole argument.

If you want to draw to the screen, you would create a class that conforms to GPUERenderTask, and use runTasks:withDrawable:.

Tasks are meant to be chained together. There are specialized protocols which define whether a task consumes or produces output resources. Resources, as defined by Metal, are of two kinds: MTLBuffer and MTLTexture. A GPUEBufferProducer declares an outBuffer property. This can be used an input to a GPUEBufferConsumer. Similarly for GPUETextureProducer and GPUETextureConsumer.

GPUEBufferMap takes a MTLBuffer and produces another MTLBuffer. GPUEBufferTransformer takes a MTLBuffer and produces a MTLTexture. These are all just protocols, however. In effect, they are just suggestions for how to organize a sequence of simple GPU functions.

Each compute and render task requires associated Metal functions: a compute kernel, or a pair of vertex and fragment functions, respectively. The job of the task is quite simple: it declares the function names, and it submits encoded commands on demand, in -encodeTaskWithCommandBuffer:. The abstract task classes already implement this method. Subclassers are encouraged to instead implement -configureEncoderReources:, and append their resources to the provided encoder.

The Task pattern is extended by the Process pattern, defined by the GPUEProcess protocol. A process takes over more of the work of managing a group of tasks, submitting them to the engine, and triggering refresh and completion blocks when necessary. (There is still no reference implementation of GPUEProcess. Should be coming soon.) A process should be able to descriminate between which tasks need to run, based on what dependencies have been modified.

Finally, the last piece of the puzzle is the GPUERenderer. As its name suggests, it expects to work with render tasks. There is no need for a renderer when using only compute and blit tasks. Like the other classes in the library, it's quite simple. It's purpose is to abstract away tedious glue code that otherwise might get mixed up in controller classes, where it doesn't really belong. It provides a connection between the GPUEEngine—via a GPUEProcess—and a MTKView. It acts as the view's delegate, running the process each time a new frame is requested by the view.

The library also includes a few basic tasks.

  • GPUEComputePyramid demonstrates a simple compute task that fills a buffer with rectangles that are reminiscent of pyramid shapes on a plane.
  • GPUEBufferToTexture demonstrates a buffer transformer; it converts a buffer of floating point values into a texture.
  • GPUEDrawTexture demonstrates a simple texture consumer; it draws a full-screen quad with the given texture applied.
  • GPUEDrawFlatMesh demonstrates a buffer consumer; it draws a GPUEMesh. (See below)
  • GPUETexturePresent demonstrates a blit task; it draws a texture directly into a render buffer without the need for geometry. (TODO: verify it works!)

A GPUEMesh is a trivial container for vertices and indices held in MTLBuffer objects.

GPUECGImageUtilities contains a set of functions for converting raw data blobs into bitmaps, instances of CGContextRef objects. There are also convenience categories on NSImage and UIImage for converting bitmaps into instances of those classes. (Using these interfaces might result in superfluous data copying, but for one-shot operations, this should not be an issue.)

There are sample applications for both macOS (in Objective-C) and iOS (in Swift).

About

Easier workflows with Metal shaders.

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Sep 3, 2026. It is now read-only.

Repository files navigation

GPUEngine

A fancy name for a simple library.

GPUEngine is a collection of classes designed to make it easier to work with Metal on macOS and iOS. It hides away the usual boilerplate of setting up the Metal library objects that you need, and the work of connecting them together, and with your own code.

The essential idea is that there is an Engine that runs Tasks: classes that conform to GPUETask. There are three kinds of specialized task (two on iOS): Blit (macOS only), Compute, and Render. These are implemented abstractly by the classes GPUEBlitTask, GPUEComputeTask, and GPUERenderTask, respectively.

The simplest way to use GPUEngine is to create a custom Compute task. That is, a class that inherits from GPUEComputeTask . Instantiate an instace of GPUEEngine, an instance of your task class, and then submit it to the engine by wrapping it in an array, and sending a -runTasks: message with the array as the sole argument.

If you want to draw to the screen, you would create a class that conforms to GPUERenderTask, and use runTasks:withDrawable:.

Tasks are meant to be chained together. There are specialized protocols which define whether a task consumes or produces output resources. Resources, as defined by Metal, are of two kinds: MTLBuffer and MTLTexture. A GPUEBufferProducer declares an outBuffer property. This can be used an input to a GPUEBufferConsumer. Similarly for GPUETextureProducer and GPUETextureConsumer.

GPUEBufferMap takes a MTLBuffer and produces another MTLBuffer. GPUEBufferTransformer takes a MTLBuffer and produces a MTLTexture. These are all just protocols, however. In effect, they are just suggestions for how to organize a sequence of simple GPU functions.

Each compute and render task requires associated Metal functions: a compute kernel, or a pair of vertex and fragment functions, respectively. The job of the task is quite simple: it declares the function names, and it submits encoded commands on demand, in -encodeTaskWithCommandBuffer:. The abstract task classes already implement this method. Subclassers are encouraged to instead implement -configureEncoderReources:, and append their resources to the provided encoder.

The Task pattern is extended by the Process pattern, defined by the GPUEProcess protocol. A process takes over more of the work of managing a group of tasks, submitting them to the engine, and triggering refresh and completion blocks when necessary. (There is still no reference implementation of GPUEProcess. Should be coming soon.) A process should be able to descriminate between which tasks need to run, based on what dependencies have been modified.

Finally, the last piece of the puzzle is the GPUERenderer. As its name suggests, it expects to work with render tasks. There is no need for a renderer when using only compute and blit tasks. Like the other classes in the library, it's quite simple. It's purpose is to abstract away tedious glue code that otherwise might get mixed up in controller classes, where it doesn't really belong. It provides a connection between the GPUEEngine—via a GPUEProcess—and a MTKView. It acts as the view's delegate, running the process each time a new frame is requested by the view.

The library also includes a few basic tasks.

  • GPUEComputePyramid demonstrates a simple compute task that fills a buffer with rectangles that are reminiscent of pyramid shapes on a plane.
  • GPUEBufferToTexture demonstrates a buffer transformer; it converts a buffer of floating point values into a texture.
  • GPUEDrawTexture demonstrates a simple texture consumer; it draws a full-screen quad with the given texture applied.
  • GPUEDrawFlatMesh demonstrates a buffer consumer; it draws a GPUEMesh. (See below)
  • GPUETexturePresent demonstrates a blit task; it draws a texture directly into a render buffer without the need for geometry. (TODO: verify it works!)

A GPUEMesh is a trivial container for vertices and indices held in MTLBuffer objects.

GPUECGImageUtilities contains a set of functions for converting raw data blobs into bitmaps, instances of CGContextRef objects. There are also convenience categories on NSImage and UIImage for converting bitmaps into instances of those classes. (Using these interfaces might result in superfluous data copying, but for one-shot operations, this should not be an issue.)

There are sample applications for both macOS (in Objective-C) and iOS (in Swift).

About

Easier workflows with Metal shaders.

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Sep 3, 2026. It is now read-only.

Repository files navigation

GPUEngine

A fancy name for a simple library.

GPUEngine is a collection of classes designed to make it easier to work with Metal on macOS and iOS. It hides away the usual boilerplate of setting up the Metal library objects that you need, and the work of connecting them together, and with your own code.

The essential idea is that there is an Engine that runs Tasks: classes that conform to GPUETask. There are three kinds of specialized task (two on iOS): Blit (macOS only), Compute, and Render. These are implemented abstractly by the classes GPUEBlitTask, GPUEComputeTask, and GPUERenderTask, respectively.

The simplest way to use GPUEngine is to create a custom Compute task. That is, a class that inherits from GPUEComputeTask . Instantiate an instace of GPUEEngine, an instance of your task class, and then submit it to the engine by wrapping it in an array, and sending a -runTasks: message with the array as the sole argument.

If you want to draw to the screen, you would create a class that conforms to GPUERenderTask, and use runTasks:withDrawable:.

Tasks are meant to be chained together. There are specialized protocols which define whether a task consumes or produces output resources. Resources, as defined by Metal, are of two kinds: MTLBuffer and MTLTexture. A GPUEBufferProducer declares an outBuffer property. This can be used an input to a GPUEBufferConsumer. Similarly for GPUETextureProducer and GPUETextureConsumer.

GPUEBufferMap takes a MTLBuffer and produces another MTLBuffer. GPUEBufferTransformer takes a MTLBuffer and produces a MTLTexture. These are all just protocols, however. In effect, they are just suggestions for how to organize a sequence of simple GPU functions.

Each compute and render task requires associated Metal functions: a compute kernel, or a pair of vertex and fragment functions, respectively. The job of the task is quite simple: it declares the function names, and it submits encoded commands on demand, in -encodeTaskWithCommandBuffer:. The abstract task classes already implement this method. Subclassers are encouraged to instead implement -configureEncoderReources:, and append their resources to the provided encoder.

The Task pattern is extended by the Process pattern, defined by the GPUEProcess protocol. A process takes over more of the work of managing a group of tasks, submitting them to the engine, and triggering refresh and completion blocks when necessary. (There is still no reference implementation of GPUEProcess. Should be coming soon.) A process should be able to descriminate between which tasks need to run, based on what dependencies have been modified.

Finally, the last piece of the puzzle is the GPUERenderer. As its name suggests, it expects to work with render tasks. There is no need for a renderer when using only compute and blit tasks. Like the other classes in the library, it's quite simple. It's purpose is to abstract away tedious glue code that otherwise might get mixed up in controller classes, where it doesn't really belong. It provides a connection between the GPUEEngine—via a GPUEProcess—and a MTKView. It acts as the view's delegate, running the process each time a new frame is requested by the view.

The library also includes a few basic tasks.

  • GPUEComputePyramid demonstrates a simple compute task that fills a buffer with rectangles that are reminiscent of pyramid shapes on a plane.
  • GPUEBufferToTexture demonstrates a buffer transformer; it converts a buffer of floating point values into a texture.
  • GPUEDrawTexture demonstrates a simple texture consumer; it draws a full-screen quad with the given texture applied.
  • GPUEDrawFlatMesh demonstrates a buffer consumer; it draws a GPUEMesh. (See below)
  • GPUETexturePresent demonstrates a blit task; it draws a texture directly into a render buffer without the need for geometry. (TODO: verify it works!)

A GPUEMesh is a trivial container for vertices and indices held in MTLBuffer objects.

GPUECGImageUtilities contains a set of functions for converting raw data blobs into bitmaps, instances of CGContextRef objects. There are also convenience categories on NSImage and UIImage for converting bitmaps into instances of those classes. (Using these interfaces might result in superfluous data copying, but for one-shot operations, this should not be an issue.)

There are sample applications for both macOS (in Objective-C) and iOS (in Swift).

About

Easier workflows with Metal shaders.

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
This repository was archived by the owner on Sep 3, 2026. It is now read-only.

Repository files navigation

GPUEngine

A fancy name for a simple library.

GPUEngine is a collection of classes designed to make it easier to work with Metal on macOS and iOS. It hides away the usual boilerplate of setting up the Metal library objects that you need, and the work of connecting them together, and with your own code.

The essential idea is that there is an Engine that runs Tasks: classes that conform to GPUETask. There are three kinds of specialized task (two on iOS): Blit (macOS only), Compute, and Render. These are implemented abstractly by the classes GPUEBlitTask, GPUEComputeTask, and GPUERenderTask, respectively.

The simplest way to use GPUEngine is to create a custom Compute task. That is, a class that inherits from GPUEComputeTask . Instantiate an instace of GPUEEngine, an instance of your task class, and then submit it to the engine by wrapping it in an array, and sending a -runTasks: message with the array as the sole argument.

If you want to draw to the screen, you would create a class that conforms to GPUERenderTask, and use runTasks:withDrawable:.

Tasks are meant to be chained together. There are specialized protocols which define whether a task consumes or produces output resources. Resources, as defined by Metal, are of two kinds: MTLBuffer and MTLTexture. A GPUEBufferProducer declares an outBuffer property. This can be used an input to a GPUEBufferConsumer. Similarly for GPUETextureProducer and GPUETextureConsumer.

GPUEBufferMap takes a MTLBuffer and produces another MTLBuffer. GPUEBufferTransformer takes a MTLBuffer and produces a MTLTexture. These are all just protocols, however. In effect, they are just suggestions for how to organize a sequence of simple GPU functions.

Each compute and render task requires associated Metal functions: a compute kernel, or a pair of vertex and fragment functions, respectively. The job of the task is quite simple: it declares the function names, and it submits encoded commands on demand, in -encodeTaskWithCommandBuffer:. The abstract task classes already implement this method. Subclassers are encouraged to instead implement -configureEncoderReources:, and append their resources to the provided encoder.

The Task pattern is extended by the Process pattern, defined by the GPUEProcess protocol. A process takes over more of the work of managing a group of tasks, submitting them to the engine, and triggering refresh and completion blocks when necessary. (There is still no reference implementation of GPUEProcess. Should be coming soon.) A process should be able to descriminate between which tasks need to run, based on what dependencies have been modified.

Finally, the last piece of the puzzle is the GPUERenderer. As its name suggests, it expects to work with render tasks. There is no need for a renderer when using only compute and blit tasks. Like the other classes in the library, it's quite simple. It's purpose is to abstract away tedious glue code that otherwise might get mixed up in controller classes, where it doesn't really belong. It provides a connection between the GPUEEngine—via a GPUEProcess—and a MTKView. It acts as the view's delegate, running the process each time a new frame is requested by the view.

The library also includes a few basic tasks.

  • GPUEComputePyramid demonstrates a simple compute task that fills a buffer with rectangles that are reminiscent of pyramid shapes on a plane.
  • GPUEBufferToTexture demonstrates a buffer transformer; it converts a buffer of floating point values into a texture.
  • GPUEDrawTexture demonstrates a simple texture consumer; it draws a full-screen quad with the given texture applied.
  • GPUEDrawFlatMesh demonstrates a buffer consumer; it draws a GPUEMesh. (See below)
  • GPUETexturePresent demonstrates a blit task; it draws a texture directly into a render buffer without the need for geometry. (TODO: verify it works!)

A GPUEMesh is a trivial container for vertices and indices held in MTLBuffer objects.

GPUECGImageUtilities contains a set of functions for converting raw data blobs into bitmaps, instances of CGContextRef objects. There are also convenience categories on NSImage and UIImage for converting bitmaps into instances of those classes. (Using these interfaces might result in superfluous data copying, but for one-shot operations, this should not be an issue.)

There are sample applications for both macOS (in Objective-C) and iOS (in Swift).

About

Easier workflows with Metal shaders.

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Sep 3, 2026. It is now read-only.

Repository files navigation

GPUEngine

A fancy name for a simple library.

GPUEngine is a collection of classes designed to make it easier to work with Metal on macOS and iOS. It hides away the usual boilerplate of setting up the Metal library objects that you need, and the work of connecting them together, and with your own code.

The essential idea is that there is an Engine that runs Tasks: classes that conform to GPUETask. There are three kinds of specialized task (two on iOS): Blit (macOS only), Compute, and Render. These are implemented abstractly by the classes GPUEBlitTask, GPUEComputeTask, and GPUERenderTask, respectively.

The simplest way to use GPUEngine is to create a custom Compute task. That is, a class that inherits from GPUEComputeTask . Instantiate an instace of GPUEEngine, an instance of your task class, and then submit it to the engine by wrapping it in an array, and sending a -runTasks: message with the array as the sole argument.

If you want to draw to the screen, you would create a class that conforms to GPUERenderTask, and use runTasks:withDrawable:.

Tasks are meant to be chained together. There are specialized protocols which define whether a task consumes or produces output resources. Resources, as defined by Metal, are of two kinds: MTLBuffer and MTLTexture. A GPUEBufferProducer declares an outBuffer property. This can be used an input to a GPUEBufferConsumer. Similarly for GPUETextureProducer and GPUETextureConsumer.

GPUEBufferMap takes a MTLBuffer and produces another MTLBuffer. GPUEBufferTransformer takes a MTLBuffer and produces a MTLTexture. These are all just protocols, however. In effect, they are just suggestions for how to organize a sequence of simple GPU functions.

Each compute and render task requires associated Metal functions: a compute kernel, or a pair of vertex and fragment functions, respectively. The job of the task is quite simple: it declares the function names, and it submits encoded commands on demand, in -encodeTaskWithCommandBuffer:. The abstract task classes already implement this method. Subclassers are encouraged to instead implement -configureEncoderReources:, and append their resources to the provided encoder.

The Task pattern is extended by the Process pattern, defined by the GPUEProcess protocol. A process takes over more of the work of managing a group of tasks, submitting them to the engine, and triggering refresh and completion blocks when necessary. (There is still no reference implementation of GPUEProcess. Should be coming soon.) A process should be able to descriminate between which tasks need to run, based on what dependencies have been modified.

Finally, the last piece of the puzzle is the GPUERenderer. As its name suggests, it expects to work with render tasks. There is no need for a renderer when using only compute and blit tasks. Like the other classes in the library, it's quite simple. It's purpose is to abstract away tedious glue code that otherwise might get mixed up in controller classes, where it doesn't really belong. It provides a connection between the GPUEEngine—via a GPUEProcess—and a MTKView. It acts as the view's delegate, running the process each time a new frame is requested by the view.

The library also includes a few basic tasks.

  • GPUEComputePyramid demonstrates a simple compute task that fills a buffer with rectangles that are reminiscent of pyramid shapes on a plane.
  • GPUEBufferToTexture demonstrates a buffer transformer; it converts a buffer of floating point values into a texture.
  • GPUEDrawTexture demonstrates a simple texture consumer; it draws a full-screen quad with the given texture applied.
  • GPUEDrawFlatMesh demonstrates a buffer consumer; it draws a GPUEMesh. (See below)
  • GPUETexturePresent demonstrates a blit task; it draws a texture directly into a render buffer without the need for geometry. (TODO: verify it works!)

A GPUEMesh is a trivial container for vertices and indices held in MTLBuffer objects.

GPUECGImageUtilities contains a set of functions for converting raw data blobs into bitmaps, instances of CGContextRef objects. There are also convenience categories on NSImage and UIImage for converting bitmaps into instances of those classes. (Using these interfaces might result in superfluous data copying, but for one-shot operations, this should not be an issue.)

There are sample applications for both macOS (in Objective-C) and iOS (in Swift).

About

Easier workflows with Metal shaders.

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Sep 3, 2026. It is now read-only.

Repository files navigation

GPUEngine

A fancy name for a simple library.

GPUEngine is a collection of classes designed to make it easier to work with Metal on macOS and iOS. It hides away the usual boilerplate of setting up the Metal library objects that you need, and the work of connecting them together, and with your own code.

The essential idea is that there is an Engine that runs Tasks: classes that conform to GPUETask. There are three kinds of specialized task (two on iOS): Blit (macOS only), Compute, and Render. These are implemented abstractly by the classes GPUEBlitTask, GPUEComputeTask, and GPUERenderTask, respectively.

The simplest way to use GPUEngine is to create a custom Compute task. That is, a class that inherits from GPUEComputeTask . Instantiate an instace of GPUEEngine, an instance of your task class, and then submit it to the engine by wrapping it in an array, and sending a -runTasks: message with the array as the sole argument.

If you want to draw to the screen, you would create a class that conforms to GPUERenderTask, and use runTasks:withDrawable:.

Tasks are meant to be chained together. There are specialized protocols which define whether a task consumes or produces output resources. Resources, as defined by Metal, are of two kinds: MTLBuffer and MTLTexture. A GPUEBufferProducer declares an outBuffer property. This can be used an input to a GPUEBufferConsumer. Similarly for GPUETextureProducer and GPUETextureConsumer.

GPUEBufferMap takes a MTLBuffer and produces another MTLBuffer. GPUEBufferTransformer takes a MTLBuffer and produces a MTLTexture. These are all just protocols, however. In effect, they are just suggestions for how to organize a sequence of simple GPU functions.

Each compute and render task requires associated Metal functions: a compute kernel, or a pair of vertex and fragment functions, respectively. The job of the task is quite simple: it declares the function names, and it submits encoded commands on demand, in -encodeTaskWithCommandBuffer:. The abstract task classes already implement this method. Subclassers are encouraged to instead implement -configureEncoderReources:, and append their resources to the provided encoder.

The Task pattern is extended by the Process pattern, defined by the GPUEProcess protocol. A process takes over more of the work of managing a group of tasks, submitting them to the engine, and triggering refresh and completion blocks when necessary. (There is still no reference implementation of GPUEProcess. Should be coming soon.) A process should be able to descriminate between which tasks need to run, based on what dependencies have been modified.

Finally, the last piece of the puzzle is the GPUERenderer. As its name suggests, it expects to work with render tasks. There is no need for a renderer when using only compute and blit tasks. Like the other classes in the library, it's quite simple. It's purpose is to abstract away tedious glue code that otherwise might get mixed up in controller classes, where it doesn't really belong. It provides a connection between the GPUEEngine—via a GPUEProcess—and a MTKView. It acts as the view's delegate, running the process each time a new frame is requested by the view.

The library also includes a few basic tasks.

  • GPUEComputePyramid demonstrates a simple compute task that fills a buffer with rectangles that are reminiscent of pyramid shapes on a plane.
  • GPUEBufferToTexture demonstrates a buffer transformer; it converts a buffer of floating point values into a texture.
  • GPUEDrawTexture demonstrates a simple texture consumer; it draws a full-screen quad with the given texture applied.
  • GPUEDrawFlatMesh demonstrates a buffer consumer; it draws a GPUEMesh. (See below)
  • GPUETexturePresent demonstrates a blit task; it draws a texture directly into a render buffer without the need for geometry. (TODO: verify it works!)

A GPUEMesh is a trivial container for vertices and indices held in MTLBuffer objects.

GPUECGImageUtilities contains a set of functions for converting raw data blobs into bitmaps, instances of CGContextRef objects. There are also convenience categories on NSImage and UIImage for converting bitmaps into instances of those classes. (Using these interfaces might result in superfluous data copying, but for one-shot operations, this should not be an issue.)

There are sample applications for both macOS (in Objective-C) and iOS (in Swift).

About

Easier workflows with Metal shaders.

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
This repository was archived by the owner on Sep 3, 2026. It is now read-only.

Repository files navigation

GPUEngine

A fancy name for a simple library.

GPUEngine is a collection of classes designed to make it easier to work with Metal on macOS and iOS. It hides away the usual boilerplate of setting up the Metal library objects that you need, and the work of connecting them together, and with your own code.

The essential idea is that there is an Engine that runs Tasks: classes that conform to GPUETask. There are three kinds of specialized task (two on iOS): Blit (macOS only), Compute, and Render. These are implemented abstractly by the classes GPUEBlitTask, GPUEComputeTask, and GPUERenderTask, respectively.

The simplest way to use GPUEngine is to create a custom Compute task. That is, a class that inherits from GPUEComputeTask . Instantiate an instace of GPUEEngine, an instance of your task class, and then submit it to the engine by wrapping it in an array, and sending a -runTasks: message with the array as the sole argument.

If you want to draw to the screen, you would create a class that conforms to GPUERenderTask, and use runTasks:withDrawable:.

Tasks are meant to be chained together. There are specialized protocols which define whether a task consumes or produces output resources. Resources, as defined by Metal, are of two kinds: MTLBuffer and MTLTexture. A GPUEBufferProducer declares an outBuffer property. This can be used an input to a GPUEBufferConsumer. Similarly for GPUETextureProducer and GPUETextureConsumer.

GPUEBufferMap takes a MTLBuffer and produces another MTLBuffer. GPUEBufferTransformer takes a MTLBuffer and produces a MTLTexture. These are all just protocols, however. In effect, they are just suggestions for how to organize a sequence of simple GPU functions.

Each compute and render task requires associated Metal functions: a compute kernel, or a pair of vertex and fragment functions, respectively. The job of the task is quite simple: it declares the function names, and it submits encoded commands on demand, in -encodeTaskWithCommandBuffer:. The abstract task classes already implement this method. Subclassers are encouraged to instead implement -configureEncoderReources:, and append their resources to the provided encoder.

The Task pattern is extended by the Process pattern, defined by the GPUEProcess protocol. A process takes over more of the work of managing a group of tasks, submitting them to the engine, and triggering refresh and completion blocks when necessary. (There is still no reference implementation of GPUEProcess. Should be coming soon.) A process should be able to descriminate between which tasks need to run, based on what dependencies have been modified.

Finally, the last piece of the puzzle is the GPUERenderer. As its name suggests, it expects to work with render tasks. There is no need for a renderer when using only compute and blit tasks. Like the other classes in the library, it's quite simple. It's purpose is to abstract away tedious glue code that otherwise might get mixed up in controller classes, where it doesn't really belong. It provides a connection between the GPUEEngine—via a GPUEProcess—and a MTKView. It acts as the view's delegate, running the process each time a new frame is requested by the view.

The library also includes a few basic tasks.

  • GPUEComputePyramid demonstrates a simple compute task that fills a buffer with rectangles that are reminiscent of pyramid shapes on a plane.
  • GPUEBufferToTexture demonstrates a buffer transformer; it converts a buffer of floating point values into a texture.
  • GPUEDrawTexture demonstrates a simple texture consumer; it draws a full-screen quad with the given texture applied.
  • GPUEDrawFlatMesh demonstrates a buffer consumer; it draws a GPUEMesh. (See below)
  • GPUETexturePresent demonstrates a blit task; it draws a texture directly into a render buffer without the need for geometry. (TODO: verify it works!)

A GPUEMesh is a trivial container for vertices and indices held in MTLBuffer objects.

GPUECGImageUtilities contains a set of functions for converting raw data blobs into bitmaps, instances of CGContextRef objects. There are also convenience categories on NSImage and UIImage for converting bitmaps into instances of those classes. (Using these interfaces might result in superfluous data copying, but for one-shot operations, this should not be an issue.)

There are sample applications for both macOS (in Objective-C) and iOS (in Swift).

About

Easier workflows with Metal shaders.

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages