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