diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 5f8e2070c37..56619756283 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1775,6 +1775,20 @@ "Structure controls how closely the output image will keep to the layout of the original. Low structure allows major changes, while high structure strictly maintains the original composition and layout." ] }, + "tileSize": { + "heading": "Tile Size", + "paragraphs": [ + "Controls the size of tiles used during the upscaling process. Larger tiles use more memory but may produce better results.", + "SD1.5 models default to 768, while SDXL models default to 1024. Reduce tile size if you encounter memory issues." + ] + }, + "tileOverlap": { + "heading": "Tile Overlap", + "paragraphs": [ + "Controls the overlap between adjacent tiles during upscaling. Higher overlap values help reduce visible seams between tiles but use more memory.", + "The default value of 128 works well for most cases, but you can adjust based on your specific needs and memory constraints." + ] + }, "fluxDevLicense": { "heading": "Non-Commercial License", "paragraphs": [ @@ -2396,6 +2410,8 @@ "upscaleModel": "Upscale Model", "postProcessingModel": "Post-Processing Model", "scale": "Scale", + "tileSize": "Tile Size", + "tileOverlap": "Tile Overlap", "postProcessingMissingModelWarning": "Visit the Model Manager to install a post-processing (image to image) model.", "missingModelsWarning": "Visit the Model Manager to install the required models:", "mainModelDesc": "Main model (SD1.5 or SDXL architecture)", diff --git a/invokeai/frontend/web/src/common/components/InformationalPopover/constants.ts b/invokeai/frontend/web/src/common/components/InformationalPopover/constants.ts index f115ab3a640..22a813b6de1 100644 --- a/invokeai/frontend/web/src/common/components/InformationalPopover/constants.ts +++ b/invokeai/frontend/web/src/common/components/InformationalPopover/constants.ts @@ -67,6 +67,8 @@ export type Feature = | 'scale' | 'creativity' | 'structure' + | 'tileSize' + | 'tileOverlap' | 'optimizedDenoising' | 'fluxDevLicense'; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts index 7c6192e06a4..fafedd1a5df 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/buildMultidiffusionUpscaleGraph.ts @@ -12,7 +12,16 @@ import type { GraphBuilderReturn } from './types'; export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise => { const { model, upscaleCfgScale: cfg_scale, upscaleScheduler: scheduler, steps, vaePrecision, vae } = state.params; - const { upscaleModel, upscaleInitialImage, structure, creativity, tileControlnetModel, scale } = state.upscale; + const { + upscaleModel, + upscaleInitialImage, + structure, + creativity, + tileControlnetModel, + scale, + tileSize, + tileOverlap, + } = state.upscale; assert(model, 'No model selected'); assert(model.base === 'sd-1' || model.base === 'sdxl', 'Multi-Diffusion upscaling requires a SD1.5 or SDXL model'); @@ -62,7 +71,7 @@ export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise type: 'i2l', id: getPrefixedId('i2l'), fp32: vaePrecision === 'fp32', - tile_size: 1024, + tile_size: tileSize, tiled: true, }); @@ -72,7 +81,7 @@ export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise type: 'l2i', id: getPrefixedId('l2i'), fp32: vaePrecision === 'fp32', - tile_size: 1024, + tile_size: tileSize, tiled: true, board: getBoardField(state), is_intermediate: false, @@ -81,9 +90,9 @@ export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise const tiledMultidiffusion = g.addNode({ type: 'tiled_multi_diffusion_denoise_latents', id: getPrefixedId('tiled_multidiffusion_denoise_latents'), - tile_height: 1024, // is this dependent on base model - tile_width: 1024, // is this dependent on base model - tile_overlap: 128, + tile_height: tileSize, + tile_width: tileSize, + tile_overlap: tileOverlap || 128, steps, cfg_scale, scheduler, @@ -184,6 +193,8 @@ export const buildMultidiffusionUpscaleGraph = async (state: RootState): Promise upscale_model: Graph.getModelMetadataField(upscaleModelConfig), creativity, structure, + tile_size: tileSize, + tile_overlap: tileOverlap || 128, upscale_initial_image: { image_name: upscaleInitialImage.image_name, width: upscaleInitialImage.width, diff --git a/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamTileOverlap.tsx b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamTileOverlap.tsx new file mode 100644 index 00000000000..7834e53309b --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamTileOverlap.tsx @@ -0,0 +1,53 @@ +import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { selectTileOverlap, tileOverlapChanged } from 'features/parameters/store/upscaleSlice'; +import { useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; + +const initial = 128; +const sliderMin = 32; +const sliderMax = 256; +const numberInputMin = 16; +const numberInputMax = 512; +const coarseStep = 16; +const fineStep = 8; +const marks = [sliderMin, 128, sliderMax]; + +const ParamTileOverlap = () => { + const tileOverlap = useAppSelector(selectTileOverlap); + const dispatch = useAppDispatch(); + const { t } = useTranslation(); + const onChange = useCallback( + (v: number) => { + dispatch(tileOverlapChanged(v)); + }, + [dispatch] + ); + + return ( + + {t('upscaling.tileOverlap')} + + + + ); +}; + +export default ParamTileOverlap; diff --git a/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamTileSize.tsx b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamTileSize.tsx new file mode 100644 index 00000000000..c0443cb6fe1 --- /dev/null +++ b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamTileSize.tsx @@ -0,0 +1,53 @@ +import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { selectTileSize, tileSizeChanged } from 'features/parameters/store/upscaleSlice'; +import { useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; + +const initial = 1024; +const sliderMin = 512; +const sliderMax = 1536; +const numberInputMin = 512; +const numberInputMax = 1536; +const coarseStep = 64; +const fineStep = 64; +const marks = [sliderMin, 1024, sliderMax]; + +const ParamTileSize = () => { + const tileSize = useAppSelector(selectTileSize); + const dispatch = useAppDispatch(); + const { t } = useTranslation(); + const onChange = useCallback( + (v: number) => { + dispatch(tileSizeChanged(v)); + }, + [dispatch] + ); + + return ( + + {t('upscaling.tileSize')} + + + + ); +}; + +export default ParamTileSize; diff --git a/invokeai/frontend/web/src/features/parameters/store/upscaleSlice.ts b/invokeai/frontend/web/src/features/parameters/store/upscaleSlice.ts index a3fa9ae0aae..294d88fb481 100644 --- a/invokeai/frontend/web/src/features/parameters/store/upscaleSlice.ts +++ b/invokeai/frontend/web/src/features/parameters/store/upscaleSlice.ts @@ -13,6 +13,8 @@ export interface UpscaleState { tileControlnetModel: ControlNetModelConfig | null; scale: number; postProcessingModel: ParameterSpandrelImageToImageModel | null; + tileSize: number; + tileOverlap: number; } const initialUpscaleState: UpscaleState = { @@ -24,6 +26,8 @@ const initialUpscaleState: UpscaleState = { tileControlnetModel: null, scale: 4, postProcessingModel: null, + tileSize: 1024, + tileOverlap: 128, }; export const upscaleSlice = createSlice({ @@ -51,6 +55,12 @@ export const upscaleSlice = createSlice({ postProcessingModelChanged: (state, action: PayloadAction) => { state.postProcessingModel = action.payload; }, + tileSizeChanged: (state, action: PayloadAction) => { + state.tileSize = action.payload; + }, + tileOverlapChanged: (state, action: PayloadAction) => { + state.tileOverlap = action.payload; + }, }, }); @@ -62,6 +72,8 @@ export const { tileControlnetModelChanged, scaleChanged, postProcessingModelChanged, + tileSizeChanged, + tileOverlapChanged, } = upscaleSlice.actions; /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ @@ -88,3 +100,5 @@ export const selectTileControlNetModel = createUpscaleSelector((upscale) => upsc export const selectStructure = createUpscaleSelector((upscale) => upscale.structure); export const selectUpscaleInitialImage = createUpscaleSelector((upscale) => upscale.upscaleInitialImage); export const selectUpscaleScale = createUpscaleSelector((upscale) => upscale.scale); +export const selectTileSize = createUpscaleSelector((upscale) => upscale.tileSize); +export const selectTileOverlap = createUpscaleSelector((upscale) => upscale.tileOverlap); diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/UpscaleTabAdvancedSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/UpscaleTabAdvancedSettingsAccordion.tsx index 4aa0708ac03..efeddb35940 100644 --- a/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/UpscaleTabAdvancedSettingsAccordion.tsx +++ b/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/UpscaleTabAdvancedSettingsAccordion.tsx @@ -4,6 +4,8 @@ import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { useAppSelector } from 'app/store/storeHooks'; import { selectIsFLUX, selectIsSD3, selectParamsSlice, selectVAEKey } from 'features/controlLayers/store/paramsSlice'; import { ParamSeed } from 'features/parameters/components/Seed/ParamSeed'; +import ParamTileOverlap from 'features/parameters/components/Upscale/ParamTileOverlap'; +import ParamTileSize from 'features/parameters/components/Upscale/ParamTileSize'; import ParamFLUXVAEModelSelect from 'features/parameters/components/VAEModel/ParamFLUXVAEModelSelect'; import ParamVAEModelSelect from 'features/parameters/components/VAEModel/ParamVAEModelSelect'; import ParamVAEPrecision from 'features/parameters/components/VAEModel/ParamVAEPrecision'; @@ -73,6 +75,8 @@ export const UpscaleTabAdvancedSettingsAccordion = memo(() => { {!isFLUX && !isSD3 && } + + );