1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 *
26 *
27 **************************************************************************/
28 /*
29 * Authors: Thomas Hellstr�m <thomas-at-tungstengraphics-dot-com>
30 */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <X11/Xlib.h>
37 #include <X11/Xutil.h>
38 #include <stdint.h>
39 #include <drm/drm.h>
40 #include "xf86dri.h"
41 #include "xf86drm.h"
42 #include "stdio.h"
43 #include "sys/types.h"
44 #include <unistd.h>
45 #include <string.h>
46 #include <errno.h>
47 #include <stdlib.h>
48 #include "sys/mman.h"
49
50 typedef struct
51 {
52 enum
53 {
54 haveNothing,
55 haveDisplay,
56 haveConnection,
57 haveDriverName,
58 haveDeviceInfo,
59 haveDRM,
60 haveContext
61 }
62 state;
63
64 Display *display;
65 int screen;
66 drm_handle_t sAreaOffset;
67 char *curBusID;
68 char *driverName;
69 int drmFD;
70 XVisualInfo visualInfo;
71 XID id;
72 drm_context_t hwContext;
73 void *driPriv;
74 int driPrivSize;
75 int fbSize;
76 int fbOrigin;
77 int fbStride;
78 drm_handle_t fbHandle;
79 int ddxDriverMajor;
80 int ddxDriverMinor;
81 int ddxDriverPatch;
82 } TinyDRIContext;
83
84 #ifndef __x86_64__
85 static unsigned
fastrdtsc(void)86 fastrdtsc(void)
87 {
88 unsigned eax;
89 __asm__ volatile ("\t"
90 "pushl %%ebx\n\t"
91 "cpuid\n\t" ".byte 0x0f, 0x31\n\t" "popl %%ebx\n":"=a" (eax)
92 :"0"(0)
93 :"ecx", "edx", "cc");
94
95 return eax;
96 }
97 #else
98 static unsigned
fastrdtsc(void)99 fastrdtsc(void)
100 {
101 unsigned eax;
102 __asm__ volatile ("\t" "cpuid\n\t" ".byte 0x0f, 0x31\n\t":"=a" (eax)
103 :"0"(0)
104 :"ecx", "edx", "ebx", "cc");
105
106 return eax;
107 }
108 #endif
109
110 void
bmError(int val,const char * file,const char * function,int line)111 bmError(int val, const char *file, const char *function, int line)
112 {
113 fprintf(stderr, "Fatal video memory manager error \"%s\".\n"
114 "Check kernel logs or set the LIBGL_DEBUG\n"
115 "environment variable to \"verbose\" for more info.\n"
116 "Detected in file %s, line %d, function %s.\n",
117 strerror(-val), file, line, function);
118 abort();
119 }
120
121 #define BM_CKFATAL(val) \
122 do{ \
123 int tstVal = (val); \
124 if (tstVal) \
125 bmError(tstVal, __FILE__, __FUNCTION__, __LINE__); \
126 } while(0);
127
128 static unsigned
time_diff(unsigned t,unsigned t2)129 time_diff(unsigned t, unsigned t2)
130 {
131 return ((t < t2) ? t2 - t : 0xFFFFFFFFU - (t - t2 - 1));
132 }
133
134 static int
releaseContext(TinyDRIContext * ctx)135 releaseContext(TinyDRIContext * ctx)
136 {
137 switch (ctx->state) {
138 case haveContext:
139 uniDRIDestroyContext(ctx->display, ctx->screen, ctx->id);
140 case haveDRM:
141 drmClose(ctx->drmFD);
142 case haveDeviceInfo:
143 XFree(ctx->driPriv);
144 case haveDriverName:
145 XFree(ctx->driverName);
146 case haveConnection:
147 XFree(ctx->curBusID);
148 uniDRICloseConnection(ctx->display, ctx->screen);
149 case haveDisplay:
150 XCloseDisplay(ctx->display);
151 default:
152 break;
153 }
154 return -1;
155 }
156
157 static void
readBuf(void * buf,unsigned long size)158 readBuf(void *buf, unsigned long size)
159 {
160 volatile unsigned *buf32 = (unsigned *)buf;
161 unsigned *end = (unsigned *)buf32 + size / sizeof(*buf32);
162
163 while (buf32 < end) {
164 (void)*buf32++;
165 }
166 }
167
168 static int
benchmarkBuffer(TinyDRIContext * ctx,unsigned long size,unsigned long * ticks)169 benchmarkBuffer(TinyDRIContext * ctx, unsigned long size,
170 unsigned long *ticks)
171 {
172 unsigned long curTime, oldTime;
173 int ret;
174 drmBO buf;
175 void *virtual;
176
177 /*
178 * Test system memory objects.
179 */
180 oldTime = fastrdtsc();
181 BM_CKFATAL(drmBOCreate(ctx->drmFD, size, 0, NULL,
182 DRM_BO_FLAG_READ |
183 DRM_BO_FLAG_WRITE |
184 DRM_BO_FLAG_MEM_LOCAL, 0, &buf));
185 curTime = fastrdtsc();
186 *ticks++ = time_diff(oldTime, curTime);
187
188 oldTime = fastrdtsc();
189 BM_CKFATAL(drmBOMap(ctx->drmFD, &buf,
190 DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual));
191 curTime = fastrdtsc();
192 *ticks++ = time_diff(oldTime, curTime);
193
194 oldTime = fastrdtsc();
195 memset(virtual, 0xF0, buf.size);
196 curTime = fastrdtsc();
197 *ticks++ = time_diff(oldTime, curTime);
198
199 oldTime = fastrdtsc();
200 memset(virtual, 0x0F, buf.size);
201 curTime = fastrdtsc();
202 *ticks++ = time_diff(oldTime, curTime);
203
204 oldTime = fastrdtsc();
205 readBuf(virtual, buf.size);
206 curTime = fastrdtsc();
207 *ticks++ = time_diff(oldTime, curTime);
208
209 oldTime = fastrdtsc();
210 BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf));
211 curTime = fastrdtsc();
212 *ticks++ = time_diff(oldTime, curTime);
213
214 /*
215 * Test TT bound buffer objects.
216 */
217
218 oldTime = fastrdtsc();
219 BM_CKFATAL(drmBOSetStatus(ctx->drmFD, &buf,
220 DRM_BO_FLAG_MEM_TT,
221 DRM_BO_MASK_MEM,
222 0,0,0));
223 curTime = fastrdtsc();
224 *ticks++ = time_diff(oldTime, curTime);
225
226 oldTime = fastrdtsc();
227 BM_CKFATAL(drmBOMap(ctx->drmFD, &buf,
228 DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual));
229 curTime = fastrdtsc();
230 *ticks++ = time_diff(oldTime, curTime);
231
232 oldTime = fastrdtsc();
233 memset(virtual, 0xF0, buf.size);
234 curTime = fastrdtsc();
235 *ticks++ = time_diff(oldTime, curTime);
236
237 oldTime = fastrdtsc();
238 memset(virtual, 0x0F, buf.size);
239 curTime = fastrdtsc();
240 *ticks++ = time_diff(oldTime, curTime);
241
242 oldTime = fastrdtsc();
243 readBuf(virtual, buf.size);
244 curTime = fastrdtsc();
245 *ticks++ = time_diff(oldTime, curTime);
246
247 BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf));
248
249 oldTime = fastrdtsc();
250 BM_CKFATAL(drmBOSetStatus(ctx->drmFD, &buf,
251 DRM_BO_FLAG_MEM_LOCAL, DRM_BO_MASK_MEM, 0, 0,0));
252 curTime = fastrdtsc();
253 *ticks++ = time_diff(oldTime, curTime);
254
255 /*
256 * Test cached buffers objects.
257 */
258
259 oldTime = fastrdtsc();
260 ret = drmBOSetStatus(ctx->drmFD, &buf,
261 DRM_BO_FLAG_MEM_TT |
262 DRM_BO_FLAG_CACHED |
263 DRM_BO_FLAG_FORCE_CACHING,
264 DRM_BO_MASK_MEMTYPE |
265 DRM_BO_FLAG_FORCE_CACHING,
266 0, 0, 0);
267 curTime = fastrdtsc();
268
269 if (ret) {
270 printf("Couldn't bind cached. Probably no support\n");
271 BM_CKFATAL(drmBOUnreference(ctx->drmFD, &buf));
272 return 1;
273 }
274 *ticks++ = time_diff(oldTime, curTime);
275
276 oldTime = fastrdtsc();
277 BM_CKFATAL(drmBOMap(ctx->drmFD, &buf,
278 DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual));
279
280 curTime = fastrdtsc();
281 *ticks++ = time_diff(oldTime, curTime);
282
283 oldTime = fastrdtsc();
284 memset(virtual, 0xF0, buf.size);
285 curTime = fastrdtsc();
286 *ticks++ = time_diff(oldTime, curTime);
287
288 oldTime = fastrdtsc();
289 memset(virtual, 0x0F, buf.size);
290 curTime = fastrdtsc();
291 *ticks++ = time_diff(oldTime, curTime);
292
293 oldTime = fastrdtsc();
294 readBuf(virtual, buf.size);
295 curTime = fastrdtsc();
296 *ticks++ = time_diff(oldTime, curTime);
297
298 BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf));
299 BM_CKFATAL(drmBOUnreference(ctx->drmFD, &buf));
300
301 return 0;
302 }
303
304 static void
testAGP(TinyDRIContext * ctx)305 testAGP(TinyDRIContext * ctx)
306 {
307 unsigned long ticks[128], *pTicks;
308 unsigned long size = 8 * 1024;
309 int ret;
310
311 ret = benchmarkBuffer(ctx, size, ticks);
312 if (ret < 0) {
313 fprintf(stderr, "Buffer error %s\n", strerror(-ret));
314 return;
315 }
316 pTicks = ticks;
317
318 printf("Buffer size %d bytes\n", size);
319 printf("System memory timings ********************************\n");
320 printf("Creation took %12lu ticks\n", *pTicks++);
321 printf("Mapping took %12lu ticks\n", *pTicks++);
322 printf("Writing took %12lu ticks\n", *pTicks++);
323 printf("Writing Again took %12lu ticks\n", *pTicks++);
324 printf("Reading took %12lu ticks\n", *pTicks++);
325 printf("Unmapping took %12lu ticks\n", *pTicks++);
326
327 printf("\nTT Memory timings ************************************\n");
328 printf("Moving to TT took %12lu ticks\n", *pTicks++);
329 printf("Mapping in TT took %12lu ticks\n", *pTicks++);
330 printf("Writing to TT took %12lu ticks\n", *pTicks++);
331 printf("Writing again to TT took %12lu ticks\n", *pTicks++);
332 printf("Reading from TT took %12lu ticks\n", *pTicks++);
333 printf("Moving to system took %12lu ticks\n", *pTicks++);
334
335 if (ret == 1)
336 return;
337
338 printf("\nCached TT Memory timings *****************************\n");
339 printf("Moving to CTT took %12lu ticks\n", *pTicks++);
340 printf("Mapping in CTT took %12lu ticks\n", *pTicks++);
341 printf("Writing to CTT took %12lu ticks\n", *pTicks++);
342 printf("Re-writing to CTT took %12lu ticks\n", *pTicks++);
343 printf("Reading from CTT took %12lu ticks\n", *pTicks++);
344 printf("\n\n");
345 }
346
347 int
main()348 main()
349 {
350 int ret, screen, isCapable;
351 char *displayName = ":0";
352 TinyDRIContext ctx;
353 unsigned magic;
354
355 ctx.screen = 0;
356 ctx.state = haveNothing;
357 ctx.display = XOpenDisplay(displayName);
358 if (!ctx.display) {
359 fprintf(stderr, "Could not open display\n");
360 return releaseContext(&ctx);
361 }
362 ctx.state = haveDisplay;
363
364 ret =
365 uniDRIQueryDirectRenderingCapable(ctx.display, ctx.screen,
366 &isCapable);
367 if (!ret || !isCapable) {
368 fprintf(stderr, "No DRI on this display:sceen\n");
369 return releaseContext(&ctx);
370 }
371
372 if (!uniDRIOpenConnection(ctx.display, ctx.screen, &ctx.sAreaOffset,
373 &ctx.curBusID)) {
374 fprintf(stderr, "Could not open DRI connection.\n");
375 return releaseContext(&ctx);
376 }
377 ctx.state = haveConnection;
378
379 if (!uniDRIGetClientDriverName(ctx.display, ctx.screen,
380 &ctx.ddxDriverMajor, &ctx.ddxDriverMinor,
381 &ctx.ddxDriverPatch, &ctx.driverName)) {
382 fprintf(stderr, "Could not get DRI driver name.\n");
383 return releaseContext(&ctx);
384 }
385 ctx.state = haveDriverName;
386
387 if (!uniDRIGetDeviceInfo(ctx.display, ctx.screen,
388 &ctx.fbHandle, &ctx.fbOrigin, &ctx.fbSize,
389 &ctx.fbStride, &ctx.driPrivSize, &ctx.driPriv)) {
390 fprintf(stderr, "Could not get DRI device info.\n");
391 return releaseContext(&ctx);
392 }
393 ctx.state = haveDriverName;
394
395 if ((ctx.drmFD = drmOpen(NULL, ctx.curBusID)) < 0) {
396 perror("DRM Device could not be opened");
397 return releaseContext(&ctx);
398 }
399 ctx.state = haveDRM;
400
401 drmGetMagic(ctx.drmFD, &magic);
402 if (!uniDRIAuthConnection(ctx.display, ctx.screen, magic)) {
403 fprintf(stderr, "Could not get X server to authenticate us.\n");
404 return releaseContext(&ctx);
405 }
406
407 ret = XMatchVisualInfo(ctx.display, ctx.screen, 24, TrueColor,
408 &ctx.visualInfo);
409 if (!ret) {
410 ret = XMatchVisualInfo(ctx.display, ctx.screen, 16, TrueColor,
411 &ctx.visualInfo);
412 if (!ret) {
413 fprintf(stderr, "Could not find a matching visual.\n");
414 return releaseContext(&ctx);
415 }
416 }
417
418 if (!uniDRICreateContext(ctx.display, ctx.screen, ctx.visualInfo.visual,
419 &ctx.id, &ctx.hwContext)) {
420 fprintf(stderr, "Could not create DRI context.\n");
421 return releaseContext(&ctx);
422 }
423 ctx.state = haveContext;
424
425 testAGP(&ctx);
426
427 releaseContext(&ctx);
428 printf("Terminating normally\n");
429 return 0;
430 }
431