mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Queue lfb text render commands with async render.
This commit is contained in:
parent
ad0875aaac
commit
ca7ad9709f
2 changed files with 394 additions and 55 deletions
|
@ -48,28 +48,56 @@ static uint32_t ColorFromRGB(uint8_t r, uint8_t g, uint8_t b)
|
||||||
return ret.color;
|
return ret.color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void LFBTextBuffer__RenderThread(void* user)
|
||||||
|
{
|
||||||
|
((LFBTextBuffer*) user)->RenderThread();
|
||||||
|
}
|
||||||
|
|
||||||
LFBTextBuffer* CreateLFBTextBuffer(uint8_t* lfb, uint32_t lfbformat,
|
LFBTextBuffer* CreateLFBTextBuffer(uint8_t* lfb, uint32_t lfbformat,
|
||||||
size_t xres, size_t yres, size_t scansize)
|
size_t xres, size_t yres, size_t scansize)
|
||||||
{
|
{
|
||||||
|
const size_t QUEUE_LENGTH = 1024;
|
||||||
size_t columns = xres / (VGA_FONT_WIDTH + 1);
|
size_t columns = xres / (VGA_FONT_WIDTH + 1);
|
||||||
size_t rows = yres / VGA_FONT_HEIGHT;
|
size_t rows = yres / VGA_FONT_HEIGHT;
|
||||||
size_t fontsize = VGA_FONT_CHARSIZE * VGA_FONT_NUMCHARS;
|
size_t fontsize = VGA_FONT_CHARSIZE * VGA_FONT_NUMCHARS;
|
||||||
|
uint8_t* backbuf;
|
||||||
uint8_t* font;
|
uint8_t* font;
|
||||||
uint16_t* chars;
|
uint16_t* chars;
|
||||||
uint16_t* attrs;
|
uint16_t* attrs;
|
||||||
|
TextBufferCmd* queue;
|
||||||
LFBTextBuffer* ret;
|
LFBTextBuffer* ret;
|
||||||
|
|
||||||
if ( !(font = new uint8_t[fontsize]) )
|
Process* kernel_process = Scheduler::GetKernelProcess();
|
||||||
|
|
||||||
|
if ( !(backbuf = new uint8_t[yres * scansize]) )
|
||||||
goto cleanup_done;
|
goto cleanup_done;
|
||||||
|
if ( !(font = new uint8_t[fontsize]) )
|
||||||
|
goto cleanup_backbuf;
|
||||||
if ( !(chars = new uint16_t[columns * rows]) )
|
if ( !(chars = new uint16_t[columns * rows]) )
|
||||||
goto cleanup_font;
|
goto cleanup_font;
|
||||||
if ( !(attrs = new uint16_t[columns * rows]) )
|
if ( !(attrs = new uint16_t[columns * rows]) )
|
||||||
goto cleanup_chars;
|
goto cleanup_chars;
|
||||||
if ( !(ret = new LFBTextBuffer) )
|
if ( !(queue = new TextBufferCmd[QUEUE_LENGTH]) )
|
||||||
goto cleanup_attrs;
|
goto cleanup_attrs;
|
||||||
|
if ( !(ret = new LFBTextBuffer) )
|
||||||
|
goto cleanup_queue;
|
||||||
|
|
||||||
memcpy(font, VGA::GetFont(), fontsize);
|
memcpy(font, VGA::GetFont(), fontsize);
|
||||||
|
ret->queue_lock = KTHREAD_MUTEX_INITIALIZER;
|
||||||
|
ret->queue_not_full = KTHREAD_COND_INITIALIZER;
|
||||||
|
ret->queue_not_empty = KTHREAD_COND_INITIALIZER;
|
||||||
|
ret->queue_exit = KTHREAD_COND_INITIALIZER;
|
||||||
|
ret->queue_sync = KTHREAD_COND_INITIALIZER;
|
||||||
|
ret->queue_paused = KTHREAD_COND_INITIALIZER;
|
||||||
|
ret->queue_resume = KTHREAD_COND_INITIALIZER;
|
||||||
|
ret->queue = queue;
|
||||||
|
ret->queue_length = QUEUE_LENGTH;
|
||||||
|
ret->queue_offset = 0;
|
||||||
|
ret->queue_used = 0;
|
||||||
|
ret->queue_is_paused = false;
|
||||||
|
ret->queue_thread = false;
|
||||||
ret->lfb = lfb;
|
ret->lfb = lfb;
|
||||||
|
ret->backbuf = backbuf;
|
||||||
ret->lfbformat = lfbformat;
|
ret->lfbformat = lfbformat;
|
||||||
ret->pixelsx = xres;
|
ret->pixelsx = xres;
|
||||||
ret->pixelsy = yres;
|
ret->pixelsy = yres;
|
||||||
|
@ -92,14 +120,25 @@ LFBTextBuffer* CreateLFBTextBuffer(uint8_t* lfb, uint32_t lfbformat,
|
||||||
ret->cursorpos = TextPos(0, 0);
|
ret->cursorpos = TextPos(0, 0);
|
||||||
for ( size_t y = 0; y < yres; y++ )
|
for ( size_t y = 0; y < yres; y++ )
|
||||||
memset(lfb + scansize * y, 0, lfbformat/8UL * xres);
|
memset(lfb + scansize * y, 0, lfbformat/8UL * xres);
|
||||||
|
|
||||||
|
if ( !RunKernelThread(kernel_process, LFBTextBuffer__RenderThread, ret) )
|
||||||
|
{
|
||||||
|
delete ret;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
cleanup_queue:
|
||||||
|
delete[] queue;
|
||||||
cleanup_attrs:
|
cleanup_attrs:
|
||||||
delete[] attrs;
|
delete[] attrs;
|
||||||
cleanup_chars:
|
cleanup_chars:
|
||||||
delete[] chars;
|
delete[] chars;
|
||||||
cleanup_font:
|
cleanup_font:
|
||||||
delete[] font;
|
delete[] font;
|
||||||
|
cleanup_backbuf:
|
||||||
|
delete[] backbuf;
|
||||||
cleanup_done:
|
cleanup_done:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -125,9 +164,21 @@ LFBTextBuffer::LFBTextBuffer()
|
||||||
|
|
||||||
LFBTextBuffer::~LFBTextBuffer()
|
LFBTextBuffer::~LFBTextBuffer()
|
||||||
{
|
{
|
||||||
|
kthread_mutex_lock(&queue_lock);
|
||||||
|
if ( queue_thread )
|
||||||
|
{
|
||||||
|
TextBufferCmd cmd;
|
||||||
|
cmd.type = TEXTBUFCMD_EXIT;
|
||||||
|
IssueCommand(&cmd);
|
||||||
|
while ( queue_thread )
|
||||||
|
kthread_cond_wait(&queue_exit, &queue_lock);
|
||||||
|
}
|
||||||
|
kthread_mutex_unlock(&queue_lock);
|
||||||
|
delete[] backbuf;
|
||||||
delete[] font;
|
delete[] font;
|
||||||
delete[] chars;
|
delete[] chars;
|
||||||
delete[] attrs;
|
delete[] attrs;
|
||||||
|
delete[] queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t LFBTextBuffer::Width() const
|
size_t LFBTextBuffer::Width() const
|
||||||
|
@ -216,19 +267,77 @@ void LFBTextBuffer::RenderRange(TextPos from, TextPos to)
|
||||||
{
|
{
|
||||||
from = CropPosition(from);
|
from = CropPosition(from);
|
||||||
to = CropPosition(to);
|
to = CropPosition(to);
|
||||||
|
#if !defined(HAS_FAST_VIDEO_MEMORY)
|
||||||
|
uint8_t* orig_lfb = lfb;
|
||||||
|
bool backbuffered = from.y != to.y;
|
||||||
|
if ( backbuffered )
|
||||||
|
{
|
||||||
|
lfb = backbuf;
|
||||||
|
from.x = 0;
|
||||||
|
to.x = columns - 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
TextPos i = from;
|
TextPos i = from;
|
||||||
RenderChar(chars[i.y * columns + i.x], i.x, i.y);
|
RenderChar(chars[i.y * columns + i.x], i.x, i.y);
|
||||||
do
|
while ( !(i.x==to.x && i.y==to.y) )
|
||||||
{
|
{
|
||||||
i = AddToPosition(i, 1);
|
i = AddToPosition(i, 1);
|
||||||
RenderChar(chars[i.y * columns + i.x], i.x, i.y);
|
RenderChar(chars[i.y * columns + i.x], i.x, i.y);
|
||||||
} while ( !(i.x==to.x && i.y==to.y) );
|
}
|
||||||
|
#if !defined(HAS_FAST_VIDEO_MEMORY)
|
||||||
|
if ( backbuffered )
|
||||||
|
{
|
||||||
|
lfb = orig_lfb;
|
||||||
|
size_t font_height = 16;
|
||||||
|
size_t font_width = 9;
|
||||||
|
size_t scanline_start = from.y * font_height;
|
||||||
|
size_t scanline_end = ((to.y+1) * font_height) - 1;
|
||||||
|
size_t linesize = font_width * sizeof(uint32_t) * columns;
|
||||||
|
for ( size_t sc = scanline_start; sc <= scanline_end; sc++ )
|
||||||
|
{
|
||||||
|
size_t offset = sc * scansize;
|
||||||
|
memcpy(lfb + offset, backbuf + offset, linesize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void LFBTextBuffer::IssueCommand(TextBufferCmd* cmd)
|
||||||
|
{
|
||||||
|
ScopedLock lock(&queue_lock);
|
||||||
|
while ( queue_used == queue_length )
|
||||||
|
kthread_cond_wait(&queue_not_full, &queue_lock);
|
||||||
|
if ( !queue_used )
|
||||||
|
kthread_cond_signal(&queue_not_empty);
|
||||||
|
queue[(queue_offset + queue_used++) % queue_length] = *cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LFBTextBuffer::StopRendering()
|
||||||
|
{
|
||||||
|
TextBufferCmd cmd;
|
||||||
|
cmd.type = TEXTBUFCMD_PAUSE;
|
||||||
|
IssueCommand(&cmd);
|
||||||
|
ScopedLock lock(&queue_lock);
|
||||||
|
while ( !queue_is_paused )
|
||||||
|
kthread_cond_wait(&queue_paused, &queue_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LFBTextBuffer::ResumeRendering()
|
||||||
|
{
|
||||||
|
ScopedLock lock(&queue_lock);
|
||||||
|
queue_is_paused = false;
|
||||||
|
kthread_cond_signal(&queue_resume);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextChar LFBTextBuffer::GetChar(TextPos pos) const
|
TextChar LFBTextBuffer::GetChar(TextPos pos) const
|
||||||
{
|
{
|
||||||
if ( UsablePosition(pos) )
|
if ( UsablePosition(pos) )
|
||||||
return EntryToTextChar(chars[pos.y * columns + pos.x]);
|
{
|
||||||
|
((LFBTextBuffer*) this)->StopRendering();
|
||||||
|
TextChar ret = EntryToTextChar(chars[pos.y * columns + pos.x]);
|
||||||
|
((LFBTextBuffer*) this)->ResumeRendering();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
return {0, 0};
|
return {0, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,47 +345,70 @@ void LFBTextBuffer::SetChar(TextPos pos, TextChar c)
|
||||||
{
|
{
|
||||||
if ( !UsablePosition(pos) )
|
if ( !UsablePosition(pos) )
|
||||||
return;
|
return;
|
||||||
chars[pos.y * columns + pos.x] = CharToTextEntry(c);
|
uint16_t entry = CharToTextEntry(c);
|
||||||
RenderRegion(pos.x, pos.y, pos.x, pos.y);
|
TextBufferCmd cmd;
|
||||||
|
cmd.type = TEXTBUFCMD_CHAR;
|
||||||
|
cmd.x = pos.x;
|
||||||
|
cmd.y = pos.y;
|
||||||
|
cmd.c = entry;
|
||||||
|
IssueCommand(&cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t LFBTextBuffer::GetCharAttr(TextPos pos) const
|
uint16_t LFBTextBuffer::GetCharAttr(TextPos pos) const
|
||||||
{
|
{
|
||||||
if ( UsablePosition(pos) )
|
if ( UsablePosition(pos) )
|
||||||
return attrs[pos.y * columns + pos.x];
|
{
|
||||||
|
((LFBTextBuffer*) this)->StopRendering();
|
||||||
|
uint16_t ret = attrs[pos.y * columns + pos.x];
|
||||||
|
((LFBTextBuffer*) this)->ResumeRendering();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LFBTextBuffer::SetCharAttr(TextPos pos, uint16_t attrval)
|
void LFBTextBuffer::SetCharAttr(TextPos pos, uint16_t attrval)
|
||||||
{
|
{
|
||||||
if ( UsablePosition(pos) )
|
if ( !UsablePosition(pos) )
|
||||||
attrs[pos.y * columns + pos.x] = attrval;
|
return;
|
||||||
|
TextBufferCmd cmd;
|
||||||
|
cmd.type = TEXTBUFCMD_ATTR;
|
||||||
|
cmd.x = pos.x;
|
||||||
|
cmd.y = pos.y;
|
||||||
|
cmd.attr = attrval;
|
||||||
|
IssueCommand(&cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LFBTextBuffer::GetCursorEnabled() const
|
bool LFBTextBuffer::GetCursorEnabled() const
|
||||||
{
|
{
|
||||||
return cursorenabled;
|
((LFBTextBuffer*) this)->StopRendering();
|
||||||
|
bool ret = cursorenabled;
|
||||||
|
((LFBTextBuffer*) this)->ResumeRendering();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LFBTextBuffer::SetCursorEnabled(bool enablecursor)
|
void LFBTextBuffer::SetCursorEnabled(bool enablecursor)
|
||||||
{
|
{
|
||||||
bool updatecursor = cursorenabled != enablecursor;
|
TextBufferCmd cmd;
|
||||||
cursorenabled = enablecursor;
|
cmd.type = TEXTBUFCMD_CURSOR_SET_ENABLED;
|
||||||
if ( updatecursor )
|
cmd.b = enablecursor;
|
||||||
RenderCharAt(cursorpos);
|
IssueCommand(&cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextPos LFBTextBuffer::GetCursorPos() const
|
TextPos LFBTextBuffer::GetCursorPos() const
|
||||||
{
|
{
|
||||||
return cursorpos;
|
((LFBTextBuffer*) this)->StopRendering();
|
||||||
|
TextPos ret = cursorpos;
|
||||||
|
((LFBTextBuffer*) this)->ResumeRendering();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LFBTextBuffer::SetCursorPos(TextPos newcursorpos)
|
void LFBTextBuffer::SetCursorPos(TextPos newcursorpos)
|
||||||
{
|
{
|
||||||
TextPos oldcursorpos = cursorpos;
|
TextBufferCmd cmd;
|
||||||
cursorpos = newcursorpos;
|
cmd.type = TEXTBUFCMD_CURSOR_MOVE;
|
||||||
RenderCharAt(oldcursorpos);
|
cmd.x = newcursorpos.x;
|
||||||
RenderCharAt(newcursorpos);
|
cmd.y = newcursorpos.y;
|
||||||
|
IssueCommand(&cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t LFBTextBuffer::OffsetOfPos(TextPos pos) const
|
size_t LFBTextBuffer::OffsetOfPos(TextPos pos) const
|
||||||
|
@ -288,6 +420,45 @@ void LFBTextBuffer::Scroll(ssize_t off, TextChar fillwith)
|
||||||
{
|
{
|
||||||
if ( !off )
|
if ( !off )
|
||||||
return;
|
return;
|
||||||
|
TextBufferCmd cmd;
|
||||||
|
cmd.type = TEXTBUFCMD_SCROLL;
|
||||||
|
cmd.scroll_offset = off;
|
||||||
|
cmd.c = CharToTextEntry(fillwith);
|
||||||
|
IssueCommand(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LFBTextBuffer::Move(TextPos to, TextPos from, size_t numchars)
|
||||||
|
{
|
||||||
|
to = CropPosition(to);
|
||||||
|
from = CropPosition(from);
|
||||||
|
TextBufferCmd cmd;
|
||||||
|
cmd.type = TEXTBUFCMD_MOVE;
|
||||||
|
cmd.to_x = to.x;
|
||||||
|
cmd.to_y = to.y;
|
||||||
|
cmd.from_x = from.x;
|
||||||
|
cmd.from_y = from.y;
|
||||||
|
cmd.val = numchars;
|
||||||
|
IssueCommand(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LFBTextBuffer::Fill(TextPos from, TextPos to, TextChar fillwith,
|
||||||
|
uint16_t fillattr)
|
||||||
|
{
|
||||||
|
from = CropPosition(from);
|
||||||
|
to = CropPosition(to);
|
||||||
|
TextBufferCmd cmd;
|
||||||
|
cmd.type = TEXTBUFCMD_FILL;
|
||||||
|
cmd.from_x = from.x;
|
||||||
|
cmd.from_y = from.y;
|
||||||
|
cmd.to_x = to.x;
|
||||||
|
cmd.to_y = to.y;
|
||||||
|
cmd.c = CharToTextEntry(fillwith);
|
||||||
|
cmd.attr = fillattr;
|
||||||
|
IssueCommand(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LFBTextBuffer::DoScroll(ssize_t off, uint16_t entry)
|
||||||
|
{
|
||||||
bool neg = 0 < off;
|
bool neg = 0 < off;
|
||||||
size_t absoff = off < 0 ? -off : off;
|
size_t absoff = off < 0 ? -off : off;
|
||||||
if ( rows < absoff )
|
if ( rows < absoff )
|
||||||
|
@ -297,14 +468,12 @@ void LFBTextBuffer::Scroll(ssize_t off, TextChar fillwith)
|
||||||
TextPos fillfrom = neg ? TextPos{0, rows-absoff} : TextPos{0, 0};
|
TextPos fillfrom = neg ? TextPos{0, rows-absoff} : TextPos{0, 0};
|
||||||
TextPos fillto = neg ? TextPos{columns-1, rows-1} : TextPos{columns-1, absoff-1};
|
TextPos fillto = neg ? TextPos{columns-1, rows-1} : TextPos{columns-1, absoff-1};
|
||||||
size_t scrollchars = columns * (rows-absoff);
|
size_t scrollchars = columns * (rows-absoff);
|
||||||
Move(scrollto, scrollfrom, scrollchars);
|
DoMove(scrollto, scrollfrom, scrollchars);
|
||||||
Fill(fillfrom, fillto, fillwith, 0);
|
DoFill(fillfrom, fillto, entry, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LFBTextBuffer::Move(TextPos to, TextPos from, size_t numchars)
|
void LFBTextBuffer::DoMove(TextPos to, TextPos from, size_t numchars)
|
||||||
{
|
{
|
||||||
to = CropPosition(to);
|
|
||||||
from = CropPosition(from);
|
|
||||||
size_t dest = OffsetOfPos(to);
|
size_t dest = OffsetOfPos(to);
|
||||||
size_t src = OffsetOfPos(from);
|
size_t src = OffsetOfPos(from);
|
||||||
if ( dest < src )
|
if ( dest < src )
|
||||||
|
@ -315,22 +484,163 @@ void LFBTextBuffer::Move(TextPos to, TextPos from, size_t numchars)
|
||||||
for ( size_t i = 0; i < numchars; i++ )
|
for ( size_t i = 0; i < numchars; i++ )
|
||||||
chars[dest + numchars-1 - i] = chars[src + numchars-1 - i],
|
chars[dest + numchars-1 - i] = chars[src + numchars-1 - i],
|
||||||
attrs[dest + numchars-1 - i] = attrs[src + numchars-1 - i];
|
attrs[dest + numchars-1 - i] = attrs[src + numchars-1 - i];
|
||||||
TextPos toend = AddToPosition(to, numchars);
|
|
||||||
RenderRange(to, toend);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LFBTextBuffer::Fill(TextPos from, TextPos to, TextChar fillwith,
|
void LFBTextBuffer::DoFill(TextPos from, TextPos to, uint16_t fillwith,
|
||||||
uint16_t fillattr)
|
uint16_t fillattr)
|
||||||
{
|
{
|
||||||
from = CropPosition(from);
|
|
||||||
to = CropPosition(to);
|
|
||||||
size_t start = OffsetOfPos(from);
|
size_t start = OffsetOfPos(from);
|
||||||
size_t end = OffsetOfPos(to);
|
size_t end = OffsetOfPos(to);
|
||||||
size_t entry = CharToTextEntry(fillwith);
|
|
||||||
for ( size_t i = start; i <= end; i++ )
|
for ( size_t i = start; i <= end; i++ )
|
||||||
chars[i] = entry,
|
chars[i] = fillwith,
|
||||||
attrs[i] = fillattr;
|
attrs[i] = fillattr;
|
||||||
RenderRange(from, to);
|
}
|
||||||
|
|
||||||
|
void LFBTextBuffer::RenderThread()
|
||||||
|
{
|
||||||
|
queue_is_paused = false;
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t amount = 0;
|
||||||
|
bool exit_requested = false;
|
||||||
|
bool sync_requested = false;
|
||||||
|
bool pause_requested = false;
|
||||||
|
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
kthread_mutex_lock(&queue_lock);
|
||||||
|
|
||||||
|
if ( queue_used == queue_length && amount )
|
||||||
|
kthread_cond_signal(&queue_not_full);
|
||||||
|
|
||||||
|
queue_used -= amount;
|
||||||
|
queue_offset = (queue_offset + amount) % queue_length;
|
||||||
|
|
||||||
|
if ( !queue_used )
|
||||||
|
{
|
||||||
|
if ( exit_requested )
|
||||||
|
{
|
||||||
|
queue_thread = false;
|
||||||
|
kthread_cond_signal(&queue_exit);
|
||||||
|
kthread_mutex_unlock(&queue_lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( sync_requested )
|
||||||
|
{
|
||||||
|
kthread_cond_signal(&queue_sync);
|
||||||
|
sync_requested = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( pause_requested )
|
||||||
|
{
|
||||||
|
queue_is_paused = true;
|
||||||
|
kthread_cond_signal(&queue_paused);
|
||||||
|
while ( queue_is_paused )
|
||||||
|
kthread_cond_wait(&queue_resume, &queue_lock);
|
||||||
|
pause_requested = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( !queue_used )
|
||||||
|
kthread_cond_wait(&queue_not_empty, &queue_lock);
|
||||||
|
|
||||||
|
amount = queue_used;
|
||||||
|
offset = queue_offset;
|
||||||
|
|
||||||
|
kthread_mutex_unlock(&queue_lock);
|
||||||
|
|
||||||
|
TextPos render_from(columns - 1, rows - 1);
|
||||||
|
TextPos render_to(0, 0);
|
||||||
|
|
||||||
|
for ( size_t i = 0; i < amount; i++ )
|
||||||
|
{
|
||||||
|
TextBufferCmd* cmd = &queue[(offset + i) % queue_length];
|
||||||
|
switch ( cmd->type )
|
||||||
|
{
|
||||||
|
case TEXTBUFCMD_EXIT:
|
||||||
|
exit_requested = true;
|
||||||
|
break;
|
||||||
|
case TEXTBUFCMD_SYNC:
|
||||||
|
sync_requested = true;
|
||||||
|
break;
|
||||||
|
case TEXTBUFCMD_PAUSE:
|
||||||
|
pause_requested = true;
|
||||||
|
break;
|
||||||
|
case TEXTBUFCMD_CHAR:
|
||||||
|
{
|
||||||
|
TextPos pos(cmd->x, cmd->y);
|
||||||
|
chars[pos.y * columns + pos.x] = cmd->c;
|
||||||
|
if ( IsTextPosBeforeTextPos(pos, render_from) )
|
||||||
|
render_from = pos;
|
||||||
|
if ( IsTextPosAfterTextPos(pos, render_to) )
|
||||||
|
render_to = pos;
|
||||||
|
} break;
|
||||||
|
case TEXTBUFCMD_ATTR:
|
||||||
|
{
|
||||||
|
TextPos pos(cmd->x, cmd->y);
|
||||||
|
attrs[pos.y * columns + pos.x] = cmd->attr;
|
||||||
|
} break;
|
||||||
|
case TEXTBUFCMD_CURSOR_SET_ENABLED:
|
||||||
|
if ( cmd->b != cursorenabled )
|
||||||
|
{
|
||||||
|
cursorenabled = cmd->b;
|
||||||
|
if ( IsTextPosBeforeTextPos(cursorpos, render_from) )
|
||||||
|
render_from = cursorpos;
|
||||||
|
if ( IsTextPosAfterTextPos(cursorpos, render_to) )
|
||||||
|
render_to = cursorpos;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TEXTBUFCMD_CURSOR_MOVE:
|
||||||
|
{
|
||||||
|
TextPos pos(cmd->x, cmd->y);
|
||||||
|
if ( cursorpos.x != pos.x || cursorpos.y != pos.y )
|
||||||
|
{
|
||||||
|
if ( IsTextPosBeforeTextPos(cursorpos, render_from) )
|
||||||
|
render_from = cursorpos;
|
||||||
|
if ( IsTextPosAfterTextPos(cursorpos, render_to) )
|
||||||
|
render_to = cursorpos;
|
||||||
|
cursorpos = pos;
|
||||||
|
if ( IsTextPosBeforeTextPos(cursorpos, render_from) )
|
||||||
|
render_from = cursorpos;
|
||||||
|
if ( IsTextPosAfterTextPos(cursorpos, render_to) )
|
||||||
|
render_to = cursorpos;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case TEXTBUFCMD_MOVE:
|
||||||
|
{
|
||||||
|
TextPos to(cmd->to_x, cmd->to_y);
|
||||||
|
TextPos from(cmd->from_x, cmd->from_y);
|
||||||
|
size_t numchars = cmd->val;
|
||||||
|
DoMove(to, from, numchars);
|
||||||
|
TextPos toend = AddToPosition(to, numchars);
|
||||||
|
if ( IsTextPosBeforeTextPos(to, render_from) )
|
||||||
|
render_from = to;
|
||||||
|
if ( IsTextPosAfterTextPos(toend, render_to) )
|
||||||
|
render_to = toend;
|
||||||
|
} break;
|
||||||
|
case TEXTBUFCMD_FILL:
|
||||||
|
{
|
||||||
|
TextPos from(cmd->from_x, cmd->from_y);
|
||||||
|
TextPos to(cmd->to_x, cmd->to_y);
|
||||||
|
DoFill(from, to, cmd->c, cmd->attr);
|
||||||
|
if ( IsTextPosBeforeTextPos(from, render_from) )
|
||||||
|
render_from = from;
|
||||||
|
if ( IsTextPosAfterTextPos(to, render_to) )
|
||||||
|
render_to = to;
|
||||||
|
} break;
|
||||||
|
case TEXTBUFCMD_SCROLL:
|
||||||
|
{
|
||||||
|
ssize_t off = cmd->scroll_offset;
|
||||||
|
DoScroll(off, cmd->c);
|
||||||
|
render_from = {0, 0};
|
||||||
|
render_to = {columns-1, rows-1};
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !IsTextPosBeforeTextPos(render_to, render_from) )
|
||||||
|
RenderRange(render_from, render_to);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
|
@ -25,32 +25,38 @@
|
||||||
#ifndef SORTIX_LFBTEXTBUFFER_H
|
#ifndef SORTIX_LFBTEXTBUFFER_H
|
||||||
#define SORTIX_LFBTEXTBUFFER_H
|
#define SORTIX_LFBTEXTBUFFER_H
|
||||||
|
|
||||||
|
#include <sortix/kernel/kthread.h>
|
||||||
#include <sortix/kernel/textbuffer.h>
|
#include <sortix/kernel/textbuffer.h>
|
||||||
|
|
||||||
namespace Sortix {
|
namespace Sortix {
|
||||||
|
|
||||||
// Needed information:
|
enum TextBufferCmdType
|
||||||
// Linear frame bufer
|
|
||||||
// - Pointer
|
|
||||||
// - Format (bit depth)
|
|
||||||
// - X resolution, Y resolution, scanline size
|
|
||||||
// Font
|
|
||||||
// - Pointer to our copy of the font.
|
|
||||||
// Color table for each VGA color in <sortix/vga.h>
|
|
||||||
// Number of columns and rows.
|
|
||||||
// Table of characters and attributes.
|
|
||||||
|
|
||||||
struct LFBTextBufferInfo
|
|
||||||
{
|
{
|
||||||
uint8_t* lfb;
|
TEXTBUFCMD_EXIT = 0,
|
||||||
size_t lfbformat;
|
TEXTBUFCMD_SYNC,
|
||||||
size_t xres;
|
TEXTBUFCMD_PAUSE,
|
||||||
size_t yres;
|
TEXTBUFCMD_CHAR,
|
||||||
size_t columns;
|
TEXTBUFCMD_ATTR,
|
||||||
size_t rows;
|
TEXTBUFCMD_CURSOR_SET_ENABLED,
|
||||||
uint16_t* chars;
|
TEXTBUFCMD_CURSOR_MOVE,
|
||||||
uint16_t* attrs;
|
TEXTBUFCMD_MOVE,
|
||||||
uint8_t* vgafont;
|
TEXTBUFCMD_FILL,
|
||||||
|
TEXTBUFCMD_SCROLL,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextBufferCmd
|
||||||
|
{
|
||||||
|
union { TextBufferCmdType type; size_t align; };
|
||||||
|
union { size_t x; size_t from_x; ssize_t scroll_offset; };
|
||||||
|
union { size_t y; size_t from_y; };
|
||||||
|
union { size_t to_x; };
|
||||||
|
union { size_t to_y; };
|
||||||
|
union
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
struct { uint16_t c; uint16_t attr; };
|
||||||
|
size_t val;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class LFBTextBuffer : public TextBuffer
|
class LFBTextBuffer : public TextBuffer
|
||||||
|
@ -78,6 +84,9 @@ public:
|
||||||
virtual TextPos GetCursorPos() const;
|
virtual TextPos GetCursorPos() const;
|
||||||
virtual void SetCursorPos(TextPos newcursorpos);
|
virtual void SetCursorPos(TextPos newcursorpos);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void RenderThread();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void RenderChar(uint16_t vgachar, size_t posx, size_t posy);
|
void RenderChar(uint16_t vgachar, size_t posx, size_t posy);
|
||||||
void RenderCharAt(TextPos pos);
|
void RenderCharAt(TextPos pos);
|
||||||
|
@ -87,9 +96,29 @@ private:
|
||||||
size_t OffsetOfPos(TextPos pos) const;
|
size_t OffsetOfPos(TextPos pos) const;
|
||||||
TextPos CropPosition(TextPos pos) const;
|
TextPos CropPosition(TextPos pos) const;
|
||||||
TextPos AddToPosition(TextPos pos, size_t count);
|
TextPos AddToPosition(TextPos pos, size_t count);
|
||||||
|
void DoScroll(ssize_t off, uint16_t entry);
|
||||||
|
void DoMove(TextPos to, TextPos from, size_t numchars);
|
||||||
|
void DoFill(TextPos from, TextPos to, uint16_t fillwith, uint16_t fillattr);
|
||||||
|
void IssueCommand(TextBufferCmd* cmd);
|
||||||
|
void StopRendering();
|
||||||
|
void ResumeRendering();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
kthread_mutex_t queue_lock;
|
||||||
|
kthread_cond_t queue_not_full;
|
||||||
|
kthread_cond_t queue_not_empty;
|
||||||
|
kthread_cond_t queue_exit;
|
||||||
|
kthread_cond_t queue_sync;
|
||||||
|
kthread_cond_t queue_paused;
|
||||||
|
kthread_cond_t queue_resume;
|
||||||
|
TextBufferCmd* queue;
|
||||||
|
size_t queue_length;
|
||||||
|
size_t queue_offset;
|
||||||
|
size_t queue_used;
|
||||||
|
bool queue_is_paused;
|
||||||
|
bool queue_thread;
|
||||||
uint8_t* lfb;
|
uint8_t* lfb;
|
||||||
|
uint8_t* backbuf;
|
||||||
uint8_t* font;
|
uint8_t* font;
|
||||||
uint16_t* chars;
|
uint16_t* chars;
|
||||||
uint16_t* attrs;
|
uint16_t* attrs;
|
||||||
|
|
Loading…
Reference in a new issue