SKBitmap cpu caching

398 views
Skip to first unread message

syawin

unread,
Jun 15, 2021, 12:29:05 PM6/15/21
to skia-discuss
Hello There,

Cpu cache is not used by SKBitmap.  Is that how it works or any configuration to be done explicitly ?

-syawin

syawin

unread,
Jun 15, 2021, 9:57:29 PM6/15/21
to skia-discuss

Hello There,

Adding to above question on enabling cpu cache for SkBitmap,

I'm working to find a best performant way to handle image with Skia on non GPU Device. What is observed , SKBitmap is faster than Skimage. But couldn't see any Cpu cache is been used by SKBitmap as like SKImage. Looking to leverage cached data on "redraw" to have SKBitmap faster on redraw scenario as well. Can  Cpu caching is possible for  SkBitmap ?

Also want to know, is there a way in SKIA to decide caching only on CPU for Skimage or transfer the cached data  from GPU to CPU to avoid memory pressure on GPU. This info will helps to decide between SKBitmap & SKImage w.r.t resources in device.

-syawin

Mike Reed

unread,
Jun 16, 2021, 8:26:33 AM6/16/21
to skia-d...@googlegroups.com
Very surprising that there would be any speed diff just because of image -vs- bitmap for raster surfaces. Can you show a code-shippet?

--
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 view this discussion on the web visit https://groups.google.com/d/msgid/skia-discuss/f8b44d07-ba4e-48e7-b84e-faa672d51305n%40googlegroups.com.

syawin

unread,
Jun 17, 2021, 12:08:03 AM6/17/21
to skia-discuss
Hi Mike,

Thanks for the quick comeback.

Here is the handled code 

using SKBitmap
------------------------
sk_sp<SkData> data = SkData::MakeFromFileName(path);
std::unique_ptr<SkImageGenerator> gen(SkImageGenerator::MakeFromEncoded(std::move(data)));
auto bitmap = std::make_unique<SkBitmap>();
bitmap->tryAllocPixels(gen->getInfo()) &&
      gen->getPixels(
          gen->getInfo().makeColorSpace(nullptr),
          bitmap->getPixels(),
          bitmap->rowBytes());
canvas->drawBitmapRect(*bitmap, rect, nullptr);

using SKImage
------------------------
sk_sp<SkData> data = SkData::MakeFromFileName(path);
sk_sp<SkImage>imageData_ = SkImage::MakeFromEncoded(data );
canvas->drawImage(imageData_, Xcoordinate,Ycoordinate);


with the data collected for  12Kb jpg image, canvas call "drawBitmapRect" took ~7 ms & "drawImage" took ~ 18 ms.



Brian Osman

