Skip to content

Commit 3a74317

Browse files
authored
Merge pull request #7543 from processing/perf
2.0 perf updates
2 parents 0b5f5a0 + 3a55130 commit 3a74317

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+432
-352
lines changed

preview/index.html

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,27 @@
2020
import p5 from '../src/app.js';
2121

2222
const sketch = function (p) {
23+
let fbo;
2324
p.setup = async function () {
24-
p.createCanvas(400, 400);
25+
p.createCanvas(400, 400, p.WEBGL);
26+
fbo = p.createFramebuffer()
2527
};
2628

2729
p.draw = function () {
30+
p.push();
2831
p.background(200);
32+
fbo.begin()
33+
p.background('blue')
2934
p.strokeWeight(10);
35+
p.push()
36+
p.stroke('red')
3037
p.line(-100, -100, 100, 100);
38+
p.pop()
39+
p.translate(200, 200)
40+
p.line(-100, -100, 100, 100);
41+
fbo.end()
42+
p.image(fbo, 0, 0)
43+
p.pop();
3144
};
3245
};
3346

src/color/creating_reading.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,13 @@ function creatingReading(p5, fn){
5252
[OKLAB]: [100, [-125, 125], [-125, 125], 1],
5353
[OKLCH]: [100, 150, 360, 1],
5454
clone: function(){
55-
let ret = {};
56-
for(const key in this){
57-
if(typeof this[key] !== 'function'){
58-
ret[key] = structuredClone(this[key]);
59-
}else{
60-
ret[key] = this[key];
55+
const cloned = { ...this };
56+
for (const key in cloned) {
57+
if (cloned[key] instanceof Array) {
58+
cloned[key] = [...cloned[key]];
6159
}
6260
}
63-
return ret;
61+
return cloned;
6462
}
6563
};
6664

src/color/p5.Color.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import HSBSpace from './color_spaces/hsb.js';
3333
const map = (n, start1, stop1, start2, stop2) =>
3434
((n - start1) / (stop1 - start1) * (stop2 - start2) + start2);
3535

36+
const serializationMap = {};
37+
3638
class Color {
3739
// Reference to underlying color object depending on implementation
3840
// Not meant to be used publicly unless the implementation is known for sure
@@ -242,10 +244,16 @@ class Color {
242244
* </div>
243245
*/
244246
toString(format) {
245-
// NOTE: memoize
246-
return serialize(this._color, {
247-
format
248-
});
247+
const key = `${this._color.space.id}-${this._color.coords.join(",")}-${this._color.alpha}-${format}`;
248+
let colorString = serializationMap[key];
249+
250+
if(!colorString){
251+
colorString = serialize(this._color, {
252+
format
253+
});
254+
serializationMap[key] = colorString;
255+
}
256+
return colorString;
249257
}
250258

251259
/**

src/color/setting.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -964,9 +964,10 @@ function setting(p5, fn){
964964
].includes(mode)
965965
) {
966966
// Set color mode.
967-
this._renderer.states.colorMode = mode;
967+
this._renderer.states.setValue('colorMode', mode);
968968

969969
// Set color maxes.
970+
this._renderer.states.setValue('colorMaxes', this._renderer.states.colorMaxes.clone());
970971
const maxes = this._renderer.states.colorMaxes[mode];
971972
if (arguments.length === 2) {
972973
maxes[0] = max1; // Red
@@ -1335,7 +1336,7 @@ function setting(p5, fn){
13351336
* </div>
13361337
*/
13371338
fn.noStroke = function() {
1338-
this._renderer.states.strokeColor = null;
1339+
this._renderer.states.setValue('strokeColor', null);
13391340
return this;
13401341
};
13411342

src/core/States.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
export class States {
2+
#modified = {};
3+
4+
constructor(initialState) {
5+
for (const key in initialState) {
6+
this[key] = initialState[key];
7+
}
8+
}
9+
10+
setValue(key, value) {
11+
if (!(key in this.#modified)) {
12+
this.#modified[key] = this[key];
13+
}
14+
this[key] = value;
15+
}
16+
17+
getDiff() {
18+
const diff = this.#modified;
19+
this.#modified = {};
20+
return diff;
21+
}
22+
23+
getModified() {
24+
return this.#modified;
25+
}
26+
27+
applyDiff(prevModified) {
28+
for (const key in this.#modified) {
29+
this[key] = this.#modified[key];
30+
}
31+
this.#modified = prevModified;
32+
}
33+
}

src/core/p5.Renderer.js

Lines changed: 43 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import * as constants from '../core/constants';
99
import { Image } from '../image/p5.Image';
1010
import { Vector } from '../math/p5.Vector';
1111
import { Shape } from '../shape/custom_shapes';
12+
import { States } from './States';
1213

1314
class ClonableObject {
1415
constructor(obj = {}) {
@@ -70,15 +71,7 @@ class Renderer {
7071
}
7172

7273
// Renderer state machine
73-
this.states = Object.assign({}, Renderer.states);
74-
// Clone properties that support it
75-
for (const key in this.states) {
76-
if (this.states[key] instanceof Array) {
77-
this.states[key] = this.states[key].slice();
78-
} else if (this.states[key] && this.states[key].clone instanceof Function) {
79-
this.states[key] = this.states[key].clone();
80-
}
81-
}
74+
this.states = new States(Renderer.states);
8275

8376
this.states.strokeColor = new Color([0, 0, 0]);
8477
this.states.fillColor = new Color([255, 255, 255]);
@@ -122,33 +115,25 @@ class Renderer {
122115
// and push it into the push pop stack
123116
push() {
124117
this._pushPopDepth++;
125-
const currentStates = Object.assign({}, this.states);
126-
// Clone properties that support it
127-
for (const key in currentStates) {
128-
if (currentStates[key] instanceof Array) {
129-
currentStates[key] = currentStates[key].slice();
130-
} else if (currentStates[key] && currentStates[key].clone instanceof Function) {
131-
currentStates[key] = currentStates[key].clone();
132-
}
133-
}
134-
this._pushPopStack.push(currentStates);
135-
return currentStates;
118+
this._pushPopStack.push(this.states.getDiff());
136119
}
137120

138121
// Pop the previous states out of the push pop stack and
139122
// assign it back to the current state
140123
pop() {
141124
this._pushPopDepth--;
142-
Object.assign(this.states, this._pushPopStack.pop());
143-
this.updateShapeVertexProperties();
144-
this.updateShapeProperties();
125+
const diff = this._pushPopStack.pop() || {};
126+
const modified = this.states.getModified();
127+
this.states.applyDiff(diff);
128+
this.updateShapeVertexProperties(modified);
129+
this.updateShapeProperties(modified);
145130
}
146131

147132
bezierOrder(order) {
148133
if (order === undefined) {
149134
return this.states.bezierOrder;
150135
} else {
151-
this.states.bezierOrder = order;
136+
this.states.setValue('bezierOrder', order);
152137
this.updateShapeProperties();
153138
}
154139
}
@@ -165,6 +150,7 @@ class Renderer {
165150
if (value === undefined) {
166151
return this.states.splineProperties[key];
167152
} else {
153+
this.states.setValue('splineProperties', this.states.splineProperties.clone());
168154
this.states.splineProperties[key] = value;
169155
}
170156
this.updateShapeProperties();
@@ -192,7 +178,7 @@ class Renderer {
192178
if (d === undefined) {
193179
return this.states.curveDetail;
194180
} else {
195-
this.states.curveDetail = d;
181+
this.states.setValue('curveDetail', d);
196182
}
197183
}
198184

@@ -287,31 +273,31 @@ class Renderer {
287273
}
288274

289275
fill(...args) {
290-
this.states.fillSet = true;
291-
this.states.fillColor = this._pInst.color(...args);
276+
this.states.setValue('fillSet', true);
277+
this.states.setValue('fillColor', this._pInst.color(...args));
292278
this.updateShapeVertexProperties();
293279
}
294280

295281
noFill() {
296-
this.states.fillColor = null;
282+
this.states.setValue('fillColor', null);
297283
}
298284

299285
strokeWeight(w) {
300286
if (w === undefined) {
301287
return this.states.strokeWeight;
302288
} else {
303-
this.states.strokeWeight = w;
289+
this.states.setValue('strokeWeight', w);
304290
}
305291
}
306292

307293
stroke(...args) {
308-
this.states.strokeSet = true;
309-
this.states.strokeColor = this._pInst.color(...args);
294+
this.states.setValue('strokeSet', true);
295+
this.states.setValue('strokeColor', this._pInst.color(...args));
310296
this.updateShapeVertexProperties();
311297
}
312298

313299
noStroke() {
314-
this.states.strokeColor = null;
300+
this.states.setValue('strokeColor', null);
315301
}
316302

317303
getCommonVertexProperties() {
@@ -324,25 +310,31 @@ class Renderer {
324310
}
325311
}
326312

327-
updateShapeProperties() {
328-
this.currentShape.bezierOrder(this.states.bezierOrder);
329-
this.currentShape.splineProperty('ends', this.states.splineProperties.ends);
330-
this.currentShape.splineProperty('tightness', this.states.splineProperties.tightness);
313+
updateShapeProperties(modified) {
314+
if (!modified || modified.bezierOrder || modified.splineProperties) {
315+
const shape = this.currentShape;
316+
shape.bezierOrder(this.states.bezierOrder);
317+
shape.splineProperty('ends', this.states.splineProperties.ends);
318+
shape.splineProperty('tightness', this.states.splineProperties.tightness);
319+
}
331320
}
332321

333-
updateShapeVertexProperties() {
322+
updateShapeVertexProperties(modified) {
334323
const props = this.getCommonVertexProperties();
335-
for (const key in props) {
336-
this.currentShape[key](props[key]);
324+
if (!modified || Object.keys(modified).some((k) => k in props)) {
325+
const shape = this.currentShape;
326+
for (const key in props) {
327+
shape[key](props[key]);
328+
}
337329
}
338330
}
339331

340332
textSize(s) {
341333
if (typeof s === 'number') {
342-
this.states.textSize = s;
334+
this.states.setValue('textSize', s);
343335
if (!this.states.leadingSet) {
344336
// only use a default value if not previously set (#5181)
345-
this.states.textLeading = s * constants._DEFAULT_LEADMULT;
337+
this.states.setValue('textLeading', s * constants._DEFAULT_LEADMULT);
346338
}
347339
return this._applyTextProperties();
348340
}
@@ -352,8 +344,8 @@ class Renderer {
352344

353345
textLeading (l) {
354346
if (typeof l === 'number') {
355-
this.states.leadingSet = true;
356-
this.states.textLeading = l;
347+
this.states.setValue('leadingSet', true);
348+
this.states.setValue('textLeading', l);
357349
return this._pInst;
358350
}
359351

@@ -368,7 +360,7 @@ class Renderer {
368360
s === constants.BOLD ||
369361
s === constants.BOLDITALIC
370362
) {
371-
this.states.fontStyle = s;
363+
this.states.setValue('fontStyle', s);
372364
}
373365

374366
return this._applyTextProperties();
@@ -393,10 +385,10 @@ class Renderer {
393385

394386
textAlign (h, v) {
395387
if (typeof h !== 'undefined') {
396-
this.states.textAlign = h;
388+
this.states.setValue('textAlign', h);
397389

398390
if (typeof v !== 'undefined') {
399-
this.states.textBaseline = v;
391+
this.states.setValue('textBaseline', v);
400392
}
401393

402394
return this._applyTextProperties();
@@ -409,7 +401,7 @@ class Renderer {
409401
}
410402

411403
textWrap (wrapStyle) {
412-
this.states.textWrap = wrapStyle;
404+
this.states.setValue('textWrap', wrapStyle);
413405
return this.states.textWrap;
414406
}
415407

@@ -657,8 +649,8 @@ class Renderer {
657649

658650
_updateTextMetrics() {
659651
if (this._isOpenType()) {
660-
this.states.textAscent = this.states.textFont._textAscent();
661-
this.states.textDescent = this.states.textFont._textDescent();
652+
this.states.setValue('textAscent', this.states.textFont._textAscent());
653+
this.states.setValue('textDescent', this.states.textFont._textDescent());
662654
return this;
663655
}
664656

@@ -694,8 +686,8 @@ class Renderer {
694686

695687
document.body.removeChild(container);
696688

697-
this.states.textAscent = ascent;
698-
this.states.textDescent = descent;
689+
this.states.setValue('textAscent', ascent);
690+
this.states.setValue('textDescent', descent);
699691

700692
return this;
701693
}

0 commit comments

Comments
 (0)