omx cam: add test app
[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 void
39 disp_usage(void)
40 {
41         MSG("Generic Display options:");
42         MSG("\t--debug\tTurn on debug messages.");
43         MSG("\t--fps <fps>\tforce playback rate (0 means \"do not force\")");
44         MSG("\t--no-post\tDo not post buffers (disables screen updates) for benchmarking. Rate can still be controlled.");
46 #ifdef HAVE_X11
47         disp_x11_usage();
48 #endif
49         disp_kms_usage();
50 }
52 static int
53 empty_post_buffer(struct display *disp, struct buffer *buf)
54 {
55         return 0;
56 }
58 static int
59 empty_post_vid_buffer(struct display *disp, struct buffer *buf,
60                         uint32_t x, uint32_t y, uint32_t w, uint32_t h)
61 {
62         return 0;
63 }
65 struct display *
66 disp_open(int argc, char **argv)
67 {
68         struct display *disp;
69         int i, fps = 0, no_post = 0;
71         for (i = 1; i < argc; i++) {
72                 if (!argv[i]) {
73                         continue;
74                 }
75                 if (!strcmp("--debug", argv[i])) {
76                         debug = 1;
77                         MSG("Enabling dynamic debug.");
78                         argv[i] = NULL;
80                 } else if (!strcmp("--fps", argv[i])) {
81                         argv[i++] = NULL;
83                         if (sscanf(argv[i], "%d", &fps) != 1) {
84                                 ERROR("invalid arg: %s", argv[i]);
85                                 return NULL;
86                         }
88                         MSG("Forcing playback rate at %d fps.", fps);
89                         argv[i] = NULL;
91                 } else if (!strcmp("--no-post", argv[i])) {
92                         MSG("Disabling buffers posting.");
93                         no_post = 1;
94                         argv[i] = NULL;
95                 }
96         }
98 #ifdef HAVE_X11
99         disp = disp_x11_open(argc, argv);
100         if (disp)
101                 goto out;
102 #endif
104         disp = disp_kms_open(argc, argv);
106         if (!disp) {
107                 ERROR("unable to create display");
108                 return NULL;
109         }
111 out:
112         disp->rtctl.fps = fps;
114         /* If buffer posting is disabled from command line, override post
115          * functions with empty ones. */
116         if (no_post) {
117                 disp->post_buffer = empty_post_buffer;
118                 disp->post_vid_buffer = empty_post_vid_buffer;
119         }
121         return disp;
124 struct buffer **
125 disp_get_vid_buffers(struct display *disp, uint32_t n,
126                 uint32_t fourcc, uint32_t w, uint32_t h)
128         struct buffer **buffers;
129         unsigned int i;
131         buffers = disp->get_vid_buffers(disp, n, fourcc, w, h);
132         if (buffers) {
133                 /* if allocation succeeded, store in the unlocked
134                  * video buffer list
135                  */
136                 list_init(&disp->unlocked);
137                 for (i = 0; i < n; i++)
138                         list_add(&buffers[i]->unlocked, &disp->unlocked);
139         }
141         return buffers;
144 struct buffer *
145 disp_get_vid_buffer(struct display *disp)
147         struct buffer *buf = NULL;
148         if (!list_is_empty(&disp->unlocked)) {
149                 buf = list_last_entry(&disp->unlocked, struct buffer, unlocked);
150                 list_del(&buf->unlocked);
152                 /* barrier.. if we are using GPU blitting, we need to make sure
153                  * that the GPU is finished:
154                  */
155                 omap_bo_cpu_prep(buf->bo[0], OMAP_GEM_WRITE);
156                 omap_bo_cpu_fini(buf->bo[0], OMAP_GEM_WRITE);
157         }
158         return buf;
161 void
162 disp_put_vid_buffer(struct display *disp, struct buffer *buf)
164         list_add(&buf->unlocked, &disp->unlocked);
167 /* Maintain playback rate if fps > 0. */
168 static void maintain_playback_rate(struct rate_control *p)
170         long usecs_since_last_frame;
171         int usecs_between_frames, usecs_to_sleep;
173         if (p->fps <= 0)
174                 return;
176         usecs_between_frames = 1000000 / p->fps;
177         usecs_since_last_frame = mark(&p->last_frame_mark);
178         DBG("fps: %.02f", 1000000.0 / usecs_since_last_frame);
179         usecs_to_sleep = usecs_between_frames - usecs_since_last_frame + p->usecs_to_sleep;
181         if (usecs_to_sleep < 0)
182                 usecs_to_sleep = 0;
184         /* mark() has a limitation that >1s time deltas will make the whole
185          * loop diverge. Workaround that limitation by clamping our desired sleep time
186          * to a maximum. TODO: Remove when mark() is in better shape. */
187         if (usecs_to_sleep >= 1000000)
188                 usecs_to_sleep = 999999;
190         /* We filter a bit our rate adaptation, to avoid being too "choppy".
191          * Adjust the "alpha" value as needed. */
192         p->usecs_to_sleep = ((67 * p->usecs_to_sleep) + (33 * usecs_to_sleep)) / 100;
194         if (p->usecs_to_sleep >= 1) {
195                 DBG("sleeping %dus", p->usecs_to_sleep);
196                 usleep(p->usecs_to_sleep);
197         }
200 /* flip to / post the specified buffer */
201 int
202 disp_post_buffer(struct display *disp, struct buffer *buf)
204         maintain_playback_rate(&disp->rtctl);
205         return disp->post_buffer(disp, buf);
208 /* flip to / post the specified video buffer */
209 int
210 disp_post_vid_buffer(struct display *disp, struct buffer *buf,
211                 uint32_t x, uint32_t y, uint32_t w, uint32_t h)
213         maintain_playback_rate(&disp->rtctl);
214         return disp->post_vid_buffer(disp, buf, x, y, w, h);
217 struct buffer *
218 disp_get_fb(struct display *disp)
220         struct buffer **bufs = disp_get_buffers(disp, 1);
221         if (!bufs)
222                 return NULL;
223         fill(bufs[0], 42);
224         disp_post_buffer(disp, bufs[0]);
225         return bufs[0];
229 int
230 check_args(int argc, char **argv)
232         int i;
233         for (i = 1; i < argc; i++) {
234                 if (argv[i]) {
235                         ERROR("invalid arg: %s", argv[i]);
236                         return -1;
237                 }
238         }
239         return 0;
242 /* stolen from modetest.c */
243 static void
244 fillRGB4(char *virtual, int n, int width, int height, int stride)
246         int i, j;
247         /* paint the buffer with colored tiles */
248         for (j = 0; j < height; j++) {
249                 uint32_t *fb_ptr = (uint32_t*)((char*)virtual + j * stride);
250                 for (i = 0; i < width; i++) {
251                         div_t d = div(n+i+j, width);
252                         fb_ptr[i] =
253                                         0x00130502 * (d.quot >> 6) +
254                                         0x000a1120 * (d.rem >> 6);
255                 }
256         }
260 /* swap these for big endian.. */
261 #define RED   2
262 #define GREEN 1
263 #define BLUE  0
265 static void
266 fill420(unsigned char *y, unsigned char *u, unsigned char *v,
267                 int cs /*chroma pixel stride */,
268                 int n, int width, int height, int stride)
270         int i, j;
272         /* paint the buffer with colored tiles, in blocks of 2x2 */
273         for (j = 0; j < height; j+=2) {
274                 unsigned char *y1p = y + j * stride;
275                 unsigned char *y2p = y1p + stride;
276                 unsigned char *up = u + (j/2) * stride * cs / 2;
277                 unsigned char *vp = v + (j/2) * stride * cs / 2;
279                 for (i = 0; i < width; i+=2) {
280                         div_t d = div(n+i+j, width);
281                         uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
282                         unsigned char *rgbp = (unsigned char *)&rgb;
283                         unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]);
285                         *(y2p++) = *(y1p++) = y;
286                         *(y2p++) = *(y1p++) = y;
288                         *up = (rgbp[BLUE] - y) * 0.565 + 128;
289                         *vp = (rgbp[RED] - y) * 0.713 + 128;
290                         up += cs;
291                         vp += cs;
292                 }
293         }
296 static void
297 fill422(unsigned char *virtual, int n, int width, int height, int stride)
299         int i, j;
300         /* paint the buffer with colored tiles */
301         for (j = 0; j < height; j++) {
302                 uint8_t *ptr = (uint8_t*)((char*)virtual + j * stride);
303                 for (i = 0; i < width; i++) {
304                         div_t d = div(n+i+j, width);
305                         uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
306                         unsigned char *rgbp = (unsigned char *)&rgb;
307                         unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]);
309                         *(ptr++) = y;
310                         *(ptr++) = (rgbp[BLUE] - y) * 0.565 + 128;
311                         *(ptr++) = y;
312                         *(ptr++) = (rgbp[RED] - y) * 0.713 + 128;
313                 }
314         }
318 void
319 fill(struct buffer *buf, int n)
321         int i;
323         for (i = 0; i < buf->nbo; i++)
324                 omap_bo_cpu_prep(buf->bo[i], OMAP_GEM_WRITE);
326         switch(buf->fourcc) {
327         case 0: {
328                 assert(buf->nbo == 1);
329                 fillRGB4(omap_bo_map(buf->bo[0]), n,
330                                 buf->width, buf->height, buf->pitches[0]);
331                 break;
332         }
333         case FOURCC('Y','U','Y','V'): {
334                 assert(buf->nbo == 1);
335                 fill422(omap_bo_map(buf->bo[0]), n,
336                                 buf->width, buf->height, buf->pitches[0]);
337                 break;
338         }
339         case FOURCC('N','V','1','2'): {
340                 unsigned char *y, *u, *v;
341                 assert(buf->nbo == 2);
342                 y = omap_bo_map(buf->bo[0]);
343                 u = omap_bo_map(buf->bo[1]);
344                 v = u + 1;
345                 fill420(y, u, v, 2, n, buf->width, buf->height, buf->pitches[0]);
346                 break;
347         }
348         case FOURCC('I','4','2','0'): {
349                 unsigned char *y, *u, *v;
350                 assert(buf->nbo == 3);
351                 y = omap_bo_map(buf->bo[0]);
352                 u = omap_bo_map(buf->bo[1]);
353                 v = omap_bo_map(buf->bo[2]);
354                 fill420(y, u, v, 1, n, buf->width, buf->height, buf->pitches[0]);
355                 break;
356         }
357         default:
358                 ERROR("invalid format: 0x%08x", buf->fourcc);
359                 break;
360         }
362         for (i = 0; i < buf->nbo; i++)
363                 omap_bo_cpu_fini(buf->bo[i], OMAP_GEM_WRITE);