1 /*
2 * Copyright (c) 2008-2010, 2015 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8
9 /**
10 * @file
11 * @brief Manage graphics console
12 *
13 * This file contains functions to provide stdout to the graphics console.
14 *
15 * @ingroup graphics
16 */
17
18 #include <lk/debug.h>
19 #include <assert.h>
20 #include <lib/io.h>
21 #include <lk/init.h>
22 #include <lib/gfx.h>
23 #include <lib/gfxconsole.h>
24 #include <lib/font.h>
25 #include <dev/display.h>
26
27 /** @addtogroup graphics
28 * @{
29 */
30
31 /**
32 * @brief Represent state of graphics console
33 */
34 static struct {
35 gfx_surface *surface;
36 uint rows, columns;
37 uint extray; // extra pixels left over if the rows doesn't fit precisely
38
39 uint x, y;
40
41 uint32_t front_color;
42 uint32_t back_color;
43 } gfxconsole;
44
gfxconsole_putc(char c)45 static void gfxconsole_putc(char c) {
46 static enum { NORMAL, ESCAPE } state = NORMAL;
47 static uint32_t p_num = 0;
48
49 switch (state) {
50 case NORMAL: {
51 if (c == '\n' || c == '\r') {
52 gfxconsole.x = 0;
53 gfxconsole.y++;
54 } else if (c == 0x1b) {
55 p_num = 0;
56 state = ESCAPE;
57 } else {
58 font_draw_char(gfxconsole.surface, c, gfxconsole.x * FONT_X, gfxconsole.y * FONT_Y, gfxconsole.front_color);
59 gfxconsole.x++;
60 }
61 break;
62 }
63
64 case ESCAPE: {
65 if (c >= '0' && c <= '9') {
66 p_num = (p_num * 10) + (c - '0');
67 } else if (c == 'D') {
68 if (p_num <= gfxconsole.x)
69 gfxconsole.x -= p_num;
70 state = NORMAL;
71 } else if (c == '[') {
72 // eat this character
73 } else {
74 font_draw_char(gfxconsole.surface, c, gfxconsole.x * FONT_X, gfxconsole.y * FONT_Y, gfxconsole.front_color);
75 gfxconsole.x++;
76 state = NORMAL;
77 }
78 break;
79 }
80 }
81
82 if (gfxconsole.x >= gfxconsole.columns) {
83 gfxconsole.x = 0;
84 gfxconsole.y++;
85 }
86 if (gfxconsole.y >= gfxconsole.rows) {
87 // scroll up
88 gfx_copyrect(gfxconsole.surface, 0, FONT_Y, gfxconsole.surface->width, gfxconsole.surface->height - FONT_Y - gfxconsole.extray, 0, 0);
89 gfxconsole.y--;
90 gfx_fillrect(gfxconsole.surface, 0, gfxconsole.surface->height - FONT_Y - gfxconsole.extray, gfxconsole.surface->width, FONT_Y, gfxconsole.back_color);
91 gfx_flush(gfxconsole.surface);
92 }
93 }
94
gfxconsole_print_callback(print_callback_t * cb,const char * str,size_t len)95 void gfxconsole_print_callback(print_callback_t *cb, const char *str, size_t len) {
96 for (size_t i = 0; i < len; i++) {
97 gfxconsole_putc(str[i]);
98 }
99 }
100
101 static print_callback_t cb = {
102 .entry = { 0 },
103 .print = gfxconsole_print_callback,
104 .context = NULL
105 };
106
107 /**
108 * @brief Initialize graphics console on given drawing surface.
109 *
110 * The graphics console subsystem is initialized, and registered as
111 * an output device for debug output.
112 */
gfxconsole_start(gfx_surface * surface)113 void gfxconsole_start(gfx_surface *surface) {
114 DEBUG_ASSERT(gfxconsole.surface == NULL);
115
116 // set up the surface
117 gfxconsole.surface = surface;
118
119 // calculate how many rows/columns we have
120 gfxconsole.rows = surface->height / FONT_Y;
121 gfxconsole.columns = surface->width / FONT_X;
122 gfxconsole.extray = surface->height - (gfxconsole.rows * FONT_Y);
123
124 dprintf(SPEW, "gfxconsole: rows %d, columns %d, extray %d\n", gfxconsole.rows, gfxconsole.columns, gfxconsole.extray);
125
126 // start in the upper left
127 gfxconsole.x = 0;
128 gfxconsole.y = 0;
129
130 // colors are white and black for now
131 gfxconsole.front_color = 0xffffffff;
132 gfxconsole.back_color = 0;
133
134 // register for debug callbacks
135 register_print_callback(&cb);
136 }
137
138 /**
139 * @brief Initialize graphics console on default display
140 */
gfxconsole_start_on_display(void)141 void gfxconsole_start_on_display(void) {
142 static bool started = false;
143
144 if (started)
145 return;
146
147 /* pop up the console */
148 struct display_framebuffer fb;
149 if (display_get_framebuffer(&fb) < 0)
150 return;
151
152 gfx_surface *s = gfx_create_surface_from_display(&fb);
153 gfxconsole_start(s);
154 started = true;
155 }
156
gfxconsole_init_hook(uint level)157 static void gfxconsole_init_hook(uint level) {
158 gfxconsole_start_on_display();
159 }
160
161 LK_INIT_HOOK(gfxconsole, &gfxconsole_init_hook, LK_INIT_LEVEL_PLATFORM);
162