nupp.gpu

nupp.gpu manages resident compute buffers over the selected GPU provider.

The context owns every buffer, compiled kernel and binding made from it. Each is closeable and borrows the context, so checked code cannot close the device while one is live, or use one after closing it. Uploads, dispatches, and downloads only enqueue commands; synchronize() is the explicit CPU boundary. gpu.available() says whether a device can be opened at all, since open raises when none can.

local gpu = nupp.gpu
local array = nupp.mem.array
local kernels = require("kernels")

with context = gpu.open() do
    with input = context:buffer(array.float, 1024), output = context:buffer(array.float, 1024) do
        with kernel = kernels.scale:compile(context) do
            with scale = kernel:bind(output, input) do
                context:upload(input, values:read())
                scale:dispatch(2.0)
            end
        end
        context:enqueueDownload(output)
        context:synchronize()
        context:readDownloaded(output, result:write())
    end
end

Here kernels.scale is generated from an @aot(target = "gpu") function by a target with aot = "require". Shader source, entrypoint identity, binding order and uniform packing remain compiler details. Ordinary spans are the CPU boundary; a chain of kernels keeps its intermediate buffers resident and pays upload/download only where the program asks for them.

context:tensor(element, shape) allocates dense row-major storage. A checked gpu.Layout can be sliced, transposed, broadcast, or explicitly strided, then applied with buffer:view(layout) without allocating device storage. Transfers remain dense; layout-aware kernels consume the explicit metadata.

Submodules

ModuleDescription
nupp.gpu.layoutWhere an element of a tensor actually is.
nupp.gpu.spiShared interfaces for resident GPU implementations.

Module contents

Types

TypeKindDescription
BufferinterfaceTyped resident device storage or a view borrowing its owning context.
ContextinterfaceDevice operations shared by application and provider contexts.
Layoutrecord
Phasesinterface
Sharedinterface

Functions

FunctionKindDescription
availablefunctionReports whether the selected provider can open a compute device now.
openfunctionOpens a compute device through the selected provider.
workgroupsfunctionExecutes uniformly ordered workgroup phases on the CPU.

Values

ValueKindDescription
PORTABLE_SCRATCH_BYTESvariable
PORTABLE_WORKGROUP_THREADSvariable

Types#

Bufferinterface#

interface Buffer<T> is nupp.Closeable ...

Typed resident device storage or a view borrowing its owning context.

Type parameters

NameDescription
T

Members

NameKindDescription
closemethodReleases a root buffer's allocation, or ends a view, without suspending.
countfieldNumber of logical elements in this buffer or view.
dimensionsmethodReturns the logical shape in elements.
stridesmethodReturns the element strides for the logical view.
subviewmethodCreates a context-borrowed view at a zero-based origin with the requested shape.
layoutmethodReturns the canonical tensor layout for this view.
isDensemethodReports whether this buffer or view occupies a dense element range.
isInjectivemethodReports whether every logical element maps to a distinct storage element.
viewmethodCreates a view using the supplied checked layout without copying storage.

closemethod#

close: @nosuspend function(takes self: Buffer<T>): nil

Releases a root buffer's allocation, or ends a view, without suspending.

Arguments
NameTypeDescription
takes selfBuffer<T>
Returns
TypeDescription
nil

countfield#

count: integer
@readonly

Number of logical elements in this buffer or view.

dimensionsmethod#

dimensions: function(borrows self: Buffer<T>): {integer}
@readonly

Returns the logical shape in elements.

Arguments
NameTypeDescription
borrows selfBuffer<T>
Returns
TypeDescription
{integer}

stridesmethod#

strides: function(borrows self: Buffer<T>): {integer}
@readonly

Returns the element strides for the logical view.

Arguments
NameTypeDescription
borrows selfBuffer<T>
Returns
TypeDescription
{integer}

subviewmethod#

subview: function(
    borrows self: Buffer<T>,
    origin: {integer},
    shape: {integer}
): affine(Buffer<T>) borrows (self)
@readonly

Creates a context-borrowed view at a zero-based origin with the requested shape.

Arguments
NameTypeDescription
borrows selfBuffer<T>
origin{integer}
shape{integer}
Returns
TypeDescription
affine(Buffer<T>) borrows (self)

layoutmethod#

layout: function(borrows self: Buffer<T>): TensorLayout
@readonly

Returns the canonical tensor layout for this view.

Arguments
NameTypeDescription
borrows selfBuffer<T>
Returns
TypeDescription
TensorLayout

isDensemethod#

isDense: function(borrows self: Buffer<T>): boolean
@readonly

Reports whether this buffer or view occupies a dense element range.

Arguments
NameTypeDescription
borrows selfBuffer<T>
Returns
TypeDescription
boolean

isInjectivemethod#

isInjective: function(borrows self: Buffer<T>): boolean
@readonly

Reports whether every logical element maps to a distinct storage element. A false result also covers a stride proof that was inconclusive.

Arguments
NameTypeDescription
borrows selfBuffer<T>
Returns
TypeDescription
boolean

viewmethod#

