Correctly use VGA palette now

Optimised some VGA operations
This commit is contained in:
Quajak 2020-05-18 00:23:47 +02:00
parent 19cffbadd1
commit e36c87192f
5 changed files with 240 additions and 68 deletions

View file

@ -15,26 +15,26 @@ namespace Cosmos.TestRunner.Full
// Stable kernel types: the ones that are stable and will run in AppVeyor
public static IEnumerable<Type> GetStableKernelTypes()
{
//yield return typeof(BoxingTests.Kernel);
//yield return typeof(Cosmos.Compiler.Tests.TypeSystem.Kernel);
//yield return typeof(Cosmos.Compiler.Tests.Bcl.Kernel);
//yield return typeof(Cosmos.Compiler.Tests.Bcl.System.Kernel);
////yield return typeof(Cosmos.Compiler.Tests.Encryption.Kernel);
//yield return typeof(Cosmos.Compiler.Tests.Exceptions.Kernel);
//yield return typeof(Cosmos.Compiler.Tests.MethodTests.Kernel);
//yield return typeof(Cosmos.Compiler.Tests.SingleEchoTest.Kernel);
//yield return typeof(Cosmos.Kernel.Tests.Fat.Kernel);
//yield return typeof(Cosmos.Kernel.Tests.IO.Kernel);
//yield return typeof(SimpleStructsAndArraysTest.Kernel);
//yield return typeof(Cosmos.Kernel.Tests.DiskManager.Kernel);
yield return typeof(BoxingTests.Kernel);
yield return typeof(Cosmos.Compiler.Tests.TypeSystem.Kernel);
yield return typeof(Cosmos.Compiler.Tests.Bcl.Kernel);
yield return typeof(Cosmos.Compiler.Tests.Bcl.System.Kernel);
//yield return typeof(Cosmos.Compiler.Tests.Encryption.Kernel);
yield return typeof(Cosmos.Compiler.Tests.Exceptions.Kernel);
yield return typeof(Cosmos.Compiler.Tests.MethodTests.Kernel);
yield return typeof(Cosmos.Compiler.Tests.SingleEchoTest.Kernel);
yield return typeof(Cosmos.Kernel.Tests.Fat.Kernel);
yield return typeof(Cosmos.Kernel.Tests.IO.Kernel);
yield return typeof(SimpleStructsAndArraysTest.Kernel);
yield return typeof(Cosmos.Kernel.Tests.DiskManager.Kernel);
//yield return typeof(KernelGen3.Boot);
yield return typeof(GraphicTest.Kernel);
/* Please see the notes on the kernel itself before enabling it */
//yield return typeof(ConsoleTest.Kernel);
yield return typeof(ConsoleTest.Kernel);
/* This is a bit slow and works only because ring check is disabled to decide if leave it enabled */
//yield return typeof(MemoryOperationsTest.Kernel);
yield return typeof(MemoryOperationsTest.Kernel);
}
}
}

View file

