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 }
110 out:
111 disp->rtctl.fps = fps;
113 /* If buffer posting is disabled from command line, override post
114 * functions with empty ones. */
115 if (no_post) {
116 disp->post_buffer = empty_post_buffer;
117 disp->post_vid_buffer = empty_post_vid_buffer;
118 }
120 return disp;
121 }
123 void disp_close(struct display *disp)
124 {
125 #ifdef HAVE_X11
126 disp_x11_close(disp);
127 #endif
128 }
130 struct buffer **
131 disp_get_vid_buffers(struct display *disp, uint32_t n,
132 uint32_t fourcc, uint32_t w, uint32_t h)
133 {
134 struct buffer **buffers;
135 unsigned int i;
137 buffers = disp->get_vid_buffers(disp, n, fourcc, w, h);
138 if (buffers) {
139 /* if allocation succeeded, store in the unlocked
140 * video buffer list
141 */
142 list_init(&disp->unlocked);
143 for (i = 0; i < n; i++)
144 list_add(&buffers[i]->unlocked, &disp->unlocked);
145 }
147 return buffers;
148 }
150 struct buffer *
151 disp_get_vid_buffer(struct display *disp)
152 {
153 struct buffer *buf = NULL;
154 if (!list_is_empty(&disp->unlocked)) {
155 buf = list_last_entry(&disp->unlocked, struct buffer, unlocked);
156 list_del(&buf->unlocked);
158 /* barrier.. if we are using GPU blitting, we need to make sure
159 * that the GPU is finished:
160 */
161 omap_bo_cpu_prep(buf->bo[0], OMAP_GEM_WRITE);
162 omap_bo_cpu_fini(buf->bo[0], OMAP_GEM_WRITE);
163 }
164 return buf;
165 }
167 void
168 disp_put_vid_buffer(struct display *disp, struct buffer *buf)
169 {
170 list_add(&buf->unlocked, &disp->unlocked);
171 }
173 /* Maintain playback rate if fps > 0. */
174 static void maintain_playback_rate(struct rate_control *p)
175 {
176 long usecs_since_last_frame;
177 int usecs_between_frames, usecs_to_sleep;
179 if (p->fps <= 0)
180 return;
182 usecs_between_frames = 1000000 / p->fps;
183 usecs_since_last_frame = mark(&p->last_frame_mark);
184 DBG("fps: %.02f", 1000000.0 / usecs_since_last_frame);
185 usecs_to_sleep = usecs_between_frames - usecs_since_last_frame + p->usecs_to_sleep;
187 if (usecs_to_sleep < 0)
188 usecs_to_sleep = 0;
190 /* mark() has a limitation that >1s time deltas will make the whole
191 * loop diverge. Workaround that limitation by clamping our desired sleep time
192 * to a maximum. TODO: Remove when mark() is in better shape. */
193 if (usecs_to_sleep >= 1000000)
194 usecs_to_sleep = 999999;
196 /* We filter a bit our rate adaptation, to avoid being too "choppy".
197 * Adjust the "alpha" value as needed. */
198 p->usecs_to_sleep = ((67 * p->usecs_to_sleep) + (33 * usecs_to_sleep)) / 100;
200 if (p->usecs_to_sleep >= 1) {
201 DBG("sleeping %dus", p->usecs_to_sleep);
202 usleep(p->usecs_to_sleep);
203 }
204 }
206 /* flip to / post the specified buffer */
207 int
208 disp_post_buffer(struct display *disp, struct buffer *buf)
209 {
210 maintain_playback_rate(&disp->rtctl);
211 return disp->post_buffer(disp, buf);
212 }
214 /* flip to / post the specified video buffer */
215 int
216 disp_post_vid_buffer(struct display *disp, struct buffer *buf,
217 uint32_t x, uint32_t y, uint32_t w, uint32_t h)
218 {
219 maintain_playback_rate(&disp->rtctl);
220 return disp->post_vid_buffer(disp, buf, x, y, w, h);
221 }
223 struct buffer *
224 disp_get_fb(struct display *disp)
225 {
226 struct buffer **bufs = disp_get_buffers(disp, 1);
227 if (!bufs)
228 return NULL;
229 fill(bufs[0], 42);
230 disp_post_buffer(disp, bufs[0]);
231 return bufs[0];
232 }
235 int
236 check_args(int argc, char **argv)
237 {
238 int i;
239 for (i = 1; i < argc; i++) {
240 if (argv[i]) {
241 ERROR("invalid arg: %s", argv[i]);
242 return -1;
243 }
244 }
245 return 0;
246 }
248 /* stolen from modetest.c */
249 static void
250 fillRGB4(char *virtual, int n, int width, int height, int stride)
251 {
252 int i, j;
253 /* paint the buffer with colored tiles */
254 for (j = 0; j < height; j++) {
255 uint32_t *fb_ptr = (uint32_t*)((char*)virtual + j * stride);
256 for (i = 0; i < width; i++) {
257 div_t d = div(n+i+j, width);
258 fb_ptr[i] =
259 0x00130502 * (d.quot >> 6) +
260 0x000a1120 * (d.rem >> 6);
261 }
262 }
263 }
266 /* swap these for big endian.. */
267 #define RED 2
268 #define GREEN 1
269 #define BLUE 0
271 static void
272 fill420(unsigned char *y, unsigned char *u, unsigned char *v,
273 int cs /*chroma pixel stride */,
274 int n, int width, int height, int stride)
275 {
276 int i, j;
278 /* paint the buffer with colored tiles, in blocks of 2x2 */
279 for (j = 0; j < height; j+=2) {
280 unsigned char *y1p = y + j * stride;
281 unsigned char *y2p = y1p + stride;
282 unsigned char *up = u + (j/2) * stride * cs / 2;
283 unsigned char *vp = v + (j/2) * stride * cs / 2;
285 for (i = 0; i < width; i+=2) {
286 div_t d = div(n+i+j, width);
287 uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
288 unsigned char *rgbp = (unsigned char *)&rgb;
289 unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]);
291 *(y2p++) = *(y1p++) = y;
292 *(y2p++) = *(y1p++) = y;
294 *up = (rgbp[BLUE] - y) * 0.565 + 128;
295 *vp = (rgbp[RED] - y) * 0.713 + 128;
296 up += cs;
297 vp += cs;
298 }
299 }
300 }
302 static void
303 fill422(unsigned char *virtual, int n, int width, int height, int stride)
304 {
305 int i, j;
306 /* paint the buffer with colored tiles */
307 for (j = 0; j < height; j++) {
308 uint8_t *ptr = (uint8_t*)((char*)virtual + j * stride);
309 for (i = 0; i < width; i++) {
310 div_t d = div(n+i+j, width);
311 uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
312 unsigned char *rgbp = (unsigned char *)&rgb;
313 unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]);
315 *(ptr++) = y;
316 *(ptr++) = (rgbp[BLUE] - y) * 0.565 + 128;
317 *(ptr++) = y;
318 *(ptr++) = (rgbp[RED] - y) * 0.713 + 128;
319 }
320 }
321 }
324 void
325 fill(struct buffer *buf, int n)
326 {
327 int i;
329 for (i = 0; i < buf->nbo; i++)
330 omap_bo_cpu_prep(buf->bo[i], OMAP_GEM_WRITE);
332 switch(buf->fourcc) {
333 case 0: {
334 assert(buf->nbo == 1);
335 fillRGB4(omap_bo_map(buf->bo[0]), n,
336 buf->width, buf->height, buf->pitches[0]);
337 break;
338 }
339 case FOURCC('Y','U','Y','V'): {
340 assert(buf->nbo == 1);
341 fill422(omap_bo_map(buf->bo[0]), n,
342 buf->width, buf->height, buf->pitches[0]);
343 break;
344 }
345 case FOURCC('N','V','1','2'): {
346 unsigned char *y, *u, *v;
347 assert(buf->nbo == 2);
348 y = omap_bo_map(buf->bo[0]);
349 u = omap_bo_map(buf->bo[1]);
350 v = u + 1;
351 fill420(y, u, v, 2, n, buf->width, buf->height, buf->pitches[0]);
352 break;
353 }
354 case FOURCC('I','4','2','0'): {
355 unsigned char *y, *u, *v;
356 assert(buf->nbo == 3);
357 y = omap_bo_map(buf->bo[0]);
358 u = omap_bo_map(buf->bo[1]);
359 v = omap_bo_map(buf->bo[2]);
360 fill420(y, u, v, 1, n, buf->width, buf->height, buf->pitches[0]);
361 break;
362 }
363 default:
364 ERROR("invalid format: 0x%08x", buf->fourcc);
365 break;
366 }
368 for (i = 0; i < buf->nbo; i++)
369 omap_bo_cpu_fini(buf->bo[i], OMAP_GEM_WRITE);
370 }