1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-12 17:38:13 +00:00

fixup! refactor(core): extract framebuffer queue for reuse

This commit is contained in:
tychovrahe 2024-12-10 10:40:27 +01:00
parent a6db55dc5d
commit ac2b244107
4 changed files with 69 additions and 40 deletions

View File

@ -1,33 +1,48 @@
#ifdef KERNEL_MODE #ifdef KERNEL_MODE
#include <sys/irq.h>
#include "fb_queue.h" #include "fb_queue.h"
int16_t fb_queue_get_for_copy(volatile frame_buffer_queue_t *queue) { int16_t fb_queue_get_for_copy(frame_buffer_queue_t *queue) {
if (queue->entry[queue->wix] != FB_STATE_PREPARING) { irq_key_t key = irq_lock();
int16_t wix = queue->wix;
if (queue->entry[wix] != FB_STATE_PREPARING) {
// No refresh needed as the frame buffer is not in // No refresh needed as the frame buffer is not in
// the state to be copied to the display // the state to be copied to the display
irq_unlock(key);
return -1; return -1;
} }
return queue->wix; irq_unlock(key);
return wix;
} }
int16_t fb_queue_get_for_write(volatile frame_buffer_queue_t *queue) { int16_t fb_queue_get_for_write(frame_buffer_queue_t *queue) {
frame_buffer_state_t state; frame_buffer_state_t state;
// We have to wait if the buffer was passed for copying // We have to wait if the buffer was passed for copying
// to the interrupt handler // to the interrupt handler
do { do {
irq_key_t key = irq_lock();
state = queue->entry[queue->wix]; state = queue->entry[queue->wix];
irq_unlock(key);
} while (state == FB_STATE_READY || state == FB_STATE_COPYING); } while (state == FB_STATE_READY || state == FB_STATE_COPYING);
irq_key_t key = irq_lock();
queue->entry[queue->wix] = FB_STATE_PREPARING; queue->entry[queue->wix] = FB_STATE_PREPARING;
irq_unlock(key);
return queue->wix; return queue->wix;
} }
int16_t fb_queue_get_for_transfer(volatile frame_buffer_queue_t *queue) { int16_t fb_queue_get_for_transfer(frame_buffer_queue_t *queue) {
irq_key_t key = irq_lock();
if (queue->rix >= FRAME_BUFFER_COUNT) { if (queue->rix >= FRAME_BUFFER_COUNT) {
// This is an invalid state, and we should never get here // This is an invalid state, and we should never get here
irq_unlock(key);
return -1; return -1;
} }
@ -38,12 +53,15 @@ int16_t fb_queue_get_for_transfer(volatile frame_buffer_queue_t *queue) {
case FB_STATE_COPYING: case FB_STATE_COPYING:
// Currently we are copying a data to the display. // Currently we are copying a data to the display.
irq_unlock(key);
return -1; return -1;
break; break;
case FB_STATE_READY: case FB_STATE_READY:
// Now it's proper time to copy the data to the display // Now it's proper time to copy the data to the display
queue->entry[queue->rix] = FB_STATE_COPYING; queue->entry[queue->rix] = FB_STATE_COPYING;
irq_unlock(key);
return queue->rix; return queue->rix;
// NOTE: when copying is done, this queue slot is marked empty // NOTE: when copying is done, this queue slot is marked empty
@ -51,29 +69,36 @@ int16_t fb_queue_get_for_transfer(volatile frame_buffer_queue_t *queue) {
default: default:
// This is an invalid state, and we should never get here // This is an invalid state, and we should never get here
irq_unlock(key);
return -1; return -1;
break; break;
} }
} }
bool fb_queue_set_done(volatile frame_buffer_queue_t *queue) { bool fb_queue_set_done(frame_buffer_queue_t *queue) {
irq_key_t key = irq_lock();
if (queue->rix >= FRAME_BUFFER_COUNT) { if (queue->rix >= FRAME_BUFFER_COUNT) {
// This is an invalid state, and we should never get here // This is an invalid state, and we should never get here
irq_unlock(key);
return false; return false;
} }
if (queue->entry[queue->rix] == FB_STATE_COPYING) { if (queue->entry[queue->rix] == FB_STATE_COPYING) {
queue->entry[queue->rix] = FB_STATE_EMPTY; queue->entry[queue->rix] = FB_STATE_EMPTY;
queue->rix = (queue->rix + 1) % FRAME_BUFFER_COUNT; queue->rix = (queue->rix + 1) % FRAME_BUFFER_COUNT;
irq_unlock(key);
return true; return true;
} }
irq_unlock(key);
return false; return false;
} }
bool fb_queue_set_switched(volatile frame_buffer_queue_t *queue) { bool fb_queue_set_switched(frame_buffer_queue_t *queue) {
irq_key_t key = irq_lock();
if (queue->rix >= FRAME_BUFFER_COUNT) { if (queue->rix >= FRAME_BUFFER_COUNT) {
// This is an invalid state, and we should never get here // This is an invalid state, and we should never get here
irq_unlock(key);
return false; return false;
} }
@ -83,28 +108,35 @@ bool fb_queue_set_switched(volatile frame_buffer_queue_t *queue) {
} }
queue->aix = queue->rix; queue->aix = queue->rix;
queue->rix = (queue->rix + 1) % FRAME_BUFFER_COUNT; queue->rix = (queue->rix + 1) % FRAME_BUFFER_COUNT;
irq_unlock(key);
return true; return true;
} }
irq_unlock(key);
return false; return false;
} }
bool fb_queue_set_ready_for_transfer(volatile frame_buffer_queue_t *queue) { bool fb_queue_set_ready_for_transfer(frame_buffer_queue_t *queue) {
irq_key_t key = irq_lock();
if (queue->wix >= FRAME_BUFFER_COUNT) { if (queue->wix >= FRAME_BUFFER_COUNT) {
// This is an invalid state, and we should never get here // This is an invalid state, and we should never get here
irq_unlock(key);
return false; return false;
} }
if (queue->entry[queue->rix] == FB_STATE_PREPARING) { if (queue->entry[queue->rix] == FB_STATE_PREPARING) {
queue->entry[queue->rix] = FB_STATE_READY; queue->entry[queue->rix] = FB_STATE_READY;
queue->wix = (queue->wix + 1) % FRAME_BUFFER_COUNT; queue->wix = (queue->wix + 1) % FRAME_BUFFER_COUNT;
irq_unlock(key);
return true; return true;
} }
irq_unlock(key);
return false; return false;
} }
void fb_queue_reset(volatile frame_buffer_queue_t *queue) { void fb_queue_reset(frame_buffer_queue_t *queue) {
irq_key_t key = irq_lock();
// Reset the buffer queue so we can eventually continue // Reset the buffer queue so we can eventually continue
// safely in thread mode // safely in thread mode
queue->wix = 0; queue->wix = 0;
@ -112,17 +144,21 @@ void fb_queue_reset(volatile frame_buffer_queue_t *queue) {
for (int i = 0; i < FRAME_BUFFER_COUNT; i++) { for (int i = 0; i < FRAME_BUFFER_COUNT; i++) {
queue->entry[i] = FB_STATE_EMPTY; queue->entry[i] = FB_STATE_EMPTY;
} }
irq_unlock(key);
} }
bool fb_queue_is_processed(volatile frame_buffer_queue_t *queue) { bool fb_queue_is_processed(frame_buffer_queue_t *queue) {
irq_key_t key = irq_lock();
for (int i = 0; i < FRAME_BUFFER_COUNT; i++) { for (int i = 0; i < FRAME_BUFFER_COUNT; i++) {
frame_buffer_state_t state = queue->entry[i]; frame_buffer_state_t state = queue->entry[i];
if (state == FB_STATE_READY || if (state == FB_STATE_READY ||
(state == FB_STATE_COPYING && i != queue->aix)) { (state == FB_STATE_COPYING && i != queue->aix)) {
irq_unlock(key);
return false; return false;
} }
} }
irq_unlock(key);
return true; return true;
} }

View File

@ -43,7 +43,7 @@ typedef enum {
typedef struct { typedef struct {
// Queue entries // Queue entries
volatile frame_buffer_state_t entry[FRAME_BUFFER_COUNT]; frame_buffer_state_t entry[FRAME_BUFFER_COUNT];
// Active index // Active index
// (accessed & updated in the context of the interrupt handlers // (accessed & updated in the context of the interrupt handlers
int16_t aix; int16_t aix;
@ -56,18 +56,29 @@ typedef struct {
} frame_buffer_queue_t; } frame_buffer_queue_t;
int16_t fb_queue_get_for_copy(volatile frame_buffer_queue_t *queue); // Get the frame buffer index for copying to display
// Call from main thread only
int16_t fb_queue_get_for_copy(frame_buffer_queue_t *queue);
int16_t fb_queue_get_for_write(volatile frame_buffer_queue_t *queue); // Get the frame buffer index for writing
// Call from main thread only
int16_t fb_queue_get_for_write(frame_buffer_queue_t *queue);
int16_t fb_queue_get_for_transfer(volatile frame_buffer_queue_t *queue); // Get the frame buffer index for transfer
int16_t fb_queue_get_for_transfer(frame_buffer_queue_t *queue);
bool fb_queue_set_done(volatile frame_buffer_queue_t *queue); // Mark the frame buffer as done, thus no longer used
bool fb_queue_set_done(frame_buffer_queue_t *queue);
bool fb_queue_set_switched(volatile frame_buffer_queue_t *queue); // Mark the frame buffer as switched, thus actively used by display
bool fb_queue_set_switched(frame_buffer_queue_t *queue);
bool fb_queue_set_ready_for_transfer(volatile frame_buffer_queue_t *queue); // Mark the frame buffer as ready to be copied to the display
// Call from main thread only
bool fb_queue_set_ready_for_transfer(frame_buffer_queue_t *queue);
void fb_queue_reset(volatile frame_buffer_queue_t *queue); // Reset the queue state
void fb_queue_reset(frame_buffer_queue_t *queue);
bool fb_queue_is_processed(volatile frame_buffer_queue_t *queue); // Check if all frame buffers are processed
bool fb_queue_is_processed(frame_buffer_queue_t *queue);

View File

@ -210,26 +210,8 @@ void display_refresh(void) {
mpu_set_active_fb(NULL, 0); mpu_set_active_fb(NULL, 0);
#ifndef BOARDLOADER #ifndef BOARDLOADER
if (is_mode_exception()) { // Mark the buffer ready to switch to
// Disable scheduling of any new background copying fb_queue_set_ready_for_transfer(&drv->queue);
NVIC_DisableIRQ(DISPLAY_TE_INTERRUPT_NUM);
// Wait for next TE signal. During this time the
// display might be updated in the background
wait_for_te_signal();
// Stop any background copying even if it is not finished yet
bg_copy_abort();
// Copy the frame buffer to the display manually
copy_fb_to_display(fb_idx);
// Reset the buffer queue so we can eventually continue
// safely in thread mode
fb_queue_reset(&drv->queue);
// Enable normal processing again
NVIC_EnableIRQ(DISPLAY_TE_INTERRUPT_NUM);
} else {
// Mark the buffer ready to switch to
fb_queue_set_ready_for_transfer(&drv->queue);
}
#else // BOARDLOADER #else // BOARDLOADER
wait_for_te_signal(); wait_for_te_signal();

View File

@ -19,7 +19,7 @@ typedef struct {
// Framebuffer queue // Framebuffer queue
// (accessed & updated in the context of the main thread // (accessed & updated in the context of the main thread
// and the interrupt context) // and the interrupt context)
volatile frame_buffer_queue_t queue; frame_buffer_queue_t queue;
#endif #endif
// Current display orientation (0, 90, 180, 270) // Current display orientation (0, 90, 180, 270)