Skip to content

Commit

Permalink
fix: dispose image texture and svg geometry + materials
Browse files Browse the repository at this point in the history
bbohlender committed Jul 3, 2024
1 parent 66d51ca commit 80f6495
Showing 3 changed files with 50 additions and 5 deletions.
12 changes: 9 additions & 3 deletions packages/uikit/src/components/image.ts
Original file line number Diff line number Diff line change
@@ -107,7 +107,7 @@ export function createImage(
setupCursorCleanup(hoveredSignal, initializers)

const src = computed(() => readReactive(style.value?.src) ?? readReactive(properties.value?.src))
loadResourceWithParams(texture, loadTextureImpl, initializers, src)
loadResourceWithParams(texture, loadTextureImpl, cleanupTexture, initializers, src)

const textureAspectRatio = computed(() => {
const tex = texture.value
@@ -354,7 +354,13 @@ function transformInsideBorder(

const textureLoader = new TextureLoader()

async function loadTextureImpl(src?: string | Texture) {
function cleanupTexture(texture: (Texture & { disposable?: boolean }) | undefined): void {
if (texture?.disposable === true) {
texture.dispose()
}
}

async function loadTextureImpl(src?: string | Texture): Promise<(Texture & { disposable?: boolean }) | undefined> {
if (src == null) {
return Promise.resolve(undefined)
}
@@ -365,7 +371,7 @@ async function loadTextureImpl(src?: string | Texture) {
const texture = await textureLoader.loadAsync(src)
texture.colorSpace = SRGBColorSpace
texture.matrixAutoUpdate = false
return texture
return Object.assign(texture, { disposable: true })
} catch (error) {
console.error(error)
return undefined
15 changes: 14 additions & 1 deletion packages/uikit/src/components/svg.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import { Signal, computed, effect, signal } from '@preact/signals-core'
import { Box3, Group, Mesh, MeshBasicMaterial, Object3D, Plane, ShapeGeometry, Vector3 } from 'three'
import {
Box3,
BufferGeometry,
Group,
Material,
Mesh,
MeshBasicMaterial,
Object3D,
Plane,
ShapeGeometry,
Vector3,
} from 'three'
import { Listeners } from '../index.js'
import { Object3DRef, ParentContext, RootContext } from '../context.js'
import { FlexNode, FlexNodeState, YogaProperties, createFlexNodeState } from '../flex/index.js'
@@ -26,6 +37,7 @@ import {
computedIsVisible,
computedMergedProperties,
createNode,
disposeGroup,
keepAspectRatioPropertyTransformer,
loadResourceWithParams,
} from './utils.js'
@@ -143,6 +155,7 @@ export function createSvg(
loadResourceWithParams(
svgObject,
loadSvg,
disposeGroup,
initializers,
src,
parentContext.root,
28 changes: 27 additions & 1 deletion packages/uikit/src/components/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Signal, computed, effect } from '@preact/signals-core'
import { Color, Matrix4, Mesh, MeshBasicMaterial, Object3D } from 'three'
import { BufferGeometry, Color, Material, Matrix4, Mesh, MeshBasicMaterial, Object3D } from 'three'
import { WithActive, addActiveHandlers } from '../active.js'
import { WithPreferredColorScheme } from '../dark.js'
import { WithHover, addHoverHandlers } from '../hover.js'
@@ -16,6 +16,22 @@ import {
computedInheritableProperty,
} from '../properties/index.js'

export function disposeGroup(object: Object3D | undefined) {
object?.traverse((mesh) => {
if (!(mesh instanceof Mesh)) {
return
}

if (mesh.material instanceof Material) {
mesh.material.dispose()
}

if (mesh.geometry instanceof BufferGeometry) {
mesh.geometry.dispose()
}
})
}

export function computedGlobalMatrix(
parentMatrix: Signal<Matrix4 | undefined>,
localMatrix: Signal<Matrix4 | undefined>,
@@ -52,6 +68,7 @@ export type WithConditionals<T> = WithHover<T> & WithResponsive<T> & WithPreferr
export function loadResourceWithParams<P, R, A extends Array<unknown>>(
target: Signal<R | undefined>,
fn: (param: P, ...additional: A) => Promise<R>,
cleanup: ((value: R) => void) | undefined,
initializers: Initializers,
param: Signal<P> | P,
...additionals: A
@@ -72,6 +89,15 @@ export function loadResourceWithParams<P, R, A extends Array<unknown>>(
return () => (canceled = true)
}),
)
if (cleanup != null) {
subscriptions.push(() => {
const { value } = target
if (value == null) {
return
}
cleanup(value)
})
}
return subscriptions
})
}

0 comments on commit 80f6495

Please sign in to comment.