Repository navigation
finalscale: fix tiled scaled exports and upscale on OpenCL - #22912
Conversation
|
All together a very nice fix! |
Tiled scaled exports were off in two ways. dt_iop_clip_and_zoom_roi() resamples a buffer from its origin and ignores the roi offsets, but the roi tilers can give a tile an output origin that is not its input origin times the scale (input row 861 -> output row 2585 at 3x, instead of 2583). Each tile was then resampled up to two pixels off, which left seams of up to 150/255. And modify_roi_in() truncates x/y and sizes the input from the output size alone, so the last row or column of tiles could end one input row short of the image: a 17000 px wide export read rows up to 2600 of 2602 and was off by up to 70/255 in its bottom rows. New dt_iop_clip_and_zoom_tile(_cl)() and dt_interpolation_resample_tile (_cl)() pass the tile's position in the image to the resampling plan as a float shift, so non-integer scales line up as well. finalscale uses them for exports while the pipe is tiling, and sizes a tile's input from the end of its output. finalscale now also upscales on OpenCL, instead of always moving the image back to the CPU for the last step. It does so only when the upscale fits the device untiled: a tiled upscale reads every output tile back to the host, which is no faster than the CPU path and slower over PCIe. dt_opencl_image_fits_device() only sees roi_in, so the pipe now also checks roi_out against the device's maximum image size; otherwise an upscaled output above it ran untiled and failed to allocate. _default_process_tiling_cl_roi() computed the tile offsets in int, which wrapped once a tile started past 2 GiB of the output (a 4x export with 1 GB of cl_mem crashed); they are size_t now, as on the CPU.
728412b to
f15ff67
Compare
|
Done. #22901 is squashed in here: one commit, plus a single release note under Bug Fixes ("Upscaled exports no longer show shifted bands where they were processed in tiles, and the upscale now runs on OpenCL when it fits the device."). The FIXME is gone with it. On the name: the This also takes your point from #22901 about tiled OpenCL upscales, see there. |
Summary
When finalscale has to tile an export, each tile comes out shifted by up to two output pixels, which leaves visible seams. This happens on the CPU today, and on OpenCL once #22901 lets upscales run there. Found while testing #22901 for review.
dt_iop_clip_and_zoom_roi()resamples output pixel x of its roi at input position x / scale, counted from the start of the input buffer. It ignores the roi offsets. That works for the whole image. A tile only lines up if its output origin is exactly its input origin times the scale, and the roi tiling doesn't guarantee that. A 3x export with OpenCL off and resourcelevel=notebook got a tile at output row 2585 for input row 861, which should have been 2583.The fix passes the tile's offset in the image to the resampling plan as a float, so non-integer scales line up as well. This goes through new
dt_iop_clip_and_zoom_tile()anddt_iop_clip_and_zoom_tile_cl(), and finalscale uses them for exports while the pipe is tiling. Untiled exports and the other callers of the roi functions (demosaic, highlights) are unchanged. The plan's shift is now a float, but integer callers get the same values as before.Checklist
RELEASE_NOTES.mdentry was added (Bug Fixes).Test instructions
mire1.cr2 with default history,
--upscale true --hq true, at widths 10316 (2.64x), 11724 (3x) and 15632 (4x). Each export was compared with an untiled CPU export of the same size (resourcelevel=unrestricted). The table shows 8-bit JPEG differences; two untiled exports already differ by up to 9.Together with #22901 on PoCL, finalscale tiled on OpenCL at reference, notebook and mini. All of those match the untiled export too (max 12, at most 6 px over 8). Before this fix they were up to 154 off.
On an M4 Pro with Apple OpenCL (with #22901), tiled GPU exports were up to 200 off before (2.64x, notebook) and are at most 11 off after. CPU tiling on the Mac goes from 152-167 off to 0-11. 4x at 200 MB runs without errors. finalscale's own time doesn't change.
0001 and 0004 give the same CPU vs GPU pixel counts as before; those exports don't tile.
Not tested: a tiled downscale (I couldn't make finalscale tile one on these machines), and a discrete GPU.
AI assistance
Written with Claude Code. I checked it on PoCL and on my M4 Pro.