# NXP PXP GPU (/integration/chip_vendors/nxp/pxp_gpu)



The PXP (PiXel Pipeline) is an accelerator in NXP i.MX RT SoCs. LVGL integrates it as a
[draw unit](/main-modules/draw), so several drawing features are offloaded to the PXP engine while
the CPU is available for other operations. An RTOS is required to block the LVGL drawing thread
and switch to another task or suspend the CPU for power savings.

Basic configuration [#basic-configuration]

* In order to use PXP as a draw unit, select in `lv_conf.h`: Set <ApiLink name="LV_USE_DRAW_PXP" /> to `1`.
* In order to use PXP to rotate the screen, select in `lv_conf.h`: Set <ApiLink name="LV_USE_ROTATE_PXP" /> to `1`.
* Enable PXP asserts in `lv_conf.h`: Set <ApiLink name="LV_USE_PXP_ASSERT" /> to `1`.
  There are a few PXP assertions that can stop the program execution in case the
  <ApiLink name="LV_ASSERT_HANDLER" /> is set to `while(1);` (Halt by default). Otherwise,
  only an error message is logged via `LV_LOG_ERROR`.
* If the `SDK_OS_FREE_RTOS` symbol is defined, the FreeRTOS implementation
  will be used, otherwise bare metal code will be included.

Basic initialization [#basic-initialization]

PXP draw initialization is done automatically in <ApiLink name="lv_init" /> once the
PXP is enabled as a draw unit or to rotate the screen, no user code is required:

```c title=" " lineNumbers=1
#if LV_USE_DRAW_PXP || LV_USE_ROTATE_PXP
  lv_draw_pxp_init();
#endif
```

During PXP initialization, a new draw unit `lv_draw_pxp_unit_t` will be created
with the additional callbacks, if <ApiLink name="LV_USE_DRAW_PXP" /> is set to `1`:

```c title=" " lineNumbers=1
lv_draw_pxp_unit_t * draw_pxp_unit = lv_draw_create_unit(sizeof(lv_draw_pxp_unit_t));
draw_pxp_unit->base_unit.evaluate_cb = _pxp_evaluate;
draw_pxp_unit->base_unit.dispatch_cb = _pxp_dispatch;
draw_pxp_unit->base_unit.delete_cb = _pxp_delete;
```

and an additional thread `_pxp_render_thread_cb()` will be spawned in order to
handle the supported draw tasks.

```c title=" " lineNumbers=1
#if LV_USE_PXP_DRAW_THREAD
    lv_thread_init(&draw_pxp_unit->thread, "pxpdraw", LV_THREAD_PRIO_HIGH, _pxp_render_thread_cb, 2 * 1024, draw_pxp_unit);
#endif
```

If `LV_USE_PXP_DRAW_THREAD` is not defined, then no additional draw thread will be created
and the PXP drawing task will get executed on the same LVGL main thread.

`_pxp_evaluate()` will get called after each task is being created and will
analyze if the task is supported by PXP or not. If it is supported, then a
preferred score and the draw unit id will be set to the task. A `score` equal
to `100` is the default CPU score. Smaller score means that PXP is capable of
drawing it faster.

`_pxp_dispatch()` is the PXP dispatcher callback, it will take a ready to draw
task (having the `DRAW_UNIT_ID_PXP` set) and will pass the task to the PXP draw
unit for processing.

`_pxp_delete()` will cleanup the PXP draw unit.

Features supported [#features-supported]

Supported draw tasks are available in `src/draw/nxp/pxp/lv_draw_pxp.c`:

```c title=" " lineNumbers=1
switch(t->type) {
    case LV_DRAW_TASK_TYPE_FILL:
        lv_draw_pxp_fill(t, t->draw_dsc, &t->area);
        break;
    case LV_DRAW_TASK_TYPE_IMAGE:
        lv_draw_pxp_img(t, t->draw_dsc, &t->area);
        break;
    case LV_DRAW_TASK_TYPE_LAYER:
        lv_draw_pxp_layer(t, t->draw_dsc, &t->area);
        break;
    default:
        break;
}
```

Additionally, the screen rotation can be handled by the PXP:

```c title=" " lineNumbers=1
void lv_draw_pxp_rotate(const void * src_buf, void * dest_buf, int32_t src_width, int32_t src_height,
                        int32_t src_stride, int32_t dest_stride, lv_display_rotation_t rotation,
                        lv_color_format_t cf);
```

* Fill area with color (w/o radius, w/o gradient) + optional opacity.
* Blit source image RGB565/ARGB888/XRGB8888 over destination.
  RGB565/RGB888/ARGB888/XRGB8888 + optional opacity.
* Recolor source image RGB565.
* Scale and rotate (90, 180, 270 degree) source image RGB565.
* Blending layers (w/ same supported formats as blitting).
* Rotate screen (90, 180, 270 degree).

Known limitations [#known-limitations]

* PXP can only rotate the frames in angles that are multiple of 90 degrees.
* Rotation is not supported for images unaligned to blocks of 16x16 pixels. PXP
  is set to process 16x16 blocks to optimize the system for memory bandwidth and
  image processing time. The output engine essentially truncates any output
  pixels after the desired number of pixels has been written. When rotating a
  source image and the output is not divisible by the block size, the incorrect
  pixels could be truncated and the final output image can look shifted.
* Recolor or transformation for images w/ opacity or alpha channel can't be
  obtained in a single PXP pipeline configuration. Two or multiple steps would
  be required.
* Buffer address must be aligned to 64 bytes: set <ApiLink name="LV_DRAW_BUF_ALIGN" />
  to `64` in `lv_conf.h`.
  No stride alignment is required: set <ApiLink name="LV_DRAW_BUF_STRIDE_ALIGN" /> to
  `1` in `lv_conf.h`.

Project setup [#project-setup]

Add the PXP related source files (and corresponding headers if available) to the project:

* `src/draw/nxp/pxp/lv_draw_buf_pxp.c`: draw buffer callbacks
* `src/draw/nxp/pxp/lv_draw_pxp_fill.c`: fill area
* `src/draw/nxp/pxp/lv_draw_pxp_img.c`: blit image (w/ optional recolor or transformation)
* `src/draw/nxp/pxp/lv_draw_pxp_layer.c`: layer blending
* `src/draw/nxp/pxp/lv_draw_pxp.c`: draw unit initialization
* `src/draw/nxp/pxp/lv_pxp_cfg.c`: init, deinit, run/wait PXP device
* `src/draw/nxp/pxp/lv_pxp_osa.c`: OS abstraction (FreeRTOS or bare metal)
* `src/draw/nxp/pxp/lv_pxp_utils.c`: function helpers

The PXP related code depends on two drivers provided by the MCU SDK. These drivers
need to be added to the project as well:

* `fsl_pxp.c`: PXP driver
* `fsl_cache.c`: CPU cache handling functions

PXP default configuration [#pxp-default-configuration]

The implementation depends on multiple OS-specific functions. The struct
`pxp_cfg_t` with callback pointers is used as a parameter for the
<ApiLink name="lv_pxp_init" /> function. The default implementation for
FreeRTOS is in `lv_pxp_osa.c`.

* `pxp_interrupt_init`: Initialize PXP interrupt (HW setup, OS setup)
* `pxp_interrupt_deinit`: Deinitialize PXP interrupt (HW setup, OS setup)
* `pxp_run`: Start PXP job. Use OS-specific mechanism to block the drawing thread.
* `pxp_wait`: Wait for PXP completion.
