Component: corelib — TfpgCanvasBase / THybridCanvas (software renderer)
Description:
The only way to draw an image onto a canvas is DrawImage/DrawImagePart, which always routes through the transparency path. On the hybrid (software/AggPas) renderer this means every image goes through AggPas's per-pixel alpha-blend rasteriser (transformImage → BGRA32_BLEND_SOLID_HSPAN), and for masked images it first builds a temporary alpha-applied copy of the whole image. For fully opaque content — background tiles, double-buffered composites, screenshots, sprite sheets with no transparency — this blending is pure overhead and shows up clearly in profiling.
There was no public way to ask the canvas for a plain copy of pixels.
Fix:
Add a blit operation to the canvas contract that copies image pixels straight into the target, bypassing the transparency path:
- TfpgCanvasBase gains public BlitImage(x, y, img) and BlitImagePart(x, y, img, xi, yi, w, h), dispatching through a new protected virtual DoBlitImagePart.
- The default DoBlitImagePart simply forwards to DoDrawImagePart, so every backend keeps rendering correctly — backends without a pixel buffer transparently degrade to the normal image draw, and calling code stays portable.
- THybridCanvas overrides DoBlitImagePart with a direct row-by-row Move into the pixel buffer: it applies the window delta, clips to the AggPas clip rect, the buffer bounds, and the source image bounds, then copies — no mask lookup, no alpha blend. It falls back to DoDrawImagePart when prerequisites (allocated buffer, 32-bit image) aren't met.
This mirrors the existing opaque fast-path already used in THybridCanvas.DoFillRectangle.
Notes / limitations:
- The blit is 1:1 (no scaling) — it's a copy, not a StretchDraw replacement.
- It is intentionally opaque: mask/alpha are ignored. Callers that need transparency should keep using DrawImage/DrawImagePart.
hybrid_canvas_blit.patch
Component: corelib — TfpgCanvasBase / THybridCanvas (software renderer)
Description:
The only way to draw an image onto a canvas is DrawImage/DrawImagePart, which always routes through the transparency path. On the hybrid (software/AggPas) renderer this means every image goes through AggPas's per-pixel alpha-blend rasteriser (transformImage → BGRA32_BLEND_SOLID_HSPAN), and for masked images it first builds a temporary alpha-applied copy of the whole image. For fully opaque content — background tiles, double-buffered composites, screenshots, sprite sheets with no transparency — this blending is pure overhead and shows up clearly in profiling.
There was no public way to ask the canvas for a plain copy of pixels.
Fix:
Add a blit operation to the canvas contract that copies image pixels straight into the target, bypassing the transparency path:
This mirrors the existing opaque fast-path already used in THybridCanvas.DoFillRectangle.
Notes / limitations:
hybrid_canvas_blit.patch