Paul,
Thanks, that is very useful.
Your recollection is entirely consistent with what I have observed both without and with smoothing.
I will use draw_filled_rectangle@ instead of draw_pixel@ from now on.
According to AI:
*When you call draw_point@ in ClearWin+ (which wraps Windows SetPixel), each pixel goes through a full GDI pipeline individually:
- GDI checks the device context (DC) for clipping, mapping modes, and transformations.
- GDI validates the coordinates to make sure they are inside the drawable region.
- GDI computes the actual memory location of the pixel in the framebuffer or bitmap.
- The pixel value is written, sometimes with extra synchronization to ensure the graphics engine sees it immediately.
- Windows may flush the pipeline to the display (or schedule a refresh).
All of these steps are repeated for every single pixel, which is why SetPixel is notoriously slow — even for just one pixel, a lot of overhead happens.
On the other hand, when you call draw_filled_rectangle@ (even for a rectangle of size 1×1):
- ClearWin+ translates it into a GDI fill command (like FillRect or Rectangle).
- The GDI fill routines are highly optimised: they can batch memory writes, skip redundant calculations, and often operate directly on internal framebuffer buffers.
- The Windows graphics engine has special “fast paths” for rectangle fills, even for tiny rectangles. This means the memory and clipping calculations are done efficiently in one go rather than per pixel.
- Finally, the GDI engine can push the block to the screen efficiently, rather than flushing per pixel.
So the irony is that drawing a “tiny box” with draw_filled_rectangle@ triggers the optimized batch path, while draw_point@ forces a slow, per-pixel pipeline traversal.
draw_point@ = slow path, per-pixel, unbatched, lots of overhead.
draw_filled_rectangle@ = fast path, batch-optimized, even if the rectangle is just one pixel.
This explains why, counterintuitively, plotting a single “pixel rectangle” can be faster than plotting a single point.
*