diff --git a/core/embed/unix/common.c b/core/embed/unix/common.c index 0f2543615e..29f1605553 100644 --- a/core/embed/unix/common.c +++ b/core/embed/unix/common.c @@ -148,14 +148,20 @@ static int SDLCALL emulator_event_filter(void *userdata, SDL_Event *event) { case SDLK_p: display_save("emu"); return 0; +#if defined TREZOR_MODEL_T + // Left and right arrows controlling display gamma + // Only for TT (in button models, arrows do different things) case SDLK_LEFT: DISPLAY_GAMMA = fmaxf(0.0f, DISPLAY_GAMMA - 0.05f); printf("DISPLAY_GAMMA: %0.2f\n", DISPLAY_GAMMA); + display_refresh(); return 0; case SDLK_RIGHT: DISPLAY_GAMMA = fminf(8.0f, DISPLAY_GAMMA + 0.05f); printf("DISPLAY_GAMMA: %0.2f\n", DISPLAY_GAMMA); + display_refresh(); return 0; +#endif } break; } diff --git a/core/embed/unix/display-unix.c b/core/embed/unix/display-unix.c index d8e6fa0075..a30d487cdd 100644 --- a/core/embed/unix/display-unix.c +++ b/core/embed/unix/display-unix.c @@ -63,7 +63,11 @@ static SDL_Window *WINDOW; static SDL_Renderer *RENDERER; +// BUFFER_TO_DISPLAY will contain the actual pixels to be displayed, +// it will be filled from BUFFER by gamma-correcting the pixel colors. +// Screenshots will be taken with data from BUFFER. static SDL_Surface *BUFFER; +static SDL_Surface *BUFFER_TO_DISPLAY; static SDL_Texture *TEXTURE, *BACKGROUND; static SDL_Surface *PREV_SAVED; @@ -71,9 +75,14 @@ static SDL_Surface *PREV_SAVED; static int DISPLAY_BACKLIGHT = -1; static int DISPLAY_ORIENTATION = -1; float DISPLAY_GAMMA = 0.55f; +// Will depend on SDL_VIDEODRIVER env variable +static bool DO_GAMMA_CORRECTION = true; int sdl_display_res_x = DISPLAY_RESX, sdl_display_res_y = DISPLAY_RESY; int sdl_touch_offset_x, sdl_touch_offset_y; +// Using RGB565 (16-bit) color format. +typedef uint16_t pixel_color; + // this is just for compatibility with DMA2D using algorithms uint8_t *const DISPLAY_DATA_ADDRESS = 0; @@ -89,45 +98,46 @@ static struct { } pos; } PIXELWINDOW; -uint16_t gamma_correct(uint16_t c) { +pixel_color gamma_correct(pixel_color c) { // NOTE: 0x1f/31 and 0x3f/63 are maximum values of RGB components // given the color is 16-bit (5 bits for R, 6 bits for G, 5 bits for B). int r = (c >> 11) & 0x1f; int g = (c >> 5) & 0x3f; int b = c & 0x1f; - float fr = r / 31.0; - float fg = g / 63.0; - float fb = b / 31.0; - - fr = pow(fr, DISPLAY_GAMMA); - fg = pow(fg, DISPLAY_GAMMA); - fb = pow(fb, DISPLAY_GAMMA); - - r = (int)round(fr * 31.0); - g = (int)round(fg * 63.0); - b = (int)round(fb * 31.0); + r = (int)round(pow(r / 31.0, DISPLAY_GAMMA) * 31.0); + g = (int)round(pow(g / 63.0, DISPLAY_GAMMA) * 63.0); + b = (int)round(pow(b / 31.0, DISPLAY_GAMMA) * 31.0); return (r << 11) | (g << 5) | b; } -void display_pixeldata(uint16_t c) { +void gamma_correct_buffer_to_display(void) { + // Gamma correct all the pixels in BUFFER_TO_DISPLAY. + pixel_color *pixels = (pixel_color *)BUFFER_TO_DISPLAY->pixels; + for (int y = 0; y < BUFFER_TO_DISPLAY->h; y++) { + for (int x = 0; x < BUFFER_TO_DISPLAY->w; x++) { + int index = y * BUFFER_TO_DISPLAY->pitch / 2 + x; + pixels[index] = gamma_correct(pixels[index]); + } + } +} + +void display_pixeldata(pixel_color c) { #if defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R // set to white if highest bits of all R, G, B values are set to 1 // bin(10000 100000 10000) = hex(0x8410) // otherwise set to black c = (c & 0x8410) ? 0xFFFF : 0x0000; -#elif defined TREZOR_MODEL_T - c = gamma_correct(c); #endif if (!RENDERER) { display_init(); } if (PIXELWINDOW.pos.x <= PIXELWINDOW.end.x && PIXELWINDOW.pos.y <= PIXELWINDOW.end.y) { - ((uint16_t *) + ((pixel_color *) BUFFER->pixels)[PIXELWINDOW.pos.x + PIXELWINDOW.pos.y * BUFFER->pitch / - sizeof(uint16_t)] = c; + sizeof(pixel_color)] = c; } PIXELWINDOW.pos.x++; if (PIXELWINDOW.pos.x > PIXELWINDOW.end.x) { @@ -145,6 +155,7 @@ void display_init_seq(void) {} void display_deinit(void) { SDL_FreeSurface(PREV_SAVED); SDL_FreeSurface(BUFFER); + SDL_FreeSurface(BUFFER_TO_DISPLAY); if (BACKGROUND != NULL) { SDL_DestroyTexture(BACKGROUND); } @@ -167,6 +178,15 @@ void display_init(void) { } atexit(display_deinit); + // Not doing gamma correction for "dummy" SDL driver + // (not to slow down device/UI tests) + char *sdl_env = getenv("SDL_VIDEODRIVER"); + if (sdl_env && strcmp(sdl_env, "dummy") == 0) { + DO_GAMMA_CORRECTION = false; + } else { + DO_GAMMA_CORRECTION = true; + } + char *window_title = NULL; char *window_title_alloc = NULL; if (asprintf(&window_title_alloc, "Trezor^emu: %s", profile_name()) > 0) { @@ -200,6 +220,9 @@ void display_init(void) { SDL_RenderClear(RENDERER); BUFFER = SDL_CreateRGBSurface(0, MAX_DISPLAY_RESX, MAX_DISPLAY_RESY, 16, 0xF800, 0x07E0, 0x001F, 0x0000); + BUFFER_TO_DISPLAY = + SDL_CreateRGBSurface(0, MAX_DISPLAY_RESX, MAX_DISPLAY_RESY, 16, 0xF800, + 0x07E0, 0x001F, 0x0000); TEXTURE = SDL_CreateTexture(RENDERER, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, DISPLAY_RESX, DISPLAY_RESY); @@ -272,7 +295,17 @@ void display_refresh(void) { } else { SDL_RenderClear(RENDERER); } - SDL_UpdateTexture(TEXTURE, NULL, BUFFER->pixels, BUFFER->pitch); + // Fill BUFFER_TO_DISPLAY with BUFFER data + SDL_BlitSurface(BUFFER, NULL, BUFFER_TO_DISPLAY, NULL); +#if defined TREZOR_MODEL_T + // Gamma-correcting the display buffer for model T when wanted + if (DO_GAMMA_CORRECTION) { + gamma_correct_buffer_to_display(); + } +#endif + // Show the display buffer + SDL_UpdateTexture(TEXTURE, NULL, BUFFER_TO_DISPLAY->pixels, + BUFFER_TO_DISPLAY->pitch); #define BACKLIGHT_NORMAL 150 SDL_SetTextureAlphaMod(TEXTURE, MIN(255, 255 * DISPLAY_BACKLIGHT / BACKLIGHT_NORMAL));