12 GL Backend and Custom Backends - inanevin/LinaVG GitHub Wiki

LinaVG itself does not provide any kind of rendering functionality. It simply handles all kinds of buffer generation depending on what you want to draw, and sends the data in optimized batches to the custom backend you provide. Of course, example application has a custom OpenGL backend example which you can very well use in your own projects.

Creating a custom backend

First of all you can check these examples:

First create a new class deriving from LinaVG::Backend::BaseBackend interface. Then before initializaing LinaVG, just call:

LinaVG::Backend::BaseBackend::SetBackend(myOwnBackendInstance);

// Inherited via BaseBackend
virtual bool				  Initialize() override;
virtual void				  Terminate() override;
virtual void				  StartFrame(int threadCount) override;
virtual void				  DrawGradient(LinaVG::GradientDrawBuffer* buf, int thread) override;
virtual void				  DrawTextured(LinaVG::TextureDrawBuffer* buf, int thread) override;
virtual void				  DrawDefault(LinaVG::DrawBuffer* buf, int thread) override;
virtual void				  DrawSimpleText(LinaVG::SimpleTextDrawBuffer* buf, int thread) override;
virtual void				  DrawSDFText(LinaVG::SDFTextDrawBuffer* buf, int thread) override;
virtual void				  EndFrame() override;
virtual void				  BufferFontTextureAtlas(int width, int height, int offsetX, int offsetY, unsigned char* data) override;
virtual void				  BindFontTexture(LinaVG::BackendHandle texture) override;
virtual void				  SaveAPIState() override;
virtual void				  RestoreAPIState() override;
virtual LinaVG::BackendHandle             CreateFontTexture(int width, int height) override;

The functions are pretty self-explanatory, few crucial points:

Initialize

This function will be called when LinaVG::Initialize() is called. Implement your own init functionality here. The example OpenGL backend creates shaders, buffers, vaos, vbos etc. here.

StartFrame

Called when LinaVG::StartFrame is called. threadCount is whatever you pass inside LinaVG::StartFrame(). Example OpenGL backend sets the draw state here, doesn't do any threading functionality. If you are multi-threading, you can resize your buffers according to the threadCount.

DrawXXX

This is where you will receive the calculated buffers from LinaVG. You can record draw commands here, or save the buffers and call custom rendering functions to dispatch draw calls all at once. Each received buffer contains:

  • Vertex & index data
  • Clip/scissors data
  • Draw parameters for the draw type.

EndFrame

Called when LinaVG::EndFrame() is called. Example OpenGL backend unbinds buffers and resets drawing state here.

Save/Restore API state

Called by the font loader in-between creating new texture atlases, in case you need to make state changes on your custom backend. In the case of example GL backend, it also uses to internally change API state.

CreateFontTexture

This is where you are supposed to allocate a texture with the given size in the GPU and return a handle. The texture will be used for font atlas, so care about the filters and other sampler settings.

BindFontTexture

Handle you returned on the CreateFontTexture will be given back to you here, where you can "bind" the texture for writing. When you call LoadFont, it will either create a new texture by calling CreateFontTexture, or use a previously created one for atlas purposes. That's why this method exists. LinaVG does not necessarily create a texture per font you load.

BufferFontTextureAtlas

Buffers custom data into the texture given in the last BindFontTexture call by width & height, as well as offsetX and offsetY. Used to buffer individual character glyphs into a font atlas. This is where you will write data to your texture.

Some remarks about the combination of CreateFontTexture, BindFontTexture and BufferFontTextureAtlas

Here is an example scenario:

  • LoadFont(myFont0)
  • No atlasses, CreateFontTexture - return handle myTexture0
  • BindFontTexture(myTexture0)
  • BufferFontTexture() -- now you are supposed to be buffering into myTexture0
  • LoadFont(myFont1) -- slightly bigger font
  • Atlas size is not sufficient enough, CreateFontTexture - return handle myTexture1
  • BindFontTexture(myTexture1)
  • BufferFontTexture() -- now you are supposed to be buffering into myTexture1
  • LoadFont(myFont2) -- small font
  • Atlas that was created for the first time (myTexture0) has sufficient enough size.
  • BindFontTexture(myTexture0)
  • BufferFontTexture() -- now you are supposed to be buffering into myTexture0