On Wed, 20 Feb 2013 17:10:29 + Daniel Willmann d.willm...@samsung.com
said:
Hello raster and other evas gurus,
last week we were confronted with memory usage peaks when rotating a
canvas through elm_win_rotation_with_resize_set.
We didn't really understand what was going on and so we came up with a
patch which seemed to fix the problem:
http://git.enlightenment.org/core/efl.git/commit/?id=139737247d563f53a064c7f4a025a89ed64c2983
We now know that this fix was just stupid and doesn't really work (or
fix anything). After some more digging into the render code we have
learned so far (please correct any place where we're wrong):
looks so - either way u have to allocate temporary rgba image buffers to render
data into BEFORE its rotated out to the real upload buffer...
* Only changed regions get rendered
correct. evas figures out update regions and evas render walks thru these
asking the engine for each... and then renders to eac, then pushes it back
when done leaving it up to the engine to rotate it to the putput and upload to
display when done (it gets deferred until flush for less artifacts).
* For each region a new region_for_update is allocated with
evas_software_xlib_outbuf_new_region_for_update()
correct.
* The image returned by this function is updated with the image data
for the region
correct. by the render code.
* evas_software_xlib_outbuf_push_updated_region() takes care of any
conversion (colorspace, rotation) that might be necessary
correct. it converts here and leaves in the shm buffer.
* evas_software_xlib_outbuf_flush() sends the updated regions to X
correct.
* After the rendering is done the stuff allocated through
*outbuf_new_region_for_update is freed again
correct. :)
In the common case (rotation is 0, display depth is 32bit):
* outbuf_new_region_for_update() allocates an
XShmImage and attaches its data directly to the evas_image data.
allocates and/or looks in its shm cache of existing shm segments, but correct.
this becomes a zero copy/convert path. it still is a copy up to display by x,
but within evas then no copies are done.
* outbuf_push_updated_region() detects this case
( - if (data == (unsigned char *)src_data) ) and skips any convert
function
correct. :)
In any other case (i.e. rotation is 90, 180 or 270):
* outbuf_new_region_for_update() allocates data for
the evas_image. This is where the updates will get rendered into.
It also allocates an XShmImage which is what will be pushed to X in
outbuf_flush(). The dimensions of the XShmImage is transposed if
the rotation is 90 or 270.
correct.
* outbuf_push_updated_region() selects the appropriate conversion
function and updates the XShmImage with the rotated image.
correct.
What now happens if we rotate a large window is that the complete canvas
needs to be redrawn - resulting in a large allocation of both the
original image and the rotated XShmImage. After that initial large
update we only have to update smaller regions so this is a one-time spike.
correct. though if u scroll a list filling most of the window.. it'll be
large regions too. at any point in time you need both the rendered data and its
converted/rotated output version (as at some point u have to do this
rotate/convert and both src and dest have to exist at once). evas just keeps
the whole set of them - and the whole set can in theory add up to a whole
window in size with both the unrotated/unconverted src and rotated/converted
output.
The question is now how do we reduce the allocation peaks when rotating
large windows? One possibility we see is breaking up the one large
fullscreen update into smaller ones and rendering those sequentially.
Does that make sense? Is there another/better way?
that leads to artifacts. it leads to SEEING the window update tile/region by
region. it also creates inefficiencies as you do the clipping and rendering of
many more smaller regions. you will pay a price in speed and artifacts. the set
is kept around and flushed in 1 go to minimize visible artifacts as x then
hopefully copies all the shm segments up in a very short timeframe as the
requests are temporally right next to eachother.
basically the answer is... you can't. not without creating other problems.
let me give you an extreme example:
you COULD cut down the buffer memory needed to just 1 pixel... if you update
the whole canvas 1 pixel at a time. technically evas itself allows for this. it
is, in theory, possible to make an engine that works this way. this is actually
similar to postscript printers from what i know, but they keep just 1 scanline
around at a time. they literally just keep a high resolution pixel buffer of
scaline and then scan that out with a laser (for inkjet i assume they keep
maybe 8, 16 or 32 lines depending on the head size). in this extreme example
set you now can render with very little buffer memory needed, BUT.. you pay
price in performance as you