yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Anders LeinoAdd example showing how to use Slang/WASM (#5996)7e278c3ad

master
5.4 KiB158 linesraw
1"use strict";
2
3let Example = {
4    initialize: async function (slang, canvas) {
5        async function render(shaders) {
6            if (!navigator.gpu) {
7                throw new Error("WebGPU not supported on this browser.");
8            }
9            const adapter = await navigator.gpu.requestAdapter();
10            if (!adapter) {
11                throw new Error("No appropriate GPUAdapter found.");
12            }
13            const device = await adapter.requestDevice();
14            const context = canvas.getContext("webgpu");
15            const canvasFormat = navigator.gpu.getPreferredCanvasFormat();
16            context.configure({
17                device: device,
18                format: canvasFormat,
19            });
20
21            const vertexBufferLayout = {
22                arrayStride: 8,
23                attributes: [{
24                    format: "float32x2",
25                    offset: 0,
26                    shaderLocation: 0,
27                }],
28            };
29
30            const pipeline = device.createRenderPipeline({
31                label: "Pipeline",
32                layout: "auto",
33                vertex: {
34                    module: device.createShaderModule({
35                        label: "Vertex shader module",
36                        code: shaders.vertex
37                    }),
38                    entryPoint: "vertexMain",
39                    buffers: [vertexBufferLayout]
40                },
41                fragment: {
42                    module: device.createShaderModule({
43                        label: "Fragment shader module",
44                        code: shaders.fragment
45                    }),
46                    entryPoint: "fragmentMain",
47                    targets: [{
48                        format: canvasFormat
49                    }]
50                }
51            });
52
53            const vertices = new Float32Array([
54                0.0, -0.8,
55                +0.8, +0.8,
56                -0.8, +0.8,
57            ]);
58            const vertexBuffer = device.createBuffer({
59                label: "Triangle vertices",
60                size: vertices.byteLength,
61                usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
62            });
63            const bufferOffset = 0;
64            device.queue.writeBuffer(vertexBuffer, bufferOffset, vertices);
65
66            const encoder = device.createCommandEncoder();
67            const pass = encoder.beginRenderPass({
68                colorAttachments: [{
69                    view: context.getCurrentTexture().createView(),
70                    loadOp: "clear",
71                    clearValue: { r: 0, g: 0, b: 0, a: 1 },
72                    storeOp: "store",
73                }]
74            });
75            pass.setPipeline(pipeline);
76            const vertexBufferSlot = 0;
77            pass.setVertexBuffer(vertexBufferSlot, vertexBuffer);
78            pass.draw(vertices.length / 2);
79            pass.end();
80            const commandBuffer = encoder.finish();
81            device.queue.submit([commandBuffer]);
82        }
83
84        const slangCode = await fetch("shader.slang").then(r => r.text());
85
86        var wasmCompileTarget = null;
87        var compileTargetMap = slang.module.getCompileTargets();
88        for (var i = 0; i < compileTargetMap.length; i++) {
89            var target = compileTargetMap[i];
90            if(target.name == "WGSL") {
91                wasmCompileTarget = target.value;
92            }
93        }
94        if (wasmCompileTarget === null) {
95            throw new Error("Slang/WASM module doesn't support WGSL compile target.");
96        }
97
98        var slangSession = slang.globalSession.createSession(wasmCompileTarget);
99        if (!slangSession) {
100            throw new Error("Failed to create global Slang session.");
101        }
102
103        var wgslShaders = null;
104        try {
105            var module = slangSession.loadModuleFromSource(
106                slangCode, "shader", '/shader.slang'
107            );
108            var vertexEntryPoint = module.findAndCheckEntryPoint(
109                "vertexMain", slang.constants.STAGE_VERTEX
110            );
111            var fragmentEntryPoint = module.findAndCheckEntryPoint(
112                "fragmentMain", slang.constants.STAGE_FRAGMENT
113            );
114            var linkedProgram = slangSession.createCompositeComponentType([
115                module, vertexEntryPoint, fragmentEntryPoint
116            ]).link();
117            wgslShaders = {
118                vertex: linkedProgram.getEntryPointCode(
119                    0 /* entryPointIndex */, 0 /* targetIndex */
120                ),
121                fragment: linkedProgram.getEntryPointCode(
122                    1 /* entryPointIndex */, 0 /* targetIndex */
123                ),
124            };
125        } finally {
126            if (slangSession) {
127                slangSession.delete();
128            }
129        }
130
131        if (!wgslShaders) {
132            throw new Error("Failed to compile WGSL shaders.");
133        }
134
135        render(wgslShaders);
136    }
137}
138
139var Module = {
140    onRuntimeInitialized: function() {
141        const canvas = document.querySelector("canvas");
142
143        var globalSlangSession = Module.createGlobalSession();
144        if (!globalSlangSession) {
145            throw new Error("Failed to create global Slang session.");
146        }
147
148        const slang = {
149            module: Module,
150            globalSession: globalSlangSession,
151            constants: {
152                STAGE_VERTEX: 1,
153                STAGE_FRAGMENT: 5,
154            },
155        };
156        Example.initialize(slang, canvas);
157    },
158};