libacfutils
A general purpose library of utility functions designed to make it easier to develop addons for the X-Plane flight simulator.
Loading...
Searching...
No Matches
Data Structures | Macros | Typedefs | Functions
mt_cairo_render.h File Reference
#include <cairo.h>
#include <cairo-ft.h>
#include <ft2build.h>
#include <FT_FREETYPE_H>
#include "geom.h"
#include "log.h"
#include "font_utils.h"
#include "cairo_utils.h"
Include dependency graph for mt_cairo_render.h:

Go to the source code of this file.

Data Structures

struct  mtcr_rect_t
 

Macros

#define mt_cairo_render_init(w, h, fps, init_cb, render_cb, fini_cb, userinfo)
 

Typedefs

typedef bool_t(* mt_cairo_init_cb_t) (cairo_t *cr, void *userinfo)
 
typedef void(* mt_cairo_fini_cb_t) (cairo_t *cr, void *userinfo)
 
typedef void(* mt_cairo_render_cb_t) (cairo_t *cr, unsigned w, unsigned h, void *userinfo)
 

Functions

void mt_cairo_render_glob_init (bool_t want_coherent_mem)
 
mt_cairo_render_t * mt_cairo_render_init_impl (const char *filename, int line, unsigned w, unsigned h, double fps, mt_cairo_init_cb_t init_cb, mt_cairo_render_cb_t render_cb, mt_cairo_fini_cb_t fini_cb, void *userinfo)
 
void mt_cairo_render_fini (mt_cairo_render_t *mtcr)
 
void mt_cairo_render_set_fps (mt_cairo_render_t *mtcr, double fps)
 
double mt_cairo_render_get_fps (mt_cairo_render_t *mtcr)
 
void mt_cairo_render_enable_fg_mode (mt_cairo_render_t *mtcr)
 
bool_t mt_cairo_render_get_fg_mode (const mt_cairo_render_t *mtcr)
 
void mt_cairo_render_set_texture_filter (mt_cairo_render_t *mtcr, unsigned gl_filter_enum)
 
void mt_cairo_render_set_shader (mt_cairo_render_t *mtcr, unsigned prog)
 
unsigned mt_cairo_render_get_shader (mt_cairo_render_t *mtcr)
 
void mt_cairo_render_set_monochrome (mt_cairo_render_t *mtcr, vect3_t color)
 
vect3_t mt_cairo_render_get_monochrome (const mt_cairo_render_t *mtcr)
 
void mt_cairo_render_once (mt_cairo_render_t *mtcr)
 
void mt_cairo_render_once_wait (mt_cairo_render_t *mtcr)
 
void mt_cairo_render_draw (mt_cairo_render_t *mtcr, vect2_t pos, vect2_t size)
 
void mt_cairo_render_draw_subrect (mt_cairo_render_t *mtcr, vect2_t src_pos, vect2_t src_sz, vect2_t pos, vect2_t size)
 
void mt_cairo_render_draw_pvm (mt_cairo_render_t *mtcr, vect2_t pos, vect2_t size, const float *pvm)
 
void mt_cairo_render_draw_subrect_pvm (mt_cairo_render_t *mtcr, vect2_t src_pos, vect2_t src_sz, vect2_t pos, vect2_t size, const float *pvm)
 
void mt_cairo_render_set_uploader (mt_cairo_render_t *mtcr, mt_cairo_uploader_t *mtul)
 
mt_cairo_uploader_t * mt_cairo_render_get_uploader (mt_cairo_render_t *mtcr)
 
unsigned mt_cairo_render_get_tex (mt_cairo_render_t *mtcr)
 
unsigned mt_cairo_render_get_width (mt_cairo_render_t *mtcr)
 
unsigned mt_cairo_render_get_height (mt_cairo_render_t *mtcr)
 
void mt_cairo_render_blit_back2front (mt_cairo_render_t *mtcr, const mtcr_rect_t *rects, size_t num)
 
void cairo_utils_rounded_rect (cairo_t *cr, double x, double y, double w, double h, double radius)
 
mt_cairo_uploader_t * mt_cairo_uploader_init (void)
 
void mt_cairo_uploader_fini (mt_cairo_uploader_t *mtul)
 

Detailed Description

