mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 06:20:11 +00:00
fix: cap preview resolution and extract limits from node definition
- Clamp render resolution to 1024px max dimension for browser perf - Extract maxInputs/maxFloatUniforms/maxIntUniforms from node autogrow config - Lazily create renderer with node-specific config - Pass dynamic limits to uniform value loops Amp-Thread-ID: https://ampcode.com/threads/T-019ca2a6-bf8d-75fc-b497-d0338562b57f
This commit is contained in:
@@ -7,11 +7,53 @@ import type { UUID } from '@/lib/litegraph/src/utils/uuid'
|
||||
import { useNodeOutputStore } from '@/stores/imagePreviewStore'
|
||||
import { useWidgetValueStore } from '@/stores/widgetValueStore'
|
||||
|
||||
import type { GLSLRendererConfig } from '@/renderer/glsl/useGLSLRenderer'
|
||||
import { useGLSLRenderer } from '@/renderer/glsl/useGLSLRenderer'
|
||||
|
||||
const GLSL_NODE_TYPE = 'GLSLShader'
|
||||
const DEBOUNCE_MS = 50
|
||||
const DEFAULT_SIZE = 512
|
||||
const MAX_PREVIEW_DIMENSION = 1024
|
||||
|
||||
interface AutogrowGroup {
|
||||
max: number
|
||||
min: number
|
||||
prefix?: string
|
||||
}
|
||||
|
||||
function getAutogrowLimits(node: LGraphNode): GLSLRendererConfig {
|
||||
const defaults: GLSLRendererConfig = {
|
||||
maxInputs: 5,
|
||||
maxFloatUniforms: 5,
|
||||
maxIntUniforms: 5
|
||||
}
|
||||
|
||||
if (!('comfyDynamic' in node)) return defaults
|
||||
|
||||
const dynamic = node.comfyDynamic
|
||||
if (
|
||||
typeof dynamic !== 'object' ||
|
||||
dynamic === null ||
|
||||
!('autogrow' in dynamic)
|
||||
)
|
||||
return defaults
|
||||
|
||||
const groups = dynamic.autogrow as Record<string, AutogrowGroup> | undefined
|
||||
if (!groups) return defaults
|
||||
|
||||
return {
|
||||
maxInputs: groups['images']?.max ?? defaults.maxInputs,
|
||||
maxFloatUniforms: groups['floats']?.max ?? defaults.maxFloatUniforms,
|
||||
maxIntUniforms: groups['ints']?.max ?? defaults.maxIntUniforms
|
||||
}
|
||||
}
|
||||
|
||||
function clampResolution(w: number, h: number): [number, number] {
|
||||
const maxDim = Math.max(w, h)
|
||||
if (maxDim <= MAX_PREVIEW_DIMENSION) return [w, h]
|
||||
const scale = MAX_PREVIEW_DIMENSION / maxDim
|
||||
return [Math.round(w * scale), Math.round(h * scale)]
|
||||
}
|
||||
|
||||
export function useGLSLPreview(
|
||||
nodeMaybe: MaybeRefOrGetter<LGraphNode | null | undefined>
|
||||
@@ -20,7 +62,7 @@ export function useGLSLPreview(
|
||||
const widgetValueStore = useWidgetValueStore()
|
||||
const nodeOutputStore = useNodeOutputStore()
|
||||
|
||||
const renderer = useGLSLRenderer()
|
||||
let renderer: ReturnType<typeof useGLSLRenderer> | null = null
|
||||
let rendererReady = false
|
||||
let currentBlobUrl: string | null = null
|
||||
|
||||
@@ -49,13 +91,19 @@ export function useGLSLPreview(
|
||||
| undefined
|
||||
})
|
||||
|
||||
const rendererConfig = computed(() => {
|
||||
const node = nodeRef.value
|
||||
if (!node) return { maxInputs: 5, maxFloatUniforms: 5, maxIntUniforms: 5 }
|
||||
return getAutogrowLimits(node)
|
||||
})
|
||||
|
||||
const floatValues = computed(() => {
|
||||
const gId = graphId.value
|
||||
const nId = nodeId.value
|
||||
if (!gId || nId == null) return []
|
||||
|
||||
const values: number[] = []
|
||||
for (let i = 0; i < 5; i++) {
|
||||
for (let i = 0; i < rendererConfig.value.maxFloatUniforms; i++) {
|
||||
const widget = widgetValueStore.getWidget(gId, nId, `floats.u_float${i}`)
|
||||
if (widget === undefined) break
|
||||
values.push(Number(widget.value) || 0)
|
||||
@@ -69,7 +117,7 @@ export function useGLSLPreview(
|
||||
if (!gId || nId == null) return []
|
||||
|
||||
const values: number[] = []
|
||||
for (let i = 0; i < 5; i++) {
|
||||
for (let i = 0; i < rendererConfig.value.maxIntUniforms; i++) {
|
||||
const widget = widgetValueStore.getWidget(gId, nId, `ints.u_int${i}`)
|
||||
if (widget === undefined) break
|
||||
values.push(Number(widget.value) || 0)
|
||||
@@ -86,7 +134,7 @@ export function useGLSLPreview(
|
||||
|
||||
function loadInputImages(): void {
|
||||
const node = nodeRef.value
|
||||
if (!node?.inputs) return
|
||||
if (!node?.inputs || !renderer) return
|
||||
|
||||
let imageSlotIndex = 0
|
||||
for (let slot = 0; slot < node.inputs.length; slot++) {
|
||||
@@ -116,10 +164,10 @@ export function useGLSLPreview(
|
||||
if (!upstreamNode?.imgs?.length) continue
|
||||
|
||||
const img = upstreamNode.imgs[0]
|
||||
return [
|
||||
return clampResolution(
|
||||
img.naturalWidth || DEFAULT_SIZE,
|
||||
img.naturalHeight || DEFAULT_SIZE
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
const gId = graphId.value
|
||||
@@ -136,30 +184,39 @@ export function useGLSLPreview(
|
||||
'size_mode.height'
|
||||
)
|
||||
if (widthWidget && heightWidget) {
|
||||
return [
|
||||
return clampResolution(
|
||||
Number(widthWidget.value) || DEFAULT_SIZE,
|
||||
Number(heightWidget.value) || DEFAULT_SIZE
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return [DEFAULT_SIZE, DEFAULT_SIZE]
|
||||
}
|
||||
|
||||
function ensureRenderer(): ReturnType<typeof useGLSLRenderer> {
|
||||
if (!renderer) {
|
||||
renderer = useGLSLRenderer(rendererConfig.value)
|
||||
}
|
||||
return renderer
|
||||
}
|
||||
|
||||
async function renderPreview(): Promise<void> {
|
||||
const source = shaderSource.value
|
||||
if (!source || !isActive.value) return
|
||||
|
||||
const r = ensureRenderer()
|
||||
|
||||
if (!rendererReady) {
|
||||
const [w, h] = getResolution()
|
||||
if (!renderer.init(w, h)) {
|
||||
if (!r.init(w, h)) {
|
||||
lastError.value = 'WebGL2 not available'
|
||||
return
|
||||
}
|
||||
rendererReady = true
|
||||
}
|
||||
|
||||
const result = renderer.compileFragment(source)
|
||||
const result = r.compileFragment(source)
|
||||
if (!result.success) {
|
||||
lastError.value = result.log
|
||||
return
|
||||
@@ -167,20 +224,20 @@ export function useGLSLPreview(
|
||||
lastError.value = null
|
||||
|
||||
const [w, h] = getResolution()
|
||||
renderer.setResolution(w, h)
|
||||
r.setResolution(w, h)
|
||||
|
||||
loadInputImages()
|
||||
|
||||
for (let i = 0; i < floatValues.value.length; i++) {
|
||||
renderer.setFloatUniform(i, floatValues.value[i])
|
||||
r.setFloatUniform(i, floatValues.value[i])
|
||||
}
|
||||
for (let i = 0; i < intValues.value.length; i++) {
|
||||
renderer.setIntUniform(i, intValues.value[i])
|
||||
r.setIntUniform(i, intValues.value[i])
|
||||
}
|
||||
|
||||
renderer.render()
|
||||
r.render()
|
||||
|
||||
const blob = await renderer.toBlob()
|
||||
const blob = await r.toBlob()
|
||||
revokeBlobUrl()
|
||||
currentBlobUrl = URL.createObjectURL(blob)
|
||||
|
||||
@@ -209,7 +266,7 @@ export function useGLSLPreview(
|
||||
function dispose(): void {
|
||||
debouncedRender.cancel()
|
||||
revokeBlobUrl()
|
||||
renderer.dispose()
|
||||
renderer?.dispose()
|
||||
}
|
||||
|
||||
onScopeDispose(dispose)
|
||||
|
||||
Reference in New Issue
Block a user