kopia lustrzana https://github.com/raspberrypi/pico-playground
115 wiersze
3.3 KiB
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();
|
|
}
|