blob: d1bf6417eddaa8e796e17959d6d10737c5629e73 [file] [log] [blame]
<!DOCTYPE html>
<meta charset="utf-8">
<title>Blitting Texture To Texture</title>
<meta name="assert" content="Blit operations populate a texture correctly (all mip levels).">
<link rel="match" href="blit-commands-texture-to-texture-expected.html">
<p>Pass if square canvas below shows a green mip chain on a red background.</p>
<canvas width="512" height="512"></canvas>
<body>
<script src="js/webgpu-functions.js"></script>
<script>
if (window.testRunner)
testRunner.waitUntilDone();
async function loadTextureFromCanvas2d(device, canvas2d) {
const textureSize = {
width: canvas2d.width,
height: canvas2d.height,
depth: 2
};
// Mipmap count
let maxResolution = Math.max(canvas2d.width, canvas2d.height);
let mipLevelCount = Math.ceil(Math.log2(maxResolution));
if (mipLevelCount < 1) mipLevelCount = 1;
const textureDescriptor = {
size: textureSize,
mipLevelCount: mipLevelCount,
sampleCount: 1,
dimension: "2d",
format: "rgba8unorm",
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST | GPUTextureUsage.SAMPLED
};
// Create texture and also add the descriptor
const texture = device.createTexture(textureDescriptor);
textureSize.depth = 1;
texture.descriptor = textureDescriptor;
// Texture data
const context2d = canvas2d.getContext('2d');
const imageData = context2d.getImageData(0, 0, canvas2d.width, canvas2d.height);
const textureDataBufferDescriptor = {
size: imageData.data.length,
usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.MAP_WRITE
};
const textureDataBuffer = device.createBuffer(textureDataBufferDescriptor);
const textureArrayBuffer = await textureDataBuffer.mapWriteAsync();
const textureWriteArray = new Uint8Array(textureArrayBuffer);
textureWriteArray.set(imageData.data);
textureDataBuffer.unmap();
const dataCopyView = {
buffer: textureDataBuffer,
offset: 0,
rowPitch: canvas2d.width * 4,
imageHeight: canvas2d.width * canvas2d.height * 4
};
const textureCopyView = {
texture: texture,
mipLevel: 0,
arrayLayer: 0,
origin: { x: 0, y: 0, z: 0 }
};
const blitCommandEncoder = device.createCommandEncoder();
blitCommandEncoder.copyBufferToTexture(dataCopyView, textureCopyView, textureSize);
device.getQueue().submit([blitCommandEncoder.finish()]);
return texture;
}
async function test(device) {
const canvas2d = await document.querySelector("canvas");
const context2d = canvas2d.getContext('2d');
// textureA (layer 0, mip 0): Green
context2d.fillStyle = 'rgb(0, 255, 0)';
context2d.fillRect(0, 0, canvas2d.width, canvas2d.height);
const textureA = await loadTextureFromCanvas2d(device, canvas2d);
// textureB (layer 0, mip 0): Red
context2d.fillStyle = 'rgb(255, 0, 0)';
context2d.fillRect(0, 0, canvas2d.width, canvas2d.height);
const textureB = await loadTextureFromCanvas2d(device, canvas2d);
// Clean canvas to blue
context2d.fillStyle = 'rgb(0, 0, 255)';
context2d.fillRect(0, 0, canvas2d.width, canvas2d.height);
// Test copyTextureToTexture
let size = Object.assign({}, textureA.descriptor.size);
let blitCommandEncoder = device.createCommandEncoder();
for (var i = 1; i < textureA.descriptor.mipLevelCount; ++i) {
size.width = Math.max(Math.floor(size.width / 2), 1);
size.height = Math.max(Math.floor(size.height / 2), 1);
let srcTextureCopyView = {
texture: textureA,
mipLevel: 0,
arrayLayer: 0,
origin: { x: 0, y: 0, z: 0 }
};
let dstTextureCopyView = {
texture: textureA,
mipLevel: i,
arrayLayer: 1,
origin: { x: 0, y: 0, z: 0 }
};
// Populate textureA (layer 1, mip i)
blitCommandEncoder.copyTextureToTexture(srcTextureCopyView, dstTextureCopyView, size);
srcTextureCopyView = {
texture: textureA,
mipLevel: i,
arrayLayer: 1,
origin: { x: 0, y: 0, z: 0 }
};
dstTextureCopyView = {
texture: textureB,
mipLevel: 0,
arrayLayer: 0,
origin: { x: 0, y: size.height, z: 0 }
};
// Populate textureB (layer 0, mip 0) with textureA (layer 1, mip i)
blitCommandEncoder.copyTextureToTexture(srcTextureCopyView, dstTextureCopyView, size);
}
// Render textureB into canvas2d
const imageDataLengthInBytes = canvas2d.width * canvas2d.height * 4;
const bufferDescriptor = {
size: imageDataLengthInBytes,
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
};
const bufferA = device.createBuffer(bufferDescriptor);
const bufferCopyView = {
buffer: bufferA,
rowPitch: canvas2d.width * 4,
imageHeight: canvas2d.width * canvas2d.height * 4
};
const textureCopyView = {
texture: textureB
};
blitCommandEncoder.copyTextureToBuffer(textureCopyView, bufferCopyView, textureA.descriptor.size);
device.getQueue().submit([blitCommandEncoder.finish()]);
const ab = await bufferA.mapReadAsync()
const array = new Uint8ClampedArray(ab);
const resultImageData = new ImageData(array, canvas2d.width, canvas2d.height);
context2d.putImageData(resultImageData, 0, 0);
bufferA.destroy();
}
getBasicDevice().then(function(device) {
test(device).then(function() {
if (window.testRunner)
testRunner.notifyDone();
}, function(e) {
if (window.testRunner)
testRunner.notifyDone();
});
}, function() {
const canvas2d = document.querySelector("canvas");
drawGreenMipChainOnRedBackgroundInSoftware(canvas2d);
if (window.testRunner)
testRunner.notifyDone();
});
</script>
</body>