Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update samples to work with TypeScript strict mode (part 2) #285

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
14 changes: 9 additions & 5 deletions src/sample/cornell/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,22 @@ import Radiosity from './radiosity';
import Rasterizer from './rasterizer';
import Tonemapper from './tonemapper';
import Raytracer from './raytracer';
import { assert } from '../../components/SampleLayout';

const init: SampleInit = async ({ canvas, pageState, gui }) => {
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
const requiredFeatures: GPUFeatureName[] =
presentationFormat === 'bgra8unorm' ? ['bgra8unorm-storage'] : [];
const adapter = await navigator.gpu.requestAdapter();
for (const feature of requiredFeatures) {
if (!adapter.features.has(feature)) {
if (!adapter?.features.has(feature)) {
nash1111 marked this conversation as resolved.
Show resolved Hide resolved
throw new Error(
`sample requires ${feature}, but is not supported by the adapter`
);
}
}
const device = await adapter.requestDevice({ requiredFeatures });
const device = await adapter?.requestDevice({ requiredFeatures });
assert(device, 'device is null');
nash1111 marked this conversation as resolved.
Show resolved Hide resolved

if (!pageState.active) return;

Expand All @@ -36,8 +38,8 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
rotateCamera: true,
};

gui.add(params, 'renderer', ['rasterizer', 'raytracer']);
gui.add(params, 'rotateCamera', true);
gui?.add(params, 'renderer', ['rasterizer', 'raytracer']);
gui?.add(params, 'rotateCamera', true);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this can't actually happen I think I'd prefer gui! over gui?
If it's wrong it'll just throw a TypeError which is fine for a sample.

Or just assert(gui).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the review. I used assert because non-null assertions are discouraged in some lint settings


const devicePixelRatio = window.devicePixelRatio || 1;
canvas.width = canvas.clientWidth * devicePixelRatio;
Expand Down Expand Up @@ -80,7 +82,9 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
}

const canvasTexture = context.getCurrentTexture();
const commandEncoder = device.createCommandEncoder();
const commandEncoder = device?.createCommandEncoder();
assert(commandEncoder, 'commandEncoder is null');
assert(device, 'device is null');
nash1111 marked this conversation as resolved.
Show resolved Hide resolved

