UNPKG

typegpu

Version:

A thin layer between JS and WebGPU/WGSL that improves development experience and allows for faster iteration.

61 lines (60 loc) 2.78 kB
import { memoryLayoutOf } from "../../data/offsetUtils.js"; import { sizeOf } from "../../data/sizeOf.js"; import { isGPUBuffer } from "../../types.js"; import { logger } from "../../tgpuLogger.js"; export const DISPATCH_INDIRECT_SIZE = 12; // 3 x u32 (x, y, z) export const DRAW_INDIRECT_SIZE = 16; // 4 x 4 export const DRAW_INDEXED_INDIRECT_SIZE = 20; // 5 x 4 export function collectBindGroupPairs(layouts, catchall, map) { return layouts.flatMap((layout, idx) => { const resource = catchall && idx === catchall[0] ? catchall[1] : map?.get(layout); return resource ? [[layout, resource]] : []; }); } export function collectVertexBufferPairs(layouts, map) { return layouts.flatMap((layout) => { const resource = map?.get(layout); return resource ? [[layout, resource]] : []; }); } export function restoreTimestampPriors(pipeline, priors) { let result = pipeline; if (priors.timestampWrites) { result = result.withTimestampWrites(priors.timestampWrites); } if (priors.performanceCallback) { result = result.withPerformanceCallback(priors.performanceCallback); } return result; } const IndirectOperationToRequiredData = { dispatchWorkgroupsIndirect: '3 x u32', drawIndirect: '4 x u32', drawIndexedIndirect: '3 x u32, i32, u32', }; function validateIndirectBufferSize(bufferSize, offset, requiredBytes, operation) { if (offset + requiredBytes > bufferSize) { throw new Error(`Buffer too small for ${operation}. Required: ${requiredBytes} bytes at offset ${offset}, but buffer is only ${bufferSize} bytes.`); } if (offset % 4 !== 0) { throw new Error(`Indirect buffer offset must be a multiple of 4. Got: ${offset}`); } } export function resolveIndirectOffset(indirectBuffer, start, requiredSize, operation) { if (isGPUBuffer(indirectBuffer)) { const offset = typeof start === 'number' ? start : (start?.offset ?? 0); validateIndirectBufferSize(indirectBuffer.size, offset, requiredSize, operation); return offset; } const offsetInfo = start ? typeof start === 'number' ? { offset: start, contiguous: requiredSize } : start : memoryLayoutOf(indirectBuffer.dataType); const { offset, contiguous } = offsetInfo; validateIndirectBufferSize(sizeOf(indirectBuffer.dataType), offset, requiredSize, operation); if (contiguous < requiredSize) { logger.warn('suspicious', `${operation}: Starting at offset ${offset}, only ${contiguous} contiguous bytes are available before padding. '${operation}' requires ${requiredSize} bytes (${IndirectOperationToRequiredData[operation]}). Reading across padding may result in undefined behavior.`); } return offset; }