display-wayland: Wayland backend implementation
[glsdk/omapdrmtest.git] / util / util.c
1 /*
2  * Copyright (C) 2011 Texas Instruments
3  * Author: Rob Clark <rob.clark@linaro.org>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 as published by
7  * the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
22 #include "util.h"
24 #include <drm.h>
26 /* Dynamic debug. */
27 int debug = 0;
29 void disp_kms_usage(void);
30 struct display * disp_kms_open(int argc, char **argv);
32 #ifdef HAVE_X11
33 void disp_x11_usage(void);
34 struct display * disp_x11_open(int argc, char **argv);
35 void disp_x11_close(struct display *disp);
36 #endif
38 #ifdef HAVE_KMSCUBE
39 void disp_kmscube_usage(void);
40 struct display * disp_kmscube_open(int argc, char **argv);
41 #endif
43 #ifdef HAVE_WAYLAND
44 void disp_wayland_usage(void);
45 struct display *disp_wayland_open(int argc, char **argv);
46 #endif
48 void
49 disp_usage(void)
50 {
51         MSG("Generic Display options:");
52         MSG("\t--debug\tTurn on debug messages.");
53         MSG("\t--fps <fps>\tforce playback rate (0 means \"do not force\")");
54         MSG("\t--no-post\tDo not post buffers (disables screen updates) for benchmarking. Rate can still be controlled.");
56 #ifdef HAVE_X11
57         disp_x11_usage();
58 #endif
59 #ifdef HAVE_KMSCUBE
60         disp_kmscube_usage();
61 #endif
62 #ifdef HAVE_WAYLAND
63         disp_wayland_usage();
64 #endif
65         disp_kms_usage();
66 }
68 static int
69 empty_post_buffer(struct display *disp, struct buffer *buf)
70 {
71         return 0;
72 }
74 static int
75 empty_post_vid_buffer(struct display *disp, struct buffer *buf,
76                         uint32_t x, uint32_t y, uint32_t w, uint32_t h)
77 {
78         return 0;
79 }
81 struct display *
82 disp_open(int argc, char **argv)
83 {
84         struct display *disp;
85         int i, fps = 0, no_post = 0;
87         for (i = 1; i < argc; i++) {
88                 if (!argv[i]) {
89                         continue;
90                 }
91                 if (!strcmp("--debug", argv[i])) {
92                         debug = 1;
93                         MSG("Enabling dynamic debug.");
94                         argv[i] = NULL;
96                 } else if (!strcmp("--fps", argv[i])) {
97                         argv[i++] = NULL;
99                         if (sscanf(argv[i], "%d", &fps) != 1) {
100                                 ERROR("invalid arg: %s", argv[i]);
101                                 return NULL;
102                         }
104                         MSG("Forcing playback rate at %d fps.", fps);
105                         argv[i] = NULL;
107                 } else if (!strcmp("--no-post", argv[i])) {
108                         MSG("Disabling buffers posting.");
109                         no_post = 1;
110                         argv[i] = NULL;
111                 }
112         }
114 #ifdef HAVE_X11
115         disp = disp_x11_open(argc, argv);
116         if (disp)
117                 goto out;
118 #endif
119 #ifdef HAVE_KMSCUBE
120         disp = disp_kmscube_open(argc, argv);
121         if (disp)
122                 goto out;
123 #endif
124 #ifdef HAVE_WAYLAND
125         disp = disp_wayland_open(argc, argv);
126         if (disp)
127                 goto out;
128 #endif
130         disp = disp_kms_open(argc, argv);
132         if (!disp) {
133                 ERROR("unable to create display");
134                 return NULL;
135         }
137 out:
138         disp->rtctl.fps = fps;
140         /* If buffer posting is disabled from command line, override post
141          * functions with empty ones. */
142         if (no_post) {
143                 disp->post_buffer = empty_post_buffer;
144                 disp->post_vid_buffer = empty_post_vid_buffer;
145         }
147         return disp;
150 struct buffer **
151 disp_get_vid_buffers(struct display *disp, uint32_t n,
152                 uint32_t fourcc, uint32_t w, uint32_t h)
154         struct buffer **buffers;
155         unsigned int i;
157         buffers = disp->get_vid_buffers(disp, n, fourcc, w, h);
158         if (buffers) {
159                 /* if allocation succeeded, store in the unlocked
160                  * video buffer list
161                  */
162                 list_init(&disp->unlocked);
163                 for (i = 0; i < n; i++)
164                         list_add(&buffers[i]->unlocked, &disp->unlocked);
165         }
167         return buffers;
170 void
171 disp_free_buffers(struct display *disp, uint32_t n)
173         disp->disp_free_buf(disp, n);
176 struct buffer *
177 disp_get_vid_buffer(struct display *disp)
179         struct buffer *buf = NULL;
180         if (!list_is_empty(&disp->unlocked)) {
181                 buf = list_last_entry(&disp->unlocked, struct buffer, unlocked);
182                 list_del(&buf->unlocked);
184                 /* barrier.. if we are using GPU blitting, we need to make sure
185                  * that the GPU is finished:
186                  */
187                 omap_bo_cpu_prep(buf->bo[0], OMAP_GEM_WRITE);
188                 omap_bo_cpu_fini(buf->bo[0], OMAP_GEM_WRITE);
189         }
190         return buf;
193 void
194 disp_put_vid_buffer(struct display *disp, struct buffer *buf)
196         list_add(&buf->unlocked, &disp->unlocked);
199 /* Maintain playback rate if fps > 0. */
200 static void maintain_playback_rate(struct rate_control *p)
202         long usecs_since_last_frame;
203         int usecs_between_frames, usecs_to_sleep;
205         if (p->fps <= 0)
206                 return;
208         usecs_between_frames = 1000000 / p->fps;
209         usecs_since_last_frame = mark(&p->last_frame_mark);
210         DBG("fps: %.02f", 1000000.0 / usecs_since_last_frame);
211         usecs_to_sleep = usecs_between_frames - usecs_since_last_frame + p->usecs_to_sleep;
213         if (usecs_to_sleep < 0)
214                 usecs_to_sleep = 0;
216         /* mark() has a limitation that >1s time deltas will make the whole
217          * loop diverge. Workaround that limitation by clamping our desired sleep time
218          * to a maximum. TODO: Remove when mark() is in better shape. */
219         if (usecs_to_sleep >= 1000000)
220                 usecs_to_sleep = 999999;
222         /* We filter a bit our rate adaptation, to avoid being too "choppy".
223          * Adjust the "alpha" value as needed. */
224         p->usecs_to_sleep = ((67 * p->usecs_to_sleep) + (33 * usecs_to_sleep)) / 100;
226         if (p->usecs_to_sleep >= 1) {
227                 DBG("sleeping %dus", p->usecs_to_sleep);
228                 usleep(p->usecs_to_sleep);
229         }
232 /* flip to / post the specified buffer */
233 int
234 disp_post_buffer(struct display *disp, struct buffer *buf)
236         int ret;
238         ret = disp->post_buffer(disp, buf);
239         if(!ret)
240                 maintain_playback_rate(&disp->rtctl);
241         return ret;
244 /* flip to / post the specified video buffer */
245 int
246 disp_post_vid_buffer(struct display *disp, struct buffer *buf,
247                 uint32_t x, uint32_t y, uint32_t w, uint32_t h)
249         int ret;
251         ret = disp->post_vid_buffer(disp, buf, x, y, w, h);
252         if(!ret)
253                 maintain_playback_rate(&disp->rtctl);
254         return ret;
257 struct buffer *
258 disp_get_fb(struct display *disp)
260         struct buffer **bufs = disp_get_buffers(disp, 1);
261         if (!bufs)
262                 return NULL;
263         fill(bufs[0], 42);
264         disp_post_buffer(disp, bufs[0]);
265         return bufs[0];
269 int
270 check_args(int argc, char **argv)
272         int i;
273         for (i = 1; i < argc; i++) {
274                 if (argv[i]) {
275                         ERROR("invalid arg: %s", argv[i]);
276                         return -1;
277                 }
278         }
279         return 0;
282 /* stolen from modetest.c */
283 static void
284 fillRGB4(char *virtual, int n, int width, int height, int stride)
286         int i, j;
287         /* paint the buffer with colored tiles */
288         for (j = 0; j < height; j++) {
289                 uint32_t *fb_ptr = (uint32_t*)((char*)virtual + j * stride);
290                 for (i = 0; i < width; i++) {
291                         div_t d = div(n+i+j, width);
292                         fb_ptr[i] =
293                                         0x00130502 * (d.quot >> 6) +
294                                         0x000a1120 * (d.rem >> 6);
295                 }
296         }
300 /* swap these for big endian.. */
301 #define RED   2
302 #define GREEN 1
303 #define BLUE  0
305 static void
306 fill420(unsigned char *y, unsigned char *u, unsigned char *v,
307                 int cs /*chroma pixel stride */,
308                 int n, int width, int height, int stride)
310         int i, j;
312         /* paint the buffer with colored tiles, in blocks of 2x2 */
313         for (j = 0; j < height; j+=2) {
314                 unsigned char *y1p = y + j * stride;
315                 unsigned char *y2p = y1p + stride;
316                 unsigned char *up = u + (j/2) * stride * cs / 2;
317                 unsigned char *vp = v + (j/2) * stride * cs / 2;
319                 for (i = 0; i < width; i+=2) {
320                         div_t d = div(n+i+j, width);
321                         uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
322                         unsigned char *rgbp = (unsigned char *)&rgb;
323                         unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]);
325                         *(y2p++) = *(y1p++) = y;
326                         *(y2p++) = *(y1p++) = y;
328                         *up = (rgbp[BLUE] - y) * 0.565 + 128;
329                         *vp = (rgbp[RED] - y) * 0.713 + 128;
330                         up += cs;
331                         vp += cs;
332                 }
333         }
336 static void
337 fill422(unsigned char *virtual, int n, int width, int height, int stride)
339         int i, j;
340         /* paint the buffer with colored tiles */
341         for (j = 0; j < height; j++) {
342                 uint8_t *ptr = (uint8_t*)((char*)virtual + j * stride);
343                 for (i = 0; i < width; i++) {
344                         div_t d = div(n+i+j, width);
345                         uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
346                         unsigned char *rgbp = (unsigned char *)&rgb;
347                         unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]);
349                         *(ptr++) = y;
350                         *(ptr++) = (rgbp[BLUE] - y) * 0.565 + 128;
351                         *(ptr++) = y;
352                         *(ptr++) = (rgbp[RED] - y) * 0.713 + 128;
353                 }
354         }
358 void
359 fill(struct buffer *buf, int n)
361         int i;
363         for (i = 0; i < buf->nbo; i++)
364                 omap_bo_cpu_prep(buf->bo[i], OMAP_GEM_WRITE);
366         switch(buf->fourcc) {
367         case 0: {
368                 assert(buf->nbo == 1);
369                 fillRGB4(omap_bo_map(buf->bo[0]), n,
370                                 buf->width, buf->height, buf->pitches[0]);
371                 break;
372         }
373         case FOURCC('Y','U','Y','V'): {
374                 assert(buf->nbo == 1);
375                 fill422(omap_bo_map(buf->bo[0]), n,
376                                 buf->width, buf->height, buf->pitches[0]);
377                 break;
378         }
379         case FOURCC('N','V','1','2'): {
380                 unsigned char *y, *u, *v;
381                 assert(buf->nbo == 2);
382                 y = omap_bo_map(buf->bo[0]);
383                 u = omap_bo_map(buf->bo[1]);
384                 v = u + 1;
385                 fill420(y, u, v, 2, n, buf->width, buf->height, buf->pitches[0]);
386                 break;
387         }
388         case FOURCC('I','4','2','0'): {
389                 unsigned char *y, *u, *v;
390                 assert(buf->nbo == 3);
391                 y = omap_bo_map(buf->bo[0]);
392                 u = omap_bo_map(buf->bo[1]);
393                 v = omap_bo_map(buf->bo[2]);
394                 fill420(y, u, v, 1, n, buf->width, buf->height, buf->pitches[0]);
395                 break;
396         }
397         default:
398                 ERROR("invalid format: 0x%08x", buf->fourcc);
399                 break;
400         }
402         for (i = 0; i < buf->nbo; i++)
403                 omap_bo_cpu_fini(buf->bo[i], OMAP_GEM_WRITE);