What is best way to generate texture from SkImage ?

2,356 views
Skip to first unread message

mohsen timar

unread,
Jul 2, 2017, 5:38:54 PM7/2/17
to skia-discuss
Hi,
I want to draw on an SKImage and get its texture and save it to later use for better performance so I need to:
-Make an image
-Draw something on it, for example, a bitmap
-Get texture
-Release image memory in CPU
-Draw it many times in GPU as fast as I can

And for this I write this code:

if (image2.get() == nullptr) {
sk_sp<SkImage> image;
sk_sp<SkData> imageData(SkData::MakeFromFileName("C:\\C\\C.jpg"));
image = SkImage::MakeFromEncoded(imageData);
SkImageInfo info = SkImageInfo::MakeN32(1920,1080,SkAlphaType::kPremul_SkAlphaType);
sk_sp<SkSurface> bSurface =  SkSurface::MakeRenderTarget(grContext.get(), SkBudgeted::kYes, info);
SkCanvas *bCanvas = bSurface->getCanvas();
bCanvas->drawImage(image,0,0);
bCanvas->flush();
image = bSurface->makeImageSnapshot();
GrBackendTextureDesc dest;
dest.fConfig = kRGBA_8888_GrPixelConfig;
dest.fHeight = image->height();
dest.fWidth = image->width();
dest.fOrigin = kDefault_GrSurfaceOrigin;
dest.fSampleCnt = 0;
GrTexture *txt = image->getTexture();
dest.fTextureHandle = txt->getTextureHandle();
image2 = SkImage::MakeFromTexture(grContext.get(), dest);
txt->abandon();
}
for (size_t i = 0; i < 100; i++)
{
canvas->drawImage(image2, i, i);
}


But it seems weird to me and I think there should be a better way for this.

Can anyone guide me?

Brian Osman

unread,
Jul 5, 2017, 10:16:49 AM7/5/17
to skia-d...@googlegroups.com
You're on the right track, but as soon as you do makeImageSnapshot, you're pretty much done. Because the surface was created on the GPU (MakeRenderTarget always makes a GPU surface), the image will start out on the GPU as well. Here's a fiddle: https://fiddle.skia.org/c/4a844269d5da66004e1f335d1b0ea656

--
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+unsubscribe@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.

mohsen timar

unread,
Jul 6, 2017, 8:02:29 AM7/6/17
to skia-discuss
Thanks for the answer and great sample.
Now speed is much higher than before and for example, for drawing 1000 of 100x100 texture it takes 50ms on my machine.

The remaining problem is the speed is lower than a simple OpenGL program, for example for 3000 of 100x100 textures it takes less than 20ms and near 200mb of memory but skia sample takes 500ms and 300mb of memory.

Can we do some optimizations in this sample code?

sk_sp<SkImage> *surfImage;
bool isFirst = true;
void draw2(SkCanvas* canvas) {
// This fiddle directly renders to an off-screen GPU surface
if (!canvas->getGrContext()) {
return;
}
if (isFirst) {
surfImage = new sk_sp<SkImage>[3000];
// sk_sp<SkImage> image is defined above, but could have been loaded from disk...
sk_sp<SkImage> image;
sk_sp<SkData> imageData(SkData::MakeFromFileName("test.png"));// 100x100 png file
image = SkImage::MakeFromEncoded(imageData);

for (size_t i = 0; i < 3000; i++)
{
SkImageInfo info = SkImageInfo::MakeN32(image->width(), image->height(), SkAlphaType::kPremul_SkAlphaType);
sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(canvas->getGrContext(), SkBudgeted::kYes, info);
SkCanvas* surfCanvas = surface->getCanvas();
surfCanvas->drawImage(image, 0, 0);
// No flush needed here - Skia handles that.

// We can draw on top of the image, if we like:
SkPaint p;
p.setColor(SK_ColorRED);
p.setStyle(SkPaint::kStroke_Style);
p.setStrokeWidth(15);
surfCanvas->drawLine(0, image->height(), image->width(), 0, p);

// Make a snapshot of this surface at this point in time. Because the surface was
// created on the GPU ('MakeRenderTarget'), the image is also on the GPU.
surfImage[i] = surface->makeImageSnapshot();

// Release the surface, too, if we're worried about that
surface = nullptr;
}
// Release the original image
image = nullptr;

// At this point, the only thing that exists is our image we created, with an extra line on it
// Draw a bunch of copies of it...
isFirst = false;
}
SkRandom random;
for (int i = 0; i < 3000; ++i) {
canvas->drawImage(surfImage[i], random.nextRangeF(0,1920) , random.nextRangeF(0, 1080));
}
}

