From 604bf4e9ec8fe11fef5ee560bb0c0322a4dbf2b1 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 20 Apr 2024 13:37:21 +1000 Subject: [PATCH] perf(ui): use efficient group caching instead of a compositing rect Seems to be the same speed and it's less complex. --- .../store/regionalPromptsSlice.ts | 1 - .../regionalPrompts/util/renderers.ts | 33 ++++++++----------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/invokeai/frontend/web/src/features/regionalPrompts/store/regionalPromptsSlice.ts b/invokeai/frontend/web/src/features/regionalPrompts/store/regionalPromptsSlice.ts index 34616df99a..a833b9a832 100644 --- a/invokeai/frontend/web/src/features/regionalPrompts/store/regionalPromptsSlice.ts +++ b/invokeai/frontend/web/src/features/regionalPrompts/store/regionalPromptsSlice.ts @@ -355,7 +355,6 @@ const getRPLayerId = (layerId: string) => `rp_layer_${layerId}`; const getRPLayerLineId = (layerId: string, lineId: string) => `${layerId}.line_${lineId}`; export const getRPLayerObjectGroupId = (layerId: string, groupId: string) => `${layerId}.objectGroup_${groupId}`; export const getPRLayerBboxId = (layerId: string) => `${layerId}.bbox`; -export const getRPLayerTransparencyRectId = (layerId: string) => `${layerId}.transparency_rect`; export const regionalPromptsPersistConfig: PersistConfig = { name: regionalPromptsSlice.name, diff --git a/invokeai/frontend/web/src/features/regionalPrompts/util/renderers.ts b/invokeai/frontend/web/src/features/regionalPrompts/util/renderers.ts index a7da4b7613..154d2cd9c2 100644 --- a/invokeai/frontend/web/src/features/regionalPrompts/util/renderers.ts +++ b/invokeai/frontend/web/src/features/regionalPrompts/util/renderers.ts @@ -9,7 +9,6 @@ import { BRUSH_PREVIEW_LAYER_ID, getPRLayerBboxId, getRPLayerObjectGroupId, - getRPLayerTransparencyRectId, REGIONAL_PROMPT_LAYER_BBOX_NAME, REGIONAL_PROMPT_LAYER_LINE_NAME, REGIONAL_PROMPT_LAYER_NAME, @@ -192,16 +191,6 @@ const renderRPLayer = ( }); konvaLayer.add(konvaObjectGroup); - // To achieve performant transparency, we use the `source-in` blending mode on a rect that covers the entire layer. - // The brush strokes group functions as a mask for this rect, which has the layer's fill and opacity. The brush - // strokes' color doesn't matter - the only requirement is that they are not transparent. - const transparencyRect = new Konva.Rect({ - id: getRPLayerTransparencyRectId(rpLayer.id), - globalCompositeOperation: 'source-in', - listening: false, - }); - konvaLayer.add(transparencyRect); - stage.add(konvaLayer); // When a layer is added, it ends up on top of the brush preview - we need to move the preview back to the top. @@ -223,14 +212,20 @@ const renderRPLayer = ( const konvaObjectGroup = konvaLayer.findOne(`.${REGIONAL_PROMPT_LAYER_OBJECT_GROUP_NAME}`); assert(konvaObjectGroup, `Object group not found for layer ${rpLayer.id}`); - const transparencyRect = konvaLayer.findOne(`#${getRPLayerTransparencyRectId(rpLayer.id)}`); - assert(transparencyRect, `Transparency rect not found for layer ${rpLayer.id}`); + // We use caching to handle "global" layer opacity, but caching is expensive and we should only do it when required. + let groupNeedsCache = false; + + if (konvaObjectGroup.opacity() !== layerOpacity) { + konvaObjectGroup.opacity(layerOpacity); + groupNeedsCache = true; + } // Remove deleted objects const objectIds = rpLayer.objects.map(mapId); for (const objectNode of konvaLayer.find(`.${REGIONAL_PROMPT_LAYER_LINE_NAME}`)) { if (!objectIds.includes(objectNode.id())) { objectNode.destroy(); + groupNeedsCache = true; } } @@ -262,23 +257,23 @@ const renderRPLayer = ( // Only update the points if they have changed. The point values are never mutated, they are only added to the array. if (konvaObject.points().length !== reduxObject.points.length) { konvaObject.points(reduxObject.points); + groupNeedsCache = true; } // Only update the color if it has changed. if (konvaObject.stroke() !== color) { konvaObject.stroke(color); + groupNeedsCache = true; } // Only update layer visibility if it has changed. if (konvaObject.visible() !== rpLayer.isVisible) { konvaObject.visible(rpLayer.isVisible); + groupNeedsCache = true; } } - // Set the layer opacity - must happen after all objects are added to the layer so the rect is the right size - transparencyRect.setAttrs({ - ...konvaLayer.getClientRect({ skipTransform: true }), - fill: color, - opacity: layerOpacity, - }); + if (groupNeedsCache) { + konvaObjectGroup.cache(); + } }; /**