@ -80,7 +80,7 @@ namespace GraphicTest
/* A LimeGreen rectangle */
pen.Color = Color.LimeGreen;
aCanvas.DrawRectangle(pen, 450, 450, 80, 60);
aCanvas.DrawRectangle(pen, 450, 300, 80, 60);
/* A filled rectange */
pen.Color = Color.Chocolate;
@ -123,22 +123,24 @@ namespace GraphicTest
TestBitmaps();
/* First test with the DefaultMode */
//canvas = FullScreenCanvas.GetFullScreenCanvas();
//DoTest(canvas);
//DoTest(FullScreenCanvas.GetFullScreenCanvas(new Mode(800, 600, ColorDepth.ColorDepth32)));
//DoTest(FullScreenCanvas.GetFullScreenCanvas(new Mode(1024, 768, ColorDepth.ColorDepth32)));
//DoTest(FullScreenCanvas.GetFullScreenCanvas(new Mode(1366, 768, ColorDepth.ColorDepth32)));
//DoTest(FullScreenCanvas.GetFullScreenCanvas(new Mode(1280, 720, ColorDepth.ColorDepth32)));
VGACanvas vGACanvas = new VGACanvas(new Mode(320, 200, ColorDepth.ColorDepth8));
DoTest(vGACanvas);
//DoTest(vGACanvas);
//vGACanvas = new VGACanvas(new Mode(720, 480, ColorDepth.ColorDepth4));
//DoTest(vGACanvas);
vGACanvas = new VGACanvas(new Mode(720, 480, ColorDepth.ColorDepth4));
DoTest(vGACanvas);
DoTest((Canvas)vGACanvas);
vGACanvas = new VGACanvas(new Mode(320, 200, ColorDepth.ColorDepth8));
DoTest(vGACanvas);
/* First test with the DefaultMode */
canvas = FullScreenCanvas.GetFullScreenCanvas();
DoTest(canvas);
DoTest(FullScreenCanvas.GetFullScreenCanvas(new Mode(800, 600, ColorDepth.ColorDepth32)));
DoTest(FullScreenCanvas.GetFullScreenCanvas(new Mode(1024, 768, ColorDepth.ColorDepth32)));
DoTest(FullScreenCanvas.GetFullScreenCanvas(new Mode(1366, 768, ColorDepth.ColorDepth32)));
DoTest(FullScreenCanvas.GetFullScreenCanvas(new Mode(1280, 720, ColorDepth.ColorDepth32)));
TestController.Completed();
}
catch (Exception e)
@ -152,13 +154,12 @@ namespace GraphicTest
private void DoTest(VGACanvas vGACanvas)
{
mDebugger.Send($"Testing VGA Canvas with mode {vGACanvas.Mode}");
vGACanvas.Clear();
vGACanvas.Clear(Color.Blue);
for (int x = 0; x < 20; x++)
{
for (int y = 0; y < 20; y++)
{
vGACanvas.DrawPoint((uint)(x % (int)vGACanvas.Mode.ColorDepth), 5 + x, 5 + y);
vGACanvas.DrawPoint((uint)(x % (2 << ((int)vGACanvas.Mode.ColorDepth - 1))), 5 + x, 5 + y);
}
}
@ -166,7 +167,7 @@ namespace GraphicTest
{
for (int y = 0; y < 20; y++)
{
vGACanvas.DrawPoint((uint)((x + 1) % (int)vGACanvas.Mode.ColorDepth), 5 + x, 5 + y);
vGACanvas.DrawPoint((uint)(x % (2 << ((int)vGACanvas.Mode.ColorDepth - 1))), 25 + x, 5 + y);
}
}

View file

@ -1,5 +1,6 @@
#define COSMOSDEBUG
using System;
using System.Collections.Generic;
using System.Drawing;
using Cosmos.Core;
@ -178,8 +179,63 @@ namespace Cosmos.HAL
public VGADriver()
{
}
/// <summary>
/// The closest color in the palette will be found to be drawn
/// This is quite slow, so whenever possible use the index of the color
/// </summary>
/// <param name="aX"></param>
/// <param name="aY"></param>
/// <param name="aColor"></param>
public void SetPixel(uint aX, uint aY, Color aColor)
{
//Find the closest index
var index = GetClosestColorInPalette(aColor);
//Draw
SetPixel(aX, aY, index);
}
private static Dictionary<int, uint> colorToPalette = new Dictionary<int, uint>();
public uint GetClosestColorInPalette(Color aColor)
{
if (colorToPalette.ContainsKey(aColor.ToArgb()))
{
return colorToPalette[aColor.ToArgb()];
}
uint index = 0;
double diff = 1000000;
for (uint i = 0; i < 2 << ((int)_ColorDepth - 1); i++) //iterate over the total palette
{
var paletteColor = _Palette[i];
var colorDiff = (aColor.R - paletteColor.R) * (aColor.R - paletteColor.R) * 0.3 + //Taken from https://stackoverflow.com/questions/1847092/given-an-rgb-value-what-would-be-the-best-way-to-find-the-closest-match-in-the-d
(aColor.G - paletteColor.G) * (aColor.G - paletteColor.G) * 0.59 + (aColor.B - paletteColor.B) * (aColor.B - paletteColor.B) * 0.11;
mDebugger.Send($"Standard Color: {aColor.R} {aColor.G} {aColor.B} Comparing to: {paletteColor.R} {paletteColor.G} {paletteColor.B} Diff: {colorDiff}");
if (colorDiff < diff)
{
index = i;
diff = colorDiff;
if (diff == 0)
{
break;
}
}
}
colorToPalette.Add(aColor.ToArgb(), index);
mDebugger.Send("Chosen index: " + index);
return index;
}
/// <summary>
///
/// </summary>
/// <param name="aX"></param>
/// <param name="aY"></param>
/// <param name="aColor">The index of the color in the palette</param>
public void SetPixel(uint aX, uint aY, uint aColor)
{
//Global.mDebugger.Send($"Setting pixel: ({x}, {y}) to {color}");
@ -425,6 +481,73 @@ namespace Cosmos.HAL
default:
throw new Exception("Unknown screen size");
}
//Initialize the palette
_Palette[0] = Color.Black;
switch (aDepth)
{
case ColorDepth.BitDepth2:
_Palette[1] = Color.Cyan;
_Palette[2] = Color.Magenta;
_Palette[3] = Color.Gray;
break;
case ColorDepth.BitDepth4:
_Palette[1] = Color.Blue;
_Palette[2] = Color.Green;
_Palette[3] = Color.Cyan;
_Palette[4] = Color.Red;
_Palette[5] = Color.DarkMagenta;
_Palette[6] = Color.Brown;
_Palette[7] = Color.LightGray;
_Palette[8] = Color.DarkGray;
_Palette[9] = Color.LightBlue;
_Palette[10] = Color.LightGreen;
_Palette[11] = Color.LightCyan;
_Palette[12] = Color.Pink;
_Palette[13] = Color.Magenta;
_Palette[14] = Color.Yellow;
_Palette[15] = Color.White;
break;
case ColorDepth.BitDepth8:
int[] colors = new int[256] // Credits to https://commons.wikimedia.org/w/index.php?title=User:Psychonaut/ipalette.sh&oldid=8607095
{
0x000000,0x0000AA,0x00AA00,0x00AAAA,0xAA0000,0xAA00AA,0xAA5500,0xAAAAAA,0x555555,0x5555FF,
0x55FF55,0x55FFFF,0xFF5555,0xFF55FF,0xFFFF55,0xFFFFFF,0x000000,0x101010,0x202020,0x353535,
0x454545,0x555555,0x656565,0x757575,0x8A8A8A,0x9A9A9A,0xAAAAAA,0xBABABA,0xCACACA,0xDFDFDF,
0xEFEFEF,0xFFFFFF,0x0000FF,0x4100FF,0x8200FF,0xBE00FF,0xFF00FF,0xFF00BE,0xFF0082,0xFF0041,
0xFF0000,0xFF4100,0xFF8200,0xFFBE00,0xFFFF00,0xBEFF00,0x82FF00,0x41FF00,0x00FF00,0x00FF41,
0x00FF82,0x00FFBE,0x00FFFF,0x00BEFF,0x0082FF,0x0041FF,0x8282FF,0x9E82FF,0xBE82FF,0xDF82FF,
0xFF82FF,0xFF82DF,0xFF82BE,0xFF829E,0xFF8282,0xFF9E82,0xFFBE82,0xFFDF82,0xFFFF82,0xDFFF82,
0xBEFF82,0x9EFF82,0x82FF82,0x82FF9E,0x82FFBE,0x82FFDF,0x82FFFF,0x82DFFF,0x82BEFF,0x829EFF,
0xBABAFF,0xCABAFF,0xDFBAFF,0xEFBAFF,0xFFBAFF,0xFFBAEF,0xFFBADF,0xFFBACA,0xFFBABA,0xFFCABA,
0xFFDFBA,0xFFEFBA,0xFFFFBA,0xEFFFBA,0xDFFFBA,0xCAFFBA,0xBAFFBA,0xBAFFCA,0xBAFFDF,0xBAFFEF,
0xBAFFFF,0xBAEFFF,0xBADFFF,0xBACAFF,0x000071,0x1C0071,0x390071,0x550071,0x710071,0x710055,
0x710039,0x71001C,0x710000,0x711C00,0x713900,0x715500,0x717100,0x557100,0x397100,0x1C7100,
0x007100,0x00711C,0x007139,0x007155,0x007171,0x005571,0x003971,0x001C71,0x393971,0x453971,
0x553971,0x613971,0x713971,0x713961,0x713955,0x713945,0x713939,0x714539,0x715539,0x716139,
0x717139,0x617139,0x557139,0x457139,0x397139,0x397145,0x397155,0x397161,0x397171,0x396171,
0x395571,0x394571,0x515171,0x595171,0x615171,0x695171,0x715171,0x715169,0x715161,0x715159,
0x715151,0x715951,0x716151,0x716951,0x717151,0x697151,0x617151,0x597151,0x517151,0x517159,
0x517161,0x517169,0x517171,0x516971,0x516171,0x515971,0x000041,0x100041,0x200041,0x310041,
0x410041,0x410031,0x410020,0x410010,0x410000,0x411000,0x412000,0x413100,0x414100,0x314100,
0x204100,0x104100,0x004100,0x004110,0x004120,0x004131,0x004141,0x003141,0x002041,0x001041,
0x202041,0x282041,0x312041,0x392041,0x412041,0x412039,0x412031,0x412028,0x412020,0x412820,
0x413120,0x413920,0x414120,0x394120,0x314120,0x284120,0x204120,0x204128,0x204131,0x204139,
0x204141,0x203941,0x203141,0x202841,0x2D2D41,0x312D41,0x352D41,0x3D2D41,0x412D41,0x412D3D,
0x412D35,0x412D31,0x412D2D,0x41312D,0x41352D,0x413D2D,0x41412D,0x3D412D,0x35412D,0x31412D,
0x2D412D,0x2D4131,0x2D4135,0x2D413D,0x2D4141,0x2D3D41,0x2D3541,0x2D3141,0x000000,0x000000,
0x000000,0x000000,0x000000,0x000000,0x000000,0x000000
};
for (int i = 0; i < 256; i++)
{
_Palette[i] = Color.FromArgb(colors[i]);
}
break;
case ColorDepth.BitDepth16:
break;
default:
break;
}
}
public void SetPixel320x200x8(uint aX, uint aY, uint aC)
@ -549,38 +672,83 @@ namespace Cosmos.HAL
public int PixelHeight { private set; get; }
public int Colors { private set; get; }
public void TestMode320x200x8()
public void DrawFilledRectangle(int aX, int aY, int aW, int aH, uint aColor)
{
SetGraphicsMode(ScreenSize.Size320x200, ColorDepth.BitDepth8);
for (byte i = 0; i < 64; i++)
mDebugger.Send("Clearing the screen");
if (_Mode == Mode.Text)
{
SetPaletteEntry(i, i, 0, 0);
SetPaletteEntry(i + 64, 63, i, 0);
SetPaletteEntry(i + 128, 63, 63, i);
SetPaletteEntry(i + 192, (byte)(63 - i), (byte)(63 - i), (byte)(63 - i));
throw new Exception("Cannot set pixel in text mode");
}
var xSegment = GetFramebufferSegment();
for (uint y = 0; y < PixelHeight; y++)
switch (_ScreenSize)
{
for (uint x = 0; x < PixelWidth; x++)
{
xSegment[(y * 320) + x] = (byte)(x + y);
}
}
}
public void Clear(int aColor)
{
//TODO: Copy more memory at once
for (int y = 0; y < PixelHeight; y++)
{
for (int x = 0; x < PixelWidth; x++)
{
SetPixel((uint)x, (uint)y, (uint)aColor);
}
case ScreenSize.Size640x480:
switch (_ColorDepth)
{
case ColorDepth.BitDepth2:
throw new NotImplementedException();
case ColorDepth.BitDepth4:
for (uint x = (uint)aX; x < aX + aW; x++)
{
for (uint y = (uint)aY; y < aY + aH; y++)
{
SetPixel640x480x4(x, y, aColor);
}
}
break;
case ColorDepth.BitDepth8:
throw new NotImplementedException();
case ColorDepth.BitDepth16:
throw new NotImplementedException();
default:
throw new NotImplementedException();
}
break;
case ScreenSize.Size720x480:
switch (_ColorDepth)
{
case ColorDepth.BitDepth2:
throw new NotImplementedException();
case ColorDepth.BitDepth4:
for (uint x = (uint)aX; x < aX + aW; x++)
{
for (uint y = (uint)aY; y < aY + aH; y++)
{
SetPixel720x480x4(x, y, aColor);
}
}
break;
case ColorDepth.BitDepth8:
throw new NotImplementedException();
case ColorDepth.BitDepth16:
throw new NotImplementedException();
default:
throw new NotImplementedException();
}
break;
case ScreenSize.Size320x200:
switch (_ColorDepth)
{
case ColorDepth.BitDepth2:
throw new NotImplementedException();
case ColorDepth.BitDepth4:
throw new NotImplementedException();
case ColorDepth.BitDepth8:
for (uint x = (uint)aX; x < aX + aW; x++)
{
for (uint y = (uint)aY; y < aY + aH; y++)
{
SetPixel320x200x8(x, y, aColor);
}
}
break;
case ColorDepth.BitDepth16:
throw new NotImplementedException();
default:
throw new NotImplementedException();
}
break;
default:
throw new NotImplementedException();
}
}
@ -599,6 +767,7 @@ namespace Cosmos.HAL
public void SetPaletteEntry(int aIndex, byte aR, byte aG, byte aB)
{
_Palette[aIndex] = Color.FromArgb(aR, aG, aB);
_MIO.DACIndex_Write.Byte = (byte)aIndex;
_MIO.DAC_Data.Byte = (byte)(aR >> 2);
_MIO.DAC_Data.Byte = (byte)(aG >> 2);

View file

@ -31,7 +31,8 @@ namespace Cosmos.System.Graphics
public override void Clear(Color aColor)
{
base.Clear(aColor);
var paletteIndex = _VGADriver.GetClosestColorInPalette(aColor);
_VGADriver.DrawFilledRectangle(0,0, _VGADriver.PixelWidth, _VGADriver.PixelHeight, paletteIndex);
}
public override void Disable()
@ -92,12 +93,12 @@ namespace Cosmos.System.Graphics
public override void DrawFilledRectangle(Pen aPen, Point aPoint, int aWidth, int aHeight)
{
base.DrawFilledRectangle(aPen, aPoint, aWidth, aHeight);
DrawFilledRectangle(aPen, aPoint.X, aPoint.Y, aWidth, aHeight);
}
public override void DrawFilledRectangle(Pen aPen, int aXStart, int aYStart, int aWidth, int aHeight)
{
base.DrawFilledRectangle(aPen, aXStart, aYStart, aWidth, aHeight);
_VGADriver.DrawFilledRectangle(aXStart, aYStart, aWidth, aHeight, _VGADriver.GetClosestColorInPalette(aPen.Color));
}
public override void DrawLine(Pen aPen, int aX1, int aY1, int aX2, int aY2)
@ -107,7 +108,7 @@ namespace Cosmos.System.Graphics
public override void DrawPoint(Pen aPen, int aX, int aY)
{
DrawPoint((uint)aPen.Color.ToArgb(), aX, aY);
_VGADriver.SetPixel((uint)aX, (uint)aY, aPen.Color);
}
public void DrawPoint(uint aColor, int aX, int aY)
@ -162,7 +163,13 @@ namespace Cosmos.System.Graphics
new Mode(320, 200, ColorDepth.ColorDepth8)
};
public override List<Mode> AvailableModes => _AvailableModes;
public override List<Mode> AvailableModes
{
get
{
return _AvailableModes;
}
}
public override Color GetPointColor(int aX, int aY)
{

View file

@ -30,12 +30,7 @@ namespace Cosmos.System.Graphics
public static void Clear(int aColor)
{
_Screen.Clear(aColor);
}
public static void TestMode320x200x8()
{
_Screen.TestMode320x200x8();
_Screen.DrawFilledRectangle(0,0, _Screen.PixelWidth, _Screen.PixelHeight, (uint)aColor);
}
public static void SetPaletteEntry(int aIndex, byte aR, byte aG, byte aB)