캔버스에 그리기

캔버스에 그리기

전체 화면 @fragment 진입점과 이를 그리는 호스트입니다. 호스트는 fs를 가져와 프레임마다 fs(canvas, { frame })를 한 번 부르고, 유니폼에 시간을 넣습니다. 그리는 것은 전체 화면 삼각형 하나입니다. WebGPU가 먼저이고, 없으면 WebGL2, 그다음은 CPU tier입니다. 호스트 코드에는 파이프라인도 버퍼도 바인드 그룹도 없다(규칙 8.24).

실행 tier WebGPUWebGL2CPU tier

이 목록은 컴파일러가 확인합니다. tier(호출이 실행되는 백엔드)는 호스트의 실행 전체가 그 tier 하나만으로 기준값을 낼 때만 목록에 오릅니다. 컴파일러의 저니 게이트가 호스트마다 WebGPU와 WebGL2에서 실행하고, 단위 테스트가 CPU tier에서 실행합니다.

"use typeshade";
/* @example
{
"title": "Host: draw into a canvas",
"blurb": "A full-screen `@fragment` entry and the host that draws it. The host imports `fs` and calls `fs(canvas, { frame })` once a frame, with the time in the uniform: one full-screen triangle, on WebGPU, then WebGL2, then the CPU tier, with no pipeline, buffer or bind group in the host's code (Rule 8.24).",
"renderable": false,
"reason": "no entry point"
}
*/
// What the host sets each frame: the time, and the canvas's size in pixels.
class Frame {
time: f32;
size: vec2;
}
declare const frame: uniform<Frame>;
// A full-screen fragment entry reads no builtin but `position`, and writes one colour, so a host
// draws it into a canvas with no vertex entry of its own.
@fragment
export function fs(@builtin("position") p: vec4): vec4 {
const uv = p.xy / frame.size;
const wave = 0.5 + 0.5 * sin(6.2831853 * uv.x + frame.time);
return vec4(uv.x, uv.y, wave, 1.);
}
// Draw a full-screen fragment entry into a canvas (surface §67, Rule 8.24).
//
// The import is the shader module itself: the Vite plugin (`typeshade/vite`) turns `fs` into a
// function that draws one frame. The first draw into a canvas picks its tier: WebGPU, then
// WebGL2, then the CPU tier, which paints the frame pixel by pixel.
import { fs } from './host-draw.shade.ts';
/** Draw one frame at `time` seconds. The promise resolves when the frame is submitted. */
export function draw(canvas: HTMLCanvasElement | OffscreenCanvas, time: number): Promise<void> {
return fs(canvas, { frame: { time, size: [canvas.width, canvas.height] } });
}
/** Animate `canvas`: a new uniform value each frame. A frame loop need not wait for a draw. */
export function animate(canvas: HTMLCanvasElement): void {
const frame = (ms: number): void => {
void draw(canvas, ms / 1000);
requestAnimationFrame(frame);
};
requestAnimationFrame(frame);
}
/** Draw the frames at `times`, one after another. The canvas then shows the last one. */
export async function run(
canvas: HTMLCanvasElement | OffscreenCanvas,
times: readonly number[] = [0, 0.5, 1.25],
): Promise<void> {
for (const time of times) await draw(canvas, time);
}

두 파일 모두 커밋 91c2fe31의 컴파일러에 있는 그대로이며, 예제 디렉터리에서 읽어 왔습니다.

GitHub의 모듈GitHub의 호스트 파일

이 페이지 편집 문제 보고