Skip to content

Commit 738f719

Browse files
committed
RendererPool mechanism added for sharing WebGL contexts
1 parent 98e9b0f commit 738f719

File tree

7 files changed

+1246
-432
lines changed

7 files changed

+1246
-432
lines changed

examples/renderer_limit.ipynb

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 1,
6+
"metadata": {
7+
"collapsed": true
8+
},
9+
"outputs": [],
10+
"source": [
11+
"from pythreejs import *\n",
12+
"from IPython.display import display\n",
13+
"import time"
14+
]
15+
},
16+
{
17+
"cell_type": "code",
18+
"execution_count": 2,
19+
"metadata": {
20+
"collapsed": false
21+
},
22+
"outputs": [],
23+
"source": [
24+
"# Setup our objects\n",
25+
"mat1 = MeshStandardMaterial(color='#ff0000')\n",
26+
"mat2 = MeshStandardMaterial(color='#00ff00')\n",
27+
"mat3 = MeshStandardMaterial(color='#0000ff')\n",
28+
"mat4 = MeshStandardMaterial(color='#ffff00')\n",
29+
"mat5 = MeshStandardMaterial(color='#ff00ff')\n",
30+
"mat6 = MeshStandardMaterial(color='#00ffff')\n",
31+
"torus = TorusGeometry(radius=12, tube=3, radialSegments=16, tubularSegments=100)\n",
32+
"mesh1 = Mesh(geometry=torus, material=mat1, _width=75, _height=75)\n",
33+
"mesh2 = Mesh(geometry=torus, material=mat2, _width=75, _height=75)\n",
34+
"mesh3 = Mesh(geometry=torus, material=mat3, _width=75, _height=75)\n",
35+
"mesh4 = Mesh(geometry=torus, material=mat4, _width=75, _height=75)\n",
36+
"mesh5 = Mesh(geometry=torus, material=mat5, _width=75, _height=75)\n",
37+
"mesh6 = Mesh(geometry=torus, material=mat6, _width=75, _height=75)"
38+
]
39+
},
40+
{
41+
"cell_type": "code",
42+
"execution_count": 3,
43+
"metadata": {
44+
"collapsed": false
45+
},
46+
"outputs": [],
47+
"source": [
48+
"# This will render our meshes, each multiple times, resulting in 30 different renderings\n",
49+
"# Each of the 30 is a separate widget. \n",
50+
"# This test demonstrates:\n",
51+
"# - rendering shared objects in multiple places\n",
52+
"# - maintaining interactivity for all renderings\n",
53+
"# - no prior image is lost because of subsequent renderings\n",
54+
"display(mesh1, mesh2, mesh3, mesh4, mesh5, mesh6, \n",
55+
" mesh1, mesh2, mesh3, mesh4, mesh5, mesh6, \n",
56+
" mesh1, mesh2, mesh3, mesh4, mesh5, mesh6, \n",
57+
" mesh1, mesh2, mesh3, mesh4, mesh5, mesh6, \n",
58+
" mesh1, mesh2, mesh3, mesh4, mesh5, mesh6, \n",
59+
" mesh1, mesh2, mesh3, mesh4, mesh5, mesh6)"
60+
]
61+
},
62+
{
63+
"cell_type": "code",
64+
"execution_count": 4,
65+
"metadata": {
66+
"collapsed": true
67+
},
68+
"outputs": [],
69+
"source": [
70+
"time.sleep(2)"
71+
]
72+
},
73+
{
74+
"cell_type": "code",
75+
"execution_count": 5,
76+
"metadata": {
77+
"collapsed": true
78+
},
79+
"outputs": [],
80+
"source": [
81+
"# Test using raw WebGLRenderer\n",
82+
"# Need a scene, cam, and lights to do so\n",
83+
"scene = Scene()\n",
84+
"\n",
85+
"scene.add(mesh1)\n",
86+
"\n",
87+
"cam = PerspectiveCamera(position=[0, 0, 50], fov=75)\n",
88+
"cam.lookAt([0, 0, 0])\n",
89+
"scene.add(cam)\n",
90+
"\n",
91+
"amb = AmbientLight(color=\"#ffffff\", intensity=0.5)\n",
92+
"point = PointLight(color=\"#ffffff\", intensity=1.0, distance=0.0)\n",
93+
"point.position = [ -100, 100, 100 ]\n",
94+
"point.lookAt([0, 0, 0])\n",
95+
"cam.add(amb)\n",
96+
"cam.add(point)\n",
97+
"\n",
98+
"scene"
99+
]
100+
},
101+
{
102+
"cell_type": "code",
103+
"execution_count": 6,
104+
"metadata": {
105+
"collapsed": true
106+
},
107+
"outputs": [],
108+
"source": [
109+
"renderer = WebGLRenderer(width=50, height=50)\n",
110+
"r = renderer\n",
111+
"display(r, r, r, r, r,\n",
112+
" r, r, r, r, r,\n",
113+
" r, r, r, r, r,\n",
114+
" r, r, r, r, r,\n",
115+
" r, r, r, r, r)"
116+
]
117+
},
118+
{
119+
"cell_type": "code",
120+
"execution_count": 7,
121+
"metadata": {
122+
"collapsed": true
123+
},
124+
"outputs": [],
125+
"source": [
126+
"time.sleep(3)"
127+
]
128+
},
129+
{
130+
"cell_type": "code",
131+
"execution_count": 11,
132+
"metadata": {
133+
"collapsed": true
134+
},
135+
"outputs": [],
136+
"source": [
137+
"renderer.render(scene, cam)"
138+
]
139+
},
140+
{
141+
"cell_type": "code",
142+
"execution_count": 10,
143+
"metadata": {
144+
"collapsed": true
145+
},
146+
"outputs": [],
147+
"source": [
148+
"scene = Scene()\n",
149+
"scene.add(mesh2)\n",
150+
"scene.add(cam)"
151+
]
152+
},
153+
{
154+
"cell_type": "code",
155+
"execution_count": null,
156+
"metadata": {
157+
"collapsed": true
158+
},
159+
"outputs": [],
160+
"source": []
161+
}
162+
],
163+
"metadata": {
164+
"anaconda-cloud": {},
165+
"kernelspec": {
166+
"display_name": "Python [py27]",
167+
"language": "python",
168+
"name": "Python [py27]"
169+
},
170+
"language_info": {
171+
"codemirror_mode": {
172+
"name": "ipython",
173+
"version": 2
174+
},
175+
"file_extension": ".py",
176+
"mimetype": "text/x-python",
177+
"name": "python",
178+
"nbconvert_exporter": "python",
179+
"pygments_lexer": "ipython2",
180+
"version": "2.7.12"
181+
}
182+
},
183+
"nbformat": 4,
184+
"nbformat_minor": 0
185+
}

