dri2video support
[gstreamer-omap:libdri2.git] / test / dri2videotest.c
1 /*
2  * Copyright © 2011 Texas Instruments, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Soft-
6  * ware"), to deal in the Software without restriction, including without
7  * limitation the rights to use, copy, modify, merge, publish, distribute,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, provided that the above copyright
10  * notice(s) and this permission notice appear in all copies of the Soft-
11  * ware and that both the above copyright notice(s) and this permission
12  * notice appear in supporting documentation.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16  * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
17  * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
18  * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
19  * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
22  * MANCE OF THIS SOFTWARE.
23  *
24  * Except as contained in this notice, the name of a copyright holder shall
25  * not be used in advertising or otherwise to promote the sale, use or
26  * other dealings in this Software without prior written authorization of
27  * the copyright holder.
28  *
29  * Authors:
30  *   Rob Clark (rob@ti.com)
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #  include "config.h"
35 #endif
36
37 #include <ctype.h>
38
39 #include "dri2util.h"
40
41 #define NFRAMES 300
42 #define WIN_WIDTH  500
43 #define WIN_HEIGHT 500
44 #define VID_WIDTH  1920
45 #define VID_HEIGHT 1080
46
47 #define FOURCC(a, b, c, d) ((uint32_t)(uint8_t)(a) | ((uint32_t)(uint8_t)(b) << 8) | ((uint32_t)(uint8_t)(c) << 16) | ((uint32_t)(uint8_t)(d) << 24 ))
48 #define FOURCC_STR(str)    FOURCC(str[0], str[1], str[2], str[3])
49
50 /* swap these for big endian.. */
51 #define RED   2
52 #define GREEN 1
53 #define BLUE  0
54
55 static void fill420(unsigned char *y, unsigned char *u, unsigned char *v,
56                 int cs /*chroma pixel stride */,
57                 int n, int width, int height, int stride)
58 {
59         int i, j;
60
61         /* paint the buffer with colored tiles, in blocks of 2x2 */
62         for (j = 0; j < height; j+=2) {
63                 unsigned char *y1p = y + j * stride;
64                 unsigned char *y2p = y1p + stride;
65                 unsigned char *up = u + (j/2) * stride * cs / 2;
66                 unsigned char *vp = v + (j/2) * stride * cs / 2;
67
68                 for (i = 0; i < width; i+=2) {
69                         div_t d = div(n+i+j, width);
70                         uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
71                         unsigned char *rgbp = &rgb;
72                         unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]);
73
74                         *(y2p++) = *(y1p++) = y;
75                         *(y2p++) = *(y1p++) = y;
76
77                         *up = (rgbp[BLUE] - y) * 0.565 + 128;
78                         *vp = (rgbp[RED] - y) * 0.713 + 128;
79                         up += cs;
80                         vp += cs;
81                 }
82         }
83 }
84
85 static void fill422(unsigned char *virtual, int n, int width, int height, int stride)
86 {
87         int i, j;
88         /* paint the buffer with colored tiles */
89         for (j = 0; j < height; j++) {
90                 uint8_t *ptr = (uint32_t*)((char*)virtual + j * stride);
91                 for (i = 0; i < width; i+=2) {
92                         div_t d = div(n+i+j, width);
93                         uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
94                         unsigned char *rgbp = &rgb;
95                         unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]);
96
97                         *(ptr++) = y;
98                         *(ptr++) = (rgbp[BLUE] - y) * 0.565 + 128;
99                         *(ptr++) = y;
100                         *(ptr++) = (rgbp[RED] - y) * 0.713 + 128;
101                 }
102         }
103 }
104
105 /* stolen from modetest.c */
106 static void fill(unsigned char *virtual, int n, int width, int height, int stride)
107 {
108         int i, j;
109     /* paint the buffer with colored tiles */
110     for (j = 0; j < height; j++) {
111             uint32_t *fb_ptr = (uint32_t*)((char*)virtual + j * stride);
112             for (i = 0; i < width; i++) {
113                     div_t d = div(n+i+j, width);
114                     fb_ptr[i] =
115                             0x00130502 * (d.quot >> 6) +
116                             0x000a1120 * (d.rem >> 6);
117             }
118     }
119 }
120
121
122 /* move this somewhere common?  It does seem useful.. */
123 static Bool is_fourcc(unsigned int val)
124 {
125         char *str = (char *)&val;
126         return isalnum(str[0]) && isalnum(str[1]) && isalnum(str[2]) && isalnum(str[3]);
127 }
128
129 #define ATOM(name) XInternAtom(dpy, name, False)
130
131 int main(int argc, char **argv)
132 {
133         Display *dpy;
134         Window win;
135         Backend *backend = NULL;
136         DRI2Buffer *dri2bufs;
137         Buffer *bufs;
138         char *driver;
139         unsigned int nformats, *formats, format = 0;
140         int fd, nbufs, i;
141         CARD32 *pval;
142
143         dpy = XOpenDisplay(NULL);
144         win = XCreateSimpleWindow(dpy, RootWindow(dpy, 0), 1, 1,
145                         WIN_WIDTH, WIN_HEIGHT, 0, BlackPixel (dpy, 0), BlackPixel(dpy, 0));
146         XMapWindow(dpy, win);
147         XFlush(dpy);
148
149         if ((fd = dri2_connect(dpy, DRI2DriverXV, &driver)) < 0) {
150                 return -1;
151         }
152
153         if (!DRI2GetFormats(dpy, RootWindow(dpy, DefaultScreen(dpy)),
154                         &nformats, &formats)) {
155                 ERROR_MSG("DRI2GetFormats failed");
156                 return -1;
157         }
158
159         if (nformats == 0) {
160                 ERROR_MSG("no formats!");
161                 return -1;
162         }
163
164         /* print out supported formats */
165         MSG("Found %d supported formats:", nformats);
166         for (i = 0; i < nformats; i++) {
167                 if (is_fourcc(formats[i])) {
168                         MSG("  %d: %08x (\"%.4s\")", i, formats[i], (char *)&formats[i]);
169                 } else {
170                         MSG("  %d: %08x (device dependent)", i, formats[i]);
171                 }
172         }
173
174         // XXX pick something we understand!
175 //      format = FOURCC_STR("I420");
176         format = FOURCC_STR("YUY2");
177 //      format = FOURCC_STR("RGB4");
178
179         free(formats);
180
181         backend = get_backend(driver);
182         if (!backend) {
183                 return -1;
184         }
185
186         backend->setup(fd);
187
188         DRI2CreateDrawable(dpy, win);
189
190         /* check some attribute.. just to exercise the code-path: */
191         if (!DRI2GetAttribute(dpy, win, ATOM("XV_CSC_MATRIX"), &i, &pval)) {
192                 ERROR_MSG("DRI2GetAttribute failed");
193                 return -1;
194         }
195
196         MSG("Got CSC matrix:");
197         print_hex(i*4, (const unsigned char *)pval);
198
199         free(pval);
200
201         unsigned attachments[] = {
202                         DRI2BufferFrontLeft, 32, /* always requested, never returned */
203                         1, format, 2, format, 3, format, 4, format,
204         };
205         dri2bufs = DRI2GetBuffersVid(dpy, win, VID_WIDTH, VID_HEIGHT, attachments, 4, &nbufs);
206         if (!dri2bufs) {
207                 ERROR_MSG("DRI2GetBuffersVid failed");
208                 return -1;
209         }
210
211         MSG("DRI2GetBuffers: nbufs=%d", nbufs);
212
213         bufs = calloc(nbufs, sizeof(Buffer));
214
215         for (i = 0; i < nbufs; i++) {
216                 bufs[i].dri2buf = &dri2bufs[i];
217                 bufs[i].hdl = backend->init(bufs[i].dri2buf);
218         }
219
220         for (i = 0; i < NFRAMES; i++) {
221                 BoxRec b = {
222                                 // TODO change this dynamically..  fill appropriately so
223                                 // the cropped region has different color, or something,
224                                 // so we can see visually if cropping is incorrect..
225                                 .x1 = 0,
226                                 .y1 = 0,
227                                 .x2 = VID_WIDTH,
228                                 .y2 = VID_HEIGHT,
229                 };
230                 CARD64 count;
231
232                 Buffer *buf = &bufs[i % nbufs];
233                 int pitch = buf->dri2buf->pitch[0];
234                 unsigned char *ptr = backend->prep(buf->hdl);
235                 if (format == FOURCC_STR("I420")) {
236 #if 0
237                         unsigned char *y = ptr;
238                         // XXX deal with multiple bo case
239                         unsigned char *u = y + (VID_HEIGHT * pitch);
240                         unsigned char *v = u + (VID_HEIGHT * pitch) / 4;
241                         fill420(y, u, v, 1, i, VID_WIDTH, VID_HEIGHT, pitch);
242 #else
243                         /* I think the nouveau shader actually expects NV12... */
244                         unsigned char *y = ptr;
245                         // XXX deal with multiple bo case
246                         unsigned char *u = y + (VID_HEIGHT * pitch);
247                         unsigned char *v = u + 1;
248                         fill420(y, u, v, 2, i, VID_WIDTH, VID_HEIGHT, pitch);
249 #endif
250                 } else if (format == FOURCC_STR("YUY2")) {
251                         fill422(ptr, i, VID_WIDTH, VID_HEIGHT, pitch);
252                 } else if (format == FOURCC_STR("RGB4")) {
253                         fill(ptr, i, VID_WIDTH, VID_HEIGHT, pitch);
254                 }
255                 backend->fini(buf->hdl);
256                 DRI2SwapBuffersVid(dpy, win, 0, 0, 0, &count, (i % nbufs) + 1, &b);
257                 MSG("DRI2SwapBuffersVid: count=%lu", count);
258                 if (i > 0) {
259                         /* XXX wait.. */
260                 }
261         }
262
263         return 0;
264 }