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 {