[haiku-development] [PATCH 2/2] Remap vesa frame buffer only if necessary.

* Allocate frame buffer area for the biggest mode
* Fall back to old behaviour when different modes have different frame buffer
  addresses
---
 headers/private/graphics/vesa/vesa_info.h         |    1 +
 headers/private/kernel/frame_buffer_console.h     |    2 +
 src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp |   57 +++++++++++---------
 src/system/boot/platform/bios_ia32/video.cpp      |   55 ++++++++++++--------
 src/system/kernel/debug/frame_buffer_console.cpp  |    2 +
 5 files changed, 68 insertions(+), 49 deletions(-)

diff --git a/headers/private/graphics/vesa/vesa_info.h 
b/headers/private/graphics/vesa/vesa_info.h
index 1de16a6..ea60578 100644
--- a/headers/private/graphics/vesa/vesa_info.h
+++ b/headers/private/graphics/vesa/vesa_info.h
@@ -31,6 +31,7 @@ struct vesa_shared_info {
        uint8                   *frame_buffer;
                // pointer to frame buffer (visible by all apps!)
        uint8                   *physical_frame_buffer;
+       uint32                  mapping_size;
 
        uint32                  vesa_mode_offset;
        uint32                  vesa_mode_count;
diff --git a/headers/private/kernel/frame_buffer_console.h 
b/headers/private/kernel/frame_buffer_console.h
index 4c80a4c..06801db 100644
--- a/headers/private/kernel/frame_buffer_console.h
+++ b/headers/private/kernel/frame_buffer_console.h
@@ -16,6 +16,8 @@ struct kernel_args;
 struct frame_buffer_boot_info {
        area_id area;
        addr_t  frame_buffer;
+       addr_t  frame_buffer_phys;
+       int32   frame_buffer_size;
        int32   width;
        int32   height;
        int32   depth;
diff --git a/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp 
b/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp
index 31971c6..4526dbd 100644
--- a/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp
+++ b/src/add-ons/kernel/drivers/graphics/vesa/vesa.cpp
@@ -131,6 +131,8 @@ vesa_init(vesa_info &info)
 
        sharedInfo.frame_buffer_area = bufferInfo->area;
        sharedInfo.frame_buffer = (uint8 *)bufferInfo->frame_buffer;
+       sharedInfo.physical_frame_buffer = (uint8 
*)bufferInfo->frame_buffer_phys;
+       sharedInfo.mapping_size = bufferInfo->frame_buffer_size;
 
        sharedInfo.current_mode.virtual_width = bufferInfo->width;
        sharedInfo.current_mode.virtual_height = bufferInfo->height;
@@ -138,11 +140,6 @@ vesa_init(vesa_info &info)
                bufferInfo->depth);
        sharedInfo.bytes_per_row = bufferInfo->bytes_per_row;
 
-       physical_entry mapping;
-       get_memory_map((void *)sharedInfo.frame_buffer, B_PAGE_SIZE,
-               &mapping, 1);
-       sharedInfo.physical_frame_buffer = (uint8 *)mapping.address;
-
        dprintf(DEVICE_NAME ": vesa_init() completed successfully!\n");
        return B_OK;
 }
@@ -173,7 +170,9 @@ vesa_set_display_mode(vesa_info &info, unsigned int mode)
        }
 
        area_id newFBArea;
-       frame_buffer_boot_info *bufferInfo;
+       uint32 newFBSize;
+       frame_buffer_boot_info *bufferInfo =
+               (frame_buffer_boot_info *)get_boot_item(FRAME_BUFFER_BOOT_INFO, 
NULL);
        struct vbe_mode_info modeInfo;
 
        // Get mode information
@@ -190,33 +189,39 @@ vesa_set_display_mode(vesa_info &info, unsigned int mode)
                goto error;
        }
 
