diff --git a/sample/alphaToCoverage/index.html b/sample/alphaToCoverage/index.html
deleted file mode 100644
index 6cc028d0..00000000
--- a/sample/alphaToCoverage/index.html
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
- webgpu-samples: alphaToCoverage
-
-
-
-
-
-
-
-
diff --git a/sample/alphaToCoverage/main.ts b/sample/alphaToCoverage/main.ts
deleted file mode 100644
index cde25c0a..00000000
--- a/sample/alphaToCoverage/main.ts
+++ /dev/null
@@ -1,264 +0,0 @@
-import { GUI } from 'dat.gui';
-
-import showMultisampleTextureWGSL from './showMultisampleTexture.wgsl';
-import renderWithAlphaToCoverageWGSL from './renderWithAlphaToCoverage.wgsl';
-import { quitIfWebGPUNotAvailable } from '../util';
-
-const canvas = document.querySelector('canvas') as HTMLCanvasElement;
-const adapter = await navigator.gpu?.requestAdapter();
-const device = await adapter?.requestDevice();
-quitIfWebGPUNotAvailable(adapter, device);
-
-//
-// GUI controls
-//
-
-const kInitConfig = {
- sizeLog2: 3,
- showResolvedColor: true,
- color1: 0x0000ff,
- alpha1: 127,
- color2: 0xff0000,
- alpha2: 16,
- pause: false,
-};
-const config = { ...kInitConfig };
-
-const gui = new GUI();
-gui.width = 300;
-{
- const buttons = {
- initial() {
- Object.assign(config, kInitConfig);
- gui.updateDisplay();
- },
- };
-
- const settings = gui.addFolder('Settings');
- settings.open();
- settings.add(config, 'sizeLog2', 0, 8, 1).name('size = 2**');
- settings.add(config, 'showResolvedColor', true);
-
- const draw1Panel = gui.addFolder('Draw 1');
- draw1Panel.open();
- draw1Panel.addColor(config, 'color1').name('color');
- draw1Panel.add(config, 'alpha1', 0, 255).name('alpha');
-
- const draw2Panel = gui.addFolder('Draw 2');
- draw2Panel.open();
- draw2Panel.addColor(config, 'color2').name('color');
- draw2Panel.add(config, 'alpha2', 0, 255).name('alpha');
- draw2Panel.add(config, 'pause', false);
-
- gui.add(buttons, 'initial').name('reset to initial');
-}
-
-//
-// Canvas setup
-//
-
-function updateCanvasSize() {
- const devicePixelRatio = window.devicePixelRatio;
- canvas.width = canvas.clientWidth * devicePixelRatio;
- canvas.height = canvas.clientHeight * devicePixelRatio;
-}
-updateCanvasSize();
-const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
-
-const context = canvas.getContext('webgpu') as GPUCanvasContext;
-context.configure({
- device,
- format: presentationFormat,
-});
-
-//
-// GPU state controlled by the config gui
-//
-
-const bufInstanceColors = device.createBuffer({
- usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.VERTEX,
- size: 8,
-});
-
-let multisampleTexture: GPUTexture, multisampleTextureView: GPUTextureView;
-let resolveTexture: GPUTexture, resolveTextureView: GPUTextureView;
-let lastSize = 0;
-function resetMultisampleTexture() {
- const size = 2 ** config.sizeLog2;
- if (lastSize !== size) {
- if (multisampleTexture) {
- multisampleTexture.destroy();
- }
- multisampleTexture = device.createTexture({
- format: 'rgba8unorm',
- usage:
- GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
- size: [size, size],
- sampleCount: 4,
- });
- multisampleTextureView = multisampleTexture.createView();
-
- if (resolveTexture) {
- resolveTexture.destroy();
- }
- resolveTexture = device.createTexture({
- format: 'rgba8unorm',
- usage:
- GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
- size: [size, size],
- });
- resolveTextureView = resolveTexture.createView();
-
- lastSize = size;
- }
-}
-
-function applyConfig() {
- // Update the colors in the (instance-step-mode) vertex buffer
- const data = new Uint8Array([
- // instance 0 color
- (config.color1 >> 16) & 0xff, // R
- (config.color1 >> 8) & 0xff, // G
- (config.color1 >> 0) & 0xff, // B
- config.alpha1,
- // instance 1 color
- (config.color2 >> 16) & 0xff, // R
- (config.color2 >> 8) & 0xff, // G
- (config.color2 >> 0) & 0xff, // B
- config.alpha2,
- ]);
- device.queue.writeBuffer(bufInstanceColors, 0, data);
-
- resetMultisampleTexture();
-}
-
-//
-// Pipeline to render to a multisampled texture using alpha-to-coverage
-//
-
-const renderWithAlphaToCoverageModule = device.createShaderModule({
- code: renderWithAlphaToCoverageWGSL,
-});
-const renderWithAlphaToCoveragePipeline = device.createRenderPipeline({
- label: 'renderWithAlphaToCoveragePipeline',
- layout: 'auto',
- vertex: {
- module: renderWithAlphaToCoverageModule,
- buffers: [
- {
- stepMode: 'instance',
- arrayStride: 4,
- attributes: [{ shaderLocation: 0, format: 'unorm8x4', offset: 0 }],
- },
- ],
- },
- fragment: {
- module: renderWithAlphaToCoverageModule,
- targets: [{ format: 'rgba8unorm' }],
- },
- multisample: { count: 4, alphaToCoverageEnabled: true },
- primitive: { topology: 'triangle-list' },
-});
-
-//
-// "Debug" view of the actual texture contents
-//
-
-const showMultisampleTextureModule = device.createShaderModule({
- code: showMultisampleTextureWGSL,
-});
-const showMultisampleTexturePipeline = device.createRenderPipeline({
- label: 'showMultisampleTexturePipeline',
- layout: 'auto',
- vertex: { module: showMultisampleTextureModule },
- fragment: {
- module: showMultisampleTextureModule,
- targets: [{ format: presentationFormat }],
- },
- primitive: { topology: 'triangle-list' },
-});
-const showMultisampleTextureBGL =
- showMultisampleTexturePipeline.getBindGroupLayout(0);
-
-function render() {
- applyConfig();
-
- const showMultisampleTextureBG = device.createBindGroup({
- layout: showMultisampleTextureBGL,
- entries: [
- { binding: 0, resource: multisampleTextureView },
- { binding: 1, resource: resolveTextureView },
- ],
- });
-
- const commandEncoder = device.createCommandEncoder();
- // clear resolveTextureView to gray if it won't be used
- if (!config.showResolvedColor) {
- const pass = commandEncoder.beginRenderPass({
- colorAttachments: [
- {
- view: resolveTextureView,
- clearValue: [0.3, 0.3, 0.3, 1],
- loadOp: 'clear',
- storeOp: 'store',
- },
- ],
- });
- pass.end();
- }
- // renderWithAlphaToCoverage pass
- {
- const pass = commandEncoder.beginRenderPass({
- label: 'renderWithAlphaToCoverage pass',
- colorAttachments: [
- {
- view: multisampleTextureView,
- resolveTarget: config.showResolvedColor
- ? resolveTextureView
- : undefined,
- clearValue: [0, 0, 0, 1], // black background
- loadOp: 'clear',
- storeOp: 'store',
- },
- ],
- });
- pass.setPipeline(renderWithAlphaToCoveragePipeline);
- pass.setVertexBuffer(0, bufInstanceColors);
- pass.draw(6, 2);
- pass.end();
- }
- // showMultisampleTexture pass
- {
- const pass = commandEncoder.beginRenderPass({
- label: 'showMultisampleTexture pass',
- colorAttachments: [
- {
- view: context.getCurrentTexture().createView(),
- clearValue: [1, 0, 1, 1], // error color, will be overwritten
- loadOp: 'clear',
- storeOp: 'store',
- },
- ],
- });
- pass.setPipeline(showMultisampleTexturePipeline);
- pass.setBindGroup(0, showMultisampleTextureBG);
- pass.draw(6);
- pass.end();
- }
- device.queue.submit([commandEncoder.finish()]);
-}
-
-function frame() {
- if (!config.pause) {
- // scrub alpha2 over 15 seconds
- let alpha = ((performance.now() / 15000) % 1) * (255 + 20) - 10;
- alpha = Math.max(0, Math.min(alpha, 255));
- config.alpha2 = alpha;
- gui.updateDisplay();
- }
- updateCanvasSize();
- render();
- requestAnimationFrame(frame);
-}
-
-requestAnimationFrame(frame);
diff --git a/sample/alphaToCoverage/meta.ts b/sample/alphaToCoverage/meta.ts
deleted file mode 100644
index 8cb35bc7..00000000
--- a/sample/alphaToCoverage/meta.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-export default {
- name: 'Alpha-to-Coverage',
- description: `
-Alpha-to-coverage is an alternative to alpha testing and alpha blending. See:
-
-
-This sample visualizes how alpha-to-coverage translates alpha values into sample
-coverage on your device. It draws two full-screen quads into a 4-sample
-texture, each with the configured color and alpha value. Then, it visualizes the
-contents of the resulting 4-sample texture: the circles show the 4 samples of
-each texel; the background shows the "resolved" results (average of 4 samples).
-
-The algorithm that converts alpha to a coverage sample mask varies per device.
-This results in different average "blending" proportions between the black
-background, the first draw, and the second draw.
-Device differences include different tile sizes (e.g. 1x1, 2x2, or 4x4),
-"moving" samples (or not) around with in the tile as alpha increases, etc.
-`,
- filename: __DIRNAME__,
- sources: [
- { path: 'main.ts' },
- { path: './renderWithAlphaToCoverage.wgsl' },
- { path: './showMultisampleTexture.wgsl' },
- ],
-};
diff --git a/sample/alphaToCoverage/renderWithAlphaToCoverage.wgsl b/sample/alphaToCoverage/renderWithAlphaToCoverage.wgsl
deleted file mode 100644
index 352f4043..00000000
--- a/sample/alphaToCoverage/renderWithAlphaToCoverage.wgsl
+++ /dev/null
@@ -1,24 +0,0 @@
-struct Varying {
- @builtin(position) pos: vec4f,
- // Color from instance-step-mode vertex buffer
- @location(0) color: vec4f,
-}
-
-@vertex
-fn vmain(
- @builtin(vertex_index) vertex_index: u32,
- @location(0) color: vec4f,
-) -> Varying {
- var square = array(
- vec2f(-1, -1), vec2f(-1, 1), vec2f( 1, -1),
- vec2f( 1, -1), vec2f(-1, 1), vec2f( 1, 1),
- );
-
- return Varying(vec4(square[vertex_index], 0, 1), color);
-}
-
-@fragment
-fn fmain(vary: Varying) -> @location(0) vec4f {
- return vary.color;
-}
-
diff --git a/sample/alphaToCoverage/showMultisampleTexture.wgsl b/sample/alphaToCoverage/showMultisampleTexture.wgsl
deleted file mode 100644
index 99b22a03..00000000
--- a/sample/alphaToCoverage/showMultisampleTexture.wgsl
+++ /dev/null
@@ -1,77 +0,0 @@
-@group(0) @binding(0) var tex: texture_multisampled_2d;
-@group(0) @binding(1) var resolved: texture_2d;
-
-struct Varying {
- @builtin(position) pos: vec4f,
- @location(0) uv: vec2f,
-}
-
-const kMipLevels = 4;
-const baseMipSize: u32 = 16;
-
-const kSquare = array(
- vec2f(0, 0), vec2f(0, 1), vec2f(1, 0),
- vec2f(1, 0), vec2f(0, 1), vec2f(1, 1),
-);
-
-@vertex
-fn vmain(
- @builtin(vertex_index) vertex_index: u32,
-) -> Varying {
-
- let uv = kSquare[vertex_index];
- let pos = vec4(uv * vec2(2, -2) + vec2(-1, 1), 0.0, 1.0);
-
- return Varying(pos, uv);
-}
-
-// Standard sample positions for 4xMSAA (assuming the device conforms to spec)
-const kSampleCount = 4;
-const kSamplePositions: array = array(
- vec2f(0.375, 0.125),
- vec2f(0.875, 0.375),
- vec2f(0.125, 0.625),
- vec2f(0.625, 0.875),
-);
-
-// Compute dimensions for drawing a nice-looking visualization
-const kSampleDistanceFromCloseEdge = 0.125; // from the standard sample positions
-const kGridEdgeHalfWidth = 0.025;
-const kSampleInnerRadius = kSampleDistanceFromCloseEdge - kGridEdgeHalfWidth;
-const kSampleOuterRadius = kSampleDistanceFromCloseEdge + kGridEdgeHalfWidth;
-
-@fragment
-fn fmain(vary: Varying) -> @location(0) vec4f {
- let dim = textureDimensions(tex);
- let dimMax = max(dim.x, dim.y);
-
- let xy = vary.uv * f32(dimMax);
- let xyInt = vec2u(xy);
- let xyFrac = xy % vec2f(1, 1);
-
- // Show the visualization only if the resolution is large enough to see it
- if (dpdx(xy.x) < kGridEdgeHalfWidth * 2) & (dpdy(xy.y) < kGridEdgeHalfWidth * 2) {
- // Check if we're close to a sample; if so, visualize the sample value
- for (var sampleIndex = 0; sampleIndex < kSampleCount; sampleIndex += 1) {
- let distanceFromSample = distance(xyFrac, kSamplePositions[sampleIndex]);
- if distanceFromSample < kSampleInnerRadius {
- // Draw a circle for the sample value
- let val = textureLoad(tex, xyInt, sampleIndex).rgb;
- return vec4f(val, 1);
- } else if distanceFromSample < kSampleOuterRadius {
- // Draw a ring around the circle
- return vec4f(0, 0, 0, 1);
- }
- }
-
- // If close to a grid edge, render the grid
- let distanceToGridEdge = abs((xyFrac + 0.5) % 1 - 0.5);
- if min(distanceToGridEdge.x, distanceToGridEdge.y) < kGridEdgeHalfWidth {
- return vec4f(0, 0, 0, 1);
- }
- }
-
- // Otherwise, show the multisample-resolved result as the background
- let val = textureLoad(resolved, xyInt, /*level*/ 0).rgb;
- return vec4f(val, 1);
-}
diff --git a/sample/alphaToCoverageEmulator/meta.ts b/sample/alphaToCoverageEmulator/meta.ts
new file mode 100644
index 00000000..9972c519
--- /dev/null
+++ b/sample/alphaToCoverageEmulator/meta.ts
@@ -0,0 +1,10 @@
+export default {
+ name: 'Alpha-to-Coverage Inspector/Emulator',
+ description: '',
+ filename: __DIRNAME__,
+ external: {
+ url: 'https://kai.graphics/alpha-to-coverage-emulator/',
+ sourceURL: 'https://github.com/kainino0x/alpha-to-coverage-emulator',
+ },
+ sources: [],
+};
diff --git a/src/main.ts b/src/main.ts
index 1043eb65..6791c882 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -199,7 +199,7 @@ function setSampleIFrame(
sampleContainerElem.innerHTML = '';
if (filename) {
const src = external ? external.url : `${filename}${search}`;
- sampleContainerElem.appendChild(el('iframe', { src }));
+ sampleContainerElem.appendChild(el('iframe', { src, allowfullscreen: '' }));
sampleContainerElem.style.height = sources.length > 0 ? '600px' : '100%';
if (external) {
diff --git a/src/samples.ts b/src/samples.ts
index 8f2c400d..ce2ed1c4 100644
--- a/src/samples.ts
+++ b/src/samples.ts
@@ -1,5 +1,5 @@
import aBuffer from '../sample/a-buffer/meta';
-import alphaToCoverage from '../sample/alphaToCoverage/meta';
+import alphaToCoverageEmulator from '../sample/alphaToCoverageEmulator/meta';
import animometer from '../sample/animometer/meta';
import bitonicSort from '../sample/bitonicSort/meta';
import bundleCulling from '../sample/bundleCulling/meta';
@@ -93,7 +93,6 @@ export const pageCategories: PageCategory[] = [
renderBundles,
occlusionQuery,
samplerParameters,
- alphaToCoverage,
},
},
@@ -161,6 +160,7 @@ export const pageCategories: PageCategory[] = [
clusteredShading,
spookyball,
marchingCubes,
+ alphaToCoverageEmulator,
},
},