Faster set_pixel

This commit is contained in:
Ryan Kennedy 2020-03-22 23:11:22 -05:00
parent 51bdc82df9
commit c4486427c0
4 changed files with 46 additions and 30 deletions

View file

@ -73,6 +73,21 @@ impl From<GraphicsControllerIndex> for u8 {
}
}
#[derive(Debug)]
#[repr(u8)]
pub enum WriteMode {
Mode0 = 0x0,
Mode1 = 0x1,
Mode2 = 0x2,
Mode3 = 0x3,
}
impl From<WriteMode> for u8 {
fn from(value: WriteMode) -> u8 {
value as u8
}
}
/// Represents the graphics controller registers on vga hardware.
#[derive(Debug)]
pub struct GraphicsControllerRegisters {
@ -130,6 +145,18 @@ impl GraphicsControllerRegisters {
);
}
pub fn set_write_mode(&mut self, write_mode: WriteMode) {
let original_value = self.read(GraphicsControllerIndex::GraphicsMode) & 0xFC;
self.write(
GraphicsControllerIndex::GraphicsMode,
original_value | u8::from(write_mode),
);
}
pub fn set_bit_mask(&mut self, bit_mask: u8) {
self.write(GraphicsControllerIndex::BitMask, bit_mask);
}
fn set_index(&mut self, index: GraphicsControllerIndex) {
unsafe {
self.grx_index.write(u8::from(index));

View file

@ -13,7 +13,7 @@ pub use attribute_controller::{AttributeControllerIndex, AttributeControllerRegi
pub use color_palette::ColorPaletteRegisters;
pub use crtc_controller::{CrtcControllerIndex, CrtcControllerRegisters};
pub use general::GeneralRegisters;
pub use graphics_controller::{GraphicsControllerIndex, GraphicsControllerRegisters};
pub use graphics_controller::{GraphicsControllerIndex, GraphicsControllerRegisters, WriteMode};
pub use sequencer::{PlaneMask, SequencerIndex, SequencerRegisters};
const ST00_READ_ADDRESS: u16 = 0x3C2;

View file

@ -96,7 +96,11 @@ impl SequencerRegisters {
/// Sets the plane mask of the sequencer controller, as specified by `plane_mask`.
pub fn set_plane_mask(&mut self, plane_mask: PlaneMask) {
self.write(SequencerIndex::PlaneMask, u8::from(plane_mask));
let original_value = self.read(SequencerIndex::PlaneMask);
self.write(
SequencerIndex::PlaneMask,
original_value | u8::from(plane_mask),
);
}
fn set_index(&mut self, index: SequencerIndex) {

View file

@ -1,9 +1,8 @@
use crate::{
colors::{Color16Bit, DEFAULT_PALETTE},
registers::PlaneMask,
registers::{PlaneMask, WriteMode},
vga::{Vga, VideoMode, VGA},
};
use core::convert::TryInto;
use spinning_top::SpinlockGuard;
const WIDTH: usize = 640;
@ -34,17 +33,16 @@ impl Graphics640x480x16 {
}
/// Clears the screen by setting all pixels to `Color16Bit::Black`.
pub fn clear_screen(&self) {
pub fn clear_screen(&self, color: Color16Bit) {
let (mut vga, frame_buffer) = self.get_frame_buffer();
vga.sequencer_registers
.set_plane_mask(PlaneMask::ALL_PLANES);
vga.graphics_controller_registers.set_bit_mask(0xFF);
vga.graphics_controller_registers
.write_enable_set_reset(PlaneMask::NONE);
.set_write_mode(WriteMode::Mode2);
for offset in 0..ALL_PLANES_SCREEN_SIZE {
unsafe {
frame_buffer
.add(offset)
.write_volatile(Color16Bit::Black as u8);
frame_buffer.add(offset).write_volatile(u8::from(color));
}
}
}
@ -53,27 +51,14 @@ impl Graphics640x480x16 {
pub fn set_pixel(&self, x: usize, y: usize, color: Color16Bit) {
let (mut vga, frame_buffer) = self.get_frame_buffer();
let offset = x / 8 + (WIDTH / 8) * y;
// Store the current value for masking.
let x = x & 7;
let mask = 0x80 >> (x & 7);
let mut plane_mask = 0x01;
for plane in 0u8..4u8 {
let pixel_offset = x & 7;
vga.graphics_controller_registers
.write_read_plane(plane.try_into().unwrap());
vga.sequencer_registers
.set_plane_mask(plane.try_into().unwrap());
let current_value = unsafe { frame_buffer.add(offset).read_volatile() };
let new_value = if plane_mask & color as u8 != 0 {
current_value | mask
} else {
current_value & !mask
};
.set_write_mode(WriteMode::Mode2);
vga.graphics_controller_registers
.set_bit_mask(1 << pixel_offset);
unsafe {
frame_buffer.add(offset).write_volatile(new_value);
}
plane_mask <<= 1;
frame_buffer.add(offset).read_volatile();
frame_buffer.add(offset).write_volatile(u8::from(color));
}
}