memononen / nanovg

Antialiased 2D vector drawing library on top of OpenGL for UI and visualizations.
zlib License
5.15k stars 771 forks source link

NanoVG (GL2) and OpenGL cannot drawing together, but NanoVG(GL3) could #572

Open jiandingzhe opened 4 years ago

jiandingzhe commented 4 years ago

For some reason, I tried to render using mixed NanoVG and raw OpenGL.

        glClearColor( 0.7f, 0.8f, 1, 1 );
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_ACCUM_BUFFER_BIT );

        // PART1: nanovg
        nvgBeginFrame( nvg, w, h, 1.0f );
        nvgCircle( nvg, 50, 50, 50 );
        nvgStrokeWidth( nvg, 3.0f );
        nvgStrokeColor( nvg, nvgRGB( 255, 127, 64 ) );
        nvgStroke( nvg );
        nvgEndFrame( nvg );

        // PART2: raw OpenGL
        glUseProgram( prog );
        glBindVertexArray( vao );
        glBindBuffer( GL_ARRAY_BUFFER, vbo );
        glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );

        glFinish();
        SDL_GL_SwapWindow( win );

If I compile nanovg_gl.h with NANOVG_GL2_IMPLEMENTATION, the OpenGL drawing part would always output nothing; and if compile with NANOVG_GL3_IMPLEMENTATION, it renders correctly.

The OpenGL drawing part as simple as drawing an rectangle with vertex color.

What make it so different between GL2 and GL3?

In addition:

jiandingzhe commented 4 years ago

I run both GL2 and GL3 programs with CodeXL and recorded all OpenGL calls in rendering loop.

Records from NanoVG compiled with NANOVG_GL2_IMPLEMENTATION:

glClearColor(0.69999999, 0.80000001, 1, 1)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
glUseProgram(1) [Context 3 - program 1: shader 2, shader 3]
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK)
glFrontFace(GL_CCW)
glEnable(GL_BLEND)
glDisable(GL_DEPTH_TEST)
glDisable(GL_SCISSOR_TEST)
glColorMask(TRUE, TRUE, TRUE, TRUE)
glStencilMask(4294967295)
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)
glStencilFunc(GL_ALWAYS, 0, 4294967295)
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, 0)
glBindBuffer(GL_ARRAY_BUFFER, 1)
glBufferData(GL_ARRAY_BUFFER, 2080, 0x00000208FB7AB5E0, GL_STREAM_DRAW)
glEnableVertexAttribArray(0)
glEnableVertexAttribArray(1)
glVertexAttribPointer(0, 2, GL_FLOAT, FALSE, 16, 0x0000000000000000)
glVertexAttribPointer(1, 2, GL_FLOAT, FALSE, 16, 0x0000000000000008)
glUniform1i(12, 0) [Context 3 - program 1: shader 2, shader 3]
glUniform2fv(11, 1, {600, 400}) [Context 3 - program 1: shader 2, shader 3]
glBlendFuncSeparate(1, GL_ONE_MINUS_SRC_ALPHA, 1, GL_ONE_MINUS_SRC_ALPHA)
glEnable(GL_STENCIL_TEST)
glStencilMask(255)
glStencilFunc(GL_EQUAL, 0, 255)
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR)
glUniform4fv(0, 11, {0, 0, 0, 0}) [Context 3 - program 1: shader 2, shader 3]
glGetError()
glDrawArrays(GL_TRIANGLE_STRIP, 0, 130)
glUniform4fv(0, 11, {0, 0, 0, 0}) [Context 3 - program 1: shader 2, shader 3]
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)
glDrawArrays(GL_TRIANGLE_STRIP, 0, 130)
glColorMask(FALSE, FALSE, FALSE, FALSE)
glStencilFunc(GL_ALWAYS, 0, 255)
glStencilOp(0, 0, 0)
glGetError()
glDrawArrays(GL_TRIANGLE_STRIP, 0, 130)
glColorMask(TRUE, TRUE, TRUE, TRUE)
glDisable(GL_STENCIL_TEST)
glDisableVertexAttribArray(0)
glDisableVertexAttribArray(1)
glDisable(GL_CULL_FACE)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glUseProgram(0) [Context 3 - program 0]
glUseProgram(4) [Context 3 - program 4: shader 5, shader 6]
glBindVertexArray(1)
glBindBuffer(GL_ARRAY_BUFFER, 2)
glDrawArrays(GL_TRIANGLE_FAN, 0, 4)
glFinish()
wglSwapBuffers(0x000000001A01224C)

