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:
parent
d89736b87b
commit
5b29060167
@ -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
|
||||||
|
@ -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);
|
|
||||||
|
Loading…
Reference in New Issue
Block a user