mt_cairo_render is a multi-threaded Cairo rendering surface with built-in buffering and OpenGL compositing. You only need to provide a callback that renders into the surface using a passed cairo_t and then call mt_cairo_render_draw() at regular intervals to display the rendered result.

Definition in file mt_cairo_render.h.

Macro Definition Documentation

◆ mt_cairo_render_init

#define mt_cairo_render_init (   w,
  h,
  fps,
  init_cb,
  render_cb,
  fini_cb,
  userinfo 
)
Value:
mt_cairo_render_init_impl(log_basename(__FILE__), __LINE__, \
(w), (h), (fps), (init_cb), (render_cb), (fini_cb), (userinfo))
#define log_basename(f)
Definition log.h:89
mt_cairo_render_t * mt_cairo_render_init_impl(const char *filename, int line, unsigned w, unsigned h, double fps, mt_cairo_init_cb_t init_cb, mt_cairo_render_cb_t render_cb, mt_cairo_fini_cb_t fini_cb, void *userinfo)

Creates a new mt_cairo_render_t surface.

Parameters
wWidth of the rendered surface (in pixels).
hHeight of the rendered surface (in pixels).
fpsFramerate at which the surface should be rendered. This can be changed at any time later. Pass a zero fps value to make the renderer only run on-request (see mt_cairo_render_once()).
init_cbAn optional initialization callback of type mt_cairo_init_cb_t. This can be used to initialize private resources needed during rendering. This gets called once for every cairo_t instance (two instances for every mt_cairo_render_t, due to double-buffering). Please note that this can be called even after calling mt_cairo_render_init, since mt_cairo_render_set_monochrome() will re-allocate the cairo instances. If you don't want to receive this callback, pass NULL here.
render_cbA mandatory rendering callback of type mt_cairo_render_cb_t. This is called for each rendered frame.
fini_cbAn optional finalization callback of type mt_cairo_fini_cb_t, which can be used to free resources allocated during init_cb. Similarly to init_cb above, this will be called for each surface that is being deinitialized and may be called multiple times during surface reinit. If you don't want to receive this callback, pass NULL here.
userinfoAn optional user info pointer for the init_cb, render_cb and fini_cb callbacks.
Returns
The initialized and started mt_cairo_render_t instance. Returns NULL if initialization failed.

Definition at line 128 of file mt_cairo_render.h.

Typedef Documentation

◆ mt_cairo_fini_cb_t

typedef void(* mt_cairo_fini_cb_t) (cairo_t *cr, void *userinfo)

An optional finalization callback which can be passed to mt_cairo_render_init() in the fini_cb argument. This callback can be used to free resources allocated during initialization. This will be called for each surface that is being deinitialized and may be called multiple times during surface reinit.

Parameters
crThe cairo_t for which this callback is being invoked.
userinfoThe argument passed to mt_cairo_render_init() in the userinfo argument.

Definition at line 81 of file mt_cairo_render.h.

◆ mt_cairo_init_cb_t

typedef bool_t(* mt_cairo_init_cb_t) (cairo_t *cr, void *userinfo)

An optional initialization callback which can be passed to mt_cairo_render_init() in the init_cb argument. This callback can be used to allocate custom resources for each surface, or to configure the default state of the renderer. This will be called for each surface that is being deinitialized and may be called multiple times during surface reinit.

Parameters
crThe cairo_t for which this callback is being invoked.
userinfoThe argument passed to mt_cairo_render_init() in the userinfo argument.
Returns
B_TRUE if you want initialization to proceed, or B_FALSE if you need it to abort. Please note that returning B_FALSE is only allowed during mt_cairo_render_init(), as that's the only time the renderer can abort cleanly. You must NOT return B_FALSE on subsequent surface reinit operations (this only happens if mt_cairo_render_set_monochrome() is called).

Definition at line 70 of file mt_cairo_render.h.

◆ mt_cairo_render_cb_t

typedef void(* mt_cairo_render_cb_t) (cairo_t *cr, unsigned w, unsigned h, void *userinfo)

Mandatory rendering callback, which must be provided to mt_cairo_render_init() in the render_cb argument. This will be called every time a new frame is to be rendered.

Parameters
crThe cairo_t into which you should perform rendering. The renderer is not reinitialized between frames and no blanking of the rendered image is performed automatically, so if you want redraw the entire contents, perform your own screen clearing first.
wThe width of the rendering surface in pixels.
hThe height of the rendering surface in pixels.
userinfoThe argument passed to mt_cairo_render_init() in the userinfo argument.

