Skip to content

Commit d96db1c

Browse files
author
Hugo Amiard
committed
Add blit to 2d array performance test
1 parent 67285f1 commit d96db1c

File tree

1 file changed

+170
-16
lines changed

1 file changed

+170
-16
lines changed

immersive-vr-session.html

Lines changed: 170 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,36 @@
8383
let xrButton = null;
8484
let xrRefSpace = null;
8585

86+
// WebGL scene globals.
87+
let gl = null;
88+
let renderer = null;
89+
90+
function createFramebuffer(texture, arrayLayer) {
91+
const framebuffer = gl.createFramebuffer();
92+
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
93+
if(arrayLayer !== null) {
94+
gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture, 0, arrayLayer);
95+
} else {
96+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
97+
}
98+
return framebuffer;
99+
}
100+
101+
let scene = new Scene();
102+
scene.addNode(new Gltf2Node({url: 'media/gltf/space/space.gltf'}));
103+
scene.addNode(new SkyboxNode({url: 'media/textures/milky-way-4k.png'}));
104+
86105
/* @test: 2d canvas setup */
87106

88107
const test = {
89108
multipleUpload: true,
90-
multipleTextures: false,
109+
multipleTextures: true,
91110
useMultipleCanvases: false,
92111
useTexture2D: false,
93-
canvasSize: [512, 512],
112+
useBlit: true,
113+
tempBuffer: false,
114+
subTexture: false,
115+
canvasSize: [1024, 1024],
94116
atlasSize: 1024,
95117
layers: 1
96118
};
@@ -100,10 +122,13 @@
100122
.map(_ => {
101123
if(test.useTexture2D) {
102124
return new Custom2DTexture(test.atlasSize, test.atlasSize);
125+
} else {
126+
return new ArrayTexture(test.atlasSize, test.atlasSize, test.layers);
103127
}
104-
return new ArrayTexture(test.atlasSize, test.atlasSize, test.layers);
105128
});
106129

130+
const buffers = new Array(2);
131+
107132
const canvases = new Array(2)
108133
.fill()
109134
.map(_ => {
@@ -114,21 +139,138 @@
114139
return canvas;
115140
});
116141

117-
// WebGL scene globals.
118-
let gl = null;
119-
let renderer = null;
120-
let scene = new Scene();
121-
scene.addNode(new Gltf2Node({url: 'media/gltf/space/space.gltf'}));
122-
scene.addNode(new SkyboxNode({url: 'media/textures/milky-way-4k.png'}));
123142
const boxMaterial = new PbrMaterial();
124143
boxMaterial.baseColorFactor.value = [1.0, 1.0, 1.0, 1.0];
125144
boxMaterial.baseColor.texture = textures[0];
126145
boxMaterial.arrayLayer.value = 5.0;
127146

