Files
Robert Wojciechowski 3058b11ff2 Remove list splitter/collector feature and refactor distributed modules
- Remove DistributedListSplitter and DistributedListCollector nodes
- Remove /distributed/init_list_queue and /distributed/request_list_item endpoints
- Clean up all references from prompt_transform, queue_orchestration, constants, and tests
- Refactor and reorganize distributed modules for quality improvements
2026-03-07 05:22:09 +00:00

105 lines
3.9 KiB
Python

from __future__ import annotations
import math, torch
from typing import Any
from ...utils.logging import log
from ...utils.image import blend_processed_batch_item, pil_to_tensor, tensor_to_pil
from ..mode_contexts import SingleGpuModeContext, TileOpsCollaborator
from ..processing_args import UpscaleCoreArgs
from ..tile_processing import TileBatchArgs, extract_and_process_tile_batch
class SingleGpuModeMixin:
def _build_single_gpu_mode_context(self) -> SingleGpuModeContext:
"""Build explicit collaborators for single-GPU mode execution."""
return SingleGpuModeContext(tile_ops=TileOpsCollaborator(self))
def process_single_gpu(
self,
upscaled_image: torch.Tensor,
core_args: UpscaleCoreArgs,
tile_width: int,
tile_height: int,
padding: int,
mask_blur: int,
force_uniform_tiles: bool,
mode_context: SingleGpuModeContext | None = None,
) -> tuple[torch.Tensor]:
"""Process all tiles on a single GPU (no distribution), batching per tile like USDU."""
context = mode_context or self._build_single_gpu_mode_context()
ops = context.tile_ops
# Round tile dimensions
tile_width = ops.round_to_multiple(tile_width)
tile_height = ops.round_to_multiple(tile_height)
# Get image dimensions and batch size
batch_size, height, width, _ = upscaled_image.shape
# Calculate all tiles
all_tiles = ops.calculate_tiles(width, height, tile_width, tile_height, force_uniform_tiles)
rows = math.ceil(height / tile_height)
cols = math.ceil(width / tile_width)
log(
f"USDU Dist: Single GPU | Canvas {width}x{height} | Tile {tile_width}x{tile_height} | Grid {rows}x{cols} ({len(all_tiles)} tiles/image) | Batch {batch_size}"
)
tile_batch_args = TileBatchArgs(
core=core_args,
tile_width=tile_width,
tile_height=tile_height,
padding=padding,
force_uniform_tiles=force_uniform_tiles,
width=width,
height=height,
)
# Prepare result images list
result_images = []
for b in range(batch_size):
image_pil = tensor_to_pil(upscaled_image[b:b+1], 0).convert('RGB')
result_images.append(image_pil.copy())
# Precompute tile masks once
tile_masks = []
for tx, ty in all_tiles:
tile_masks.append(ops.create_tile_mask(width, height, tx, ty, tile_width, tile_height, mask_blur))
# Process tiles batched across images
for tile_idx, (tx, ty) in enumerate(all_tiles):
# Progressive state parity: extract each tile from the current updated image batch.
source_batch = torch.cat([pil_to_tensor(img) for img in result_images], dim=0)
if upscaled_image.is_cuda:
source_batch = source_batch.cuda()
processed_batch, x1, y1, ew, eh = extract_and_process_tile_batch(
node=ops,
upscaled_image=source_batch,
tx=tx,
ty=ty,
args=tile_batch_args,
)
# Blend results back into each image using cached mask
tile_mask = tile_masks[tile_idx]
for b in range(batch_size):
blend_processed_batch_item(
result_images,
processed_batch,
b,
ops.blend_tile,
x1,
y1,
ew,
eh,
tile_mask,
padding,
)
# Convert back to tensor
result_tensors = [pil_to_tensor(img) for img in result_images]
result_tensor = torch.cat(result_tensors, dim=0)
if upscaled_image.is_cuda:
result_tensor = result_tensor.cuda()
return (result_tensor,)