2 * uterm - Linux User-Space Terminal fbdev module
4 * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@googlemail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files
8 * (the "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * FBDEV module rendering functions
35 #include "uterm_fbdev_internal.h"
36 #include "uterm_video.h"
37 #include "uterm_video_internal.h"
39 #define LOG_SUBSYSTEM "fbdev_render"
41 static int clamp_value(int val, int low, int up)
51 static uint_fast32_t xrgb32_to_device(struct uterm_display *disp,
54 uint8_t r, g, b, nr, ng, nb;
57 struct fbdev_display *fbdev = disp->data;
59 r = (pixel >> 16) & 0xff;
60 g = (pixel >> 8) & 0xff;
61 b = (pixel >> 0) & 0xff;
63 if (disp->flags & DISPLAY_DITHERING) {
64 /* This is some very basic dithering which simply does small
65 * rotations in the lower pixel bits. TODO: Let's take a look
66 * at Floyd-Steinberg dithering which should give much better
67 * results. It is slightly slower, though.
68 * Or even better would be some Sierra filter like the Sierra
70 fbdev->dither_r = r - fbdev->dither_r;
71 fbdev->dither_g = g - fbdev->dither_g;
72 fbdev->dither_b = b - fbdev->dither_b;
73 r = clamp_value(fbdev->dither_r, 0, 255) >> (8 - fbdev->len_r);
74 g = clamp_value(fbdev->dither_g, 0, 255) >> (8 - fbdev->len_g);
75 b = clamp_value(fbdev->dither_b, 0, 255) >> (8 - fbdev->len_b);
76 nr = r << (8 - fbdev->len_r);
77 ng = g << (8 - fbdev->len_g);
78 nb = b << (8 - fbdev->len_b);
80 for (i = fbdev->len_r; i < 8; i <<= 1)
82 for (i = fbdev->len_g; i < 8; i <<= 1)
84 for (i = fbdev->len_b; i < 8; i <<= 1)
87 fbdev->dither_r = nr - fbdev->dither_r;
88 fbdev->dither_g = ng - fbdev->dither_g;
89 fbdev->dither_b = nb - fbdev->dither_b;
91 res = r << fbdev->off_r;
92 res |= g << fbdev->off_g;
93 res |= b << fbdev->off_b;
95 res = (r >> (8 - fbdev->len_r)) << fbdev->off_r;
96 res |= (g >> (8 - fbdev->len_g)) << fbdev->off_g;
97 res |= (b >> (8 - fbdev->len_b)) << fbdev->off_b;
103 int uterm_fbdev_display_blit(struct uterm_display *disp,
104 const struct uterm_video_buffer *buf,
105 unsigned int x, unsigned int y)
109 unsigned int width, height, i;
111 struct fbdev_display *fbdev = disp->data;
113 if (!buf || buf->format != UTERM_FORMAT_XRGB32)
116 tmp = x + buf->width;
117 if (tmp < x || x >= fbdev->xres)
119 if (tmp > fbdev->xres)
120 width = fbdev->xres - x;
124 tmp = y + buf->height;
125 if (tmp < y || y >= fbdev->yres)
127 if (tmp > fbdev->yres)
128 height = fbdev->yres - y;
130 height = buf->height;
132 if (!(disp->flags & DISPLAY_DBUF) || fbdev->bufid)
135 dst = &fbdev->map[fbdev->yres * fbdev->stride];
136 dst = &dst[y * fbdev->stride + x * fbdev->Bpp];
141 memcpy(dst, src, 4 * width);
142 dst += fbdev->stride;
145 } else if (fbdev->Bpp == 2) {
147 for (i = 0; i < width; ++i) {
148 val = ((uint32_t*)src)[i];
149 ((uint16_t*)dst)[i] = xrgb32_to_device(disp, val);
151 dst += fbdev->stride;
154 } else if (fbdev->Bpp == 4) {
156 for (i = 0; i < width; ++i) {
157 val = ((uint32_t*)src)[i];
158 ((uint32_t*)dst)[i] = xrgb32_to_device(disp, val);
160 dst += fbdev->stride;
164 log_debug("invalid Bpp");
170 int uterm_fbdev_display_fake_blendv(struct uterm_display *disp,
171 const struct uterm_video_blend_req *req,
176 unsigned int width, height, i, j;
177 unsigned int r, g, b;
179 struct fbdev_display *fbdev = disp->data;
184 for (j = 0; j < num; ++j, ++req) {
188 if (req->buf->format != UTERM_FORMAT_GREY)
191 tmp = req->x + req->buf->width;
192 if (tmp < req->x || req->x >= fbdev->xres)
194 if (tmp > fbdev->xres)
195 width = fbdev->xres - req->x;
197 width = req->buf->width;
199 tmp = req->y + req->buf->height;
200 if (tmp < req->y || req->y >= fbdev->yres)
202 if (tmp > fbdev->yres)
203 height = fbdev->yres - req->y;
205 height = req->buf->height;
207 if (!(disp->flags & DISPLAY_DBUF) || fbdev->bufid)
210 dst = &fbdev->map[fbdev->yres * fbdev->stride];
211 dst = &dst[req->y * fbdev->stride + req->x * fbdev->Bpp];
212 src = req->buf->data;
214 /* Division by 256 instead of 255 increases
215 * speed by like 20% on slower machines.
216 * Downside is, full white is 254/254/254
217 * instead of 255/255/255. */
220 for (i = 0; i < width; ++i) {
225 } else if (src[i] == 255) {
230 r = req->fr * src[i] +
231 req->br * (255 - src[i]);
233 g = req->fg * src[i] +
234 req->bg * (255 - src[i]);
236 b = req->fb * src[i] +
237 req->bb * (255 - src[i]);
240 val = (r << 16) | (g << 8) | b;
241 ((uint32_t*)dst)[i] = val;
243 dst += fbdev->stride;
244 src += req->buf->stride;
246 } else if (fbdev->Bpp == 2) {
248 for (i = 0; i < width; ++i) {
253 } else if (src[i] == 255) {
258 r = req->fr * src[i] +
259 req->br * (255 - src[i]);
261 g = req->fg * src[i] +
262 req->bg * (255 - src[i]);
264 b = req->fb * src[i] +
265 req->bb * (255 - src[i]);
268 val = (r << 16) | (g << 8) | b;
269 ((uint16_t*)dst)[i] =
270 xrgb32_to_device(disp, val);
272 dst += fbdev->stride;
273 src += req->buf->stride;
275 } else if (fbdev->Bpp == 4) {
277 for (i = 0; i < width; ++i) {
282 } else if (src[i] == 255) {
287 r = req->fr * src[i] +
288 req->br * (255 - src[i]);
290 g = req->fg * src[i] +
291 req->bg * (255 - src[i]);
293 b = req->fb * src[i] +
294 req->bb * (255 - src[i]);
297 val = (r << 16) | (g << 8) | b;
298 ((uint32_t*)dst)[i] =
299 xrgb32_to_device(disp, val);
301 dst += fbdev->stride;
302 src += req->buf->stride;
305 log_warning("invalid Bpp");
312 int uterm_fbdev_display_fill(struct uterm_display *disp,
313 uint8_t r, uint8_t g, uint8_t b,
314 unsigned int x, unsigned int y,
315 unsigned int width, unsigned int height)
319 uint32_t full_val, rgb32;
320 struct fbdev_display *fbdev = disp->data;
323 if (tmp < x || x >= fbdev->xres)
325 if (tmp > fbdev->xres)
326 width = fbdev->xres - x;
328 if (tmp < y || y >= fbdev->yres)
330 if (tmp > fbdev->yres)
331 height = fbdev->yres - y;
333 if (!(disp->flags & DISPLAY_DBUF) || fbdev->bufid)
336 dst = &fbdev->map[fbdev->yres * fbdev->stride];
337 dst = &dst[y * fbdev->stride + x * fbdev->Bpp];
339 full_val = ((r & 0xff) >> (8 - fbdev->len_r)) << fbdev->off_r;
340 full_val |= ((g & 0xff) >> (8 - fbdev->len_g)) << fbdev->off_g;
341 full_val |= ((b & 0xff) >> (8 - fbdev->len_b)) << fbdev->off_b;
343 if (fbdev->Bpp == 2) {
344 if (disp->flags & DISPLAY_DITHERING) {
345 rgb32 = (r & 0xff) << 16;
346 rgb32 |= (g & 0xff) << 8;
347 rgb32 |= (b & 0xff) << 0;
349 for (i = 0; i < width; ++i)
350 ((uint16_t*)dst)[i] = xrgb32_to_device(disp, rgb32);
351 dst += fbdev->stride;
356 for (i = 0; i < width; ++i)
357 ((uint16_t*)dst)[i] = full_val;
358 dst += fbdev->stride;
361 } else if (fbdev->Bpp == 4) {
363 for (i = 0; i < width; ++i)
364 ((uint32_t*)dst)[i] = full_val;
365 dst += fbdev->stride;
368 log_error("invalid Bpp");