147+
function createBlitProgram() {
148+
const vsSource = `
149+
attribute vec2 a_position;
150+
attribute vec2 a_texCoord;
151+
varying vec2 v_texCoord;
152+
void main() {
153+
gl_Position = vec4(a_position, 0, 1);
154+
v_texCoord = a_texCoord;
155+
}`;
156+
const fsSource = `
157+
precision mediump float;
158+
uniform sampler2D u_texture;
159+
varying vec2 v_texCoord;
160+
void main() {
161+
gl_FragColor = texture2D(u_texture, v_texCoord);
162+
gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
163+
}`;
164+
165+
function compileShader(type, source) {
166+
const shader = gl.createShader(type);
167+
gl.shaderSource(shader, source);
168+
gl.compileShader(shader);
169+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
170+
console.error(gl.getShaderInfoLog(shader));
171+
return null;
172+
}
173+
return shader;
174+
}
175+
176+
const vs = compileShader(gl.VERTEX_SHADER, vsSource);
177+
const fs = compileShader(gl.FRAGMENT_SHADER, fsSource);
178+
const program = gl.createProgram();
179+
gl.attachShader(program, vs);
180+
gl.attachShader(program, fs);
181+
gl.linkProgram(program);
182+
return program;
183+
}
184+
185+
function quadVertexBuffer() {
186+
// Fullscreen quad (2 triangles forming a rectangle)
187+
// Interleaved: [posX, posY, texU, texV]
188+
const quadVertices = new Float32Array([
189+
-1, -1, 0, 0,
190+
1, -1, 1, 0,
191+
-1, 1, 0, 1,
192+
1, 1, 1, 1,
193+
]);
194+
const quadBuffer = gl.createBuffer();
195+
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer);
196+
gl.bufferData(gl.ARRAY_BUFFER, quadBuffer, gl.STATIC_DRAW);
197+
return quadBuffer;
198+
}
199+
200+
let blitProgram = null;
201+
let blitQuad = null;
202+
203+
function blitTexture(framebuffer, texture, width, height) {
204+
if(!blitProgram) {
205+
blitProgram = createBlitProgram();
206+
blitQuad = quadVertexBuffer();
207+
}
208+
const a_position = gl.getAttribLocation(blitProgram, 'a_position');
209+
const a_texCoord = gl.getAttribLocation(blitProgram, 'a_texCoord');
210+
211+
gl.viewport(0, 0, width, height);
212+
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
213+
gl.clearColor(0, 0, 0, 1);
214+
gl.clear(gl.COLOR_BUFFER_BIT);
215+
216+
gl.useProgram(blitProgram);
217+
gl.bindBuffer(gl.ARRAY_BUFFER, blitQuad);
218+
219+
gl.enableVertexAttribArray(a_position);
220+
gl.vertexAttribPointer(a_position, 2, gl.FLOAT, false, 16, 0);
221+
222+
gl.enableVertexAttribArray(a_texCoord);
223+
gl.vertexAttribPointer(a_texCoord, 2, gl.FLOAT, false, 16, 8);
224+
225+
gl.activeTexture(gl.TEXTURE0);
226+
gl.bindTexture(gl.TEXTURE_2D, texture);
227+
gl.uniform1i(gl.getUniformLocation(blitProgram, 'u_texture'), 0);
228+
229+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
230+
}
231+
232+
function createBlitTexture(img) {
233+
let tempTexture = gl.createTexture();
234+
gl.bindTexture(gl.TEXTURE_2D, tempTexture);
235+
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, img.width, img.height)
236+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
237+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
238+
gl.bindTexture(gl.TEXTURE_2D, null);
239+
return tempTexture;
240+
}
241+
242+
let blitTexturePing = null;
243+
let blitTexturePong = null;
244+
let blitTextureNext = null;
245+
128246
function uploadTextureLayer(texture, layer, img, offsets = [0, 0]) {
129-
const textureGL = renderer._getRenderTexture(texture);
130-
if(test.useTexture2D) {
131-
gl.bindTexture(gl.TEXTURE_2D, textureGL._texture);
247+
const textureGL = renderer._getRenderTexture(texture)._texture;
248+
if(test.useBlit) {
249+
if(!blitTextureNext) {
250+
blitTexturePing = createBlitTexture(img);
251+
blitTexturePong = createBlitTexture(img);
252+
blitTextureNext = blitTexturePing;
253+
}
254+
gl.bindTexture(gl.TEXTURE_2D, blitTextureNext);
255+
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, img.width, img.height,
256+
gl.RGBA, gl.UNSIGNED_BYTE, img);
257+
gl.bindTexture(gl.TEXTURE_2D, null);
258+
if(!texture.framebuffers) {
259+
texture.framebuffers = new Array(test.layers)
260+
.fill()
261+
.map((value, index) => {
262+
if(test.useTexture2D) {
263+
return createFramebuffer(textureGL, null);
264+
} else {
265+
return createFramebuffer(textureGL, index);
266+
}
267+
});
268+
}
269+
blitTexture(texture.framebuffers[layer], blitTextureNext, img.width, img.height);
270+
blitTextureNext = blitTextureNext === blitTexturePing ? blitTexturePong : blitTexturePing;
271+
}
272+
else if(test.useTexture2D) {
273+
gl.bindTexture(gl.TEXTURE_2D, textureGL);
132274
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
133275
gl.texSubImage2D(
134276
gl.TEXTURE_2D,
@@ -142,7 +284,7 @@
142284
img
143285
);
144286
} else {
145-
gl.bindTexture(gl.TEXTURE_2D_ARRAY, textureGL._texture);
287+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, textureGL);
146288
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
147289
gl.texSubImage3D(
148290
gl.TEXTURE_2D_ARRAY,
@@ -332,12 +474,24 @@
332474

333475
// console.log(`Drawing to image ${nextTexture.textureKey}, displaying image ${boxMaterial.baseColor.texture.textureKey}`);
334476

335-
uploadTextureLayer(nextTexture, currentLayerToUpdate++, canvases[0]);
477+
if(test.tempBuffer) {
478+
const ctx = canvases[0].getContext('2d');
479+
buffers[0] = ctx.getImageData(0, 0, canvases[0].width, canvases[0].height);
480+
uploadTextureLayer(nextTexture, currentLayerToUpdate++, buffers[0]);
481+
} else {
482+
uploadTextureLayer(nextTexture, currentLayerToUpdate++, canvases[0]);
483+
}
336484
currentLayerToUpdate = currentLayerToUpdate%test.layers;
337485
if(test.multipleUpload) {
338486
const canvas = test.useMultipleCanvases ? canvases[1] : canvases[0];
339-
const offsets = [canvas.width*0.5, canvas.height*0.5];
340-
uploadTextureLayer(nextTexture, currentLayerToUpdate, canvas, offsets);
487+
uploadTextureLayer(nextTexture, currentLayerToUpdate, canvas);
488+
if(test.tempBuffer) {
489+
const ctx = canvas.getContext('2d');
490+
buffers[1] = ctx.getImageData(0, 0, canvas.width, canvas.height);
491+
uploadTextureLayer(nextTexture, currentLayerToUpdate++, buffers[1]);
492+
} else {
493+
uploadTextureLayer(nextTexture, currentLayerToUpdate++, canvas);
494+
}
341495
currentLayerToUpdate = currentLayerToUpdate%test.layers;
342496
}
343497

0 commit comments

Comments
 (0)