fix: LVGL rendering for 16bpp framebuffers (HyperV compatibility)
continuous-integration/drone/push Build is failing
continuous-integration/drone/push Build is failing
The LVGL flush callback assumed 32bpp (4-byte stride, direct pixel copy), causing corrupted output on hypervisors that fall back to 16bpp modes (e.g. HyperV at 1600x1200x16). - lvgl.pas: Make lvgl_flush_cb BPP-aware; add ARGB8888->RGB565 conversion path for 16bpp, keep direct copy for 32bpp. Replace static lv_buf1 array (hardcoded 1600px wide) with kalloc'd buffer sized to actual screen width. - doublebuffer.pas: Fix allocateBackBuffer size from (W*H*BPP) to (W*H*BPP) div 8 to get correct byte count. - vesa.pas: Account for BPP in allocateVESAFrameBuffer page range calculation to avoid under-mapping at higher BPP/resolutions. - Removed the initialization of console in kernel.pas as this will cause issues on some systems that don't expect to need to allocate the textmode buffer.
This commit is contained in:
@@ -32,8 +32,7 @@ implementation
|
||||
function allocateBackBuffer(Width : uint32; Height : uint32; BitsPerPixel : uint8) : uint64;
|
||||
begin
|
||||
tracer.push_trace('doublebuffer.allocateBackBuffer.enter');
|
||||
//This doesn't currently work... Needs a rework of lmemorymanager
|
||||
allocateBackBuffer:= uint64(klalloc((Width * Height) * BitsPerPixel));
|
||||
allocateBackBuffer:= uint64(klalloc((Width * Height * BitsPerPixel) div 8));
|
||||
tracer.push_trace('doublebuffer.allocateBackBuffer.exit');
|
||||
end;
|
||||
|
||||
|
||||
@@ -1725,7 +1725,8 @@ const
|
||||
LV_BUF_LINES = 120;
|
||||
|
||||
var
|
||||
lv_buf1: array[0..1600*LV_BUF_LINES-1] of lv_color_t;
|
||||
lv_buf1: pointer;
|
||||
lv_buf1_size: uint32;
|
||||
|
||||
{ ============================================================
|
||||
Color helper
|
||||
@@ -1740,24 +1741,46 @@ end;
|
||||
|
||||
{ ============================================================
|
||||
Flush callback — copies LVGL render buffer to video back buffer
|
||||
Handles 32bpp (direct copy) and 16bpp (ARGB8888 -> RGB565).
|
||||
============================================================ }
|
||||
procedure lvgl_flush_cb(disp: Plv_display; area: Plv_area; color_p: Plv_color); cdecl;
|
||||
var
|
||||
y, x, area_w: sint32;
|
||||
src: puint32;
|
||||
dst: puint32;
|
||||
dst32: puint32;
|
||||
dst16: puint16;
|
||||
fb_w: uint32;
|
||||
bpp: uint8;
|
||||
pixel: uint32;
|
||||
r, g, b: uint8;
|
||||
begin
|
||||
fb_w := video.backBufferWidth;
|
||||
bpp := video.backBufferBpp;
|
||||
area_w := (area^.x2 - area^.x1) + 1;
|
||||
src := puint32(color_p);
|
||||
|
||||
for y := area^.y1 to area^.y2 do begin
|
||||
dst := puint32(video.backBufferLocation + uint32((y * sint32(fb_w) + area^.x1) * 4));
|
||||
for x := 0 to area_w - 1 do begin
|
||||
dst[x] := src[x];
|
||||
if bpp >= 32 then begin
|
||||
{ 32bpp: direct copy, 4 bytes per pixel }
|
||||
for y := area^.y1 to area^.y2 do begin
|
||||
dst32 := puint32(video.backBufferLocation + uint32((y * sint32(fb_w) + area^.x1) * 4));
|
||||
for x := 0 to area_w - 1 do begin
|
||||
dst32[x] := src[x];
|
||||
end;
|
||||
src := puint32(uint32(src) + uint32(area_w * 4));
|
||||
end;
|
||||
end else if bpp = 16 then begin
|
||||
{ 16bpp: convert ARGB8888 -> RGB565, 2 bytes per pixel }
|
||||
for y := area^.y1 to area^.y2 do begin
|
||||
dst16 := puint16(video.backBufferLocation + uint32((y * sint32(fb_w) + area^.x1) * 2));
|
||||
for x := 0 to area_w - 1 do begin
|
||||
pixel := src[x];
|
||||
b := pixel and $FF;
|
||||
g := (pixel shr 8) and $FF;
|
||||
r := (pixel shr 16) and $FF;
|
||||
dst16[x] := uint16(((uint16(r) shr 3) shl 11) or ((uint16(g) shr 2) shl 5) or (uint16(b) shr 3));
|
||||
end;
|
||||
src := puint32(uint32(src) + uint32(area_w * 4));
|
||||
end;
|
||||
src := puint32(uint32(src) + uint32(area_w * 4));
|
||||
end;
|
||||
|
||||
lv_display_flush_ready(disp);
|
||||
@@ -1852,11 +1875,15 @@ begin
|
||||
{ Register log callback }
|
||||
lv_log_register_print_cb(@lvgl_log_cb);
|
||||
|
||||
{ Allocate LVGL render buffer dynamically (1/10th of screen) }
|
||||
lv_buf1_size := screen_w * LV_BUF_LINES * SizeOf(lv_color_t);
|
||||
lv_buf1 := pointer(kalloc(lv_buf1_size));
|
||||
|
||||
{ Create display }
|
||||
disp := lv_display_create(sint32(screen_w), sint32(screen_h));
|
||||
lv_display_set_flush_cb(disp, @lvgl_flush_cb);
|
||||
lv_display_set_buffers(disp, @lv_buf1[0], nil,
|
||||
SizeOf(lv_buf1), LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
lv_display_set_buffers(disp, lv_buf1, nil,
|
||||
lv_buf1_size, LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
|
||||
{ Create mouse input device with read callback }
|
||||
mouse_indev := lv_indev_create;
|
||||
|
||||
@@ -32,22 +32,24 @@ implementation
|
||||
uses
|
||||
VESA8, VESA16, VESA24, VESA32;
|
||||
|
||||
procedure allocateVESAFrameBuffer(Address : uint32; Width : uint32; Height : uint32);
|
||||
procedure allocateVESAFrameBuffer(Address : uint32; Width : uint32; Height : uint32; BitsPerPixel : uint8);
|
||||
var
|
||||
LowerAddress, UpperAddress : uint32;
|
||||
Block : uint32;
|
||||
FrameBufferSize : uint32;
|
||||
|
||||
begin
|
||||
tracer.push_trace('VESA.allocateFrameBuffer.enter');
|
||||
FrameBufferSize := (Width * Height * BitsPerPixel) div 8;
|
||||
LowerAddress:= ((Address) SHR 22)-1;
|
||||
UpperAddress:= ((Address + (Width * Height)) SHR 22)+1;
|
||||
UpperAddress:= ((Address + FrameBufferSize) SHR 22)+1;
|
||||
For Block:=LowerAddress to UpperAddress do begin
|
||||
kpalloc(Block SHL 22);
|
||||
end;
|
||||
tracer.push_trace('VESA.allocateFrameBuffer.exit');
|
||||
end;
|
||||
|
||||
procedure initVESAFrameBuffer(VideoBuffer : PVideoBuffer; Location : uint64; Width : uint32; Height : uint32; BitsPerPixel : uint8);
|
||||
procedure initVESAFrameBuffer(VideoBuffer : PVideoBuffer; Location : uint64; Width : uint32; Height : uint32; BitsPerPixel : uint8; Pitch : uint32);
|
||||
begin
|
||||
tracer.push_trace('VESA.initVESAFrameBuffer.enter');
|
||||
if not(VideoBuffer^.Initialized) then begin
|
||||
@@ -55,7 +57,7 @@ begin
|
||||
VideoBuffer^.BitsPerPixel:= BitsPerPixel;
|
||||
VideoBuffer^.Width:= Width;
|
||||
VideoBuffer^.Height:= Height;
|
||||
allocateVESAFrameBuffer(VideoBuffer^.Location, VideoBuffer^.Width, VideoBuffer^.Height);
|
||||
allocateVESAFrameBuffer(VideoBuffer^.Location, VideoBuffer^.Width, VideoBuffer^.Height, BitsPerPixel);
|
||||
if VideoBuffer^.Location <> 0 then
|
||||
VideoBuffer^.Initialized:= True;
|
||||
end;
|
||||
@@ -65,7 +67,7 @@ end;
|
||||
function enable(VideoInterface : PVideoInterface) : boolean;
|
||||
begin
|
||||
tracer.push_trace('VESA.enable.enter');
|
||||
initVESAFrameBuffer(@VideoInterface^.FrontBuffer, multiboot.multibootinfo^.framebuffer_addr, multiboot.multibootinfo^.framebuffer_width, multiboot.multibootinfo^.framebuffer_height, multiboot.multibootinfo^.framebuffer_bpp);
|
||||
initVESAFrameBuffer(@VideoInterface^.FrontBuffer, multiboot.multibootinfo^.framebuffer_addr, multiboot.multibootinfo^.framebuffer_width, multiboot.multibootinfo^.framebuffer_height, multiboot.multibootinfo^.framebuffer_bpp, multiboot.multibootinfo^.framebuffer_pitch);
|
||||
case (VideoInterface^.FrontBuffer.BitsPerPixel) of
|
||||
08:VESA8.init(@VideoInterface^.DrawRoutines);
|
||||
16:VESA16.init(@VideoInterface^.DrawRoutines);
|
||||
|
||||
+1
-3
@@ -123,8 +123,6 @@ begin
|
||||
multibootinfo:= mbinfo;
|
||||
multibootmagic:= mbmagic;
|
||||
|
||||
//video.init();
|
||||
|
||||
{ Ensure tracer is frozen }
|
||||
tracer.freeze();
|
||||
|
||||
@@ -181,7 +179,7 @@ begin
|
||||
scheduler.init();
|
||||
|
||||
{ Console Init }
|
||||
console.init();
|
||||
//console.init();
|
||||
|
||||
{ CPUID }
|
||||
console.outputln('CPU', 'Init begin');
|
||||
|
||||
Reference in New Issue
Block a user