Skia and FBO

1,919 views
Skip to first unread message

Anthony Catel

unread,
Oct 8, 2012, 4:22:23 PM10/8/12
to skia-d...@googlegroups.com
Hey,

I'm trying to draw into an FBO instead of directly drawing into the window frame buffer.

So what I've done :

- Generate a framebuffer object
- Generate a texture
- Attach the texture to the FBO
- Bind the FBO
- Pass the FBO id to skia : desc.fRenderTargetHandle = fbo_handle;
[...]
- Do usual skia calls + SkCanvas::flush.
- Unbind the FBO (glBindFramebuffer(GL_FRAMEBUFFER, 0)) + glBindTexture(GL_TEXTURE_2D, fbo_texture);
- Trying to draw a GL_QUADS using the texture : I got either a black screen or a red screen depending on what I do with skia. But the texture is not drawn.

Using gDebugger I can see that the FBO's texture is filled with what I want but I'm unable to paint it on a rectancle. What Am I doing wrong? Does skia enable some state I should disable before painting the texture?

Here is a screen of gDebugger with my rendered texture : http://p.nf/debug.png
FBO 1 is the one I created. Others are created by Skia I guess.

Thanks !

Brian Salomon

unread,
Oct 8, 2012, 4:38:49 PM10/8/12
to skia-d...@googlegroups.com
Skia will definitely mess with the OpenGL state quite a bit. It will change the bound textures, program, array buffers, enable/disable states, etc. Since you're using GL_QUADS it sounds like you're on a non-ES ("desktop") OpenGL. You could use glPush[Client]Attrib to save state before invoking Skia and then pop it afterwards. The other options are to give Skia its own GL context (with shared ids) or make your other GL code able to cope with the Skia's state changes.

Brian



--
You received this message because you are subscribed to the Google Groups "skia-discuss" group.
To view this discussion on the web visit https://groups.google.com/d/msg/skia-discuss/-/UZY4zK_3oNkJ.
To post to this group, send email to skia-d...@googlegroups.com.
To unsubscribe from this group, send email to skia-discuss...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/skia-discuss?hl=en.

Anthony Catel

unread,
Oct 8, 2012, 4:46:57 PM10/8/12
to skia-d...@googlegroups.com
That's what I also though.

Basically what I'm trying to achieve is :

Composing a layer with some transparent part onto a white (or any other color) surface. Something like a browser's <canvas> element would do on the document body surface.
I could't achieve this efficiently using skia API (I have to keep a decent frame rate). Do you think using FBO is a good plan for this task? Or is there a Skia API in order to manage layers I'm not aware of?

Thanks,

Anthony

Brian Salomon

unread,
Oct 8, 2012, 5:02:00 PM10/8/12
to skia-d...@googlegroups.com
On Mon, Oct 8, 2012 at 4:46 PM, Anthony Catel <a.c...@weelya.com> wrote:
That's what I also though.

Basically what I'm trying to achieve is :

Composing a layer with some transparent part onto a white (or any other color) surface. Something like a browser's <canvas> element would do on the document body surface.
I could't achieve this efficiently using skia API (I have to keep a decent frame rate). Do you think using FBO is a good plan for this task? Or is there a Skia API in order to manage layers I'm not aware of?

Is the stuff underneath the layer also rendered by Skia? If so you can use SkCanvas's saveLayer mechanism. It switches the canvas to an offscreen target and draws it back to the main target when SkCanvas::restore is called. Check out the code comment in SkCanvas.h at line 267.
 
To view this discussion on the web visit https://groups.google.com/d/msg/skia-discuss/-/Xh7MHbwl1YMJ.

Anthony Catel

unread,
Oct 8, 2012, 5:10:01 PM10/8/12
to skia-d...@googlegroups.com
Already tried to use saveLayer but the performances are undermined. I have to do one saveLayer per frame.
Because : 

- I need xfer modes to be applied like I'm on a transparent surface
- I want a white background.

I can't find a reliable solution for this.

The flow would be :

loop() { // frame loop
  saveLayer();
  Skia Call 1;
  Skia Call 2;
  ...
  restore() /* and compose to a white background */
}

