SkImage, SkPicture, SkRecord and drawing command alteration

710 views
Skip to first unread message

alexis...@eiosis.com

unread,
Aug 14, 2018, 4:08:21 AM8/14/18
to skia-discuss
Hi,

We're developping a UI library using Skia for drawing.

We use the SkPicture/Recorder mechanism, there is a thread generating these SkPictures and a thread drawing them.

Here's my problem: I'd like the users to draw 1x and 2x images (for retina) with no overhead. Ideally, the user doesn't know the existence of 2 images.


In order to draw all our UI in 2x, we simply add a scale of 2x before drawing our SkPictures.

We've tried several solution but we are not satisfied with them:
Supposing we can retrieve 2x SkImage from the 1x one.
  • Add a function that knows which picture it should draw, rescale to fit etc ... It works, but there is an overhead for the user. He should call explicitly this function to make a selection of the right SkImage.
  • Create our own SkRecorder which replace the calls to "drawImage", by our own custom call to retrieve the 2x and draw it... It also works, but it's a lot of Skia extension for few "drawImage" calls (SkRecorder is final so we have to rewrite it ...).
  • Replace the "drawImage" commands in the SkPicture's SkRecord ... It works, it's few modifications, but it's a "hack" of Skia, and we don't like it. We have to cast the SkPicture in SkBigPicture, and const_cast the SkRecords to modify it using SkRecord::mutate, SkRecord::replace ...
  • Not tested: We can regenerate a SkPicture from an other one, replacing our "drawImage" with the good image.. I suppose it works, but for each SkPicture we'll have to potentially regenerate it and I don't really like it.

Does anyone have a better idea on how we can do this in a lightweight way, without forcing the user to use a non-Skia function for his draw call ?

BR,

Alexis

Cary Clark

unread,
Aug 14, 2018, 7:54:56 AM8/14/18
to skia-d...@googlegroups.com
How about using SkCanvas::drawAnnotation to include additional data, like a URL for the 2x version of the image, in addition to or instead of the drawImage call.

--
You received this message because you are subscribed to the Google Groups "skia-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to skia-discuss...@googlegroups.com.
To post to this group, send email to skia-d...@googlegroups.com.
Visit this group at https://groups.google.com/group/skia-discuss.
For more options, visit https://groups.google.com/d/optout.

Mike Klein

unread,
Aug 14, 2018, 10:12:01 AM8/14/18
to skia-d...@googlegroups.com
I think the simplest thing to try is to record an SkPicture for each scale.  Usually recording an SkPicture is pretty cheap compared to actually drawing it.

I'm not quite sure I get your setup though.  Are the users dynamically switching between 1x and 2x scale frame to frame?

alexis...@eiosis.com

unread,
Aug 14, 2018, 10:33:56 AM8/14/18
to skia-discuss
Thank your for you answer.

I understand you point, but I don't want the user (I mean the UI lib user/ a developper) to manage the 1x or 2x paint. With your solution, the problem is still the same, at a moment, the user will need to generate the picture with a specific image (1x or 2x). But i want to avoid this selection from the user by doing it automatically.

Why I need to do it at runtime and not at program startup is because the final application user may have a retina screen and a normal screen, and switch his application from a screen to another.
The part of scaling from normal screen to retina screen is already done one the other calls (scaling x2). But in the case of the images, we want to replace an image(with, height) with another image(width * 2, height * 2), not a simple scale (more details etc...).

Mike Reed

unread,
Aug 14, 2018, 10:59:18 AM8/14/18
to skia-d...@googlegroups.com
It is hard (so far) for us to imagine how to give you the solution you're suggesting, mostly because it involves somebody deciding at runtime *which* image to use. Skia has mipmap support, which is similar. With the mip, it is well defined what level(s) to sample from when we draw, based on the CTM. If we had an image with exactly 2 versions, what should we draw if the CTM's scale is 1.5 (or any other non-integral value)?

We have an alternative to Picture called a Drawable. When you "finish" recording, you can finish as a picture or as a drawable. Drawable recordings can contain nested drawables (which are user-defined drawing objects which you can subclass). The downside of a drawable is that it is not intrinsically thread-safe : you would have to take care of that yourself for any contained drawables during playback.

Brian Osman

unread,
Aug 14, 2018, 11:50:09 AM8/14/18
to skia-d...@googlegroups.com
I think you could do the double-recording (to two different SkPictures) thing without the user knowing about it. There are a variety of canvas proxy classes, all (mostly) derived from SkNWayCanvas. That class, by default, just forwards all calls to N attached canvases. If you made a new kind of N-way canvas, and had it recording into two recorder canvases, then you'd just need to override the onDrawImage family of functions in your canvas class, sending the original image to one, and the 2x image to the other. From a user perspective, you could still just return this top-level 2-way canvas, and they wouldn't have to know about the fact that it's making two different recordings under the hood, right?

On Tue, Aug 14, 2018 at 10:33 AM <alexis...@eiosis.com> wrote:

alexis...@eiosis.com

unread,
Aug 16, 2018, 4:08:20 AM8/16/18
to skia-discuss
Hi,

Thank you all for your answers.
I think I'll try the Drawable solution first but the double-recording canvas seems to be a good solution too. May be I'll try it before choosing the final implementation.
The more I learn about Skia, the more I like it, thank you !
Reply all
Reply to author
Forward
0 new messages