// The CMLeonOS Project (https://github.com/Leonmmcoset/CMLeonOS) // Copyright (C) 2025-present LeonOS 2 Developer Team // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . using Cosmos.Core; using Cosmos.HAL; using Cosmos.System.Graphics; using System; namespace CMLeonOS.Driver { /// /// VMWareSVGAII class. /// public class VMWareSVGAII { /// /// Register values. /// public enum Register : ushort { /// /// ID. /// ID = 0, /// /// Enabled. /// Enable = 1, /// /// Width. /// Width = 2, /// /// Height. /// Height = 3, /// /// Max width. /// MaxWidth = 4, /// /// Max height. /// MaxHeight = 5, /// /// Depth. /// Depth = 6, /// /// Bits per pixel. /// BitsPerPixel = 7, /// /// Pseudo color. /// PseudoColor = 8, /// /// Red mask. /// RedMask = 9, /// /// Green mask. /// GreenMask = 10, /// /// Blue mask. /// BlueMask = 11, /// /// Bytes per line. /// BytesPerLine = 12, /// /// Frame buffer start. /// FrameBufferStart = 13, /// /// Frame buffer offset. /// FrameBufferOffset = 14, /// /// VRAM size. /// VRamSize = 15, /// /// Frame buffer size. /// FrameBufferSize = 16, /// /// Capabilities. /// Capabilities = 17, /// /// Memory start. /// MemStart = 18, /// /// Memory size. /// MemSize = 19, /// /// Config done. /// ConfigDone = 20, /// /// Sync. /// Sync = 21, /// /// Busy. /// Busy = 22, /// /// Guest ID. /// GuestID = 23, /// /// Cursor ID. /// CursorID = 24, /// /// Cursor X. /// CursorX = 25, /// /// Cursor Y. /// CursorY = 26, /// /// Cursor on. /// CursorOn = 27, /// /// Host bits per pixel. /// HostBitsPerPixel = 28, /// /// Scratch size. /// ScratchSize = 29, /// /// Memory registers. /// MemRegs = 30, /// /// Number of displays. /// NumDisplays = 31, /// /// Pitch lock. /// PitchLock = 32, /// /// Indicates maximum size of FIFO Registers. /// FifoNumRegisters = 293 } /// /// ID values. /// private enum ID : uint { /// /// Magic starting point. /// Magic = 0x900000, /// /// V0. /// V0 = Magic << 8, /// /// V1. /// V1 = (Magic << 8) | 1, /// /// V2. /// V2 = (Magic << 8) | 2, /// /// Invalid /// Invalid = 0xFFFFFFFF } /// /// FIFO values. /// public enum FIFO : uint { // values are multiplied by 4 to access the array by byte index /// /// Min. /// Min = 0, /// /// Max. /// Max = 4, /// /// Next command. /// NextCmd = 8, /// /// Stop. /// Stop = 12 } /// /// FIFO command values. /// private enum FIFOCommand { /// /// Update. /// Update = 1, /// /// Rectange fill. /// RECT_FILL = 2, /// /// Rectange copy. /// RECT_COPY = 3, /// /// Define bitmap. /// DEFINE_BITMAP = 4, /// /// Define bitmap scanline. /// DEFINE_BITMAP_SCANLINE = 5, /// /// Define pixmap. /// DEFINE_PIXMAP = 6, /// /// Define pixmap scanline. /// DEFINE_PIXMAP_SCANLINE = 7, /// /// Rectange bitmap fill. /// RECT_BITMAP_FILL = 8, /// /// Rectange pixmap fill. /// RECT_PIXMAP_FILL = 9, /// /// Rectange bitmap copy. /// RECT_BITMAP_COPY = 10, /// /// Rectange pixmap fill. /// RECT_PIXMAP_COPY = 11, /// /// Free object. /// FREE_OBJECT = 12, /// /// Rectangle raster operation fill. /// RECT_ROP_FILL = 13, /// /// Rectangle raster operation copy. /// RECT_ROP_COPY = 14, /// /// Rectangle raster operation bitmap fill. /// RECT_ROP_BITMAP_FILL = 15, /// /// Rectangle raster operation pixmap fill. /// RECT_ROP_PIXMAP_FILL = 16, /// /// Rectangle raster operation bitmap copy. /// RECT_ROP_BITMAP_COPY = 17, /// /// Rectangle raster operation pixmap copy. /// RECT_ROP_PIXMAP_COPY = 18, /// /// Define cursor. /// DEFINE_CURSOR = 19, /// /// Display cursor. /// DISPLAY_CURSOR = 20, /// /// Move cursor. /// MOVE_CURSOR = 21, /// /// Define alpha cursor. /// DEFINE_ALPHA_CURSOR = 22 } /// /// IO port offset. /// private enum IOPortOffset : byte { /// /// Index. /// Index = 0, /// /// Value. /// Value = 1, /// /// BIOS. /// Bios = 2, /// /// IRQ. /// IRQ = 3 } /// /// Capability values. /// [Flags] private enum Capability { /// /// None. /// None = 0, /// /// Rectangle fill. /// RectFill = 1, /// /// Rectangle copy. /// RectCopy = 2, /// /// Rectangle pattern fill. /// RectPatFill = 4, /// /// Lecacy off screen. /// LecacyOffscreen = 8, /// /// Raster operation. /// RasterOp = 16, /// /// Cruser. /// Cursor = 32, /// /// Cursor bypass. /// CursorByPass = 64, /// /// Cursor bypass2. /// CursorByPass2 = 128, /// /// Eigth bit emulation. /// EigthBitEmulation = 256, /// /// Alpha cursor. /// AlphaCursor = 512, /// /// Glyph. /// Glyph = 1024, /// /// Glyph clipping. /// GlyphClipping = 0x00000800, /// /// Offscreen. /// Offscreen1 = 0x00001000, /// /// Alpha blend. /// AlphaBlend = 0x00002000, /// /// Three D. /// ThreeD = 0x00004000, /// /// Extended FIFO. /// ExtendedFifo = 0x00008000, /// /// Multi monitors. /// MultiMon = 0x00010000, /// /// Pitch lock. /// PitchLock = 0x00020000, /// /// IRQ mask. /// IrqMask = 0x00040000, /// /// Display topology. /// DisplayTopology = 0x00080000, /// /// GMR. /// Gmr = 0x00100000, /// /// Traces. /// Traces = 0x00200000, /// /// GMR2. /// Gmr2 = 0x00400000, /// /// Screen objects. /// ScreenObject2 = 0x00800000 } /// /// Index port. /// private readonly ushort IndexPort; /// /// Value port. /// private readonly ushort ValuePort; /// /// BIOS port. /// private ushort BiosPort; /// /// IRQ port. /// private ushort IRQPort; /// /// Video memory block. /// public MemoryBlock VideoMemory; /// /// FIFO memory block. /// private MemoryBlock FIFO_Memory; /// /// PCI device. /// private PCIDevice device; /// /// Height. /// private uint height; /// /// Width. /// private uint width; /// /// Depth. /// private uint depth; /// /// Capabilities. /// private uint capabilities; public uint FrameSize; public uint FrameOffset; /// /// Create new instance of the class. /// public VMWareSVGAII() { device = (PCI.GetDevice(VendorID.VMWare, DeviceID.SVGAIIAdapter)); device.EnableMemory(true); uint basePort = device.BaseAddressBar[0].BaseAddress; IndexPort = (ushort)(basePort + (uint)IOPortOffset.Index); ValuePort = (ushort)(basePort + (uint)IOPortOffset.Value); BiosPort = (ushort)(basePort + (uint)IOPortOffset.Bios); IRQPort = (ushort)(basePort + (uint)IOPortOffset.IRQ); WriteRegister(Register.ID, (uint)ID.V2); VideoMemory = new MemoryBlock(ReadRegister(Register.FrameBufferStart), ReadRegister(Register.VRamSize)); capabilities = ReadRegister(Register.Capabilities); InitializeFIFO(); } /// /// Initialize FIFO. /// protected void InitializeFIFO() { FIFO_Memory = new MemoryBlock(ReadRegister(Register.MemStart), ReadRegister(Register.MemSize)); FIFO_Memory[(uint)FIFO.Min] = (uint)Register.FifoNumRegisters * sizeof(uint); FIFO_Memory[(uint)FIFO.Max] = FIFO_Memory.Size; FIFO_Memory[(uint)FIFO.NextCmd] = FIFO_Memory[(uint)FIFO.Min]; FIFO_Memory[(uint)FIFO.Stop] = FIFO_Memory[(uint)FIFO.Min]; WriteRegister(Register.ConfigDone, 1); } /// /// Set video mode. /// /// Width. /// Height. /// Depth. public void SetMode(uint width, uint height, uint depth = 32) { Disable(); this.depth = (depth / 8); this.width = width; this.height = height; WriteRegister(Register.Width, width); WriteRegister(Register.Height, height); WriteRegister(Register.BitsPerPixel, depth); Enable(); InitializeFIFO(); FrameSize = ReadRegister(Register.FrameBufferSize); FrameOffset = ReadRegister(Register.FrameBufferOffset); } /// /// Write register. /// /// A register. /// A value. protected void WriteRegister(Register register, uint value) { IOPort.Write32(IndexPort, (uint)register); IOPort.Write32(ValuePort, value); } /// /// Read register. /// /// A register. /// uint value. protected uint ReadRegister(Register register) { IOPort.Write32(IndexPort, (uint)register); return IOPort.Read32(ValuePort); } /// /// Get FIFO. /// /// FIFO command. /// uint value. protected uint GetFIFO(FIFO cmd) { return FIFO_Memory[(uint)cmd]; } /// /// Set FIFO. /// /// Command. /// Value. /// protected uint SetFIFO(FIFO cmd, uint value) { return FIFO_Memory[(uint)cmd] = value; } /// /// Wait for FIFO. /// protected void WaitForFifo() { WriteRegister(Register.Sync, 1); while (ReadRegister(Register.Busy) != 0) { } } /// /// Write to FIFO. /// /// Value to write. protected void WriteToFifo(uint value) { if (((GetFIFO(FIFO.NextCmd) == GetFIFO(FIFO.Max) - 4) && GetFIFO(FIFO.Stop) == GetFIFO(FIFO.Min)) || (GetFIFO(FIFO.NextCmd) + 4 == GetFIFO(FIFO.Stop))) WaitForFifo(); SetFIFO((FIFO)GetFIFO(FIFO.NextCmd), value); SetFIFO(FIFO.NextCmd, GetFIFO(FIFO.NextCmd) + 4); if (GetFIFO(FIFO.NextCmd) == GetFIFO(FIFO.Max)) SetFIFO(FIFO.NextCmd, GetFIFO(FIFO.Min)); } /// /// Update FIFO. /// /// X coordinate. /// Y coordinate. /// Width. /// Height. public void Update(uint x, uint y, uint width, uint height) { WriteToFifo((uint)FIFOCommand.Update); WriteToFifo(x); WriteToFifo(y); WriteToFifo(width); WriteToFifo(height); WaitForFifo(); } /// /// Update video memory. /// public void DoubleBufferUpdate() { VideoMemory.MoveDown(FrameOffset, FrameSize, FrameSize); Update(0, 0, width, height); } /// /// Set pixel. /// /// X coordinate. /// Y coordinate. /// Color. /// Thrown on memory access violation. public void SetPixel(uint x, uint y, uint color) { VideoMemory[((y * width + x) * depth) + FrameSize] = color; } /// /// Get pixel. /// /// X coordinate. /// Y coordinate. /// uint value. /// Thrown on memory access violation. public uint GetPixel(uint x, uint y) { return VideoMemory[((y * width + x) * depth) + FrameSize]; } /// /// Clear screen to specified color. /// /// Color. /// Thrown on memory access violation. /// Thrown if VMWare SVGA 2 has no rectange copy capability public void Clear(uint color) { VideoMemory.Fill(FrameSize, FrameSize, color); } /// /// Copy rectangle. /// /// Source X coordinate. /// Source Y coordinate. /// Destination X coordinate. /// Destination Y coordinate. /// Width. /// Height. /// Thrown if VMWare SVGA 2 has no rectange copy capability public void Copy(uint x, uint y, uint newX, uint newY, uint width, uint height) { if ((capabilities & (uint)Capability.RectCopy) != 0) { WriteToFifo((uint)FIFOCommand.RECT_COPY); WriteToFifo(x); WriteToFifo(y); WriteToFifo(newX); WriteToFifo(newY); WriteToFifo(width); WriteToFifo(height); WaitForFifo(); } else throw new NotImplementedException("VMWareSVGAII Copy()"); } /// /// Fill rectangle. /// /// X coordinate. /// Y coordinate. /// Width. /// Height. /// Color. /// Thrown on memory access violation. /// Thrown if VMWare SVGA 2 has no rectange copy capability public void Fill(uint x, uint y, uint width, uint height, uint color) { if ((capabilities & (uint)Capability.RectFill) != 0) { WriteToFifo((uint)FIFOCommand.RECT_FILL); WriteToFifo(color); WriteToFifo(x); WriteToFifo(y); WriteToFifo(width); WriteToFifo(height); WaitForFifo(); } else { if ((capabilities & (uint)Capability.RectCopy) != 0) { // fill first line and copy it to all other uint xTarget = (x + width); uint yTarget = (y + height); for (uint xTmp = x; xTmp < xTarget; xTmp++) { SetPixel(xTmp, y, color); } // refresh first line for copy process Update(x, y, width, 1); for (uint yTmp = y + 1; yTmp < yTarget; yTmp++) { Copy(x, y, x, yTmp, width, 1); } } else { uint xTarget = (x + width); uint yTarget = (y + height); for (uint xTmp = x; xTmp < xTarget; xTmp++) { for (uint yTmp = y; yTmp < yTarget; yTmp++) { SetPixel(xTmp, yTmp, color); } } Update(x, y, width, height); } } } /// /// Define alpha cursor. /// public void DefineAlphaCursor(Bitmap bitmap) { WaitForFifo(); WriteToFifo((uint)FIFOCommand.DEFINE_ALPHA_CURSOR); WriteToFifo(0); // ID WriteToFifo(0); // Hotspot X WriteToFifo(0); // Hotspot Y WriteToFifo(bitmap.Width); // Width WriteToFifo(bitmap.Height); // Height for (int i = 0; i < bitmap.RawData.Length; i++) WriteToFifo((uint)bitmap.RawData[i]); WaitForFifo(); } //Allow to enable the Driver again after it has been disabled (switch between text and graphics mode currently this is SVGA only) /// /// Enable the SVGA Driver , only needed after Disable() has been called /// public void Enable() { WriteRegister(Register.Enable, 1); } /// /// Disable the SVGA Driver , return to text mode /// public void Disable() { WriteRegister(Register.Enable, 0); } /// /// Set the cursor visibility and position, once it has been defined with . /// /// If the cursor will be visible. /// The X coordinate of the cursor. /// The UY coordinate of the cursor. public void SetCursor(bool visible, uint x, uint y) { WriteRegister(Register.CursorOn, (uint)(visible ? 1 : 0)); WriteRegister(Register.CursorX, x); WriteRegister(Register.CursorY, y); // To-do: Remove these register casts. WriteRegister((Register)0x0C, ReadRegister((Register)0x0C) + 1); // CursorCount } } }