view: function(borrows self: Buffer<T>, layout: TensorLayout): affine(Buffer<T>) borrows (self)
@readonly

Creates a view using the supplied checked layout without copying storage. The layout must fit within the root allocation.

Arguments
NameTypeDescription
borrows selfBuffer<T>
layoutTensorLayout
Returns
TypeDescription
affine(Buffer<T>) borrows (self)

Contextinterface#

interface Context is nupp.Closeable ...

Device operations shared by application and provider contexts.

Members

NameKindDescription
closemethodConsumes the context and releases all device resources without suspending.
drivermethodReturns a diagnostic name for the selected device implementation.
buffermethodAllocates a typed resident device buffer.
tensormethodAllocates typed storage with the requested logical shape, its element named as buffer names it.
uploadmethodCopies borrowed host-span data into a same-sized dense buffer or view.
enqueueDownloadmethodQueues a dense buffer or view readback for synchronization and reading.
synchronizemethodWaits for queued device work and readbacks to complete.
readDownloadedmethodCopies a synchronized readback into a same-sized exclusive destination.
downloadmethodQueues, synchronizes, and copies a dense readback into the destination.

closemethod#

close: @nosuspend function(takes self: Context): nil

Consumes the context and releases all device resources without suspending.

Arguments
NameTypeDescription
takes selfContext
Returns
TypeDescription
nil

drivermethod#

driver: function(borrows self: Context): string
@readonly

Returns a diagnostic name for the selected device implementation.

Arguments
NameTypeDescription
borrows selfContext
Returns
TypeDescription
string

buffermethod#

buffer: function<T>(
    borrows self: Context,
    element: Scalar<T> | Type<T>,
    count: integer
): affine(gpu.Buffer<T>) borrows (self)
@readonly

Allocates a typed resident device buffer. The element is named by its array witness, such as nupp.mem.array.float, or by a struct declaration.

Arguments
NameTypeDescription
borrows selfContext
elementScalar<T> | Type<T>
countinteger
Returns
TypeDescription
affine(gpu.Buffer<T>) borrows (self)

tensormethod#

tensor: function<T>(
    borrows self: Context,
    element: Scalar<T> | Type<T>,
    shape: {integer}
): affine(gpu.Buffer<T>) borrows (self)
@readonly

Allocates typed storage with the requested logical shape, its element named as buffer names it.

Arguments
NameTypeDescription
borrows selfContext
elementScalar<T> | Type<T>
shape{integer}
Returns
TypeDescription
affine(gpu.Buffer<T>) borrows (self)

uploadmethod#

upload: function<T>(
    borrows self: Context,
    borrows buffer: gpu.Buffer<T>,
    borrows source: Span<T>
): nil
@readonly

Copies borrowed host-span data into a same-sized dense buffer or view.

Arguments
NameTypeDescription
borrows selfContext
borrows buffergpu.Buffer<T>
borrows sourceSpan<T>
Returns
TypeDescription
nil

enqueueDownloadmethod#

enqueueDownload: function<T>(borrows self: Context, borrows buffer: gpu.Buffer<T>): nil
@readonly

Queues a dense buffer or view readback for synchronization and reading.

Arguments
NameTypeDescription
borrows selfContext
borrows buffergpu.Buffer<T>
Returns
TypeDescription
nil

synchronizemethod#

synchronize: function(borrows self: Context): nil
@readonly

Waits for queued device work and readbacks to complete.

Arguments
NameTypeDescription
borrows selfContext
Returns
TypeDescription
nil

readDownloadedmethod#

readDownloaded: function<T>(
    borrows self: Context,
    borrows buffer: gpu.Buffer<T>,
    exclusive destination: WriteSpan<T>
): nil
@readonly

Copies a synchronized readback into a same-sized exclusive destination.

Arguments
NameTypeDescription
borrows selfContext
borrows buffergpu.Buffer<T>
exclusive destinationWriteSpan<T>
Returns
TypeDescription
nil

downloadmethod#

download: function<T>(
    borrows self: Context,
    borrows buffer: gpu.Buffer<T>,
    exclusive destination: WriteSpan<T>
): nil
@readonly

Queues, synchronizes, and copies a dense readback into the destination.

Arguments
NameTypeDescription
borrows selfContext
borrows buffergpu.Buffer<T>
exclusive destinationWriteSpan<T>
Returns
TypeDescription
nil

Layoutrecord#

record Layout ...

Members

NameKindDescription
countfield
offsetmethodThe element offset of the layout's first element.
extentmethodOne more than the largest element offset the layout reaches, measured from its first element.
dimensionsmethodThe logical shape.
stridesmethodThe element stride of each dimension.
isDensemethodReports whether the elements occupy a dense row-major range.
isInjectivemethodReports whether the layout's strides prove that element offsets are distinct.

countfield#

count: integer
@readonly

offsetmethod#

offset: function offset(borrows self): integer

The element offset of the layout's first element.

Arguments
NameTypeDescription
borrows selfany
Returns
TypeDescription
integer

extentmethod#

