|
1 | | -import React from "react"; |
| 1 | +import React, { useCallback } from "react"; |
2 | 2 | import { StyleSheet, View } from "react-native"; |
3 | 3 | import { Canvas, useCanvasEffect } from "react-native-wgpu"; |
4 | 4 |
|
5 | 5 | import { redFragWGSL, triangleVertWGSL } from "./triangle"; |
6 | 6 |
|
7 | 7 | export function HelloTriangleMSAA() { |
8 | | - const ref = useCanvasEffect(() => { |
9 | | - (async () => { |
10 | | - const adapter = await navigator.gpu.requestAdapter(); |
11 | | - if (!adapter) { |
12 | | - throw new Error("No adapter"); |
13 | | - } |
14 | | - const device = await adapter.requestDevice(); |
15 | | - const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); |
| 8 | + const ref = useCanvasEffect(useCallback(async (signal) => { |
| 9 | + const adapter = await navigator.gpu.requestAdapter(); |
| 10 | + if (!adapter) { |
| 11 | + throw new Error("No adapter"); |
| 12 | + } |
| 13 | + const device = await adapter.requestDevice(); |
16 | 14 |
|
17 | | - const context = ref.current!.getContext("webgpu")!; |
18 | | - const { canvas } = context; |
19 | | - if (!context) { |
20 | | - throw new Error("No context"); |
21 | | - } |
22 | | - context.configure({ |
23 | | - device, |
24 | | - format: presentationFormat, |
25 | | - alphaMode: "premultiplied", |
26 | | - }); |
| 15 | + if (signal.aborted) { |
| 16 | + device.destroy(); |
| 17 | + return; |
| 18 | + } |
27 | 19 |
|
28 | | - const sampleCount = 4; |
| 20 | + const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); |
| 21 | + const context = ref.current!.getContext("webgpu")!; |
| 22 | + const { canvas } = context; |
| 23 | + if (!context) { |
| 24 | + throw new Error("No context"); |
| 25 | + } |
| 26 | + context.configure({ |
| 27 | + device, |
| 28 | + format: presentationFormat, |
| 29 | + alphaMode: "premultiplied", |
| 30 | + }); |
29 | 31 |
|
30 | | - const pipeline = device.createRenderPipeline({ |
31 | | - layout: "auto", |
32 | | - vertex: { |
33 | | - module: device.createShaderModule({ |
34 | | - code: triangleVertWGSL, |
35 | | - }), |
36 | | - }, |
37 | | - fragment: { |
38 | | - module: device.createShaderModule({ |
39 | | - code: redFragWGSL, |
40 | | - }), |
41 | | - targets: [ |
42 | | - { |
43 | | - format: presentationFormat, |
44 | | - }, |
45 | | - ], |
46 | | - }, |
47 | | - primitive: { |
48 | | - topology: "triangle-list", |
49 | | - }, |
50 | | - multisample: { |
51 | | - count: sampleCount, |
52 | | - }, |
53 | | - }); |
| 32 | + const sampleCount = 4; |
54 | 33 |
|
55 | | - const texture = device.createTexture({ |
56 | | - size: [canvas.width, canvas.height], |
57 | | - sampleCount, |
58 | | - format: presentationFormat, |
59 | | - usage: GPUTextureUsage.RENDER_ATTACHMENT, |
60 | | - }); |
61 | | - const view = texture.createView(); |
| 34 | + const pipeline = device.createRenderPipeline({ |
| 35 | + layout: "auto", |
| 36 | + vertex: { |
| 37 | + module: device.createShaderModule({ |
| 38 | + code: triangleVertWGSL, |
| 39 | + }), |
| 40 | + }, |
| 41 | + fragment: { |
| 42 | + module: device.createShaderModule({ |
| 43 | + code: redFragWGSL, |
| 44 | + }), |
| 45 | + targets: [ |
| 46 | + { |
| 47 | + format: presentationFormat, |
| 48 | + }, |
| 49 | + ], |
| 50 | + }, |
| 51 | + primitive: { |
| 52 | + topology: "triangle-list", |
| 53 | + }, |
| 54 | + multisample: { |
| 55 | + count: sampleCount, |
| 56 | + }, |
| 57 | + }); |
62 | 58 |
|
63 | | - function frame() { |
64 | | - const commandEncoder = device.createCommandEncoder(); |
| 59 | + const texture = device.createTexture({ |
| 60 | + size: [canvas.width, canvas.height], |
| 61 | + sampleCount, |
| 62 | + format: presentationFormat, |
| 63 | + usage: GPUTextureUsage.RENDER_ATTACHMENT, |
| 64 | + }); |
| 65 | + const view = texture.createView(); |
| 66 | + |
| 67 | + const commandEncoder = device.createCommandEncoder(); |
| 68 | + |
| 69 | + const renderPassDescriptor: GPURenderPassDescriptor = { |
| 70 | + colorAttachments: [ |
| 71 | + { |
| 72 | + view, |
| 73 | + resolveTarget: context.getCurrentTexture().createView(), |
| 74 | + clearValue: [0, 0, 0, 1], |
| 75 | + loadOp: "clear", |
| 76 | + storeOp: "discard", |
| 77 | + }, |
| 78 | + ], |
| 79 | + }; |
65 | 80 |
|
66 | | - const renderPassDescriptor: GPURenderPassDescriptor = { |
67 | | - colorAttachments: [ |
68 | | - { |
69 | | - view, |
70 | | - resolveTarget: context.getCurrentTexture().createView(), |
71 | | - clearValue: [0, 0, 0, 1], |
72 | | - loadOp: "clear", |
73 | | - storeOp: "discard", |
74 | | - }, |
75 | | - ], |
76 | | - }; |
| 81 | + const passEncoder = |
| 82 | + commandEncoder.beginRenderPass(renderPassDescriptor); |
| 83 | + passEncoder.setPipeline(pipeline); |
| 84 | + passEncoder.draw(3); |
| 85 | + passEncoder.end(); |
77 | 86 |
|
78 | | - const passEncoder = |
79 | | - commandEncoder.beginRenderPass(renderPassDescriptor); |
80 | | - passEncoder.setPipeline(pipeline); |
81 | | - passEncoder.draw(3); |
82 | | - passEncoder.end(); |
| 87 | + device.queue.submit([commandEncoder.finish()]); |
83 | 88 |
|
84 | | - device.queue.submit([commandEncoder.finish()]); |
85 | | - } |
| 89 | + context.present(); |
86 | 90 |
|
87 | | - frame(); |
88 | | - context.present(); |
89 | | - })(); |
90 | | - }); |
| 91 | + // Cleanup |
| 92 | + device.destroy(); |
| 93 | + }, [])); |
91 | 94 |
|
92 | 95 | return ( |
93 | 96 | <View style={style.container}> |
|
0 commit comments