Initial framebuffer setup
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
#ifndef NOVA64_FRAMEBUFFER_H
|
||||
#define NOVA64_FRAMEBUFFER_H
|
||||
|
||||
#include "nova64_core.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Display dimensions
|
||||
#define NOVA64_DISPLAY_WIDTH 480
|
||||
#define NOVA64_DISPLAY_HEIGHT 800
|
||||
#define NOVA64_DISPLAY_PIXELS (NOVA64_DISPLAY_WIDTH * NOVA64_DISPLAY_HEIGHT)
|
||||
|
||||
// Pixel format: RGB565 (uint16_t)
|
||||
typedef uint16_t pixel_t;
|
||||
|
||||
// Framebuffer size in bytes (768,000 bytes)
|
||||
#define NOVA64_FRAMEBUFFER_SIZE_BYTES (NOVA64_DISPLAY_PIXELS * sizeof(pixel_t))
|
||||
|
||||
// Alignment requirement for PPU/DMA2D on ESP32-P4 (cache line alignment)
|
||||
#define NOVA64_DMA_ALIGNMENT 64
|
||||
|
||||
typedef struct {
|
||||
pixel_t *front_buffer; // Buffer currently being read by display/MIPI-DSI
|
||||
pixel_t *back_buffer; // Buffer currently being written to by WASM/PPU
|
||||
|
||||
volatile bool vsync_pending; // True when a buffer swap has been requested
|
||||
uint32_t frame_count; // Frame counter
|
||||
} nova64_framebuffer_t;
|
||||
|
||||
// Global instance access
|
||||
NOVA64_API nova64_framebuffer_t nova64_framebuffer;
|
||||
|
||||
// Function prototypes
|
||||
bool nova64_framebuffer_init(void);
|
||||
void nova64_framebuffer_destroy(void);
|
||||
void nova64_framebuffer_swap(void);
|
||||
void nova64_framebuffer_clear(pixel_t color);
|
||||
|
||||
#endif // NOVA64_FRAMEBUFFER_H
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "nova64_core.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "nova64_framebuffer.h"
|
||||
#include "nova64_internal.h"
|
||||
#include "queue.h"
|
||||
#include "task.h"
|
||||
@@ -7,6 +8,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#if defined(ESP_PLATFORM)
|
||||
#include "esp_pm.h"
|
||||
#include "esp_rom_sys.h"
|
||||
@@ -152,6 +154,12 @@ NOVA64_API bool nova64_init(const nova64_io_interface_t *io_interface) {
|
||||
}
|
||||
|
||||
nova64_log("Initializing...\n");
|
||||
|
||||
if (!nova64_framebuffer_init()) {
|
||||
nova64_log("Framebuffer initialization failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!initialize_wasm_runtime()) {
|
||||
nova64_log("WASM runtime initialization failed.\n");
|
||||
return false;
|
||||
@@ -199,6 +207,7 @@ NOVA64_API bool nova64_shutdown(void) {
|
||||
}
|
||||
|
||||
wasm_runner_terminate();
|
||||
nova64_framebuffer_destroy();
|
||||
|
||||
nova64_host_sleep_ms(100); // Allow time for tasks to clean up
|
||||
nova64_log_scheduler_state();
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "nova64_framebuffer.h"
|
||||
#include "nova64_internal.h"
|
||||
#include <string.h>
|
||||
|
||||
// Framebuffer allocation
|
||||
#if defined(ESP_PLATFORM)
|
||||
// ESP-IDF heap-cap-APIs for PSRAM allocation
|
||||
#include "esp_heap_caps.h"
|
||||
#define ALLOC_FRAMEBUFFER(size) \
|
||||
heap_caps_aligned_alloc(NOVA64_DMA_ALIGNMENT, size, \
|
||||
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT)
|
||||
#define FREE_FRAMEBUFFER(ptr) heap_caps_free(ptr)
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#define ALLOC_FRAMEBUFFER(size) malloc(size)
|
||||
#define FREE_FRAMEBUFFER(ptr) free(ptr)
|
||||
#endif
|
||||
|
||||
nova64_framebuffer_t nova64_framebuffer = {0};
|
||||
|
||||
bool nova64_framebuffer_init(void) {
|
||||
nova64_log("Initializing Framebuffer (Resolution: %dx%d, RGB565)...\n");
|
||||
|
||||
nova64_framebuffer.front_buffer =
|
||||
(pixel_t *)ALLOC_FRAMEBUFFER(NOVA64_FRAMEBUFFER_SIZE_BYTES);
|
||||
|
||||
if (!nova64_framebuffer.front_buffer) {
|
||||
nova64_log("ERROR: Failed to allocate Front-Buffer (%d Bytes) in PSRAM!\n",
|
||||
NOVA64_FRAMEBUFFER_SIZE_BYTES);
|
||||
return false;
|
||||
}
|
||||
|
||||
nova64_framebuffer.back_buffer =
|
||||
(pixel_t *)ALLOC_FRAMEBUFFER(NOVA64_FRAMEBUFFER_SIZE_BYTES);
|
||||
|
||||
if (!nova64_framebuffer.back_buffer) {
|
||||
nova64_log("ERROR: Failed to allocate Back-Buffer (%d Bytes) in PSRAM!\n",
|
||||
NOVA64_FRAMEBUFFER_SIZE_BYTES);
|
||||
FREE_FRAMEBUFFER(nova64_framebuffer.front_buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize buffers
|
||||
memset(nova64_framebuffer.front_buffer, 0, NOVA64_FRAMEBUFFER_SIZE_BYTES);
|
||||
memset(nova64_framebuffer.back_buffer, 0, NOVA64_FRAMEBUFFER_SIZE_BYTES);
|
||||
|
||||
nova64_framebuffer.vsync_pending = false;
|
||||
nova64_framebuffer.frame_count = 0;
|
||||
|
||||
nova64_log("Framebuffer initialized successfully in PSRAM. Address: "
|
||||
"Front=%p, Back=%p\n",
|
||||
(void *)nova64_framebuffer.front_buffer,
|
||||
(void *)nova64_framebuffer.back_buffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void nova64_framebuffer_destroy(void) {
|
||||
nova64_log("Destroying Framebuffer and freeing PSRAM...\n");
|
||||
|
||||
if (nova64_framebuffer.front_buffer) {
|
||||
FREE_FRAMEBUFFER(nova64_framebuffer.front_buffer);
|
||||
nova64_framebuffer.front_buffer = NULL;
|
||||
}
|
||||
|
||||
if (nova64_framebuffer.back_buffer) {
|
||||
FREE_FRAMEBUFFER(nova64_framebuffer.back_buffer);
|
||||
nova64_framebuffer.back_buffer = NULL;
|
||||
}
|
||||
|
||||
nova64_framebuffer.vsync_pending = false;
|
||||
nova64_framebuffer.frame_count = 0;
|
||||
|
||||
nova64_log("Framebuffer successfully destroyed.\n");
|
||||
}
|
||||
|
||||
void nova64_framebuffer_swap(void) {
|
||||
pixel_t *temp = nova64_framebuffer.front_buffer;
|
||||
nova64_framebuffer.front_buffer = nova64_framebuffer.back_buffer;
|
||||
nova64_framebuffer.back_buffer = temp;
|
||||
|
||||
nova64_framebuffer.frame_count++;
|
||||
nova64_framebuffer.vsync_pending = false;
|
||||
}
|
||||
|
||||
void nova64_framebuffer_clear(pixel_t color) {
|
||||
uint32_t *p32 = (uint32_t *)nova64_framebuffer.back_buffer;
|
||||
uint32_t color32 = ((uint32_t)color << 16) | color;
|
||||
size_t count32 = NOVA64_DISPLAY_PIXELS / 2;
|
||||
|
||||
for (size_t i = 0; i < count32; i++) {
|
||||
p32[i] = color32;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user