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 Hellstrm <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 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 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 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 129 time_diff(unsigned t, unsigned t2) 130 { 131 return ((t < t2) ? t2 - t : 0xFFFFFFFFU - (t - t2 - 1)); 132 } 133 134 static int 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 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 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 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 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