On the second frame I want to keep my object on the screen with the transparent background. The next saveLayer() would be unaware of what is already on the screen unless I redraw what's on the screen after the saveLayer() which seems to be very expensive. SkPicture() is maybe a solution?

Using FBO seems less painful to me.

Anthony

Anthony Catel

unread,
Oct 8, 2012, 5:18:26 PM10/8/12
to skia-d...@googlegroups.com
Or can I do this : ?

- create a new layer;
- draw to the new layer
- composite it to the root layer
- draw on the same layer
- compose
- etc...

So that the layer and its memory are not lost like on the saveLayer()/restore() flow.

Brian Salomon

unread,
Oct 8, 2012, 5:22:50 PM10/8/12
to skia-d...@googlegroups.com
I'm not totally sure I get what you're trying to do but you can draw from one canvas to another:

   layerCanvas->clear();
   layerCanvas->draw();
   mainCanvas->drawBitmap(layerCanvas->getDevice()->accessBitmap(false)).
   // layerCanvas's contents are preserved here



To view this discussion on the web visit https://groups.google.com/d/msg/skia-discuss/-/byuPM4DLLskJ.

Anthony Catel

unread,
Oct 8, 2012, 5:44:54 PM10/8/12
to skia-d...@googlegroups.com
this is the idea. But layerCanvas can't be backed by another GL device right? Or may be if :

- mainCanvas is attached to a GL device on the window framebuffer
- layerCanvas is attached to the same GL context but attached to an FBO
- mainCanvas->drawBitmap(layerCanvas->getDevice()->accessBitmap(false)) will tell OpenGL to draw layerCanvas texture onto mainCanvas buffer without performing CPU operation?

Brian Salomon

unread,
Oct 8, 2012, 7:02:09 PM10/8/12
to skia-d...@googlegroups.com

If you create an SkGpuDevice using the constructor that takes a config, width, and height then it will be FBO-backed. You can then install that device on the layerCanvas using SkCanvas::setDevice. It should just work and you don't need to call SkCanvas::flush when you switch from one canvas to the other.

To view this discussion on the web visit https://groups.google.com/d/msg/skia-discuss/-/jOV_BVae6mkJ.

Anthony Catel

unread,
Oct 8, 2012, 7:23:09 PM10/8/12
to skia-d...@googlegroups.com
Thanks for your patience. I'll try this solution.
(FWIW, I've "resolved" my initial issue by unsetting the current shader (glUseProgram(0)). I'm now seeing my texture with some distortion :)).

Ralph Thomas

unread,
Oct 8, 2012, 8:28:31 PM10/8/12
to skia-d...@googlegroups.com
I've found apitrace handy when trying to figure out what's wrong with
the current GL state: https://github.com/apitrace/apitrace

Ralph
> https://groups.google.com/d/msg/skia-discuss/-/xhI2E3dZa5sJ.

Anthony Catel

unread,
Oct 8, 2012, 9:01:53 PM10/8/12
to skia-d...@googlegroups.com
Brian,

It looks like there is a problem with alpha pixel when transfering the offscreen canvas to the other :

I create two devices and two canvas using this :

    [...]
    SkGpuDevice *devbg = new SkGpuDevice(context, target);
    SkGpuDevice *dev = new SkGpuDevice(GrContext::Create(kOpenGL_Shaders_GrEngine,
        (GrPlatform3DContext)interface), SkBitmap::kARGB_8888_Config,
        width, height);
    canvasBG = new SkCanvas(dev);
    canvas = new SkCanvas(devbg);

I then fill canvasBG with SK_ColorWhite and canvas with transparent black. I do some skia cann to canvas and then :

    canvasBG->drawBitmap(canvas->getDevice()->accessBitmap(false), 0, 0, NULL);
   
    canvasBG->flush();

The drawing is working but all the transparent pixels from canvas are displayed as garbage pixels (like unitialized memory) though. However if I fill the same canvas with blue instead of transparent at the begining, it's working well (blue color instead of garbage values). Setting it with semi-alpha-blue displays transparent blue blended with garbage values.

