AlgorithMan-de / wyoos

Source codes for the "Write your own Operating System" video-series on YouTube
http://wyoos.org
GNU General Public License v3.0
719 stars 222 forks source link

Slow VGA Fill? #42

Open Stanlyhalo opened 1 month ago

Stanlyhalo commented 1 month ago

Not sure if this is an issue exactly. But I just got done with vid n.12. And in the video, his goes from the terminal then quickly to a screen with that glitchy background but fills to blue almost immediately. Mine takes about 2 seconds or so.

I've checked through my code base with the commit and some of the notes. I don't see if I did anything wrong? Is it something wrong with vm box? I gave it plenty of vram, memory, and I even tried to see if giving it more cores help (which I'd assume not because I would assume I need to make manual work of that in a custom os build).

VGA.hpp

class VGA {
protected:
    Port8Bit miscPort;
    Port8Bit crtcIndexPort;
    Port8Bit crtcDataPort;
    Port8Bit sequencerIndexPort;
    Port8Bit sequencerDataPort;
    Port8Bit graphicsControllerIndexPort;
    Port8Bit graphicsControllerDataPort;
    Port8Bit attributeControllerIndexPort;
    Port8Bit attributeControllerReadPort;
    Port8Bit attributeControllerWritePort;
    Port8Bit attributeControllerResetPort;

    void WriteRegisters(uint8* registers);
    uint8* GetFrameBufferSegment();
public:
    VGA();
    ~VGA();

    virtual bool SupportsMode(uint32 width, uint32 height, uint32 colorDepth);
    virtual bool SetMode(uint32 width, uint32 height, uint32 colorDepth);
    virtual uint8 GetColorIndex(uint8 r, uint8 g, uint8 b);
    virtual void SetPixel(uint32 x, uint32 y, uint8 colorIndex);
    virtual void SetPixel(uint32 x, uint32 y, uint8 r, uint8 g, uint8 b);
};

VGA.cpp

void VGA::WriteRegisters(uint8* registers) {
    miscPort.Write(*(registers++));

    for (uint8 i = 0; i < 5; i++) {
        sequencerIndexPort.Write(i);
        sequencerDataPort.Write(*(registers++));
    }

/*
    crtcIndexPort.Write(0x03);
    crtcDataPort.Write(crtcDataPort.Read() | 0x80);
    crtcIndexPort.Write(0x11);
    crtcDataPort.Write(crtcDataPort.Read() & ~0x80);

    registers[0x03] = registers[0x03] | 0x80;
    registers[0x11] = registers[0x11] & ~0x80;
    */
    crtcIndexPort.Write(0x09);
    crtcDataPort.Write(crtcDataPort.Read() | 0x80);
    crtcIndexPort.Write(0x16);
    crtcDataPort.Write(crtcDataPort.Read() & ~0x80);

    registers[0x09] = registers[0x09] | 0x80;
    registers[0x16] = registers[0x16] & ~0x80;

    for (uint8 i = 0; i < 25; i++) {
        crtcIndexPort.Write(i);
        crtcDataPort.Write(*(registers++));
    }

    for (uint8 i = 0; i < 9; i++) {
        graphicsControllerIndexPort.Write(i);
        graphicsControllerDataPort.Write(*(registers++));
    }

    for (uint8 i = 0; i < 21; i++) {
        attributeControllerResetPort.Read();
        attributeControllerIndexPort.Write(i);
        attributeControllerWritePort.Write(*(registers++));
    }

    attributeControllerResetPort.Read();
    attributeControllerIndexPort.Write(0x20);
}
uint8* VGA::GetFrameBufferSegment() {
    graphicsControllerIndexPort.Write(0x06);
    uint8 segmentNumber = graphicsControllerDataPort.Read() & (3 << 2);

    switch (segmentNumber) {
    default:
    case(0 << 2): return (uint8*)0x00000;
    case(1 << 2): return (uint8*)0xA0000;
    case(2 << 2): return (uint8*)0xB0000;
    case(3 << 2): return (uint8*)0xB8000;
    }
}

VGA::VGA() :
miscPort(0x3C2),
crtcIndexPort(0x3D4),
crtcDataPort(0x3D5),
sequencerIndexPort(0x3C4),
sequencerDataPort(0x3C5),
graphicsControllerIndexPort(0x3CE),
graphicsControllerDataPort(0x3CF),
attributeControllerIndexPort(0x3C0),
attributeControllerReadPort(0x3C1),
attributeControllerWritePort(0x3C0),
attributeControllerResetPort(0x3DA) {
    //
}
VGA::~VGA() {
    //
}

bool VGA::SupportsMode(uint32 width, uint32 height, uint32 colorDepth) {
    return width == 320 && height == 200 && colorDepth == 8;
}
bool VGA::SetMode(uint32 width, uint32 height, uint32 colorDepth) {
    if (!SupportsMode(width, height, colorDepth)) return false;

    unsigned char g_320x200x256[] = {
    /* MISC */
        0x63,
    /* SEQ */
        0x03, 0x01, 0x0F, 0x00, 0x0E,
    /* CRTC */
        0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F,
        0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x9C, 0x0E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3,
        0xFF,
    /* GC */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
        0xFF,
    /* AC */
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
        0x41, 0x00, 0x0F, 0x00, 0x00
    };

    WriteRegisters(g_320x200x256);
    return true;
}
uint8 VGA::GetColorIndex(uint8 r, uint8 g, uint8 b) {
    if (r == 0x00 && g == 0x00 && 0xA8)
        return 0x01;
    return 0x00;
}
void VGA::SetPixel(uint32 x, uint32 y, uint8 colorIndex) {
    uint8* pixelAddr = GetFrameBufferSegment() + 320*y + x;
    *pixelAddr = colorIndex;
}
void VGA::SetPixel(uint32 x, uint32 y, uint8 r, uint8 g, uint8 b) {
    SetPixel(x,y,GetColorIndex(r, g, b));
}
Stanlyhalo commented 1 month ago

Is it just different for everybody and it's just because I'm telling it to draw a single pixel for every pixel on the screen from the cpu? I couldn't imagine it taking longer then what it did in the video, right?

I'm gonna begin the GUI video, I have my own way of writing GUI setups so this is most likely where I'll start to really branch off, but I'm just concerned about the draw time (I assume though that later on I'll switch away from VGA, right?).