uvtd: vt: implement VT_GETMODE/SETMODE ioctl state-tracking
[platform/upstream/kmscon.git] / src / uterm_drm2d_render.c
1 /*
2  * uterm - Linux User-Space Terminal drm2d module
3  *
4  * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@googlemail.com>
5  *
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:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
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.
24  */
25
26 /*
27  * DRM2D Video backend rendering functions
28  */
29
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <inttypes.h>
33 #include <stdbool.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/mman.h>
37 #include <unistd.h>
38 #include <xf86drm.h>
39 #include <xf86drmMode.h>
40 #include "eloop.h"
41 #include "shl_log.h"
42 #include "uterm_drm_shared_internal.h"
43 #include "uterm_drm2d_internal.h"
44 #include "uterm_video.h"
45 #include "uterm_video_internal.h"
46
47 #define LOG_SUBSYSTEM "uterm_drm2d_render"
48
49 int uterm_drm2d_display_blit(struct uterm_display *disp,
50                              const struct uterm_video_buffer *buf,
51                              unsigned int x, unsigned int y)
52 {
53         unsigned int tmp;
54         uint8_t *dst, *src;
55         unsigned int width, height;
56         unsigned int sw, sh;
57         struct uterm_drm2d_rb *rb;
58         struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
59
60         if (!buf || buf->format != UTERM_FORMAT_XRGB32)
61                 return -EINVAL;
62
63         rb = &d2d->rb[d2d->current_rb ^ 1];
64         sw = uterm_drm_mode_get_width(disp->current_mode);
65         sh = uterm_drm_mode_get_height(disp->current_mode);
66
67         tmp = x + buf->width;
68         if (tmp < x || x >= sw)
69                 return -EINVAL;
70         if (tmp > sw)
71                 width = sw - x;
72         else
73                 width = buf->width;
74
75         tmp = y + buf->height;
76         if (tmp < y || y >= sh)
77                 return -EINVAL;
78         if (tmp > sh)
79                 height = sh - y;
80         else
81                 height = buf->height;
82
83         dst = rb->map;
84         dst = &dst[y * rb->stride + x * 4];
85         src = buf->data;
86
87         while (height--) {
88                 memcpy(dst, src, 4 * width);
89                 dst += rb->stride;
90                 src += buf->stride;
91         }
92
93         return 0;
94 }
95
96 int uterm_drm2d_display_fake_blendv(struct uterm_display *disp,
97                                     const struct uterm_video_blend_req *req,
98                                     size_t num)
99 {
100         unsigned int tmp;
101         uint8_t *dst, *src;
102         unsigned int width, height, i, j;
103         unsigned int sw, sh;
104         uint_fast32_t r, g, b, out;
105         struct uterm_drm2d_rb *rb;
106         struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
107
108         if (!req)
109                 return -EINVAL;
110
111         rb = &d2d->rb[d2d->current_rb ^ 1];
112         sw = uterm_drm_mode_get_width(disp->current_mode);
113         sh = uterm_drm_mode_get_height(disp->current_mode);
114
115         for (j = 0; j < num; ++j, ++req) {
116                 if (!req->buf)
117                         continue;
118
119                 if (req->buf->format != UTERM_FORMAT_GREY)
120                         return -EOPNOTSUPP;
121
122                 tmp = req->x + req->buf->width;
123                 if (tmp < req->x || req->x >= sw)
124                         return -EINVAL;
125                 if (tmp > sw)
126                         width = sw - req->x;
127                 else
128                         width = req->buf->width;
129
130                 tmp = req->y + req->buf->height;
131                 if (tmp < req->y || req->y >= sh)
132                         return -EINVAL;
133                 if (tmp > sh)
134                         height = sh - req->y;
135                 else
136                         height = req->buf->height;
137
138                 dst = rb->map;
139                 dst = &dst[req->y * rb->stride + req->x * 4];
140                 src = req->buf->data;
141
142                 while (height--) {
143                         for (i = 0; i < width; ++i) {
144                                 /* Division by 255 (t /= 255) is done with:
145                                  *   t += 0x80
146                                  *   t = (t + (t >> 8)) >> 8
147                                  * This speeds up the computation by ~20% as the
148                                  * division is not needed. */
149                                 if (src[i] == 0) {
150                                         r = req->br;
151                                         g = req->bg;
152                                         b = req->bb;
153                                         out = (r << 16) | (g << 8) | b;
154                                 } else if (src[i] == 255) {
155                                         r = req->fr;
156                                         g = req->fg;
157                                         b = req->fb;
158                                         out = (r << 16) | (g << 8) | b;
159                                 } else {
160                                         r = req->fr * src[i] +
161                                             req->br * (255 - src[i]);
162                                         r += 0x80;
163                                         r = (r + (r >> 8)) >> 8;
164
165                                         g = req->fg * src[i] +
166                                             req->bg * (255 - src[i]);
167                                         g += 0x80;
168                                         g = (g + (g >> 8)) >> 8;
169
170                                         b = req->fb * src[i] +
171                                             req->bb * (255 - src[i]);
172                                         b += 0x80;
173                                         b = (b + (b >> 8)) >> 8;
174                                         out = (r << 16) | (g << 8) | b;
175                                 }
176
177                                 ((uint32_t*)dst)[i] = out;
178                         }
179                         dst += rb->stride;
180                         src += req->buf->stride;
181                 }
182         }
183
184         return 0;
185 }
186
187 int uterm_drm2d_display_fill(struct uterm_display *disp,
188                              uint8_t r, uint8_t g, uint8_t b,
189                              unsigned int x, unsigned int y,
190                              unsigned int width, unsigned int height)
191 {
192         unsigned int tmp, i;
193         uint8_t *dst;
194         unsigned int sw, sh;
195         struct uterm_drm2d_rb *rb;
196         struct uterm_drm2d_display *d2d = uterm_drm_display_get_data(disp);
197
198         rb = &d2d->rb[d2d->current_rb ^ 1];
199         sw = uterm_drm_mode_get_width(disp->current_mode);
200         sh = uterm_drm_mode_get_height(disp->current_mode);
201
202         tmp = x + width;
203         if (tmp < x || x >= sw)
204                 return -EINVAL;
205         if (tmp > sw)
206                 width = sw - x;
207         tmp = y + height;
208         if (tmp < y || y >= sh)
209                 return -EINVAL;
210         if (tmp > sh)
211                 height = sh - y;
212
213         dst = rb->map;
214         dst = &dst[y * rb->stride + x * 4];
215
216         while (height--) {
217                 for (i = 0; i < width; ++i)
218                         ((uint32_t*)dst)[i] = (r << 16) | (g << 8) | b;
219                 dst += rb->stride;
220         }
221
222         return 0;
223 }