mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-13 17:10:06 +00:00
GPU accelerated maskeditor rendering (#6767)
## GPU accelerated brush engine for the mask editor - Full GPU acceleration using TypeGPU and type-safe shaders - Catmull-Rom Spline Smoothing - arc-length equidistant resampling - much improved performance, even for huge images - photoshop like opacity clamping for brush strokes - much improved soft brushes - fallback to CPU fully implemented, much improved CPU rendering features as well ### Tested Browsers - Chrome (fully supported) - Safari 26 (fully supported, prev versions CPU fallback) - Firefox (CPU fallback, flags needed for full support) https://github.com/user-attachments/assets/b7b5cb8a-2290-4a95-ae7d-180e11fccdb0 https://github.com/user-attachments/assets/4297aaa5-f249-499a-9b74-869677f1c73b https://github.com/user-attachments/assets/602b4783-3e2b-489e-bcb9-70534bcaac5e ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6767-GPU-accelerated-maskeditor-rendering-2b16d73d3650818cb294e1fca03f6169) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -22,7 +22,7 @@ export const useMaskEditorStore = defineStore('maskEditor', () => {
|
||||
size: 10,
|
||||
opacity: 0.7,
|
||||
hardness: 1,
|
||||
smoothingPrecision: 10
|
||||
stepSize: 10
|
||||
})
|
||||
|
||||
const maskBlendMode = ref<MaskBlendMode>(MaskBlendMode.Black)
|
||||
@@ -50,6 +50,7 @@ export const useMaskEditorStore = defineStore('maskEditor', () => {
|
||||
const panOffset = ref<Offset>({ x: 0, y: 0 })
|
||||
const cursorPoint = ref<Point>({ x: 0, y: 0 })
|
||||
const resetZoomTrigger = ref<number>(0)
|
||||
const clearTrigger = ref<number>(0)
|
||||
|
||||
const maskCanvas = ref<HTMLCanvasElement | null>(null)
|
||||
const maskCtx = ref<CanvasRenderingContext2D | null>(null)
|
||||
@@ -70,6 +71,8 @@ export const useMaskEditorStore = defineStore('maskEditor', () => {
|
||||
|
||||
const canvasHistory = useCanvasHistory(20)
|
||||
|
||||
const tgpuRoot = ref<any>(null)
|
||||
|
||||
watch(maskCanvas, (canvas) => {
|
||||
if (canvas) {
|
||||
maskCtx.value = canvas.getContext('2d', { willReadFrequently: true })
|
||||
@@ -110,7 +113,7 @@ export const useMaskEditorStore = defineStore('maskEditor', () => {
|
||||
})
|
||||
|
||||
function setBrushSize(size: number): void {
|
||||
brushSettings.value.size = _.clamp(size, 1, 100)
|
||||
brushSettings.value.size = _.clamp(size, 1, 500)
|
||||
}
|
||||
|
||||
function setBrushOpacity(opacity: number): void {
|
||||
@@ -121,8 +124,8 @@ export const useMaskEditorStore = defineStore('maskEditor', () => {
|
||||
brushSettings.value.hardness = _.clamp(hardness, 0, 1)
|
||||
}
|
||||
|
||||
function setBrushSmoothingPrecision(precision: number): void {
|
||||
brushSettings.value.smoothingPrecision = _.clamp(precision, 1, 100)
|
||||
function setBrushStepSize(step: number): void {
|
||||
brushSettings.value.stepSize = _.clamp(step, 1, 100)
|
||||
}
|
||||
|
||||
function resetBrushToDefault(): void {
|
||||
@@ -130,7 +133,7 @@ export const useMaskEditorStore = defineStore('maskEditor', () => {
|
||||
brushSettings.value.size = 20
|
||||
brushSettings.value.opacity = 1
|
||||
brushSettings.value.hardness = 1
|
||||
brushSettings.value.smoothingPrecision = 60
|
||||
brushSettings.value.stepSize = 5
|
||||
}
|
||||
|
||||
function setPaintBucketTolerance(tolerance: number): void {
|
||||
@@ -169,6 +172,10 @@ export const useMaskEditorStore = defineStore('maskEditor', () => {
|
||||
resetZoomTrigger.value++
|
||||
}
|
||||
|
||||
function triggerClear(): void {
|
||||
clearTrigger.value++
|
||||
}
|
||||
|
||||
function setMaskOpacity(opacity: number): void {
|
||||
maskOpacity.value = _.clamp(opacity, 0, 1)
|
||||
}
|
||||
@@ -179,7 +186,7 @@ export const useMaskEditorStore = defineStore('maskEditor', () => {
|
||||
size: 10,
|
||||
opacity: 0.7,
|
||||
hardness: 1,
|
||||
smoothingPrecision: 10
|
||||
stepSize: 5
|
||||
}
|
||||
maskBlendMode.value = MaskBlendMode.Black
|
||||
activeLayer.value = 'mask'
|
||||
@@ -243,10 +250,12 @@ export const useMaskEditorStore = defineStore('maskEditor', () => {
|
||||
|
||||
canvasHistory,
|
||||
|
||||
tgpuRoot,
|
||||
|
||||
setBrushSize,
|
||||
setBrushOpacity,
|
||||
setBrushHardness,
|
||||
setBrushSmoothingPrecision,
|
||||
setBrushStepSize,
|
||||
resetBrushToDefault,
|
||||
setPaintBucketTolerance,
|
||||
setFillOpacity,
|
||||
@@ -257,6 +266,8 @@ export const useMaskEditorStore = defineStore('maskEditor', () => {
|
||||
setPanOffset,
|
||||
setCursorPoint,
|
||||
resetZoom,
|
||||
triggerClear,
|
||||
clearTrigger,
|
||||
setMaskOpacity,
|
||||
resetState
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user