source: mainline/uspace/lib/congfx/src/console.c@ f05edcb

serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f05edcb was bb14312, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Use hardware cursor in text mode

We extend GC with cursor control operations. This will also allow to
control the HW cursor when running display server in text mode in
the future (provided that we implement the missing bits in the rest
of the stack, i.e. in IPC GC and in the display server).

  • Property mode set to 100644
File size: 12.1 KB
Line 
1/*
2 * Copyright (c) 2021 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libcongfx
30 * @{
31 */
32/**
33 * @file GFX console backend
34 *
35 * This implements a graphics context over a classic console interface.
36 * This is just for experimentation purposes. In the end we want the
37 * console to actually directly suport GFX interface.
38 */
39
40#include <congfx/console.h>
41#include <gfx/context.h>
42#include <gfx/coord.h>
43#include <gfx/render.h>
44#include <io/pixel.h>
45#include <io/pixelmap.h>
46#include <stdlib.h>
47#include "../private/console.h"
48#include "../private/color.h"
49
50static errno_t console_gc_set_clip_rect(void *, gfx_rect_t *);
51static errno_t console_gc_set_color(void *, gfx_color_t *);
52static errno_t console_gc_fill_rect(void *, gfx_rect_t *);
53static errno_t console_gc_update(void *);
54static errno_t console_gc_bitmap_create(void *, gfx_bitmap_params_t *,
55 gfx_bitmap_alloc_t *, void **);
56static errno_t console_gc_bitmap_destroy(void *);
57static errno_t console_gc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
58static errno_t console_gc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
59static errno_t console_gc_cursor_get_pos(void *, gfx_coord2_t *);
60static errno_t console_gc_cursor_set_pos(void *, gfx_coord2_t *);
61static errno_t console_gc_cursor_set_visible(void *, bool);
62
63gfx_context_ops_t console_gc_ops = {
64 .set_clip_rect = console_gc_set_clip_rect,
65 .set_color = console_gc_set_color,
66 .fill_rect = console_gc_fill_rect,
67 .update = console_gc_update,
68 .bitmap_create = console_gc_bitmap_create,
69 .bitmap_destroy = console_gc_bitmap_destroy,
70 .bitmap_render = console_gc_bitmap_render,
71 .bitmap_get_alloc = console_gc_bitmap_get_alloc,
72 .cursor_get_pos = console_gc_cursor_get_pos,
73 .cursor_set_pos = console_gc_cursor_set_pos,
74 .cursor_set_visible = console_gc_cursor_set_visible
75};
76
77/** Set clipping rectangle on console GC.
78 *
79 * @param arg Console GC
80 * @param rect Rectangle
81 *
82 * @return EOK on success or an error code
83 */
84static errno_t console_gc_set_clip_rect(void *arg, gfx_rect_t *rect)
85{
86 console_gc_t *cgc = (console_gc_t *) arg;
87
88 if (rect != NULL)
89 gfx_rect_clip(rect, &cgc->rect, &cgc->clip_rect);
90 else
91 cgc->clip_rect = cgc->rect;
92
93 return EOK;
94}
95
96/** Set color on console GC.
97 *
98 * Set drawing color on console GC.
99 *
100 * @param arg Console GC
101 * @param color Color
102 *
103 * @return EOK on success or an error code
104 */
105static errno_t console_gc_set_color(void *arg, gfx_color_t *color)
106{
107 console_gc_t *cgc = (console_gc_t *) arg;
108
109 cgc->clr = PIXEL(0, color->r >> 8, color->g >> 8, color->b >> 8);
110 return EOK;
111}
112
113/** Fill rectangle on console GC.
114 *
115 * @param arg Console GC
116 * @param rect Rectangle
117 *
118 * @return EOK on success or an error code
119 */
120static errno_t console_gc_fill_rect(void *arg, gfx_rect_t *rect)
121{
122 console_gc_t *cgc = (console_gc_t *) arg;
123 gfx_coord_t x, y;
124 gfx_coord_t cols;
125 gfx_rect_t crect;
126 charfield_t ch;
127
128 /* Make sure rectangle is clipped and sorted */
129 gfx_rect_clip(rect, &cgc->clip_rect, &crect);
130
131 cols = cgc->rect.p1.x - cgc->rect.p0.x;
132
133 ch.ch = cgc->clr >> 24;
134 ch.flags = CHAR_FLAG_DIRTY;
135 ch.attrs.type = CHAR_ATTR_RGB;
136 ch.attrs.val.rgb.fgcolor = cgc->clr ^ 0xffffff;
137 ch.attrs.val.rgb.bgcolor = cgc->clr;
138
139 for (y = crect.p0.y; y < crect.p1.y; y++) {
140 for (x = crect.p0.x; x < crect.p1.x; x++) {
141 cgc->buf[y * cols + x] = ch;
142 }
143 }
144
145 console_update(cgc->con, crect.p0.x, crect.p0.y,
146 crect.p1.x, crect.p1.y);
147
148 return EOK;
149}
150
151/** Update console GC.
152 *
153 * @param arg Console GC
154 *
155 * @return EOK on success or an error code
156 */
157static errno_t console_gc_update(void *arg)
158{
159 console_gc_t *cgc = (console_gc_t *) arg;
160
161 /*
162 * XXX Before actually deferring update to here (and similarly other
163 * GC implementations) need to make sure all consumers properly
164 * call update.
165 */
166 (void) cgc;
167 return EOK;
168}
169
170/** Create console GC.
171 *
172 * Create graphics context for rendering into a console.
173 *
174 * @param con Console object
175 * @param fout File to which characters are written (console)
176 * @param rgc Place to store pointer to new GC.
177 *
178 * @return EOK on success or an error code
179 */
180errno_t console_gc_create(console_ctrl_t *con, FILE *fout,
181 console_gc_t **rgc)
182{
183 console_gc_t *cgc = NULL;
184 gfx_context_t *gc = NULL;
185 sysarg_t rows;
186 sysarg_t cols;
187 charfield_t *buf = NULL;
188 errno_t rc;
189
190 cgc = calloc(1, sizeof(console_gc_t));
191 if (cgc == NULL) {
192 rc = ENOMEM;
193 goto error;
194 }
195
196 rc = console_get_size(con, &cols, &rows);
197 if (rc != EOK)
198 goto error;
199
200 console_clear(con);
201
202 rc = console_map(con, cols, rows, &buf);
203 if (rc != EOK)
204 goto error;
205
206 rc = gfx_context_new(&console_gc_ops, cgc, &gc);
207 if (rc != EOK)
208 goto error;
209
210 cgc->gc = gc;
211 cgc->con = con;
212 cgc->fout = fout;
213 cgc->rect.p0.x = 0;
214 cgc->rect.p0.y = 0;
215 cgc->rect.p1.x = cols;
216 cgc->rect.p1.y = rows;
217 cgc->clip_rect = cgc->rect;
218 cgc->buf = buf;
219
220 *rgc = cgc;
221 return EOK;
222error:
223 if (buf != NULL)
224 console_unmap(cgc->con, buf);
225 if (cgc != NULL)
226 free(cgc);
227 gfx_context_delete(gc);
228 return rc;
229}
230
231/** Delete console GC.
232 *
233 * @param cgc Console GC
234 */
235errno_t console_gc_delete(console_gc_t *cgc)
236{
237 errno_t rc;
238
239 rc = gfx_context_delete(cgc->gc);
240 if (rc != EOK)
241 return rc;
242
243 console_clear(cgc->con);
244 console_unmap(cgc->con, cgc->buf);
245
246 free(cgc);
247 return EOK;
248}
249
250/** Get generic graphic context from console GC.
251 *
252 * @param cgc Console GC
253 * @return Graphic context
254 */
255gfx_context_t *console_gc_get_ctx(console_gc_t *cgc)
256{
257 return cgc->gc;
258}
259
260/** Create bitmap in console GC.
261 *
262 * @param arg console GC
263 * @param params Bitmap params
264 * @param alloc Bitmap allocation info or @c NULL
265 * @param rbm Place to store pointer to new bitmap
266 * @return EOK on success or an error code
267 */
268errno_t console_gc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
269 gfx_bitmap_alloc_t *alloc, void **rbm)
270{
271 console_gc_t *cgc = (console_gc_t *) arg;
272 console_gc_bitmap_t *cbm = NULL;
273 gfx_coord2_t dim;
274 errno_t rc;
275
276 /* Check that we support all requested flags */
277 if ((params->flags & ~(bmpf_color_key | bmpf_colorize)) != 0)
278 return ENOTSUP;
279
280 cbm = calloc(1, sizeof(console_gc_bitmap_t));
281 if (cbm == NULL)
282 return ENOMEM;
283
284 gfx_coord2_subtract(&params->rect.p1, &params->rect.p0, &dim);
285 cbm->rect = params->rect;
286 cbm->flags = params->flags;
287 cbm->key_color = params->key_color;
288
289 if (alloc == NULL) {
290 cbm->alloc.pitch = dim.x * sizeof(uint32_t);
291 cbm->alloc.off0 = 0;
292 cbm->alloc.pixels = calloc(dim.x * dim.y, sizeof(uint32_t));
293 if (cbm->alloc.pixels == NULL) {
294 rc = ENOMEM;
295 goto error;
296 }
297
298 cbm->myalloc = true;
299 } else {
300 cbm->alloc = *alloc;
301 }
302
303 cbm->cgc = cgc;
304 *rbm = (void *)cbm;
305 return EOK;
306error:
307 if (cbm != NULL)
308 free(cbm);
309 return rc;
310}
311
312/** Destroy bitmap in console GC.
313 *
314 * @param bm Bitmap
315 * @return EOK on success or an error code
316 */
317static errno_t console_gc_bitmap_destroy(void *bm)
318{
319 console_gc_bitmap_t *cbm = (console_gc_bitmap_t *)bm;
320 if (cbm->myalloc)
321 free(cbm->alloc.pixels);
322 free(cbm);
323 return EOK;
324}
325
326/** Render bitmap in console GC.
327 *
328 * @param bm Bitmap
329 * @param srect0 Source rectangle or @c NULL
330 * @param offs0 Offset or @c NULL
331 * @return EOK on success or an error code
332 */
333static errno_t console_gc_bitmap_render(void *bm, gfx_rect_t *srect0,
334 gfx_coord2_t *offs0)
335{
336 console_gc_bitmap_t *cbm = (console_gc_bitmap_t *)bm;
337 gfx_coord_t x, y;
338 pixel_t clr;
339 charfield_t ch;
340 pixelmap_t pixelmap;
341 gfx_rect_t srect;
342 gfx_rect_t drect;
343 gfx_rect_t crect;
344 gfx_coord2_t offs;
345 gfx_coord_t cols;
346
347 if (srect0 != NULL)
348 srect = *srect0;
349 else
350 srect = cbm->rect;
351
352 if (offs0 != NULL) {
353 offs = *offs0;
354 } else {
355 offs.x = 0;
356 offs.y = 0;
357 }
358
359 gfx_rect_translate(&offs, &srect, &drect);
360 gfx_rect_clip(&drect, &cbm->cgc->clip_rect, &crect);
361
362 pixelmap.width = cbm->rect.p1.x - cbm->rect.p0.x;
363 pixelmap.height = cbm->rect.p1.y = cbm->rect.p1.y;
364 pixelmap.data = cbm->alloc.pixels;
365
366 cols = cbm->cgc->rect.p1.x - cbm->cgc->rect.p0.x;
367
368 if ((cbm->flags & bmpf_color_key) == 0) {
369 /* Simple copy */
370 for (y = crect.p0.y; y < crect.p1.y; y++) {
371 for (x = crect.p0.x; x < crect.p1.x; x++) {
372 clr = pixelmap_get_pixel(&pixelmap,
373 x - offs.x - cbm->rect.p0.x,
374 y - offs.y - cbm->rect.p0.y);
375
376 ch.ch = clr >> 24;
377 ch.flags = CHAR_FLAG_DIRTY;
378 ch.attrs.type = CHAR_ATTR_RGB;
379 ch.attrs.val.rgb.fgcolor = clr ^ 0xffffff;
380 ch.attrs.val.rgb.bgcolor = clr;
381
382 cbm->cgc->buf[y * cols + x] = ch;
383 }
384 }
385 } else if ((cbm->flags & bmpf_colorize) == 0) {
386 /* Color key */
387 for (y = crect.p0.y; y < crect.p1.y; y++) {
388 for (x = crect.p0.x; x < crect.p1.x; x++) {
389
390 clr = pixelmap_get_pixel(&pixelmap,
391 x - offs.x - cbm->rect.p0.x,
392 y - offs.y - cbm->rect.p0.y);
393
394 ch.ch = clr >> 24;
395 ch.flags = CHAR_FLAG_DIRTY;
396 ch.attrs.type = CHAR_ATTR_RGB;
397 ch.attrs.val.rgb.fgcolor = clr ^ 0xffffff;
398 ch.attrs.val.rgb.bgcolor = clr;
399
400 if (clr != cbm->key_color)
401 cbm->cgc->buf[y * cols + x] = ch;
402 }
403 }
404 } else {
405 /* Color key & colorize */
406 ch.ch = 0;
407 ch.flags = CHAR_FLAG_DIRTY;
408 ch.attrs.type = CHAR_ATTR_RGB;
409 ch.attrs.val.rgb.fgcolor = cbm->cgc->clr;
410 ch.attrs.val.rgb.bgcolor = cbm->cgc->clr;
411
412 for (y = crect.p0.y; y < crect.p1.y; y++) {
413 for (x = crect.p0.x; x < crect.p1.x; x++) {
414 clr = pixelmap_get_pixel(&pixelmap,
415 x - offs.x - cbm->rect.p0.x,
416 y - offs.y - cbm->rect.p0.y);
417
418 if (clr != cbm->key_color)
419 cbm->cgc->buf[y * cols + x] = ch;
420 }
421 }
422 }
423
424 console_update(cbm->cgc->con, crect.p0.x, crect.p0.y, crect.p1.x,
425 crect.p1.y);
426
427 return EOK;
428}
429
430/** Get allocation info for bitmap in console GC.
431 *
432 * @param bm Bitmap
433 * @param alloc Place to store allocation info
434 * @return EOK on success or an error code
435 */
436static errno_t console_gc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
437{
438 console_gc_bitmap_t *cbm = (console_gc_bitmap_t *)bm;
439 *alloc = cbm->alloc;
440 return EOK;
441}
442
443/** Get cursor position on console GC.
444 *
445 * @param arg Console GC
446 * @param pos Place to store position
447 *
448 * @return EOK on success or an error code
449 */
450static errno_t console_gc_cursor_get_pos(void *arg, gfx_coord2_t *pos)
451{
452 console_gc_t *cgc = (console_gc_t *) arg;
453 sysarg_t col;
454 sysarg_t row;
455 errno_t rc;
456
457 rc = console_get_pos(cgc->con, &col, &row);
458 if (rc != EOK)
459 return rc;
460
461 pos->x = col;
462 pos->y = row;
463 return EOK;
464}
465
466/** Set cursor position on console GC.
467 *
468 * @param arg Console GC
469 * @param pos New cursor position
470 *
471 * @return EOK on success or an error code
472 */
473static errno_t console_gc_cursor_set_pos(void *arg, gfx_coord2_t *pos)
474{
475 console_gc_t *cgc = (console_gc_t *) arg;
476
477 console_set_pos(cgc->con, pos->x, pos->y);
478 return EOK;
479}
480
481/** Set cursor visibility on console GC.
482 *
483 * @param arg Console GC
484 * @param visible @c true iff cursor should be made visible
485 *
486 * @return EOK on success or an error code
487 */
488static errno_t console_gc_cursor_set_visible(void *arg, bool visible)
489{
490 console_gc_t *cgc = (console_gc_t *) arg;
491
492 console_cursor_visibility(cgc->con, visible);
493 return EOK;
494}
495
496/** @}
497 */
Note: See TracBrowser for help on using the repository browser.