blob: 93589d283e931e5acff0809eecac7aac0ddc4e3a [file] [log] [blame]
Yalong Liu1df84372018-01-24 17:10:12 +08001/*
2 * Copyright 2017 The Chromium OS Authors. All rights reserved.
3
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "bs_drm.h"
9
10struct draw_format_component {
11 float rgb_coeffs[3];
12 float value_offset;
13 uint32_t horizontal_subsample_rate;
14 uint32_t vertical_subsample_rate;
15 uint32_t byte_skip;
16 uint32_t plane_index;
17 uint32_t plane_offset;
18};
19
20#define MAX_COMPONENTS 4
21struct bs_draw_format {
22 uint32_t pixel_format;
23 const char *name;
24 size_t component_count;
25 struct draw_format_component components[MAX_COMPONENTS];
26};
27
28struct draw_data {
29 uint32_t x;
30 uint32_t y;
31 uint32_t w;
32 uint32_t h;
33 float progress;
34 uint8_t out_color[MAX_COMPONENTS];
35};
36
37struct draw_data_lines {
38 struct draw_data base;
39 bool color_olive;
40 uint32_t interval;
41 uint32_t stop;
42};
43
44typedef void (*compute_color_t)(struct draw_data *data);
45
46#define PIXEL_FORMAT_AND_NAME(x) GBM_FORMAT_##x, #x
47static const struct bs_draw_format bs_draw_formats[] = {
48 {
49 PIXEL_FORMAT_AND_NAME(ABGR8888),
50 4,
51 {
52 { { 1.0f, 0.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 0 },
53 { { 0.0f, 1.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 1 },
54 { { 0.0f, 0.0f, 1.0f }, 0.0f, 1, 1, 4, 0, 2 },
55 { { 0.0f, 0.0f, 0.0f }, 255.0f, 1, 1, 4, 0, 3 },
56 },
57 },
58 {
59 PIXEL_FORMAT_AND_NAME(ARGB8888),
60 4,
61 {
62 { { 0.0f, 0.0f, 1.0f }, 0.0f, 1, 1, 4, 0, 0 },
63 { { 0.0f, 1.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 1 },
64 { { 1.0f, 0.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 2 },
65 { { 0.0f, 0.0f, 0.0f }, 255.0f, 1, 1, 4, 0, 3 },
66 },
67 },
68 {
69 PIXEL_FORMAT_AND_NAME(BGR888),
70 3,
71 {
72 { { 1.0f, 0.0f, 0.0f }, 0.0f, 1, 1, 3, 0, 0 },
73 { { 0.0f, 1.0f, 0.0f }, 0.0f, 1, 1, 3, 0, 1 },
74 { { 0.0f, 0.0f, 1.0f }, 0.0f, 1, 1, 3, 0, 2 },
75 },
76 },
77 {
78 PIXEL_FORMAT_AND_NAME(NV12),
79 3,
80 {
81 { { 0.2567890625f, 0.50412890625f, 0.09790625f }, 16.0f, 1, 1, 1, 0, 0 },
82 { { -0.14822265625f, -0.2909921875f, 0.43921484375f }, 128.0f, 2, 2, 2, 1, 0 },
83 { { 0.43921484375f, -0.3677890625f, -0.07142578125f }, 128.0f, 2, 2, 2, 1, 1 },
84 },
85 },
86 {
87 PIXEL_FORMAT_AND_NAME(NV21),
88 3,
89 {
90 { { 0.2567890625f, 0.50412890625f, 0.09790625f }, 16.0f, 1, 1, 1, 0, 0 },
91 { { 0.43921484375f, -0.3677890625f, -0.07142578125f }, 128.0f, 2, 2, 2, 1, 0 },
92 { { -0.14822265625f, -0.2909921875f, 0.43921484375f }, 128.0f, 2, 2, 2, 1, 1 },
93 },
94 },
95 {
96 PIXEL_FORMAT_AND_NAME(RGB888),
97 3,
98 {
99 { { 0.0f, 0.0f, 1.0f }, 0.0f, 1, 1, 3, 0, 0 },
100 { { 0.0f, 1.0f, 0.0f }, 0.0f, 1, 1, 3, 0, 1 },
101 { { 1.0f, 0.0f, 0.0f }, 0.0f, 1, 1, 3, 0, 2 },
102 },
103 },
104 {
105 PIXEL_FORMAT_AND_NAME(XBGR8888),
106 3,
107 {
108 { { 1.0f, 0.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 0 },
109 { { 0.0f, 1.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 1 },
110 { { 0.0f, 0.0f, 1.0f }, 0.0f, 1, 1, 4, 0, 2 },
111 },
112 },
113 {
114 PIXEL_FORMAT_AND_NAME(XRGB8888),
115 3,
116 {
117 { { 0.0f, 0.0f, 1.0f }, 0.0f, 1, 1, 4, 0, 0 },
118 { { 0.0f, 1.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 1 },
119 { { 1.0f, 0.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 2 },
120 },
121 },
122 {
123 PIXEL_FORMAT_AND_NAME(UYVY),
124 3,
125 {
126 { { -0.14822265625f, -0.2909921875f, 0.43921484375f }, 128.0f, 2, 1, 4, 0, 0 },
127 { { 0.2567890625f, 0.50412890625f, 0.09790625f }, 16.0f, 1, 1, 2, 0, 1 },
128 { { 0.43921484375f, -0.3677890625f, -0.07142578125f }, 128.0f, 2, 1, 4, 0, 2 },
129 },
130 },
131 {
132 PIXEL_FORMAT_AND_NAME(YUYV),
133 3,
134 {
135 { { 0.2567890625f, 0.50412890625f, 0.09790625f }, 16.0f, 1, 1, 2, 0, 0 },
136 { { -0.14822265625f, -0.2909921875f, 0.43921484375f }, 128.0f, 2, 1, 4, 0, 1 },
137 { { 0.43921484375f, -0.3677890625f, -0.07142578125f }, 128.0f, 2, 1, 4, 0, 3 },
138 },
139 },
140 {
141 PIXEL_FORMAT_AND_NAME(YVU420),
142 3,
143 {
144 { { 0.2567890625f, 0.50412890625f, 0.09790625f }, 16.0f, 1, 1, 1, 0, 0 },
145 { { 0.43921484375f, -0.3677890625f, -0.07142578125f }, 128.0f, 2, 2, 1, 1, 0 },
146 { { -0.14822265625f, -0.2909921875f, 0.43921484375f }, 128.0f, 2, 2, 1, 2, 0 },
147 },
148 },
149};
150
151struct draw_plane {
152 uint32_t row_stride;
153 uint8_t *ptr;
154 void *map_data;
155};
156
157static uint8_t clampbyte(float f)
158{
159 if (f >= 255.0f)
160 return 255;
161 if (f <= 0.0f)
162 return 0;
163 return (uint8_t)f;
164}
165
166uint8_t static convert_color(const struct draw_format_component *comp, uint8_t r, uint8_t g,
167 uint8_t b)
168{
169 return clampbyte(comp->value_offset + r * comp->rgb_coeffs[0] + g * comp->rgb_coeffs[1] +
170 b * comp->rgb_coeffs[2]);
171}
172
173static void unmmap_planes(struct bs_mapper *mapper, struct gbm_bo *bo, size_t num_planes,
174 struct draw_plane *planes)
175{
176 for (uint32_t plane_index = 0; plane_index < num_planes; plane_index++)
177 bs_mapper_unmap(mapper, bo, planes[plane_index].map_data);
178}
179
180static size_t mmap_planes(struct bs_mapper *mapper, struct gbm_bo *bo,
181 struct draw_plane planes[GBM_MAX_PLANES])
182{
183 size_t num_planes = gbm_bo_get_num_planes(bo);
184 for (size_t plane_index = 0; plane_index < num_planes; plane_index++) {
185 struct draw_plane *plane = &planes[plane_index];
186 plane->row_stride = gbm_bo_get_plane_stride(bo, plane_index);
187 plane->ptr = bs_mapper_map(mapper, bo, plane_index, &plane->map_data);
188 if (plane->ptr == MAP_FAILED) {
189 bs_debug_error("failed to mmap plane %zu of buffer object", plane_index);
190 unmmap_planes(mapper, bo, plane_index, planes);
191 return 0;
192 }
193 }
194
195 return num_planes;
196}
197
198static bool draw_color(struct bs_mapper *mapper, struct gbm_bo *bo,
199 const struct bs_draw_format *format, struct draw_data *data,
200 compute_color_t compute_color_fn)
201{
202 uint8_t *ptr, *converted_colors[MAX_COMPONENTS];
203 struct draw_plane planes[GBM_MAX_PLANES];
204 uint32_t height = data->h = gbm_bo_get_height(bo);
205 uint32_t width = data->w = gbm_bo_get_width(bo);
206
207 size_t num_planes = mmap_planes(mapper, bo, planes);
208 if (num_planes == 0) {
209 bs_debug_error("failed to prepare to draw pattern to buffer object");
210 return false;
211 }
212
213 for (size_t comp_index = 0; comp_index < format->component_count; comp_index++) {
214 converted_colors[comp_index] = calloc(width * height, sizeof(uint8_t));
215 assert(converted_colors[comp_index]);
216 }
217
218 for (uint32_t y = 0; y < height; y++) {
219 data->y = y;
220 for (uint32_t x = 0; x < width; x++) {
221 data->x = x;
222 compute_color_fn(data);
223 for (size_t comp_index = 0; comp_index < format->component_count;
224 comp_index++) {
225 const struct draw_format_component *comp =
226 &format->components[comp_index];
227 ptr = converted_colors[comp_index] + width * y + x;
228 *ptr = convert_color(comp, data->out_color[2], data->out_color[1],
229 data->out_color[0]);
230 }
231 }
232 }
233
234 uint32_t color, samples, offset;
235 uint8_t *rows[MAX_COMPONENTS] = { 0 };
236 for (size_t comp_index = 0; comp_index < format->component_count; comp_index++) {
237 const struct draw_format_component *comp = &format->components[comp_index];
238 struct draw_plane *plane = &planes[comp->plane_index];
239 for (uint32_t y = 0; y < height / comp->vertical_subsample_rate; y++) {
240 rows[comp_index] = plane->ptr + comp->plane_offset + plane->row_stride * y;
241 for (uint32_t x = 0; x < width / comp->horizontal_subsample_rate; x++) {
242 offset = color = samples = 0;
243 for (uint32_t j = 0; j < comp->vertical_subsample_rate; j++) {
244 offset = (y * comp->vertical_subsample_rate + j) * width +
245 x * comp->horizontal_subsample_rate;
246 for (uint32_t i = 0; i < comp->horizontal_subsample_rate;
247 i++) {
248 color += converted_colors[comp_index][offset];
249 samples++;
250 offset++;
251 }
252 }
253
254 *(rows[comp_index] + x * comp->byte_skip) = color / samples;
255 }
256 }
257 }
258
259 unmmap_planes(mapper, bo, num_planes, planes);
260 for (size_t comp_index = 0; comp_index < format->component_count; comp_index++) {
261 free(converted_colors[comp_index]);
262 }
263
264 return true;
265}
266
267static void compute_stripe(struct draw_data *data)
268{
269 const uint32_t striph = data->h / 4;
270 const uint32_t s = data->y / striph;
271 uint8_t r = 0, g = 0, b = 0;
272 switch (s) {
273 case 0:
274 r = g = b = 1;
275 break;
276 case 1:
277 r = 1;
278 break;
279 case 2:
280 g = 1;
281 break;
282 case 3:
283 b = 1;
284 break;
285 default:
286 r = g = b = 0;
287 break;
288 }
289
290 const float i = (float)data->x / (float)data->w * 256.0f;
291 data->out_color[0] = b * i;
292 data->out_color[1] = g * i;
293 data->out_color[2] = r * i;
294 data->out_color[3] = 0;
295}
296
297static void compute_ellipse(struct draw_data *data)
298{
299 float xratio = ((int)data->x - (int)data->w / 2) / ((float)(data->w / 2));
300 float yratio = ((int)data->y - (int)data->h / 2) / ((float)(data->h / 2));
301
302 // If a point is on or inside an ellipse, num <= 1.
303 float num = xratio * xratio + yratio * yratio;
304 uint32_t g = 255 * num;
305
306 if (g < 256) {
307 memset(data->out_color, 0, 4);
308 data->out_color[2] = 0xFF;
309 data->out_color[1] = g;
310 } else {
311 memset(data->out_color, (uint8_t)(data->progress * 255), 4);
312 }
313}
314
315static void compute_cursor(struct draw_data *data)
316{
317 // A white triangle pointing right
318 if (data->y > data->x / 2 && data->y < (data->w - data->x / 2))
319 memset(data->out_color, 0xFF, 4);
320 else
321 memset(data->out_color, 0, 4);
322}
323
324static void compute_lines(struct draw_data *data)
325{
326 struct draw_data_lines *line_data = (struct draw_data_lines *)data;
327 // horizontal stripes on first vertical half, vertical stripes on next half
328 if (line_data->base.y < (line_data->base.h / 2)) {
329 if (line_data->base.x == 0) {
330 line_data->color_olive = false;
331 line_data->interval = 5;
332 line_data->stop = line_data->base.x + line_data->interval;
333 } else if (line_data->base.x >= line_data->stop) {
334 if (line_data->color_olive)
335 line_data->interval += 5;
336
337 line_data->stop += line_data->interval;
338 line_data->color_olive = !line_data->color_olive;
339 }
340 } else {
341 if (line_data->base.y == (line_data->base.h / 2)) {
342 line_data->color_olive = false;
343 line_data->interval = 10;
344 line_data->stop = line_data->base.y + line_data->interval;
345 } else if (line_data->base.y >= line_data->stop) {
346 if (line_data->color_olive)
347 line_data->interval += 5;
348
349 line_data->stop += line_data->interval;
350 line_data->color_olive = !line_data->color_olive;
351 }
352 }
353 if (line_data->color_olive) {
354 // yellowish green color
355 line_data->base.out_color[0] = 0;
356 line_data->base.out_color[1] = 128;
357 line_data->base.out_color[2] = 128;
358 line_data->base.out_color[3] = 0;
359 } else {
360 // fuchsia
361 line_data->base.out_color[0] = 255;
362 line_data->base.out_color[1] = 0;
363 line_data->base.out_color[2] = 255;
364 line_data->base.out_color[3] = 0;
365 }
366}
367
368bool bs_draw_stripe(struct bs_mapper *mapper, struct gbm_bo *bo,
369 const struct bs_draw_format *format)
370{
371 struct draw_data data = { 0 };
372 return draw_color(mapper, bo, format, &data, compute_stripe);
373}
374
375bool bs_draw_ellipse(struct bs_mapper *mapper, struct gbm_bo *bo,
376 const struct bs_draw_format *format, float progress)
377{
378 struct draw_data data = { 0 };
379 data.progress = progress;
380 return draw_color(mapper, bo, format, &data, compute_ellipse);
381}
382
383bool bs_draw_cursor(struct bs_mapper *mapper, struct gbm_bo *bo,
384 const struct bs_draw_format *format)
385{
386 struct draw_data data = { 0 };
387 return draw_color(mapper, bo, format, &data, compute_cursor);
388}
389
390bool bs_draw_lines(struct bs_mapper *mapper, struct gbm_bo *bo, const struct bs_draw_format *format)
391{
392 struct draw_data_lines line_data = { { 0 } };
393 return draw_color(mapper, bo, format, &line_data.base, compute_lines);
394}
395
396const struct bs_draw_format *bs_get_draw_format(uint32_t pixel_format)
397{
398 for (size_t format_index = 0; format_index < BS_ARRAY_LEN(bs_draw_formats);
399 format_index++) {
400 const struct bs_draw_format *format = &bs_draw_formats[format_index];
401 if (format->pixel_format == pixel_format)
402 return format;
403 }
404
405 return NULL;
406}
407
408const struct bs_draw_format *bs_get_draw_format_from_name(const char *str)
409{
410 for (size_t format_index = 0; format_index < BS_ARRAY_LEN(bs_draw_formats);
411 format_index++) {
412 const struct bs_draw_format *format = &bs_draw_formats[format_index];
413 if (!strcmp(str, format->name))
414 return format;
415 }
416
417 return NULL;
418}
419
420uint32_t bs_get_pixel_format(const struct bs_draw_format *format)
421{
422 assert(format);
423 return format->pixel_format;
424}
425
426const char *bs_get_format_name(const struct bs_draw_format *format)
427{
428 assert(format);
429 return format->name;
430}
431
432bool bs_parse_draw_format(const char *str, const struct bs_draw_format **format)
433{
434 if (strlen(str) == 4) {
435 const struct bs_draw_format *bs_draw_format = bs_get_draw_format(*(uint32_t *)str);
436 if (bs_draw_format) {
437 *format = bs_draw_format;
438 return true;
439 }
440 } else {
441 const struct bs_draw_format *bs_draw_format = bs_get_draw_format_from_name(str);
442 if (bs_draw_format) {
443 *format = bs_draw_format;
444 return true;
445 }
446 }
447
448 bs_debug_error("format %s is not recognized\n", str);
449 return false;
450}