Skip to content

Commit

Permalink
If available, using a single OffscreenCanvas
Browse files Browse the repository at this point in the history
This eliminates the too many webgl context errors, but it is a new
(2023) feature and more testing is needed before release.
  • Loading branch information
dkoes committed Aug 18, 2024
1 parent a4f2f12 commit 2f3c313
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 49 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/GLViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,10 +310,10 @@ export class GLViewer {
this.renderer.setViewport();
if (!this.scene)
return;
// var time = new Date();
//let time = new Date();
this.setSlabAndFog();
this.renderer.render(this.scene, this.camera);
// console.log("rendered in " + (+new Date() - time) + "ms");
//console.log("rendered in " + (+new Date() - (time as any)) + "ms");

//have any scene change trigger a callback
if (this.viewChangeCallback) this.viewChangeCallback(this._viewer.getView());
Expand Down
118 changes: 75 additions & 43 deletions src/WebGL/Renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ import { Mesh, Line, Sprite } from "./objects";
import { ShaderLib, ShaderUtils } from "./shaders";
import { SpritePlugin } from "./SpritePlugin";

// share a single offscreen renderer across all Renderers
var _offscreen_singleton = null;
var _gl_singleton = null;


export class Renderer {
row: any;
col: any;
Expand Down Expand Up @@ -51,7 +56,9 @@ export class Renderer {
};

// webgl rednering context
private _gl: WebGLRenderingContext | WebGL2RenderingContext;
private _gl: WebGLRenderingContext | WebGL2RenderingContext;
private _offscreen: OffscreenCanvas = null;
private _bitmap: ImageBitmapRenderingContext = null;
// internal properties
private _programs = [];
private _programs_counter = 0;
Expand Down Expand Up @@ -191,16 +198,16 @@ export class Renderer {
);
this._outlineEnabled = !!parameters.outline;
this._AOEnabled = !!parameters.ambientOcclusion;
if(parameters.ambientOcclusion && typeof(parameters.ambientOcclusion.strength) !== 'undefined') {
if (parameters.ambientOcclusion && typeof (parameters.ambientOcclusion.strength) !== 'undefined') {
this._AOstrength = parseFloat(parameters.ambientOcclusion.strength);
}
if(this._AOstrength == 0) {
if (this._AOstrength == 0) {
this._AOEnabled = false;
}
if(parameters.ambientOcclusion && typeof(parameters.ambientOcclusion.radius) !== 'undefined') {
if (parameters.ambientOcclusion && typeof (parameters.ambientOcclusion.radius) !== 'undefined') {
this._AOradius = parseFloat(parameters.ambientOcclusion.radius);
}
}

this.domElement = this._canvas;
this._canvas.id = parameters.id;

Expand Down Expand Up @@ -276,9 +283,9 @@ export class Renderer {
}

enableAmbientOcclusion(parameters) {
if(parameters) {
if(parameters.strength) this._AOstrength = parameters.strength;
if(parameters.scale) this._AOradius = parameters.scale;
if (parameters) {
if (parameters.strength) this._AOstrength = parameters.strength;
if (parameters.scale) this._AOradius = parameters.scale;
}
this._AOEnabled = this._AOstrength > 0;
}
Expand All @@ -288,6 +295,11 @@ export class Renderer {
}

setViewport() {
if(this._offscreen) {
//set viewport is called before every render, so setup offscreen size here
this._offscreen.width = this._canvas.width;
this._offscreen.height = this._canvas.height;
}
if (
this.rows != undefined &&
this.cols != undefined &&
Expand All @@ -305,7 +317,7 @@ export class Renderer {
this._gl.scissor(wid * this.col, hei * this.row, wid, hei);
this._gl.viewport(wid * this.col, hei * this.row, wid, hei);
}
}
}
}

setSize(width, height) {
Expand Down Expand Up @@ -345,6 +357,7 @@ export class Renderer {
this._gl.viewport(0, 0, this._gl.drawingBufferWidth, this._gl.drawingBufferHeight);
}
}

this.initFrameBuffer();
}

Expand Down Expand Up @@ -618,7 +631,7 @@ export class Renderer {
this._shadingTexture,
0
);
this.clear(false,true,false);
this.clear(false, true, false);
this._gl.framebufferTexture2D(
this._gl.FRAMEBUFFER,
this._gl.DEPTH_ATTACHMENT,
Expand Down Expand Up @@ -666,7 +679,7 @@ export class Renderer {
//calculate depth map
this.renderObjects(scene.__webglObjects, true, materialType + "Depth",
camera, lights, fog, false);

//detach so we can read and attach scratch
this._gl.framebufferTexture2D(
this._gl.FRAMEBUFFER,
Expand All @@ -675,7 +688,7 @@ export class Renderer {
this._scratchTexture,
0
);
this.clear(false,true,false);
this.clear(false, true, false);

//perform AO calculation from depth map to scratch buffer

Expand All @@ -695,15 +708,15 @@ export class Renderer {
this._fullProjModelMatrix = new Matrix4();
this._fullProjModelMatrixInv = new Matrix4();
let object = renderList[0].object;
this._fullProjModelMatrix.multiplyMatrices(camera.projectionMatrix,object._modelViewMatrix);
this._fullProjModelMatrix.multiplyMatrices(camera.projectionMatrix, object._modelViewMatrix);
this._fullProjModelMatrixInv.getInverse(this._fullProjModelMatrix);
this._gl.uniformMatrix4fv(
p_uniforms.projectionMatrix,
false,
this._fullProjModelMatrix.elements
);
this._gl.uniformMatrix4fv(p_uniforms.projinv, false, this._fullProjModelMatrixInv.elements);
this._gl.uniformMatrix4fv(
p_uniforms.projectionMatrix,
false,
this._fullProjModelMatrix.elements
);

this._gl.uniformMatrix4fv(p_uniforms.projinv, false, this._fullProjModelMatrixInv.elements);


// bind vertexarray buffer and texture
Expand All @@ -726,12 +739,12 @@ export class Renderer {
this._shadingTexture,
0
);
this.clear(false,true,false);
this.clear(false, true, false);

this._gl.useProgram(this._blurshader);
this._currentProgram = this._blurshader;
this.setDepthTest(-1);
this.setDepthWrite(-1);
this.setDepthWrite(-1);


this._gl.bindBuffer(this._gl.ARRAY_BUFFER, this._screenQuadVBO);
Expand Down Expand Up @@ -846,9 +859,9 @@ export class Renderer {
this.renderObjects(scene.__webglObjects, true, "opaque",
camera, lights, fog, false);

if (hasAO) {
this.clearShading();
}
if (hasAO) {
this.clearShading();
}

// Render embedded labels (sprites)
this.renderSprites(scene, camera, false);
Expand Down Expand Up @@ -883,6 +896,12 @@ export class Renderer {

// Render floating labels (sprites)
this.renderSprites(scene, camera, true);

//if using offscreen render, copy final image
if(this._bitmap) {
const bitmap = this._offscreen.transferToImageBitmap();
this._bitmap.transferFromImageBitmap(bitmap);
}
}


Expand Down Expand Up @@ -934,7 +953,7 @@ export class Renderer {
this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_T, this._gl.CLAMP_TO_EDGE);

//shading texture - for AO and maybe eventually shadows? I don't like shadows
if(this._shadingTexture) {
if (this._shadingTexture) {
//for whatever reason, chrome seems to require this manual memory management
//for these textures, at least in the auto tests webpage where many viewers are being created/destroyed
this._gl.deleteTexture(this._shadingTexture);
Expand Down Expand Up @@ -975,7 +994,7 @@ export class Renderer {
this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, this._gl.NEAREST);
this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_S, this._gl.CLAMP_TO_EDGE);
this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_T, this._gl.CLAMP_TO_EDGE);

}
//bind fb
this._gl.bindFramebuffer(this._gl.FRAMEBUFFER, this._fb);
Expand Down Expand Up @@ -1894,7 +1913,7 @@ export class Renderer {
blankMaterial.opacity = 0.0;
globject.opaqueDepth = blankMaterial;
}
if(material.hasAO) {
if (material.hasAO) {
globject.hasAO = true;
}
if (this._AOEnabled || globject.hasAO) {
Expand Down Expand Up @@ -2106,35 +2125,48 @@ export class Renderer {
}

private initGL() {
//note setting antialis to true doesn't seem to do much and
//causes problems on iOS Safari

try {
if (
!(this._gl = this._canvas.getContext("webgl2", {
alpha: this._alpha,
premultipliedAlpha: this._premultipliedAlpha,
antialias: this._antialias,
preserveDrawingBuffer: this._preserveDrawingBuffer,
}))
) {
if (OffscreenCanvas) {
if(_gl_singleton == null || _gl_singleton.isContextLost()) {
_offscreen_singleton = new OffscreenCanvas(this._canvas.width, this._canvas.height);
_gl_singleton = _offscreen_singleton.getContext("webgl2", {
alpha: this._alpha,
premultipliedAlpha: this._premultipliedAlpha,
antialias: this._antialias,
preserveDrawingBuffer: this._preserveDrawingBuffer,
}) as WebGL2RenderingContext;
}
this._offscreen = _offscreen_singleton;
this._gl = _gl_singleton;
this._bitmap = this._canvas.getContext("bitmaprenderer");
} else {
if (
!(this._gl = this._canvas.getContext("experimental-webgl", {
!(this._gl = this._canvas.getContext("webgl2", {
alpha: this._alpha,
premultipliedAlpha: this._premultipliedAlpha,
antialias: this._antialias,
preserveDrawingBuffer: this._preserveDrawingBuffer,
}))
) {
if (
!(this._gl = this._canvas.getContext("webgl", {
!(this._gl = this._canvas.getContext("experimental-webgl", {
alpha: this._alpha,
premultipliedAlpha: this._premultipliedAlpha,
antialias: this._antialias,
preserveDrawingBuffer: this._preserveDrawingBuffer,
}))
) {
throw "Error creating WebGL context.";
if (
!(this._gl = this._canvas.getContext("webgl", {
alpha: this._alpha,
premultipliedAlpha: this._premultipliedAlpha,
antialias: this._antialias,
preserveDrawingBuffer: this._preserveDrawingBuffer,
}))
) {
throw "Error creating WebGL context.";
}
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion tests/webpages/multi.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

<body>
<script src="../../build/3Dmol.js"></script>
<div class='viewer_3Dmoljs' id="20" style="height: 100%; width: 100%; z-index: 100; float: true; position: absolute;" data-pdb='3erk'
data-style='cartoon' data-backgroundalpha=".25" data-backgroundcolor='green'></div>
<div class='viewer_3Dmoljs' id="1" style="height: 300px; width: 300px; display: inline-block; position: relative;" data-cid='2519'
data-style='stick' data-spin='axis:z;speed:100'></div>
<div class='viewer_3Dmoljs' id="2" style="height: 300px; width: 300px; display: inline-block; position: relative;" data-cid='2518'
Expand Down Expand Up @@ -42,7 +44,8 @@
<div class='viewer_3Dmoljs' id="18" style="height: 300px; width: 300px; display: inline-block; position: relative;" data-pdb='1ycr'
data-style='stick'></div>
<div class='viewer_3Dmoljs' id="19" style="height: 300px; width: 300px; display: inline-block; position: relative;" data-pdb='3erk'
data-style='stick'></div>
data-style='stick'></div>

</body>

</html>
2 changes: 1 addition & 1 deletion tests/webpages/simple.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<body>
<script src="../../build/3Dmol.js"></script>
<div style="height: 600px; width: 600px;" class='viewer_3Dmoljs'
data-config='ambientOcclusion:strength~1.2,radius=10' data-pdb='3M8L' data-backgroundcolor='0xffffff'
data-config='ambientOcclusion:strength~1.2,radius=10' data-pdb='3M8L' data-backgroundcolor='black'
data-select1='chain:A' data-style1='stick:radius=1,color=red'
data-select2='chain:B' data-style2='sphere:color=white'
data-select3='chain:C' data-surface3='VDW;color:white;opacity:1'></div>
Expand Down

0 comments on commit 2f3c313

Please sign in to comment.