How to properly connect skia to an existing opengl context?

751 views
Skip to first unread message

Andrew M

unread,
Nov 3, 2022, 3:36:07 AM11/3/22
to skia-discuss
Good day. I have a window with OWNDC and an Opengl context created. The glew library is also connected.

BOOL InitPixelFormat(HDC& _hDC, HWND& _hWnd)
{
    PIXELFORMATDESCRIPTOR pfd = 
    {
        sizeof(PIXELFORMATDESCRIPTOR),
         1,
         PFD_SUPPORT_OPENGL |
         PFD_DRAW_TO_WINDOW |
         PFD_DOUBLEBUFFER ,
         //PFD_SUPPORT_GDI,
         PFD_TYPE_RGBA,
         32,
         0, 0, 0, 0, 0, 0,
         0,
         0,
         0,
         0, 0, 0, 0,
         32,
         8,
         0,
         PFD_MAIN_PLANE,
         0,
         0, 0, 0
    };

    if (!(_hDC = GetDC(_hWnd)))
    {
        MessageBox(NULL, L"Can't Create A GL Device Context.", L"ERROR", MB_OK | MB_ICONEXCLAMATION);
        return FALSE;                
    }

    int pixelFormat = ChoosePixelFormat(_hDC, &pfd);
    if (!pixelFormat)
    {
        MessageBox(NULL, L"Can't Find A Suitable PixelFormat.", L"ERROR", MB_OK | MB_ICONEXCLAMATION);
        return FALSE;                
    }

    if ((!SetPixelFormat(_hDC, pixelFormat, &pfd)))
    {
        MessageBox(NULL, L"Can't Set The PixelFormat.", L"ERROR", MB_OK | MB_ICONEXCLAMATION);
        return FALSE;             
    }

    return TRUE;
}

BOOL InitOpenGL(HDC& _hDC, HGLRC& _hGLRC)
{
   
    _hGLRC = wglCreateContext(_hDC);

    if (!_hGLRC)
    {
        MessageBox(NULL, L"Can't Create A GL Rendering Context.", L"ERROR", MB_OK | MB_ICONEXCLAMATION); return FALSE;
    }
    if (!(wglMakeCurrent(_hDC, _hGLRC)))
    {
        MessageBox(NULL, L"Can't Activate The GL Rendering Context.", L"ERROR", MB_OK | MB_ICONEXCLAMATION);
        return FALSE;               
    }

    return TRUE;
}


I output the opengl rendering code in the OpenGLPaint function via a while loop:

    while (true)
    {
        /* check for messages */
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            /* handle or dispatch messages */
            if (msg.message == WM_QUIT)
            {
                break;
            }
            else if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        else
        {
             
            OpenGLPaint();

        }
    }

Here is the code of the OpenGLPaint() function: 

void OpenGLPaint()
{
glClearColor(1.0, 1.0, 1.0, 1.0);//white
glClearStencil(0);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    //sk_sp<const GrGLInterface> intf = nullptr;
    sk_sp<const GrGLInterface> intf = GrGLMakeNativeInterface();
    if (intf->validate()) cout << "Good" << endl;
    sk_sp<GrDirectContext> context = GrDirectContext::MakeGL(intf);
    SkImageInfo info = SkImageInfo::MakeN32Premul(glWindowWidth, glWindowHeight);
    sk_sp<SkSurface> gpuSurface(SkSurface::MakeRenderTarget(context.get(),  SkBudgeted::kNo, info));
    if (!gpuSurface) cout << "gpu surface wasn't create properly" << endl;
    SkCanvas* gpuCanvas = gpuSurface->getCanvas();

    SkRect rect = SkRect::MakeXYWH(50, 50, 40, 60);
    SkPaint paint;
    paint.setStrokeWidth(20);
    paint.setColor(SK_ColorRED);
    gpuCanvas->drawRect(rect, paint);

glFlush();
SwapBuffers(hDC2);

Skia initializes successfully, but the rectangle is not output. What am I doing wrong? Opengl renders normally. I need to draw via skia in my opengl context, no other way.
I also tried initializing kia in a separate function, also doesn't work.

Brian Salomon

unread,
Nov 3, 2022, 8:51:37 AM11/3/22
to skia-d...@googlegroups.com
So if you're trying to connect Skia to the OpenGL's default framebuffer object (FBO ID 0) then you need to import that into Skia. SkSurface::MakeRenderTarget() creates a new texture and FBO to draw into. Instead use SkSurface::MakeFromBackendRenderTarget(). It should look something like:

GrGLFramebufferInfo fbInfo;
fbInfo.fFBOID = 0;
fbInfo.fFormat = GL_RGBA8;

GrBackendRenderTarget backendRT(glWindowWidth,
                                glWindowHeight,
                                /*sampelCount=*/1,
                                /*stencilBits=*/8,
                                fbInfo);

sk_sp<SkSurface> gpuSurface = SkSurface::MakeFromBackendRenderTarget(context.get(), backendRT,
                                                                     kBottomLeft_GrSurfaceOrigin,
                                                                     kRGBA_8888_SkColorType,
                                                                     /*colorSpace=*/nullptr,
                                                                     /*surfaceProps=*/nullptr);

Also, after you are finished drawing to SkSurface, before you swap buffers, you have to call surface->flush(). This tells Skia to flush all its work to OpenGL. You shouldn't need the glFlush().

--
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/c1926730-838d-41f5-8b28-eb8e1afdf16bn%40googlegroups.com.


--

Brian Salomon | Office Hours: go/bsalomon-office | bsal...@google.com
Message has been deleted

Andrew M

unread,
Nov 4, 2022, 8:38:54 AM11/4/22
to skia-discuss
Thanks, it works. But only in the Opengl rendering function. If I create global variables:

sk_sp<const GrGLInterface> intf;
sk_sp<GrDirectContext> context;
sk_sp<SkSurface> gpu Surface;
SkCanvas* gpu Canvas;

and I initialize skia in a separate function, only one frame is displayed and then a white screen is displayed all the time. I'm racking my head over this and I can't figure out what the reason is.

четверг, 3 ноября 2022 г. в 20:51:37 UTC+8, Brian Salomon:

Lin Wither

unread,
Jul 11, 2023, 10:19:53 PM7/11/23
to skia-discuss
hi, I met the same problem that only one frame is displayer. I finally found out that skia context should be reset for each frame to draw.
just add this line for drawing loop:
 
    context->resetContext();

Jim Van Verth

unread,
Jul 12, 2023, 9:49:58 AM7/12/23
to skia-d...@googlegroups.com
FYI, if you know the subset of GL state you're changing in your code then you can be more granular by passing in GrGLBackendState flags to resetContext().



--

Jim Van Verth |
 Software Engineer | Google.com
Reply all
Reply to author
Forward
0 new messages