Make JetStream 2
[WebKit-https.git] / PerformanceTests / JetStream2 / WSL / SPIRVCodegen.js
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25 "use strict";
26
27 function generateSPIRV(spirv, program)
28 {
29
30     function findEntryPoints()
31     {
32         let entryPoints = [];
33         for (let functionNames of program.functions.values()) {
34             for (let func of functionNames) {
35                 switch (func.shaderType) {
36                 case "vertex":
37                 case "fragment":
38                     entryPoints.push(func);
39                     break;
40                 }
41             }
42         }
43         return entryPoints;
44     }
45
46     let currentId = 3;
47     let currentLocation = 0;
48     let typeMap = new Map();
49     let reverseTypeMap = new Map();
50     let entryPoints = [];
51
52     typeMap.set(program.intrinsics.void, currentId++);
53     typeMap.set(program.intrinsics.uint32, currentId++);
54
55     for (let entryPoint of findEntryPoints()) {
56         let inlinedShader = program.funcInstantiator.getUnique(entryPoint, []);
57         _inlineFunction(program, inlinedShader, new VisitingSet(entryPoint));
58
59         let typeAnalyzer = new SPIRVTypeAnalyzer(program, typeMap, currentId);
60         inlinedShader.visit(typeAnalyzer);
61         currentId = typeAnalyzer.currentId;
62
63         currentLocation = 0;
64         let valueAnalyzer = new SPIRVPrimitiveVariableAnalyzer(program, typeMap, currentId, currentLocation);
65         inlinedShader.returnType.visit(valueAnalyzer);
66         currentId = valueAnalyzer.currentId;
67         let outputValues = valueAnalyzer.result;
68
69         let inputValues = [];
70         for (let parameter of inlinedShader.parameters) {
71             if (parameter.type.type instanceof StructType) {
72                 let valueAnalyzer = new SPIRVPrimitiveVariableAnalyzer(program, typeMap, currentId, currentLocation, parameter.name);
73                 parameter.visit(valueAnalyzer);
74                 currentId = valueAnalyzer.currentId;
75                 currentLocation = valueAnalyzer.currentLocation;
76                 for (let inputValue of valueAnalyzer.result)
77                     inputValues.push(inputValue);
78             } else if (parameter.type.type instanceof ArrayRefType) {
79                 // FIXME: Implement this.
80             }
81         }
82
83         entryPoints.push({ id: currentId++, shader: inlinedShader, inputs: inputValues, outputs: outputValues });
84     }
85     
86     for (let type of typeMap) {
87         if (typeof type[1] == "object")
88             reverseTypeMap.set(type[1].id, type[0]);
89         else
90             reverseTypeMap.set(type[1], type[0]);
91     }
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106     function emitTypes(assembler) {
107         let emittedTypes = new Set();
108         function doEmitTypes(type)
109         {
110             if (emittedTypes.has(type[0]))
111                 return;
112             emittedTypes.add(type[0]);
113             if (typeof type[1] == "object") {
114                 if (type[1].fieldTypes) {
115                     for (let fieldType of type[1].fieldTypes) {
116                         let key = reverseTypeMap.get(fieldType);
117                         let value = typeMap.get(key);
118                         doEmitTypes([key, value]);
119                     }
120                     switch (type[0]) {
121                     case "struct vec2<> { int32 x; int32 y }":
122                     case "struct vec2<> { uint32 x; uint32 y; }":
123                     case "struct vec2<> { float32 x; float32 y; }":
124                     case "struct vec2<> { float64 x; float64 y; }":
125                     case "struct vec3<> { int32 x; int32 y; int32 z; }":
126                     case "struct vec3<> { uint32 x; uint32 y; uint32 z; }":
127                     case "struct vec3<> { float32 x; float32 y; float32 z; }":
128                     case "struct vec3<> { float64 x; float64 y; float64 z; }":
129                     case "struct vec4<> { int32 x; int32 y; int32 z; int32 w; }":
130                     case "struct vec4<> { uint32 x; uint32 y; uint32 z; uint32 w; }":
131                     case "struct vec4<> { float32 x; float32 y; float32 z; float32 w; }":
132                     case "struct vec4<> { float64 x; float64 y; float64 z; float64 w; }":
133                         assembler.append(new spirv.ops.TypeVector(type[1].id, type[1].fieldTypes[0], type[1].fieldTypes.length));
134                         break;
135                     default:
136                         assembler.append(new spirv.ops.TypeStruct(type[1].id, ...type[1].fieldTypes));
137                         break;
138                     }
139                 } else {
140                     if (!type[1].elementType)
141                         throw new Error("Unknown type!");
142             
143                     let elementType = type[1].elementType;
144                     let key = reverseTypeMap.get(elementType);
145                     let value = typeMap.get(key);
146                     doEmitTypes([key, value]);
147
148                     let id = currentId++;
149                     assembler.append(new spirv.ops.Constant(typeMap.get(program.intrinsics.uint32), id, type[1].numElements));
150                     assembler.append(new spirv.ops.TypeArray(type[1].id, elementType, id));
151                 }
152             } else {
153                 switch (type[0].name) {
154                 case "void":
155                     assembler.append(new spirv.ops.TypeVoid(type[1]));
156                     break;
157                 case "bool":
158                     assembler.append(new spirv.ops.TypeBool(type[1]));
159                     break;
160                 case "int32":
161                     assembler.append(new spirv.ops.TypeInt(type[1], 32, 1));
162                     break;
163                 case "uint32":
164                 case "uint8":
165                     assembler.append(new spirv.ops.TypeInt(type[1], 32, 0));
166                     break;
167                 case "float32":
168                     assembler.append(new spirv.ops.TypeFloat(type[1], 32));
169                     break;
170                 case "float64":
171                     assembler.append(new spirv.ops.TypeFloat(type[1], 64));
172                     break;
173                 }
174             }
175         }
176         doEmitTypes([program.intrinsics.uint32, typeMap.get(program.intrinsics.uint32)]);
177         for (let type of typeMap)
178             doEmitTypes(type)
179     }
180
181
182
183
184
185
186
187
188
189
190
191
192     let constants = new Map();
193     class ConstantFinder extends Visitor {
194         visitGenericLiteralType(node)
195         {
196             let type = node.type;
197             while (type instanceof TypeRef)
198                 type = type.type;
199             let values;
200             switch (type) {
201             case program.intrinsics.bool:
202                 values = [node.value];
203                 break;
204             case program.intrinsics.int32:
205             case program.intrinsics.uint32:
206             case program.intrinsics.uint8:
207                 values = [node.value]
208                 break;
209             case program.intrinsics.float: {
210                 let arrayBuffer = new ArrayBuffer(Math.max(Uint32Array.BYTES_PER_ELEMENT, Float32Array.BYTES_PER_ELEMENT));
211                 let floatView = new Float32Array(arrayBuffer);
212                 let uintView = new Uint32Array(arrayBuffer);
213                 floatView[0] = node.value;
214                 values = uintView;
215                 break;
216             }
217             case program.intrinsics.double: {
218                 let arrayBuffer = new ArrayBuffer(Math.max(Uint32Array.BYTES_PER_ELEMENT, Float64Array.BYTES_PER_ELEMENT));
219                 let doubleView = new Float64Array(arrayBuffer);
220                 let uintView = new Uint32Array(arrayBuffer);
221                 doubleView[0] = node.value;
222                 values = uintView;
223                 break;
224             }
225             default:
226                 throw new Error("Unrecognized literal.");
227             }
228             constants.set(node, { id: currentId++, typeId: typeMap.get(type), type: type, values: values });
229         }
230     }
231     for (let entryPoint of entryPoints)
232         entryPoint.shader.visit(new ConstantFinder());
233
234
235
236
237
238
239
240
241
242
243
244
245     let assembler = new SPIRVAssembler();
246     // 1. All OpCapability instructions
247     assembler.append(new spirv.ops.Capability(spirv.kinds.Capability.Shader));
248     assembler.append(new spirv.ops.Capability(spirv.kinds.Capability.Float64));
249     // 2. Optional OpExtension instructions
250     // 3. Optional OpExtInstImport instructions
251     // 4. The single required OpMemoryModel instruction
252     // FIXME: Figure out if we can use the Simple memory model instead of the GLSL memory model.
253     // The spec says nothing about what the difference between them is. 💯
254     assembler.append(new spirv.ops.MemoryModel(spirv.kinds.AddressingModel.Logical, spirv.kinds.MemoryModel.GLSL450));
255
256     // 5. All entry point declarations
257     for (let entryPoint of entryPoints) {
258         let executionModel;
259         switch (entryPoint.shader.shaderType) {
260         case "vertex":
261             executionModel = spirv.kinds.ExecutionModel.Vertex;
262             break;
263         case "fragment":
264             executionModel = spirv.kinds.ExecutionModel.Fragment;
265             break;
266         }
267         let id = entryPoint.id;
268         let name = entryPoint.shader.name;
269         let interfaceIds = []
270         for (let value of entryPoint.inputs)
271             interfaceIds.push(value.id);
272         for (let value of entryPoint.outputs)
273             interfaceIds.push(value.id);
274         assembler.append(new spirv.ops.EntryPoint(executionModel, id, name, ...interfaceIds));
275     }
276
277     // 6. All execution mode declarations
278     for (let entryPoint of entryPoints) {
279         let id = entryPoint.id;
280         assembler.append(new spirv.ops.ExecutionMode(id, spirv.kinds.ExecutionMode.OriginLowerLeft));
281     }
282
283     // 7. These debug instructions
284     // 8. All annotation instructions
285     // FIXME: There are probably more annotations that are required than just location.
286     let locations = [];
287     for (let entryPoint of entryPoints) {
288         switch (entryPoint.shader.shaderType) {
289         case "vertex":
290             for (let input of entryPoint.inputs) {
291                 assembler.append(new spirv.ops.Decorate(input.id, spirv.kinds.Decoration.Location, input.location));
292                 locations.push({ name: entryPoint.shader.name + "." + input.name, location: input.location });
293             }
294             break;
295         case "fragment":
296             for (let output of entryPoint.outputs) {
297                 assembler.append(new spirv.ops.Decorate(output.id, spirv.kinds.Decoration.Location, output.location));
298                 locations.push({ name: entryPoint.shader.name + "." + output.name, location: output.location });
299             }
300             break;
301         }
302     }
303
304     // 9. All type declarations, all constant instructions, and all global variable declarations
305     emitTypes(assembler);
306     let functionType = currentId++;
307     assembler.append(new spirv.ops.TypeFunction(functionType, typeMap.get(program.intrinsics.void)));
308     for (let constant of constants) {
309         if (constant[1].type == program.intrinsics.bool) {
310             if (constant[1].value[0])
311                 assembler.append(new spirv.ops.ConstantTrue(constant[1].id));
312             else
313                 assembler.append(new spirv.ops.ConstantFalse(constant[1].id));
314         } else
315             assembler.append(new spirv.ops.Constant(constant[1].typeId, constant[1].id, ...constant[1].values));
316     }
317     for (let entryPoint of entryPoints) {
318         for (let input of entryPoint.inputs)
319             assembler.append(new spirv.ops.Variable(input.type, input.id, spirv.kinds.StorageClass.Input));
320         for (let output of entryPoint.outputs)
321             assembler.append(new spirv.ops.Variable(output.type, output.id, spirv.kinds.StorageClass.Output));
322     }
323
324     // 10. All function declarations
325     // 11. All function definitions
326     for (let entryPoint of entryPoints) {
327         assembler.append(new spirv.ops.Function(typeMap.get(program.intrinsics.void), entryPoint.id, [spirv.kinds.FunctionControl.None], functionType));
328         assembler.append(new spirv.ops.FunctionEnd());
329     }
330
331     return { file: assembler.result, locations: locations };
332 }
333