1- import { ReflectionJSON } from './compiler.js' ;
1+ import { ReflectionJSON , ReflectionType } from './compiler.js' ;
22import { ParsedCommand } from './try-slang.js' ;
33
44export function configContext ( device : GPUDevice , canvas : HTMLCanvasElement ) {
@@ -42,6 +42,42 @@ function reinterpretUint32AsFloat(uint32: number) {
4242 return float32View [ 0 ] ;
4343}
4444
45+ function roundUpToNearest ( x : number , nearest : number ) {
46+ return Math . ceil ( x / nearest ) * nearest ;
47+ }
48+
49+ function getSize ( reflectionType : ReflectionType ) : number {
50+ if ( reflectionType . kind == "resource" ) {
51+ throw new Error ( "unimplemented" ) ;
52+ } else if ( reflectionType . kind == "scalar" ) {
53+ const bitsMatch = reflectionType . scalarType . match ( / \d + $ / ) ;
54+ if ( bitsMatch == null ) {
55+ throw new Error ( "Could not get bit count out of scalar type" ) ;
56+ }
57+ return parseInt ( bitsMatch [ 0 ] ) / 8 ;
58+ } else if ( reflectionType . kind == "struct" ) {
59+ const alignment = reflectionType . fields . map ( ( f ) => {
60+ if ( f . binding . kind == "uniform" ) return f . binding . size ;
61+ else throw new Error ( "Invalid state" )
62+ } ) . reduce ( ( a , b ) => Math . max ( a , b ) ) ;
63+
64+ const unalignedSize = reflectionType . fields . map ( ( f ) => {
65+ if ( f . binding . kind == "uniform" ) return f . binding . offset + f . binding . size ;
66+ else throw new Error ( "Invalid state" )
67+ } ) . reduce ( ( a , b ) => Math . max ( a , b ) ) ;
68+
69+ return roundUpToNearest ( unalignedSize , alignment ) ;
70+ } else if ( reflectionType . kind == "vector" ) {
71+ if ( reflectionType . elementCount == 3 ) {
72+ return 4 * getSize ( reflectionType . elementType ) ;
73+ }
74+ return reflectionType . elementCount * getSize ( reflectionType . elementType ) ;
75+ } else {
76+ let x :never = reflectionType ;
77+ throw new Error ( "Cannot get size of unrecognized reflection type" ) ;
78+ }
79+ }
80+
4581/**
4682 * Here are some patterns we support:
4783 *
@@ -63,20 +99,41 @@ export function getCommandsFromAttributes(reflection: ReflectionJSON): { resourc
6399 if ( ! attribute . name . startsWith ( "playground_" ) ) continue ;
64100
65101 let playground_attribute_name = attribute . name . slice ( 11 ) ;
66- if ( playground_attribute_name == "ZEROS" || playground_attribute_name == "RAND" ) {
102+ if ( playground_attribute_name == "ZEROS" ) {
103+ if ( parameter . type . kind != "resource" || parameter . type . baseShape != "structuredBuffer" ) {
104+ throw new Error ( `ZEROS attribute cannot be applied to ${ parameter . name } , it only supports buffers` )
105+ }
67106 command = {
68107 type : playground_attribute_name ,
69108 count : attribute . arguments [ 0 ] as number ,
109+ elementSize : getSize ( parameter . type . resultType ) ,
110+ } ;
111+ } else if ( playground_attribute_name == "RAND" ) {
112+ if ( parameter . type . kind != "resource" || parameter . type . baseShape != "structuredBuffer" ) {
113+ throw new Error ( `RAND attribute cannot be applied to ${ parameter . name } , it only supports buffers` )
114+ }
115+ if ( parameter . type . resultType . kind != "scalar" || parameter . type . resultType . scalarType != "float32" ) {
116+ throw new Error ( `RAND attribute cannot be applied to ${ parameter . name } , it only supports float buffers` )
117+ }
118+ command = {
119+ type : playground_attribute_name ,
120+ count : attribute . arguments [ 0 ] as number
70121 } ;
71122 } else if ( playground_attribute_name == "BLACK" ) {
123+ if ( parameter . type . kind != "resource" || parameter . type . baseShape != "texture2D" ) {
124+ throw new Error ( `BLACK attribute cannot be applied to ${ parameter . name } , it only supports 2D textures` )
125+ }
72126 command = {
73- type : "BLACK" ,
127+ type : playground_attribute_name ,
74128 width : attribute . arguments [ 0 ] as number ,
75129 height : attribute . arguments [ 1 ] as number ,
76130 } ;
77131 } else if ( playground_attribute_name == "URL" ) {
132+ if ( parameter . type . kind != "resource" || parameter . type . baseShape != "texture2D" ) {
133+ throw new Error ( `URL attribute cannot be applied to ${ parameter . name } , it only supports 2D textures` )
134+ }
78135 command = {
79- type : "URL" ,
136+ type : playground_attribute_name ,
80137 url : attribute . arguments [ 0 ] as string ,
81138 } ;
82139 }
@@ -97,13 +154,14 @@ export type CallCommand = {
97154 type : "RESOURCE_BASED" ,
98155 fnName : string ,
99156 resourceName : string ,
157+ elementSize ?: number ,
100158} | {
101159 type : "FIXED_SIZE" ,
102160 fnName : string ,
103161 size : number [ ] ,
104162} ;
105163
106- export function parseCallCommands ( userSource : string ) : CallCommand [ ] {
164+ export function parseCallCommands ( userSource : string , reflection : ReflectionJSON ) : CallCommand [ ] {
107165 // Look for commands of the form:
108166 //
109167 // 1. //! CALL(fn-name, SIZE_OF(<resource-name>)) ==> Dispatch a compute pass with the given
@@ -122,7 +180,16 @@ export function parseCallCommands(userSource: string): CallCommand[] {
122180 const args = match [ 2 ] . split ( ',' ) . map ( arg => arg . trim ( ) ) ;
123181
124182 if ( args [ 0 ] . startsWith ( "SIZE_OF" ) ) {
125- callCommands . push ( { type : "RESOURCE_BASED" , fnName, resourceName : args [ 0 ] . slice ( 8 , - 1 ) } ) ;
183+ let resourceName = args [ 0 ] . slice ( 8 , - 1 ) ;
184+ let resourceReflection = reflection . parameters . find ( ( param ) => param . name == resourceName ) ;
185+ if ( resourceReflection == undefined ) {
186+ throw new Error ( `Cannot find resource ${ resourceName } for ${ fnName } CALL command` )
187+ }
188+ let elementSize : number | undefined = undefined ;
189+ if ( resourceReflection . type . kind == "resource" && resourceReflection . type . baseShape == "structuredBuffer" ) {
190+ elementSize = getSize ( resourceReflection . type . resultType ) ;
191+ }
192+ callCommands . push ( { type : "RESOURCE_BASED" , fnName, resourceName, elementSize } ) ;
126193 }
127194 else {
128195 callCommands . push ( { type : "FIXED_SIZE" , fnName, size : args . map ( Number ) } ) ;
0 commit comments