blob: 3f1b48031babade19cd5c7fea4fce8719b30c1e4 [file]
<script>
globalThis.testRunner?.waitUntilDone();
const log = console.debug;
const width = 3;
const height = 3;
const format = 'bgra8unorm';
function createOffscreenCanvas() {
let canvas = new OffscreenCanvas(width, height);
let context = canvas.getContext('2d');
context.fillStyle = 'red';
context.fillRect(1, 1, 1, 1);
return canvas;
}
function setupCanvas(device) {
let canvas = document.createElement('canvas');
canvas.width = 512;
canvas.height = 512;
document.body.append(canvas);
let context = canvas.getContext('webgpu');
context.configure({device, format, usage: GPUTextureUsage.RENDER_ATTACHMENT});
return context;
}
function createVertexBuffer(device) {
let vertexesF32 = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);
let vertexBuffer = device.createBuffer({size: vertexesF32.byteLength, usage: GPUBufferUsage.VERTEX, mappedAtCreation: true});
new Float32Array(vertexBuffer.getMappedRange()).set(vertexesF32);
vertexBuffer.unmap();
return vertexBuffer;
}
function createTexture(device) {
let texture = device.createTexture({
format, size: [width, height, 1],
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
});
let source = createOffscreenCanvas();
device.queue.copyExternalImageToTexture({source}, {texture}, {width, height});
return texture;
}
onload = async () => {
let adapter = await navigator.gpu.requestAdapter({});
let device = await adapter.requestDevice({requiredLimits: {maxTextureDimension2D: 16384}});
let context = setupCanvas(device);
let texture = createTexture(device);
let vertexBuffer = createVertexBuffer(device);
let code = `
@vertex
fn v(@location(0) position : vec4f) -> @builtin(position) vec4f {
return position;
}
@group(0) @binding(0) var t: texture_2d<f32>;
@group(0) @binding(1) var s: sampler;
@fragment
fn f(@builtin(position) position: vec4f) -> @location(0) vec4f {
return textureSample(t, s, position.xy/512);
}
`;
let bindGroupLayout = device.createBindGroupLayout({
entries: [
{binding: 0, texture: {}, visibility: GPUShaderStage.FRAGMENT},
{binding: 1, sampler: {}, visibility: GPUShaderStage.FRAGMENT},
],
});
let module = device.createShaderModule({code});
let pipeline = device.createRenderPipeline({
layout: device.createPipelineLayout({bindGroupLayouts: [bindGroupLayout]}),
vertex: {
module,
buffers: [{arrayStride: 8, attributes: [{shaderLocation: 0, offset: 0, format: 'float32x2'}]}],
},
fragment: {module, targets: [{format}]},
primitive: {topology: 'triangle-strip'},
});
let sampler0 = device.createSampler({
magFilter: 'linear',
});
globalThis.keep = sampler0;
let textureBindGroup = device.createBindGroup({
layout: bindGroupLayout,
entries: [
{binding: 0, resource: texture.createView()},
{binding: 1, resource: sampler0},
],
});
let frameCount = 0;
let oneFrame = async _ => {
let commandEncoder = device.createCommandEncoder();
let passEncoder = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
clearValue: [0.5, 0.5, 0.5, 1],
loadOp: 'clear', storeOp: 'store',
}],
});
passEncoder.setPipeline(pipeline);
passEncoder.setBindGroup(0, textureBindGroup);
passEncoder.setVertexBuffer(0, vertexBuffer);
passEncoder.draw(4);
passEncoder.end();
device.pushErrorScope('validation');
device.queue.submit([commandEncoder.finish()]);
await device.queue.onSubmittedWorkDone();
let error = await device.popErrorScope();
if (error) {
log(error.message);
} else {
if (++frameCount < 100) {
new ArrayBuffer(2 ** 20);
requestAnimationFrame(oneFrame);
}
}
globalThis.testRunner?.notifyDone();
};
requestAnimationFrame(oneFrame);
};
</script>