Refactor graphical resolution changes.

This commit is contained in:
Jonas 'Sortie' Termansen 2016-09-03 23:46:10 +02:00
parent 0342e03073
commit e7c5d032d1
16 changed files with 481 additions and 126 deletions

View File

@ -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 <sortix/kernel/textbuffer.h>
#include <sortix/kernel/video.h>
#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()

View File

@ -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
{

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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) )

View File

@ -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 )