[WHLSL] Educate the property resolver about IndexExpressions
[WebKit-https.git] / LayoutTests / webgpu / texture-triangle-strip.html
1 <!DOCTYPE html>
2 <meta charset="utf-8">
3 <title>WebGPU Hello Triangles</title>
4 <meta name="assert" content="WebGPU correctly renders a green canvas.">
5 <link rel="match" href="vertex-buffer-triangle-strip-expected.html">
6 <p>Pass if square canvas below is a 4 by 4 blue/green checkerboard.</p>
7 <canvas width="400" height="400"></canvas>
8 <script src="js/webgpu-functions.js"></script>
9 <script>
10 if (window.testRunner)
11     testRunner.waitUntilDone();
12
13 const positionBufferIndex = 0;
14 const texCoordsBufferIndex = 1;
15 const positionAttributeNum = 0;
16 const texCoordsAttributeNum = 1;
17 const bindGroupIndex = 0;
18 const textureBindingNum = 0;
19 const samplerBindingNum = 1;
20
21 const shaderCode = `
22 #include <metal_stdlib>
23     
24 using namespace metal;
25
26 struct VertexIn
27 {
28     float4 position [[attribute(${positionAttributeNum})]];
29     float2 texCoords [[attribute(${texCoordsAttributeNum})]];
30 };
31
32 struct VertexOut
33 {
34     float4 position [[position]];
35     float2 texCoords;
36 };
37
38 vertex VertexOut vertex_main(VertexIn vertexIn [[stage_in]])
39 {
40     VertexOut vOut;
41     vOut.position = vertexIn.position;
42     vOut.texCoords = vertexIn.texCoords;
43     return vOut;
44 }
45
46 struct TextureSampler
47 {
48     texture2d<float> t [[id(${textureBindingNum})]];
49     sampler s [[id(${samplerBindingNum})]];
50 };
51
52 fragment float4 fragment_main(VertexOut v [[stage_in]], const device TextureSampler& args [[buffer(${bindGroupIndex})]])
53 {
54     return args.t.sample(args.s, v.texCoords);
55 }
56 `
57
58 function createVertexInputDescriptor() {
59     var bufferDescriptors = [];
60     bufferDescriptors[positionBufferIndex] = {
61         stride: 4 * 4,
62         attributeSet: [{
63             format: "float4",
64             shaderLocation: positionAttributeNum
65         }]
66     };
67     bufferDescriptors[texCoordsBufferIndex] = {
68         stride: 4 * 2,
69         attributeSet: [{
70             format: "float2",
71             shaderLocation: texCoordsAttributeNum
72         }]
73     };
74
75     return { vertexBuffers: bufferDescriptors };
76 }
77
78 async function test() {
79     const device = await getBasicDevice();
80     const canvas = document.querySelector("canvas");
81     const swapChain = createBasicSwapChain(canvas, device);
82     // FIXME: Replace with non-MSL shaders.
83     const shaderModule = device.createShaderModule({ code: shaderCode });
84
85     const positionArray = new Float32Array([
86         // float4 xyzw
87         -1, 1, 0, 1,
88         -1, -1, 0, 1,
89         1, 1, 0, 1, 
90         1, -1, 0, 1
91     ]);
92     const positionBuffer = createBufferWithData(device, { size: positionArray.byteLength, usage: GPUBufferUsage.VERTEX }, positionArray.buffer);
93
94     const texCoordsArray = new Float32Array([
95         // float2 texCoords
96         0, 0,
97         0, 1,
98         1, 0,
99         1, 1
100     ]);
101     const textureCoordBuffer = createBufferWithData(device, { size: texCoordsArray.byteLength, usage: GPUBufferUsage.VERTEX }, texCoordsArray.buffer);
102
103     const vertexInputDescriptor = createVertexInputDescriptor();
104
105     // Load texture image
106     const image = new Image();
107     const imageLoadPromise = new Promise(resolve => { 
108         image.onload = () => resolve(); 
109         image.src = "resources/blue-checkered.png";
110     });
111     await Promise.resolve(imageLoadPromise);
112
113     // Convert image to data and fill GPUBuffer
114     const canvas2d = document.createElement("canvas");
115     canvas2d.width = image.width;
116     canvas2d.height = image.height;
117     const context2d = canvas2d.getContext("2d");
118     context2d.drawImage(image, 0, 0);
119     const imageData = context2d.getImageData(0, 0, image.width, image.height);
120
121     const textureBufferDescriptor = {
122         size: imageData.data.length,
123         usage: GPUBufferUsage.TRANSFER_SRC
124     };
125     const textureBuffer = createBufferWithData(device, textureBufferDescriptor, imageData.data.buffer);
126
127     // Create GPUTexture
128     const textureSize = {
129         width: image.width,
130         height: image.height,
131         depth: 1
132     };
133
134     const textureDescriptor = {
135         size: { width: image.width, height: image.height, depth: 1 },
136         format: "rgba8unorm",
137         usage: GPUTextureUsage.TRANSFER_DST | GPUTextureUsage.SAMPLED
138     };
139     const texture = device.createTexture(textureDescriptor);
140
141     // Bind texture and a sampler to pipeline
142     const textureLayoutBinding = { 
143         binding: textureBindingNum, 
144         visibility: GPUShaderStageBit.FRAGMENT, 
145         type: "sampled-texture" 
146     };
147     const samplerLayoutBinding = {
148         binding: samplerBindingNum,
149         visibility: GPUShaderStageBit.FRAGMENT,
150         type: "sampler"
151     };
152
153     const bindGroupLayoutDescriptor = {
154         bindings: [textureLayoutBinding, samplerLayoutBinding]
155     };
156     bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor);
157     const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout] });
158
159     const textureBinding = { 
160         binding: textureBindingNum, 
161         resource: texture.createDefaultView() 
162     };
163     const samplerBinding = {
164         binding: samplerBindingNum,
165         resource: device.createSampler({ minFilter: "nearest", magFilter: "nearest" })
166     };
167
168     const bindGroupDescriptor = {
169         layout: bindGroupLayout,
170         bindings: [textureBinding, samplerBinding]
171     };
172     const bindGroup = device.createBindGroup(bindGroupDescriptor);
173
174     // Pipeline and render
175     const pipeline = createBasicPipeline(shaderModule, device, null, pipelineLayout, vertexInputDescriptor);
176     const commandEncoder = device.createCommandEncoder();
177
178     const bufferCopyView = {
179         buffer: textureBuffer,
180         rowPitch: image.width * 4,
181         imageHeight: 0
182     };
183     const textureCopyView = { texture: texture };
184     commandEncoder.copyBufferToTexture(bufferCopyView, textureCopyView, textureSize);
185     const passEncoder = beginBasicRenderPass(swapChain, commandEncoder);
186     passEncoder.setPipeline(pipeline);
187     passEncoder.setBindGroup(bindGroupIndex, bindGroup);
188     passEncoder.setVertexBuffers(positionBufferIndex, [positionBuffer, textureCoordBuffer], [0, 0]);
189     passEncoder.draw(4, 1, 0, 0);
190     passEncoder.endPass();
191
192     const queue = device.getQueue();
193     queue.submit([commandEncoder.finish()]);
194     positionBuffer.destroy();
195     textureCoordBuffer.destroy();
196     texture.destroy();
197 }
198
199 test().then(function() {
200     if (window.testRunner)
201         testRunner.notifyDone();
202 }, function() {
203     if (window.testRunner)
204         testRunner.notifyDone();
205 });
206 </script>