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

Organize Sample List #358

Merged
merged 22 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d51dc45
Merge pull request #1 from webgpu/main
cmhhelgeson Oct 18, 2023
766427d
Merge pull request #2 from webgpu/main
cmhhelgeson Oct 27, 2023
415bd67
Merge pull request #3 from webgpu/main
cmhhelgeson Oct 31, 2023
ff38128
Merge pull request #4 from webgpu/main
cmhhelgeson Nov 15, 2023
c4f73a1
Merge branch 'main' of https://github.com/cmhhelgeson/webgpu-samples
cmhhelgeson Nov 30, 2023
c5a9982
Merge pull request #5 from webgpu/main
cmhhelgeson Dec 4, 2023
08d811d
Merge branch 'main' of https://github.com/cmhhelgeson/webgpu-samples
cmhhelgeson Dec 4, 2023
1db2e10
Merge branch 'webgpu:main' into main
cmhhelgeson Feb 21, 2024
ebbb389
Encapsulated sample page link logic into its own component, which wil…
cmhhelgeson Feb 28, 2024
73f26d7
Test
cmhhelgeson Feb 28, 2024
5419898
New sidebar layout
cmhhelgeson Feb 28, 2024
970f069
First draft
cmhhelgeson Feb 28, 2024
12e1770
Sketch dropdown before merging main into this branch
cmhhelgeson Feb 28, 2024
8bfa289
Merge branch 'webgpu:main' into main
cmhhelgeson Feb 28, 2024
1879c54
merge main into sample_organize_branch
cmhhelgeson Feb 28, 2024
f3c618c
Dropdowns complete. Note that dropdowns can easily be removed if they…
cmhhelgeson Feb 28, 2024
bc57254
fix build errors
cmhhelgeson Feb 28, 2024
8a980a8
Implemented most suggested changes, will have further discussions abo…
cmhhelgeson Feb 28, 2024
95334d3
Moved stuffed around, added comments justifying each category
cmhhelgeson Feb 29, 2024
f05a846
Capitalize GPGPU
cmhhelgeson Feb 29, 2024
40ee507
Added more specific comments to gpgpu section
cmhhelgeson Feb 29, 2024
14c55f8
Cambios pequenos
cmhhelgeson Feb 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/components/SampleCategory.module.css
cmhhelgeson marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
@keyframes openTriangle {
from { transform: rotate(0deg); }
to { transform: rotate(180deg); }
}

@keyframes closeTriangle {
from { transform: rotate(180deg); }
to { transform: rotate(0deg); }
}
cmhhelgeson marked this conversation as resolved.
Show resolved Hide resolved

.sampleCategory {
display: flex;
}

.dropdown {
margin-left: 8px;
margin-top: 7px;
margin-bottom: 5px;
}

li.selected a {
cmhhelgeson marked this conversation as resolved.
Show resolved Hide resolved
color: #ff0000;
}
84 changes: 84 additions & 0 deletions src/components/SampleCategory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import styles from './SampleCategory.module.css';

import { NextRouter } from 'next/router';
import Link from 'next/link';
import { PageCategory } from '../pages/samples/[slug]';

type PageType = {
[key: string]: React.ComponentType & { render: { preload: () => void } };
};

type PageComponentType = {
[key: string]: React.ComponentType;
};

interface SampleCategoryProps {
category: PageCategory;
router: NextRouter;
onClickPageLink: () => void;
}

export const SampleCategory = ({
category,
onClickPageLink,
router,
}: SampleCategoryProps) => {
const { title, pages, sampleNames } = category;
return (
<div>
<div className={styles.sampleCategory}>
<h3
style={{
marginTop: '5px',
}}
>
{title}
</h3>
</div>
{sampleNames.map((slug) => {
return (
<SampleLink
key={`samples/${slug}`}
slug={slug}
router={router}
pages={pages}
onClick={() => onClickPageLink()}
/>
);
})}
</div>
);
};

interface SampleLinkProps {
router: NextRouter;
slug: string;
pages: PageComponentType;
onClick: () => void;
}

export const SampleLink = ({
router,
slug,
pages,
onClick,
}: SampleLinkProps) => {
const className =
router.pathname === `/samples/[slug]` && router.query['slug'] === slug
? styles.selected
: undefined;

return (
<li
key={slug}
className={className}
onMouseOver={() => {
(pages as PageType)[slug].render.preload();
}}
>
<Link href={`/samples/${slug}`} onClick={() => onClick()}>
{slug}
</Link>
</li>
);
};
7 changes: 5 additions & 2 deletions src/pages/MainLayout.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
margin-block-end: 16px;
}

.exampleList h3 {
color: rgb(43, 126, 171);
}

