blob: 0cbf85ec86bf443e695ec63dad3671c0fdc9934f [file] [log] [blame]
Zach Reiznerd847a7e2016-04-28 16:48:32 -07001/*
2 * Copyright 2015 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <ctype.h>
8
9#include "bs_drm.h"
10
11#define MAX_PLANES 4
12#define MAX_COMPONENTS 4
13
14static drmModeModeInfoPtr find_best_mode(int mode_count, drmModeModeInfoPtr modes)
15{
16 if (mode_count <= 0 || modes == NULL)
17 return NULL;
18
19 for (int m = 0; m < mode_count; m++)
20 if (modes[m].type & DRM_MODE_TYPE_PREFERRED)
21 return &modes[m];
22
23 return &modes[0];
24}
25
26static bool is_format_supported(uint32_t format_count, uint32_t *formats, uint32_t format)
27{
28 for (uint32_t i = 0; i < format_count; i++)
29 if (formats[i] == format)
30 return true;
31 return false;
32}
33
34static uint32_t find_overlay_plane(int fd, uint32_t crtc_id, uint32_t format)
35{
36 drmModeRes *res = drmModeGetResources(fd);
37 if (res == NULL) {
38 bs_debug_error("failed to get drm resources");
39 return 0;
40 }
41
42 uint32_t crtc_mask = 0;
43 for (int crtc_index = 0; crtc_index < res->count_crtcs; crtc_index++) {
44 if (res->crtcs[crtc_index] == crtc_id) {
45 crtc_mask = (1 << crtc_index);
46 break;
47 }
48 }
49 if (crtc_mask == 0) {
50 bs_debug_error("invalid crtc id %u", crtc_id);
51 drmModeFreeResources(res);
52 return 0;
53 }
54
55 drmModePlaneRes *plane_res = drmModeGetPlaneResources(fd);
56 if (plane_res == NULL) {
57 bs_debug_error("failed to get plane resources");
58 drmModeFreeResources(res);
59 return 0;
60 }
61
62 uint32_t plane_id = 0;
63 bool use_plane = false;
64 for (uint32_t plane_index = 0; !use_plane && plane_index < plane_res->count_planes;
65 plane_index++) {
66 drmModePlane *plane = drmModeGetPlane(fd, plane_res->planes[plane_index]);
67 if (plane == NULL) {
68 bs_debug_error("failed to get plane id %u", plane_res->planes[plane_index]);
69 continue;
70 }
71
72 if ((plane->possible_crtcs & crtc_mask) == 0 ||
73 !is_format_supported(plane->count_formats, plane->formats, format)) {
74 drmModeFreePlane(plane);
75 continue;
76 }
77
78 drmModeObjectPropertiesPtr props =
79 drmModeObjectGetProperties(fd, plane->plane_id, DRM_MODE_OBJECT_PLANE);
80 for (uint32_t prop_index = 0; prop_index < props->count_props; ++prop_index) {
81 drmModePropertyPtr prop = drmModeGetProperty(fd, props->props[prop_index]);
82 if (strcmp(prop->name, "type")) {
83 drmModeFreeProperty(prop);
84 continue;
85 }
86
87 uint64_t desired_value = 0;
88 bool has_value = false;
89 for (int enum_index = 0; enum_index < prop->count_enums; enum_index++) {
90 struct drm_mode_property_enum *penum = &prop->enums[enum_index];
91 if (!strcmp(penum->name, "Overlay")) {
92 desired_value = penum->value;
93 has_value = true;
94 break;
95 }
96 }
97 drmModeFreeProperty(prop);
98
99 if (has_value && desired_value == props->prop_values[prop_index])
100 use_plane = true;
101
102 break;
103 }
104 drmModeFreeObjectProperties(props);
105
106 if (use_plane)
107 plane_id = plane->plane_id;
108
109 drmModeFreePlane(plane);
110 }
111
112 drmModeFreePlaneResources(plane_res);
113 drmModeFreeResources(res);
114
115 return plane_id;
116}
117
118struct draw_format_component {
119 float rgb_coeffs[3];
120 float value_offset;
121 uint32_t horizontal_subsample_rate;
122 uint32_t vertical_subsample_rate;
123 uint32_t pixel_skip;
124 uint32_t plane_index;
125 uint32_t plane_offset;
126};
127
128struct draw_format {
129 uint32_t pixel_format;
130 const char *name;
131 size_t component_count;
132 struct draw_format_component components[MAX_COMPONENTS];
133};
134
135#define PIXEL_FORMAT_AND_NAME(x) GBM_FORMAT_##x, #x
136
137static const struct draw_format g_draw_formats[] = {
138 {
139 PIXEL_FORMAT_AND_NAME(NV12),
140 3,
141 {
142 { { 0.2567890625f, 0.50412890625f, 0.09790625f }, 16.0f, 1, 1, 1, 0, 0 },
143 { { -0.14822265625f, -0.2909921875f, 0.43921484375f }, 128.0f, 2, 2, 1, 1, 0 },
144 { { 0.43921484375f, -0.3677890625f, -0.07142578125f }, 128.0f, 2, 2, 1, 1, 1 },
145 },
146 },
147 {
148 PIXEL_FORMAT_AND_NAME(XRGB8888),
149 3,
150 {
151 { { 0.0f, 0.0f, 1.0f }, 0.0f, 1, 1, 4, 0, 0 },
152 { { 0.0f, 1.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 1 },
153 { { 1.0f, 0.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 2 },
154 },
155 },
156 {
157 PIXEL_FORMAT_AND_NAME(ARGB8888),
158 4,
159 {
160 { { 0.0f, 0.0f, 1.0f }, 0.0f, 1, 1, 4, 0, 0 },
161 { { 0.0f, 1.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 1 },
162 { { 1.0f, 0.0f, 0.0f }, 0.0f, 1, 1, 4, 0, 2 },
163 { { 0.0f, 0.0f, 0.0f }, 255.0f, 1, 1, 4, 0, 3 },
164 },
165 },
166};
167
168static uint8_t clampbyte(float f)
169{
170 if (f >= 255.0f)
171 return 255;
172 if (f <= 0.0f)
173 return 0;
174 return (uint8_t)f;
175}
176
177static uint8_t convert_color(const struct draw_format_component *comp, uint8_t r, uint8_t g,
178 uint8_t b)
179{
180 return clampbyte(comp->value_offset + r * comp->rgb_coeffs[0] + g * comp->rgb_coeffs[1] +
181 b * comp->rgb_coeffs[2]);
182}
183
184static const struct draw_format *get_draw_format(uint32_t pixel_format)
185{
186 for (size_t format_index = 0;
187 format_index < sizeof(g_draw_formats) / sizeof(g_draw_formats[0]); format_index++) {
188 const struct draw_format *format = &g_draw_formats[format_index];
189 if (format->pixel_format == pixel_format)
190 return format;
191 }
192
193 return NULL;
194}
195
196struct draw_plane {
197 uint32_t row_stride;
198 uint8_t *ptr;
199};
200
201static void unmmap_planes(struct gbm_bo *bo, size_t num_planes, struct draw_plane *planes)
202{
203 for (uint32_t plane_index = 0; plane_index < num_planes; plane_index++)
204 bs_dma_buf_unmmap_plane(bo, plane_index, planes[plane_index].ptr);
205}
206
207static size_t mmap_planes(struct gbm_bo *bo, struct draw_plane planes[MAX_PLANES])
208{
209 size_t num_planes = gbm_bo_get_num_planes(bo);
210 if (num_planes > MAX_PLANES) {
211 bs_debug_error("buffer object has unexpected number of planes %zu", num_planes);
212 return 0;
213 }
214
215 for (size_t plane_index = 0; plane_index < num_planes; plane_index++) {
216 struct draw_plane *plane = &planes[plane_index];
217 plane->row_stride = gbm_bo_get_plane_stride(bo, plane_index);
218 plane->ptr = bs_dma_buf_mmap_plane(bo, plane_index);
219 if (!plane->ptr) {
220 bs_debug_error("failed to mmap plane %zu of buffer object", plane_index);
221 unmmap_planes(bo, plane_index, planes);
222 return 0;
223 }
224 }
225
226 return true;
227}
228
229static bool draw_pattern(struct gbm_bo *bo, const struct draw_format *format)
230{
231 const uint32_t width = gbm_bo_get_width(bo);
232 const uint32_t height = gbm_bo_get_height(bo);
233 const uint32_t striph = height / 4;
234
235 struct draw_plane planes[MAX_PLANES];
236 size_t num_planes = mmap_planes(bo, planes);
237 if (num_planes == 0) {
238 bs_debug_error("failed to prepare to draw pattern to buffer object");
239 return false;
240 }
241
242 for (uint32_t s = 0; s < 4; s++) {
243 uint8_t r = 0, g = 0, b = 0;
244 switch (s) {
245 case 0:
246 r = g = b = 1;
247 break;
248 case 1:
249 r = 1;
250 break;
251 case 2:
252 g = 1;
253 break;
254 case 3:
255 b = 1;
256 break;
257 default:
258 r = g = b = 0;
259 break;
260 }
261 for (uint32_t y = s * striph; y < (s + 1) * striph; y++) {
262 uint8_t *rows[MAX_COMPONENTS] = { 0 };
263 for (size_t comp_index = 0; comp_index < format->component_count;
264 comp_index++) {
265 const struct draw_format_component *comp =
266 &format->components[comp_index];
267 struct draw_plane *plane = &planes[comp->plane_index];
268 rows[comp_index] =
269 plane->ptr + comp->plane_offset +
270 plane->row_stride * (y / comp->vertical_subsample_rate);
271 }
272 for (uint32_t x = 0; x < width; x++) {
273 const float i = (float)x / (float)width * 256.0f;
274 for (size_t comp_index = 0; comp_index < format->component_count;
275 comp_index++) {
276 const struct draw_format_component *comp =
277 &format->components[comp_index];
278 if ((y % comp->vertical_subsample_rate) == 0 &&
279 (x % comp->horizontal_subsample_rate) == 0)
280 *(rows[comp_index] + x * comp->pixel_skip) =
281 convert_color(comp, r * i, g * i, b * i);
282 }
283 }
284 }
285 }
286
287 unmmap_planes(bo, num_planes, planes);
288 return true;
289}
290
291int main(int argc, char **argv)
292{
293 assert(sizeof(g_draw_formats) / sizeof(g_draw_formats[0]) > 0);
294 const struct draw_format *plane_format = &g_draw_formats[0];
295 if (argc == 2) {
296 char *format_str = argv[1];
297 if (strlen(format_str) == 4) {
298 plane_format = get_draw_format(*(uint32_t *)format_str);
299 }
300 else {
301 plane_format = 0;
302 for (size_t format_index = 0;
303 format_index < sizeof(g_draw_formats) / sizeof(g_draw_formats[0]);
304 format_index++) {
305 const struct draw_format *format = &g_draw_formats[format_index];
306 if (!strcmp(format_str, format->name)) {
307 plane_format = format;
308 break;
309 }
310 }
311 }
312
313 if (plane_format == NULL) {
314 printf("plane format %s is not recognized\n", format_str);
315 return false;
316 }
317 }
318
319 printf("Using plane format %s (%4.4s)\n", plane_format->name,
320 (char *)&plane_format->pixel_format);
321
322 drmModeConnector *connector;
323 struct bs_drm_pipe pipe = { 0 };
324 struct bs_drm_pipe_plumber *plumber = bs_drm_pipe_plumber_new();
325 bs_drm_pipe_plumber_connector_ranks(plumber, bs_drm_connectors_internal_rank);
326 bs_drm_pipe_plumber_connector_ptr(plumber, &connector);
327 if (!bs_drm_pipe_plumber_make(plumber, &pipe)) {
328 bs_debug_error("failed to make pipe");
329 return 1;
330 }
331 bs_drm_pipe_plumber_destroy(&plumber);
332
333 drmModeModeInfo *mode_ptr = find_best_mode(connector->count_modes, connector->modes);
334 if (!mode_ptr) {
335 bs_debug_error("failed to find preferred mode");
336 return 1;
337 }
338 drmModeModeInfo mode = *mode_ptr;
339 drmModeFreeConnector(connector);
340 printf("Using mode %s\n", mode.name);
341
342 uint32_t plane_id = find_overlay_plane(pipe.fd, pipe.crtc_id, plane_format->pixel_format);
343 if (plane_id == 0) {
344 bs_debug_error("failed to find overlay plane");
345 return 1;
346 }
347
348 printf("Using CRTC:%u ENCODER:%u CONNECTOR:%u PLANE:%u\n", pipe.crtc_id, pipe.encoder_id,
349 pipe.connector_id, plane_id);
350
351 struct gbm_device *gbm = gbm_create_device(pipe.fd);
352 if (!gbm) {
353 bs_debug_error("failed to create gbm");
354 return 1;
355 }
356
357 struct gbm_bo *bg_bo = gbm_bo_create(gbm, mode.hdisplay, mode.vdisplay, GBM_FORMAT_XRGB8888,
358 GBM_BO_USE_SCANOUT | GBM_BO_USE_LINEAR);
359 if (!bg_bo) {
360 bs_debug_error("failed to create background buffer ojbect");
361 return 1;
362 }
363
364 void *bo_ptr = bs_dma_buf_mmap_plane(bg_bo, 0);
365 if (bo_ptr == NULL) {
366 bs_debug_error("failed to mmap background buffer object");
367 return 1;
368 }
369 memset(bo_ptr, 0xff, gbm_bo_get_height(bg_bo) * gbm_bo_get_stride(bg_bo));
370 bs_dma_buf_unmmap_plane(bg_bo, 0, bo_ptr);
371
372 printf("Creating buffer %ux%u\n", mode.hdisplay, mode.vdisplay);
373 struct gbm_bo *bo =
374 gbm_bo_create(gbm, mode.hdisplay, mode.vdisplay, plane_format->pixel_format,
375 GBM_BO_USE_SCANOUT | GBM_BO_USE_LINEAR);
376 if (!bo) {
377 bs_debug_error("failed to create buffer object");
378 return 1;
379 }
380
381 uint32_t crtc_fb_id = bs_drm_fb_create_gbm(bg_bo);
382 if (!crtc_fb_id) {
383 bs_debug_error("failed to create frame buffer for buffer object");
384 return 1;
385 }
386
387 uint32_t plane_fb_id = bs_drm_fb_create_gbm(bo);
388 if (!plane_fb_id) {
389 bs_debug_error("failed to create plane frame buffer for buffer object");
390 return 1;
391 }
392
393 if (!draw_pattern(bo, plane_format)) {
394 bs_debug_error("failed to draw pattern to buffer object");
395 return 1;
396 }
397
398 int ret =
399 drmModeSetCrtc(pipe.fd, pipe.crtc_id, crtc_fb_id, 0, 0, &pipe.connector_id, 1, &mode);
400 if (ret < 0) {
401 bs_debug_error("Could not set mode on CRTC %d %s", pipe.crtc_id, strerror(errno));
402 return 1;
403 }
404
405 ret = drmModeSetPlane(pipe.fd, plane_id, pipe.crtc_id, plane_fb_id, 0, 0, 0, mode.hdisplay,
406 mode.vdisplay, 0, 0, mode.hdisplay << 16, mode.vdisplay << 16);
407
408 if (ret) {
409 bs_debug_error("failed to set plane %d", ret);
410 return 1;
411 }
412
413 sleep(5);
414
415 ret = drmModeSetCrtc(pipe.fd, pipe.crtc_id, 0, 0, 0, NULL, 0, NULL);
416 if (ret < 0) {
417 bs_debug_error("Could not disable CRTC %d %s", pipe.crtc_id, strerror(errno));
418 return 1;
419 }
420
421 drmModeRmFB(pipe.fd, plane_fb_id);
422 drmModeRmFB(pipe.fd, crtc_fb_id);
423 gbm_bo_destroy(bo);
424 gbm_bo_destroy(bg_bo);
425 gbm_device_destroy(gbm);
426 close(pipe.fd);
427
428 return 0;
429}