Isabel Malasa

unread,
Dec 15, 2019, 6:51:58 PM12/15/19
to skia-discuss
I know right? There is a huge difference compare to a simple opengl program. Do you find a way to improve it now?

Brian Osman

unread,
Dec 16, 2019, 9:06:29 AM12/16/19
to skia-discuss
When you mention your simple OpenGL program - is that drawing the same texture over and over, or 1000s of unique textures? The Skia code you posted ends up making (and then drawing) 3000 unique textures. I'd expect it to be slightly slow, although 500 ms is quite a bit. Is that including all of the setup code to generate those (which - as written - involves making 3000 off-screen render targets).

Zhenobi MCPE

unread,
Dec 16, 2019, 9:35:48 AM12/16/19
to skia-discuss
Yeah drawing texture even just one make my memory usage go really big. Compare to simple opengl program. Is it because im using sdl or glfw? I dont really know why. I might try publishing my whole code next.

Shawn Riordan

unread,
Dec 17, 2019, 12:02:58 AM12/17/19
to skia-discuss
Question for Brian:

If we call SkSurface::MakeRenderTarget() in OpenGL, to make an off-screen surface, is that surface backed by an OpenGL pbuffer?

Also, does it work in WebGL / WebAssembly too?


On Wednesday, July 5, 2017 at 7:16:49 AM UTC-7, Brian Osman wrote:
You're on the right track, but as soon as you do makeImageSnapshot, you're pretty much done. Because the surface was created on the GPU (MakeRenderTarget always makes a GPU surface), the image will start out on the GPU as well. Here's a fiddle: https://fiddle.skia.org/c/4a844269d5da66004e1f335d1b0ea656
To unsubscribe from this group and stop receiving emails from it, send an email to skia-d...@googlegroups.com.

Brian Salomon

unread,
Dec 17, 2019, 1:30:00 PM12/17/19
to skia-d...@googlegroups.com
It's backed by a GL texture attached to a FBO. I believe it works in WebGL.

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/49347b2b-c31f-472f-9cd5-b18547f51da7%40googlegroups.com.

Shawn Riordan

unread,
Dec 17, 2019, 2:14:03 PM12/17/19
to skia-discuss
Ah. Thanks
To unsubscribe from this group and stop receiving emails from it, send an email to skia-d...@googlegroups.com.

Shachar Langbeheim

unread,
Dec 18, 2019, 2:10:02 AM12/18/19
to skia-discuss
Shawn, MakeFromBackendTextureAsRenderTarget works in WebGL for sure. I don't have the time to verify, but I assume that MakeRenderTarget works via a similar mechanism, so it should be WebGL compatible too.

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/f46872fd-c5a3-46f4-b49a-66d5c2604676%40googlegroups.com.

Brian Salomon

unread,
Dec 18, 2019, 10:21:47 AM12/18/19
to skia-d...@googlegroups.com
FWIW MakeFromBackendTextureAsRenderTarget() is strictly worse than MakeFromBackendTexture(). It exists only to work around some issues reading from certain types of textures in Chrome. When you use MakeFromBackendTextureAsRenderTarget() Skia will never use texture from the passed in texture. If we think we need to read from the texture in a shader (e.g. to perform advanced blending when you draw to the SkSurface's canvas) we will copy the contents from the FBO to a texture and read that instead.

Reply all
Reply to author
Forward
0 new messages