Skip to content

Commit b051d84

Browse files
committed
feat: Made textures referenced
By making textures referenced, we prevent duplicating them when not needed and allow for reuse of textures where possible.
1 parent f78f689 commit b051d84

File tree

4 files changed

+76
-47
lines changed

4 files changed

+76
-47
lines changed

src/backend/gl/texture/index.js

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,35 @@ class GLTexture extends Texture {
99
throw new Error(`"textureType" not implemented on ${ this.name }`);
1010
}
1111
clone() {
12+
return new this.constructor(this);
13+
}
14+
15+
beforeMutate() {
16+
if (this.texture.refs > 1) {
17+
this.cloneTexture();
18+
}
19+
}
20+
21+
cloneTexture() {
22+
this.texture.refs--;
1223
const { context: gl, size, texture } = this;
13-
gl.activeTexture(gl.TEXTURE0);
14-
gl.bindTexture(gl.TEXTURE_2D, texture);
15-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
16-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
17-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
18-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
24+
selTex(texture);
1925
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
2026
const target = gl.createTexture();
21-
gl.activeTexture(gl.TEXTURE0);
22-
gl.bindTexture(gl.TEXTURE_2D, target);
23-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
24-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
25-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
26-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
27+
selTex(target);
2728
gl.texImage2D(gl.TEXTURE_2D, 0, this.internalFormat, size[0], size[1], 0, this.textureFormat, this.textureType, null);
2829
gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, size[0], size[1]);
29-
return new this.constructor(Object.assign({}, this, { texture: target }));
30+
target.refs = 1;
31+
this.texture = target;
32+
33+
function selTex(tex) {
34+
gl.activeTexture(gl.TEXTURE0);
35+
gl.bindTexture(gl.TEXTURE_2D, tex);
36+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
37+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
38+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
39+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
40+
}
3041
}
3142
}
32-
module.exports = { GLTexture };
43+
module.exports = { GLTexture };

src/backend/web-gl/kernel-value/number-texture.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,29 @@ class WebGLKernelValueNumberTexture extends WebGLKernelValue {
2828
}
2929

