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 (
|
import (
|
||||||
"gopheros/device"
|
"gopheros/device"
|
||||||
"gopheros/device/video/console/font"
|
"gopheros/device/video/console/font"
|
||||||
|
"gopheros/device/video/console/logo"
|
||||||
"gopheros/kernel"
|
"gopheros/kernel"
|
||||||
"gopheros/kernel/hal/multiboot"
|
"gopheros/kernel/hal/multiboot"
|
||||||
"gopheros/kernel/kfmt"
|
"gopheros/kernel/kfmt"
|
||||||
@ -75,8 +76,63 @@ func (cons *VesaFbConsole) SetFont(f *font.Font) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cons.font = f
|
cons.font = f
|
||||||
cons.widthInChars = cons.width / uint32(f.GlyphWidth)
|
cons.widthInChars = cons.width / f.GlyphWidth
|
||||||
cons.heightInChars = (cons.height - cons.offsetY) / uint32(f.GlyphHeight)
|
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.
|
// 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
|
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
|
cons.palette[index] = rgba
|
||||||
|
|
||||||
switch cons.bpp {
|
switch cons.bpp {
|
||||||
@ -394,13 +458,13 @@ func (cons *VesaFbConsole) SetPaletteColor(index uint8, rgba color.RGBA) {
|
|||||||
portWriteByteFn(0x3c9, rgba.G>>2)
|
portWriteByteFn(0x3c9, rgba.G>>2)
|
||||||
portWriteByteFn(0x3c9, rgba.B>>2)
|
portWriteByteFn(0x3c9, rgba.B>>2)
|
||||||
case 15, 16:
|
case 15, 16:
|
||||||
if oldColor == nil {
|
if oldColor == nil || !replace {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cons.replace16(oldColor.(color.RGBA), rgba)
|
cons.replace16(oldColor.(color.RGBA), rgba)
|
||||||
case 24, 32:
|
case 24, 32:
|
||||||
if oldColor == nil {
|
if oldColor == nil || !replace {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,7 +481,7 @@ func (cons *VesaFbConsole) replace16(src, dst color.RGBA) {
|
|||||||
cons.palette[0] = dst
|
cons.palette[0] = dst
|
||||||
dstComp := cons.packColor16(0)
|
dstComp := cons.packColor16(0)
|
||||||
cons.palette[0] = tmp
|
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] &&
|
if cons.fb[fbOffset] == srcComp[0] &&
|
||||||
cons.fb[fbOffset+1] == srcComp[1] {
|
cons.fb[fbOffset+1] == srcComp[1] {
|
||||||
cons.fb[fbOffset] = dstComp[0]
|
cons.fb[fbOffset] = dstComp[0]
|
||||||
@ -435,7 +499,7 @@ func (cons *VesaFbConsole) replace24(src, dst color.RGBA) {
|
|||||||
cons.palette[0] = dst
|
cons.palette[0] = dst
|
||||||
dstComp := cons.packColor24(0)
|
dstComp := cons.packColor24(0)
|
||||||
cons.palette[0] = tmp
|
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] &&
|
if cons.fb[fbOffset] == srcComp[0] &&
|
||||||
cons.fb[fbOffset+1] == srcComp[1] &&
|
cons.fb[fbOffset+1] == srcComp[1] &&
|
||||||
cons.fb[fbOffset+2] == srcComp[2] {
|
cons.fb[fbOffset+2] == srcComp[2] {
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"gopheros/device"
|
"gopheros/device"
|
||||||
"gopheros/device/video/console/font"
|
"gopheros/device/video/console/font"
|
||||||
|
"gopheros/device/video/console/logo"
|
||||||
"gopheros/kernel"
|
"gopheros/kernel"
|
||||||
"gopheros/kernel/cpu"
|
"gopheros/kernel/cpu"
|
||||||
"gopheros/kernel/hal/multiboot"
|
"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 {
|
func dumpFramebuffer(consW, consH, consPitch uint32, fb []byte) string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
||||||
@ -1602,7 +1751,7 @@ func dumpFramebuffer(consW, consH, consPitch uint32, fb []byte) string {
|
|||||||
fmt.Fprintf(&buf, "%04d |", y)
|
fmt.Fprintf(&buf, "%04d |", y)
|
||||||
index := (y * consPitch)
|
index := (y * consPitch)
|
||||||
for x := uint32(0); x < consPitch; x++ {
|
for x := uint32(0); x < consPitch; x++ {
|
||||||
fmt.Fprintf(&buf, "%d", fb[index+x])
|
fmt.Fprintf(&buf, "%d ", fb[index+x])
|
||||||
}
|
}
|
||||||
fmt.Fprintln(&buf, "|")
|
fmt.Fprintln(&buf, "|")
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user