.exampleList li {
list-style: none;
padding: 0.3em 0;
Expand All @@ -45,7 +49,6 @@
.panel .panelContents {
display: block;
transition: max-height 0s;
overflow: none;
max-height: 100vh;
}

Expand All @@ -67,12 +70,12 @@
.panel .panelContents {
display: block;
transition: max-height 0.3s ease-out;
overflow: hidden;
max-height: 0px;
}

.panel[data-expanded='false'] .panelContents {
max-height: 0vh;
overflow: hidden;
}

.panel[data-expanded='true'] .panelContents {
Expand Down
56 changes: 21 additions & 35 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,16 @@ import { useMemo, memo, useState } from 'react';
import './styles.css';
import styles from './MainLayout.module.css';

import { pages } from './samples/[slug]';
import { pageCategories } from './samples/[slug]';
import { SampleCategory } from '../components/SampleCategory';

const title = 'WebGPU Samples';

type PageType = {
[key: string]: React.ComponentType & { render: { preload: () => void } };
};

const MainLayout: React.FunctionComponent<AppProps> = ({
Component,
pageProps,
}) => {
const router = useRouter();
const samplesNames = Object.keys(pages);
const [listExpanded, setListExpanded] = useState<boolean>(false);

const ComponentMemo = useMemo(() => {
Expand Down Expand Up @@ -66,36 +62,26 @@ const MainLayout: React.FunctionComponent<AppProps> = ({
Github
</a>
<hr />
<ul className={styles.exampleList}>
{samplesNames.map((slug) => {
const className =
router.pathname === `/samples/[slug]` &&
router.query['slug'] === slug
? styles.selected
: undefined;
return (
<li
key={slug}
className={className}
onMouseOver={() => {
(pages as PageType)[slug].render.preload();
}}
>
<Link
href={`/samples/${slug}`}
onClick={() => {
setListExpanded(false);
}}
>
{slug}
</Link>
</li>
);
})}
</ul>
{pageCategories.map((category) => {
return (
<ul
className={styles.exampleList}
key={`/categories/${category.title}`}
>
<SampleCategory
category={category}
router={router}
onClickPageLink={() => setListExpanded(false)}
/>
</ul>
);
})}
<hr />
<h3>Other Pages</h3>
<ul className={styles.exampleList}>
<h3 style={{ marginBottom: '5px' }}>Other Pages</h3>
<ul
style={{ margin: '0px', paddingBottom: '20px' }}
className={styles.exampleList}
>
<li>
<a
rel="noreferrer"
Expand Down
109 changes: 90 additions & 19 deletions src/pages/samples/[slug].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,55 +13,126 @@ type PageComponentType = {
[key: string]: React.ComponentType;
};

export const pages: PageComponentType = {
// Samples that implement basic rendering functionality using the WebGPU API.
const graphicsBasicsPages: PageComponentType = {
helloTriangle: dynamic(() => import('../../sample/helloTriangle/main')),
helloTriangleMSAA: dynamic(
() => import('../../sample/helloTriangleMSAA/main')
),
resizeCanvas: dynamic(() => import('../../sample/resizeCanvas/main')),
rotatingCube: dynamic(() => import('../../sample/rotatingCube/main')),
twoCubes: dynamic(() => import('../../sample/twoCubes/main')),
texturedCube: dynamic(() => import('../../sample/texturedCube/main')),
instancedCube: dynamic(() => import('../../sample/instancedCube/main')),
fractalCube: dynamic(() => import('../../sample/fractalCube/main')),
cameras: dynamic(() => import('../../sample/cameras/main')),
cubemap: dynamic(() => import('../../sample/cubemap/main')),
computeBoids: dynamic(() => import('../../sample/computeBoids/main')),
animometer: dynamic(() => import('../../sample/animometer/main')),
videoUploading: dynamic(() => import('../../sample/videoUploading/main')),
videoUploadingWebCodecs: dynamic(
() => import('../../sample/videoUploadingWebCodecs/main')
),
};

// Samples that demonstrate functionality specific to WebGPU, or demonstrate the particularities
// of how WebGPU implements a particular feature within its api. For instance, while many of the
// sampler parameters in the 'samplerParameters' sample have direct analogues in other graphics api,
// the primary purpose of 'sampleParameters' is to demonstrate their specific nomenclature and
// functionality within the context of the WebGPU API.
const webGPUFeaturesPages: PageComponentType = {
samplerParameters: dynamic(
() => import('../../sample/samplerParameters/main')
),
imageBlur: dynamic(() => import('../../sample/imageBlur/main')),
shadowMapping: dynamic(() => import('../../sample/shadowMapping/main')),
reversedZ: dynamic(() => import('../../sample/reversedZ/main')),
renderBundles: dynamic(() => import('../../sample/renderBundles/main')),
};

// A selection of samples demonstrating various graphics techniques, utilizing various features
// of the WebGPU API, and often executing render and compute pipelines in tandem to achieve their
// visual results.
cmhhelgeson marked this conversation as resolved.
Show resolved Hide resolved
const graphicsDemoPages: PageComponentType = {
cameras: dynamic(() => import('../../sample/cameras/main')),
normalMap: dynamic(() => import('../../sample/normalMap/main')),
shadowMapping: dynamic(() => import('../../sample/shadowMapping/main')),
deferredRendering: dynamic(
() => import('../../sample/deferredRendering/main')
),
particles: dynamic(() => import('../../sample/particles/main')),
imageBlur: dynamic(() => import('../../sample/imageBlur/main')),
cornell: dynamic(() => import('../../sample/cornell/main')),
gameOfLife: dynamic(() => import('../../sample/gameOfLife/main')),
renderBundles: dynamic(() => import('../../sample/renderBundles/main')),
worker: dynamic(() => import('../../sample/worker/main')),
'A-buffer': dynamic(() => import('../../sample/a-buffer/main')),
bitonicSort: dynamic(() => import('../../sample/bitonicSort/main')),
normalMap: dynamic(() => import('../../sample/normalMap/main')),
skinnedMesh: dynamic(() => import('../../sample/skinnedMesh/main')),
};

// Samples that demonstrate the GPGPU functionality of WebGPU. These samples generally
// provide a visual representation of the result of a compute operation. Accordingly, the rendering
// functionality of these samples exists soley to demonstrate the results of these operations.
// As a general rule of thumb, samples within this category should be of two types:
// 1. Visualizations of compute operations where the rendering is or could just as effectively be
// implemented within canvas2D with minimal changes to the code.
// 2. Visualizations of compute features that are endemic to the domain of machine learning or A.I
// such as 'f16', convolution, backpropogation, etc.
cmhhelgeson marked this conversation as resolved.
Show resolved Hide resolved
const gpuComputeDemoPages: PageComponentType = {
computeBoids: dynamic(() => import('../../sample/computeBoids/main')),
gameOfLife: dynamic(() => import('../../sample/gameOfLife/main')),
bitonicSort: dynamic(() => import('../../sample/bitonicSort/main')),
};

// Samples that demonstrate how to integrate WebGPU and/or WebGPU render operations with other
// functionalities provided by the web platform.
const webPlatformPages: PageComponentType = {
resizeCanvas: dynamic(() => import('../../sample/resizeCanvas/main')),
videoUploading: dynamic(() => import('../../sample/videoUploading/main')),
videoUploadingWebCodecs: dynamic(
() => import('../../sample/videoUploadingWebCodecs/main')
),
worker: dynamic(() => import('../../sample/worker/main')),
};

// Samples whose primary purpose is to benchmark WebGPU performance.
const benchmarkPages: PageComponentType = {
animometer: dynamic(() => import('../../sample/animometer/main')),
};

const pages: PageComponentType = {
...graphicsBasicsPages,
...webGPUFeaturesPages,
...graphicsDemoPages,
...gpuComputeDemoPages,
...webPlatformPages,
...benchmarkPages,
};

export interface PageCategory {
title: string;
pages: PageComponentType;
sampleNames: string[];
}

const createPageCategory = (
title: string,
pages: PageComponentType
): PageCategory => {
return {
title,
pages,
sampleNames: Object.keys(pages),
};
};

export const pageCategories: PageCategory[] = [
createPageCategory('Basic Graphics', graphicsBasicsPages),
createPageCategory('WebGPU Features', webGPUFeaturesPages),
kainino0x marked this conversation as resolved.
Show resolved Hide resolved
createPageCategory('GPGPU Demos', gpuComputeDemoPages),
createPageCategory('Graphics Techniques', graphicsDemoPages),
createPageCategory('Web Platform Demos', webPlatformPages),
cmhhelgeson marked this conversation as resolved.
Show resolved Hide resolved
createPageCategory('Benchmarks', benchmarkPages),
kainino0x marked this conversation as resolved.
Show resolved Hide resolved
];

function Page({ slug }: Props): JSX.Element {
const PageComponent = pages[slug];
return <PageComponent />;
}

export const getStaticPaths: GetStaticPaths<PathParams> = async () => {
const paths = Object.keys(pages).map((p) => ({
params: { slug: p },
}));
return {
paths: Object.keys(pages).map((p) => {
return { params: { slug: p } };
}),
paths,
fallback: false,
};
};
Expand Down
5 changes: 5 additions & 0 deletions src/pages/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ a:hover {
text-decoration: underline;
}

h3 {
margin-bottom: 5px;
margin-top: 5px;
}

main {
position: relative;
flex: 1;
Expand Down
Loading