libacfutils
A general purpose library of utility functions designed to make it easier to develop addons for the X-Plane flight simulator.
|
#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"
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) |
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.
#define mt_cairo_render_init | ( | w, | |
h, | |||
fps, | |||
init_cb, | |||
render_cb, | |||
fini_cb, | |||
userinfo | |||
) |
Creates a new mt_cairo_render_t surface.
w | Width of the rendered surface (in pixels). |
h | Height of the rendered surface (in pixels). |
fps | Framerate 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_cb | An 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_cb | A mandatory rendering callback of type mt_cairo_render_cb_t. This is called for each rendered frame. |
fini_cb | An 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. |
userinfo | An optional user info pointer for the init_cb , render_cb and fini_cb callbacks. |
Definition at line 128 of file mt_cairo_render.h.
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.
cr | The cairo_t for which this callback is being invoked. |
userinfo | The argument passed to mt_cairo_render_init() in the userinfo argument. |
Definition at line 81 of file mt_cairo_render.h.
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.
cr | The cairo_t for which this callback is being invoked. |
userinfo | The argument passed to mt_cairo_render_init() in the userinfo argument. |
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.
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.
cr | The 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. |
w | The width of the rendering surface in pixels. |
h | The height of the rendering surface in pixels. |
userinfo | The argument passed to mt_cairo_render_init() in the userinfo argument. |
Definition at line 95 of file mt_cairo_render.h.
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.
x | X coordinate origin of the rectangle. |
y | Y coordinate origin of the rectangle. |
w | Width of rectangle. |
h | Height of rectangle. |
radius | Radius of the rounded arcs comprising the corners. |
Definition at line 31 of file cairo_utils.c.
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.
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.
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.
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.
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).
mtcr | Renderer 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_pos | Origin 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_sz | Size 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. |
pos | Target 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. |
size | Target rendering rectangle size to which to composite. This is specified in OpenGL coordinates and is transformed using the provided matrix for final rendering. |
pvm | The 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.
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.
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.
void mt_cairo_render_fini | ( | mt_cairo_render_t * | mtcr | ) |
Destroys a previously created mt_cairo_render_t instance.
Definition at line 658 of file mt_cairo_render.c.
bool_t mt_cairo_render_get_fg_mode | ( | const mt_cairo_render_t * | mtcr | ) |
B_TRUE
if the passed renderer is configure for foreground rendering, B_FALSE
otherwise. Definition at line 759 of file mt_cairo_render.c.
double mt_cairo_render_get_fps | ( | mt_cairo_render_t * | mtcr | ) |
Definition at line 710 of file mt_cairo_render.c.
unsigned mt_cairo_render_get_height | ( | mt_cairo_render_t * | mtcr | ) |
Definition at line 1517 of file mt_cairo_render.c.
vect3_t mt_cairo_render_get_monochrome | ( | const mt_cairo_render_t * | mtcr | ) |
NULL_VECT3
. Definition at line 952 of file mt_cairo_render.c.
unsigned mt_cairo_render_get_shader | ( | mt_cairo_render_t * | mtcr | ) |
Definition at line 878 of file mt_cairo_render.c.
unsigned mt_cairo_render_get_tex | ( | mt_cairo_render_t * | mtcr | ) |
Definition at line 1477 of file mt_cairo_render.c.
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.
unsigned mt_cairo_render_get_width | ( | mt_cairo_render_t * | mtcr | ) |
Definition at line 1506 of file mt_cairo_render.c.
void mt_cairo_render_glob_init | ( | bool_t | want_coherent_mem | ) |
Performs global initialization of the mt_cairo_render backend logic.
want_coherent_mem | If 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. |
Definition at line 426 of file mt_cairo_render.c.
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.
Definition at line 599 of file mt_cairo_render.c.
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().
Definition at line 975 of file mt_cairo_render.c.
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.
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.
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.
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.
mtcr | The mt_cairo_render_t into which to install the shader. |
prog | The shader program handle to set. If you set this to 0, the shader program used by the mtcr is reset back to the default. |
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:
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().vec2
named "vtx_tex0".mat4
named "pvm".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
.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.
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().
gl_filter_enum | Must 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.
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.
mtcr | Renderer to configure for asynchronous uploading. |
mtul | Uploader 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.
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_t * mt_cairo_uploader_init | ( | void | ) |
Initializes an asynchronous render surface uploader. This should be called from the main X-Plane thread.
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:
Definition at line 1749 of file mt_cairo_render.c.