-       // Map new frame buffer
-       void *frameBuffer;
-       newFBArea = map_physical_memory("vesa_fb",
-               (void *)modeInfo.physical_base,
-               modeInfo.bytes_per_row * modeInfo.height, B_ANY_KERNEL_ADDRESS,
-               B_READ_AREA | B_WRITE_AREA, &frameBuffer);
-       if (newFBArea < B_OK) {
-               status = (status_t)newFBArea;
-               goto error;
+       // Remap the frame buffer only if it's now at other address or if the
+       // mapping is too small
+       newFBSize = modeInfo.bytes_per_row * modeInfo.height;
+       if (info.shared_info->physical_frame_buffer != (uint8 
*)modeInfo.physical_base
+               || info.shared_info->mapping_size < newFBSize) {
+
+               void *frameBuffer;
+               newFBArea = map_physical_memory("vesa_fb",
+                       (void *)modeInfo.physical_base, newFBSize, 
B_ANY_KERNEL_ADDRESS,
+                       B_READ_AREA | B_WRITE_AREA, &frameBuffer);
+               if (newFBArea < B_OK) {
+                       status = (status_t)newFBArea;
+                       goto error;
+               }
+               delete_area(info.shared_info->frame_buffer_area);
+
+               // Update shared frame buffer information
+               info.shared_info->frame_buffer_area = newFBArea;
+               info.shared_info->frame_buffer = (uint8 *)frameBuffer;
+               info.shared_info->mapping_size = newFBSize;
+               info.shared_info->physical_frame_buffer = (uint8 
*)modeInfo.physical_base;
+
+               // Update boot item as it's used in vesa_init()
+               bufferInfo->area = newFBArea;
+               bufferInfo->frame_buffer = (addr_t)frameBuffer;
        }
-       delete_area(info.shared_info->frame_buffer_area);
 
-       // Update shared frame buffer information
-       info.shared_info->frame_buffer_area = newFBArea;
-       info.shared_info->frame_buffer = (uint8 *)frameBuffer;
-       info.shared_info->physical_frame_buffer = (uint8 
*)modeInfo.physical_base;
+       // Update necessary stuff
        info.shared_info->bytes_per_row = modeInfo.bytes_per_row;
        info.shared_info->current_mode.virtual_width = modeInfo.width;
        info.shared_info->current_mode.virtual_height = modeInfo.height;
        info.shared_info->current_mode.space = get_color_space_for_depth(
                modeInfo.bits_per_pixel);
-
-       // Update boot item as it's used in vesa_init()
-       bufferInfo
-               = (frame_buffer_boot_info 
*)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL);
-       bufferInfo->area = newFBArea;
-       bufferInfo->frame_buffer = (addr_t)frameBuffer;
        bufferInfo->width = modeInfo.width;
        bufferInfo->height = modeInfo.height;
        bufferInfo->depth = modeInfo.bits_per_pixel;
diff --git a/src/system/boot/platform/bios_ia32/video.cpp 
b/src/system/boot/platform/bios_ia32/video.cpp
index 2309989..a0aebd7 100644
--- a/src/system/boot/platform/bios_ia32/video.cpp
+++ b/src/system/boot/platform/bios_ia32/video.cpp
@@ -364,6 +364,8 @@ vesa_init(vbe_info_block *info, video_mode **_standardMode)
        // fill mode list and find standard video mode
 
        video_mode *standardMode = NULL;
+       uint32 fbBase = 0;
+       uint32 fbSize = 0;
 
        for (int32 i = 0; true; i++) {
                uint16 mode = ((uint16 *)info->mode_list)[i];
@@ -408,6 +410,17 @@ vesa_init(vbe_info_block *info, video_mode **_standardMode)
                                        videoMode->bits_per_pixel = 15;
                                }
 
+                               if (fbBase == 0 || fbBase == 
modeInfo.physical_base) {
+                                       fbBase = modeInfo.physical_base;
+                                       uint32 size = modeInfo.bytes_per_row * 
modeInfo.height;
+                                       if (size > fbSize)
+                                               fbSize = size;
+                               } else {
+                                       // different frame buffer base -> 
cannot map whole frame
+                                       // buffer in one area for all modes
+                                       fbBase = 0xFFFFFFFF;
+                               }
+
                                add_video_mode(videoMode);
                        }
                } else
@@ -437,6 +450,9 @@ vesa_init(vbe_info_block *info, video_mode **_standardMode)
                return B_ERROR;
        }
 
+       gKernelArgs.frame_buffer.physical_buffer.start = fbBase;
+       gKernelArgs.frame_buffer.physical_buffer.size = fbSize;
+
        *_standardMode = standardMode;
        return B_OK;
 }
@@ -844,8 +860,8 @@ platform_switch_to_logo(void)
        if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) != 0)
                return;
 