Definition at line 95 of file mt_cairo_render.h.

Function Documentation

◆ cairo_utils_rounded_rect()

void cairo_utils_rounded_rect ( cairo_t *  cr,
double  x,
double  y,
double  w,
double  h,
double  radius 
)

Appends a rounded rectangle to the current path. In essence operates exactly as cairo_rectangle(), except the corners can be rounded over.

Parameters
xX coordinate origin of the rectangle.
yY coordinate origin of the rectangle.
wWidth of rectangle.
hHeight of rectangle.
radiusRadius of the rounded arcs comprising the corners.

Definition at line 31 of file cairo_utils.c.

◆ mt_cairo_render_blit_back2front()

void mt_cairo_render_blit_back2front ( mt_cairo_render_t *  mtcr,
const mtcr_rect_t rects,
size_t  num 
)

Definition at line 1524 of file mt_cairo_render.c.

◆ mt_cairo_render_draw()

void mt_cairo_render_draw ( mt_cairo_render_t *  mtcr,
vect2_t  pos,
vect2_t  size 
)

Same as mt_cairo_render_draw_subrect(), but renders the entire surface to the passed coordinates. For the vast majority of cases, this is the call you want to use to composite the entire surface onto the target framebuffer.

Definition at line 1215 of file mt_cairo_render.c.

◆ mt_cairo_render_draw_pvm()

void mt_cairo_render_draw_pvm ( mt_cairo_render_t *  mtcr,
vect2_t  pos,
vect2_t  size,
const float *  pvm 
)

Same as mt_cairo_render_draw_subrect_pvm(), but always draws the entire surface, rather than just a subrect of it.

Definition at line 1225 of file mt_cairo_render.c.

◆ mt_cairo_render_draw_subrect()

void mt_cairo_render_draw_subrect ( mt_cairo_render_t *  mtcr,
vect2_t  src_pos,
vect2_t  src_sz,
vect2_t  pos,
vect2_t  size 
)

Same as mt_cairo_render_draw_subrect_pvm(), but automatically determines the projection-view-model matrix from X-Plane's datarefs.

Definition at line 1237 of file mt_cairo_render.c.

◆ mt_cairo_render_draw_subrect_pvm()

void mt_cairo_render_draw_subrect_pvm ( mt_cairo_render_t *  mtcr,
vect2_t  src_pos,
vect2_t  src_sz,
vect2_t  pos,
vect2_t  size,
const float *  pvm 
)

Composites the rendered surface onto the currently bound OpenGL drawing target. This should be called at regular intervals to draw the results of the cairo render (though not necessarily in lockstep with it).

Parameters
mtcrRenderer instance to be drawn. If a new frame hasn't been rendered yet, this function simply renders the old buffer again (or nothing at all if no surface has completed internal Cairo rendering). You can guarantee that a surface is ready by first calling mt_cairo_render_once_wait().
src_posOrigin position within the surface from which to perform the compositing. This is referenced to the top left coordinate origin of the Cairo image surface.
src_szSize of area to composite from the source image surface. If you pass src_pos=ZERO_VECT2 and src_sz set to the entire image surface size to composite the entirety of the image surface.
posTarget rendering position of the origin of the rectangle to which to composite. This is specified in OpenGL coordinates and is transformed using the provided matrix for final rendering.
sizeTarget rendering rectangle size to which to composite. This is specified in OpenGL coordinates and is transformed using the provided matrix for final rendering.
pvmThe projection-View-Model matrix, which will be used by the vertex shader to transform the coordinates of the final rendering rectangle. If you've installed your own custom shader, this parameter will be passed to your shader in a mat4 uniform named "pvm".

Definition at line 1303 of file mt_cairo_render.c.

◆ mt_cairo_render_enable_fg_mode()

void mt_cairo_render_enable_fg_mode ( mt_cairo_render_t *  mtcr)

Enables foreground rendering mode for the mt_cairo_render_t (mtcr) instance. Normally, an mtcr performs rendering in a separate background thread. There cases where you don't want or need that to happen (e.g. if you are already controlling the mtcr from a background thread and want to have the rendering happen in that background thread, instead of an extra one). Calling this function will shut down the background rendering thread of the mtcr and reconfigure it for rendering in the mt_cairo_render_once_wait() call.

