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:
parent
c7fc9f0ac9
commit
eaeae85600
@ -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] {
|
||||
|
@ -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, "|")
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user