-       addr_t lastBase = gKernelArgs.frame_buffer.physical_buffer.start;
-       size_t lastSize = gKernelArgs.frame_buffer.physical_buffer.size;
+       addr_t fbBase = gKernelArgs.frame_buffer.physical_buffer.start;
+       size_t fbSize = gKernelArgs.frame_buffer.physical_buffer.size;
 
        if (sVesaCompatible && sMode != NULL) {
                if (!sModeChosen)
@@ -866,9 +882,14 @@ platform_switch_to_logo(void)
                gKernelArgs.frame_buffer.height = modeInfo.height;
                gKernelArgs.frame_buffer.bytes_per_row = modeInfo.bytes_per_row;
                gKernelArgs.frame_buffer.depth = modeInfo.bits_per_pixel;
-               gKernelArgs.frame_buffer.physical_buffer.size = 
modeInfo.bytes_per_row
-                       * gKernelArgs.frame_buffer.height;
-               gKernelArgs.frame_buffer.physical_buffer.start = 
modeInfo.physical_base;
+
+               uint32 size = modeInfo.bytes_per_row * 
gKernelArgs.frame_buffer.height;
+               if (modeInfo.physical_base != fbBase) {
+                       fbBase = modeInfo.physical_base;
+                       fbSize = size;
+               } else if (size > fbSize) {
+                       fbSize = size;
+               }
        } else {
 fallback:
                // use standard VGA mode 640x480x4
@@ -878,32 +899,20 @@ fallback:
                gKernelArgs.frame_buffer.height = 480;
                gKernelArgs.frame_buffer.bytes_per_row = 640 / 2;
                gKernelArgs.frame_buffer.depth = 4;
-               gKernelArgs.frame_buffer.physical_buffer.size
-                       = gKernelArgs.frame_buffer.width
+               fbSize = gKernelArgs.frame_buffer.width
                        * gKernelArgs.frame_buffer.height / 2;
-               gKernelArgs.frame_buffer.physical_buffer.start = 0xa0000;
+               fbBase = 0xa0000;
        }
+       gKernelArgs.frame_buffer.physical_buffer.size = fbSize;
+       gKernelArgs.frame_buffer.physical_buffer.start = fbBase;
 
        dprintf("video mode: %ux%ux%u\n", gKernelArgs.frame_buffer.width,
                gKernelArgs.frame_buffer.height, 
gKernelArgs.frame_buffer.depth);
 
        gKernelArgs.frame_buffer.enabled = true;
 
-       // If the new frame buffer is either larger than the old one or located 
at
-       // a different address, we need to remap it, so we first have to throw
-       // away its previous mapping
-       if (lastBase != 0
-               && (lastBase != gKernelArgs.frame_buffer.physical_buffer.start
-                       || lastSize < 
gKernelArgs.frame_buffer.physical_buffer.size)) {
-               mmu_free((void *)sFrameBuffer, lastSize);
-               lastBase = 0;
-       }
-       if (lastBase == 0) {
-               // the graphics memory has not been mapped yet!
-               sFrameBuffer = mmu_map_physical_memory(
-                       gKernelArgs.frame_buffer.physical_buffer.start,
-                       gKernelArgs.frame_buffer.physical_buffer.size, 
kDefaultPageFlags);
-       }
+       // map the graphics memory
+       sFrameBuffer = mmu_map_physical_memory(fbBase, fbSize, 
kDefaultPageFlags);
 
        // clear the video memory
        memset((void *)sFrameBuffer, 0,
diff --git a/src/system/kernel/debug/frame_buffer_console.cpp 
b/src/system/kernel/debug/frame_buffer_console.cpp
index c5b7b88..aedb71d 100644
--- a/src/system/kernel/debug/frame_buffer_console.cpp
+++ b/src/system/kernel/debug/frame_buffer_console.cpp
@@ -412,6 +412,8 @@ frame_buffer_console_init(kernel_args *args)
 
        sBootInfo.area = sConsole.area;
        sBootInfo.frame_buffer = (addr_t)frameBuffer;
+       sBootInfo.frame_buffer_phys = args->frame_buffer.physical_buffer.start;
+       sBootInfo.frame_buffer_size = args->frame_buffer.physical_buffer.size;
        sBootInfo.width = args->frame_buffer.width;
        sBootInfo.height = args->frame_buffer.height;
        sBootInfo.depth = args->frame_buffer.depth;
-- 
1.5.4.2


Other related posts: