pico-playground/scanvideo/scanvideo_minimal/scanvideo_minimal.c

115 wiersze
3.3 KiB
C

/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#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) {
#if PICO_SCANVIDEO_48MHZ
set_sys_clock_48mhz();
#endif
// Re init uart now that clk_peri has changed
setup_default_uart();
return vga_main();
}