Note
The mtcr MUST have been configured with an FPS of 0 (i.e. manual rendering invocation) before calling this function.

After this function returns, you must manually invoke mt_cairo_render_once_wait() whenever you want the mtcr to actually perform rendering. The rendering and surface swap operations will be done directly on the calling thread, so there are no background thread synchronization issues.

Definition at line 735 of file mt_cairo_render.c.

◆ mt_cairo_render_fini()

void mt_cairo_render_fini ( mt_cairo_render_t *  mtcr)

Destroys a previously created mt_cairo_render_t instance.

See also
mt_cairo_render_init()

Definition at line 658 of file mt_cairo_render.c.

◆ mt_cairo_render_get_fg_mode()

bool_t mt_cairo_render_get_fg_mode ( const mt_cairo_render_t *  mtcr)
Returns
B_TRUE if the passed renderer is configure for foreground rendering, B_FALSE otherwise.
See also
mt_cairo_render_enable_fg_mode()

Definition at line 759 of file mt_cairo_render.c.

◆ mt_cairo_render_get_fps()

double mt_cairo_render_get_fps ( mt_cairo_render_t *  mtcr)
Returns
The rendering FPS of the mt_cairo_render_t.

Definition at line 710 of file mt_cairo_render.c.

◆ mt_cairo_render_get_height()

unsigned mt_cairo_render_get_height ( mt_cairo_render_t *  mtcr)
Returns
The height of the cairo image surface in pixels. This is equal to the "h" argument originally passed to mt_cairo_render_init().

Definition at line 1517 of file mt_cairo_render.c.

◆ mt_cairo_render_get_monochrome()

vect3_t mt_cairo_render_get_monochrome ( const mt_cairo_render_t *  mtcr)
Returns
The color used for monochrome rendering and compositing. If monochrome rendering is not in use (the default), returns NULL_VECT3.

Definition at line 952 of file mt_cairo_render.c.

◆ mt_cairo_render_get_shader()

unsigned mt_cairo_render_get_shader ( mt_cairo_render_t *  mtcr)
Returns
The custom shader program handle which was passed to mt_cairo_render_set_shader(). If no custom shader program was installed, this function returns 0 instead, to indicate that the mtcr is using the default shader program.

Definition at line 878 of file mt_cairo_render.c.

◆ mt_cairo_render_get_tex()

unsigned mt_cairo_render_get_tex ( mt_cairo_render_t *  mtcr)
Returns
The OpenGL texture object of the surface that has currently completed rendering. If no surface is ready yet, returns 0 instead.

Definition at line 1477 of file mt_cairo_render.c.

◆ mt_cairo_render_get_uploader()

mt_cairo_uploader_t * mt_cairo_render_get_uploader ( mt_cairo_render_t *  mtcr)

Returns the asynchronous uploader used by an mt_cairo_render_t, or NULL if the renderer doesn't utilize asynchronous uploading.

Definition at line 1460 of file mt_cairo_render.c.

◆ mt_cairo_render_get_width()

unsigned mt_cairo_render_get_width ( mt_cairo_render_t *  mtcr)
Returns
The width of the cairo image surface in pixels. This is equal to the "w" argument originally passed to mt_cairo_render_init().

Definition at line 1506 of file mt_cairo_render.c.

◆ mt_cairo_render_glob_init()

void mt_cairo_render_glob_init ( bool_t  want_coherent_mem)

Performs global initialization of the mt_cairo_render backend logic.

Parameters
want_coherent_memIf set to B_TRUE, this enables the use of persistent coherent memory for OpenGL texture uploading. This is generally recommended for most deployments, unless your OpenGL driver has bugs which make this mechanism not work well. If the underlying driver doesn't support persistent coherent memory (such as on macOS), mt_cairo_render_t automatically falls back to a different mechanism.
Note
Only the first call of mt_cairo_render_glob_init() is honored. If you want your call to take precedence, you MUST call this function before creating any renderers or an uploader using mt_cairo_render_init() or mt_cairo_uploader_init() respectively.

Definition at line 426 of file mt_cairo_render.c.

◆ mt_cairo_render_init_impl()

