blob: 36df24287772d6e9e16ff444fe0fc648ffda4ca0 [file] [log] [blame]
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
*
**************************************************************************/
/*
* Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdint.h>
#include <drm/drm.h>
#include "xf86dri.h"
#include "xf86drm.h"
#include "stdio.h"
#include "sys/types.h"
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include "sys/mman.h"
typedef struct
{
enum
{
haveNothing,
haveDisplay,
haveConnection,
haveDriverName,
haveDeviceInfo,
haveDRM,
haveContext
}
state;
Display *display;
int screen;
drm_handle_t sAreaOffset;
char *curBusID;
char *driverName;
int drmFD;
XVisualInfo visualInfo;
XID id;
drm_context_t hwContext;
void *driPriv;
int driPrivSize;
int fbSize;
int fbOrigin;
int fbStride;
drm_handle_t fbHandle;
int ddxDriverMajor;
int ddxDriverMinor;
int ddxDriverPatch;
} TinyDRIContext;
#ifndef __x86_64__
static unsigned
fastrdtsc(void)
{
unsigned eax;
__asm__ volatile ("\t"
"pushl %%ebx\n\t"
"cpuid\n\t" ".byte 0x0f, 0x31\n\t" "popl %%ebx\n":"=a" (eax)
:"0"(0)
:"ecx", "edx", "cc");
return eax;
}
#else
static unsigned
fastrdtsc(void)
{
unsigned eax;
__asm__ volatile ("\t" "cpuid\n\t" ".byte 0x0f, 0x31\n\t":"=a" (eax)
:"0"(0)
:"ecx", "edx", "ebx", "cc");
return eax;
}
#endif
void
bmError(int val, const char *file, const char *function, int line)
{
fprintf(stderr, "Fatal video memory manager error \"%s\".\n"
"Check kernel logs or set the LIBGL_DEBUG\n"
"environment variable to \"verbose\" for more info.\n"
"Detected in file %s, line %d, function %s.\n",
strerror(-val), file, line, function);
abort();
}
#define BM_CKFATAL(val) \
do{ \
int tstVal = (val); \
if (tstVal) \
bmError(tstVal, __FILE__, __FUNCTION__, __LINE__); \
} while(0);
static unsigned
time_diff(unsigned t, unsigned t2)
{
return ((t < t2) ? t2 - t : 0xFFFFFFFFU - (t - t2 - 1));
}
static int
releaseContext(TinyDRIContext * ctx)
{
switch (ctx->state) {
case haveContext:
uniDRIDestroyContext(ctx->display, ctx->screen, ctx->id);
case haveDRM:
drmClose(ctx->drmFD);
case haveDeviceInfo:
XFree(ctx->driPriv);
case haveDriverName:
XFree(ctx->driverName);
case haveConnection:
XFree(ctx->curBusID);
uniDRICloseConnection(ctx->display, ctx->screen);
case haveDisplay:
XCloseDisplay(ctx->display);
default:
break;
}
return -1;
}
static void
readBuf(void *buf, unsigned long size)
{
volatile unsigned *buf32 = (unsigned *)buf;
unsigned *end = (unsigned *)buf32 + size / sizeof(*buf32);
while (buf32 < end) {
(void)*buf32++;
}
}
static int
benchmarkBuffer(TinyDRIContext * ctx, unsigned long size,
unsigned long *ticks)
{
unsigned long curTime, oldTime;
int ret;
drmBO buf;
void *virtual;
/*
* Test system memory objects.
*/
oldTime = fastrdtsc();
BM_CKFATAL(drmBOCreate(ctx->drmFD, size, 0, NULL,
DRM_BO_FLAG_READ |
DRM_BO_FLAG_WRITE |
DRM_BO_FLAG_MEM_LOCAL, 0, &buf));
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
oldTime = fastrdtsc();
BM_CKFATAL(drmBOMap(ctx->drmFD, &buf,
DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual));
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
oldTime = fastrdtsc();
memset(virtual, 0xF0, buf.size);
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
oldTime = fastrdtsc();
memset(virtual, 0x0F, buf.size);
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
oldTime = fastrdtsc();
readBuf(virtual, buf.size);
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
oldTime = fastrdtsc();
BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf));
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
/*
* Test TT bound buffer objects.
*/
oldTime = fastrdtsc();
BM_CKFATAL(drmBOSetStatus(ctx->drmFD, &buf,
DRM_BO_FLAG_MEM_TT,
DRM_BO_MASK_MEM,
0,0,0));
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
oldTime = fastrdtsc();
BM_CKFATAL(drmBOMap(ctx->drmFD, &buf,
DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual));
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
oldTime = fastrdtsc();
memset(virtual, 0xF0, buf.size);
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
oldTime = fastrdtsc();
memset(virtual, 0x0F, buf.size);
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
oldTime = fastrdtsc();
readBuf(virtual, buf.size);
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf));
oldTime = fastrdtsc();
BM_CKFATAL(drmBOSetStatus(ctx->drmFD, &buf,
DRM_BO_FLAG_MEM_LOCAL, DRM_BO_MASK_MEM, 0, 0,0));
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
/*
* Test cached buffers objects.
*/
oldTime = fastrdtsc();
ret = drmBOSetStatus(ctx->drmFD, &buf,
DRM_BO_FLAG_MEM_TT |
DRM_BO_FLAG_CACHED |
DRM_BO_FLAG_FORCE_CACHING,
DRM_BO_MASK_MEMTYPE |
DRM_BO_FLAG_FORCE_CACHING,
0, 0, 0);
curTime = fastrdtsc();
if (ret) {
printf("Couldn't bind cached. Probably no support\n");
BM_CKFATAL(drmBOUnreference(ctx->drmFD, &buf));
return 1;
}
*ticks++ = time_diff(oldTime, curTime);
oldTime = fastrdtsc();
BM_CKFATAL(drmBOMap(ctx->drmFD, &buf,
DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual));
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
oldTime = fastrdtsc();
memset(virtual, 0xF0, buf.size);
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
oldTime = fastrdtsc();
memset(virtual, 0x0F, buf.size);
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
oldTime = fastrdtsc();
readBuf(virtual, buf.size);
curTime = fastrdtsc();
*ticks++ = time_diff(oldTime, curTime);
BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf));
BM_CKFATAL(drmBOUnreference(ctx->drmFD, &buf));
return 0;
}
static void
testAGP(TinyDRIContext * ctx)
{
unsigned long ticks[128], *pTicks;
unsigned long size = 8 * 1024;
int ret;
ret = benchmarkBuffer(ctx, size, ticks);
if (ret < 0) {
fprintf(stderr, "Buffer error %s\n", strerror(-ret));
return;
}
pTicks = ticks;
printf("Buffer size %d bytes\n", size);
printf("System memory timings ********************************\n");
printf("Creation took %12lu ticks\n", *pTicks++);
printf("Mapping took %12lu ticks\n", *pTicks++);
printf("Writing took %12lu ticks\n", *pTicks++);
printf("Writing Again took %12lu ticks\n", *pTicks++);
printf("Reading took %12lu ticks\n", *pTicks++);
printf("Unmapping took %12lu ticks\n", *pTicks++);
printf("\nTT Memory timings ************************************\n");
printf("Moving to TT took %12lu ticks\n", *pTicks++);
printf("Mapping in TT took %12lu ticks\n", *pTicks++);
printf("Writing to TT took %12lu ticks\n", *pTicks++);
printf("Writing again to TT took %12lu ticks\n", *pTicks++);
printf("Reading from TT took %12lu ticks\n", *pTicks++);
printf("Moving to system took %12lu ticks\n", *pTicks++);
if (ret == 1)
return;
printf("\nCached TT Memory timings *****************************\n");
printf("Moving to CTT took %12lu ticks\n", *pTicks++);
printf("Mapping in CTT took %12lu ticks\n", *pTicks++);
printf("Writing to CTT took %12lu ticks\n", *pTicks++);
printf("Re-writing to CTT took %12lu ticks\n", *pTicks++);
printf("Reading from CTT took %12lu ticks\n", *pTicks++);
printf("\n\n");
}
int
main()
{
int ret, screen, isCapable;
char *displayName = ":0";
TinyDRIContext ctx;
unsigned magic;
ctx.screen = 0;
ctx.state = haveNothing;
ctx.display = XOpenDisplay(displayName);
if (!ctx.display) {
fprintf(stderr, "Could not open display\n");
return releaseContext(&ctx);
}
ctx.state = haveDisplay;
ret =
uniDRIQueryDirectRenderingCapable(ctx.display, ctx.screen,
&isCapable);
if (!ret || !isCapable) {
fprintf(stderr, "No DRI on this display:sceen\n");
return releaseContext(&ctx);
}
if (!uniDRIOpenConnection(ctx.display, ctx.screen, &ctx.sAreaOffset,
&ctx.curBusID)) {
fprintf(stderr, "Could not open DRI connection.\n");
return releaseContext(&ctx);
}
ctx.state = haveConnection;
if (!uniDRIGetClientDriverName(ctx.display, ctx.screen,
&ctx.ddxDriverMajor, &ctx.ddxDriverMinor,
&ctx.ddxDriverPatch, &ctx.driverName)) {
fprintf(stderr, "Could not get DRI driver name.\n");
return releaseContext(&ctx);
}
ctx.state = haveDriverName;
if (!uniDRIGetDeviceInfo(ctx.display, ctx.screen,
&ctx.fbHandle, &ctx.fbOrigin, &ctx.fbSize,
&ctx.fbStride, &ctx.driPrivSize, &ctx.driPriv)) {
fprintf(stderr, "Could not get DRI device info.\n");
return releaseContext(&ctx);
}
ctx.state = haveDriverName;
if ((ctx.drmFD = drmOpen(NULL, ctx.curBusID)) < 0) {
perror("DRM Device could not be opened");
return releaseContext(&ctx);
}
ctx.state = haveDRM;
drmGetMagic(ctx.drmFD, &magic);
if (!uniDRIAuthConnection(ctx.display, ctx.screen, magic)) {
fprintf(stderr, "Could not get X server to authenticate us.\n");
return releaseContext(&ctx);
}
ret = XMatchVisualInfo(ctx.display, ctx.screen, 24, TrueColor,
&ctx.visualInfo);
if (!ret) {
ret = XMatchVisualInfo(ctx.display, ctx.screen, 16, TrueColor,
&ctx.visualInfo);
if (!ret) {
fprintf(stderr, "Could not find a matching visual.\n");
return releaseContext(&ctx);
}
}
if (!uniDRICreateContext(ctx.display, ctx.screen, ctx.visualInfo.visual,
&ctx.id, &ctx.hwContext)) {
fprintf(stderr, "Could not create DRI context.\n");
return releaseContext(&ctx);
}
ctx.state = haveContext;
testAGP(&ctx);
releaseContext(&ctx);
printf("Terminating normally\n");
return 0;
}