Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/Cosmos.Kernel.Native.x64/CPU/RhpStackProbe.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
;; Stack probe helper
;; Probes each page from rsp down to r11 to ensure the guard page is touched
;; Input:
;; r11 - lowest address of the allocated stack frame ([InitialSp - FrameSize])
;; rsp - some byte on the last probed page
;; Output:
;; rax - scratch (not preserved)
;; r11 - preserved
;; Notes:
;; Probes at least one page below rsp.
global RhpStackProbe
section .text


PROBE_STEP equ 0x1000

RhpStackProbe:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a no-op in kernel-mode!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know that raghhhhh I was just getting an error

; Align rax to the start of the current page
mov rax, rsp
and rax, -PROBE_STEP ; rax = lowest address on the last probed page

ProbeLoop:
sub rax, PROBE_STEP ; move to the next page to probe
test dword [rax], eax ; touch the page
cmp rax, r11
jg ProbeLoop ; continue if still above r11

ret
61 changes: 58 additions & 3 deletions src/Cosmos.Kernel.System.Graphics/Canvas.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public unsafe class Canvas
public static uint Height;
public static uint Pitch;

public static FontFormat DefaultFont = new BIOSFont();

public static void DrawPixel(uint color, int x, int y)
{
if (x >= 0 && x < Width && y >= 0 && y < Height)
Expand Down Expand Up @@ -83,16 +85,69 @@ public static void ClearScreen(uint color)

public static void DrawChar(char c, int x, int y, uint color)
{
PCScreenFont.PutChar(c, x, y, color, Color.Transparent);
DefaultFont.PutChar(c, x, y, color, Color.Transparent);
}

public static void DrawString(string text, int x, int y, uint color)
{
PCScreenFont.PutString(text, x, y, color, Color.Transparent);
DefaultFont.PutString(text, x, y, color, Color.Transparent);
}

public static unsafe void DrawString(char* text, int x, int y, uint color)
{
PCScreenFont.PutString(text, x, y, color, Color.Transparent);
DefaultFont.PutString(text, x, y, color, Color.Transparent);
}

public static unsafe void DrawQuadraticBezier(uint color, int x0, int y0, int x1, int y1, int x2, int y2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure we want to do this in kernel mode...? Why would we need Bezier curve drawing in the kernel?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was a sanity check to make sure floats weren't being wacky, I forgot to remove it

{
//Smooth line, so first calculate the distance between the start and end points to determine the number of steps
int dx = x2 - x0;
int dy = y2 - y0;
int distance = Math.Sqrt((int)(dx * dx + dy * dy));
int steps = distance * 2; // More steps for smoother curve
for (int i = 0; i <= steps; i++)
{
float t = (float)i / steps;
float u = 1 - t;
int x = (int)(u * u * x0 + 2 * u * t * x1 + t * t * x2);
int y = (int)(u * u * y0 + 2 * u * t * y1 + t * t * y2);
DrawPixel(color, x, y);
}
}

public static unsafe void DrawQuadraticBezierAA(uint color, int x0, int y0, int x1, int y1, int x2, int y2)
{
// First, calculate the distance between the start and end points to determine the number of steps, then each nearby pixel is drawn with an intensity based on its distance to the ideal curve
int dx = x2 - x0;
int dy = y2 - y0;
int distance = Math.Sqrt((int)(dx * dx + dy * dy));
int steps = distance * 2; // More steps for smoother curve
for (int i = 0; i <= steps; i++)
{
float t = (float)i / steps;
float u = 1 - t;
int x = (int)(u * u * x0 + 2 * u * t * x1 + t * t * x2);
int y = (int)(u * u * y0 + 2 * u * t * y1 + t * t * y2);

// Draw the pixel with anti-aliasing
for (int offsetX = -1; offsetX <= 1; offsetX++)
{
for (int offsetY = -1; offsetY <= 1; offsetY++)
{
int px = x + offsetX;
int py = y + offsetY;
if (px >= 0 && px < Width && py >= 0 && py < Height)
{
float distanceToCurve = Math.Sqrt(offsetX * offsetX + offsetY * offsetY);
if (distanceToCurve <= 1.5f) // Adjust the threshold for anti-aliasing effect
{
float intensity = 1.5f - distanceToCurve; // Closer pixels are more intense
uint blendedColor = Color.Blend(color, Address[py * (int)(Pitch / 4) + px], intensity);
DrawPixel(blendedColor, px, py);
}
}
}
}
}
}
}
20 changes: 20 additions & 0 deletions src/Cosmos.Kernel.System.Graphics/Color.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,24 @@ public class Color
public static uint LightPink = 0xFFB6C1;
public static uint LightBrown = 0xD2B48C;
public static uint Transparent = 0x00000000; // Transparent color

public static uint Blend(uint color1, uint color2, float ratio)
{
if (ratio < 0) ratio = 0;
if (ratio > 1) ratio = 1;

byte r1 = (byte)((color1 >> 16) & 0xFF);
byte g1 = (byte)((color1 >> 8) & 0xFF);
byte b1 = (byte)(color1 & 0xFF);

byte r2 = (byte)((color2 >> 16) & 0xFF);
byte g2 = (byte)((color2 >> 8) & 0xFF);
byte b2 = (byte)(color2 & 0xFF);

byte r = (byte)(r1 * (1 - ratio) + r2 * ratio);
byte g = (byte)(g1 * (1 - ratio) + g2 * ratio);
byte b = (byte)(b1 * (1 - ratio) + b2 * ratio);

return (uint)((r << 16) | (g << 8) | b);
}
}
109 changes: 109 additions & 0 deletions src/Cosmos.Kernel.System.Graphics/Fonts/BIOSFont.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using Cosmos.Kernel.Core.Memory;
using Cosmos.Kernel.System.Conversion;