common.update({
rotateCamera: params.rotateCamera,
Expand Down
21 changes: 15 additions & 6 deletions src/sample/cubemap/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { mat4, vec3 } from 'wgpu-matrix';
import { makeSample, SampleInit } from '../../components/SampleLayout';
import { assert, makeSample, SampleInit } from '../../components/SampleLayout';

import {
cubeVertexArray,
Expand All @@ -14,7 +14,8 @@ import sampleCubemapWGSL from './sampleCubemap.frag.wgsl';

const init: SampleInit = async ({ canvas, pageState }) => {
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const device = await adapter?.requestDevice();
assert(device, 'device is null');

if (!pageState.active) return;
const context = canvas.getContext('webgpu') as GPUCanvasContext;
Expand Down Expand Up @@ -198,7 +199,7 @@ const init: SampleInit = async ({ canvas, pageState }) => {
const renderPassDescriptor: GPURenderPassDescriptor = {
colorAttachments: [
{
view: undefined, // Assigned later
view: undefined as any, // Assigned later
Copy link
Collaborator

@kainino0x kainino0x Aug 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(In response to the GitHub Actions check warning)
It would be nice to make the build warning-free. In this case it can probably be view: undefined!,

Copy link
Contributor Author

@nash1111 nash1111 Aug 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kainino0x
I wanted to use view: undefined! too, but it was inferred as the never type and didn't work out. How about using view: undefined as unknown as GPUTextureView ? Using as twice isn't intuitive, but since we can't directly cast undefined to GPUTextureView, it seems unavoidable. If there's a better suggestion, I'd love to hear it.

loadOp: 'clear',
storeOp: 'store',
},
Expand Down Expand Up @@ -245,6 +246,7 @@ const init: SampleInit = async ({ canvas, pageState }) => {
function frame() {
// Sample is no longer the active page.
if (!pageState.active) return;
assert(device, 'device is null');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly shouldn't be necessary, though I'm less certain about this since it's inside a function. OK to keep if needed.


updateTransformationMatrix();
device.queue.writeBuffer(
Expand All @@ -255,9 +257,16 @@ const init: SampleInit = async ({ canvas, pageState }) => {
modelViewProjectionMatrix.byteLength
);

renderPassDescriptor.colorAttachments[0].view = context
.getCurrentTexture()
.createView();
type GPURenderPassColorAttachmentArray =
(GPURenderPassColorAttachment | null)[];

const attachment = (
renderPassDescriptor.colorAttachments as GPURenderPassColorAttachmentArray
)[0];

assert(attachment, 'attachment is null');

attachment.view = context.getCurrentTexture().createView();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a complicated way to get colorAttachments[0]. How about storing colorAttachment0 into its own variable?

const colorAttachment0: GPURenderPassColorAttachment = {
  view: undefined as any, // Assigned later
};

const renderPassDescriptor: GPURenderPassDescriptor = {
  colorAttachments: [colorAttachment0],
colorAttachment0.view = context.getCurrentTexture().createView();


const commandEncoder = device.createCommandEncoder();
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
Expand Down
24 changes: 16 additions & 8 deletions src/sample/deferredRendering/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { makeSample, SampleInit } from '../../components/SampleLayout';
import { assert, makeSample, SampleInit } from '../../components/SampleLayout';
import { mat4, vec3, vec4 } from 'wgpu-matrix';
import { mesh } from '../../meshes/stanfordDragon';

Expand All @@ -15,7 +15,9 @@ const lightExtentMax = vec3.fromValues(50, 50, 50);

const init: SampleInit = async ({ canvas, pageState, gui }) => {
const adapter = await navigator.gpu.requestAdapter();
assert(adapter, 'Unable to find a suitable GPU adapter.');
const device = await adapter.requestDevice();
assert(gui, 'gui is null');

if (!pageState.active) return;
const context = canvas.getContext('webgpu') as GPUCanvasContext;
Expand Down Expand Up @@ -285,7 +287,7 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
colorAttachments: [
{
// view is acquired and set in render loop.
view: undefined,
view: undefined as any,

clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
loadOp: 'clear',
Expand Down Expand Up @@ -549,6 +551,8 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
);

const commandEncoder = device.createCommandEncoder();
type GPURenderPassColorAttachmentArray =
(GPURenderPassColorAttachment | null)[];
{
// Write position, normal, albedo etc. data to gBuffers
const gBufferPass = commandEncoder.beginRenderPass(
Expand All @@ -575,9 +579,11 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
// Left: depth
// Middle: normal
// Right: albedo (use uv to mimic a checkerboard texture)
textureQuadPassDescriptor.colorAttachments[0].view = context
.getCurrentTexture()
.createView();
const textureQuadAttachment = (
textureQuadPassDescriptor.colorAttachments as GPURenderPassColorAttachmentArray
)[0];
assert(textureQuadAttachment, 'textureQuadAttachment is null');
textureQuadAttachment.view = context.getCurrentTexture().createView();
const debugViewPass = commandEncoder.beginRenderPass(
textureQuadPassDescriptor
);
Expand All @@ -587,9 +593,11 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
debugViewPass.end();
} else {
// Deferred rendering
textureQuadPassDescriptor.colorAttachments[0].view = context
.getCurrentTexture()
.createView();
const textureQuadAttachment = (
textureQuadPassDescriptor.colorAttachments as GPURenderPassColorAttachmentArray
)[0];
assert(textureQuadAttachment, 'textureQuadAttachment is null');
textureQuadAttachment.view = context.getCurrentTexture().createView();
const deferredRenderingPass = commandEncoder.beginRenderPass(
textureQuadPassDescriptor
);
Expand Down
14 changes: 10 additions & 4 deletions src/sample/fractalCube/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { mat4, vec3 } from 'wgpu-matrix';
import { makeSample, SampleInit } from '../../components/SampleLayout';
import { assert, makeSample, SampleInit } from '../../components/SampleLayout';

import {
cubeVertexArray,
Expand All @@ -14,6 +14,7 @@ import sampleSelfWGSL from './sampleSelf.frag.wgsl';

const init: SampleInit = async ({ canvas, pageState }) => {
const adapter = await navigator.gpu.requestAdapter();
assert(adapter, 'Unable to find a suitable GPU adapter.');
const device = await adapter.requestDevice();

if (!pageState.active) return;
Expand Down Expand Up @@ -148,7 +149,7 @@ const init: SampleInit = async ({ canvas, pageState }) => {
const renderPassDescriptor: GPURenderPassDescriptor = {
colorAttachments: [
{
view: undefined, // Assigned later
view: undefined as any, // Assigned later

clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },
loadOp: 'clear',
Expand Down Expand Up @@ -203,8 +204,13 @@ const init: SampleInit = async ({ canvas, pageState }) => {
);

const swapChainTexture = context.getCurrentTexture();
// prettier-ignore
renderPassDescriptor.colorAttachments[0].view = swapChainTexture.createView();
type GPURenderPassColorAttachmentArray =
(GPURenderPassColorAttachment | null)[];
const renderPassAttachment = (
renderPassDescriptor.colorAttachments as GPURenderPassColorAttachmentArray
)[0];
assert(renderPassAttachment, 'renderPassAttachment is null');
renderPassAttachment.view = swapChainTexture.createView();

const commandEncoder = device.createCommandEncoder();
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
Expand Down
7 changes: 5 additions & 2 deletions src/sample/gameOfLife/main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { makeSample, SampleInit } from '../../components/SampleLayout';
import { assert, makeSample, SampleInit } from '../../components/SampleLayout';
import computeWGSL from './compute.wgsl';
import vertWGSL from './vert.wgsl';
import fragWGSL from './frag.wgsl';

const init: SampleInit = async ({ canvas, pageState, gui }) => {
const adapter = await navigator.gpu.requestAdapter();
assert(adapter, 'Unable to find a suitable GPU adapter.');
const device = await adapter.requestDevice();
if (!pageState.active) return;
const context = canvas.getContext('webgpu') as GPUCanvasContext;
Expand Down Expand Up @@ -103,6 +104,7 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
};

function addGUI() {
assert(gui, 'gui is null');
gui.add(GameOptions, 'timestep', 1, 60, 1);
gui.add(GameOptions, 'width', 16, 1024, 16).onFinishChange(resetGameData);
gui.add(GameOptions, 'height', 16, 1024, 16).onFinishChange(resetGameData);
Expand All @@ -115,7 +117,8 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
loopTimes = 0,
buffer0: GPUBuffer,
buffer1: GPUBuffer;
let render: () => void;
// eslint-disable-next-line @typescript-eslint/no-empty-function
let render: () => void = () => {};
function resetGameData() {
// compute pipeline
const computePipeline = device.createComputePipeline({
Expand Down
3 changes: 2 additions & 1 deletion src/sample/helloTriangle/main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { makeSample, SampleInit } from '../../components/SampleLayout';
import { assert, makeSample, SampleInit } from '../../components/SampleLayout';

import triangleVertWGSL from '../../shaders/triangle.vert.wgsl';
import redFragWGSL from '../../shaders/red.frag.wgsl';

const init: SampleInit = async ({ canvas, pageState }) => {
const adapter = await navigator.gpu.requestAdapter();
assert(adapter, 'Unable to find a suitable GPU adapter.');
const device = await adapter.requestDevice();

if (!pageState.active) return;
Expand Down
3 changes: 2 additions & 1 deletion src/sample/helloTriangleMSAA/main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { makeSample, SampleInit } from '../../components/SampleLayout';
import { assert, makeSample, SampleInit } from '../../components/SampleLayout';

import triangleVertWGSL from '../../shaders/triangle.vert.wgsl';
import redFragWGSL from '../../shaders/red.frag.wgsl';

const init: SampleInit = async ({ canvas, pageState }) => {
const adapter = await navigator.gpu.requestAdapter();
assert(adapter, 'Unable to find a suitable GPU adapter.');
const device = await adapter.requestDevice();

if (!pageState.active) return;
Expand Down
4 changes: 3 additions & 1 deletion src/sample/imageBlur/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { makeSample, SampleInit } from '../../components/SampleLayout';
import { assert, makeSample, SampleInit } from '../../components/SampleLayout';

import blurWGSL from './blur.wgsl';
import fullscreenTexturedQuadWGSL from '../../shaders/fullscreenTexturedQuad.wgsl';
Expand All @@ -9,6 +9,7 @@ const batch = [4, 4];

const init: SampleInit = async ({ canvas, pageState, gui }) => {
const adapter = await navigator.gpu.requestAdapter();
assert(adapter, 'Unable to find a suitable GPU adapter.');
const device = await adapter.requestDevice();

if (!pageState.active) return;
Expand Down Expand Up @@ -229,6 +230,7 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
new Uint32Array([settings.filterSize, blockDim])
);
};
assert(gui, 'gui is null');
gui.add(settings, 'filterSize', 1, 33).step(2).onChange(updateSettings);
gui.add(settings, 'iterations', 1, 10).step(1);

Expand Down
18 changes: 13 additions & 5 deletions src/sample/instancedCube/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { mat4, vec3 } from 'wgpu-matrix';
import { makeSample, SampleInit } from '../../components/SampleLayout';
import { assert, makeSample, SampleInit } from '../../components/SampleLayout';

import {
cubeVertexArray,
Expand All @@ -14,6 +14,7 @@ import vertexPositionColorWGSL from '../../shaders/vertexPositionColor.frag.wgsl

const init: SampleInit = async ({ canvas, pageState }) => {
const adapter = await navigator.gpu.requestAdapter();
assert(adapter, 'Unable to find a suitable GPU adapter.');
const device = await adapter.requestDevice();

if (!pageState.active) return;
Expand Down Expand Up @@ -193,7 +194,7 @@ const init: SampleInit = async ({ canvas, pageState }) => {
const renderPassDescriptor: GPURenderPassDescriptor = {
colorAttachments: [
{
view: undefined, // Assigned later
view: undefined as any, // Assigned later

clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },
loadOp: 'clear',
Expand Down Expand Up @@ -223,9 +224,16 @@ const init: SampleInit = async ({ canvas, pageState }) => {
mvpMatricesData.byteLength
);

renderPassDescriptor.colorAttachments[0].view = context
.getCurrentTexture()
.createView();
type GPURenderPassColorAttachmentArray =
(GPURenderPassColorAttachment | null)[];

const attachment = (
renderPassDescriptor.colorAttachments as GPURenderPassColorAttachmentArray
)[0];

assert(attachment, 'attachment is null');

attachment.view = context.getCurrentTexture().createView();

const commandEncoder = device.createCommandEncoder();
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
Expand Down
21 changes: 15 additions & 6 deletions src/sample/particles/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { mat4, vec3 } from 'wgpu-matrix';
import { makeSample, SampleInit } from '../../components/SampleLayout';
import { assert, makeSample, SampleInit } from '../../components/SampleLayout';

import particleWGSL from './particle.wgsl';
import probabilityMapWGSL from './probabilityMap.wgsl';
Expand All @@ -17,6 +17,7 @@ const particleInstanceByteSize =

const init: SampleInit = async ({ canvas, pageState, gui }) => {
const adapter = await navigator.gpu.requestAdapter();
assert(adapter, 'Unable to find a suitable GPU adapter.');
const device = await adapter.requestDevice();

if (!pageState.active) return;
Expand Down Expand Up @@ -147,7 +148,7 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
const renderPassDescriptor: GPURenderPassDescriptor = {
colorAttachments: [
{
view: undefined, // Assigned later
view: undefined as any, // Assigned later
clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
loadOp: 'clear',
storeOp: 'store',
Expand Down Expand Up @@ -332,8 +333,9 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
});

assert(gui, 'gui is null');
Object.keys(simulationParams).forEach((k) => {
gui.add(simulationParams, k);
gui.add(simulationParams, k as 'simulate' | 'deltaTime');
});

const computePipeline = device.createComputePipeline({
Expand Down Expand Up @@ -418,9 +420,16 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
0, // padding
])
);
const swapChainTexture = context.getCurrentTexture();
// prettier-ignore
renderPassDescriptor.colorAttachments[0].view = swapChainTexture.createView();
type GPURenderPassColorAttachmentArray =
(GPURenderPassColorAttachment | null)[];

const attachment = (
renderPassDescriptor.colorAttachments as GPURenderPassColorAttachmentArray
)[0];

assert(attachment, 'attachment is null');

attachment.view = context.getCurrentTexture().createView();

const commandEncoder = device.createCommandEncoder();
{
Expand Down
Loading