From 4f87970bfcc28199a2f35a5b9b96ff7b59a8a18b Mon Sep 17 00:00:00 2001 From: Seth Junot Date: Tue, 24 Oct 2023 01:41:55 -0700 Subject: [PATCH] Interlaced 640x480 with more test image improvements Changes: - Interlacing without interrupts - Added dim hue bars on the test image - Keep frame buffer 1 untouched, use fb2 Notes: - Since the test image is still, use Weave deinterlacing. - There is a weird phenomena where the busy bit of the RDP goes false but data continues to be written to the frame buffer, resulting in artifacts. This is worked around by drawing the CPU content again after a second frame swap. More investigation is needed. --- game/src/bin/main.rs | 497 +++++++++++++++++++++++++------- kernel/src/dev/rdp/interface.rs | 4 +- kernel/src/dev/vi.rs | 8 +- 3 files changed, 410 insertions(+), 99 deletions(-) diff --git a/game/src/bin/main.rs b/game/src/bin/main.rs index 3b0a3d4..3990962 100644 --- a/game/src/bin/main.rs +++ b/game/src/bin/main.rs @@ -33,7 +33,7 @@ use kernel::pic::RGBA; const FRAME_BUFFER_1_VADDR: usize = 0xA0100000; // ..0xA022C000 const FRAME_BUFFER_2_VADDR: usize = 0xA02D4000; // ..0xA0400000 -static mut DISPLAY_LIST: [u64; 42] = [0; 42]; +static mut DISPLAY_LIST: [u64; 73] = [0; 73]; /// Initializes the video interface (NTSC, 640x480 (480i), 32-bit color) /// @@ -60,7 +60,7 @@ fn init_vi() { ); video_interface.width.write( vi::VI_WIDTH(0) - .with_width(640) + .with_width(640 * 2) ); video_interface.v_intr.write( vi::VI_V_INTR(0) @@ -94,8 +94,8 @@ fn init_vi() { ); video_interface.v_video.write( vi::VI_V_VIDEO(0) - .with_v_start(0x025) - .with_v_end(0x1FF) + .with_v_start(37) + .with_v_end(511) ); video_interface.v_burst.write( vi::VI_V_BURST(0) @@ -110,7 +110,7 @@ fn init_vi() { video_interface.y_scale.write( vi::VI_Y_SCALE(0) .with_offset(0) - .with_scale(0b_10_0000000000) // 2.10 fixed-point + .with_scale(0b_01_0000000000) // 2.10 fixed-point ); video_control.set_color_depth(vi::ColorDepth::TrueColor); // begin the signal after setup video_interface.ctrl.write(video_control); @@ -122,7 +122,7 @@ fn init_vi() { #[inline(never)] fn init_fbs() { - // RDP display list to blank and draw color bars to the frame buffers + // RDP display list to draw color bars to the frame buffers. let clear_fbs_display_list = &[ rdp_commands::set_other_modes::SetOtherModes(0) @@ -135,15 +135,17 @@ fn init_fbs() { .with_opcode(rdp_commands::RDPCommands::SET_SCISSOR.opcode()) .with_x_upper_left(0) .with_y_upper_left(0) - .with_x_lower_right(640 << 2) - .with_y_lower_right(480 << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right(479 << 2) .into(), - // Zero the two frame buffers + // Black the two frame buffers with a near-black color just light enough to + // denote the projected frame against an emulator's default background or + // other border. rdp_commands::set_fill_color::SetFillColor(0) .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) - .with_packed_color(0) + .with_packed_color(0x01010100) .into(), rdp_commands::set_color_image::SetColorImage(0) @@ -157,9 +159,9 @@ fn init_fbs() { rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) .with_x_upper_left(0) - .with_y_upper_left(1 << 2) - .with_x_lower_right(640 << 2) - .with_y_lower_right(480 << 2) + .with_y_upper_left(0) + .with_x_lower_right(639 << 2) + .with_y_lower_right(479 << 2) .into(), rdp_commands::set_color_image::SetColorImage(0) @@ -174,31 +176,24 @@ fn init_fbs() { .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) .with_x_upper_left(0) .with_y_upper_left(0) - .with_x_lower_right(640 << 2) - .with_y_lower_right(480 << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right(479 << 2) .into(), - // Vertical color bars (white, grey, rgb, ycp) - - rdp_commands::set_color_image::SetColorImage(0) - .with_opcode(rdp_commands::RDPCommands::SET_COLOR_IMAGE.opcode()) - .with_address(FRAME_BUFFER_1_VADDR as u32) - .with_model(rdp_commands::set_color_image::CanvasColorModel::RGBA) - .with_pixel_size(rdp_commands::set_color_image::CanvasPixelSize::WORD) - .with_width(640 - 1) - .into(), + // Vertical color bars of bright primary colors rdp_commands::set_fill_color::SetFillColor(0) .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) .with_packed_color(0xFFFFFF00) .into(), + // note: clipped out rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) - .with_x_upper_left((8 + (16 * 0)) << 2) + .with_x_upper_left((16 * 0) << 2) .with_y_upper_left(0) - .with_x_lower_right((15 + (16 * 0)) << 2) - .with_y_lower_right(480 << 2) + .with_x_lower_right((7 + (16 * 0)) << 2) + .with_y_lower_right(479 << 2) .into(), rdp_commands::set_fill_color::SetFillColor(0) @@ -208,10 +203,10 @@ fn init_fbs() { rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) - .with_x_upper_left((8 + (16 * 1)) << 2) + .with_x_upper_left((16 * 1) << 2) .with_y_upper_left(0) - .with_x_lower_right((15 + (16 * 1)) << 2) - .with_y_lower_right(480 << 2) + .with_x_lower_right((7 + (16 * 1)) << 2) + .with_y_lower_right(479 << 2) .into(), rdp_commands::set_fill_color::SetFillColor(0) @@ -221,10 +216,10 @@ fn init_fbs() { rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) - .with_x_upper_left((8 + (16 * 2)) << 2) + .with_x_upper_left((16 * 2) << 2) .with_y_upper_left(0) - .with_x_lower_right((15 + (16 * 2)) << 2) - .with_y_lower_right(480 << 2) + .with_x_lower_right((7 + (16 * 2)) << 2) + .with_y_lower_right(479 << 2) .into(), rdp_commands::set_fill_color::SetFillColor(0) @@ -232,12 +227,12 @@ fn init_fbs() { .with_packed_color(0x00FF0000) .into(), - rdp_commands::fill_rectangle::FillRectangle(0) + rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) - .with_x_upper_left((8 + (16 * 3)) << 2) + .with_x_upper_left((16 * 3) << 2) .with_y_upper_left(0) - .with_x_lower_right((15 + (16 * 3)) << 2) - .with_y_lower_right(480 << 2) + .with_x_lower_right((7 + (16 * 3)) << 2) + .with_y_lower_right(479 << 2) .into(), rdp_commands::set_fill_color::SetFillColor(0) @@ -245,12 +240,12 @@ fn init_fbs() { .with_packed_color(0x0000FF00) .into(), - rdp_commands::fill_rectangle::FillRectangle(0) + rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) - .with_x_upper_left((8 + (16 * 4)) << 2) + .with_x_upper_left((16 * 4) << 2) .with_y_upper_left(0) - .with_x_lower_right((15 + (16 * 4)) << 2) - .with_y_lower_right(480 << 2) + .with_x_lower_right((7 + (16 * 4)) << 2) + .with_y_lower_right(479 << 2) .into(), rdp_commands::set_fill_color::SetFillColor(0) @@ -260,10 +255,10 @@ fn init_fbs() { rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) - .with_x_upper_left((8 + (16 * 5)) << 2) + .with_x_upper_left((16 * 5) << 2) .with_y_upper_left(0) - .with_x_lower_right((15 + (16 * 5)) << 2) - .with_y_lower_right(480 << 2) + .with_x_lower_right((7 + (16 * 5)) << 2) + .with_y_lower_right(479 << 2) .into(), rdp_commands::set_fill_color::SetFillColor(0) @@ -273,10 +268,10 @@ fn init_fbs() { rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) - .with_x_upper_left((8 + (16 * 6)) << 2) + .with_x_upper_left((16 * 6) << 2) .with_y_upper_left(0) - .with_x_lower_right((15 + (16 * 6)) << 2) - .with_y_lower_right(480 << 2) + .with_x_lower_right((7 + (16 * 6)) << 2) + .with_y_lower_right(479 << 2) .into(), rdp_commands::set_fill_color::SetFillColor(0) @@ -286,13 +281,119 @@ fn init_fbs() { rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) - .with_x_upper_left((8 + (16 * 7)) << 2) + .with_x_upper_left((16 * 7) << 2) + .with_y_upper_left(0) + .with_x_lower_right((7 + (16 * 7)) << 2) + .with_y_lower_right(479 << 2) + .into(), + + // Vertical bars fo dim primary colors + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0xFFFFFF00 & 0x0F0F0F00) + .into(), + + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left((639 - (7 + (16 * 0))) << 2) + .with_y_upper_left(0) + .with_x_lower_right((639 - (16 * 0)) << 2) + .with_y_lower_right(479 << 2) + .into(), + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0x7F7F7F00 & 0x0F0F0F00) + .into(), + + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left((639 - (7 + (16 * 1))) << 2) .with_y_upper_left(0) - .with_x_lower_right((15 + (16 * 7)) << 2) - .with_y_lower_right(480 << 2) + .with_x_lower_right((639 - (16 * 1)) << 2) + .with_y_lower_right(479 << 2) + .into(), + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0xFF000000 & 0x0F0F0F00) .into(), - // Horizontal color bars + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left((639 - (7 + (16 * 2))) << 2) + .with_y_upper_left(0) + .with_x_lower_right((639 - (16 * 2)) << 2) + .with_y_lower_right(479 << 2) + .into(), + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0x00FF0000 & 0x0F0F0F00) + .into(), + + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left((639 - (7 + (16 * 3))) << 2) + .with_y_upper_left(0) + .with_x_lower_right((639 - (16 * 3)) << 2) + .with_y_lower_right(479 << 2) + .into(), + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0x0000FF00 & 0x0F0F0F00) + .into(), + + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left((639 - (7 + (16 * 4))) << 2) + .with_y_upper_left(0) + .with_x_lower_right((639 - (16 * 4)) << 2) + .with_y_lower_right(479 << 2) + .into(), + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0xFFFF0000 & 0x0F0F0F00) + .into(), + + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left((639 - (7 + (16 * 5))) << 2) + .with_y_upper_left(0) + .with_x_lower_right((639 - (16 * 5)) << 2) + .with_y_lower_right(479 << 2) + .into(), + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0x00FFFF00 & 0x0F0F0F00) + .into(), + + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left((639 - (7 + (16 * 6))) << 2) + .with_y_upper_left(0) + .with_x_lower_right((639 - (16 * 6)) << 2) + .with_y_lower_right(479 << 2) + .into(), + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0xFF00FF00 & 0x0F0F0F00) + .into(), + + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left((639 - (7 + (16 * 7))) << 2) + .with_y_upper_left(0) + .with_x_lower_right((639 - (16 * 7)) << 2) + .with_y_lower_right(479 << 2) + .into(), + + // Horizontal bars of bright primary colors rdp_commands::set_fill_color::SetFillColor(0) .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) @@ -302,9 +403,9 @@ fn init_fbs() { rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) .with_x_upper_left(0) - .with_y_upper_left((8 + (16 * 0)) << 2) - .with_x_lower_right(640 << 2) - .with_y_lower_right((15 + (16 * 0)) << 2) + .with_y_upper_left((16 * 0) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((7 + (16 * 0)) << 2) .into(), rdp_commands::set_fill_color::SetFillColor(0) @@ -315,9 +416,9 @@ fn init_fbs() { rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) .with_x_upper_left(0) - .with_y_upper_left((8 + (16 * 1)) << 2) - .with_x_lower_right(640 << 2) - .with_y_lower_right((15 + (16 * 1)) << 2) + .with_y_upper_left((16 * 1) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((7 + (16 * 1)) << 2) .into(), rdp_commands::set_fill_color::SetFillColor(0) @@ -328,9 +429,9 @@ fn init_fbs() { rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) .with_x_upper_left(0) - .with_y_upper_left((8 + (16 * 2)) << 2) - .with_x_lower_right(640 << 2) - .with_y_lower_right((15 + (16 * 2)) << 2) + .with_y_upper_left((16 * 2) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((7 + (16 * 2)) << 2) .into(), rdp_commands::set_fill_color::SetFillColor(0) @@ -338,12 +439,12 @@ fn init_fbs() { .with_packed_color(0x00FF0000) .into(), - rdp_commands::fill_rectangle::FillRectangle(0) + rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) .with_x_upper_left(0) - .with_y_upper_left((8 + (16 * 3)) << 2) - .with_x_lower_right(640 << 2) - .with_y_lower_right((15 + (16 * 3)) << 2) + .with_y_upper_left((16 * 3) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((7 + (16 * 3)) << 2) .into(), rdp_commands::set_fill_color::SetFillColor(0) @@ -351,12 +452,12 @@ fn init_fbs() { .with_packed_color(0x0000FF00) .into(), - rdp_commands::fill_rectangle::FillRectangle(0) + rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) .with_x_upper_left(0) - .with_y_upper_left((8 + (16 * 4)) << 2) - .with_x_lower_right(640 << 2) - .with_y_lower_right((15 + (16 * 4)) << 2) + .with_y_upper_left((16 * 4) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((7 + (16 * 4)) << 2) .into(), rdp_commands::set_fill_color::SetFillColor(0) @@ -367,9 +468,9 @@ fn init_fbs() { rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) .with_x_upper_left(0) - .with_y_upper_left((8 + (16 * 5)) << 2) - .with_x_lower_right(640 << 2) - .with_y_lower_right((15 + (16 * 5)) << 2) + .with_y_upper_left((16 * 5) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((7 + (16 * 5)) << 2) .into(), rdp_commands::set_fill_color::SetFillColor(0) @@ -380,9 +481,9 @@ fn init_fbs() { rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) .with_x_upper_left(0) - .with_y_upper_left((8 + (16 * 6)) << 2) - .with_x_lower_right(640 << 2) - .with_y_lower_right((15 + (16 * 6)) << 2) + .with_y_upper_left((16 * 6) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((7 + (16 * 6)) << 2) .into(), rdp_commands::set_fill_color::SetFillColor(0) @@ -393,9 +494,115 @@ fn init_fbs() { rdp_commands::fill_rectangle::FillRectangle(0) .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) .with_x_upper_left(0) - .with_y_upper_left((8 + (16 * 7)) << 2) - .with_x_lower_right(640 << 2) - .with_y_lower_right((15 + (16 * 7)) << 2) + .with_y_upper_left((16 * 7) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((7 + (16 * 7)) << 2) + .into(), + + // Horizontal bars of dim colors + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0xFFFFFF00 & 0x0F0F0F00) + .into(), + + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left(0) + .with_y_upper_left((479 - (8 + (16 * 0))) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((479 - (16 * 0)) << 2) + .into(), + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0x7F7F7F00 & 0x0F0F0F00) + .into(), + + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left(0) + .with_y_upper_left((479 - (8 + (16 * 1))) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((479 - (16 * 1)) << 2) + .into(), + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0xFF000000 & 0x0F0F0F00) + .into(), + + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left(0) + .with_y_upper_left((479 - (8 + (16 * 2))) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((479 - (16 * 2)) << 2) + .into(), + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0x00FF0000 & 0x0F0F0F00) + .into(), + + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left(0) + .with_y_upper_left((479 - (8 + (16 * 3))) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((479 - (16 * 3)) << 2) + .into(), + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0x0000FF00 & 0x0F0F0F00) + .into(), + + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left(0) + .with_y_upper_left((479 - (8 + (16 * 4))) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((479 - (16 * 4)) << 2) + .into(), + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0xFFFF0000 & 0x0F0F0F00) + .into(), + + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left(0) + .with_y_upper_left((479 - (8 + (16 * 5))) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((479 - (16 * 5)) << 2) + .into(), + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0x00FFFF00 & 0x0F0F0F00) + .into(), + + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left(0) + .with_y_upper_left((479 - (8 + (16 * 6))) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((479 - (16 * 6)) << 2) + .into(), + + rdp_commands::set_fill_color::SetFillColor(0) + .with_opcode(rdp_commands::RDPCommands::SET_FILL_COLOR.opcode()) + .with_packed_color(0xFF00FF00 & 0x0F0F0F00) + .into(), + + rdp_commands::fill_rectangle::FillRectangle(0) + .with_opcode(rdp_commands::RDPCommands::FILL_RECTANGLE.opcode()) + .with_x_upper_left(0) + .with_y_upper_left((479 - (8 + (16 * 7))) << 2) + .with_x_lower_right(639 << 2) + .with_y_lower_right((479 - (16 * 7)) << 2) .into(), rdp_commands::full_sync::FullSync(0) @@ -429,62 +636,111 @@ fn init_fbs() { // Wait for the RDP to draw the bars loop { - if !rdpi.dp_status.read().busy() { + let status = rdpi.dp_status.read(); + if !status.command_busy() { break; } } - let fb1 = FRAME_BUFFER_1_VADDR as *mut u32; + draw_interlace_pattern(); + +} + +#[inline(never)] +fn draw_interlace_pattern() { + + let fb2 = FRAME_BUFFER_2_VADDR as *mut u32; // Draw special vertical bars for col in (320 - 32)..(320 + 32) as isize { for row in 0..480 as isize { let offset = col + (640 * row); + + // Black/White alternation, the most pathological interlacing case. + // Jitter on these line is expected if interlacing is implemented + // and no deinterlacer is involved. if col < 320 { - unsafe { - if row & 0x1 == 0 { - *fb1.offset(offset) = 0xFFFFFF00; - } else { - *fb1.offset(offset) = 0x00000000; + + // Even/Odd field alternation + if col < 320 - 16 { + unsafe { + if row & 0x1 == 0 { + *fb2.offset(offset) = 0xFFFFFF00; + } else { + *fb2.offset(offset) = 0x00000000; + } + } + } else { + unsafe { + if row & 0x1 == 0 { + *fb2.offset(offset) = 0x00000000; + } else { + *fb2.offset(offset) = 0xFFFFFF00; + } } } + } else { - unsafe { - if row & 0x1 == 0 { - *fb1.offset(offset) = 0x12345600; - } else { - *fb1.offset(offset) = 0x65432100; + + let gradient_offset: u8 = (0xFF as u8).saturating_sub((row >> 1) as u8); + + // Produce a gradient + let gradient_color: u32 = RGBA(0) + .with_red(gradient_offset) + .with_green(gradient_offset) + .with_blue(gradient_offset) + .with_alpha(0) + .into(); + + // .. ditto ^, but with a gradient. + // Demonstrates that closer hues shouldn't flicker, much. + if col < 320 + 16 { + unsafe { + if row & 0x1 == 0 { + *fb2.offset(offset) = gradient_color; + } else { + *fb2.offset(offset) = 0xFFFFFF00; + } + } + } else { + unsafe { + if row & 0x1 == 0 { + *fb2.offset(offset) = 0xFFFFFF00; + } else { + *fb2.offset(offset) = gradient_color; + } } } + } } } - // Draw special horizontal bars + // Draw special horizontal bars. No expected vertical or horizontal flicker. for row in (240 - 32)..(240 + 32) as isize { for col in 0..640 as isize { let offset = col + (640 * row); if row < 240 { unsafe { if col & 0x1 == 0 { - *fb1.offset(offset) = 0x33FF3300; + *fb2.offset(offset) = 0x33FF3300; } else { - *fb1.offset(offset) = 0x33333300; + *fb2.offset(offset) = 0x33333300; } } } else { unsafe { if col & 0x1 == 0 { - *fb1.offset(offset) = 0xCCCCCC00; + *fb2.offset(offset) = 0xCCCCCC00; } else { - *fb1.offset(offset) = 0xFF33FF00; + *fb2.offset(offset) = 0xFF33FF00; } } } } } - // Draw special screen center + // Draw special screen center. Expect flicker without deinterlacer at box top. let row_start = 240 - 32; let row_end = 240 + 32; let col_start = 320 - 32; @@ -501,7 +757,7 @@ fn init_fbs() { .with_blue(b) .with_alpha(0); unsafe { - *fb1.offset(offset) = color.into(); + *fb2.offset(offset) = color.into(); } } } @@ -512,7 +768,54 @@ fn init_fbs() { pub extern "C" fn __start() -> ! { init_vi(); init_fbs(); - loop {} + + // No interrupt handler yet, so interlacing is done by polling the + // current projected line from the VI and adjusting the frame buffer address + // when it changes from the even to odd field. + let video_interface = vi::VI::new(); + let mut offset: usize = 0; + let mut swap: bool; + let mut swap_counter = 0; + unsafe { + video_interface.origin.write( + vi::VI_ORIGIN(0) + .with_vaddr(FRAME_BUFFER_2_VADDR as u32) + ); + } + loop { + let current_half_line: u16 = video_interface.v_current.read().half_line(); + + // Only swap the projected field at the end of a frame + // if current_half_line < 500 { + // continue; + // } + + // If on an even half-line (an even field), adjust so odd half lines are + // used on the next field (and v.v.). + if current_half_line & 0x1 == 0 { + swap = offset == 0; + offset = 640; // skip a line of 4-byte pixels + } else { + swap = offset > 0; + offset = 0; + } + + // Offset the address of the frame buffer so that the VI skips even or odd fields. + if swap { + unsafe { + video_interface.origin.write( + vi::VI_ORIGIN(0) + .with_vaddr((FRAME_BUFFER_2_VADDR + (offset * 4)) as u32) + ); + } + swap_counter += 1; + if swap_counter == 2 { + draw_interlace_pattern(); + } + } + + } + } #[panic_handler] diff --git a/kernel/src/dev/rdp/interface.rs b/kernel/src/dev/rdp/interface.rs index 0d7d730..1af0da9 100644 --- a/kernel/src/dev/rdp/interface.rs +++ b/kernel/src/dev/rdp/interface.rs @@ -49,7 +49,9 @@ bitfield! { pub struct RDPStatusAsRead(pub u32): IntoRaw, FromRaw { pub start_pending: bool @ 10, pub end_pending: bool @ 9, - pub busy: bool @ 6, + pub buffer_busy: bool @ 7, + pub command_busy: bool @ 6, + pub pipe_busy: bool @ 5, pub flush: bool @ 2, pub freeze: bool @ 1, pub source: bool [DMATransferSource] @ 0, diff --git a/kernel/src/dev/vi.rs b/kernel/src/dev/vi.rs index 0653f47..56c6dc3 100644 --- a/kernel/src/dev/vi.rs +++ b/kernel/src/dev/vi.rs @@ -200,7 +200,13 @@ bitfield! { bitfield! { - /// Width of the frame buffer in pixels + /// Width in pixels of a full line of a frame in the frame buffer. + /// + /// If using progressive scan (e.g. 240p), lines are only made up + /// only one "field" is projected (e.g. width of 320px). If using + /// interlace scan (e.g. 480i), lines are made up of even and odd + /// "fields" (e.g. width of 640 * 2 = 1280px). This register seems + /// involved with how frame pixels are sampled and scaled. /// #[derive(Clone, Copy, PartialEq, Eq)] pub struct VI_WIDTH(pub u32): IntoRaw, FromRaw {