disp: new option --no-post to disable buffers posting
[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 void disp_kms_usage(void);
27 struct display * disp_kms_open(int argc, char **argv);
29 #ifdef HAVE_X11
30 void disp_x11_usage(void);
31 struct display * disp_x11_open(int argc, char **argv);
32 void disp_x11_close(struct display *disp);
33 #endif
35 void
36 disp_usage(void)
37 {
38         MSG("Generic Display options:");
39         MSG("\t--fps <fps>\tforce playback rate (0 means \"do not force\")");
40         MSG("\t--no-post\tDo not post buffers (disables screen updates) for benchmarking. Rate can still be controlled.");
42 #ifdef HAVE_X11
43         disp_x11_usage();
44 #endif
45         disp_kms_usage();
46 }
48 static int
49 empty_post_buffer(struct display *disp, struct buffer *buf)
50 {
51         return 0;
52 }
54 static int
55 empty_post_vid_buffer(struct display *disp, struct buffer *buf,
56                         uint32_t x, uint32_t y, uint32_t w, uint32_t h)
57 {
58         return 0;
59 }
61 struct display *
62 disp_open(int argc, char **argv)
63 {
64         struct display *disp;
65         int i, fps = 0, no_post = 0;
67         for (i = 1; i < argc; i++) {
68                 if (!argv[i]) {
69                         continue;
70                 }
71                 if (!strcmp("--fps", argv[i])) {
72                         argv[i++] = NULL;
74                         if (sscanf(argv[i], "%d", &fps) != 1) {
75                                 ERROR("invalid arg: %s", argv[i]);
76                                 return NULL;
77                         }
79                         MSG("Forcing playback rate at %d fps.", fps);
80                         argv[i] = NULL;
82                 } else if (!strcmp("--no-post", argv[i])) {
83                         MSG("Disabling buffers posting.");
84                         no_post = 1;
85                         argv[i] = NULL;
86                 }
87         }
89 #ifdef HAVE_X11
90         disp = disp_x11_open(argc, argv);
91         if (disp)
92                 goto out;
93 #endif
95         disp = disp_kms_open(argc, argv);
97         if (!disp) {
98                 ERROR("unable to create display");
99         }
101 out:
102         disp->rtctl.fps = fps;
104         /* If buffer posting is disabled from command line, override post
105          * functions with empty ones. */
106         if (no_post) {
107                 disp->post_buffer = empty_post_buffer;
108                 disp->post_vid_buffer = empty_post_vid_buffer;
109         }
111         return disp;
114 void disp_close(struct display *disp)
116 #ifdef HAVE_X11
117         disp_x11_close(disp);
118 #endif
121 struct buffer **
122 disp_get_vid_buffers(struct display *disp, uint32_t n,
123                 uint32_t fourcc, uint32_t w, uint32_t h)
125         struct buffer **buffers;
126         unsigned int i;
128         buffers = disp->get_vid_buffers(disp, n, fourcc, w, h);
129         if (buffers) {
130                 /* if allocation succeeded, store in the unlocked
131                  * video buffer list
132                  */
133                 list_init(&disp->unlocked);
134                 for (i = 0; i < n; i++)
135                         list_add(&buffers[i]->unlocked, &disp->unlocked);
136         }
138         return buffers;
141 struct buffer *
142 disp_get_vid_buffer(struct display *disp)
144         struct buffer *buf = NULL;
145         if (!list_is_empty(&disp->unlocked)) {
146                 buf = list_last_entry(&disp->unlocked, struct buffer, unlocked);
147                 list_del(&buf->unlocked);
149                 /* barrier.. if we are using GPU blitting, we need to make sure
150                  * that the GPU is finished:
151                  */
152                 omap_bo_cpu_prep(buf->bo[0], OMAP_GEM_WRITE);
153                 omap_bo_cpu_fini(buf->bo[0], OMAP_GEM_WRITE);
154         }
155         return buf;
158 void
159 disp_put_vid_buffer(struct display *disp, struct buffer *buf)
161         list_add(&buf->unlocked, &disp->unlocked);
164 /* Maintain playback rate if fps > 0. */
165 static void maintain_playback_rate(struct rate_control *p)
167         long usecs_since_last_frame;
168         int usecs_between_frames, usecs_to_sleep;
170         if (p->fps <= 0)
171                 return;
173         usecs_between_frames = 1000000 / p->fps;
174         usecs_since_last_frame = mark(&p->last_frame_mark);
175         MSG("fps: %.02f", 1000000.0 / usecs_since_last_frame);
176         usecs_to_sleep = usecs_between_frames - usecs_since_last_frame + p->usecs_to_sleep;
178         if (usecs_to_sleep < 0)
179                 usecs_to_sleep = 0;
181         /* mark() has a limitation that >1s time deltas will make the whole
182          * loop diverge. Workaround that limitation by clamping our desired sleep time
183          * to a maximum. TODO: Remove when mark() is in better shape. */
184         if (usecs_to_sleep >= 1000000)
185                 usecs_to_sleep = 999999;
187         /* We filter a bit our rate adaptation, to avoid being too "choppy".
188          * Adjust the "alpha" value as needed. */
189         p->usecs_to_sleep = ((67 * p->usecs_to_sleep) + (33 * usecs_to_sleep)) / 100;
191         if (p->usecs_to_sleep >= 1) {
192                 MSG("sleeping %dus", p->usecs_to_sleep);
193                 usleep(p->usecs_to_sleep);
194         }
197 /* flip to / post the specified buffer */
198 int
199 disp_post_buffer(struct display *disp, struct buffer *buf)
201         maintain_playback_rate(&disp->rtctl);
202         return disp->post_buffer(disp, buf);
205 /* flip to / post the specified video buffer */
206 int
207 disp_post_vid_buffer(struct display *disp, struct buffer *buf,
208                 uint32_t x, uint32_t y, uint32_t w, uint32_t h)
210         maintain_playback_rate(&disp->rtctl);
211         return disp->post_vid_buffer(disp, buf, x, y, w, h);
214 struct buffer *
215 disp_get_fb(struct display *disp)
217         struct buffer **bufs = disp_get_buffers(disp, 1);
218         if (!bufs)
219                 return NULL;
220         fill(bufs[0], 42);
221         disp_post_buffer(disp, bufs[0]);
222         return bufs[0];
226 int
227 check_args(int argc, char **argv)
229         int i;
230         for (i = 1; i < argc; i++) {
231                 if (argv[i]) {
232                         ERROR("invalid arg: %s", argv[i]);
233                         return -1;
234                 }
235         }
236         return 0;
239 /* stolen from modetest.c */
240 static void
241 fillRGB4(char *virtual, int n, int width, int height, int stride)
243         int i, j;
244         /* paint the buffer with colored tiles */
245         for (j = 0; j < height; j++) {
246                 uint32_t *fb_ptr = (uint32_t*)((char*)virtual + j * stride);
247                 for (i = 0; i < width; i++) {
248                         div_t d = div(n+i+j, width);
249                         fb_ptr[i] =
250                                         0x00130502 * (d.quot >> 6) +
251                                         0x000a1120 * (d.rem >> 6);
252                 }
253         }
257 /* swap these for big endian.. */
258 #define RED   2
259 #define GREEN 1
260 #define BLUE  0
262 static void
263 fill420(unsigned char *y, unsigned char *u, unsigned char *v,
264                 int cs /*chroma pixel stride */,
265                 int n, int width, int height, int stride)
267         int i, j;
269         /* paint the buffer with colored tiles, in blocks of 2x2 */
270         for (j = 0; j < height; j+=2) {
271                 unsigned char *y1p = y + j * stride;
272                 unsigned char *y2p = y1p + stride;
273                 unsigned char *up = u + (j/2) * stride * cs / 2;
274                 unsigned char *vp = v + (j/2) * stride * cs / 2;
276                 for (i = 0; i < width; i+=2) {
277                         div_t d = div(n+i+j, width);
278                         uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
279                         unsigned char *rgbp = (unsigned char *)&rgb;
280                         unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]);
282                         *(y2p++) = *(y1p++) = y;
283                         *(y2p++) = *(y1p++) = y;
285                         *up = (rgbp[BLUE] - y) * 0.565 + 128;
286                         *vp = (rgbp[RED] - y) * 0.713 + 128;
287                         up += cs;
288                         vp += cs;
289                 }
290         }
293 static void
294 fill422(unsigned char *virtual, int n, int width, int height, int stride)
296         int i, j;
297         /* paint the buffer with colored tiles */
298         for (j = 0; j < height; j++) {
299                 uint8_t *ptr = (uint8_t*)((char*)virtual + j * stride);
300                 for (i = 0; i < width; i++) {
301                         div_t d = div(n+i+j, width);
302                         uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
303                         unsigned char *rgbp = (unsigned char *)&rgb;
304                         unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]);
306                         *(ptr++) = y;
307                         *(ptr++) = (rgbp[BLUE] - y) * 0.565 + 128;
308                         *(ptr++) = y;
309                         *(ptr++) = (rgbp[RED] - y) * 0.713 + 128;
310                 }
311         }
315 void
316 fill(struct buffer *buf, int n)
318         int i;
320         for (i = 0; i < buf->nbo; i++)
321                 omap_bo_cpu_prep(buf->bo[i], OMAP_GEM_WRITE);
323         switch(buf->fourcc) {
324         case 0: {
325                 assert(buf->nbo == 1);
326                 fillRGB4(omap_bo_map(buf->bo[0]), n,
327                                 buf->width, buf->height, buf->pitches[0]);
328                 break;
329         }
330         case FOURCC('Y','U','Y','V'): {
331                 assert(buf->nbo == 1);
332                 fill422(omap_bo_map(buf->bo[0]), n,
333                                 buf->width, buf->height, buf->pitches[0]);
334                 break;
335         }
336         case FOURCC('N','V','1','2'): {
337                 unsigned char *y, *u, *v;
338                 assert(buf->nbo == 2);
339                 y = omap_bo_map(buf->bo[0]);
340                 u = omap_bo_map(buf->bo[1]);
341                 v = u + 1;
342                 fill420(y, u, v, 2, n, buf->width, buf->height, buf->pitches[0]);
343                 break;
344         }
345         case FOURCC('I','4','2','0'): {
346                 unsigned char *y, *u, *v;
347                 assert(buf->nbo == 3);
348                 y = omap_bo_map(buf->bo[0]);
349                 u = omap_bo_map(buf->bo[1]);
350                 v = omap_bo_map(buf->bo[2]);
351                 fill420(y, u, v, 1, n, buf->width, buf->height, buf->pitches[0]);
352                 break;
353         }
354         default:
355                 ERROR("invalid format: 0x%08x", buf->fourcc);
356                 break;
357         }
359         for (i = 0; i < buf->nbo; i++)
360                 omap_bo_cpu_fini(buf->bo[i], OMAP_GEM_WRITE);