mt_cairo_render_t * mt_cairo_render_init_impl ( const char *  filename,
int  line,
unsigned  w,
unsigned  h,
double  fps,
mt_cairo_init_cb_t  init_cb,
mt_cairo_render_cb_t  render_cb,
mt_cairo_fini_cb_t  fini_cb,
void *  userinfo 
)

Implementation of mt_cairo_render_init() macro. Don't call this function directly use the macro instead.

See also
mt_cairo_render_init()

Definition at line 599 of file mt_cairo_render.c.

◆ mt_cairo_render_once()

void mt_cairo_render_once ( mt_cairo_render_t *  mtcr)

Fires the renderer off once to produce a new frame. This can be especially useful for renderers with fps = 0, which are only invoked on request. This doesn't cause the caller to block until the render is complete. Instead, it simply does an asynchronous render request to the background thread. If the background thread is currently in the process of rendering a frame, this request might get ignored. If you need to make absolutely sure that a new image is drawn and that rendering is finished, use mt_cairo_render_once_wait().

Note
Calling this function on an mt_cairo_render_t which has been configured for foreground rendering using mt_cairo_render_enable_fg_mode() will cause an assertion failure. Foreground-mode renderers MUST be driven using mt_cairo_render_once_wait() instead.
See also
mt_cairo_render_once_wait()

Definition at line 975 of file mt_cairo_render.c.

◆ mt_cairo_render_once_wait()

void mt_cairo_render_once_wait ( mt_cairo_render_t *  mtcr)

Same as mt_cairo_render_once(), but waits for the new frame to finish rendering. This guarantees that the image is complete and ready for compositing.

If the renderer is set to foreground mode (mt_cairo_render_enable_fg_mode()), you must use this function to drive the rendering.

Definition at line 994 of file mt_cairo_render.c.

◆ mt_cairo_render_set_fps()

void mt_cairo_render_set_fps ( mt_cairo_render_t *  mtcr,
double  fps 
)

Changes the rendering FPS of an mt_cairo_render_t instance.

Definition at line 695 of file mt_cairo_render.c.

◆ mt_cairo_render_set_monochrome()

void mt_cairo_render_set_monochrome ( mt_cairo_render_t *  mtcr,
vect3_t  color 
)

Enables or disables monochrome rendering mode. The default is disabled (i.e. the image is rendered in RGBA mode). Monochrome rendering in Cairo is controlled using the alpha channel. If you are using the default mt_cairo_render compositing shader, the color vector argument to this function sets what RGB color is used in the final render. Passing any non-NULL vector here enables monochrome mode. Pass a NULL_VECT3 to disable monochrome mode.

Switching rendering modes stops & restarts the worker thread (when not in foreground rendering mode) and calls any surface fini and init callbacks you passed mt_cairo_render_init().

Definition at line 898 of file mt_cairo_render.c.

◆ mt_cairo_render_set_shader()

void mt_cairo_render_set_shader ( mt_cairo_render_t *  mtcr,
unsigned  prog 
)

Sets a custom compositing shader program for use during mt_cairo_render_draw() and related functions. This lets you control how the compositing happens and apply arbitrary effects.

Parameters
mtcrThe mt_cairo_render_t into which to install the shader.
progThe shader program handle to set. If you set this to 0, the shader program used by the mtcr is reset back to the default.

Shader Uniforms and Vertex Attributes

Your custom shader program must contain at least a vertex and fragment shader. The mt_cairo_render_t automatically resolves attribute and uniform bindings using the following names:

  • The vertex position attribute as a vec3 named "vtx_pos". The Z coordinate is always set to zero and only. X and Y correspond to the input vertex coordinates based on the pos and size arguments passed to mt_cairo_render_draw().
  • The vertex texture UV attribute is passed as a vec2 named "vtx_tex0".
  • The combined projection-model-view matrix is passed in a uniform of type mat4 named "pvm".
  • The texture containing the cairo surface is passed in a uniform of type sampler2D named "tex". If the mtcr is configured for RGBA rendering (the default), the texture format and internal format are both GL_RGBA. If the mtcr is configured for monochrome rendering, the texture is of format GL_RED and internal format GL_R8 (meaning, the surface information is contained in the red channel only). In all cases, the texture data is of type GL_UNSIGNED_BYTE.
  • If configured for monochrome rendering, the monochrome color passed in the color argument of mt_cairo_render_set_monochrome() is passed in a uniform of type vec3 named "color_in". In RGBA mode, this uniform isn't filled.

