setRenderQuality
The render-quality passes. This tier blits OES to an RGBA8 image, so eight bits is what the dither spreads across; anything it cannot do it ignores, as the SPI allows.
Asking for a kernel also changes the SIZE of that image. The blit normally refuses to enlarge, because enlarging in an intermediate buffer wastes memory when the drawing step can do it just as well. On Android it cannot: Compose maps every FilterQuality above None onto one boolean, isFilterBitmap, so High and Low are the same bilinear and the kernel has nowhere else to run. With one requested, the blit takes the enlargement itself and Compose then draws at 1:1. Ask for none and the old size law holds, bit for bit.
That enlargement is paid for in memory: the queue holds six buffers, and they grow from the source's size to the viewport's. A 480p film on a 1080p phone goes from about 8 MB to about 50 MB. It is bounded by the display and it is opt-in, which is why the cost is taken rather than capped, but it is a cost and it belongs next to the switch that spends it.
The animation upscaler lets the blit enlarge for the same reason, and runs ahead of it: the picture is drawn at its own size, debanded there if asked, the network doubles it, and the blit then takes the doubled picture to the viewport with the kernel, the colour controls and the dither. It runs only past the network's 1.2x rule, and a GPU that cannot draw into half floats skips it, once, with a log line saying why.