unread,
Jun 17, 2021, 9:10:32 AM6/17/21
to skia-d...@googlegroups.com
If you are just timing the drawImage and drawBitmapRect calls, that makes sense. The key thing is that SkBitmap is guaranteed to be a big block of pixels. (In other words, it's always decoded from whatever image format the data may have started in.) Drawing a bitmap on the CPU backend is very fast, because the only work is copying the pixel data over (possibly with some transformation matrix, scaling, etc...). But nothing needs to be done to "get" the pixel data, it's stored in the SkBitmap.

SkImage does not guarantee that - there are several kinds of SkImage. It could be a "raster" image, which works the same as SkBitmap (and would also be very fast to draw). But in the code you posted, you will have a SkImage that holds the encoded (JPEG) data directly. It waits until it's used (when you call drawImage), and then it decodes the data (and puts it in a cache).

SkBitmap doesn't use a cache, because there's nothing to cache - the object itself holds all of the data that you might want to cache.

So looking at your two samples: With SkBitmap, when you call "gen->getPixels(...)", that forced the codec to do the (slow) work of decoding the JPEG. With SkImage, that happened automatically, inside drawImageRect. (However, the result should be cached, so if you were to draw both the bitmap and image again, the performance should be much closer).

Brian Osman

unread,
Jun 17, 2021, 9:12:55 AM6/17/21
to skia-d...@googlegroups.com
Sorry, forgot one thing: If you have an SkImage and want to make sure that it's fully decoded (so it will be fast to draw), you can do:

    image = image->makeRasterImage();   // Produces an image that will be fully decoded and fast to draw on the CPU

-or-

  image = image->makeTextureImage(context);  // Produces an image that will be fully decoded and uploaded to a texture, so it's fast to draw on the GPU

syawin

unread,
Jun 18, 2021, 2:15:16 AM6/18/21
to skia-discuss
Hi Brain,

Thanks for providing a good picture on behind the scene operations. with that measured the overall time for the first time draw from "creating a data till canvas draw call", which is nearly same for Skimage & SkBitmap.

when comes to redraw with SkImage, observed skia purges cpu cache very frequently without considering cache limit or amount of bytes consumed from it . I'm assuming respective Skimage object might be associated to the cached memory. On letting Skimage object going out of scope, it's associated cached memory where released. Is it that ?

Can you suggest, In order to retain & reuse the cpu cache with SKImage ,what to be done ? Is it needed to hold the SKImage object till its needs over ?

-syawin

Brian Osman

unread,
Jun 18, 2021, 8:40:51 AM6/18/21
to skia-d...@googlegroups.com
Yes, I'd suggest retaining the SkImage. If Skia needs to cache data for faster drawing, it will evict that data when the original object is released.

syawin

unread,
Jun 24, 2021, 2:59:13 AM6/24/21
to skia-discuss
Hi Brian,

Thanks for the Suggestion, with that achieved  using Cpu caching for redraw. 

Now, I'm started with GPU device. Where in , want to just avoid decoding of image on redraw with SKimage and don't want to capture texture data. This requirement is to avoid memory pressure on GPU. This there a way to avoid GPU caching and just have cpu caching (If my understanding is right, capture only the decoded RGB buffer on cpu and avoid texture caching @ GPU end ).

I see Caching hint is available for makeRasterImage(CachingHint chint), but my usecase involves encoded images, so using MakeFromEncoded(data ).

Can the CachingHint be set for MakeFromEncoded case as-well or any  other ways to avoid GPU caching?


-syawin

Brian Osman

unread,
Jun 24, 2021, 8:29:13 AM6/24/21
to skia-d...@googlegroups.com
You can control the size of the GPU cache, which may be more helpful if you're just trying to reduce memory pressure. Textures will still be cached, but the GPU backend will start to evict entries faster. See GrDirectContext::setResourceCacheLimit().

The other option (if you want to control the texture lifetimes manually) is to call image->makeTextureImage(). (Probably starting from a raster image, that you retain). That will return a new SkImage, backed by a GPU texture. That texture will not stay in the cache after the newly created image is freed.

Mike Reed

unread,
Jun 24, 2021, 9:33:26 AM6/24/21
to skia-d...@googlegroups.com
"avoid GPU caching and just have cpu caching"

If this means you want to *never* take up space on the GPU for an image, that is tricky. When we draw it, even a cpu-based image, we have to at least temporarily copy it to the gpu for the draw. Are you ask for a way to force us to *not* remember the upload (i.e. cache it), so that if you drew it again we'd have to upload it again?

syawin

unread,
Jun 25, 2021, 2:11:51 AM6/25/21
to skia-discuss
Hi Mike,

As per my understanding on GPU device for SKimage , there will be 2 caches. One at RAM, which captures the decoded data and another at GPU , which has uploaded texture.
Correct me if my understanding is wrong.

Based on this , thinking of below would be much beneficial for Devices with much lesser GPU memory then of CPU.
           Cache only decoded data at CPU end and  Avoid holding texture data on GPU.On redraw , only upload decoded data from cpu to GPU. 
   with this on redraw, avoid only the decoding stage. I assume decoding would take more time than uploading to GPU. 
If that's true, on trade-off between memory & speed, a balance can be achieved for resource constraint devices.
Please do correct me, if theory I'm formulating here is wrong.

On the same context, Having an one query w.r.t SKBitmap on GPU Device . This is tried to see the best fit.

Tried reuse SkBitmap object for redraw, with an idea, it reuses GPU caching done on first draw. 
With that there is  a significant speed improvement but on each redraw with same SKBitmap object, a new copy is created @ GPU instead of reusing the cache as like SKImage.
As purging occurs only for unlocked resources on GPU, till SkBitmap object is not released, every redraw increases GPU caching. Like to know, Which part of
operation is avoided in this case.

syawin

unread,
Jul 6, 2021, 3:12:35 PM7/6/21
to skia-discuss
Hi Brian & Mike,

Thanks for you info & support. Have finally settled with SkImage for both GPU & Non-GPU devices. 
--
syawin
Reply all
Reply to author
Forward
0 new messages