// 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
}
}
}