| <script src="../../resources/js-test.js"></script> | |
| <script> | |
| jsTestIsAsync = true; | |
| // Integer texels, so that what comes back can be compared exactly. | |
| const shaderCode = ` | |
| @group(0) @binding(0) var sourceTexture: texture_2d<u32>; | |
| @group(0) @binding(1) var<storage, read_write> result: array<u32, 4>; | |
| @compute @workgroup_size(1) | |
| fn main() | |
| { | |
| let texel = textureLoad(sourceTexture, vec2u(0, 0), 0); | |
| result[0] = texel.r; | |
| result[1] = texel.g; | |
| result[2] = texel.b; | |
| result[3] = texel.a; | |
| } | |
| `; | |
| onload = async () => { | |
| const adapter = await navigator.gpu.requestAdapter({}); | |
| const device = await adapter.requestDevice({ requiredFeatures: ['texture-component-swizzle'] }); | |
| const texture = device.createTexture({ | |
| size: [1, 1], | |
| format: 'rgba8uint', | |
| usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST, | |
| }); | |
| device.queue.writeTexture({ texture }, new Uint8Array([11, 22, 33, 44]), { bytesPerRow: 4 }, [1, 1]); | |
| const bindGroupLayout = device.createBindGroupLayout({ | |
| entries: [ | |
| { binding: 0, visibility: GPUShaderStage.COMPUTE, texture: { sampleType: 'uint' } }, | |
| { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'storage' } }, | |
| ], | |
| }); | |
| const pipeline = device.createComputePipeline({ | |
| layout: device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout] }), | |
| compute: { module: device.createShaderModule({ code: shaderCode }) }, | |
| }); | |
| async function readThroughSwizzle(swizzle) | |
| { | |
| const storageBuffer = device.createBuffer({ size: 16, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC }); | |
| const readbackBuffer = device.createBuffer({ size: 16, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ }); | |
| const bindGroup = device.createBindGroup({ | |
| layout: bindGroupLayout, | |
| entries: [ | |
| { binding: 0, resource: texture.createView({ swizzle }) }, | |
| { binding: 1, resource: { buffer: storageBuffer } }, | |
| ], | |
| }); | |
| const commandEncoder = device.createCommandEncoder(); | |
| const computePass = commandEncoder.beginComputePass({}); | |
| computePass.setPipeline(pipeline); | |
| computePass.setBindGroup(0, bindGroup); | |
| computePass.dispatchWorkgroups(1); | |
| computePass.end(); | |
| commandEncoder.copyBufferToBuffer(storageBuffer, 0, readbackBuffer, 0, 16); | |
| device.queue.submit([commandEncoder.finish()]); | |
| await readbackBuffer.mapAsync(GPUMapMode.READ); | |
| const values = [...new Uint32Array(readbackBuffer.getMappedRange())].toString(); | |
| readbackBuffer.unmap(); | |
| return values; | |
| } | |
| globalThis.identity = await readThroughSwizzle('rgba'); | |
| shouldBeEqualToString('identity', '11,22,33,44'); | |
| globalThis.reversed = await readThroughSwizzle('abgr'); | |
| shouldBeEqualToString('reversed', '44,33,22,11'); | |
| globalThis.broadcast = await readThroughSwizzle('gggg'); | |
| shouldBeEqualToString('broadcast', '22,22,22,22'); | |
| // '0' and '1' force the channel rather than selecting one. | |
| globalThis.constants = await readThroughSwizzle('01ab'); | |
| shouldBeEqualToString('constants', '0,1,44,33'); | |
| finishJSTest(); | |
| }; | |
| </script> |