mirror of
https://github.com/justinian/jsix.git
synced 2025-12-11 08:54:31 -08:00
For now, using VNC, I want to keep the framebuffer mode small, so I'm commenting out the bootloader's loop to pick the biggest video mode. I'll revisit this as a bootconfig option later.
127 lines
3.3 KiB
C++
127 lines
3.3 KiB
C++
#include <uefi/boot_services.h>
|
|
#include <uefi/graphics.h>
|
|
#include <uefi/protos/graphics_output.h>
|
|
|
|
#include <bootproto/init.h>
|
|
|
|
#include "allocator.h"
|
|
#include "console.h"
|
|
#include "error.h"
|
|
#include "video.h"
|
|
|
|
namespace boot {
|
|
namespace video {
|
|
|
|
using bootproto::devices::fb_layout;
|
|
using bootproto::module_type;
|
|
|
|
static uefi::protos::graphics_output *
|
|
get_gop(uefi::boot_services *bs)
|
|
{
|
|
uefi::protos::graphics_output *gop = nullptr;
|
|
uefi::guid guid = uefi::protos::graphics_output::guid;
|
|
|
|
uefi::status has_gop = bs->locate_protocol(&guid, nullptr,
|
|
(void **)&gop);
|
|
|
|
if (has_gop != uefi::status::success)
|
|
return nullptr;
|
|
|
|
return gop;
|
|
}
|
|
|
|
screen *
|
|
pick_mode(uefi::boot_services *bs)
|
|
{
|
|
uefi::protos::graphics_output *gop = get_gop(bs);
|
|
if (!gop) {
|
|
console::print(L"No framebuffer found.\r\n");
|
|
return nullptr;
|
|
}
|
|
|
|
uefi::graphics_output_mode_info *info = gop->mode->info;
|
|
|
|
uint32_t best = gop->mode->mode;
|
|
uint32_t res = info->horizontal_resolution * info->vertical_resolution;
|
|
int pixmode = static_cast<int>(info->pixel_format);
|
|
|
|
/*
|
|
const uint32_t modes = gop->mode->max_mode;
|
|
for (uint32_t i = 0; i < modes; ++i) {
|
|
size_t size = 0;
|
|
uefi::graphics_output_mode_info *new_info = nullptr;
|
|
|
|
try_or_raise(
|
|
gop->query_mode(i, &size, &new_info),
|
|
L"Failed to find a graphics mode the driver claimed to support");
|
|
|
|
const uint32_t new_res = new_info->horizontal_resolution * new_info->vertical_resolution;
|
|
int new_pixmode = static_cast<int>(new_info->pixel_format);
|
|
|
|
if (new_pixmode <= pixmode && new_res >= res) {
|
|
best = i;
|
|
res = new_res;
|
|
pixmode = new_pixmode;
|
|
}
|
|
}
|
|
*/
|
|
|
|
screen *s = new screen;
|
|
s->mode = {
|
|
.vertical = gop->mode->info->vertical_resolution,
|
|
.horizontal = gop->mode->info->horizontal_resolution,
|
|
.scanline = gop->mode->info->pixels_per_scanline,
|
|
.layout = fb_layout::unknown,
|
|
};
|
|
|
|
s->framebuffer = {
|
|
.pointer = reinterpret_cast<void*>(gop->mode->frame_buffer_base),
|
|
.count = gop->mode->frame_buffer_size
|
|
};
|
|
|
|
wchar_t const * type = nullptr;
|
|
switch (info->pixel_format) {
|
|
case uefi::pixel_format::rgb8:
|
|
type = L"rgb8";
|
|
s->mode.layout = fb_layout::rgb8;
|
|
break;
|
|
|
|
case uefi::pixel_format::bgr8:
|
|
type = L"bgr8";
|
|
s->mode.layout = fb_layout::bgr8;
|
|
break;
|
|
|
|
default:
|
|
type = L"unknown";
|
|
}
|
|
|
|
console::print(L"Found framebuffer: %dx%d[%d] type %s @0x%x\r\n",
|
|
info->horizontal_resolution, info->vertical_resolution,
|
|
info->pixels_per_scanline, type, gop->mode->frame_buffer_base);
|
|
|
|
try_or_raise(
|
|
gop->set_mode(best),
|
|
L"Failed to set graphics mode");
|
|
|
|
return s;
|
|
}
|
|
|
|
void
|
|
make_module(screen *s)
|
|
{
|
|
using bootproto::module;
|
|
using bootproto::module_type;
|
|
namespace devices = bootproto::devices;
|
|
|
|
module *mod = g_alloc.allocate_module(sizeof(devices::uefi_fb));
|
|
mod->type = module_type::device;
|
|
mod->type_id = devices::type_id_uefi_fb;
|
|
|
|
devices::uefi_fb *fb = mod->data<devices::uefi_fb>();
|
|
fb->framebuffer = s->framebuffer;
|
|
fb->mode = s->mode;
|
|
}
|
|
|
|
} // namespace video
|
|
} // namespace boot
|