WIP display doublebuffer
This commit is contained in:
parent
db141fbc14
commit
cfd777dca4
|
@ -21,9 +21,66 @@
|
||||||
|
|
||||||
#define CMD(X) (*((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE))) = (X))
|
#define CMD(X) (*((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE))) = (X))
|
||||||
#define DATA(X) (*((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE | (1 << DISPLAY_MEMORY_PIN)))) = (X))
|
#define DATA(X) (*((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE | (1 << DISPLAY_MEMORY_PIN)))) = (X))
|
||||||
#define PIXELDATA(X) DATA((X) >> 8); DATA((X) & 0xFF)
|
|
||||||
|
|
||||||
#define LED_PWM_TIM_PERIOD (10000)
|
#define DOUBLE_BUFFER 1
|
||||||
|
|
||||||
|
#if DOUBLE_BUFFER
|
||||||
|
__IO uint8_t *DBUF = (__IO uint8_t *)CCMDATARAM_BASE;
|
||||||
|
|
||||||
|
secbool DBUF_DIRTY = sectrue;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
struct {
|
||||||
|
uint16_t x, y;
|
||||||
|
} start;
|
||||||
|
struct {
|
||||||
|
uint16_t x, y;
|
||||||
|
} end;
|
||||||
|
struct {
|
||||||
|
uint16_t x, y;
|
||||||
|
} pos;
|
||||||
|
} PIXELWINDOW;
|
||||||
|
|
||||||
|
static void PIXELDATA(uint16_t c)
|
||||||
|
{
|
||||||
|
// convert from 16-bit depth to 8-bit depth
|
||||||
|
// (RBB: 5-6-5 bits to 3-3-2 bits: rrrrrggg gggbbbbb -> rrrgggbb)
|
||||||
|
if (PIXELWINDOW.pos.x <= PIXELWINDOW.end.x && PIXELWINDOW.pos.y <= PIXELWINDOW.end.y) {
|
||||||
|
const int i = PIXELWINDOW.pos.x + PIXELWINDOW.pos.y * DISPLAY_RESX;
|
||||||
|
if (i < DISPLAY_RESX * DISPLAY_RESY) {
|
||||||
|
const uint8_t d = ((c & 0xE000) >> 8) | ((c & 0x700) >> 6) | ((c & 0x18) >> 3);
|
||||||
|
DBUF[i] = d;
|
||||||
|
DBUF_DIRTY = sectrue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PIXELWINDOW.pos.x++;
|
||||||
|
if (PIXELWINDOW.pos.x > PIXELWINDOW.end.x) {
|
||||||
|
PIXELWINDOW.pos.x = PIXELWINDOW.start.x;
|
||||||
|
PIXELWINDOW.pos.y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define PIXELDATA(X) DATA((X) >> 8); DATA((X) & 0xFF)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
|
||||||
|
|
||||||
|
void display_clear(void)
|
||||||
|
{
|
||||||
|
const int saved_orientation = DISPLAY_ORIENTATION;
|
||||||
|
display_orientation(0); // set MADCTL first so that we can set the window correctly next
|
||||||
|
display_set_window(0, 0, MAX_DISPLAY_RESX - 1, MAX_DISPLAY_RESY - 1); // address the complete frame memory
|
||||||
|
for (uint32_t i = 0; i < MAX_DISPLAY_RESX * MAX_DISPLAY_RESY; i++) {
|
||||||
|
DATA(0x00); DATA(0x00); // 2 bytes per pixel because we're using RGB 5-6-5 format
|
||||||
|
}
|
||||||
|
display_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); // go back to restricted window
|
||||||
|
display_orientation(saved_orientation); // if valid, go back to the saved orientation
|
||||||
|
#if DOUBLE_BUFFER
|
||||||
|
for (int i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) {
|
||||||
|
PIXELDATA(0x0000);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void __attribute__((unused)) display_sleep(void)
|
static void __attribute__((unused)) display_sleep(void)
|
||||||
{
|
{
|
||||||
|
@ -51,15 +108,28 @@ static void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y
|
||||||
{
|
{
|
||||||
x0 += BUFFER_OFFSET.x; x1 += BUFFER_OFFSET.x;
|
x0 += BUFFER_OFFSET.x; x1 += BUFFER_OFFSET.x;
|
||||||
y0 += BUFFER_OFFSET.y; y1 += BUFFER_OFFSET.y;
|
y0 += BUFFER_OFFSET.y; y1 += BUFFER_OFFSET.y;
|
||||||
|
|
||||||
|
#if DOUBLE_BUFFER
|
||||||
|
PIXELWINDOW.start.x = x0; PIXELWINDOW.start.y = y0;
|
||||||
|
PIXELWINDOW.end.x = x1; PIXELWINDOW.end.y = y1;
|
||||||
|
PIXELWINDOW.pos.x = x0; PIXELWINDOW.pos.y = y0;
|
||||||
|
#else
|
||||||
|
|
||||||
#if DISPLAY_ILI9341V || DISPLAY_ST7789V
|
#if DISPLAY_ILI9341V || DISPLAY_ST7789V
|
||||||
CMD(0x2A); DATA(x0 >> 8); DATA(x0 & 0xFF); DATA(x1 >> 8); DATA(x1 & 0xFF); // column addr set
|
CMD(0x2A); DATA(x0 >> 8); DATA(x0 & 0xFF); DATA(x1 >> 8); DATA(x1 & 0xFF); // column addr set
|
||||||
CMD(0x2B); DATA(y0 >> 8); DATA(y0 & 0xFF); DATA(y1 >> 8); DATA(y1 & 0xFF); // row addr set
|
CMD(0x2B); DATA(y0 >> 8); DATA(y0 & 0xFF); DATA(y1 >> 8); DATA(y1 & 0xFF); // row addr set
|
||||||
CMD(0x2C);
|
CMD(0x2C);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_set_orientation(int degrees)
|
void display_set_orientation(int degrees)
|
||||||
{
|
{
|
||||||
|
#if DOUBLE_BUFFER
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
#if DISPLAY_ILI9341V || DISPLAY_ST7789V
|
#if DISPLAY_ILI9341V || DISPLAY_ST7789V
|
||||||
#define MV (1 << 5)
|
#define MV (1 << 5)
|
||||||
#define MX (1 << 6)
|
#define MX (1 << 6)
|
||||||
|
@ -88,8 +158,12 @@ void display_set_orientation(int degrees)
|
||||||
CMD(0x36); DATA(display_command_parameter);
|
CMD(0x36); DATA(display_command_parameter);
|
||||||
display_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); // reset the column and page extents
|
display_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); // reset the column and page extents
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define LED_PWM_TIM_PERIOD (10000)
|
||||||
|
|
||||||
void display_set_backlight(int val)
|
void display_set_backlight(int val)
|
||||||
{
|
{
|
||||||
TIM1->CCR1 = LED_PWM_TIM_PERIOD * val / 255;
|
TIM1->CCR1 = LED_PWM_TIM_PERIOD * val / 255;
|
||||||
|
@ -257,6 +331,101 @@ void display_refresh(void)
|
||||||
// synchronize with the panel synchronization signal in order to avoid visual tearing effects
|
// synchronize with the panel synchronization signal in order to avoid visual tearing effects
|
||||||
while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_12)) { }
|
while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_12)) { }
|
||||||
while (GPIO_PIN_SET == HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_12)) { }
|
while (GPIO_PIN_SET == HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_12)) { }
|
||||||
|
|
||||||
|
#if DOUBLE_BUFFER
|
||||||
|
|
||||||
|
// don't draw if not dirty
|
||||||
|
if (sectrue != DBUF_DIRTY) return;
|
||||||
|
|
||||||
|
// frame limiter = don't redraw frame if older one is younger than 16 ms = 60 fps
|
||||||
|
static uint32_t t0 = 0;
|
||||||
|
uint32_t t1 = HAL_GetTick();
|
||||||
|
if (t1 < t0 + 16) {
|
||||||
|
t0 = t1;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
t0 = t1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint16_t rgb332to565lut[256] = {
|
||||||
|
0x0000, 0x000a, 0x0015, 0x001f, 0x0120, 0x012a, 0x0135, 0x013f,
|
||||||
|
0x0240, 0x024a, 0x0255, 0x025f, 0x0360, 0x036a, 0x0375, 0x037f,
|
||||||
|
0x0480, 0x048a, 0x0495, 0x049f, 0x05a0, 0x05aa, 0x05b5, 0x05bf,
|
||||||
|
0x06c0, 0x06ca, 0x06d5, 0x06df, 0x07e0, 0x07ea, 0x07f5, 0x07ff,
|
||||||
|
0x2000, 0x200a, 0x2015, 0x201f, 0x2120, 0x212a, 0x2135, 0x213f,
|
||||||
|
0x2240, 0x224a, 0x2255, 0x225f, 0x2360, 0x236a, 0x2375, 0x237f,
|
||||||
|
0x2480, 0x248a, 0x2495, 0x249f, 0x25a0, 0x25aa, 0x25b5, 0x25bf,
|
||||||
|
0x26c0, 0x26ca, 0x26d5, 0x26df, 0x27e0, 0x27ea, 0x27f5, 0x27ff,
|
||||||
|
0x4800, 0x480a, 0x4815, 0x481f, 0x4920, 0x492a, 0x4935, 0x493f,
|
||||||
|
0x4a40, 0x4a4a, 0x4a55, 0x4a5f, 0x4b60, 0x4b6a, 0x4b75, 0x4b7f,
|
||||||
|
0x4c80, 0x4c8a, 0x4c95, 0x4c9f, 0x4da0, 0x4daa, 0x4db5, 0x4dbf,
|
||||||
|
0x4ec0, 0x4eca, 0x4ed5, 0x4edf, 0x4fe0, 0x4fea, 0x4ff5, 0x4fff,
|
||||||
|
0x6800, 0x680a, 0x6815, 0x681f, 0x6920, 0x692a, 0x6935, 0x693f,
|
||||||
|
0x6a40, 0x6a4a, 0x6a55, 0x6a5f, 0x6b60, 0x6b6a, 0x6b75, 0x6b7f,
|
||||||
|
0x6c80, 0x6c8a, 0x6c95, 0x6c9f, 0x6da0, 0x6daa, 0x6db5, 0x6dbf,
|
||||||
|
0x6ec0, 0x6eca, 0x6ed5, 0x6edf, 0x6fe0, 0x6fea, 0x6ff5, 0x6fff,
|
||||||
|
0x9000, 0x900a, 0x9015, 0x901f, 0x9120, 0x912a, 0x9135, 0x913f,
|
||||||
|
0x9240, 0x924a, 0x9255, 0x925f, 0x9360, 0x936a, 0x9375, 0x937f,
|
||||||
|
0x9480, 0x948a, 0x9495, 0x949f, 0x95a0, 0x95aa, 0x95b5, 0x95bf,
|
||||||
|
0x96c0, 0x96ca, 0x96d5, 0x96df, 0x97e0, 0x97ea, 0x97f5, 0x97ff,
|
||||||
|
0xb000, 0xb00a, 0xb015, 0xb01f, 0xb120, 0xb12a, 0xb135, 0xb13f,
|
||||||
|
0xb240, 0xb24a, 0xb255, 0xb25f, 0xb360, 0xb36a, 0xb375, 0xb37f,
|
||||||
|
0xb480, 0xb48a, 0xb495, 0xb49f, 0xb5a0, 0xb5aa, 0xb5b5, 0xb5bf,
|
||||||
|
0xb6c0, 0xb6ca, 0xb6d5, 0xb6df, 0xb7e0, 0xb7ea, 0xb7f5, 0xb7ff,
|
||||||
|
0xd800, 0xd80a, 0xd815, 0xd81f, 0xd920, 0xd92a, 0xd935, 0xd93f,
|
||||||
|
0xda40, 0xda4a, 0xda55, 0xda5f, 0xdb60, 0xdb6a, 0xdb75, 0xdb7f,
|
||||||
|
0xdc80, 0xdc8a, 0xdc95, 0xdc9f, 0xdda0, 0xddaa, 0xddb5, 0xddbf,
|
||||||
|
0xdec0, 0xdeca, 0xded5, 0xdedf, 0xdfe0, 0xdfea, 0xdff5, 0xdfff,
|
||||||
|
0xf800, 0xf80a, 0xf815, 0xf81f, 0xf920, 0xf92a, 0xf935, 0xf93f,
|
||||||
|
0xfa40, 0xfa4a, 0xfa55, 0xfa5f, 0xfb60, 0xfb6a, 0xfb75, 0xfb7f,
|
||||||
|
0xfc80, 0xfc8a, 0xfc95, 0xfc9f, 0xfda0, 0xfdaa, 0xfdb5, 0xfdbf,
|
||||||
|
0xfec0, 0xfeca, 0xfed5, 0xfedf, 0xffe0, 0xffea, 0xfff5, 0xffff,
|
||||||
|
};
|
||||||
|
// set full window
|
||||||
|
const uint16_t x0 = 0, y0 = 0, x1 = DISPLAY_RESX - 1, y1 = DISPLAY_RESY - 1;
|
||||||
|
CMD(0x2A); DATA(x0 >> 8); DATA(x0 & 0xFF); DATA(x1 >> 8); DATA(x1 & 0xFF); // column addr set
|
||||||
|
CMD(0x2B); DATA(y0 >> 8); DATA(y0 & 0xFF); DATA(y1 >> 8); DATA(y1 & 0xFF); // row addr set
|
||||||
|
CMD(0x2C);
|
||||||
|
|
||||||
|
// flush double buffer according to orientation
|
||||||
|
// also convert from 8-bit depth to 16-bit depth
|
||||||
|
// (RBB: 3-3-2 bits to 5-6-5 bits: rrrgggbb -> rrrrrggg gggbbbbb)
|
||||||
|
switch (DISPLAY_ORIENTATION) {
|
||||||
|
case 0:
|
||||||
|
for (int i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) {
|
||||||
|
const uint16_t d = rgb332to565lut[DBUF[i]];
|
||||||
|
DATA(d >> 8); DATA(d & 0xFF);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 90:
|
||||||
|
for (int j = 0; j < DISPLAY_RESY; j++) {
|
||||||
|
for (int i = 0; i < DISPLAY_RESX; i++) {
|
||||||
|
const int o = (DISPLAY_RESX - 1 - i) * DISPLAY_RESY + j;
|
||||||
|
const uint16_t d = rgb332to565lut[DBUF[o]];
|
||||||
|
DATA(d >> 8); DATA(d & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 180:
|
||||||
|
for (int i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) {
|
||||||
|
const int o = DISPLAY_RESX * DISPLAY_RESY - 1 - i;
|
||||||
|
const uint16_t d = rgb332to565lut[DBUF[o]];
|
||||||
|
DATA(d >> 8); DATA(d & 0xFF);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 270:
|
||||||
|
for (int j = 0; j < DISPLAY_RESY; j++) {
|
||||||
|
for (int i = 0; i < DISPLAY_RESX; i++) {
|
||||||
|
const int o = i * DISPLAY_RESY + (DISPLAY_RESY - 1 - j);
|
||||||
|
const uint16_t d = rgb332to565lut[DBUF[o]];
|
||||||
|
DATA(d >> 8); DATA(d & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUF_DIRTY = secfalse;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_save(const char *filename)
|
void display_save(const char *filename)
|
||||||
|
|
|
@ -30,8 +30,25 @@ void PIXELDATA(uint16_t c) {
|
||||||
if (!RENDERER) {
|
if (!RENDERER) {
|
||||||
display_init();
|
display_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int r = ((c & 0xF800) >> 11) * 255 / 31;
|
||||||
|
int g = ((c & 0x07E0) >> 5) * 255 / 63;
|
||||||
|
int b = (c & 0x1F) * 255 / 31;
|
||||||
|
|
||||||
|
#define BITS_R 3
|
||||||
|
#define BITS_G 3
|
||||||
|
#define BITS_B 2
|
||||||
|
|
||||||
|
r >>= (8 - BITS_R);
|
||||||
|
g >>= (8 - BITS_G);
|
||||||
|
b >>= (8 - BITS_B);
|
||||||
|
|
||||||
|
r = r * 255 / ((1 << BITS_R) - 1);
|
||||||
|
g = g * 255 / ((1 << BITS_G) - 1);
|
||||||
|
b = b * 255 / ((1 << BITS_B) - 1);
|
||||||
|
|
||||||
if (PIXELWINDOW.pos.x <= PIXELWINDOW.end.x && PIXELWINDOW.pos.y <= PIXELWINDOW.end.y) {
|
if (PIXELWINDOW.pos.x <= PIXELWINDOW.end.x && PIXELWINDOW.pos.y <= PIXELWINDOW.end.y) {
|
||||||
((uint16_t *)BUFFER->pixels)[PIXELWINDOW.pos.x + PIXELWINDOW.pos.y * BUFFER->pitch / sizeof(uint16_t)] = c;
|
((uint16_t *)BUFFER->pixels)[PIXELWINDOW.pos.x + PIXELWINDOW.pos.y * BUFFER->pitch / sizeof(uint16_t)] = RGB16(r, g, b);
|
||||||
}
|
}
|
||||||
PIXELWINDOW.pos.x++;
|
PIXELWINDOW.pos.x++;
|
||||||
if (PIXELWINDOW.pos.x > PIXELWINDOW.end.x) {
|
if (PIXELWINDOW.pos.x > PIXELWINDOW.end.x) {
|
||||||
|
@ -43,6 +60,17 @@ void PIXELDATA(uint16_t c) {
|
||||||
#define PIXELDATA(X) (void)(X)
|
#define PIXELDATA(X) (void)(X)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void display_clear(void)
|
||||||
|
{
|
||||||
|
#ifndef TREZOR_NOUI
|
||||||
|
if (!RENDERER) {
|
||||||
|
display_init();
|
||||||
|
}
|
||||||
|
SDL_FillRect(BUFFER, NULL, SDL_MapRGB(BUFFER->format, 0, 0, 0));
|
||||||
|
SDL_UpdateTexture(TEXTURE, NULL, BUFFER->pixels, BUFFER->pitch);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void display_init(void)
|
void display_init(void)
|
||||||
{
|
{
|
||||||
#ifndef TREZOR_NOUI
|
#ifndef TREZOR_NOUI
|
||||||
|
|
|
@ -67,18 +67,6 @@ static inline void clamp_coords(int x, int y, int w, int h, int *x0, int *y0, in
|
||||||
*y1 = MIN(y + h - 1, DISPLAY_RESY - 1);
|
*y1 = MIN(y + h - 1, DISPLAY_RESY - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_clear(void)
|
|
||||||
{
|
|
||||||
const int saved_orientation = DISPLAY_ORIENTATION;
|
|
||||||
display_orientation(0); // set MADCTL first so that we can set the window correctly next
|
|
||||||
display_set_window(0, 0, MAX_DISPLAY_RESX - 1, MAX_DISPLAY_RESY - 1); // address the complete frame memory
|
|
||||||
for (uint32_t i = 0; i < MAX_DISPLAY_RESX * MAX_DISPLAY_RESY; i++) {
|
|
||||||
PIXELDATA(0x0000); // 2 bytes per pixel because we're using RGB 5-6-5 format
|
|
||||||
}
|
|
||||||
display_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); // go back to restricted window
|
|
||||||
display_orientation(saved_orientation); // if valid, go back to the saved orientation
|
|
||||||
}
|
|
||||||
|
|
||||||
void display_bar(int x, int y, int w, int h, uint16_t c)
|
void display_bar(int x, int y, int w, int h, uint16_t c)
|
||||||
{
|
{
|
||||||
x += DISPLAY_OFFSET.x;
|
x += DISPLAY_OFFSET.x;
|
||||||
|
|
|
@ -13,9 +13,7 @@ from trezor import workflow
|
||||||
|
|
||||||
display = Display()
|
display = Display()
|
||||||
|
|
||||||
# for desktop platforms, we need to refresh the display after each frame
|
loop.after_step_hook = display.refresh
|
||||||
if sys.platform != 'trezor':
|
|
||||||
loop.after_step_hook = display.refresh
|
|
||||||
|
|
||||||
# import constants from modtrezorui
|
# import constants from modtrezorui
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue