Last active
February 15, 2024 00:40
-
-
Save greggman/c554126635f9dc6f8f846a336f86f359 to your computer and use it in GitHub Desktop.
WebGPU CTS fragment builtins multisampling sample_index triangles
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html, body { | |
color: white; | |
background-color: black; | |
} | |
canvas { margin: 1em; } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<canvas></canvas> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const samplePositionsToFragmentPositions = points => points.map(([x, y]) => [x, 16 - y]); | |
// These are sample positions based on a 16x16 grid with 0,0 at the top left. | |
// For example 8,8 would be a fragment coordinate of 0.5, 0.5 | |
// Based on: https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_standard_multisample_quality_levels | |
const kMultisamplingTables = new Map/*<number, readonly (readonly number[])[]>*/([ | |
[1, samplePositionsToFragmentPositions([[8, 8]])], | |
[ | |
2, | |
samplePositionsToFragmentPositions([ | |
[4, 4], | |
[12, 12], | |
]), | |
], | |
[ | |
4, | |
samplePositionsToFragmentPositions([ | |
[6, 2], | |
[14, 6], | |
[2, 10], | |
[10, 14], | |
]), | |
], | |
[ | |
8, | |
samplePositionsToFragmentPositions([ | |
[9, 5], | |
[7, 11], | |
[13, 9], | |
[5, 3], | |
[3, 13], | |
[1, 7], | |
[11, 15], | |
[15, 1], | |
]), | |
], | |
[ | |
16, | |
samplePositionsToFragmentPositions([ | |
[9, 9], | |
[7, 5], | |
[5, 10], | |
[12, 7], | |
[3, 6], | |
[10, 13], | |
[13, 11], | |
[11, 3], | |
[6, 14], | |
[8, 1], | |
[4, 2], | |
[2, 12], | |
[0, 8], | |
[15, 4], | |
[14, 15], | |
[1, 0], | |
]), | |
], | |
]); | |
/** | |
* For a given sampleCount returns an array of 2d fragment offsets | |
* where each offset is between 0 and 1. | |
*/ | |
function getMultisampleFragmentOffsets(sampleCount/*: number*/) { | |
return kMultisamplingTables.get(sampleCount); | |
} | |
const canvas = document.querySelector('canvas'); | |
const ctx = canvas.getContext('2d'); | |
const pixelSize = 64; | |
const sampleCount = 4; | |
const fragmentOffsets = getMultisampleFragmentOffsets(sampleCount); | |
const centerX = 5; | |
const centerY = 5; | |
/* | |
[ | |
[1, 1], | |
[2, 1], | |
[3, 1], | |
[-1, 1], | |
[-3, 1], | |
[1, 2], | |
[2, 2], | |
[3, 2], | |
[-2, 2], | |
[3, 3], | |
[-2, 3], | |
[-3, 3], | |
[1, -1], | |
[-1, 3], | |
[-1, 1], | |
[3, -1], | |
[-1, -1], | |
[-2, -1], | |
[-3, -1], | |
[2, -2], | |
[-1, -2], | |
[-2, -2], | |
[-3, -2], | |
[1, -3], | |
[2, -3], | |
[3, -3], | |
[-3, -3] | |
].forEach(([x, y]) => { | |
render(x, y); | |
}); | |
*/ | |
[1, 2, 3, -1, -2, -3].forEach(y => { | |
[1, 2, 3, -1, -2, -3].forEach(x => { | |
render(x, y); | |
}); | |
}); | |
function render(x, y) { | |
log(`${x}, ${y}`); | |
const canvas = document.createElement('canvas'); | |
canvas.width = pixelSize * 10; | |
canvas.height = pixelSize * 10; | |
const ctx = canvas.getContext('2d'); | |
document.body.appendChild(canvas); | |
const { width, height } = canvas; | |
for (let x = 0; x < width; x += pixelSize / 16) { | |
ctx.fillStyle = x % pixelSize === 0 ? '#888': '#444'; | |
ctx.fillRect(x, 0, 1, height); | |
} | |
for (let y = 0; y < height; y += pixelSize / 16) { | |
ctx.fillStyle = y % pixelSize === 0 ? '#888': '#444'; | |
ctx.fillRect(0, y, width, 1); | |
} | |
ctx.save(); | |
ctx.translate(pixelSize * centerX, pixelSize * centerY); | |
ctx.fillStyle = '#FFF'; | |
ctx.fillRect(-pixelSize * 2, -pixelSize * 2, pixelSize * 4, 1); | |
ctx.fillRect(-pixelSize * 2, pixelSize * 2, pixelSize * 4, 1); | |
ctx.fillRect(-pixelSize * 2, -pixelSize * 2, 1, pixelSize * 4); | |
ctx.fillRect( pixelSize * 2, -pixelSize * 2, 1, pixelSize * 4); | |
ctx.restore(); | |
for (let y = 0; y < height; y += pixelSize) { | |
for (let x = 0; x < width; x += pixelSize) { | |
ctx.save(); | |
ctx.translate(x, y); | |
ctx.scale(pixelSize / 16, pixelSize / 16); | |
// draw sample points | |
fragmentOffsets.forEach((offset, i) => { | |
ctx.beginPath(); | |
ctx.arc(...offset, 0.5, 0, Math.PI * 2); | |
ctx.fillStyle = 'red'; | |
ctx.fill(); | |
ctx.save(); | |
ctx.translate(...offset) | |
ctx.scale(0.3, 0.3); | |
ctx.fillStyle = '#ccc'; | |
ctx.fillText(i, 2, -2); | |
ctx.restore(); | |
}); | |
// draw center | |
ctx.beginPath(); | |
ctx.arc(8, 8, 0.5, 0, Math.PI * 2); | |
ctx.fillStyle = '#0FF'; | |
ctx.fill(); | |
ctx.restore(); | |
} | |
} | |
const s = 1; | |
ctx.save(); | |
ctx.translate(pixelSize * centerX, pixelSize * centerY); | |
ctx.fillStyle = '#FFF'; | |
ctx.fillRect(-pixelSize * 2, -pixelSize * 2, pixelSize * 4, s); | |
ctx.fillRect(-pixelSize * 2, pixelSize * 2, pixelSize * 4, s); | |
ctx.fillRect(-pixelSize * 2, -pixelSize * 2, s, pixelSize * 4); | |
ctx.fillRect( pixelSize * 2, -pixelSize * 2, s, pixelSize * 4); | |
ctx.restore(); | |
const clipSpacePoints = [ | |
[ x + 0.2, -y, 0, 1], | |
[-x + 0.2, y, 0, 1], | |
[ x + 0.2, y, 0, 1], | |
]; | |
ctx.save(); | |
ctx.translate(pixelSize * centerX, pixelSize * centerY); | |
ctx.scale(pixelSize * 2, -pixelSize * 2); | |
ctx.lineWidth = 2 / (pixelSize * 4) * s; | |
ctx.fillStyle = 'rgba(0,255,0,0.02)'; | |
ctx.strokeStyle = '#ff0'; | |
for (let vNdx = 0; vNdx < clipSpacePoints.length; vNdx += 3) { | |
ctx.beginPath(); | |
for (let i = 0; i < 3; ++i) { | |
ctx.lineTo(...clipSpacePoints[vNdx + i].slice(0, 2)); | |
} | |
ctx.closePath(); | |
ctx.fill(); | |
ctx.stroke(); | |
} | |
ctx.restore(); | |
ctx.fillStyle = '#0ff'; | |
ctx.font = '20px monospace'; | |
ctx.fillText(`${x}, ${y}`, 20, 20); | |
} | |
function log(...args) { | |
const elem = document.createElement('pre'); | |
elem.textContent = args.join(' '); | |
document.body.appendChild(elem); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"name":"WebGPU CTS fragment builtins multisampling sample_index triangles","settings":{},"filenames":["index.html","index.css","index.js"]} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment