1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-01-31 18:00:58 +00:00

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

This commit is contained in:
tychovrahe 2024-12-11 16:16:59 +01:00
parent d89736b87b
commit 5b29060167
2 changed files with 103 additions and 187 deletions

View File

@ -1,165 +1,94 @@
#ifdef KERNEL_MODE #ifdef KERNEL_MODE
#include <trezor_rtl.h>
#include <sys/irq.h> #include <sys/irq.h>
#include "fb_queue.h" #include "fb_queue.h"
int16_t fb_queue_get_for_copy(frame_buffer_queue_t *queue) { // Initializes the queue and make it empty
irq_key_t key = irq_lock(); // Clear peeked flag
int16_t wix = queue->wix; void fb_queue_reset(fb_queue_t* queue) {
if (queue->entry[wix] != FB_STATE_PREPARING) { memset(queue, 0, sizeof(fb_queue_t));
// No refresh needed as the frame buffer is not in
// the state to be copied to the display
irq_unlock(key);
return -1;
}
irq_unlock(key);
return wix;
}
int16_t fb_queue_get_for_write(frame_buffer_queue_t *queue) {
frame_buffer_state_t state;
// We have to wait if the buffer was passed for copying
// to the interrupt handler
do {
irq_key_t key = irq_lock();
state = queue->entry[queue->wix];
irq_unlock(key);
} while (state == FB_STATE_READY || state == FB_STATE_COPYING);
irq_key_t key = irq_lock();
queue->entry[queue->wix] = FB_STATE_PREPARING;
irq_unlock(key);
return queue->wix;
}
int16_t fb_queue_get_for_transfer(frame_buffer_queue_t *queue) {
irq_key_t key = irq_lock();
if (queue->rix >= FRAME_BUFFER_COUNT) {
// This is an invalid state, and we should never get here
irq_unlock(key);
return -1;
}
switch (queue->entry[queue->rix]) {
case FB_STATE_EMPTY:
case FB_STATE_PREPARING:
// No new frame queued
case FB_STATE_COPYING:
// Currently we are copying a data to the display.
irq_unlock(key);
return -1;
break;
case FB_STATE_READY:
// Now it's proper time to copy the data to the display
queue->entry[queue->rix] = FB_STATE_COPYING;
irq_unlock(key);
return queue->rix;
// NOTE: when copying is done, this queue slot is marked empty
break;
default:
// This is an invalid state, and we should never get here
irq_unlock(key);
return -1;
break;
}
}
bool fb_queue_set_done(frame_buffer_queue_t *queue) {
irq_key_t key = irq_lock();
if (queue->rix >= FRAME_BUFFER_COUNT) {
// This is an invalid state, and we should never get here
irq_unlock(key);
return false;
}
if (queue->entry[queue->rix] == FB_STATE_COPYING) {
queue->entry[queue->rix] = FB_STATE_EMPTY;
queue->rix = (queue->rix + 1) % FRAME_BUFFER_COUNT;
irq_unlock(key);
return true;
}
irq_unlock(key);
return false;
}
bool fb_queue_set_switched(frame_buffer_queue_t *queue) {
irq_key_t key = irq_lock();
if (queue->rix >= FRAME_BUFFER_COUNT) {
// This is an invalid state, and we should never get here
irq_unlock(key);
return false;
}
if (queue->entry[queue->rix] == FB_STATE_COPYING) {
if (queue->aix >= 0) {
queue->entry[queue->aix] = FB_STATE_EMPTY;
}
queue->aix = queue->rix;
queue->rix = (queue->rix + 1) % FRAME_BUFFER_COUNT;
irq_unlock(key);
return true;
}
irq_unlock(key);
return false;
}
bool fb_queue_set_ready_for_transfer(frame_buffer_queue_t *queue) {
irq_key_t key = irq_lock();
if (queue->wix >= FRAME_BUFFER_COUNT) {
// This is an invalid state, and we should never get here
irq_unlock(key);
return false;
}
if (queue->entry[queue->rix] == FB_STATE_PREPARING) {
queue->entry[queue->rix] = FB_STATE_READY;
queue->wix = (queue->wix + 1) % FRAME_BUFFER_COUNT;
irq_unlock(key);
return true;
}
irq_unlock(key);
return false;
}
void fb_queue_reset(frame_buffer_queue_t *queue) {
irq_key_t key = irq_lock();
// Reset the buffer queue so we can eventually continue
// safely in thread mode
queue->wix = 0;
queue->rix = 0;
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->entries[i].index = -1;
} }
irq_unlock(key);
} }
bool fb_queue_is_processed(frame_buffer_queue_t *queue) { // Inserts a new element to the tail of the queue
irq_key_t key = irq_lock(); bool fb_queue_put(fb_queue_t* queue, int16_t index) {
for (int i = 0; i < FRAME_BUFFER_COUNT; i++) { irq_key_t irq_key = irq_lock();
frame_buffer_state_t state = queue->entry[i];
if (state == FB_STATE_READY || // check if the queue is full
(state == FB_STATE_COPYING && i != queue->aix)) { if (queue->entries[queue->wix].index != -1) {
irq_unlock(key); irq_unlock(irq_key);
return false; return false;
}
} }
irq_unlock(key); queue->entries[queue->wix].index = index;
queue->wix = (queue->wix + 1) % FRAME_BUFFER_COUNT;
irq_unlock(irq_key);
return true; return true;
} }
// Removes an element from the queue head, returns -1 if the queue is empty
// Clear peeked flag
int16_t fb_queue_take(fb_queue_t* queue) {
irq_key_t irq_key = irq_lock();
if (queue->entries[queue->rix].index == -1) {
irq_unlock(irq_key);
return -1;
}
queue->peaked = false;
int16_t index = queue->entries[queue->rix].index;
queue->entries[queue->rix].index = -1;
queue->rix = (queue->rix + 1) % FRAME_BUFFER_COUNT;
irq_unlock(irq_key);
return index;
}
// Returns true if the queue is empty
bool fb_queue_empty(fb_queue_t* queue) {
irq_key_t irq_key = irq_lock();
if (queue->entries[queue->rix].index == -1) {
irq_unlock(irq_key);
return true;
}
irq_unlock(irq_key);
return false;
}
// Waits until the queue is not empty
void fb_queue_wait(fb_queue_t* queue) {
while (fb_queue_empty(queue))
;
}
// Returns the head of the queue (or -1 if the queue is empty)
// Set peeked flag if the queue is not empty
int16_t fb_queue_peek(fb_queue_t* queue) {
irq_key_t irq_key = irq_lock();
if (queue->entries[queue->rix].index == -1) {
irq_unlock(irq_key);
return -1;
}
int16_t index = queue->entries[queue->rix].index;
queue->peaked = true;
irq_unlock(irq_key);
return index;
}
// Return if the head was already peeked
bool fb_queue_peeked(fb_queue_t* queue) { return queue->peaked; }
#endif #endif

View File

@ -27,26 +27,14 @@
#define FRAME_BUFFER_COUNT 2 #define FRAME_BUFFER_COUNT 2
// Each frame buffer can be in one of the following states: // Each frame buffer can be in one of the following states:
typedef enum { typedef struct {
// The frame buffer is empty and can be written to int16_t index;
FB_STATE_EMPTY = 0, } fb_queue_entry;
// The frame buffer pass passed to application
FB_STATE_PREPARING = 1,
// The frame buffer was written to and is ready
// to be copied to the display
FB_STATE_READY = 2,
// The frame buffer is currently being copied to
// the display
FB_STATE_COPYING = 3,
} frame_buffer_state_t;
typedef struct { typedef struct {
// Queue entries // Queue entries
frame_buffer_state_t entry[FRAME_BUFFER_COUNT]; fb_queue_entry entries[FRAME_BUFFER_COUNT];
// Active index
// (accessed & updated in the context of the interrupt handlers
int16_t aix;
// Read index // Read index
// (accessed & updated in the context of the interrupt handlers // (accessed & updated in the context of the interrupt handlers
uint8_t rix; uint8_t rix;
@ -54,31 +42,30 @@ typedef struct {
// (accessed & updated in context of the main thread) // (accessed & updated in context of the main thread)
uint8_t wix; uint8_t wix;
} frame_buffer_queue_t; // Flag indicating that the head of the queue has been peaked
bool peaked;
// Get the frame buffer index for copying to display } fb_queue_t;
// Call from main thread only
int16_t fb_queue_get_for_copy(frame_buffer_queue_t *queue);
// Get the frame buffer index for writing // Initializes the queue and make it empty
// Call from main thread only // Clear peeked flag
int16_t fb_queue_get_for_write(frame_buffer_queue_t *queue); void fb_queue_reset(fb_queue_t* queue);
// Get the frame buffer index for transfer // Inserts a new element to the tail of the queue
int16_t fb_queue_get_for_transfer(frame_buffer_queue_t *queue); bool fb_queue_put(fb_queue_t* queue, int16_t index);
// Mark the frame buffer as done, thus no longer used // Removes an element from the queue head, returns -1 if the queue is empty
bool fb_queue_set_done(frame_buffer_queue_t *queue); // Clear peeked flag
int16_t fb_queue_take(fb_queue_t* queue);
// Returns true if the queue is empty
bool fb_queue_empty(fb_queue_t* queue);
// Mark the frame buffer as switched, thus actively used by display // Waits until the queue is not empty
bool fb_queue_set_switched(frame_buffer_queue_t *queue); void fb_queue_wait(fb_queue_t* queue);
// Mark the frame buffer as ready to be copied to the display // Returns the head of the queue (or -1 if the queue is empty)
// Call from main thread only // Set peeked flag if the queue is not empty
bool fb_queue_set_ready_for_transfer(frame_buffer_queue_t *queue); int16_t fb_queue_peek(fb_queue_t* queue);
// Reset the queue state // Return if the head was already peeked
void fb_queue_reset(frame_buffer_queue_t *queue); bool fb_queue_peeked(fb_queue_t* queue);
// Check if all frame buffers are processed
bool fb_queue_is_processed(frame_buffer_queue_t *queue);