src/computesim

Source   Edit  

Description

runComputeOnCpu is a function that simulates a GPU-like compute environment on the CPU. It organizes work into workgroups and invocations, similar to how compute shaders operate on GPUs.

Warning

Using barrier() within conditional branches leads to undefined behavior. The emulator is modeled using a single barrier that must be accessible from all threads within a workgroup.

Parameters

  • numWorkGroups: UVec3 The number of workgroups in each dimension (x, y, z).
  • workGroupSize: UVec3 The size of each workgroup in each dimension (x, y, z).
  • compute: ThreadGenerator[A, B, C] The compute shader procedure to execute.
  • ssbo: A Storage buffer object(s) containing the data to process.
  • smem: B Shared memory for each workgroup.
  • args: C Additional arguments passed to the compute shader.

Compute Function Signature

The compute shader procedure should have the following signature:

proc computeFunction[A, B, C](
  buffers: A,     # Storage buffer (typically ptr T or Locker[T])
  shared: ptr B,  # Shared memory
  args: C         # Additional arguments
) {.nimcall.}

Example

type
  Buffers = object
    input, output: seq[float32]
  Shared = seq[float32]
  Args = object
    factor: int32

proc myComputeShader(
    buffers: ptr Buffers,
    shared: ptr Shared,
    args: Args) {.computeShader.} =
  # Computation logic here

let numWorkGroups = uvec3(4, 1, 1)
let workGroupSize = uvec3(256, 1, 1)
var buffers: Buffers
let coarseFactor = 4'i32

runComputeOnCpu(
  numWorkGroups, workGroupSize,
  myComputeShader,
  addr buffers,
  newSeq[float32](workGroupSize.x),
  Args(factor: coarseFactor)
)

CUDA to GLSL Translation Table

CUDA ConceptGLSL EquivalentDescription
blockDimgl_WorkGroupSizeThe size of a thread block (CUDA) or work group (GLSL)
gridDimgl_NumWorkGroupsThe size of the grid (CUDA) or the number of work groups (GLSL)
blockIdxgl_WorkGroupIDThe index of the current block (CUDA) or work group (GLSL)
threadIdxgl_LocalInvocationIDThe index of the current thread within its block (CUDA) or work group (GLSL)
blockIdx * blockDim + threadIdxgl_GlobalInvocationIDThe global index of the current thread (CUDA) or invocation (GLSL)

Types

GlEnvironment = object
  gl_GlobalInvocationID*: UVec3 ## Global ID of the current invocation
  gl_LocalInvocationID*: UVec3 ## Local ID within the workgroup
  gl_WorkGroupID*: UVec3     ## ID of the current workgroup
  gl_WorkGroupSize*: UVec3   ## Size of the workgroup (x, y, z)
  gl_NumWorkGroups*: UVec3   ## Total number of workgroups (x, y, z)
  gl_NumSubgroups*: uint32   ## Number of subgroups in the workgroup
  gl_SubgroupSize*: uint32   ## Size of each subgroup
  gl_SubgroupID*: uint32     ## ID of the current subgroup [0..gl_NumSubgroups)
  gl_SubgroupInvocationID*: uint32 ## ID of the invocation within the subgroup [0..gl_SubgroupSize)
Source   Edit  
ThreadGenerator[A; B; C] = proc (env: GlEnvironment; buffers: A; shared: ptr B;
                                 args: C): ThreadClosure {.nimcall.}
Source   Edit  
ThreadGeneratorNoShared[A; C] = proc (env: GlEnvironment; buffers: A; args: C): ThreadClosure {.
    nimcall.}
Source   Edit  

Procs

proc runComputeOnCpu[A, B, C](numWorkGroups, workGroupSize: UVec3;
                              compute: ThreadGenerator[A, B, C]; ssbo: A;
                              smem: B; args: C)
Source   Edit  

Templates

template runComputeOnCpu[A, C](numWorkGroups, workGroupSize: UVec3;
                               compute: ThreadGeneratorNoShared[A, C]; ssbo: A;
                               args: C)
Source   Edit