namespace Cosmos.Kernel.System.Graphics.Fonts;

public unsafe class BIOSFont : FontFormat
{
public static class Default
{
public static int Size = 4096; // Bytes array

public static char* GetUnmanagedFontData()
{
// 8x16 BIOS font
string VGA816 = "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AAB4zMzM2MzGxsbMAAAAAAAA/sbGwMDAwMDAwAAAAAAAAAAA/mxsbGxsbGwAAAAAAAAA/sZgMBgwYMb+AAAAAAAAAAAAftjY2NjYcAAAAAAAAAAAZmZmZmZ8YGDAAAAAAAAAAHbcGBgYGBgYAAAAAAAAAH4YPGZmZjwYfgAAAAAAAAA4bMbG/sbGbDgAAAAAAAA4bMbGxmxsbGzuAAAAAAAAHjAYDD5mZmZmPAAAAAAAAAAAAH7b29t+AAAAAAAAAAAAAwZ+29vzfmDAAAAAAAAAHDBgYHxgYGAwHAAAAAAAAAB8xsbGxsbGxsYAAAAAAAAAAP4AAP4AAP4AAAAAAAAAAAAYGH4YGAAA/wAAAAAAAAAwGAwGDBgwAH4AAAAAAAAADBgwYDAYDAB+AAAAAAAADhsbGBgYGBgYGBgYGBgYGBgYGBgYGNjY2HAAAAAAAAAAABgYAH4AGBgAAAAAAAAAAAAAdtwAdtwAAAAAAAAAOGxsOAAAAAAAAAAAAAAAAAAAAAAAABgYAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAADwwMDAwM7GxsPBwAAAAAANhsbGxsbAAAAAAAAAAAAABw2DBgyPgAAAAAAAAAAAAAAAAAfHx8fHx8fAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==";
Copy link
Contributor

@ascpixi ascpixi Oct 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should include fonts out-of-the-box. This is fine if temporary, but ideally we'd remove this in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's so we can have some form of display text output that isn't serial

fixed (char* ptr = VGA816)
{
return ptr;
}
}
}

public static uint* Framebuffer;
private static bool _Initialized;

private static uint Pitch;
private static byte* FontData;

public override int CharWidth => 8;

public override int CharHeight => 16;

private static void EnsureInitialized()
{
if (!_Initialized)
{
byte* fontData = Base64.Decode(Default.GetUnmanagedFontData(), (uint)Default.Size);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be able to use a ReadOnlySpan to store the bytes directly, without the need for Base64-decoding. For example:

https://github.com/ascpixi/smolsharp/blob/54a4aeb6e8f6cdd64d049862dee611301082e71b/src/SmolSharp.Ocean/Shaders/OceanShader.cs#L20-L56

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fonts were made awhile before we could, and base64 works for now so.. 🤷‍♂️ I never bothered changing it since it worked, but if you think readonlyspan works, be my guest!

Init(Graphics.Canvas.Address, Graphics.Canvas.Pitch, fontData);
_Initialized = true;
}
}

public static void Init(uint* framebuffer, uint pitch, byte* fontData)
{
Framebuffer = framebuffer;
Pitch = pitch;
FontData = fontData;
}

public override void PutChar(char c, int x, int y, uint fgcolor, uint bgcolor)
{
EnsureInitialized();

// Since this is a BIOS font, each bit represents a pixel (1 = on, 0 = off)
if (c < 0 || c > 127)
{
c = '?'; // Replace unsupported characters with '?'
}

// If bgcolor is Transparent, we skip drawing background pixels
bool drawBackground = bgcolor != Color.Transparent;
byte* charData = FontData + (c * CharHeight);
for (int row = 0; row < CharHeight; row++)
{
byte rowData = charData[row];
for (int col = 0; col < CharWidth; col++)
{
bool pixelOn = (rowData & (1 << (7 - col))) != 0;
int fbX = x + col;
int fbY = y + row;
if (fbX < 0 || fbX >= Graphics.Canvas.Width || fbY < 0 || fbY >= Graphics.Canvas.Height)
{
continue; // Skip pixels outside the framebuffer bounds
}
uint* pixelAddress = (uint*)((byte*)Framebuffer + (fbY * Pitch) + (fbX * 4));
if (pixelOn)
{
*pixelAddress = fgcolor;
}
else if (drawBackground)
{
*pixelAddress = bgcolor;
}
}
}
}

public override void PutString(string str, int x, int y, uint fgcolor, uint bgcolor)
{
EnsureInitialized();

for (int i = 0; i < str.Length; i++)
{
PutChar(str[i], x + (i * CharWidth), y, fgcolor, bgcolor);
}
}

public override unsafe void PutString(char* str, int x, int y, uint fgcolor, uint bgcolor)
{
EnsureInitialized();

int i = 0;
while (str[i] != '\0')
{
PutChar(str[i], x + (i * CharWidth), y, fgcolor, bgcolor);
i++;
}
}
}
18 changes: 18 additions & 0 deletions src/Cosmos.Kernel.System.Graphics/Fonts/FontFormat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Cosmos.Kernel.System.Graphics.Fonts;