extent: function extent(borrows self): integer

One more than the largest element offset the layout reaches, measured from its first element.

Arguments
NameTypeDescription
borrows selfany
Returns
TypeDescription
integer

dimensionsmethod#

dimensions: function dimensions(borrows self): {integer}

The logical shape. The returned table is a copy.

Arguments
NameTypeDescription
borrows selfany
Returns
TypeDescription
{integer}

stridesmethod#

strides: function strides(borrows self): {integer}

The element stride of each dimension. The returned table is a copy.

Arguments
NameTypeDescription
borrows selfany
Returns
TypeDescription
{integer}

isDensemethod#

isDense: function isDense(borrows self): boolean

Reports whether the elements occupy a dense row-major range.

Arguments
NameTypeDescription
borrows selfany
Returns
TypeDescription
boolean

isInjectivemethod#

isInjective: function isInjective(borrows self): boolean

Reports whether the layout's strides prove that element offsets are distinct.

A false result also covers layouts for which the bounded stride proof is inconclusive.

Arguments
NameTypeDescription
borrows selfany
Returns
TypeDescription
boolean

Phasesinterface#

interface Phases ...

Members

NameKindDescription
scratchmethodAllocates fresh zero-based scratch for this workgroup.
runmethodRuns a stage to completion in ascending local-index order.
reduceSummethodReduces one power-of-two f32 workgroup in a fixed left-before-right tree.
inclusiveScanmethodComputes a deterministic inclusive u32 prefix sum.

scratchmethod#

scratch: function<T>(borrows self: Phases, initial: T, count: integer): gpu.Shared<T>
@readonly

Allocates fresh zero-based scratch for this workgroup.

Arguments
NameTypeDescription
borrows selfPhases
initialT
countinteger
Returns
TypeDescription
gpu.Shared<T>

runmethod#

run: function(borrows self: Phases, scoped stage: function(uint32): nil): nil
@readonly

Runs a stage to completion in ascending local-index order.

Arguments
NameTypeDescription
borrows selfPhases
scoped stagefunction(uint32): nil
Returns
TypeDescription
nil

reduceSummethod#

reduceSum: function(borrows self: Phases, exclusive values: gpu.Shared<float>): nil
@readonly

Reduces one power-of-two f32 workgroup in a fixed left-before-right tree. The sum is left in element zero.

Arguments
NameTypeDescription
borrows selfPhases
exclusive valuesgpu.Shared<float>
Returns
TypeDescription
nil

inclusiveScanmethod#

inclusiveScan: function(
    borrows self: Phases,
    exclusive values: gpu.Shared<uint32>,
    exclusive temporary: gpu.Shared<uint32>
): nil
@readonly

Computes a deterministic inclusive u32 prefix sum. temporary is a same-sized scratch array used for disjoint ping-pong stages; the result is left in values.

Arguments
NameTypeDescription
borrows selfPhases
exclusive valuesgpu.Shared<uint32>
exclusive temporarygpu.Shared<uint32>
Returns
TypeDescription
nil

Sharedinterface#

interface Shared<T> ...

Type parameters

NameDescription
T

Members

NameKindDescription
countfield
__lenmetamethod
__indexmetamethod
__newindexmetamethod

countfield#

count: integer
@readonly

__lenmetamethod#

__len: function(borrows self: Shared<T>): integer
Arguments
NameTypeDescription
borrows selfShared<T>
Returns
TypeDescription
integer

__indexmetamethod#

__index: function(borrows self: Shared<T>, index: integer): T
Arguments
NameTypeDescription
borrows selfShared<T>
indexinteger
Returns
TypeDescription
T

__newindexmetamethod#

__newindex: function(exclusive self: Shared<T>, index: integer, value: T): nil
Arguments
NameTypeDescription
exclusive selfShared<T>
indexinteger
valueT
Returns
TypeDescription
nil

Functions#

availablefunction#

const available: function(): boolean

Reports whether the selected provider can open a compute device now.

open raises when none can, and with needs the context it returns, so ask this first where a program has another way to run. Answering it opens and closes a device.

Returns

TypeDescription
boolean

openfunction#

const open: function(): api.Context

Opens a compute device through the selected provider.

Returns

TypeDescription
api.Context

workgroupsfunction#

function workgroups(groups: uint32, size: uint32, scoped controller: function(uint32, gpu.Phases): nil): nil

Executes uniformly ordered workgroup phases on the CPU.

A GPU AOT body recognizes this call and its immediate callbacks as structure: the controller does not escape, each run is a device barrier, and each stage invocation becomes one local lane. It runs groups groups, 0 through groups - 1, and the device runs the same ones: the kernel's required u32.div(#span, size) never visits a partial group.

Arguments

NameTypeDescription
groupsuint32
sizeuint32
scoped controllerfunction(uint32, gpu.Phases): nil

Returns

TypeDescription
nil

Raises

TypeCondition
string

when size is outside the portable workgroup limit

Values#

PORTABLE_SCRATCH_BYTESvariable#

PORTABLE_WORKGROUP_THREADSvariable#