mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
Extend vesa driver to support 24 and 32 bpp
This commit is contained in:
parent
13ba4bbbed
commit
f02c767257
@ -16,9 +16,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type VesaFbConsole struct {
|
type VesaFbConsole struct {
|
||||||
bpp uint32
|
bpp uint32
|
||||||
fbPhysAddr uintptr
|
bytesPerPixel uint32
|
||||||
fb []uint8
|
fbPhysAddr uintptr
|
||||||
|
fb []uint8
|
||||||
|
colorInfo *multiboot.FramebufferRGBColorInfo
|
||||||
|
|
||||||
// Console dimensions in pixels
|
// Console dimensions in pixels
|
||||||
width uint32
|
width uint32
|
||||||
@ -43,13 +45,15 @@ type VesaFbConsole struct {
|
|||||||
clearChar uint16
|
clearChar uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVesaFbConsole(width, height uint32, bpp uint8, pitch uint32, fbPhysAddr uintptr) *VesaFbConsole {
|
func NewVesaFbConsole(width, height uint32, bpp uint8, pitch uint32, colorInfo *multiboot.FramebufferRGBColorInfo, fbPhysAddr uintptr) *VesaFbConsole {
|
||||||
return &VesaFbConsole{
|
return &VesaFbConsole{
|
||||||
bpp: uint32(bpp),
|
bpp: uint32(bpp),
|
||||||
fbPhysAddr: fbPhysAddr,
|
bytesPerPixel: uint32(bpp+1) >> 3,
|
||||||
width: width,
|
fbPhysAddr: fbPhysAddr,
|
||||||
height: height,
|
colorInfo: colorInfo,
|
||||||
pitch: pitch,
|
width: width,
|
||||||
|
height: height,
|
||||||
|
pitch: pitch,
|
||||||
// light gray text on black background
|
// light gray text on black background
|
||||||
defaultFg: 7,
|
defaultFg: 7,
|
||||||
defaultBg: 0,
|
defaultBg: 0,
|
||||||
@ -119,6 +123,8 @@ func (cons *VesaFbConsole) Fill(x, y, width, height uint32, _, bg uint8) {
|
|||||||
switch cons.bpp {
|
switch cons.bpp {
|
||||||
case 8:
|
case 8:
|
||||||
cons.fill8(pX, pY, pW, pH, bg)
|
cons.fill8(pX, pY, pW, pH, bg)
|
||||||
|
case 24, 32:
|
||||||
|
cons.fill24(pX, pY, pW, pH, bg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +138,19 @@ func (cons *VesaFbConsole) fill8(pX, pY, pW, pH uint32, bg uint8) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fill24 implements a fill operation using a 24/32bpp framebuffer.
|
||||||
|
func (cons *VesaFbConsole) fill24(pX, pY, pW, pH uint32, bg uint8) {
|
||||||
|
comp := cons.packColor24(bg)
|
||||||
|
fbRowOffset := cons.fbOffset(pX, pY)
|
||||||
|
for ; pH > 0; pH, fbRowOffset = pH-1, fbRowOffset+cons.pitch {
|
||||||
|
for fbOffset := fbRowOffset; fbOffset < fbRowOffset+pW*cons.bytesPerPixel; fbOffset += cons.bytesPerPixel {
|
||||||
|
cons.fb[fbOffset] = comp[0]
|
||||||
|
cons.fb[fbOffset+1] = comp[1]
|
||||||
|
cons.fb[fbOffset+2] = comp[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Scroll the console contents to the specified direction. The caller
|
// Scroll the console contents to the specified direction. The caller
|
||||||
// is responsible for updating (e.g. clear or replace) the contents of
|
// is responsible for updating (e.g. clear or replace) the contents of
|
||||||
// the region that was scrolled.
|
// the region that was scrolled.
|
||||||
@ -171,10 +190,12 @@ func (cons *VesaFbConsole) Write(ch byte, fg, bg uint8, x, y uint32) {
|
|||||||
switch cons.bpp {
|
switch cons.bpp {
|
||||||
case 8:
|
case 8:
|
||||||
cons.write8(ch, fg, bg, pX, pY)
|
cons.write8(ch, fg, bg, pX, pY)
|
||||||
|
case 24, 32:
|
||||||
|
cons.write24(ch, fg, bg, pX, pY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// write8 writes a charactero using an 8bpp framebuffer.
|
// write8 writes a character using an 8bpp framebuffer.
|
||||||
func (cons *VesaFbConsole) write8(glyphIndex, fg, bg uint8, pX, pY uint32) {
|
func (cons *VesaFbConsole) write8(glyphIndex, fg, bg uint8, pX, pY uint32) {
|
||||||
var (
|
var (
|
||||||
fontOffset = uint32(glyphIndex) * cons.font.BytesPerRow * cons.font.GlyphHeight
|
fontOffset = uint32(glyphIndex) * cons.font.BytesPerRow * cons.font.GlyphHeight
|
||||||
@ -207,10 +228,104 @@ func (cons *VesaFbConsole) write8(glyphIndex, fg, bg uint8, pX, pY uint32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write16 writes a character using a 15/162bpp framebuffer.
|
||||||
|
func (cons *VesaFbConsole) write16(glyphIndex, fg, bg uint8, pX, pY uint32) {
|
||||||
|
var (
|
||||||
|
fontOffset = uint32(glyphIndex) * cons.font.BytesPerRow * cons.font.GlyphHeight
|
||||||
|
fbRowOffset = cons.fbOffset(pX, pY)
|
||||||
|
fbOffset uint32
|
||||||
|
x, y uint32
|
||||||
|
mask uint8
|
||||||
|
fgComp = cons.packColor16(fg)
|
||||||
|
bgComp = cons.packColor16(bg)
|
||||||
|
)
|
||||||
|
|
||||||
|
for y = 0; y < cons.font.GlyphHeight; y, fbRowOffset, fontOffset = y+1, fbRowOffset+cons.pitch, fontOffset+1 {
|
||||||
|
fbOffset = fbRowOffset
|
||||||
|
fontRowData := cons.font.Data[fontOffset]
|
||||||
|
mask = 1 << 7
|
||||||
|
for x = 0; x < cons.font.GlyphWidth; x, fbOffset, mask = x+1, fbOffset+cons.bytesPerPixel, mask>>1 {
|
||||||
|
// If mask becomes zero while we are still in this loop
|
||||||
|
// then the font uses > 1 byte per row. We need to
|
||||||
|
// fetch the next byte and reset the mask.
|
||||||
|
if mask == 0 {
|
||||||
|
fontOffset++
|
||||||
|
fontRowData = cons.font.Data[fontOffset]
|
||||||
|
mask = 1 << 7
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fontRowData & mask) != 0 {
|
||||||
|
cons.fb[fbOffset] = fgComp[0]
|
||||||
|
cons.fb[fbOffset+1] = fgComp[1]
|
||||||
|
} else {
|
||||||
|
cons.fb[fbOffset] = bgComp[0]
|
||||||
|
cons.fb[fbOffset+1] = bgComp[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write24 writes a character using a 24/32bpp framebuffer.
|
||||||
|
func (cons *VesaFbConsole) write24(glyphIndex, fg, bg uint8, pX, pY uint32) {
|
||||||
|
var (
|
||||||
|
fontOffset = uint32(glyphIndex) * cons.font.BytesPerRow * cons.font.GlyphHeight
|
||||||
|
fbRowOffset = cons.fbOffset(pX, pY)
|
||||||
|
fbOffset uint32
|
||||||
|
x, y uint32
|
||||||
|
mask uint8
|
||||||
|
fgComp = cons.packColor24(fg)
|
||||||
|
bgComp = cons.packColor24(bg)
|
||||||
|
)
|
||||||
|
|
||||||
|
for y = 0; y < cons.font.GlyphHeight; y, fbRowOffset, fontOffset = y+1, fbRowOffset+cons.pitch, fontOffset+1 {
|
||||||
|
fbOffset = fbRowOffset
|
||||||
|
fontRowData := cons.font.Data[fontOffset]
|
||||||
|
mask = 1 << 7
|
||||||
|
for x = 0; x < cons.font.GlyphWidth; x, fbOffset, mask = x+1, fbOffset+cons.bytesPerPixel, mask>>1 {
|
||||||
|
// If mask becomes zero while we are still in this loop
|
||||||
|
// then the font uses > 1 byte per row. We need to
|
||||||
|
// fetch the next byte and reset the mask.
|
||||||
|
if mask == 0 {
|
||||||
|
fontOffset++
|
||||||
|
fontRowData = cons.font.Data[fontOffset]
|
||||||
|
mask = 1 << 7
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fontRowData & mask) != 0 {
|
||||||
|
cons.fb[fbOffset] = fgComp[0]
|
||||||
|
cons.fb[fbOffset+1] = fgComp[1]
|
||||||
|
cons.fb[fbOffset+2] = fgComp[2]
|
||||||
|
} else {
|
||||||
|
cons.fb[fbOffset] = bgComp[0]
|
||||||
|
cons.fb[fbOffset+1] = bgComp[1]
|
||||||
|
cons.fb[fbOffset+2] = bgComp[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// fbOffset returns the linear offset into the framebuffer that corresponds to
|
// fbOffset returns the linear offset into the framebuffer that corresponds to
|
||||||
// the pixel at (x,y).
|
// the pixel at (x,y).
|
||||||
func (cons *VesaFbConsole) fbOffset(x, y uint32) uint32 {
|
func (cons *VesaFbConsole) fbOffset(x, y uint32) uint32 {
|
||||||
return ((y + cons.offsetY) * cons.pitch) + (x * cons.bpp >> 3)
|
return ((y + cons.offsetY) * cons.pitch) + (x * cons.bytesPerPixel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// packColor24 encodes a palette color into the pixel format required by a
|
||||||
|
// 24/32 bpp framebuffer.
|
||||||
|
func (cons *VesaFbConsole) packColor24(colorIndex uint8) [3]uint8 {
|
||||||
|
var (
|
||||||
|
c = cons.palette[colorIndex].(color.RGBA)
|
||||||
|
packed uint32 = 0 |
|
||||||
|
(uint32(c.R>>(8-cons.colorInfo.RedMaskSize)) << cons.colorInfo.RedPosition) |
|
||||||
|
(uint32(c.G>>(8-cons.colorInfo.GreenMaskSize)) << cons.colorInfo.GreenPosition) |
|
||||||
|
(uint32(c.B>>(8-cons.colorInfo.BlueMaskSize)) << cons.colorInfo.BluePosition)
|
||||||
|
)
|
||||||
|
|
||||||
|
return [3]uint8{
|
||||||
|
uint8(packed),
|
||||||
|
uint8(packed >> 8),
|
||||||
|
uint8(packed >> 16),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Palette returns the active color palette for this console.
|
// Palette returns the active color palette for this console.
|
||||||
@ -222,19 +337,49 @@ func (cons *VesaFbConsole) Palette() color.Palette {
|
|||||||
// palette index. Passing a color index greated than the number of
|
// palette index. Passing a color index greated than the number of
|
||||||
// supported colors should be a no-op.
|
// supported colors should be a no-op.
|
||||||
func (cons *VesaFbConsole) SetPaletteColor(index uint8, rgba color.RGBA) {
|
func (cons *VesaFbConsole) SetPaletteColor(index uint8, rgba color.RGBA) {
|
||||||
cons.palette[index] = rgba
|
oldColor := cons.palette[index]
|
||||||
|
|
||||||
// Only program the DAC when we are in indexed (8bpp) mode
|
if oldColor != nil && oldColor.(color.RGBA) == rgba {
|
||||||
if cons.bpp > 8 {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load palette entry to the DAC. Each DAC entry is a 6-bit value so
|
cons.palette[index] = rgba
|
||||||
// we need to scale the RGB values in the [0-63] range.
|
|
||||||
portWriteByteFn(0x3c8, index)
|
switch cons.bpp {
|
||||||
portWriteByteFn(0x3c9, rgba.R>>2)
|
case 8:
|
||||||
portWriteByteFn(0x3c9, rgba.G>>2)
|
// Load palette entry to the DAC. Each DAC entry is a 6-bit value so
|
||||||
portWriteByteFn(0x3c9, rgba.B>>2)
|
// we need to scale the RGB values in the [0-63] range.
|
||||||
|
portWriteByteFn(0x3c8, index)
|
||||||
|
portWriteByteFn(0x3c9, rgba.R>>2)
|
||||||
|
portWriteByteFn(0x3c9, rgba.G>>2)
|
||||||
|
portWriteByteFn(0x3c9, rgba.B>>2)
|
||||||
|
case 24, 32:
|
||||||
|
if oldColor == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cons.replace24(oldColor.(color.RGBA), rgba)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace24 replaces all srcColor values with dstColor using a 24/32bpp
|
||||||
|
// framebuffer.
|
||||||
|
func (cons *VesaFbConsole) replace24(src, dst color.RGBA) {
|
||||||
|
tmp := cons.palette[0]
|
||||||
|
cons.palette[0] = src
|
||||||
|
srcComp := cons.packColor24(0)
|
||||||
|
cons.palette[0] = dst
|
||||||
|
dstComp := cons.packColor24(0)
|
||||||
|
cons.palette[0] = tmp
|
||||||
|
for fbOffset := uint32(0); fbOffset < uint32(len(cons.fb)); fbOffset += cons.bytesPerPixel {
|
||||||
|
if cons.fb[fbOffset] == srcComp[0] &&
|
||||||
|
cons.fb[fbOffset+1] == srcComp[1] &&
|
||||||
|
cons.fb[fbOffset+2] == srcComp[2] {
|
||||||
|
cons.fb[fbOffset] = dstComp[0]
|
||||||
|
cons.fb[fbOffset+1] = dstComp[1]
|
||||||
|
cons.fb[fbOffset+2] = dstComp[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadDefaultPalette is called during driver initialization to setup the
|
// loadDefaultPalette is called during driver initialization to setup the
|
||||||
@ -262,7 +407,7 @@ func (cons *VesaFbConsole) loadDefaultPalette() {
|
|||||||
color.RGBA{R: 255, G: 255, B: 255}, /* white */
|
color.RGBA{R: 255, G: 255, B: 255}, /* white */
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load default EFA palette for colors 0-16
|
// Load default EGA palette for colors 0-16
|
||||||
var index int
|
var index int
|
||||||
for ; index < len(egaPalette); index++ {
|
for ; index < len(egaPalette); index++ {
|
||||||
cons.SetPaletteColor(uint8(index), egaPalette[index])
|
cons.SetPaletteColor(uint8(index), egaPalette[index])
|
||||||
@ -305,6 +450,7 @@ func (cons *VesaFbConsole) DriverInit(w io.Writer) *kernel.Error {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
kfmt.Fprintf(w, "mapped framebuffer to 0x%x\n", fbPage.Address())
|
kfmt.Fprintf(w, "mapped framebuffer to 0x%x\n", fbPage.Address())
|
||||||
|
kfmt.Fprintf(w, "framebuffer dimensions: %dx%dx%d\n", cons.width, cons.height, cons.bpp)
|
||||||
|
|
||||||
cons.loadDefaultPalette()
|
cons.loadDefaultPalette()
|
||||||
|
|
||||||
@ -316,8 +462,13 @@ func probeForVesaFbConsole() device.Driver {
|
|||||||
var drv device.Driver
|
var drv device.Driver
|
||||||
|
|
||||||
fbInfo := getFramebufferInfoFn()
|
fbInfo := getFramebufferInfoFn()
|
||||||
if fbInfo.Type == multiboot.FramebufferTypeIndexed {
|
if fbInfo.Type == multiboot.FramebufferTypeIndexed || fbInfo.Type == multiboot.FramebufferTypeRGB {
|
||||||
drv = NewVesaFbConsole(fbInfo.Width, fbInfo.Height, fbInfo.Bpp, fbInfo.Pitch, uintptr(fbInfo.PhysAddr))
|
drv = NewVesaFbConsole(
|
||||||
|
fbInfo.Width, fbInfo.Height,
|
||||||
|
fbInfo.Bpp, fbInfo.Pitch,
|
||||||
|
fbInfo.RGBColorInfo(),
|
||||||
|
uintptr(fbInfo.PhysAddr),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return drv
|
return drv
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestVesaFbTextDimensions(t *testing.T) {
|
func TestVesaFbTextDimensions(t *testing.T) {
|
||||||
var cons Device = NewVesaFbConsole(16, 32, 8, 16, 0)
|
var cons Device = NewVesaFbConsole(16, 32, 8, 16, nil, 0)
|
||||||
|
|
||||||
if w, h := cons.Dimensions(Characters); w != 0 || h != 0 {
|
if w, h := cons.Dimensions(Characters); w != 0 || h != 0 {
|
||||||
t.Fatalf("expected console dimensions to be 0x0 before setting a font; got %dx%d", w, h)
|
t.Fatalf("expected console dimensions to be 0x0 before setting a font; got %dx%d", w, h)
|
||||||
@ -54,7 +54,7 @@ func TestVesaFbTextDimensions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestVesaFbDefaultColors(t *testing.T) {
|
func TestVesaFbDefaultColors(t *testing.T) {
|
||||||
var cons Device = NewVesaFbConsole(16, 32, 8, 16, 0)
|
var cons Device = NewVesaFbConsole(16, 32, 8, 16, nil, 0)
|
||||||
if fg, bg := cons.DefaultColors(); fg != 7 || bg != 0 {
|
if fg, bg := cons.DefaultColors(); fg != 7 || bg != 0 {
|
||||||
t.Fatalf("expected console default colors to be fg:7, bg:0; got fg:%d, bg: %d", fg, bg)
|
t.Fatalf("expected console default colors to be fg:7, bg:0; got fg:%d, bg: %d", fg, bg)
|
||||||
}
|
}
|
||||||
@ -124,7 +124,7 @@ func TestVesaFbWrite8bpp(t *testing.T) {
|
|||||||
for specIndex, spec := range specs {
|
for specIndex, spec := range specs {
|
||||||
fb := make([]uint8, spec.consW*spec.consH)
|
fb := make([]uint8, spec.consW*spec.consH)
|
||||||
|
|
||||||
cons := NewVesaFbConsole(spec.consW, spec.consH, 8, spec.consW, 0)
|
cons := NewVesaFbConsole(spec.consW, spec.consH, 8, spec.consW, nil, 0)
|
||||||
cons.fb = fb
|
cons.fb = fb
|
||||||
cons.offsetY = spec.offsetY
|
cons.offsetY = spec.offsetY
|
||||||
cons.SetFont(spec.font)
|
cons.SetFont(spec.font)
|
||||||
@ -148,7 +148,107 @@ func TestVesaFbWrite8bpp(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVesaFbScroll8bpp(t *testing.T) {
|
func TestVesaFbWrite24bpp(t *testing.T) {
|
||||||
|
specs := []struct {
|
||||||
|
consW, consH, offsetY uint32
|
||||||
|
font *font.Font
|
||||||
|
expFb []byte
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
16, 16, 6,
|
||||||
|
mockFont8x10,
|
||||||
|
[]byte("" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000321000000000000" +
|
||||||
|
"000000000000000000000000000000321321321000000000" +
|
||||||
|
"000000000000000000000000000321321000321321000000" +
|
||||||
|
"000000000000000000000000321321000000000321321000" +
|
||||||
|
"000000000000000000000000321321000000000321321000" +
|
||||||
|
"000000000000000000000000321321321321321321321000" +
|
||||||
|
"000000000000000000000000321321000000000321321000" +
|
||||||
|
"000000000000000000000000321321000000000321321000" +
|
||||||
|
"000000000000000000000000321321000000000321321000" +
|
||||||
|
"000000000000000000000000321321000000000321321000",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
20, 20, 3,
|
||||||
|
mockFont10x14,
|
||||||
|
[]byte("" +
|
||||||
|
"000000000000000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000321000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000321000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000321321321000000000" +
|
||||||
|
"000000000000000000000000000000000000000000321321321000000000" +
|
||||||
|
"000000000000000000000000000000000000000321321000321321000000" +
|
||||||
|
"000000000000000000000000000000000000000321321000321321000000" +
|
||||||
|
"000000000000000000000000000000000000000321321000000321321000" +
|
||||||
|
"000000000000000000000000000000000000321321000000000321321000" +
|
||||||
|
"000000000000000000000000000000000000321321321321321321321000" +
|
||||||
|
"000000000000000000000000000000000000321321000000000321321000" +
|
||||||
|
"000000000000000000000000000000000321321000000000000321321000" +
|
||||||
|
"000000000000000000000000000000000321321000000000000000321321" +
|
||||||
|
"000000000000000000000000000000000321321000000000000000321321" +
|
||||||
|
"000000000000000000000000000000321321321321000000000321321321" +
|
||||||
|
"000000000000000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// BGR
|
||||||
|
colorInfo = &multiboot.FramebufferRGBColorInfo{
|
||||||
|
RedPosition: 16,
|
||||||
|
RedMaskSize: 8,
|
||||||
|
GreenPosition: 8,
|
||||||
|
GreenMaskSize: 8,
|
||||||
|
BluePosition: 0,
|
||||||
|
BlueMaskSize: 8,
|
||||||
|
}
|
||||||
|
fg = uint8(1)
|
||||||
|
fgColor = color.RGBA{R: 1, G: 2, B: 3}
|
||||||
|
bg = uint8(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
fb := make([]uint8, spec.consW*spec.consH*3)
|
||||||
|
|
||||||
|
cons := NewVesaFbConsole(spec.consW, spec.consH, 24, spec.consW*3, colorInfo, 0)
|
||||||
|
cons.fb = fb
|
||||||
|
cons.offsetY = spec.offsetY
|
||||||
|
cons.SetFont(spec.font)
|
||||||
|
cons.loadDefaultPalette()
|
||||||
|
cons.SetPaletteColor(fg, fgColor)
|
||||||
|
|
||||||
|
// ASCII 0 maps to the a blank character in the mock font
|
||||||
|
// ASCII 1 maps to the letter 'A' in the mock font
|
||||||
|
cons.Write(0, fg, bg, 0, 0)
|
||||||
|
cons.Write(1, fg, bg, 2, 1)
|
||||||
|
|
||||||
|
// Convert expected contents from ASCII to byte
|
||||||
|
for i := 0; i < len(spec.expFb); i++ {
|
||||||
|
spec.expFb[i] -= '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(spec.expFb, fb) {
|
||||||
|
t.Errorf("[spec %d] unexpected frame buffer contents:\n%s",
|
||||||
|
specIndex,
|
||||||
|
diffFrameBuffer(spec.consW, spec.consH, spec.consW*3, spec.expFb, fb),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVesaFbScroll(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
consW, consH uint32 = 16, 16
|
consW, consH uint32 = 16, 16
|
||||||
offsetY uint32 = 3
|
offsetY uint32 = 3
|
||||||
@ -325,7 +425,7 @@ func TestVesaFbScroll8bpp(t *testing.T) {
|
|||||||
fb := make([]uint8, consW*consH)
|
fb := make([]uint8, consW*consH)
|
||||||
copy(fb, origFb)
|
copy(fb, origFb)
|
||||||
|
|
||||||
cons := NewVesaFbConsole(consW, consH, 8, consW, 0)
|
cons := NewVesaFbConsole(consW, consH, 8, consW, nil, 0)
|
||||||
cons.fb = fb
|
cons.fb = fb
|
||||||
cons.offsetY = offsetY
|
cons.offsetY = offsetY
|
||||||
|
|
||||||
@ -355,7 +455,7 @@ func TestVesaFbScroll8bpp(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVesFbFill8(t *testing.T) {
|
func TestVesaFbFill8(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
consW, consH uint32 = 16, 26
|
consW, consH uint32 = 16, 26
|
||||||
bg uint8 = 1
|
bg uint8 = 1
|
||||||
@ -538,7 +638,7 @@ func TestVesFbFill8(t *testing.T) {
|
|||||||
fb := make([]uint8, consW*consH)
|
fb := make([]uint8, consW*consH)
|
||||||
copy(fb, origFb)
|
copy(fb, origFb)
|
||||||
|
|
||||||
cons := NewVesaFbConsole(consW, consH, 8, consW, 0)
|
cons := NewVesaFbConsole(consW, consH, 8, consW, nil, 0)
|
||||||
cons.fb = fb
|
cons.fb = fb
|
||||||
cons.offsetY = spec.offsetY
|
cons.offsetY = spec.offsetY
|
||||||
|
|
||||||
@ -564,6 +664,227 @@ func TestVesFbFill8(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVesaFbFill24(t *testing.T) {
|
||||||
|
var (
|
||||||
|
consW, consH uint32 = 16, 26
|
||||||
|
// BGR
|
||||||
|
colorInfo = &multiboot.FramebufferRGBColorInfo{
|
||||||
|
RedPosition: 16,
|
||||||
|
RedMaskSize: 8,
|
||||||
|
GreenPosition: 8,
|
||||||
|
GreenMaskSize: 8,
|
||||||
|
BluePosition: 0,
|
||||||
|
BlueMaskSize: 8,
|
||||||
|
}
|
||||||
|
bg uint8 = 1
|
||||||
|
bgColor = color.RGBA{R: 1, G: 2, B: 3}
|
||||||
|
origFb = []byte("" +
|
||||||
|
"666666666666666666666666666666666666666666666666" + // }
|
||||||
|
"777777777777777777777777777777777777777777777777" + // }- reserved rows
|
||||||
|
"888888888888888888888888888888888888888888888888" + // }
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
specs := []struct {
|
||||||
|
// Input rect in characters
|
||||||
|
x, y, w, h uint32
|
||||||
|
offsetY uint32
|
||||||
|
expFb []byte
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
0, 0, 1, 1,
|
||||||
|
0,
|
||||||
|
[]byte("" +
|
||||||
|
"321321321321321321321321666666666666666666666666" + // }
|
||||||
|
"321321321321321321321321777777777777777777777777" + // }- reserved rows
|
||||||
|
"321321321321321321321321888888888888888888888888" + // }
|
||||||
|
"321321321321321321321321000000000000000000000000" +
|
||||||
|
"321321321321321321321321000000000000000000000000" +
|
||||||
|
"321321321321321321321321000000000000000000000000" +
|
||||||
|
"321321321321321321321321000000000000000000000000" +
|
||||||
|
"321321321321321321321321000000000000000000000000" +
|
||||||
|
"321321321321321321321321000000000000000000000000" +
|
||||||
|
"321321321321321321321321000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
2, 0, 10, 1,
|
||||||
|
3,
|
||||||
|
[]byte("" +
|
||||||
|
"666666666666666666666666666666666666666666666666" + // }
|
||||||
|
"777777777777777777777777777777777777777777777777" + // }- reserved rows
|
||||||
|
"888888888888888888888888888888888888888888888888" + // }
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
0, 0, 100, 100,
|
||||||
|
3,
|
||||||
|
[]byte("" +
|
||||||
|
"666666666666666666666666666666666666666666666666" + // }
|
||||||
|
"777777777777777777777777777777777777777777777777" + // }- reserved rows
|
||||||
|
"888888888888888888888888888888888888888888888888" + // }
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"321321321321321321321321321321321321321321321321" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
100, 100, 1, 1,
|
||||||
|
6,
|
||||||
|
[]byte("" +
|
||||||
|
"666666666666666666666666666666666666666666666666" + // }
|
||||||
|
"777777777777777777777777777777777777777777777777" + // }- reserved rows
|
||||||
|
"888888888888888888888888888888888888888888888888" + // }
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000000000000000000000000000" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321" +
|
||||||
|
"000000000000000000000000321321321321321321321321",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert original fb contents from ASCII to byte
|
||||||
|
for i := 0; i < len(origFb); i++ {
|
||||||
|
origFb[i] -= '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
// Convert expected contents from ASCII to byte
|
||||||
|
for i := 0; i < len(spec.expFb); i++ {
|
||||||
|
spec.expFb[i] -= '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
fb := make([]uint8, consW*consH*3)
|
||||||
|
copy(fb, origFb)
|
||||||
|
|
||||||
|
cons := NewVesaFbConsole(consW, consH, 24, consW*3, colorInfo, 0)
|
||||||
|
cons.fb = fb
|
||||||
|
cons.offsetY = spec.offsetY
|
||||||
|
cons.loadDefaultPalette()
|
||||||
|
cons.SetPaletteColor(bg, bgColor)
|
||||||
|
|
||||||
|
// Calling fill before selecting a font should be a no-op
|
||||||
|
cons.Fill(spec.x, spec.y, spec.w, spec.h, 0, bg)
|
||||||
|
if !reflect.DeepEqual(origFb, fb) {
|
||||||
|
t.Errorf("[spec %d] unexpected frame buffer contents:\n%s",
|
||||||
|
specIndex,
|
||||||
|
diffFrameBuffer(consW, consH, consW*3, origFb, fb),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
cons.SetFont(mockFont8x10)
|
||||||
|
|
||||||
|
cons.Fill(spec.x, spec.y, spec.w, spec.h, 0, bg)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(spec.expFb, fb) {
|
||||||
|
t.Errorf("[spec %d] unexpected frame buffer contents:\n%s",
|
||||||
|
specIndex,
|
||||||
|
diffFrameBuffer(consW, consH, consW*3, spec.expFb, fb),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestVesaFbPalette(t *testing.T) {
|
func TestVesaFbPalette(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
portWriteByteFn = cpu.PortWriteByte
|
portWriteByteFn = cpu.PortWriteByte
|
||||||
@ -594,10 +915,12 @@ func TestVesaFbPalette(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
dacIndex uint8
|
dacIndex uint8
|
||||||
compIndex uint8
|
compIndex uint8
|
||||||
|
portWriteCount int
|
||||||
)
|
)
|
||||||
portWriteByteFn = func(port uint16, val uint8) {
|
portWriteByteFn = func(port uint16, val uint8) {
|
||||||
|
portWriteCount++
|
||||||
switch port {
|
switch port {
|
||||||
case 0x3c8:
|
case 0x3c8:
|
||||||
dacIndex = val
|
dacIndex = val
|
||||||
@ -623,13 +946,20 @@ func TestVesaFbPalette(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cons := NewVesaFbConsole(0, 0, 8, 0, 0)
|
cons := NewVesaFbConsole(0, 0, 8, 0, nil, 0)
|
||||||
cons.loadDefaultPalette()
|
cons.loadDefaultPalette()
|
||||||
|
|
||||||
customColor := color.RGBA{R: 251, G: 252, B: 253}
|
customColor := color.RGBA{R: 251, G: 252, B: 253}
|
||||||
expPal[255] = customColor
|
expPal[255] = customColor
|
||||||
cons.SetPaletteColor(255, customColor)
|
cons.SetPaletteColor(255, customColor)
|
||||||
|
|
||||||
|
// Setting the same RGB value should be a no-op
|
||||||
|
cons.SetPaletteColor(255, customColor)
|
||||||
|
|
||||||
|
if exp := 257 * 4; portWriteCount != exp {
|
||||||
|
t.Errorf("expected %d calls to cpu.portWriteByte; got %d", exp, portWriteCount)
|
||||||
|
}
|
||||||
|
|
||||||
got := cons.Palette()
|
got := cons.Palette()
|
||||||
for index, exp := range expPal {
|
for index, exp := range expPal {
|
||||||
if got[index] != exp {
|
if got[index] != exp {
|
||||||
@ -638,12 +968,96 @@ func TestVesaFbPalette(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVesaFbReplace24(t *testing.T) {
|
||||||
|
var (
|
||||||
|
consW, consH uint32 = 4, 4
|
||||||
|
// BGR
|
||||||
|
colorInfo = &multiboot.FramebufferRGBColorInfo{
|
||||||
|
RedPosition: 16,
|
||||||
|
RedMaskSize: 8,
|
||||||
|
GreenPosition: 8,
|
||||||
|
GreenMaskSize: 8,
|
||||||
|
BluePosition: 0,
|
||||||
|
BlueMaskSize: 8,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
specs := []struct {
|
||||||
|
bpp uint8
|
||||||
|
inpFb []byte
|
||||||
|
expFb []byte
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
24,
|
||||||
|
[]byte("" +
|
||||||
|
"000100010002" +
|
||||||
|
"000100010002" +
|
||||||
|
"000100010002" +
|
||||||
|
"000100010002",
|
||||||
|
),
|
||||||
|
[]byte("" +
|
||||||
|
"765100010002" +
|
||||||
|
"765100010002" +
|
||||||
|
"765100010002" +
|
||||||
|
"765100010002",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
32,
|
||||||
|
[]byte("" +
|
||||||
|
"0000100001000020" +
|
||||||
|
"0000100001000020" +
|
||||||
|
"0000100001000020" +
|
||||||
|
"0000100001000020",
|
||||||
|
),
|
||||||
|
[]byte("" +
|
||||||
|
"7650100001000020" +
|
||||||
|
"7650100001000020" +
|
||||||
|
"7650100001000020" +
|
||||||
|
"7650100001000020",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
// Convert spec fb contents from ASCII to byte
|
||||||
|
for i := 0; i < len(spec.expFb); i++ {
|
||||||
|
spec.inpFb[i] -= '0'
|
||||||
|
spec.expFb[i] -= '0'
|
||||||
|
}
|
||||||
|
fb := make([]uint8, consW*consH*uint32(spec.bpp)>>3)
|
||||||
|
copy(fb, spec.inpFb)
|
||||||
|
|
||||||
|
cons := NewVesaFbConsole(consW, consH, spec.bpp, consW*uint32(spec.bpp)>>3, colorInfo, 0)
|
||||||
|
cons.fb = fb
|
||||||
|
cons.palette = make(color.Palette, 1)
|
||||||
|
|
||||||
|
// First color update should not trigger a replace as the color is not used yet
|
||||||
|
cons.SetPaletteColor(0, color.RGBA{})
|
||||||
|
if !reflect.DeepEqual(spec.inpFb, fb) {
|
||||||
|
t.Errorf("[spec %d] unexpected frame buffer contents:\n%s",
|
||||||
|
specIndex,
|
||||||
|
diffFrameBuffer(consW, consH, cons.pitch, spec.expFb, fb),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second color update should replace existing pixels with the new RGB value
|
||||||
|
cons.SetPaletteColor(0, color.RGBA{R: 5, G: 6, B: 7})
|
||||||
|
if !reflect.DeepEqual(spec.expFb, fb) {
|
||||||
|
t.Errorf("[spec %d] unexpected frame buffer contents:\n%s",
|
||||||
|
specIndex,
|
||||||
|
diffFrameBuffer(consW, consH, cons.pitch, spec.expFb, fb),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestVesaFbDriverInterface(t *testing.T) {
|
func TestVesaFbDriverInterface(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
mapRegionFn = vmm.MapRegion
|
mapRegionFn = vmm.MapRegion
|
||||||
portWriteByteFn = cpu.PortWriteByte
|
portWriteByteFn = cpu.PortWriteByte
|
||||||
}()
|
}()
|
||||||
var dev device.Driver = NewVesaFbConsole(320, 200, 8, 320, uintptr(0xa0000))
|
var dev device.Driver = NewVesaFbConsole(320, 200, 8, 320, nil, uintptr(0xa0000))
|
||||||
|
|
||||||
if dev.DriverName() == "" {
|
if dev.DriverName() == "" {
|
||||||
t.Fatal("DriverName() returned an empty string")
|
t.Fatal("DriverName() returned an empty string")
|
||||||
@ -698,6 +1112,53 @@ func TestVesaFbProbe(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVesaFbPackColor24(t *testing.T) {
|
||||||
|
specs := []struct {
|
||||||
|
colorInfo *multiboot.FramebufferRGBColorInfo
|
||||||
|
input color.RGBA
|
||||||
|
exp [3]uint8
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// RGB
|
||||||
|
&multiboot.FramebufferRGBColorInfo{
|
||||||
|
RedPosition: 0,
|
||||||
|
RedMaskSize: 8,
|
||||||
|
GreenPosition: 8,
|
||||||
|
GreenMaskSize: 8,
|
||||||
|
BluePosition: 16,
|
||||||
|
BlueMaskSize: 8,
|
||||||
|
},
|
||||||
|
color.RGBA{R: 100, G: 200, B: 255},
|
||||||
|
[3]uint8{100, 200, 255},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// BGR
|
||||||
|
&multiboot.FramebufferRGBColorInfo{
|
||||||
|
RedPosition: 16,
|
||||||
|
RedMaskSize: 8,
|
||||||
|
GreenPosition: 8,
|
||||||
|
GreenMaskSize: 8,
|
||||||
|
BluePosition: 0,
|
||||||
|
BlueMaskSize: 8,
|
||||||
|
},
|
||||||
|
color.RGBA{R: 250, G: 200, B: 120},
|
||||||
|
[3]uint8{120, 200, 250},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cons := NewVesaFbConsole(0, 0, 32, 0, nil, 0)
|
||||||
|
cons.palette = make(color.Palette, 256)
|
||||||
|
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
cons.colorInfo = spec.colorInfo
|
||||||
|
cons.palette[0] = spec.input
|
||||||
|
|
||||||
|
if got := cons.packColor24(0); got != spec.exp {
|
||||||
|
t.Errorf("[spec %d] expected: %v; got %v", specIndex, spec.exp, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func dumpFramebuffer(consW, consH, consPitch uint32, fb []byte) string {
|
func dumpFramebuffer(consW, consH, consPitch uint32, fb []byte) string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user