Definition at line 865 of file mt_cairo_render.c.

◆ mt_cairo_render_set_texture_filter()

void mt_cairo_render_set_texture_filter ( mt_cairo_render_t *  mtcr,
unsigned  gl_filter_enum 
)

Sets the texture filtering used in compositing done by mt_cairo_render_draw().

Parameters
gl_filter_enumMust be one of the OpenGL texture filtering enums. The default on a newly created mt_cairo_render_t is GL_LINEAR.

Definition at line 772 of file mt_cairo_render.c.

◆ mt_cairo_render_set_uploader()

void mt_cairo_render_set_uploader ( mt_cairo_render_t *  mtcr,
mt_cairo_uploader_t *  mtul 
)

Configures the mt_cairo_render_t instance to use an asynchronous uploader. See mt_cairo_uploader_new() for more information.

Parameters
mtcrRenderer to configure for asynchronous uploading.
mtulUploader to use for renderer. If you pass NULL here, the renderer is returned to synchronous uploading.

Definition at line 1416 of file mt_cairo_render.c.

◆ mt_cairo_uploader_fini()

void mt_cairo_uploader_fini ( mt_cairo_uploader_t *  mtul)

Frees an mt_cairo_uploader_t and disposes of all of its resources. This must be called after all mt_cairo_render_t instances using it have either been destroyed, or have had their uploader link removed by a call to mt_cairo_render_set_uploader(mtcr, NULL).

Definition at line 1790 of file mt_cairo_render.c.

◆ mt_cairo_uploader_init()

mt_cairo_uploader_t * mt_cairo_uploader_init ( void  )

Initializes an asynchronous render surface uploader. This should be called from the main X-Plane thread.

Background

An mt_cairo_render_t runs its Cairo rendering operations in a background thread. However, to present the final rendered image on screen, the resulting image must first be uploaded to the GPU. This requires having an OpenGL context bound to the current thread, however, OpenGL contexts cannot be shared between threads. The workaround would be to create a new context in every mt_cairo_render_t worker thread, however, given that there can be dozens of render workers, this would generate dozens of OpenGL contexts, which isn't very efficient either. In lieu of a better mechanism, mt_cairo_render would simply perform the final image upload to the GPU during the mt_cairo_render_draw operation. Which this was utilizing pixel-buffer-objects to streamline the uploading process and avoid OpenGL pipeline stalls, there was still some memcpy'ing involved, which had a non-trivial cost when invoked from the main X-Plane thread.

mt_cairo_uploader_t solves all of these issues. It is a separate background worker thread with its own OpenGL context dedicated to doing nothing but uploading of finished renders to the GPU. Once created, the uploader goes into a wait-sleep, awaiting new work assignments from renderers. Once a render is finished, the uploader is notified, immediately wakes up and uploads the finished render to the GPU. This happens without waiting for the main X-Plane thread to come around wanting to draw a particular mt_cairo_render_t. With this infrastructure in place, calls to mt_cairo_render_draw no longer block for texture uploading.

This machinery isn't automatically enabled on all instances of mt_cairo_render_t however. To utilize this mechanism, you should create an mt_cairo_uploader and associate it with all your mt_cairo_render instances using mt_cairo_render_set_uploader. You generally only ever need a single uploader for all renderers you create. Thus, following this pattern is a good idea:

mt_cairo_uploader_t *uploader = mt_cairo_uploader_new();
mt_cairo_render_t *mtcr1 = mt_cairo_render_init(...);
mt_cairo_render_t *mtcr2 = mt_cairo_render_init(...);
mt_cairo_render_t *mtcr3 = mt_cairo_render_init(...);
// ...use the renderers as normal...
mt_cairo_uploader_fini(uploader); <- uploader fini must go last
void mt_cairo_render_fini(mt_cairo_render_t *mtcr)
#define mt_cairo_render_init(w, h, fps, init_cb, render_cb, fini_cb, userinfo)
void mt_cairo_uploader_fini(mt_cairo_uploader_t *mtul)
void mt_cairo_render_set_uploader(mt_cairo_render_t *mtcr, mt_cairo_uploader_t *mtul)

Definition at line 1749 of file mt_cairo_render.c.