And from NANOVG_GL3_IMPLEMENTATION:

glClearColor(0.69999999, 0.80000001, 1, 1)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
glUseProgram(1) [Context 3 - program 1: shader 2, shader 3]
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK)
glFrontFace(GL_CCW)
glEnable(GL_BLEND)
glDisable(GL_DEPTH_TEST)
glDisable(GL_SCISSOR_TEST)
glColorMask(TRUE, TRUE, TRUE, TRUE)
glStencilMask(4294967295)
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)
glStencilFunc(GL_ALWAYS, 0, 4294967295)
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, 0)
glBindBuffer(GL_UNIFORM_BUFFER, 2)
glBufferData(GL_UNIFORM_BUFFER, 512, 0x000001D670FF28B0, GL_STREAM_DRAW)
glBindVertexArray(1)
glBindBuffer(GL_ARRAY_BUFFER, 1)
glBufferData(GL_ARRAY_BUFFER, 2080, 0x000001D670FE2870, GL_STREAM_DRAW)
glEnableVertexAttribArray(0)
glEnableVertexAttribArray(1)
glVertexAttribPointer(0, 2, GL_FLOAT, FALSE, 16, 0x0000000000000000)
glVertexAttribPointer(1, 2, GL_FLOAT, FALSE, 16, 0x0000000000000008)
glUniform1i(14, 0) [Context 3 - program 1: shader 2, shader 3]
glUniform2fv(13, 1, {600, 400}) [Context 3 - program 1: shader 2, shader 3]
glBindBuffer(GL_UNIFORM_BUFFER, 2)
glBlendFuncSeparate(1, GL_ONE_MINUS_SRC_ALPHA, 1, GL_ONE_MINUS_SRC_ALPHA)
glEnable(GL_STENCIL_TEST)
glStencilMask(255)
glStencilFunc(GL_EQUAL, 0, 255)
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR)
glBindBufferRange(GL_UNIFORM_BUFFER, 0, 2, 256, 176)
glGetError()
glDrawArrays(GL_TRIANGLE_STRIP, 0, 130)
glBindBufferRange(GL_UNIFORM_BUFFER, 0, 2, 0, 176)
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)
glDrawArrays(GL_TRIANGLE_STRIP, 0, 130)
glColorMask(FALSE, FALSE, FALSE, FALSE)
glStencilFunc(GL_ALWAYS, 0, 255)
glStencilOp(0, 0, 0)
glGetError()
glDrawArrays(GL_TRIANGLE_STRIP, 0, 130)
glColorMask(TRUE, TRUE, TRUE, TRUE)
glDisable(GL_STENCIL_TEST)
glDisableVertexAttribArray(0)
glDisableVertexAttribArray(1)
glBindVertexArray(0)
glDisable(GL_CULL_FACE)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glUseProgram(0) [Context 3 - program 0]
glUseProgram(4) [Context 3 - program 4: shader 5, shader 6]
glBindVertexArray(2)
glBindBuffer(GL_ARRAY_BUFFER, 3)
glDrawArrays(GL_TRIANGLE_FAN, 0, 4)
glFinish()
wglSwapBuffers(0x000000004B0123A6)

The last six lines start from glUseProgram(4) is my custom raw GL drawing.

I compared the two records. It seems in GL3 version, nanovg is using its own VAO (an extra pair of glBindVertexArray(1) and glBindVertexArray(0)), while GL2 version not. So would GL2 version disturb some currently binding VAO? As VAO feature is not GL3-only, why nanovg don't have this pair of call in GL2 version?

mulle-nat commented 3 years ago

Did you find a solution to this ? I want to try mixing OpenGL calls with nanovg also, so I guess this will concern me too soon.

memononen commented 3 years ago

NanoVG will change some OpenGL state, which you will need to manually reset. See https://github.com/memononen/nanovg#opengl-state-touched-by-the-backend

mulle-nat commented 3 years ago

I was trying to leach off some working demo code here. :) I know that page. (But thanks anyway)