3030
updateValue(inputTexture) {
31+
const { kernel, context: gl } = this;
3132
if (inputTexture.constructor !== this.initialValueConstructor) {
3233
this.onUpdateValueMismatch(inputTexture.constructor);
3334
return;
3435
}
3536
if (this.checkContext && inputTexture.context !== this.context) {
3637
throw new Error(`Value ${this.name} (${this.type}) must be from same context`);
3738
}
38-
const { context: gl } = this;
39-
if (inputTexture.texture === this.kernel.outputTexture) {
40-
inputTexture = inputTexture.clone();
41-
gl.useProgram(this.kernel.program);
42-
this.kernel.textureGarbage.push(inputTexture);
39+
40+
if (kernel.outputTexture.texture === inputTexture.texture) {
41+
const prev = kernel.prevInput;
42+
if (prev) {
43+
if (prev.ref === 1) {
44+
if (kernel.outputTexture) {
45+
kernel.outputTexture.delete();
46+
kernel.outputTexture = prev.clone();
47+
}
48+
}
49+
prev.delete();
50+
}
51+
kernel.prevInput = inputTexture.clone();
4352
}
53+
4454
gl.activeTexture(this.contextHandle);
4555
gl.bindTexture(gl.TEXTURE_2D, this.uploadValue = inputTexture.texture);
4656
this.kernel.setUniform1i(this.id, this.index);
@@ -49,4 +59,4 @@ class WebGLKernelValueNumberTexture extends WebGLKernelValue {
4959

5060
module.exports = {
5161
WebGLKernelValueNumberTexture
52-
};
62+
};

src/backend/web-gl/kernel.js

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,6 @@ class WebGLKernel extends GLKernel {
150150
this.threadDim = null;
151151
this.framebuffer = null;
152152
this.buffer = null;
153-
this.textureGarbage = [];
154153
this.textureCache = [];
155154
this.programUniformLocationCache = {};
156155
this.uniform1fCache = {};
@@ -629,31 +628,18 @@ class WebGLKernel extends GLKernel {
629628
if (this.pipeline) {
630629
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
631630
gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
632-
if (!this.outputTexture || this.immutable) {
633-
this._setupOutputTexture();
634-
}
631+
this._setupOutputTexture();
635632
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
636-
return new this.TextureConstructor({
637-
texture: this.outputTexture,
638-
size: texSize,
639-
dimensions: this.threadDim,
640-
output: this.output,
641-
context: this.context,
642-
internalFormat: this.getInternalFormat(),
643-
textureFormat: this.getTextureFormat(),
644-
});
633+
return this.outputTexture.clone();
645634
}
646635
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
647636
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
648637
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
649-
this.garbageCollect();
650638
return;
651639
}
652640

653641
gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
654-
if (this.immutable) {
655-
this._setupOutputTexture();
656-
}
642+
this._setupOutputTexture();
657643

658644
if (this.subKernels !== null) {
659645
if (this.immutable) {
@@ -663,13 +649,6 @@ class WebGLKernel extends GLKernel {
663649
}
664650

665651
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
666-
this.garbageCollect();
667-
}
668-
669-
garbageCollect() {
670-
while (this.textureGarbage.length > 0) {
671-
this.textureGarbage.pop().delete();
672-
}
673652
}
674653

675654
drawBuffers() {
@@ -692,9 +671,13 @@ class WebGLKernel extends GLKernel {
692671
* @desc Setup and replace output texture
693672
*/
694673
_setupOutputTexture() {
674+
if (this.outputTexture) {
675+
this.outputTexture.beforeMutate();
676+
return;
677+
}
695678
const gl = this.context;
696679
const texSize = this.texSize;
697-
const texture = this.outputTexture = this.createTexture();
680+
const texture = this.createTexture();
698681
gl.activeTexture(gl.TEXTURE0 + this.constantTextureCount + this.argumentTextureCount);
699682
gl.bindTexture(gl.TEXTURE_2D, texture);
700683
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
@@ -708,6 +691,15 @@ class WebGLKernel extends GLKernel {
708691
gl.texImage2D(gl.TEXTURE_2D, 0, format, texSize[0], texSize[1], 0, format, gl.UNSIGNED_BYTE, null);
709692
}
710693
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
694+
this.outputTexture = new this.TextureConstructor({
695+
texture,
696+
size: texSize,
697+
dimensions: this.threadDim,
698+
output: this.output,
699+
context: this.context,
700+
internalFormat: this.getInternalFormat(),
701+
textureFormat: this.getTextureFormat(),
702+
});
711703
}
712704

713705
/**
@@ -1443,6 +1435,12 @@ class WebGLKernel extends GLKernel {
14431435
}
14441436
}
14451437
this.destroyExtensions();
1438+
if (this.prevInput) {
1439+
this.prevInput.delete();
1440+
}
1441+
if (this.outputTexture) {
1442+
this.outputTexture.delete();
1443+
}
14461444
delete this.context;
14471445
delete this.canvas;
14481446
}
@@ -1474,4 +1472,4 @@ class WebGLKernel extends GLKernel {
14741472

14751473
module.exports = {
14761474
WebGLKernel
1477-
};
1475+
};

src/texture.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ class Texture {
1818
if (!output) throw new Error('settings property "output" required.');
1919
if (!context) throw new Error('settings property "context" required.');
2020
this.texture = texture;
21+
if (texture.refs) {
22+
texture.refs++;
23+
} else {
24+
texture.refs = 1;
25+
}
2126
this.size = size;
2227
this.dimensions = dimensions;
2328
this.output = output;
@@ -52,11 +57,16 @@ class Texture {
5257
* @desc Deletes the Texture
5358
*/
5459
delete() {
60+
if (this._deleted) return;
5561
this._deleted = true;
62+
if (this.texture.refs) {
63+
this.texture.refs--;
64+
if (this.texture.refs) return;
65+
}
5666
return this.context.deleteTexture(this.texture);
5767
}
5868
}
5969

6070
module.exports = {
6171
Texture
62-
};
72+
};

0 commit comments

Comments
 (0)