LVGL has a flexible and extendable draw pipeline. You can hook it to do some rendering with a GPU or even completely replace the built-in software renderer.
## Draw context
The core structure of drawing is `lv_draw_ctx_t`.
It contains a pointer to a buffer where drawing should happen and a couple of callbacks to draw rectangles, texts, and other primitives.
### Fields
`lv_draw_ctx_t` has the following fields:
-`void * buf` Pointer to a buffer to draw into
-`lv_area_t * buf_area` The position and size of `buf` (absolute coordinates)
-`const lv_area_t * clip_area` The current clip area with absolute coordinates, always the same or smaller than `buf_area`. All drawings should be clipped to this area.
-`void (*draw_rect)()` Draw a rectangle with shadow, gradient, border, etc.
-`void (*draw_arc)()` Draw an arc
-`void (*draw_img_decoded)()` Draw an (A)RGB image that is already decoded by LVGL.
-`lv_res_t (*draw_img)()` Draw an image before decoding it (it bypasses LVGL's internal image decoders)
-`void (*draw_letter)()` Draw a letter
-`void (*draw_line)()` Draw a line
-`void (*draw_polygon)()` Draw a polygon
-`void (*draw_bg)()` Replace the buffer with a rect without decoration like radius or borders.
-`void (*wait_for_finish)()` Wait until all background operation are finished. (E.g. GPU operations)
-`void * user_data` Custom user data for arbitrary purpose
(For the sake of simplicity the parameters of the callbacks are not shown here.)
All `draw_*` callbacks receive a pointer to the current `draw_ctx` as their first parameter. Among the other parameters there is a descriptor that tells what to draw,
e.g. for `draw_rect` it's called [lv_draw_rect_dsc_t](https://github.com/lvgl/lvgl/blob/master/src/draw/lv_draw_rect.h),
for `lv_draw_line` it's called [lv_draw_line_dsc_t](https://github.com/lvgl/lvgl/blob/master/src/draw/lv_draw_line.h), etc.
To correctly render according to a `draw_dsc` you need to be familiar with the [Boxing model](https://docs.lvgl.io/master/overview/coords.html#boxing-model) of LVGL and the meanings of the fields. The name and meaning of the fields are identical to name and meaning of the [Style properties](https://docs.lvgl.io/master/overview/style-props.html).
### Initialization
The `lv_disp_drv_t` has 4 fields related to the draw context:
-`lv_draw_ctx_t * draw_ctx` Pointer to the `draw_ctx` of this display
-`void (*draw_ctx_init)(struct _lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx)` Callback to initialize a `draw_ctx`
-`void (*draw_ctx_deinit)(struct _lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx)` Callback to de-initialize a `draw_ctx`
-`size_t draw_ctx_size` Size of the draw context structure. E.g. `sizeof(lv_draw_sw_ctx_t)`
When you ignore these fields, LVGL will set default values for callbacks and size in `lv_disp_drv_init()` based on the configuration in `lv_conf.h`.
`lv_disp_drv_register()` will allocate a `draw_ctx` based on `draw_ctx_size` and call `draw_ctx_init()` on it.
However, you can overwrite the callbacks and the size values before calling `lv_disp_drv_register()`.
It makes it possible to use your own `draw_ctx` with your own callbacks.
## Software renderer
LVGL's built in software renderer extends the basic `lv_draw_ctx_t` structure and sets the draw callbacks. It looks like this:
As you saw above the software renderer adds the `blend` callback field. It's a special callback related to how the software renderer works.
All draw operations end up in the `blend` callback which can either fill an area or copy an image to an area by considering an optional mask.
The `lv_draw_sw_blend_dsc_t` parameter describes what and how to blend. It has the following fields:
-`const lv_area_t * blend_area` The area with absolute coordinates to draw on `draw_ctx->buf`. If `src_buf` is set, it's the coordinates of the image to blend.
-`const lv_color_t * src_buf` Pointer to an image to blend. If set, `color` is ignored. If not set fill `blend_area` with `color`
-`lv_color_t color` Fill color. Used only if `src_buf == NULL`
-`lv_opa_t * mask_buf` NULL if ignored, or an alpha mask to apply on `blend_area`
-`lv_draw_mask_res_t mask_res` The result of the previous mask operation. (`LV_DRAW_MASK_RES_...`)
-`const lv_area_t * mask_area` The area of `mask_buf` with absolute coordinates
-`lv_opa_t opa` The overall opacity
-`lv_blend_mode_t blend_mode` E.g. `LV_BLEND_MODE_ADDITIVE`
## Extend the software renderer
### New blend callback
Let's take a practical example: you would like to use your MCUs GPU for color fill operations only.
As all draw callbacks call `blend` callback to fill an area in the end only the `blend` callback needs to be overwritten.
First extend `lv_draw_sw_ctx_t`:
```c
/*We don't add new fields, so just for clarity add new type*/