examples/test.ipynb

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"cells": [
33
{
44
"cell_type": "code",
5-
"execution_count": null,
5+
"execution_count": 16,
66
"metadata": {
77
"collapsed": false
88
},
@@ -14,7 +14,7 @@
1414
},
1515
{
1616
"cell_type": "code",
17-
"execution_count": null,
17+
"execution_count": 17,
1818
"metadata": {
1919
"collapsed": false
2020
},
@@ -28,7 +28,7 @@
2828
},
2929
{
3030
"cell_type": "code",
31-
"execution_count": null,
31+
"execution_count": 18,
3232
"metadata": {
3333
"collapsed": true
3434
},
@@ -41,7 +41,7 @@
4141
},
4242
{
4343
"cell_type": "code",
44-
"execution_count": null,
44+
"execution_count": 19,
4545
"metadata": {
4646
"collapsed": true
4747
},
@@ -58,7 +58,7 @@
5858
},
5959
{
6060
"cell_type": "code",
61-
"execution_count": null,
61+
"execution_count": 20,
6262
"metadata": {
6363
"collapsed": false
6464
},
@@ -70,7 +70,7 @@
7070
},
7171
{
7272
"cell_type": "code",
73-
"execution_count": null,
73+
"execution_count": 21,
7474
"metadata": {
7575
"collapsed": true
7676
},
@@ -83,7 +83,7 @@
8383
},
8484
{
8585
"cell_type": "code",
86-
"execution_count": null,
86+
"execution_count": 22,
8787
"metadata": {
8888
"collapsed": true
8989
},
@@ -96,7 +96,7 @@
9696
},
9797
{
9898
"cell_type": "code",
99-
"execution_count": null,
99+
"execution_count": 23,
100100
"metadata": {
101101
"collapsed": true
102102
},
@@ -107,7 +107,7 @@
107107
},
108108
{
109109
"cell_type": "code",
110-
"execution_count": null,
110+
"execution_count": 24,
111111
"metadata": {
112112
"collapsed": true
113113
},
@@ -123,7 +123,7 @@
123123
},
124124
{
125125
"cell_type": "code",
126-
"execution_count": null,
126+
"execution_count": 25,
127127
"metadata": {
128128
"collapsed": true
129129
},
@@ -135,7 +135,7 @@
135135
},
136136
{
137137
"cell_type": "code",
138-
"execution_count": null,
138+
"execution_count": 26,
139139
"metadata": {
140140
"collapsed": true
141141
},
@@ -147,7 +147,7 @@
147147
},
148148
{
149149
"cell_type": "code",
150-
"execution_count": null,
150+
"execution_count": 27,
151151
"metadata": {
152152
"collapsed": true
153153
},
@@ -158,7 +158,7 @@
158158
},
159159
{
160160
"cell_type": "code",
161-
"execution_count": null,
161+
"execution_count": 30,
162162
"metadata": {
163163
"collapsed": false
164164
},
@@ -169,7 +169,7 @@
169169
},
170170
{
171171
"cell_type": "code",
172-
"execution_count": null,
172+
"execution_count": 29,
173173
"metadata": {
174174
"collapsed": true
175175
},

js/src/_base/RendererPool.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
var _ = require('underscore');
2+
3+
var MAX_RENDERERS = 1;
4+
5+
function makeRendererClaimToken(renderer, onReclaim) {
6+
return {
7+
id: renderer.poolId,
8+
claimTime: new Date(),
9+
renderer: renderer,
10+
onReclaim: onReclaim,
11+
};
12+
}
13+
14+
function RendererPool() {
15+
this.numCreated = 0;
16+
this.freePool = [];
17+
this.claimedPool = [];
18+
}
19+
_.extend(RendererPool.prototype, {
20+
21+
acquire: function(onReclaim) {
22+
23+
var renderer;
24+
console.log('RendererPool.acquiring...');
25+
26+
if (this.freePool.length > 0) {
27+
28+
renderer = this.freePool.shift();
29+
30+
} else if (this.numCreated < MAX_RENDERERS) {
31+
32+
renderer = new THREE.WebGLRenderer({
33+
// required for converting canvas to png
34+
preserveDrawingBuffer: true,
35+
});
36+
renderer.poolId = this.numCreated;
37+
this.numCreated++;
38+
39+
40+
} else {
41+
42+
// reclaim token
43+
var claimedRenderer = this.claimedPool.shift();
44+
renderer = claimedRenderer.renderer;
45+
claimedRenderer.onReclaim();
46+
47+
}
48+
49+
console.log('RendererPool.acquire(id=' + renderer.poolId + ')');
50+
this.claimedPool.push(makeRendererClaimToken(renderer, onReclaim));
51+
renderer.clear();
52+
return renderer;
53+
},
54+
55+
release: function(renderer) {
56+
console.log('RendererPool.release(id=' + renderer.poolId + ')');
57+
58+
var id = renderer.poolId;
59+
var claimedRenderer = _.find(this.claimedPool, function(claimToken) {
60+
return claimToken.renderer.poolId === id;
61+
});
62+
if (!claimedRenderer) {
63+
throw new Error('unable to find release renderer with id: ' + id);
64+
}
65+
66+
// notify holder
67+
claimedRenderer.onReclaim();
68+
69+
// remove claim token
70+
this.claimedPool = _.without(this.claimedPool, claimedRenderer);
71+
this.freePool.push(claimedRenderer.renderer);
72+
73+
},
74+
75+
});
76+
77+
module.exports = new RendererPool();

0 commit comments

Comments
 (0)