Skip to content

Commit

Permalink
[libraries/console][servers/console] Support double-buffering of cons…
Browse files Browse the repository at this point in the history
…ole output

This is mostly a quick hack to provide better support for applications
doing a lot of updates to the screen content (i.e. the modplay program
in my current use case)

Only supports text mode, at the moment. For graphics modes, we should
use some form of shared memory instead which is a lot more efficient
than silly copying of bits from one address space to another.
  • Loading branch information
perlun committed Jul 21, 2019
1 parent 7695aba commit 7333a75
Show file tree
Hide file tree
Showing 14 changed files with 261 additions and 28 deletions.
2 changes: 2 additions & 0 deletions libraries/console/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ OBJECTS = %w[

OUTPUT = 'libconsole.a'.freeze

ENV['EXTRA_CFLAGS'] = '-Wno-error=unused-parameter'

load '../libraries.rake'
105 changes: 103 additions & 2 deletions libraries/console/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <stdarg.h>
#include <console/console.h>
#include <ipc/ipc.h>
#include <memory/memory.h>
#include <string/string.h>

#define CONSOLE_MAILBOX_SIZE 32768
Expand All @@ -19,6 +20,8 @@ return_type console_init(console_structure_type *console_structure, tag_type *ta
unsigned int services = 10;
message_parameter_type message_parameter;

memory_set_uint8_t((uint8_t *) console_structure, 0, sizeof(console_structure_type));

console_structure->initialised = FALSE;

if (ipc_service_resolve("console", mailbox_id, &services, 5, tag) != IPC_RETURN_SUCCESS)
Expand Down Expand Up @@ -66,6 +69,33 @@ return_type console_open(console_structure_type *console_structure,

system_call_mailbox_send(console_structure->ipc_structure.output_mailbox_id, &message_parameter);

if (console_attribute.enable_buffer)
{
if (console_attribute.mode_type == VIDEO_MODE_TYPE_TEXT)
{
memory_allocate((void **) &console_structure->buffer,
console_attribute.width *
console_attribute.height *
sizeof(console_character_type));

// Ensure the newly allocated buffer is cleared. Note: we clear with zeroes instead 0f
// 0x0700 here (as is done on regular consoles by the console server), to deliberately
// avoid showing the cursor. Double-buffered applications are unlikely to want to
// display a text cursor anyway.
memory_set_uint16_t((uint16_t *) console_structure->buffer, 0,
console_attribute.width * console_attribute.height);
}
else
{
// Double-buffering is currently only supported for text-mode consoles.
return CONSOLE_RETURN_INVALID_ARGUMENT;
}
}

console_structure->opened = TRUE;
console_structure->width = console_attribute.width;
console_structure->height = console_attribute.height;

return CONSOLE_RETURN_SUCCESS;
}

Expand Down Expand Up @@ -200,7 +230,6 @@ return_type console_print(console_structure_type *console_structure, const char
return CONSOLE_RETURN_SUCCESS;
}

// Prints the given data to the console, a la printf and friends.
return_type console_print_formatted(console_structure_type *console_structure, const char *format_string, ...)
{
va_list arguments;
Expand All @@ -227,7 +256,6 @@ return_type console_clear(console_structure_type *console_structure)
return console_print(console_structure, "\e[2J\e[1;1H");
}

// Move the cursor. Zero indexed!!!
return_type console_cursor_move(console_structure_type *console_structure, unsigned int x, unsigned int y)
{
// FIXME: Should store the size of the console somewhere.
Expand Down Expand Up @@ -305,3 +333,76 @@ return_type console_event_wait(console_structure_type *console_structure, void *

return CONSOLE_RETURN_SUCCESS;
}

return_type console_buffer_print(console_structure_type *console_structure,
int x, int y, uint8_t attribute,
const char *string)
{
unsigned int position = (y * console_structure->width) + x;
unsigned int max_position = console_structure->width * console_structure->height;

for (unsigned int i = 0; i < string_length(string); i++)
{
if (position + i > max_position)
{
// We are past the end of the buffer. Abort and return an error to the caller.
return CONSOLE_RETURN_INVALID_ARGUMENT;
}

console_structure->buffer[position + i].character = string[i];
console_structure->buffer[position + i].attribute = attribute;
}

return CONSOLE_RETURN_SUCCESS;
}

return_type console_buffer_print_formatted(
console_structure_type *console_structure, int x, int y,
uint8_t attribute, const char *format_string, ...)
{
va_list arguments;

// FIXME: Don't have a hardwired buffer like this!
char output[1024];

if (format_string == NULL)
{
output[0] = '\0';

return CONSOLE_RETURN_INVALID_ARGUMENT;
}

va_start(arguments, format_string);
string_print_va(output, format_string, arguments);
va_end(arguments);

return console_buffer_print(console_structure, x, y, attribute, output);
}

return_type console_flip(console_structure_type *console_structure)
{
message_parameter_type message_parameter;

if (!console_structure->initialised)
{
return CONSOLE_RETURN_SERVICE_UNAVAILABLE;
}

if (console_structure->width <= 0 ||
console_structure->height <= 0)
{
return CONSOLE_RETURN_INVALID_ARGUMENT;
}

message_parameter.protocol = IPC_PROTOCOL_CONSOLE;
message_parameter.length = console_structure->width *
console_structure->height *
sizeof(console_character_type);
message_parameter.message_class = IPC_CONSOLE_OUTPUT_ALL;
message_parameter.data = (void *) console_structure->buffer;
message_parameter.block = TRUE;

system_call_mailbox_send(console_structure->ipc_structure.output_mailbox_id, &message_parameter);

return CONSOLE_RETURN_SUCCESS;
}
39 changes: 38 additions & 1 deletion libraries/console/defines.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// Abstract: Defines used by the console library.
// Author: Per Lundberg <[email protected]>
//
// © Copyright 1999-2000, 2013 chaos development.
// © Copyright 1999 chaos development

#pragma once

// Welcome, to the Real World. In this, we use EGA colors in the year of 2KAD...
// FIXME: I wonder what this is, really. These are _neither_ EGA nor
// ANSI colours in reality. They resemble ANSI more than EGA but not
// 100%...
enum
{
CONSOLE_COLOUR_BLACK,
Expand All @@ -18,6 +21,40 @@ enum
CONSOLE_COLOUR_GRAY,
};

// These colours are used when working with buffered console output.
// Note that their numeral values are different to the ones above;
// this is used so that buffers can copied to EGA-compatible text
// mode hardware without conversion.
enum
{
CONSOLE_BUFFER_COLOUR_BLACK, // 0
CONSOLE_BUFFER_COLOUR_BLUE,
CONSOLE_BUFFER_COLOUR_GREEN,
CONSOLE_BUFFER_COLOUR_CYAN,
CONSOLE_BUFFER_COLOUR_RED,
CONSOLE_BUFFER_COLOUR_MAGENTA,
CONSOLE_BUFFER_COLOUR_BROWN,
CONSOLE_BUFFER_COLOUR_LIGHT_GRAY,

CONSOLE_BUFFER_COLOUR_DARK_GRAY, // 8
CONSOLE_BUFFER_COLOUR_BRIGHT_BLUE,
CONSOLE_BUFFER_COLOUR_BRIGHT_GREEN,
CONSOLE_BUFFER_COLOUR_BRIGHT_CYAN,
CONSOLE_BUFFER_COLOUR_BRIGHT_RED,
CONSOLE_BUFFER_COLOUR_BRIGHT_MAGENTA,
CONSOLE_BUFFER_COLOUR_BRIGHT_YELLOW,
CONSOLE_BUFFER_COLOUR_BRIGHT_WHITE,

CONSOLE_BUFFER_BG_COLOUR_BLACK, // 0x10
CONSOLE_BUFFER_BG_COLOUR_BLUE,
CONSOLE_BUFFER_BG_COLOUR_GREEN,
CONSOLE_BUFFER_BG_COLOUR_CYAN,
CONSOLE_BUFFER_BG_COLOUR_RED,
CONSOLE_BUFFER_BG_COLOUR_MAGENTA,
CONSOLE_BUFFER_BG_COLOUR_BROWN,
CONSOLE_BUFFER_BG_COLOUR_LIGHT_GRAY
};

enum
{
CONSOLE_ATTRIBUTE_RESET = 0,
Expand Down
23 changes: 23 additions & 0 deletions libraries/console/functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ extern return_type console_mode_set(console_structure_type *console_structure, u
extern return_type console_resize(console_structure_type *console_structure, unsigned int width,
unsigned int height);
extern return_type console_print(console_structure_type *console_structure, const char *string);

// Prints the given data to the console, similar to printf.
extern return_type console_print_formatted(console_structure_type *console_structure,
const char *string, ...) __attribute__ ((format (printf, 2, 3)));
extern return_type console_clear(console_structure_type *console_structure);

// Moves the cursor. Note that the position is zero-indexed; the top-left coordinate is 0,0.
extern return_type console_cursor_move(console_structure_type *console_structure, unsigned int x,
unsigned int y);
extern return_type console_attribute_set(console_structure_type *console_structure, int foreground,
Expand All @@ -34,4 +38,23 @@ extern return_type console_use_mouse(console_structure_type *console_structure,
extern return_type console_event_wait(console_structure_type *console_structure, void *event_data,
int *type, bool block);

// Prints output to a console using double-buffering, at the given
// cursor position.
extern return_type console_buffer_print(
console_structure_type *console_structure, int x, int y,
uint8_t attribute, const char *string
);

// Prints printf-formatted output to a console using double-buffering, at
// the given cursor position.
extern return_type console_buffer_print_formatted(
console_structure_type *console_structure, int x, int y,
uint8_t attribute, const char *string, ...
) __attribute__ ((format (printf, 5, 6)));

// Flips double-buffered content to the "real" console. If this console
// uses double-buffering, this function must be called whenever a
// "frame" is ready to be displayed.
extern return_type console_flip(console_structure_type *console_structure);

C_EXTERN_END
13 changes: 12 additions & 1 deletion libraries/console/types.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
// Abstract: Console library types.
// Author: Per Lundberg <[email protected]>
//
// © Copyright 2000 chaos development.
// © Copyright 1999 chaos development.

#pragma once

#include <ipc/ipc.h>

typedef struct
{
uint8_t character;
uint8_t attribute;
} PACKED console_character_type;

typedef struct
{
ipc_structure_type ipc_structure;
Expand All @@ -16,4 +22,9 @@ typedef struct
unsigned int type;
bool initialised;
bool opened;

// If ipc_console_attribute_type.enable_buffer was set when
// console_open was called, this will be a non-NULL pointer that
// will be used to double-buffer content.
console_character_type *buffer;
} console_structure_type;
24 changes: 16 additions & 8 deletions libraries/ipc/console.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ enum
IPC_CONSOLE_MODE_SET,
IPC_CONSOLE_CLOSE,
IPC_CONSOLE_OUTPUT,
IPC_CONSOLE_OUTPUT_ALL,
IPC_CONSOLE_RESIZE,
IPC_CONSOLE_ENABLE_KEYBOARD,
IPC_CONSOLE_DISABLE_KEYBOARD,
Expand Down Expand Up @@ -50,22 +51,29 @@ typedef struct
// Physical console attribute type.
typedef struct
{
// The width in pixels (for VIDEO_MODE_TYPE_GRAPHIC) or characters (for VIDEO_MODE_TYPE_TEXT)
// of the console being opened.
// The width in pixels (for VIDEO_MODE_TYPE_GRAPHIC) or characters
// (for VIDEO_MODE_TYPE_TEXT) of the console being opened.
unsigned int width;

// The height in pixels (for VIDEO_MODE_TYPE_GRAPHIC) or lines (for VIDEO_MODE_TYPE_TEXT)
// of the console being opened.
// The height in pixels (for VIDEO_MODE_TYPE_GRAPHIC) or lines (for
// VIDEO_MODE_TYPE_TEXT) of the console being opened.
unsigned int height;

// For VIDEO_MODE_TYPE_GRAPHIC, indicates the depth in bits (15, 16, 24 etc) of the mode being
// requested.
// For VIDEO_MODE_TYPE_GRAPHIC, indicates the depth in bits (15, 16,
// 24 etc) of the mode being requested.
unsigned int depth;

// Set to either VIDEO_MODE_TYPE_TEXT or VIDEO_MODE_TYPE_GRAPHIC.
unsigned int mode_type;

// Indicates that the console should be activated upon creation. Can only be done once; if
// a console is already active, this flag will be ignored by the console server.
// Indicates that the console should be activated upon creation. Can
// only be done once; if a console is already active, this flag will
// be ignored by the console server.
bool activate;

// Set to TRUE if the client desires a local buffer for
// double-buffering console output. This is useful in applications
// with a lot of console outputs and/or real-time visualization
// requirements.
bool enable_buffer;
} ipc_console_attribute_type;
8 changes: 4 additions & 4 deletions libraries/ipc/keyboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ enum
IPC_KEYBOARD_SPECIAL_KEY_NUM_LOCK,
IPC_KEYBOARD_SPECIAL_KEY_SCROLL_LOCK,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_7,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_8,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_8, // Up arrow
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_9,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_MINUS,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_4,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_4, // Left arrow
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_5,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_6,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_6, // Right arrow
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_PLUS,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_1,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_2,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_2, // Down arrow
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_3,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_0,
IPC_KEYBOARD_SPECIAL_KEY_NUMERIC_DELETE,
Expand Down
4 changes: 1 addition & 3 deletions libraries/string/inlines.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@

// I think much of this is ripped from "somewhere" though... so this is probably more GPL than BSD.

// © Copyright 2000 chaos development
// © Copyright 2007 chaos development
// © Copyright 2017 chaos development
// © Copyright 1999 chaos development

#pragma once

Expand Down
1 change: 1 addition & 0 deletions servers/system/console/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ OBJECTS = %w[
connection.o
console.o
console_output.o
console_output_all.o
].freeze

LIBRARIES = %w[
Expand Down
Loading

0 comments on commit 7333a75

Please sign in to comment.