From a77f6aedea51ace50845d7324f9f18d89ac8d583 Mon Sep 17 00:00:00 2001 From: Charlie Birks Date: Sat, 19 Mar 2022 17:24:15 +0000 Subject: [PATCH 1/6] pico: Move all the display code out of main It was the last big thing in there --- 32blit-pico/CMakeLists.txt | 1 + 32blit-pico/display.cpp | 241 +++++++++++++++++++++++++++++++++++++ 32blit-pico/display.hpp | 13 ++ 32blit-pico/main.cpp | 231 +---------------------------------- 4 files changed, 259 insertions(+), 227 deletions(-) create mode 100644 32blit-pico/display.cpp create mode 100644 32blit-pico/display.hpp diff --git a/32blit-pico/CMakeLists.txt b/32blit-pico/CMakeLists.txt index cd75b0f1e..c5b5f8549 100644 --- a/32blit-pico/CMakeLists.txt +++ b/32blit-pico/CMakeLists.txt @@ -13,6 +13,7 @@ target_sources(BlitHalPico INTERFACE ${CMAKE_CURRENT_LIST_DIR}/../3rd-party/fatfs/ffunicode.c ${CMAKE_CURRENT_LIST_DIR}/audio.cpp + ${CMAKE_CURRENT_LIST_DIR}/display.cpp ${CMAKE_CURRENT_LIST_DIR}/file.cpp ${CMAKE_CURRENT_LIST_DIR}/input.cpp ${CMAKE_CURRENT_LIST_DIR}/led.cpp diff --git a/32blit-pico/display.cpp b/32blit-pico/display.cpp new file mode 100644 index 000000000..c25682239 --- /dev/null +++ b/32blit-pico/display.cpp @@ -0,0 +1,241 @@ +#include "display.hpp" + +#include "config.h" + +#ifdef DISPLAY_ST7789 +#include "st7789.hpp" +#elif defined(DISPLAY_SCANVIDEO) +#include "hardware/clocks.h" +#include "pico/time.h" +#include "pico/scanvideo.h" +#include "pico/scanvideo/composable_scanline.h" +#endif + +using namespace blit; + +static SurfaceInfo cur_surf_info; + +#ifdef DISPLAY_ST7789 +// height rounded up to handle the 135px display +static const int lores_page_size = (ST7789_WIDTH / 2) * ((ST7789_HEIGHT + 1) / 2) * 2; + +#if ALLOW_HIRES +static uint16_t screen_fb[ST7789_WIDTH * ST7789_HEIGHT]; +#else +static uint16_t screen_fb[lores_page_size]; // double-buffered +#endif +static bool have_vsync = false; +static bool backlight_enabled = false; + +static const blit::SurfaceTemplate lores_screen{(uint8_t *)screen_fb, Size(ST7789_WIDTH / 2, ST7789_HEIGHT / 2), blit::PixelFormat::RGB565, nullptr}; +static const blit::SurfaceTemplate hires_screen{(uint8_t *)screen_fb, Size(ST7789_WIDTH, ST7789_HEIGHT), blit::PixelFormat::RGB565, nullptr}; + +#elif defined(DISPLAY_SCANVIDEO) +static uint16_t screen_fb[160 * 120 * 2]; +static const blit::SurfaceTemplate lores_screen{(uint8_t *)screen_fb, Size(160, 120), blit::PixelFormat::RGB565, nullptr}; +#endif + +static ScreenMode cur_screen_mode = ScreenMode::lores; +// double buffering for lores +static volatile int buf_index = 0; + +static volatile bool do_render = true; +static uint32_t last_render = 0; + +// user render function +void render(uint32_t); + +#ifdef DISPLAY_ST7789 +static void vsync_callback(uint gpio, uint32_t events) { + if(!do_render && !st7789::dma_is_busy()) { + st7789::update(); + do_render = true; + } +} +#endif + +#ifdef DISPLAY_SCANVIDEO + +static void fill_scanline_buffer(struct scanvideo_scanline_buffer *buffer) { + static uint32_t postamble[] = { + 0x0000u | (COMPOSABLE_EOL_ALIGN << 16) + }; + + int w = screen.bounds.w; + + buffer->data[0] = 4; + buffer->data[1] = host_safe_hw_ptr(buffer->data + 8); + buffer->data[2] = (w - 4) / 2; // first four pixels are handled separately + uint16_t *pixels = screen_fb + buf_index * (160 * 120) + scanvideo_scanline_number(buffer->scanline_id) * w; + buffer->data[3] = host_safe_hw_ptr(pixels + 4); + buffer->data[4] = count_of(postamble); + buffer->data[5] = host_safe_hw_ptr(postamble); + buffer->data[6] = 0; + buffer->data[7] = 0; + buffer->data_used = 8; + + // 3 pixel run followed by main run, consuming the first 4 pixels + buffer->data[8] = (pixels[0] << 16u) | COMPOSABLE_RAW_RUN; + buffer->data[9] = (pixels[1] << 16u) | 0; + buffer->data[10] = (COMPOSABLE_RAW_RUN << 16u) | pixels[2]; + buffer->data[11] = (((w - 3) + 1 - 3) << 16u) | pixels[3]; // note we add one for the black pixel at the end +} + +static int64_t timer_callback(alarm_id_t alarm_id, void *user_data) { + static int last_frame = 0; + struct scanvideo_scanline_buffer *buffer = scanvideo_begin_scanline_generation(false); + while (buffer) { + fill_scanline_buffer(buffer); + scanvideo_end_scanline_generation(buffer); + + auto next_frame = scanvideo_frame_number(scanvideo_get_next_scanline_id()); + if(next_frame != last_frame) { + //if(scanvideo_in_vblank() && !do_render) { + do_render = true; + last_frame = next_frame; + break; + } + + buffer = scanvideo_begin_scanline_generation(false); + } + + return 100; +} +#endif + +void init_display() { +#ifdef DISPLAY_ST7789 + st7789::frame_buffer = screen_fb; + st7789::init(); + st7789::clear(); + + have_vsync = st7789::vsync_callback(vsync_callback); +#endif + +#ifdef DISPLAY_SCANVIDEO + //scanvideo_setup(&vga_mode_320x240_60); // not quite + scanvideo_setup(&vga_mode_160x120_60); + scanvideo_timing_enable(true); + add_alarm_in_us(100, timer_callback, nullptr, true); +#endif +} + +void update_display(uint32_t time) { + +#ifdef DISPLAY_ST7789 + if((do_render || (!have_vsync && time - last_render >= 20)) && (cur_screen_mode == ScreenMode::lores || !st7789::dma_is_busy())) { + if(cur_screen_mode == ScreenMode::lores) { + buf_index ^= 1; + + screen.data = (uint8_t *)screen_fb + (buf_index) * lores_page_size; + st7789::frame_buffer = (uint16_t *)screen.data; + } + + ::render(time); + + if(!have_vsync) { + while(st7789::dma_is_busy()) {} // may need to wait for lores. + st7789::update(); + } + + if(last_render && !backlight_enabled) { + // the first render should have made it to the screen at this point + st7789::set_backlight(255); + backlight_enabled = true; + } + + last_render = time; + do_render = false; + } + +#elif defined(DISPLAY_SCANVIDEO) + if(do_render) { + screen.data = (uint8_t *)screen_fb + (buf_index ^ 1) * (160 * 120 * 2); // only works because there's no "firmware" here + ::render(time); + buf_index ^= 1; + do_render = false; + } +#endif +} + +bool display_render_needed() { + return do_render; +} + +// blit api + +SurfaceInfo &set_screen_mode(ScreenMode mode) { + switch(mode) { + case ScreenMode::lores: + cur_surf_info = lores_screen; + // window +#ifdef DISPLAY_ST7789 + if(have_vsync) + do_render = true; // prevent starting an update during switch + + st7789::set_pixel_double(true); +#endif + break; + + case ScreenMode::hires: +#if defined(DISPLAY_ST7789) && ALLOW_HIRES + if(have_vsync) + do_render = true; + + cur_surf_info = hires_screen; + st7789::frame_buffer = screen_fb; + st7789::set_pixel_double(false); +#else + return cur_surf_info; +#endif + break; + + //case ScreenMode::hires_palette: + // screen = hires_palette_screen; + // break; + } + + cur_screen_mode = mode; + + return cur_surf_info; +} + +bool set_screen_mode_format(ScreenMode new_mode, SurfaceTemplate &new_surf_template) { + new_surf_template.data = (uint8_t *)screen_fb; + + switch(new_mode) { + case ScreenMode::lores: + new_surf_template.bounds = lores_screen.bounds; + break; + case ScreenMode::hires: + case ScreenMode::hires_palette: +#if defined(DISPLAY_ST7789) && ALLOW_HIRES + new_surf_template.bounds = hires_screen.bounds; + break; +#else + return false; // no hires for scanvideo +#endif + } + +#ifdef DISPLAY_ST7789 + if(have_vsync) + do_render = true; // prevent starting an update during switch + + st7789::set_pixel_double(new_mode == ScreenMode::lores); + + if(new_mode == ScreenMode::hires) + st7789::frame_buffer = screen_fb; +#endif + + // don't support any other formats for various reasons (RAM, no format conversion, pixel double PIO) + if(new_surf_template.format != PixelFormat::RGB565) + return false; + + cur_screen_mode = new_mode; + + return true; +} + +void set_screen_palette(const Pen *colours, int num_cols) { + +} diff --git a/32blit-pico/display.hpp b/32blit-pico/display.hpp new file mode 100644 index 000000000..bef4ce0de --- /dev/null +++ b/32blit-pico/display.hpp @@ -0,0 +1,13 @@ +#pragma once +#include + +#include "engine/api_private.hpp" + +void init_display(); +void update_display(uint32_t time); +bool display_render_needed(); + +blit::SurfaceInfo &set_screen_mode(blit::ScreenMode mode); +bool set_screen_mode_format(blit::ScreenMode new_mode, blit::SurfaceTemplate &new_surf_template); + +void set_screen_palette(const blit::Pen *colours, int num_cols); diff --git a/32blit-pico/main.cpp b/32blit-pico/main.cpp index 334126ed6..8a435dffe 100644 --- a/32blit-pico/main.cpp +++ b/32blit-pico/main.cpp @@ -1,137 +1,25 @@ #include #include -#include "hardware/clocks.h" #include "hardware/structs/rosc.h" #include "hardware/vreg.h" #include "pico/binary_info.h" #include "pico/stdlib.h" -#ifdef DISPLAY_SCANVIDEO -#include "pico/scanvideo.h" -#include "pico/scanvideo/composable_scanline.h" -#endif - #include "audio.hpp" #include "config.h" +#include "display.hpp" #include "file.hpp" #include "input.hpp" #include "led.hpp" -#include "st7789.hpp" #include "usb.hpp" #include "engine/api_private.hpp" -#include "engine/engine.hpp" -#include "graphics/surface.hpp" using namespace blit; -static SurfaceInfo cur_surf_info; - -#ifdef DISPLAY_ST7789 -// height rounded up to handle the 135px display -static const int lores_page_size = (ST7789_WIDTH / 2) * ((ST7789_HEIGHT + 1) / 2) * 2; - -#if ALLOW_HIRES -uint16_t screen_fb[ST7789_WIDTH * ST7789_HEIGHT]; -#else -uint16_t screen_fb[lores_page_size]; // double-buffered -#endif -static bool have_vsync = false; - -static const blit::SurfaceTemplate lores_screen{(uint8_t *)screen_fb, Size(ST7789_WIDTH / 2, ST7789_HEIGHT / 2), blit::PixelFormat::RGB565, nullptr}; -static const blit::SurfaceTemplate hires_screen{(uint8_t *)screen_fb, Size(ST7789_WIDTH, ST7789_HEIGHT), blit::PixelFormat::RGB565, nullptr}; - -#elif defined(DISPLAY_SCANVIDEO) -uint16_t screen_fb[160 * 120 * 2]; -static const blit::SurfaceTemplate lores_screen{(uint8_t *)screen_fb, Size(160, 120), blit::PixelFormat::RGB565, nullptr}; -#endif - static blit::AudioChannel channels[CHANNEL_COUNT]; - -ScreenMode cur_screen_mode = ScreenMode::lores; -// double buffering for lores -static volatile int buf_index = 0; - -static volatile bool do_render = true; - -static SurfaceInfo &set_screen_mode(ScreenMode mode) { - switch(mode) { - case ScreenMode::lores: - cur_surf_info = lores_screen; - // window -#ifdef DISPLAY_ST7789 - if(have_vsync) - do_render = true; // prevent starting an update during switch - - st7789::set_pixel_double(true); -#endif - break; - - case ScreenMode::hires: -#if defined(DISPLAY_ST7789) && ALLOW_HIRES - if(have_vsync) - do_render = true; - - cur_surf_info = hires_screen; - st7789::frame_buffer = screen_fb; - st7789::set_pixel_double(false); -#else - return cur_surf_info; -#endif - break; - - //case ScreenMode::hires_palette: - // screen = hires_palette_screen; - // break; - } - - cur_screen_mode = mode; - - return cur_surf_info; -} - -static void set_screen_palette(const Pen *colours, int num_cols) { - -} - -static bool set_screen_mode_format(ScreenMode new_mode, SurfaceTemplate &new_surf_template) { - new_surf_template.data = (uint8_t *)screen_fb; - - switch(new_mode) { - case ScreenMode::lores: - new_surf_template.bounds = lores_screen.bounds; - break; - case ScreenMode::hires: - case ScreenMode::hires_palette: -#if defined(DISPLAY_ST7789) && ALLOW_HIRES - new_surf_template.bounds = hires_screen.bounds; - break; -#else - return false; // no hires for scanvideo -#endif - } - -#ifdef DISPLAY_ST7789 - if(have_vsync) - do_render = true; // prevent starting an update during switch - - st7789::set_pixel_double(new_mode == ScreenMode::lores); - - if(new_mode == ScreenMode::hires) - st7789::frame_buffer = screen_fb; -#endif - - // don't support any other formats for various reasons (RAM, no format conversion, pixel double PIO) - if(new_surf_template.format != PixelFormat::RGB565) - return false; - - cur_screen_mode = new_mode; - - return true; -} - static uint32_t now() { return to_ms_since_boot(get_absolute_time()); } @@ -214,65 +102,6 @@ void init(); void render(uint32_t); void update(uint32_t); -#ifdef DISPLAY_ST7789 -void vsync_callback(uint gpio, uint32_t events) { - if(!do_render && !st7789::dma_is_busy()) { - st7789::update(); - do_render = true; - } -} -#endif - -#ifdef DISPLAY_SCANVIDEO - -static void fill_scanline_buffer(struct scanvideo_scanline_buffer *buffer) { - static uint32_t postamble[] = { - 0x0000u | (COMPOSABLE_EOL_ALIGN << 16) - }; - - int w = screen.bounds.w; - - buffer->data[0] = 4; - buffer->data[1] = host_safe_hw_ptr(buffer->data + 8); - buffer->data[2] = (w - 4) / 2; // first four pixels are handled separately - uint16_t *pixels = screen_fb + buf_index * (160 * 120) + scanvideo_scanline_number(buffer->scanline_id) * w; - buffer->data[3] = host_safe_hw_ptr(pixels + 4); - buffer->data[4] = count_of(postamble); - buffer->data[5] = host_safe_hw_ptr(postamble); - buffer->data[6] = 0; - buffer->data[7] = 0; - buffer->data_used = 8; - - // 3 pixel run followed by main run, consuming the first 4 pixels - buffer->data[8] = (pixels[0] << 16u) | COMPOSABLE_RAW_RUN; - buffer->data[9] = (pixels[1] << 16u) | 0; - buffer->data[10] = (COMPOSABLE_RAW_RUN << 16u) | pixels[2]; - buffer->data[11] = (((w - 3) + 1 - 3) << 16u) | pixels[3]; // note we add one for the black pixel at the end -} - -static int64_t timer_callback(alarm_id_t alarm_id, void *user_data) { - static int last_frame = 0; - struct scanvideo_scanline_buffer *buffer = scanvideo_begin_scanline_generation(false); - while (buffer) { - fill_scanline_buffer(buffer); - scanvideo_end_scanline_generation(buffer); - - auto next_frame = scanvideo_frame_number(scanvideo_get_next_scanline_id()); - if(next_frame != last_frame) { - //if(scanvideo_in_vblank() && !do_render) { - do_render = true; - last_frame = next_frame; - break; - } - - buffer = scanvideo_begin_scanline_generation(false); - } - - - return 100; -} -#endif - int main() { #if OVERCLOCK_250 // Apply a modest overvolt, default is 1.10v. @@ -338,23 +167,7 @@ int main() { api.get_metadata = ::get_metadata; init_led(); - -#ifdef DISPLAY_ST7789 - bool backlight_enabled = false; - st7789::frame_buffer = screen_fb; - st7789::init(); - st7789::clear(); - - have_vsync = st7789::vsync_callback(vsync_callback); -#endif - -#ifdef DISPLAY_SCANVIDEO - //scanvideo_setup(&vga_mode_320x240_60); // not quite - scanvideo_setup(&vga_mode_160x120_60); - scanvideo_timing_enable(true); - add_alarm_in_us(100, timer_callback, nullptr, true); -#endif - + init_display(); init_input(); init_fs(); init_usb(); @@ -369,52 +182,16 @@ int main() { // user init ::init(); - uint32_t last_render = 0; - while(true) { auto now = ::now(); - -#ifdef DISPLAY_ST7789 - if((do_render || (!have_vsync && now - last_render >= 20)) && (cur_screen_mode == ScreenMode::lores || !st7789::dma_is_busy())) { - if(cur_screen_mode == ScreenMode::lores) { - buf_index ^= 1; - - screen.data = (uint8_t *)screen_fb + (buf_index) * lores_page_size; - st7789::frame_buffer = (uint16_t *)screen.data; - } - - ::render(now); - - if(!have_vsync) { - while(st7789::dma_is_busy()) {} // may need to wait for lores. - st7789::update(); - } - - if(last_render && !backlight_enabled) { - // the first render should have made it to the screen at this point - st7789::set_backlight(255); - backlight_enabled = true; - } - - last_render = now; - do_render = false; - } - -#elif defined(DISPLAY_SCANVIDEO) - if(do_render) { - screen.data = (uint8_t *)screen_fb + (buf_index ^ 1) * (160 * 120 * 2); // only works because there's no "firmware" here - ::render(now); - buf_index ^= 1; - do_render = false; - } -#endif + update_display(now); update_input(); int ms_to_next_update = tick(::now()); update_audio(now); update_led(); update_usb(); - if(ms_to_next_update > 1 && !do_render) + if(ms_to_next_update > 1 && !display_render_needed()) best_effort_wfe_or_timeout(make_timeout_time_ms(ms_to_next_update - 1)); } From edd6aa4573d8a421d56caf87756d948d3c04ae5e Mon Sep 17 00:00:00 2001 From: Charlie Birks Date: Sat, 19 Mar 2022 17:36:17 +0000 Subject: [PATCH 2/6] pico: More generic screen width/height defines Only change is defaulting to 320 width if not st7789 --- 32blit-pico/config.h | 12 ++++++++---- 32blit-pico/display.cpp | 8 ++++---- 32blit-pico/st7789.cpp | 4 ++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/32blit-pico/config.h b/32blit-pico/config.h index aefc4b117..ba2b1b3f5 100644 --- a/32blit-pico/config.h +++ b/32blit-pico/config.h @@ -5,12 +5,16 @@ #define ALLOW_HIRES 1 #endif -#ifndef ST7789_WIDTH -#define ST7789_WIDTH 240 +#ifndef DISPLAY_WIDTH +#ifdef DISPLAY_ST7789 +#define DISPLAY_WIDTH 240 +#else +#define DISPLAY_WIDTH 320 +#endif #endif -#ifndef ST7789_HEIGHT -#define ST7789_HEIGHT 240 +#ifndef DISPLAY_HEIGHT +#define DISPLAY_HEIGHT 240 #endif #ifndef OVERCLOCK_250 diff --git a/32blit-pico/display.cpp b/32blit-pico/display.cpp index c25682239..1adbe2203 100644 --- a/32blit-pico/display.cpp +++ b/32blit-pico/display.cpp @@ -17,18 +17,18 @@ static SurfaceInfo cur_surf_info; #ifdef DISPLAY_ST7789 // height rounded up to handle the 135px display -static const int lores_page_size = (ST7789_WIDTH / 2) * ((ST7789_HEIGHT + 1) / 2) * 2; +static const int lores_page_size = (DISPLAY_WIDTH / 2) * ((DISPLAY_HEIGHT + 1) / 2) * 2; #if ALLOW_HIRES -static uint16_t screen_fb[ST7789_WIDTH * ST7789_HEIGHT]; +static uint16_t screen_fb[DISPLAY_WIDTH * DISPLAY_HEIGHT]; #else static uint16_t screen_fb[lores_page_size]; // double-buffered #endif static bool have_vsync = false; static bool backlight_enabled = false; -static const blit::SurfaceTemplate lores_screen{(uint8_t *)screen_fb, Size(ST7789_WIDTH / 2, ST7789_HEIGHT / 2), blit::PixelFormat::RGB565, nullptr}; -static const blit::SurfaceTemplate hires_screen{(uint8_t *)screen_fb, Size(ST7789_WIDTH, ST7789_HEIGHT), blit::PixelFormat::RGB565, nullptr}; +static const blit::SurfaceTemplate lores_screen{(uint8_t *)screen_fb, Size(DISPLAY_WIDTH / 2, DISPLAY_HEIGHT / 2), blit::PixelFormat::RGB565, nullptr}; +static const blit::SurfaceTemplate hires_screen{(uint8_t *)screen_fb, Size(DISPLAY_WIDTH, DISPLAY_HEIGHT), blit::PixelFormat::RGB565, nullptr}; #elif defined(DISPLAY_SCANVIDEO) static uint16_t screen_fb[160 * 120 * 2]; diff --git a/32blit-pico/st7789.cpp b/32blit-pico/st7789.cpp index 3c3188096..828b0046a 100644 --- a/32blit-pico/st7789.cpp +++ b/32blit-pico/st7789.cpp @@ -64,8 +64,8 @@ namespace st7789 { static uint32_t dma_channel = 0; // screen properties - static const uint16_t width = ST7789_WIDTH; - static const uint16_t height = ST7789_HEIGHT; + static const uint16_t width = DISPLAY_WIDTH; + static const uint16_t height = DISPLAY_HEIGHT; static uint16_t win_w, win_h; // window size From a1405ee12d653c91caeaae249c66e1ffa9e906dc Mon Sep 17 00:00:00 2001 From: Charlie Birks Date: Sat, 19 Mar 2022 17:38:45 +0000 Subject: [PATCH 3/6] pico: Default ALLOW_HIRES to 0 when not supported --- 32blit-pico/config.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/32blit-pico/config.h b/32blit-pico/config.h index ba2b1b3f5..8fe80725d 100644 --- a/32blit-pico/config.h +++ b/32blit-pico/config.h @@ -2,7 +2,11 @@ // these are the defaults #ifndef ALLOW_HIRES +#ifdef DISPLAY_ST7789 #define ALLOW_HIRES 1 +#else +#define ALLOW_HIRES 0 // hires is currently not supported for VGA/DVI +#endif #endif #ifndef DISPLAY_WIDTH From a5c0e1001fd272dc957de720c5ab79256876e0a0 Mon Sep 17 00:00:00 2001 From: Charlie Birks Date: Sat, 19 Mar 2022 17:57:06 +0000 Subject: [PATCH 4/6] pico: Deduplicate framebuffer setup --- 32blit-pico/display.cpp | 50 ++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/32blit-pico/display.cpp b/32blit-pico/display.cpp index 1adbe2203..5bcc1f3b3 100644 --- a/32blit-pico/display.cpp +++ b/32blit-pico/display.cpp @@ -15,8 +15,8 @@ using namespace blit; static SurfaceInfo cur_surf_info; -#ifdef DISPLAY_ST7789 // height rounded up to handle the 135px display +// this is in bytes static const int lores_page_size = (DISPLAY_WIDTH / 2) * ((DISPLAY_HEIGHT + 1) / 2) * 2; #if ALLOW_HIRES @@ -24,17 +24,10 @@ static uint16_t screen_fb[DISPLAY_WIDTH * DISPLAY_HEIGHT]; #else static uint16_t screen_fb[lores_page_size]; // double-buffered #endif -static bool have_vsync = false; -static bool backlight_enabled = false; static const blit::SurfaceTemplate lores_screen{(uint8_t *)screen_fb, Size(DISPLAY_WIDTH / 2, DISPLAY_HEIGHT / 2), blit::PixelFormat::RGB565, nullptr}; static const blit::SurfaceTemplate hires_screen{(uint8_t *)screen_fb, Size(DISPLAY_WIDTH, DISPLAY_HEIGHT), blit::PixelFormat::RGB565, nullptr}; -#elif defined(DISPLAY_SCANVIDEO) -static uint16_t screen_fb[160 * 120 * 2]; -static const blit::SurfaceTemplate lores_screen{(uint8_t *)screen_fb, Size(160, 120), blit::PixelFormat::RGB565, nullptr}; -#endif - static ScreenMode cur_screen_mode = ScreenMode::lores; // double buffering for lores static volatile int buf_index = 0; @@ -46,6 +39,9 @@ static uint32_t last_render = 0; void render(uint32_t); #ifdef DISPLAY_ST7789 +static bool have_vsync = false; +static bool backlight_enabled = false; + static void vsync_callback(uint gpio, uint32_t events) { if(!do_render && !st7789::dma_is_busy()) { st7789::update(); @@ -150,7 +146,7 @@ void update_display(uint32_t time) { #elif defined(DISPLAY_SCANVIDEO) if(do_render) { - screen.data = (uint8_t *)screen_fb + (buf_index ^ 1) * (160 * 120 * 2); // only works because there's no "firmware" here + screen.data = (uint8_t *)screen_fb + (buf_index ^ 1) * lores_page_size; // only works because there's no "firmware" here ::render(time); buf_index ^= 1; do_render = false; @@ -168,23 +164,11 @@ SurfaceInfo &set_screen_mode(ScreenMode mode) { switch(mode) { case ScreenMode::lores: cur_surf_info = lores_screen; - // window -#ifdef DISPLAY_ST7789 - if(have_vsync) - do_render = true; // prevent starting an update during switch - - st7789::set_pixel_double(true); -#endif break; case ScreenMode::hires: -#if defined(DISPLAY_ST7789) && ALLOW_HIRES - if(have_vsync) - do_render = true; - +#if ALLOW_HIRES cur_surf_info = hires_screen; - st7789::frame_buffer = screen_fb; - st7789::set_pixel_double(false); #else return cur_surf_info; #endif @@ -195,6 +179,16 @@ SurfaceInfo &set_screen_mode(ScreenMode mode) { // break; } +#ifdef DISPLAY_ST7789 + if(have_vsync) + do_render = true; // prevent starting an update during switch + + st7789::set_pixel_double(mode == ScreenMode::lores); + + if(mode == ScreenMode::hires) + st7789::frame_buffer = screen_fb; +#endif + cur_screen_mode = mode; return cur_surf_info; @@ -209,7 +203,7 @@ bool set_screen_mode_format(ScreenMode new_mode, SurfaceTemplate &new_surf_templ break; case ScreenMode::hires: case ScreenMode::hires_palette: -#if defined(DISPLAY_ST7789) && ALLOW_HIRES +#if ALLOW_HIRES new_surf_template.bounds = hires_screen.bounds; break; #else @@ -218,13 +212,13 @@ bool set_screen_mode_format(ScreenMode new_mode, SurfaceTemplate &new_surf_templ } #ifdef DISPLAY_ST7789 - if(have_vsync) - do_render = true; // prevent starting an update during switch + if(have_vsync) + do_render = true; // prevent starting an update during switch - st7789::set_pixel_double(new_mode == ScreenMode::lores); + st7789::set_pixel_double(new_mode == ScreenMode::lores); - if(new_mode == ScreenMode::hires) - st7789::frame_buffer = screen_fb; + if(new_mode == ScreenMode::hires) + st7789::frame_buffer = screen_fb; #endif // don't support any other formats for various reasons (RAM, no format conversion, pixel double PIO) From 0e05a0da4b47358c5073c76ad809944cf1922851 Mon Sep 17 00:00:00 2001 From: Charlie Birks Date: Sat, 19 Mar 2022 16:31:20 +0000 Subject: [PATCH 5/6] pico: shave two instructions from the pixel-doubling program Most of the delay between pairs of pixels... still only get 320x240 lores at 48Hz though --- 32blit-pico/st7789.pio | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/32blit-pico/st7789.pio b/32blit-pico/st7789.pio index 7713fa1f9..d75461864 100644 --- a/32blit-pico/st7789.pio +++ b/32blit-pico/st7789.pio @@ -14,13 +14,11 @@ .wrap_target pull ; fetch two pixels - out y, 16 ; first pixel in y register - out x, 16 ; second pixel in x register + mov x, osr ; both pixels in x register + out y, 16 ; second pixel in y register -; write first pixel +; write first pixel (still in osr) - mov osr, x ; move pixel data back into osr from register x - out null, 16 ; discard the 16-bits of dummy data from the mov p1: out pins, 1 side 0 ; output bit, clear clock jmp !osre p1 side 1 ; if still bits in osr then jump back to start of loop and clock in data @@ -28,7 +26,7 @@ p1: ; duplicate first pixel mov osr, x ; move pixel data back into osr from register x - out null, 16 ; discard as above.. + out null, 16 ; discard second pixel p1d: out pins, 1 side 0 ; output bit, clear clock jmp !osre p1d side 1 ; if still bits in osr then jump back to start of loop and clock in data @@ -36,7 +34,7 @@ p1d: ; write second pixel mov osr, y ; move pixel data back into osr from register y - out null, 16 ; discard as above.. + out null, 16 ; discard the 16-bits of dummy data from the mov p2: out pins, 1 side 0 ; output bit, clear clock jmp !osre p2 side 1 ; if still bits in osr then jump back to start of loop and clock in data From 756df7ad8854604f83e8eb8aa44007f7b3634837 Mon Sep 17 00:00:00 2001 From: Charlie Birks Date: Fri, 25 Mar 2022 11:43:53 +0000 Subject: [PATCH 6/6] pico: fix some warnings in display.cpp last_render is only used by the st7789 code, hires_palette is unsupported --- 32blit-pico/display.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/32blit-pico/display.cpp b/32blit-pico/display.cpp index 5bcc1f3b3..ee6aa6ed8 100644 --- a/32blit-pico/display.cpp +++ b/32blit-pico/display.cpp @@ -33,7 +33,6 @@ static ScreenMode cur_screen_mode = ScreenMode::lores; static volatile int buf_index = 0; static volatile bool do_render = true; -static uint32_t last_render = 0; // user render function void render(uint32_t); @@ -41,6 +40,7 @@ void render(uint32_t); #ifdef DISPLAY_ST7789 static bool have_vsync = false; static bool backlight_enabled = false; +static uint32_t last_render = 0; static void vsync_callback(uint gpio, uint32_t events) { if(!do_render && !st7789::dma_is_busy()) { @@ -174,9 +174,8 @@ SurfaceInfo &set_screen_mode(ScreenMode mode) { #endif break; - //case ScreenMode::hires_palette: - // screen = hires_palette_screen; - // break; + case ScreenMode::hires_palette: + return cur_surf_info; // unsupported } #ifdef DISPLAY_ST7789