public abstract class FontFormat
{
public abstract int CharWidth { get; }
public abstract int CharHeight { get; }
public abstract void PutChar(char c, int x, int y, uint fgcolor, uint bgcolor);
public abstract void PutString(string str, int x, int y, uint fgcolor, uint bgcolor);
public abstract unsafe void PutString(char* str, int x, int y, uint fgcolor, uint bgcolor);
public virtual void PutScaledChar(char c, int x, int y, uint fgcolor, uint bgcolor, int scale) {}
public virtual void PutScaledString(string str, int x, int y, uint fgcolor, uint bgcolor, int scale)
{
for (int i = 0; i < str.Length; i++)
{
PutScaledChar(str[i], x, y, fgcolor, bgcolor, scale);
}
}
}
4 changes: 2 additions & 2 deletions src/Cosmos.Kernel.System.Graphics/KernelConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ public static class KernelConsole
{
private static int _cursorX;
private static int _cursorY;
private static int CharWidth => PCScreenFont.CharWidth;
private static int CharHeight => PCScreenFont.CharHeight;
private static int CharWidth => Canvas.DefaultFont.CharWidth;
private static int CharHeight => Canvas.DefaultFont.CharHeight;
private const int LineSpacing = 0;
private static bool _isInitialized = false;

Expand Down
32 changes: 32 additions & 0 deletions src/Cosmos.Kernel.System/Math.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,36 @@ public static int Max(int a, int b)
{
return a > b ? a : b;
}

public static int Clamp(int value, int min, int max)
{
if (value < min) return min;
if (value > max) return max;
return value;
}

public static int Pow(int x, int y)
{
if (y < 0) throw new ArgumentOutOfRangeException(nameof(y), "Exponent must be non-negative.");
int result = 1;
for (int i = 0; i < y; i++)
{
result *= x;
}
return result;
}

public static int Sqrt(int value)
{
if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Cannot compute square root of a negative number.");
if (value == 0) return 0;
int x = value;
int y = (x + 1) / 2;
while (y < x)
{
x = y;
y = (value / x + x) / 2;
}
return x;
}
}
Loading