I added an offset to drawBitmap to see if the garbage value are from the background. It's not.

Here here the result for canvasBG->drawBitmap(canvas->getDevice()->accessBitmap(false), 30, 30, NULL); with canvasBG to white and canvas with semi-alpha-blue + drawRect :

http://i.imgur.com/EgIvS.png

Strange :s

Anthony Catel

unread,
Oct 8, 2012, 9:13:46 PM10/8/12
to skia-d...@googlegroups.com
ok, createCompatibleDevice() seems to do the tricks (with isOpaque) which is not available in SkGpuDevice directly.

Brian Salomon

unread,
Oct 9, 2012, 8:44:41 AM10/9/12
to skia-d...@googlegroups.com
Anthony, how are you doing the initial fills to white, trans black, and blue?  When you create an SkGpuDevice, or SkDevice for that matter, the contents are uninitialized. If you call SkCanvas::clear on both canvas and canvasBG then you shouldn't see garbage pixels. If so then we have a bug.

Brian


To view this discussion on the web visit https://groups.google.com/d/msg/skia-discuss/-/K3yDXVOC7AsJ.

Anthony Catel

unread,
Oct 9, 2012, 9:07:18 AM10/9/12
to skia-d...@googlegroups.com
Brian,

I used canvas->drawColor(SkColorSetARGB(0, 0, 0, 0));

Brian Salomon

unread,
Oct 9, 2012, 9:17:37 AM10/9/12
to skia-d...@googlegroups.com
So the default xfermode param to draw color is kSrcOver. This means 1 * Src + (1-Src_Alpha) * Dst. So when you pass 0 for the source alpha this simplifies to just Dst. It's as though nothing was drawn. To replace the dst color with the src color you'd use the kSrc mode. However, clear() is basically a shortcut for drawing a color in kSrc mode while ignoring the clip. So it's best to just use clear().


To view this discussion on the web visit https://groups.google.com/d/msg/skia-discuss/-/E-HEnDUsImAJ.

Anthony Catel

unread,
Oct 9, 2012, 9:25:35 AM10/9/12
to skia-d...@googlegroups.com
OIC, I didn't see that there was a transfert mode set to drawColor at first glance.

Thanks ;-)

Anthony.

Mike Reed

unread,
Oct 9, 2012, 9:30:35 AM10/9/12
to skia-d...@googlegroups.com
my 2 cents:

SkColor has helper macros like SkColorSetARGB(a, r, g, b). However,
its byte-order is completely well defined (0xAARRGGBB), so it is
common to see call-sites that just specify hex if you prefer.

e.g.

canvas->drawColor(0xFFFF0000); // draw opaque red

or in your case of transparent zero...

canvas->drawColor(0);

On the other hand, colors as they are stored in SkBitmap are a
different matter. Those are represented by SkPMColor
(pre-multiplied-color), and their byte-order may change depending on
the build. SkColorPriv.h has defines and macros this. Fortunately,
most calling code should never have to deal with SkPMColors.
> https://groups.google.com/d/msg/skia-discuss/-/JXs2bXkQLjUJ.

Anthony Catel

unread,
Oct 9, 2012, 10:17:54 AM10/9/12
to skia-d...@googlegroups.com
Indeed (I used SkColorSetARGB for reading purpose). I had to deal with pre multiplied colors and tried to Unpremul it using SkPMColorToColor I found on Webkit source. Which gave me different results on differents machines. Didn't find the time to dig into this though.

易旭昕

unread,
Jan 17, 2013, 12:09:48 AM1/17/13
to skia-d...@googlegroups.com
I do the same thing like you - use skia gpu to write a FBO and texture the FBO to window, it always crash when I use glDrawElements to texture the FBO in the beginning, 
and I fiannly solve it by just unbind the VBO, like this:

        // Unbind array buffer and element array buffer
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 

hope it could help

在 2012年10月9日星期二UTC+8上午4时22分23秒,Anthony Catel写道:
Reply all
Reply to author
Forward
0 new messages