2021-02-07 00:49:26 +00:00
/*
* Copyright ( c ) 2020 Raspberry Pi ( Trading ) Ltd .
*
* SPDX - License - Identifier : BSD - 3 - Clause
*/
2021-01-20 17:16:37 +00:00
# include <stdio.h>
# include "pico.h"
# include "pico/scanvideo.h"
# include "pico/scanvideo/composable_scanline.h"
# include "pico/multicore.h"
# include "pico/sync.h"
# include "pico/stdlib.h"
# define DUAL_CORE_RENDER
# define VGA_MODE vga_mode_320x240_60
extern const struct scanvideo_pio_program video_24mhz_composable ;
// to make sure only one core updates the state when the frame number changes
// todo note we should actually make sure here that the other core isn't still rendering (i.e. all must arrive before either can proceed - a la barrier)
static struct mutex frame_logic_mutex ;
static void frame_update_logic ( ) ;
static void render_scanline ( struct scanvideo_scanline_buffer * dest , int core ) ;
// "Worker thread" for each core
void render_loop ( ) {
static uint32_t last_frame_num = 0 ;
int core_num = get_core_num ( ) ;
printf ( " Rendering on core %d \n " , core_num ) ;
while ( true ) {
struct scanvideo_scanline_buffer * scanline_buffer = scanvideo_begin_scanline_generation ( true ) ;
mutex_enter_blocking ( & frame_logic_mutex ) ;
uint32_t frame_num = scanvideo_frame_number ( scanline_buffer - > scanline_id ) ;
// Note that with multiple cores we may have got here not for the first
// scanline, however one of the cores will do this logic first before either
// does the actual generation
if ( frame_num ! = last_frame_num ) {
last_frame_num = frame_num ;
frame_update_logic ( ) ;
}
mutex_exit ( & frame_logic_mutex ) ;
render_scanline ( scanline_buffer , core_num ) ;
// Release the rendered buffer into the wild
scanvideo_end_scanline_generation ( scanline_buffer ) ;
}
}
struct semaphore video_setup_complete ;
void core1_func ( ) {
sem_acquire_blocking ( & video_setup_complete ) ;
render_loop ( ) ;
}
int vga_main ( void ) {
mutex_init ( & frame_logic_mutex ) ;
sem_init ( & video_setup_complete , 0 , 1 ) ;
// Core 1 will wait for us to finish video setup, and then start rendering
# ifdef DUAL_CORE_RENDER
multicore_launch_core1 ( core1_func ) ;
# endif
scanvideo_setup ( & VGA_MODE ) ;
scanvideo_timing_enable ( true ) ;
sem_release ( & video_setup_complete ) ;
render_loop ( ) ;
return 0 ;
}
void frame_update_logic ( ) {
}
# define MIN_COLOR_RUN 3
int32_t single_color_scanline ( uint32_t * buf , size_t buf_length , int width , uint32_t color16 ) {
assert ( buf_length > = 2 ) ;
assert ( width > = MIN_COLOR_RUN ) ;
// | jmp color_run | color | count-3 | buf[0] =
buf [ 0 ] = COMPOSABLE_COLOR_RUN | ( color16 < < 16 ) ;
buf [ 1 ] = ( width - MIN_COLOR_RUN ) | ( COMPOSABLE_RAW_1P < < 16 ) ;
// note we must end with a black pixel
buf [ 2 ] = 0 | ( COMPOSABLE_EOL_ALIGN < < 16 ) ;
return 3 ;
}
void render_scanline ( struct scanvideo_scanline_buffer * dest , int core ) {
uint32_t * buf = dest - > data ;
size_t buf_length = dest - > data_max ;
int l = scanvideo_scanline_number ( dest - > scanline_id ) ;
uint16_t bgcolour = ( uint16_t ) l < < 2 ;
dest - > data_used = single_color_scanline ( buf , buf_length , VGA_MODE . width , bgcolour ) ;
dest - > status = SCANLINE_OK ;
}
int main ( void ) {
2022-05-17 21:03:20 +00:00
# if PICO_SCANVIDEO_48MHZ
2021-01-20 17:16:37 +00:00
set_sys_clock_48mhz ( ) ;
2021-02-13 19:54:50 +00:00
# endif
2021-01-20 17:16:37 +00:00
// Re init uart now that clk_peri has changed
setup_default_uart ( ) ;
return vga_main ( ) ;
}