Skip to content

Commit 73b1a94

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

File tree

1 file changed

+169
-16
lines changed

1 file changed

+169
-16
lines changed

immersive-vr-session.html

Lines changed: 169 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,137 @@
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+
}`;
163+
164+
function compileShader(type, source) {
165+
const shader = gl.createShader(type);
166+
gl.shaderSource(shader, source);
167+
gl.compileShader(shader);
168+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
169+
console.error(gl.getShaderInfoLog(shader));
170+
return null;
171+
}
172+
return shader;
173+
}
174+
175+
const vs = compileShader(gl.VERTEX_SHADER, vsSource);
176+
const fs = compileShader(gl.FRAGMENT_SHADER, fsSource);
177+
const program = gl.createProgram();
178+
gl.attachShader(program, vs);
179+
gl.attachShader(program, fs);
180+
gl.linkProgram(program);
181+
return program;
182+
}
183+
184+
function quadVertexBuffer() {
185+
// Fullscreen quad (2 triangles forming a rectangle)
186+
// Interleaved: [posX, posY, texU, texV]
187+
const quadVertices = new Float32Array([
188+
-1, -1, 0, 0,
189+
1, -1, 1, 0,
190+
-1, 1, 0, 1,
191+
1, 1, 1, 1,
192+
]);
193+
const quadBuffer = gl.createBuffer();
194+
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer);
195+
gl.bufferData(gl.ARRAY_BUFFER, quadVertices, gl.STATIC_DRAW);
196+
return quadBuffer;
197+
}
198+
199+
let blitProgram = null;
200+
let blitQuad = null;
201+
202+
function blitTexture(framebuffer, texture, width, height) {
203+
if(!blitProgram) {
204+
blitProgram = createBlitProgram();
205+
blitQuad = quadVertexBuffer();
206+
}
207+
const a_position = gl.getAttribLocation(blitProgram, 'a_position');
208+
const a_texCoord = gl.getAttribLocation(blitProgram, 'a_texCoord');
209+
210+
gl.viewport(0, 0, width, height);
211+
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
212+
gl.clearColor(0, 0, 0, 1);
213+
gl.clear(gl.COLOR_BUFFER_BIT);
214+
215+
gl.useProgram(blitProgram);
216+
gl.bindBuffer(gl.ARRAY_BUFFER, blitQuad);
217+
218+
gl.enableVertexAttribArray(a_position);
219+
gl.vertexAttribPointer(a_position, 2, gl.FLOAT, false, 16, 0);
220+
221+
gl.enableVertexAttribArray(a_texCoord);
222+
gl.vertexAttribPointer(a_texCoord, 2, gl.FLOAT, false, 16, 8);
223+
224+
gl.activeTexture(gl.TEXTURE0);
225+
gl.bindTexture(gl.TEXTURE_2D, texture);
226+
gl.uniform1i(gl.getUniformLocation(blitProgram, 'u_texture'), 0);
227+
228+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
229+
}
230+
231+
function createBlitTexture(img) {
232+
let tempTexture = gl.createTexture();
233+
gl.bindTexture(gl.TEXTURE_2D, tempTexture);
234+
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, img.width, img.height)
235+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
236+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
237+
gl.bindTexture(gl.TEXTURE_2D, null);
238+
return tempTexture;
239+
}
240+
241+
let blitTexturePing = null;
242+
let blitTexturePong = null;
243+
let blitTextureNext = null;
244+
128245
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);
246+
const textureGL = renderer._getRenderTexture(texture)._texture;
247+
if(test.useBlit) {
248+
if(!blitTextureNext) {
249+
blitTexturePing = createBlitTexture(img);
250+
blitTexturePong = createBlitTexture(img);
251+
blitTextureNext = blitTexturePing;
252+
}
253+
gl.bindTexture(gl.TEXTURE_2D, blitTextureNext);
254+
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, img.width, img.height,
255+
gl.RGBA, gl.UNSIGNED_BYTE, img);
256+
gl.bindTexture(gl.TEXTURE_2D, null);
257+
if(!texture.framebuffers) {
258+
texture.framebuffers = new Array(test.layers)
259+
.fill()
260+
.map((value, index) => {
261+
if(test.useTexture2D) {
262+
return createFramebuffer(textureGL, null);
263+
} else {
264+
return createFramebuffer(textureGL, index);
265+
}
266+
});
267+
}
268+
blitTexture(texture.framebuffers[layer], blitTextureNext, img.width, img.height);
269+
blitTextureNext = blitTextureNext === blitTexturePing ? blitTexturePong : blitTexturePing;
270+
}
271+
else if(test.useTexture2D) {
272+
gl.bindTexture(gl.TEXTURE_2D, textureGL);
132273
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
133274
gl.texSubImage2D(
134275
gl.TEXTURE_2D,
@@ -142,7 +283,7 @@
142283
img
143284
);
144285
} else {
145-
gl.bindTexture(gl.TEXTURE_2D_ARRAY, textureGL._texture);
286+
gl.bindTexture(gl.TEXTURE_2D_ARRAY, textureGL);
146287
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
147288
gl.texSubImage3D(
148289
gl.TEXTURE_2D_ARRAY,
@@ -332,12 +473,24 @@
332473

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

335-
uploadTextureLayer(nextTexture, currentLayerToUpdate++, canvases[0]);
476+
if(test.tempBuffer) {
477+
const ctx = canvases[0].getContext('2d');
478+
buffers[0] = ctx.getImageData(0, 0, canvases[0].width, canvases[0].height);
479+
uploadTextureLayer(nextTexture, currentLayerToUpdate++, buffers[0]);
480+
} else {
481+
uploadTextureLayer(nextTexture, currentLayerToUpdate++, canvases[0]);
482+
}
336483
currentLayerToUpdate = currentLayerToUpdate%test.layers;
337484
if(test.multipleUpload) {
338485
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);
486+
uploadTextureLayer(nextTexture, currentLayerToUpdate, canvas);
487+
if(test.tempBuffer) {
488+
const ctx = canvas.getContext('2d');
489+
buffers[1] = ctx.getImageData(0, 0, canvas.width, canvas.height);
490+
uploadTextureLayer(nextTexture, currentLayerToUpdate++, buffers[1]);
491+
} else {
492+
uploadTextureLayer(nextTexture, currentLayerToUpdate++, canvas);
493+
}
341494
currentLayerToUpdate = currentLayerToUpdate%test.layers;
342495
}
343496

0 commit comments

Comments
 (0)