1
0
mirror of https://github.com/taigrr/gopher-os synced 2025-01-18 04:43:13 -08:00

Implement LogoSetter interface for vesa fb driver

This commit is contained in:
Achilleas Anagnostopoulos 2017-07-13 22:00:21 +01:00
parent c7fc9f0ac9
commit eaeae85600
2 changed files with 220 additions and 7 deletions

View File

@ -3,6 +3,7 @@ package console
import (
"gopheros/device"
"gopheros/device/video/console/font"
"gopheros/device/video/console/logo"
"gopheros/kernel"
"gopheros/kernel/hal/multiboot"
"gopheros/kernel/kfmt"
@ -75,8 +76,63 @@ func (cons *VesaFbConsole) SetFont(f *font.Font) {
}
cons.font = f
cons.widthInChars = cons.width / uint32(f.GlyphWidth)
cons.heightInChars = (cons.height - cons.offsetY) / uint32(f.GlyphHeight)
cons.widthInChars = cons.width / f.GlyphWidth
cons.heightInChars = (cons.height - cons.offsetY) / f.GlyphHeight
}
// SetLogo selects the logo to be displayed by the console. The logo colors will
// be remapped to the end of the console's palette and space equal to the logo
// height will be reserved at the top of the framebuffer for diplaying the logo.
//
// As setting a logo changes the available space for rendering text, SetLogo
// must be invoked before SetFont.
func (cons *VesaFbConsole) SetLogo(l *logo.Image) {
if l == nil {
return
}
// Map the logo colors to the console palette replacing the transparent
// color index with the console default bg color
offset := uint8(len(cons.palette) - len(l.Palette))
for i, rgba := range l.Palette {
if uint8(i) == l.TransparentIndex {
rgba = cons.palette[cons.defaultBg].(color.RGBA)
}
cons.setPaletteColor(uint8(i)+offset, rgba, false)
}
// Draw the logo
var fbRowOffset uint32
switch l.Align {
case logo.AlignLeft:
fbRowOffset = cons.fbOffset(0, 0)
case logo.AlignCenter:
fbRowOffset = cons.fbOffset((cons.width-l.Width)>>1, 0)
case logo.AlignRight:
fbRowOffset = cons.fbOffset(cons.width-l.Width, 0)
}
for y, logoOffset := uint32(0), 0; y < l.Height; y, fbRowOffset = y+1, fbRowOffset+cons.pitch {
for x, fbOffset := uint32(0), fbRowOffset; x < l.Width; x, fbOffset, logoOffset = x+1, fbOffset+cons.bytesPerPixel, logoOffset+1 {
c := l.Data[logoOffset] + offset
switch cons.bpp {
case 8:
cons.fb[fbOffset] = c
case 15, 16:
colorComp := cons.packColor16(c)
cons.fb[fbOffset] = colorComp[0]
cons.fb[fbOffset+1] = colorComp[1]
case 24, 32:
colorComp := cons.packColor24(c)
cons.fb[fbOffset] = colorComp[0]
cons.fb[fbOffset+1] = colorComp[1]
cons.fb[fbOffset+2] = colorComp[2]
}
}
}
cons.offsetY = l.Height
}
// Dimensions returns the console width and height in the specified dimension.
@ -383,6 +439,14 @@ func (cons *VesaFbConsole) SetPaletteColor(index uint8, rgba color.RGBA) {
return
}
cons.setPaletteColor(index, rgba, true)
}
// setPaletteColor updates the color definition for the specified
// palette index. If replace is true, then all occurrences of the old color
// in the framebuffer will be replaced by the new color value (if bpp > 8).
func (cons *VesaFbConsole) setPaletteColor(index uint8, rgba color.RGBA, replace bool) {
oldColor := cons.palette[index]
cons.palette[index] = rgba
switch cons.bpp {
@ -394,13 +458,13 @@ func (cons *VesaFbConsole) SetPaletteColor(index uint8, rgba color.RGBA) {
portWriteByteFn(0x3c9, rgba.G>>2)
portWriteByteFn(0x3c9, rgba.B>>2)
case 15, 16:
if oldColor == nil {
if oldColor == nil || !replace {
return
}
cons.replace16(oldColor.(color.RGBA), rgba)
case 24, 32:
if oldColor == nil {
if oldColor == nil || !replace {
return
}
@ -417,7 +481,7 @@ func (cons *VesaFbConsole) replace16(src, dst color.RGBA) {
cons.palette[0] = dst
dstComp := cons.packColor16(0)
cons.palette[0] = tmp
for fbOffset := uint32(0); fbOffset < uint32(len(cons.fb)); fbOffset += cons.bytesPerPixel {
for fbOffset := cons.fbOffset(0, 0); fbOffset < uint32(len(cons.fb)); fbOffset += cons.bytesPerPixel {
if cons.fb[fbOffset] == srcComp[0] &&
cons.fb[fbOffset+1] == srcComp[1] {
cons.fb[fbOffset] = dstComp[0]
@ -435,7 +499,7 @@ func (cons *VesaFbConsole) replace24(src, dst color.RGBA) {
cons.palette[0] = dst
dstComp := cons.packColor24(0)
cons.palette[0] = tmp
for fbOffset := uint32(0); fbOffset < uint32(len(cons.fb)); fbOffset += cons.bytesPerPixel {
for fbOffset := cons.fbOffset(0, 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] {

View File

@ -5,6 +5,7 @@ import (
"fmt"
"gopheros/device"
"gopheros/device/video/console/font"
"gopheros/device/video/console/logo"
"gopheros/kernel"
"gopheros/kernel/cpu"
"gopheros/kernel/hal/multiboot"
@ -1595,6 +1596,154 @@ func TestVesaFbPackColor24(t *testing.T) {
}
}
func TestVesaFbSetLogo(t *testing.T) {
defer func() {
portWriteByteFn = cpu.PortWriteByte
}()
var (
consW uint32 = 4
consH uint32 = 2
inpFb8 = []byte{
0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa,
}
inpFb16 = []byte{
0xaa, 0xab, 0xaa, 0xab, 0xaa, 0xab, 0xaa, 0xab,
0xaa, 0xab, 0xaa, 0xab, 0xaa, 0xab, 0xaa, 0xab,
}
inpFb24 = []byte{
0xaa, 0xab, 0xac, 0xaa, 0xab, 0xac, 0xaa, 0xab, 0xac, 0xaa, 0xab, 0xac,
0xaa, 0xab, 0xac, 0xaa, 0xab, 0xac, 0xaa, 0xab, 0xac, 0xaa, 0xab, 0xac,
}
mockLogo = &logo.Image{
Width: 2,
Height: 2,
Align: logo.AlignLeft,
TransparentIndex: 0,
Palette: []color.RGBA{
color.RGBA{R: 255, G: 0, B: 255},
color.RGBA{R: 255, G: 0, B: 128},
},
Data: []byte{
0x0, 0x1,
0x1, 0x0,
},
}
)
specs := []struct {
inpFb []byte
bpp uint8
colorInfo *multiboot.FramebufferRGBColorInfo
align logo.Alignment
logo *logo.Image
expFb []byte
}{
{
inpFb8,
8,
nil,
logo.AlignLeft,
mockLogo,
[]byte{
0xfe, 0xff, 0xaa, 0xaa,
0xff, 0xfe, 0xaa, 0xaa,
},
},
{
inpFb8,
8,
nil,
logo.AlignCenter,
mockLogo,
[]byte{
0xaa, 0xfe, 0xff, 0xaa,
0xaa, 0xff, 0xfe, 0xaa,
},
},
{
inpFb8,
8,
nil,
logo.AlignRight,
mockLogo,
[]byte{
0xaa, 0xaa, 0xfe, 0xff,
0xaa, 0xaa, 0xff, 0xfe,
},
},
{
inpFb16,
16,
// RGB555
&multiboot.FramebufferRGBColorInfo{
RedPosition: 10,
RedMaskSize: 5,
GreenPosition: 5,
GreenMaskSize: 5,
BluePosition: 0,
BlueMaskSize: 5,
},
logo.AlignLeft,
mockLogo,
[]byte{
0x00, 0x00, 0x10, 0x7c, 0xaa, 0xab, 0xaa, 0xab,
0x10, 0x7c, 0x00, 0x00, 0xaa, 0xab, 0xaa, 0xab,
},
},
{
inpFb24,
24,
// RGB
&multiboot.FramebufferRGBColorInfo{
RedPosition: 0,
RedMaskSize: 8,
GreenPosition: 8,
GreenMaskSize: 8,
BluePosition: 16,
BlueMaskSize: 8,
},
logo.AlignRight,
mockLogo,
[]byte{
0xaa, 0xab, 0xac, 0xaa, 0xab, 0xac, 0x00, 0x00, 0x00, 0xff, 0x00, 0x80,
0xaa, 0xab, 0xac, 0xaa, 0xab, 0xac, 0xff, 0x00, 0x80, 0x00, 0x00, 0x00,
},
},
}
var ()
for specIndex, spec := range specs {
portWriteByteFn = func(port uint16, val uint8) {}
cons := NewVesaFbConsole(consW, consH, spec.bpp, consW*uint32(spec.bpp>>3), spec.colorInfo, 0)
cons.fb = make([]byte, len(spec.inpFb))
copy(cons.fb, spec.inpFb)
cons.palette = make(color.Palette, 256)
cons.loadDefaultPalette()
// Setting a nil logo should be a no-op
cons.SetLogo(nil)
if !reflect.DeepEqual(spec.inpFb, cons.fb) {
t.Errorf("[spec %d] unexpected frame buffer contents:\n%s",
specIndex,
diffFrameBuffer(consW, consH, cons.pitch, spec.expFb, cons.fb),
)
}
mockLogo.Align = spec.align
cons.SetLogo(mockLogo)
if !reflect.DeepEqual(spec.expFb, cons.fb) {
t.Errorf("[spec %d] unexpected frame buffer contents:\n%s",
specIndex,
diffFrameBuffer(consW, consH, cons.pitch, spec.expFb, cons.fb),
)
}
}
}
func dumpFramebuffer(consW, consH, consPitch uint32, fb []byte) string {
var buf bytes.Buffer
@ -1602,7 +1751,7 @@ func dumpFramebuffer(consW, consH, consPitch uint32, fb []byte) string {
fmt.Fprintf(&buf, "%04d |", y)
index := (y * consPitch)
for x := uint32(0); x < consPitch; x++ {
fmt.Fprintf(&buf, "%d", fb[index+x])
fmt.Fprintf(&buf, "%d ", fb[index+x])
}
fmt.Fprintln(&buf, "|")
}