From e7c5d032d190ebfec25c5e93cb857af20947ed81 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Sat, 3 Sep 2016 23:46:10 +0200 Subject: [PATCH] Refactor graphical resolution changes. --- kernel/gpu/bga/bga.cpp | 142 ++++++++++++++++------ kernel/include/sortix/display.h | 3 + kernel/include/sortix/kernel/log.h | 6 +- kernel/include/sortix/kernel/textbuffer.h | 18 +-- kernel/include/sortix/kernel/video.h | 20 ++- kernel/lfbtextbuffer.cpp | 78 +++++++++--- kernel/lfbtextbuffer.h | 18 +-- kernel/log.cpp | 17 ++- kernel/textbuffer.cpp | 70 ++++++++++- kernel/textterminal.cpp | 26 ++++ kernel/textterminal.h | 3 + kernel/vgatextbuffer.cpp | 21 +++- kernel/vgatextbuffer.h | 14 ++- kernel/video.cpp | 127 ++++++++++++++----- sysinstall/sysinstall.c | 24 +++- sysinstall/sysupgrade.c | 20 ++- 16 files changed, 481 insertions(+), 126 deletions(-) diff --git a/kernel/gpu/bga/bga.cpp b/kernel/gpu/bga/bga.cpp index c6ac5f2c..84de1910 100644 --- a/kernel/gpu/bga/bga.cpp +++ b/kernel/gpu/bga/bga.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014 Jonas 'Sortie' Termansen. + * Copyright (c) 2012, 2014, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -38,7 +38,10 @@ #include #include +#if defined(__i386__) || defined(__x86_64__) #include "x86-family/memorymanagement.h" +#endif + #include "lfbtextbuffer.h" #include "bga.h" @@ -100,20 +103,22 @@ public: virtual ~BGADevice(); public: - virtual struct dispmsg_crtc_mode GetCurrentMode(uint64_t connector) const; + virtual uint64_t GetConnectorCount(); + virtual bool GetDefaultMode(uint64_t connector, struct dispmsg_crtc_mode* mode); + virtual bool GetCurrentMode(uint64_t connector, struct dispmsg_crtc_mode* mode); virtual bool SwitchMode(uint64_t connector, struct dispmsg_crtc_mode mode); - virtual bool Supports(uint64_t connector, struct dispmsg_crtc_mode mode) const; - virtual struct dispmsg_crtc_mode* GetModes(uint64_t connector, size_t* num_modes) const; - virtual off_t FrameSize() const; + virtual bool Supports(uint64_t connector, struct dispmsg_crtc_mode mode); + virtual struct dispmsg_crtc_mode* GetModes(uint64_t connector, size_t* num_modes); + virtual off_t FrameSize(); virtual ssize_t WriteAt(ioctx_t* ctx, off_t off, const void* buf, size_t count); virtual ssize_t ReadAt(ioctx_t* ctx, off_t off, void* buf, size_t count); - virtual TextBuffer* CreateTextBuffer(uint64_t connector); + virtual TextBuffer* CreateTextBuffer(uint64_t connector, struct dispmsg_crtc_mode mode); public: bool Initialize(); private: - bool DetectModes() const; + bool DetectModes(); uint16_t WriteRegister(uint16_t index, uint16_t value); uint16_t ReadRegister(uint16_t index); uint16_t GetCapability(uint16_t index); @@ -121,8 +126,8 @@ private: bool SupportsResolution(uint16_t width, uint16_t height, uint16_t depth); private: - mutable size_t num_modes; - mutable struct dispmsg_crtc_mode* modes; + size_t num_modes; + struct dispmsg_crtc_mode* modes; struct dispmsg_crtc_mode current_mode; addralloc_t fb_alloc; addralloc_t mmio_alloc; @@ -223,32 +228,91 @@ bool BGADevice::SetVideoMode(uint16_t width, uint16_t height, uint16_t depth, bo return true; } +uint64_t BGADevice::GetConnectorCount() +{ + return 1; +} + // TODO: Need a better method of detecting available/desired resolutions. bool BGADevice::SupportsResolution(uint16_t width, uint16_t height, uint16_t depth) { if ( !width || !height || !depth ) - return false; + return errno = EINVAL, false; if ( maxxres < width || maxyres < height || maxbpp < depth ) - return false; + return errno = EINVAL, false; // TODO: Is this actually a restriction? - if ( width % 8U ) - return false; + // TODO: This is not a restriction in VirtualBox anymore at least. + //if ( width % 8U ) + // return errno = EINVAL, false; // TODO: Can we determine this more closely in advance? Perhaps if the // framebuffer we will be using is larger than video memory? return true; } -struct dispmsg_crtc_mode BGADevice::GetCurrentMode(uint64_t connector) const +bool BGADevice::GetDefaultMode(uint64_t connector, + struct dispmsg_crtc_mode* mode_out) { - if ( connector != 0 ) + if ( connector ) + return errno = EINVAL, false; + + bool good = false; + uint32_t xres; + uint32_t yres; + uint32_t bpp; + if ( connector == 0 && Log::fallback_framebuffer && + SupportsResolution(Log::fallback_framebuffer_width, + Log::fallback_framebuffer_height, + 32) ) { - errno = EINVAL; - struct dispmsg_crtc_mode mode; - memset(&mode, 0, sizeof(mode)); - return mode; + xres = Log::fallback_framebuffer_width; + yres = Log::fallback_framebuffer_height; + bpp = 32; + } + else if ( connector == 0 && Log::fallback_framebuffer && + SupportsResolution(Log::fallback_framebuffer_width, + Log::fallback_framebuffer_height, + Log::fallback_framebuffer_bpp) ) + { + xres = Log::fallback_framebuffer_width; + yres = Log::fallback_framebuffer_height; + bpp = Log::fallback_framebuffer_bpp; + } + else + { + return errno = EINVAL, false; } - return current_mode; + struct dispmsg_crtc_mode mode; + memset(&mode, 0, sizeof(0)); + mode.driver_index = 0; + mode.magic = 0; + mode.control = DISPMSG_CONTROL_VALID | DISPMSG_CONTROL_DEFAULT; + if ( good ) + mode.control |= DISPMSG_CONTROL_GOOD_DEFAULT; + mode.fb_format = bpp; + mode.view_xres = xres; + mode.view_yres = yres; + mode.fb_location = 0; + mode.pitch = xres * (bpp + 7) / 8; + mode.surf_off_x = 0; + mode.surf_off_y = 0; + mode.start_x = 0; + mode.start_y = 0; + mode.end_x = 0; + mode.end_y = 0; + mode.desktop_height = yres; + *mode_out = mode; + + return true; +} + +bool BGADevice::GetCurrentMode(uint64_t connector, + struct dispmsg_crtc_mode* mode) +{ + if ( connector != 0 ) + return false; + *mode = current_mode; + return true; } bool BGADevice::SwitchMode(uint64_t connector, struct dispmsg_crtc_mode mode) @@ -259,13 +323,6 @@ bool BGADevice::SwitchMode(uint64_t connector, struct dispmsg_crtc_mode mode) if ( connector != 0 ) return errno = EINVAL, false; - size_t new_framesize = (size_t) mode.view_xres * - (size_t) mode.view_yres * - ((size_t) mode.fb_format + 7) / 8UL; - // TODO: Use a better error code than ENOSPC? - if ( fb_alloc.size < new_framesize ) - return errno = ENOSPC, false; - if ( !SetVideoMode(mode.view_xres, mode.view_yres, mode.fb_format, false) ) return false; @@ -274,7 +331,7 @@ bool BGADevice::SwitchMode(uint64_t connector, struct dispmsg_crtc_mode mode) return true; } -bool BGADevice::Supports(uint64_t connector, struct dispmsg_crtc_mode mode) const +bool BGADevice::Supports(uint64_t connector, struct dispmsg_crtc_mode mode) { if ( connector != 0 ) return errno = EINVAL, false; @@ -303,10 +360,17 @@ bool BGADevice::Supports(uint64_t connector, struct dispmsg_crtc_mode mode) cons mode.fb_format != VBE_DISPI_BPP_32 ) return errno = ENOSYS, false; - return ((BGADevice*) this)->SupportsResolution(mode.view_xres, mode.view_yres, mode.fb_format); + size_t new_framesize = (size_t) mode.view_xres * + (size_t) mode.view_yres * + ((size_t) mode.fb_format + 7) / 8UL; + // TODO: Use a better error code than ENOSPC? + if ( fb_alloc.size < new_framesize ) + return errno = ENOSPC, false; + + return SupportsResolution(mode.view_xres, mode.view_yres, mode.fb_format); } -struct dispmsg_crtc_mode* BGADevice::GetModes(uint64_t connector, size_t* retnum) const +struct dispmsg_crtc_mode* BGADevice::GetModes(uint64_t connector, size_t* retnum) { if ( connector != 0 ) return errno = EINVAL, (struct dispmsg_crtc_mode*) NULL; @@ -322,7 +386,7 @@ struct dispmsg_crtc_mode* BGADevice::GetModes(uint64_t connector, size_t* retnum return result; } -off_t BGADevice::FrameSize() const +off_t BGADevice::FrameSize() { return (off_t) fb_alloc.size; } @@ -351,7 +415,7 @@ ssize_t BGADevice::ReadAt(ioctx_t* ctx, off_t off, void* buf, size_t count) return count; } -bool BGADevice::DetectModes() const +bool BGADevice::DetectModes() { num_modes = 0; unsigned bpp = VBE_DISPI_BPP_32; @@ -401,15 +465,19 @@ bool BGADevice::DetectModes() const return true; } -TextBuffer* BGADevice::CreateTextBuffer(uint64_t connector) +TextBuffer* BGADevice::CreateTextBuffer(uint64_t connector, + struct dispmsg_crtc_mode mode) { + if ( !Supports(connector, mode) ) + return NULL; + if ( connector != 0 ) return errno = EINVAL, (TextBuffer*) NULL; uint8_t* lfb = (uint8_t*) fb_alloc.from; - uint32_t lfbformat = current_mode.fb_format; - size_t scansize = current_mode.view_xres * current_mode.fb_format / 8UL; - return CreateLFBTextBuffer(lfb, lfbformat, current_mode.view_xres, current_mode.view_yres, scansize); + uint32_t lfbformat = mode.fb_format; + size_t scansize = mode.view_xres * mode.fb_format / 8UL; + return CreateLFBTextBuffer(lfb, lfbformat, mode.view_xres, mode.view_yres, scansize); } static void TryInitializeDevice(uint32_t devaddr) @@ -498,6 +566,8 @@ static void TryInitializeDevice(uint32_t devaddr) delete bga_device; return; } + + Video::ConfigureDevice(bga_device); } void Init() diff --git a/kernel/include/sortix/display.h b/kernel/include/sortix/display.h index 67a856d1..3358c980 100644 --- a/kernel/include/sortix/display.h +++ b/kernel/include/sortix/display.h @@ -33,6 +33,9 @@ static const uint32_t DISPMSG_CONTROL_VALID = 1 << 0; static const uint32_t DISPMSG_CONTROL_VGA = 1 << 1; static const uint32_t DISPMSG_CONTROL_OTHER_RESOLUTIONS = 1 << 2; static const uint32_t DISPMSG_CONTROL_FALLBACK = 1 << 3; +static const uint32_t DISPMSG_CONTROL_DEFAULT = 1 << 4; +static const uint32_t DISPMSG_CONTROL_GOOD_DEFAULT = 1 << 5; +static const uint32_t DISPMSG_CONTROL_VM_AUTO_SCALE = 1 << 6; struct dispmsg_string { diff --git a/kernel/include/sortix/kernel/log.h b/kernel/include/sortix/kernel/log.h index 27f1c6c7..32a71113 100644 --- a/kernel/include/sortix/kernel/log.h +++ b/kernel/include/sortix/kernel/log.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen. + * Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -30,6 +30,7 @@ typedef struct multiboot_info multiboot_info_t; namespace Sortix { +class TextBuffer; class TextBufferHandle; } // namespace Sortix @@ -126,6 +127,9 @@ inline size_t PrintFV(const char* format, va_list list) void Init(multiboot_info_t* bootinfo); void Center(const char* string); +void BeginReplace(); +void CancelReplace(); +void FinishReplace(TextBuffer* textbuf); } // namespace Log } // namespace Sortix diff --git a/kernel/include/sortix/kernel/textbuffer.h b/kernel/include/sortix/kernel/textbuffer.h index 2a18b944..7e8b2e9d 100644 --- a/kernel/include/sortix/kernel/textbuffer.h +++ b/kernel/include/sortix/kernel/textbuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen. + * Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -76,22 +76,24 @@ class TextBuffer { public: virtual ~TextBuffer() { } - virtual size_t Width() const = 0; - virtual size_t Height() const = 0; - virtual TextChar GetChar(TextPos pos) const = 0; + virtual size_t Width() = 0; + virtual size_t Height() = 0; + virtual TextChar GetChar(TextPos pos) = 0; virtual void SetChar(TextPos pos, TextChar c) = 0; virtual void Scroll(ssize_t off, TextChar fillwith) = 0; virtual void Move(TextPos to, TextPos from, size_t numchars) = 0; virtual void Fill(TextPos from, TextPos to, TextChar fillwith) = 0; - virtual bool GetCursorEnabled() const = 0; + virtual bool GetCursorEnabled() = 0; virtual void SetCursorEnabled(bool enablecursor) = 0; - virtual TextPos GetCursorPos() const = 0; + virtual TextPos GetCursorPos() = 0; virtual void SetCursorPos(TextPos cursorpos) = 0; virtual void SpawnThreads() = 0; virtual void Invalidate() = 0; virtual bool EmergencyIsImpaired() = 0; virtual bool EmergencyRecoup() = 0; virtual void EmergencyReset() = 0; + virtual void Resume() = 0; + virtual void Pause() = 0; }; @@ -107,7 +109,9 @@ public: ~TextBufferHandle(); TextBuffer* Acquire(); void Release(TextBuffer* textbuf); - void Replace(TextBuffer* newtextbuf); + void BeginReplace(); + void CancelReplace(); + void FinishReplace(TextBuffer* newtextbuf); bool EmergencyIsImpaired(); bool EmergencyRecoup(); void EmergencyReset(); diff --git a/kernel/include/sortix/kernel/video.h b/kernel/include/sortix/kernel/video.h index 563de3d0..2df5b062 100644 --- a/kernel/include/sortix/kernel/video.h +++ b/kernel/include/sortix/kernel/video.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, 2015 Jonas 'Sortie' Termansen. + * Copyright (c) 2012, 2014, 2015, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -36,14 +36,19 @@ class VideoDevice { public: virtual ~VideoDevice() { } - virtual struct dispmsg_crtc_mode GetCurrentMode(uint64_t connector) const = 0; + virtual uint64_t GetConnectorCount() = 0; + virtual bool GetDefaultMode(uint64_t connector, struct dispmsg_crtc_mode* mode) = 0; + virtual bool GetCurrentMode(uint64_t connector, struct dispmsg_crtc_mode* mode) = 0; virtual bool SwitchMode(uint64_t connector, struct dispmsg_crtc_mode mode) = 0; - virtual bool Supports(uint64_t connector, struct dispmsg_crtc_mode mode) const = 0; - virtual struct dispmsg_crtc_mode* GetModes(uint64_t connector, size_t* nummodes) const = 0; - virtual off_t FrameSize() const = 0; + virtual bool Supports(uint64_t connector, struct dispmsg_crtc_mode mode) = 0; + virtual struct dispmsg_crtc_mode* GetModes(uint64_t connector, size_t* nummodes) = 0; + virtual off_t FrameSize() = 0; virtual ssize_t WriteAt(ioctx_t* ctx, off_t off, const void* buf, size_t count) = 0; virtual ssize_t ReadAt(ioctx_t* ctx, off_t off, void* buf, size_t count) = 0; - virtual TextBuffer* CreateTextBuffer(uint64_t connector) = 0; + virtual TextBuffer* CreateTextBuffer(uint64_t connector, struct dispmsg_crtc_mode mode) = 0; + +public: + uint64_t device_index; }; @@ -53,6 +58,9 @@ namespace Sortix { namespace Video { bool RegisterDevice(const char* name, VideoDevice* device); +bool ConfigureDevice(VideoDevice* device); +bool ResizeDisplay(uint64_t device, uint64_t connector, uint32_t xres, + uint32_t yres, uint32_t bpp); } // namespace Video } // namespace Sortix diff --git a/kernel/lfbtextbuffer.cpp b/kernel/lfbtextbuffer.cpp index 1d2ba6da..3a1dc008 100644 --- a/kernel/lfbtextbuffer.cpp +++ b/kernel/lfbtextbuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen. + * Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -105,10 +105,10 @@ LFBTextBuffer* CreateLFBTextBuffer(uint8_t* lfb, uint32_t lfbformat, } ret->cursorenabled = true; ret->cursorpos = TextPos(0, 0); - for ( size_t y = 0; y < yres; y++ ) - memset(lfb + scansize * y, 0, ret->bytes_per_pixel * xres); ret->emergency_state = false; ret->invalidated = false; + ret->need_clear = true; + ret->exit_after_pause = false; if ( !kernel_process ) return ret; @@ -149,10 +149,21 @@ LFBTextBuffer::~LFBTextBuffer() { if ( queue_thread ) { - TextBufferCmd cmd; - cmd.type = TEXTBUFCMD_EXIT; - IssueCommand(&cmd); kthread_mutex_lock(&queue_lock); + if ( queue_is_paused ) + { + queue_is_paused = false; + exit_after_pause = true; + kthread_cond_signal(&queue_resume); + } + else + { + TextBufferCmd cmd; + cmd.type = TEXTBUFCMD_EXIT; + kthread_mutex_unlock(&queue_lock); + IssueCommand(&cmd); + kthread_mutex_lock(&queue_lock); + } while ( queue_thread ) kthread_cond_wait(&queue_exit, &queue_lock); kthread_mutex_unlock(&queue_lock); @@ -163,12 +174,12 @@ LFBTextBuffer::~LFBTextBuffer() delete[] queue; } -size_t LFBTextBuffer::Width() const +size_t LFBTextBuffer::Width() { return columns; } -size_t LFBTextBuffer::Height() const +size_t LFBTextBuffer::Height() { return rows; } @@ -363,16 +374,17 @@ void LFBTextBuffer::IssueCommand(TextBufferCmd* cmd) queue[(queue_offset + queue_used++) % queue_length] = *cmd; } -void LFBTextBuffer::StopRendering() +bool LFBTextBuffer::StopRendering() { if ( !queue_thread || emergency_state ) - return; + return false; TextBufferCmd cmd; cmd.type = TEXTBUFCMD_PAUSE; IssueCommand(&cmd); ScopedLock lock(&queue_lock); while ( !queue_is_paused ) kthread_cond_wait(&queue_paused, &queue_lock); + return true; } void LFBTextBuffer::ResumeRendering() @@ -380,17 +392,20 @@ void LFBTextBuffer::ResumeRendering() if ( !queue_thread || emergency_state ) return; ScopedLock lock(&queue_lock); + if ( !queue_is_paused ) + return; queue_is_paused = false; kthread_cond_signal(&queue_resume); } -TextChar LFBTextBuffer::GetChar(TextPos pos) const +TextChar LFBTextBuffer::GetChar(TextPos pos) { if ( UsablePosition(pos) ) { - ((LFBTextBuffer*) this)->StopRendering(); + bool was_rendering = StopRendering(); TextChar ret = chars[pos.y * columns + pos.x]; - ((LFBTextBuffer*) this)->ResumeRendering(); + if ( was_rendering ) + ResumeRendering(); return ret; } return {0, 0, 0}; @@ -408,11 +423,12 @@ void LFBTextBuffer::SetChar(TextPos pos, TextChar c) IssueCommand(&cmd); } -bool LFBTextBuffer::GetCursorEnabled() const +bool LFBTextBuffer::GetCursorEnabled() { - ((LFBTextBuffer*) this)->StopRendering(); + bool was_rendering = StopRendering(); bool ret = cursorenabled; - ((LFBTextBuffer*) this)->ResumeRendering(); + if ( was_rendering ) + ResumeRendering(); return ret; } @@ -424,11 +440,12 @@ void LFBTextBuffer::SetCursorEnabled(bool enablecursor) IssueCommand(&cmd); } -TextPos LFBTextBuffer::GetCursorPos() const +TextPos LFBTextBuffer::GetCursorPos() { - ((LFBTextBuffer*) this)->StopRendering(); + bool was_rendering = StopRendering(); TextPos ret = cursorpos; - ((LFBTextBuffer*) this)->ResumeRendering(); + if ( was_rendering ) + ResumeRendering(); return ret; } @@ -675,6 +692,13 @@ void LFBTextBuffer::RenderThread() while ( queue_is_paused ) kthread_cond_wait(&queue_resume, &queue_lock); pause_requested = false; + if ( exit_after_pause ) + { + queue_thread = false; + kthread_cond_signal(&queue_exit); + kthread_mutex_unlock(&queue_lock); + return; + } } } @@ -761,4 +785,20 @@ void LFBTextBuffer::EmergencyReset() SetCursorPos(TextPos{0, 0}); } +void LFBTextBuffer::Resume() +{ + if ( need_clear ) + { + for ( size_t y = 0; y < pixelsy; y++ ) + memset(lfb + scansize * y, 0, bytes_per_pixel * pixelsx); + need_clear = false; + } + ResumeRendering(); +} + +void LFBTextBuffer::Pause() +{ + StopRendering(); +} + } // namespace Sortix diff --git a/kernel/lfbtextbuffer.h b/kernel/lfbtextbuffer.h index ecd54646..49732ed5 100644 --- a/kernel/lfbtextbuffer.h +++ b/kernel/lfbtextbuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen. + * Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -64,22 +64,24 @@ private: public: virtual ~LFBTextBuffer(); - virtual size_t Width() const; - virtual size_t Height() const; - virtual TextChar GetChar(TextPos pos) const; + virtual size_t Width(); + virtual size_t Height(); + virtual TextChar GetChar(TextPos pos); virtual void SetChar(TextPos pos, TextChar c); virtual void Scroll(ssize_t off, TextChar fillwith); virtual void Move(TextPos to, TextPos from, size_t numchars); virtual void Fill(TextPos from, TextPos to, TextChar fillwith); - virtual bool GetCursorEnabled() const; + virtual bool GetCursorEnabled(); virtual void SetCursorEnabled(bool enablecursor); - virtual TextPos GetCursorPos() const; + virtual TextPos GetCursorPos(); virtual void SetCursorPos(TextPos newcursorpos); virtual void SpawnThreads(); virtual void Invalidate(); virtual bool EmergencyIsImpaired(); virtual bool EmergencyRecoup(); virtual void EmergencyReset(); + virtual void Resume(); + virtual void Pause(); public: virtual void RenderThread(); @@ -97,7 +99,7 @@ private: void DoMove(TextPos to, TextPos from, size_t numchars); void DoFill(TextPos from, TextPos to, TextChar fillwith); void IssueCommand(TextBufferCmd* cmd); - void StopRendering(); + bool StopRendering(); void ResumeRendering(); bool IsCommandIdempotent(const TextBufferCmd* cmd) const; void ExecuteCommand(TextBufferCmd* cmd, @@ -138,6 +140,8 @@ private: TextPos cursorpos; bool emergency_state; bool invalidated; + bool need_clear; + bool exit_after_pause; size_t execute_amount; }; diff --git a/kernel/log.cpp b/kernel/log.cpp index 483c0a76..7ee575f1 100644 --- a/kernel/log.cpp +++ b/kernel/log.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen. + * Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -246,5 +246,20 @@ void Center(const char* string) } } +void BeginReplace() +{ + ((TextTerminal*) Log::device_pointer)->BeginReplace(); +} + +void CancelReplace() +{ + ((TextTerminal*) Log::device_pointer)->CancelReplace(); +} + +void FinishReplace(TextBuffer* textbuf) +{ + ((TextTerminal*) Log::device_pointer)->FinishReplace(textbuf); +} + } // namespace Log } // namespace Sortix diff --git a/kernel/textbuffer.cpp b/kernel/textbuffer.cpp index 27f3b505..729e99dd 100644 --- a/kernel/textbuffer.cpp +++ b/kernel/textbuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 2015 Jonas 'Sortie' Termansen. + * Copyright (c) 2012, 2013, 2015, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -94,13 +94,77 @@ void TextBufferHandle::EmergencyRelease(TextBuffer* textbuf) (void) textbuf; } -void TextBufferHandle::Replace(TextBuffer* newtextbuf) +void TextBufferHandle::BeginReplace() { - ScopedLock lock(&mutex); + kthread_mutex_lock(&mutex); while ( 0 < numused ) kthread_cond_wait(&unusedcond, &mutex); + if ( textbuf ) + textbuf->Pause(); +} + +void TextBufferHandle::CancelReplace() +{ + if ( textbuf ) + textbuf->Resume(); + kthread_mutex_unlock(&mutex); +} + +void TextBufferHandle::FinishReplace(TextBuffer* newtextbuf) +{ + // TODO: This shouldn't redraw when a graphical app is in control of the + // screen. Might even leak information from the console. + newtextbuf->Resume(); + if ( textbuf ) + { + size_t src_width = textbuf->Width(); + size_t src_height = textbuf->Height(); + size_t dst_width = newtextbuf->Width(); + size_t dst_height = newtextbuf->Height(); + bool cursor_enabled = textbuf->GetCursorEnabled(); + TextPos src_cursor = textbuf->GetCursorPos(); + size_t src_y_after_cursor = src_height ? src_cursor.y + 1 : 0; + size_t src_y_count = dst_height < src_y_after_cursor ? dst_height : src_y_after_cursor; + size_t src_y_from = src_y_after_cursor - src_y_count; + TextPos dst_cursor = src_cursor; + dst_cursor.y += src_y_from; + newtextbuf->SetCursorEnabled(false); + for ( size_t dst_y = 0; dst_y < dst_height; dst_y++ ) + { + // TODO: Ability to center the boot cat. + size_t src_y = src_y_from + dst_y; + for ( size_t dst_x = 0; dst_x < dst_width; dst_x++ ) + { + size_t src_x = dst_x; + TextPos src_pos{src_x, src_y}; + TextPos dst_pos{dst_x, dst_y}; + TextChar tc{0, 0, 0}; + if ( src_x < src_width && src_y < src_height ) + tc = textbuf->GetChar(src_pos); + else if ( src_width && src_height ) + { + TextPos templ_pos; + templ_pos.x = src_y < src_width ? src_y : src_x- 1; + templ_pos.y = src_y < src_height ? src_y : src_height - 1; + tc = textbuf->GetChar(templ_pos); + tc.c = 0; + tc.attr = 0; + } + newtextbuf->SetChar(dst_pos, tc); + if ( src_x == src_cursor.x && src_y == src_cursor.y ) + dst_cursor = dst_pos; + } + } + if ( dst_width <= dst_cursor.x ) + dst_cursor.x = dst_width ? dst_cursor.x - 1 : 0; + if ( dst_height <= dst_cursor.y ) + dst_cursor.y = dst_height ? dst_cursor.y - 1 : 0; + newtextbuf->SetCursorPos(dst_cursor); + newtextbuf->SetCursorEnabled(cursor_enabled); + } delete textbuf; textbuf = newtextbuf; + kthread_mutex_unlock(&mutex); } } // namespace Sortix diff --git a/kernel/textterminal.cpp b/kernel/textterminal.cpp index 9477f073..b5e36236 100644 --- a/kernel/textterminal.cpp +++ b/kernel/textterminal.cpp @@ -133,6 +133,32 @@ bool TextTerminal::Invalidate() return true; } +void TextTerminal::BeginReplace() +{ + kthread_mutex_lock(&termlock); + textbufhandle->BeginReplace(); +} + +void TextTerminal::CancelReplace() +{ + textbufhandle->CancelReplace(); + kthread_mutex_unlock(&termlock); +} + +void TextTerminal::FinishReplace(TextBuffer* new_textbuf) +{ + textbufhandle->FinishReplace(new_textbuf); + TextBuffer* textbuf = textbufhandle->Acquire(); + size_t new_width = textbuf->Width(); + size_t new_height = textbuf->Height(); + textbufhandle->Release(textbuf); + if ( new_width < column ) + column = new_width; + if ( new_height <= line ) + line = new_height ? new_height - 1 : 0; + kthread_mutex_unlock(&termlock); +} + bool TextTerminal::EmergencyIsImpaired() { // This is during a kernel emergency where preemption has been disabled and diff --git a/kernel/textterminal.h b/kernel/textterminal.h index 4e3ca014..f3badfcd 100644 --- a/kernel/textterminal.h +++ b/kernel/textterminal.h @@ -41,6 +41,9 @@ public: void GetCursor(size_t* column, size_t* row) const; bool Sync(); bool Invalidate(); + void BeginReplace(); + void CancelReplace(); + void FinishReplace(TextBuffer* textbuf); bool EmergencyIsImpaired(); bool EmergencyRecoup(); void EmergencyReset(); diff --git a/kernel/vgatextbuffer.cpp b/kernel/vgatextbuffer.cpp index 08824fa9..416b9c5d 100644 --- a/kernel/vgatextbuffer.cpp +++ b/kernel/vgatextbuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen. + * Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -74,17 +74,17 @@ size_t VGATextBuffer::OffsetOfPos(TextPos pos) const return pos.y * width + pos.x; } -size_t VGATextBuffer::Width() const +size_t VGATextBuffer::Width() { return width; } -size_t VGATextBuffer::Height() const +size_t VGATextBuffer::Height() { return height; } -TextChar VGATextBuffer::GetChar(TextPos pos) const +TextChar VGATextBuffer::GetChar(TextPos pos) { if ( UsablePosition(pos) ) return chars[OffsetOfPos(pos)]; @@ -153,7 +153,7 @@ void VGATextBuffer::Fill(TextPos from, TextPos to, TextChar fillwith) } } -bool VGATextBuffer::GetCursorEnabled() const +bool VGATextBuffer::GetCursorEnabled() { return cursorenabled; } @@ -164,7 +164,7 @@ void VGATextBuffer::SetCursorEnabled(bool enablecursor) UpdateCursor(); } -TextPos VGATextBuffer::GetCursorPos() const +TextPos VGATextBuffer::GetCursorPos() { return cursorpos; } @@ -207,4 +207,13 @@ void VGATextBuffer::EmergencyReset() SetCursorPos(TextPos{0, 0}); } +void VGATextBuffer::Resume() +{ + UpdateCursor(); +} + +void VGATextBuffer::Pause() +{ +} + } // namespace Sortix diff --git a/kernel/vgatextbuffer.h b/kernel/vgatextbuffer.h index 55a0e434..0f48fea6 100644 --- a/kernel/vgatextbuffer.h +++ b/kernel/vgatextbuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen. + * Copyright (c) 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -29,22 +29,24 @@ class VGATextBuffer : public TextBuffer public: VGATextBuffer(uint16_t* vga, TextChar* chars, size_t width, size_t height); virtual ~VGATextBuffer(); - virtual size_t Width() const; - virtual size_t Height() const; - virtual TextChar GetChar(TextPos pos) const; + virtual size_t Width(); + virtual size_t Height(); + virtual TextChar GetChar(TextPos pos); virtual void SetChar(TextPos pos, TextChar c); virtual void Scroll(ssize_t off, TextChar fillwith); virtual void Move(TextPos to, TextPos from, size_t numchars); virtual void Fill(TextPos from, TextPos to, TextChar fillwith); - virtual bool GetCursorEnabled() const; + virtual bool GetCursorEnabled(); virtual void SetCursorEnabled(bool enablecursor); - virtual TextPos GetCursorPos() const; + virtual TextPos GetCursorPos(); virtual void SetCursorPos(TextPos cursorpos); virtual void SpawnThreads(); virtual void Invalidate(); virtual bool EmergencyIsImpaired(); virtual bool EmergencyRecoup(); virtual void EmergencyReset(); + virtual void Resume(); + virtual void Pause(); private: bool UsablePosition(TextPos pos) const; diff --git a/kernel/video.cpp b/kernel/video.cpp index a2bcca56..6a9d843b 100644 --- a/kernel/video.cpp +++ b/kernel/video.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, 2015 Jonas 'Sortie' Termansen. + * Copyright (c) 2012, 2014, 2015, 2016 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -33,10 +33,10 @@ namespace Sortix { namespace Video { -const uint64_t ONE_AND_ONLY_DEVICE = 0; -const uint64_t ONE_AND_ONLY_CONNECTOR = 0; +static const uint64_t CONSOLE_DEVICE = 0; +static const uint64_t CONSOLE_CONNECTOR = 0; -kthread_mutex_t video_lock = KTHREAD_MUTEX_INITIALIZER; +static kthread_mutex_t video_lock = KTHREAD_MUTEX_INITIALIZER; struct DeviceEntry { @@ -44,9 +44,9 @@ struct DeviceEntry VideoDevice* device; }; -size_t num_devices = 0; -size_t devices_length = 0; -DeviceEntry* devices = NULL; +static size_t num_devices = 0; +static size_t devices_length = 0; +static DeviceEntry* devices = NULL; bool RegisterDevice(const char* name, VideoDevice* device) { @@ -73,9 +73,89 @@ bool RegisterDevice(const char* name, VideoDevice* device) size_t index = num_devices++; devices[index].name = drivername; devices[index].device = device; + device->device_index = index; return true; } +static bool SetVideoMode(VideoDevice* device, + uint64_t connector, + struct dispmsg_crtc_mode mode) +{ + uint64_t device_index = device->device_index; + TextBuffer* textbuf = NULL; + if ( device_index == CONSOLE_DEVICE && connector == CONSOLE_CONNECTOR ) + { + if ( !(textbuf = device->CreateTextBuffer(connector, mode)) ) + return false; + Log::BeginReplace(); + } + if ( !device->SwitchMode(connector, mode) ) + { + if ( textbuf ) + { + Log::CancelReplace(); + delete textbuf; + } + return false; + } + if ( textbuf ) + { + Log::FinishReplace(textbuf); + Log::fallback_framebuffer = NULL; + } + return true; +} + +bool ConfigureDevice(VideoDevice* device) +{ + bool success = true; + ScopedLock lock(&video_lock); + uint64_t connectors_count = device->GetConnectorCount(); + for ( uint64_t connector = 0; connector < connectors_count; connector++ ) + { + struct dispmsg_crtc_mode mode; + if ( !device->GetDefaultMode(connector, &mode) || + !SetVideoMode(device, connector, mode) ) + success = false; + } + return success; +} + +bool ResizeDisplay(uint64_t device_index, uint64_t connector, uint32_t xres, + uint32_t yres, uint32_t bpp) +{ + ScopedLock lock(&video_lock); + + if ( num_devices <= device_index ) + return errno = ENODEV, false; + + DeviceEntry* device_entry = &devices[device_index]; + VideoDevice* device = device_entry->device; + + // TODO: xres/yres/bpp == 0 means unchanged, so get current mode. + if ( xres == 0 || yres == 0 || bpp == 0 ) + return true; + struct dispmsg_crtc_mode mode; + memset(&mode, 0, sizeof(0)); + mode.driver_index = 0; + mode.magic = 0; + mode.control = DISPMSG_CONTROL_VALID; + mode.fb_format = bpp; + mode.view_xres = xres; + mode.view_yres = yres; + mode.fb_location = 0; + mode.pitch = xres * (bpp + 7) / 8; + mode.surf_off_x = 0; + mode.surf_off_y = 0; + mode.start_x = 0; + mode.start_y = 0; + mode.end_x = 0; + mode.end_y = 0; + mode.desktop_height = yres; + + return SetVideoMode(device, connector, mode); +} + __attribute__((unused)) static bool TransmitString(struct dispmsg_string* dest, const char* str) { @@ -246,19 +326,13 @@ static int SetCrtcMode(void* ptr, size_t size) { DeviceEntry* device_entry = &devices[msg.device]; VideoDevice* device = device_entry->device; - if ( !device->SwitchMode(msg.connector, msg.mode) ) + + if ( !SetVideoMode(device, msg.connector, msg.mode) ) return -1; - // TODO: This could potentially fail. - if ( msg.device == ONE_AND_ONLY_DEVICE && - msg.connector == ONE_AND_ONLY_CONNECTOR ) - { - Log::fallback_framebuffer = NULL; - Log::device_textbufhandle->Replace(device->CreateTextBuffer(msg.connector)); - } } else if ( Log::fallback_framebuffer && - msg.device == ONE_AND_ONLY_DEVICE && - msg.connector == ONE_AND_ONLY_CONNECTOR ) + msg.device == CONSOLE_DEVICE && + msg.connector == CONSOLE_CONNECTOR ) { struct dispmsg_crtc_mode fallback_mode = GetLogFallbackMode(); if ( memcmp(&msg.mode, &fallback_mode, sizeof(msg.mode)) != 0 ) @@ -286,8 +360,8 @@ static int GetCrtcMode(void* ptr, size_t size) struct dispmsg_crtc_mode mode; if ( Log::fallback_framebuffer && - msg.device == ONE_AND_ONLY_DEVICE && - msg.connector == ONE_AND_ONLY_CONNECTOR ) + msg.device == CONSOLE_DEVICE && + msg.connector == CONSOLE_CONNECTOR ) { mode = GetLogFallbackMode(); } @@ -295,10 +369,7 @@ static int GetCrtcMode(void* ptr, size_t size) { DeviceEntry* device_entry = &devices[msg.device]; VideoDevice* device = device_entry->device; - // TODO: There is no real way to detect failure here. - errno = 0; - mode = device->GetCurrentMode(msg.connector); - if ( !(mode.control & DISPMSG_CONTROL_VALID) && errno != 0 ) + if ( !device->GetCurrentMode(msg.connector, &mode) ) return -1; } else @@ -335,8 +406,8 @@ static int GetCrtcModes(void* ptr, size_t size) return -1; } else if ( Log::fallback_framebuffer && - msg.device == ONE_AND_ONLY_DEVICE && - msg.connector == ONE_AND_ONLY_CONNECTOR ) + msg.device == CONSOLE_DEVICE && + msg.connector == CONSOLE_CONNECTOR ) { if ( !(modes = new struct dispmsg_crtc_mode[1]) ) return -1; @@ -384,7 +455,7 @@ static int GetMemorySize(void* ptr, size_t size) ScopedLock lock(&video_lock); if ( Log::fallback_framebuffer && - msg.device == ONE_AND_ONLY_DEVICE ) + msg.device == CONSOLE_DEVICE ) { msg.memory_size = Log::fallback_framebuffer_width * Log::fallback_framebuffer_height * @@ -423,7 +494,7 @@ static int WriteMemory(void* ptr, size_t size) ScopedLock lock(&video_lock); if ( Log::fallback_framebuffer && - msg.device == ONE_AND_ONLY_DEVICE ) + msg.device == CONSOLE_DEVICE ) { size_t ideal_pitch = Log::fallback_framebuffer_width * Log::fallback_framebuffer_bpp / 8; @@ -493,7 +564,7 @@ static int ReadMemory(void* ptr, size_t size) ScopedLock lock(&video_lock); if ( Log::fallback_framebuffer && - msg.device == ONE_AND_ONLY_DEVICE ) + msg.device == CONSOLE_DEVICE ) { size_t ideal_pitch = Log::fallback_framebuffer_width * Log::fallback_framebuffer_bpp / 8; diff --git a/sysinstall/sysinstall.c b/sysinstall/sysinstall.c index cf719b77..f019f768 100644 --- a/sysinstall/sysinstall.c +++ b/sysinstall/sysinstall.c @@ -544,10 +544,28 @@ int main(void) (dgdn.device = display.device, true) && (dispmsg_issue(&dgdn, sizeof(dgdn)) == 0 || errno != ENODEV) ) { + struct dispmsg_get_crtc_mode get_mode; + memset(&get_mode, 0, sizeof(get_mode)); + get_mode.msgid = DISPMSG_GET_CRTC_MODE; + get_mode.device = 0; + get_mode.connector = 0; + bool good = false; + if ( dispmsg_issue(&get_mode, sizeof(get_mode)) == 0 ) + { + good = (get_mode.mode.control & DISPMSG_CONTROL_VALID) && + (get_mode.mode.control & DISPMSG_CONTROL_GOOD_DEFAULT); + if ( get_mode.mode.control & DISPMSG_CONTROL_VM_AUTO_SCALE ) + { + text("The display resolution will automatically change to " + "match the size of the virtual machine window.\n\n"); + good = true; + } + } + const char* def = good ? "no" : "yes"; while ( true ) { prompt(input, sizeof(input), - "Select a default display resolution? (yes/no)", "yes"); + "Select a default display resolution? (yes/no)", def); if ( strcasecmp(input, "no") && strcasecmp(input, "yes") ) continue; bool was_no = strcasecmp(input, "no") == 0; @@ -556,10 +574,6 @@ int main(void) break; if ( execute((const char*[]) { "chvideomode", NULL }, "f") != 0 ) continue; - struct dispmsg_get_crtc_mode get_mode; - get_mode.msgid = DISPMSG_GET_CRTC_MODE; - get_mode.device = 0; - get_mode.connector = 0; if ( dispmsg_issue(&get_mode, sizeof(get_mode)) < 0 ) break; if ( !(get_mode.mode.control & DISPMSG_CONTROL_VALID) ) diff --git a/sysinstall/sysupgrade.c b/sysinstall/sysupgrade.c index ac9d5d5c..561293c0 100644 --- a/sysinstall/sysupgrade.c +++ b/sysinstall/sysupgrade.c @@ -439,10 +439,28 @@ int main(void) (dgdn.device = display.device, true) && (dispmsg_issue(&dgdn, sizeof(dgdn)) == 0 || errno != ENODEV) ) { + struct dispmsg_get_crtc_mode get_mode; + memset(&get_mode, 0, sizeof(get_mode)); + get_mode.msgid = DISPMSG_GET_CRTC_MODE; + get_mode.device = 0; + get_mode.connector = 0; + bool good = false; + if ( dispmsg_issue(&get_mode, sizeof(get_mode)) == 0 ) + { + good = (get_mode.mode.control & DISPMSG_CONTROL_VALID) && + (get_mode.mode.control & DISPMSG_CONTROL_GOOD_DEFAULT); + if ( get_mode.mode.control & DISPMSG_CONTROL_VM_AUTO_SCALE ) + { + text("The display resolution will automatically change to " + "match the size of the virtual machine window.\n\n"); + good = true; + } + } + const char* def = good ? "no" : "yes"; while ( true ) { prompt(input, sizeof(input), - "Select display resolution? (yes/no)", "yes"); + "Select display resolution? (yes/no)", def); if ( strcasecmp(input, "no") && strcasecmp(input, "yes") ) continue; if ( strcasecmp(input, "no") == 0 )