Home | History | Annotate | Download | only in src
      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