diff options
author | Younes Manton <younes.m@gmail.com> | 2008-09-17 22:00:37 -0400 |
---|---|---|
committer | Younes Manton <younes.m@gmail.com> | 2008-09-17 22:00:37 -0400 |
commit | 6fca18696d0e6a243f6fbb5a30de45100a8e5fa0 (patch) | |
tree | 213d3490590fedb2279ac8536b767c20ea2a4e2c /src/libXvMC/tests | |
parent | 3122f2bebe8d76568916b8cddff542f52466055e (diff) |
g3dvl: Update XvMC unit tests.
Diffstat (limited to 'src/libXvMC/tests')
-rw-r--r-- | src/libXvMC/tests/.gitignore | 2 | ||||
-rw-r--r-- | src/libXvMC/tests/Makefile | 10 | ||||
-rw-r--r-- | src/libXvMC/tests/test_blocks.c | 29 | ||||
-rw-r--r-- | src/libXvMC/tests/test_context.c | 24 | ||||
-rw-r--r-- | src/libXvMC/tests/test_rendering.c | 322 | ||||
-rw-r--r-- | src/libXvMC/tests/testlib.c | 44 | ||||
-rw-r--r-- | src/libXvMC/tests/testlib.h | 6 | ||||
-rw-r--r-- | src/libXvMC/tests/xvmc_bench.c | 271 |
8 files changed, 569 insertions, 139 deletions
diff --git a/src/libXvMC/tests/.gitignore b/src/libXvMC/tests/.gitignore index eb1ef8a076..e1d2f9023d 100644 --- a/src/libXvMC/tests/.gitignore +++ b/src/libXvMC/tests/.gitignore @@ -2,4 +2,4 @@ test_context test_surface test_blocks test_rendering - +xvmc_bench diff --git a/src/libXvMC/tests/Makefile b/src/libXvMC/tests/Makefile index 2cbc97e88b..de095161d2 100644 --- a/src/libXvMC/tests/Makefile +++ b/src/libXvMC/tests/Makefile @@ -1,4 +1,4 @@ -CFLAGS += -g -Wall -Werror +CFLAGS += -g -Wall LDFLAGS += LIBS += -lXvMCW -lXvMC -lXv @@ -6,7 +6,7 @@ LIBS += -lXvMCW -lXvMC -lXv .PHONY = all clean -all: test_context test_surface test_blocks test_rendering +all: test_context test_surface test_blocks test_rendering xvmc_bench test_context: test_context.o testlib.o $(CC) ${LDFLAGS} -o $@ $^ ${LIBS} @@ -20,6 +20,8 @@ test_blocks: test_blocks.o testlib.o test_rendering: test_rendering.o testlib.o $(CC) ${LDFLAGS} -o $@ $^ ${LIBS} -clean: - rm -rf *.o test_context test_surface test_blocks test_rendering +xvmc_bench: xvmc_bench.o testlib.o + $(CC) ${LDFLAGS} -o $@ $^ ${LIBS} +clean: + rm -rf *.o test_context test_surface test_blocks test_rendering xvmc_bench diff --git a/src/libXvMC/tests/test_blocks.c b/src/libXvMC/tests/test_blocks.c index 0b895ee773..dc80adfa65 100644 --- a/src/libXvMC/tests/test_blocks.c +++ b/src/libXvMC/tests/test_blocks.c @@ -7,7 +7,7 @@ int main(int argc, char **argv) const unsigned int width = 16, height = 16; const unsigned int min_required_blocks = 1, min_required_macroblocks = 1; const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2}; - + Display *display; XvPortID port_num; int surface_type_id; @@ -17,9 +17,9 @@ int main(int argc, char **argv) XvMCSurface surface; XvMCBlockArray blocks = {0}; XvMCMacroBlockArray macroblocks = {0}; - + display = XOpenDisplay(NULL); - + if (!GetPort ( display, @@ -37,25 +37,20 @@ int main(int argc, char **argv) XCloseDisplay(display); error(1, 0, "Error, unable to find a good port.\n"); } - + if (is_overlay) { Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0); XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey); } - + assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, &context) == Success); assert(XvMCCreateSurface(display, &context, &surface) == Success); - + /* Test NULL context */ assert(XvMCCreateBlocks(display, NULL, 1, &blocks) == XvMCBadContext); /* Test 0 blocks */ assert(XvMCCreateBlocks(display, &context, 0, &blocks) == BadValue); - /* Test too many blocks */ - /*assert(XvMCCreateBlocks(display, &context, 16384, &blocks) == BadAlloc);*/ - - /* Note: No XvMCBadBlock(s) error in spec */ - /* Test valid params */ assert(XvMCCreateBlocks(display, &context, min_required_blocks, &blocks) == Success); /* Test context id assigned and correct */ @@ -68,11 +63,6 @@ int main(int argc, char **argv) assert(XvMCCreateMacroBlocks(display, NULL, 1, ¯oblocks) == XvMCBadContext); /* Test 0 macroblocks */ assert(XvMCCreateMacroBlocks(display, &context, 0, ¯oblocks) == BadValue); - /* Test too many macroblocks */ - /*assert(XvMCCreateMacroBlocks(display, &context, 16384, ¯oblocks) == BadAlloc);*/ - - /* Note: No XvMCBadMacroBlock(s) error in spec */ - /* Test valid params */ assert(XvMCCreateMacroBlocks(display, &context, min_required_macroblocks, ¯oblocks) == Success); /* Test context id assigned and correct */ @@ -83,13 +73,12 @@ int main(int argc, char **argv) assert(XvMCDestroyMacroBlocks(display, ¯oblocks) == Success); /* Test valid params */ assert(XvMCDestroyBlocks(display, &blocks) == Success); - + assert(XvMCDestroySurface(display, &surface) == Success); assert(XvMCDestroyContext(display, &context) == Success); - + XvUngrabPort(display, port_num, CurrentTime); XCloseDisplay(display); - + return 0; } - diff --git a/src/libXvMC/tests/test_context.c b/src/libXvMC/tests/test_context.c index 22afb7ada4..53f7449cd0 100644 --- a/src/libXvMC/tests/test_context.c +++ b/src/libXvMC/tests/test_context.c @@ -6,16 +6,16 @@ int main(int argc, char **argv) { const unsigned int width = 16, height = 16; const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2}; - + Display *display; XvPortID port_num; int surface_type_id; unsigned int is_overlay, intra_unsigned; int colorkey; XvMCContext context = {0}; - + display = XOpenDisplay(NULL); - + if (!GetPort ( display, @@ -33,22 +33,21 @@ int main(int argc, char **argv) XCloseDisplay(display); error(1, 0, "Error, unable to find a good port.\n"); } - + if (is_overlay) { Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0); XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey); } - - /* Note: XvMCBadContext not a valid return for XvMCCreateContext in the XvMC API, but openChrome driver returns it */ - /* Note: Nvidia binary driver segfaults on NULL context, halts with debug output on bad port */ - + /* Test NULL context */ + /* XXX: XvMCBadContext not a valid return for XvMCCreateContext in the XvMC API, but openChrome driver returns it */ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, NULL) == XvMCBadContext); /* Test invalid port */ - assert(XvMCCreateContext(display, port_num + 1, surface_type_id, width, height, XVMC_DIRECT, &context) == XvBadPort); + /* XXX: Success and XvBadPort have the same value, if this call actually gets passed the validation step as of now we'll crash later */ + assert(XvMCCreateContext(display, -1, surface_type_id, width, height, XVMC_DIRECT, &context) == XvBadPort); /* Test invalid surface */ - assert(XvMCCreateContext(display, port_num, surface_type_id + 1, width, height, XVMC_DIRECT, &context) == BadMatch); + assert(XvMCCreateContext(display, port_num, -1, width, height, XVMC_DIRECT, &context) == BadMatch); /* Test invalid flags */ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, -1, &context) == BadValue); /* Test huge width */ @@ -85,10 +84,9 @@ int main(int argc, char **argv) assert(XvMCCreateContext(display, port_num, surface_type_id, width + 1, height + 1, XVMC_DIRECT, &context) == Success); assert(context.width >= width + 1 && context.height >= height + 1); assert(XvMCDestroyContext(display, &context) == Success); - + XvUngrabPort(display, port_num, CurrentTime); XCloseDisplay(display); - + return 0; } - diff --git a/src/libXvMC/tests/test_rendering.c b/src/libXvMC/tests/test_rendering.c index 1914b1fb62..1e7467a3aa 100644 --- a/src/libXvMC/tests/test_rendering.c +++ b/src/libXvMC/tests/test_rendering.c @@ -1,38 +1,126 @@ #include <assert.h> #include <stdio.h> +#include <string.h> #include <error.h> #include "testlib.h" +#define BLOCK_WIDTH 8 +#define BLOCK_HEIGHT 8 +#define BLOCK_SIZE (BLOCK_WIDTH * BLOCK_HEIGHT) +#define MACROBLOCK_WIDTH 16 +#define MACROBLOCK_HEIGHT 16 +#define MACROBLOCK_WIDTH_IN_BLOCKS (MACROBLOCK_WIDTH / BLOCK_WIDTH) +#define MACROBLOCK_HEIGHT_IN_BLOCKS (MACROBLOCK_HEIGHT / BLOCK_HEIGHT) +#define BLOCKS_PER_MACROBLOCK 6 + +#define INPUT_WIDTH 16 +#define INPUT_HEIGHT 16 +#define INPUT_WIDTH_IN_MACROBLOCKS (INPUT_WIDTH / MACROBLOCK_WIDTH) +#define INPUT_HEIGHT_IN_MACROBLOCKS (INPUT_HEIGHT / MACROBLOCK_HEIGHT) +#define NUM_MACROBLOCKS (INPUT_WIDTH_IN_MACROBLOCKS * INPUT_HEIGHT_IN_MACROBLOCKS) + +#define DEFAULT_OUTPUT_WIDTH INPUT_WIDTH +#define DEFAULT_OUTPUT_HEIGHT INPUT_HEIGHT +#define DEFAULT_ACCEPTABLE_ERR 0.01 + +void ParseArgs(int argc, char **argv, unsigned int *output_width, unsigned int *output_height, double *acceptable_error, int *prompt) +{ + int fail = 0; + int i; + + *output_width = DEFAULT_OUTPUT_WIDTH; + *output_height = DEFAULT_OUTPUT_WIDTH; + *acceptable_error = DEFAULT_ACCEPTABLE_ERR; + *prompt = 1; + + for (i = 1; i < argc && !fail; ++i) + { + if (!strcmp(argv[i], "-w")) + { + if (sscanf(argv[++i], "%u", output_width) != 1) + fail = 1; + } + else if (!strcmp(argv[i], "-h")) + { + if (sscanf(argv[++i], "%u", output_height) != 1) + fail = 1; + } + else if (!strcmp(argv[i], "-e")) + { + if (sscanf(argv[++i], "%lf", acceptable_error) != 1) + fail = 1; + } + else if (strcmp(argv[i], "-n")) + *prompt = 0; + else + fail = 1; + } + + if (fail) + error + ( + 1, 0, + "Bad argument.\n" + "\n" + "Usage: %s [options]\n" + "\t-w <width>\tOutput width\n" + "\t-h <height>\tOutput height\n" + "\t-e <error>\tAcceptable margin of error per pixel, from 0 to 1\n" + "\t-n\tDon't prompt for quit\n", + argv[0] + ); +} + +void Gradient(short *block, unsigned int start, unsigned int stop, int horizontal) +{ + unsigned int x, y; + unsigned int range = stop - start; + + if (horizontal) + { + for (y = 0; y < BLOCK_HEIGHT; ++y) + for (x = 0; x < BLOCK_WIDTH; ++x) + block[y * BLOCK_WIDTH + x] = (short)(start + range * (x / (float)(BLOCK_WIDTH - 1))); + } + else + { + for (y = 0; y < BLOCK_HEIGHT; ++y) + for (x = 0; x < BLOCK_WIDTH; ++x) + block[y * BLOCK_WIDTH + x] = (short)(start + range * (y / (float)(BLOCK_HEIGHT - 1))); + } +} + int main(int argc, char **argv) { - const unsigned int width = 32, height = 32; - const unsigned int mwidth = width / 16, mheight = height / 16; - const unsigned int num_macroblocks = mwidth * mheight; - const unsigned int num_blocks = num_macroblocks * 6; - const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2}; - - int quit = 0; + unsigned int output_width; + unsigned int output_height; + double acceptable_error; + int prompt; Display *display; Window root, window; - Pixmap framebuffer; - XEvent event; + const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2}; XvPortID port_num; int surface_type_id; unsigned int is_overlay, intra_unsigned; int colorkey; XvMCContext context; XvMCSurface surface; - XvMCBlockArray blocks; - XvMCMacroBlockArray macroblocks; - unsigned int b, x, y; - + XvMCBlockArray block_array; + XvMCMacroBlockArray mb_array; + int mbx, mby, bx, by; + XvMCMacroBlock *mb; + short *blocks; + int quit = 0; + + ParseArgs(argc, argv, &output_width, &output_height, &acceptable_error, &prompt); + display = XOpenDisplay(NULL); - + if (!GetPort ( display, - width, - height, + INPUT_WIDTH, + INPUT_HEIGHT, XVMC_CHROMA_FORMAT_420, mc_types, 2, @@ -45,109 +133,155 @@ int main(int argc, char **argv) XCloseDisplay(display); error(1, 0, "Error, unable to find a good port.\n"); } - + if (is_overlay) { Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0); XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey); } - + root = XDefaultRootWindow(display); - window = XCreateSimpleWindow(display, root, 0, 0, width, height, 0, 0, colorkey); - framebuffer = XCreatePixmap(display, root, width, height, 24); - - XSelectInput(display, window, ExposureMask | KeyPressMask); - XMapWindow(display, window); - XSync(display, 0); - - assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, &context) == Success); + window = XCreateSimpleWindow(display, root, 0, 0, output_width, output_height, 0, 0, colorkey); + + assert(XvMCCreateContext(display, port_num, surface_type_id, INPUT_WIDTH, INPUT_HEIGHT, XVMC_DIRECT, &context) == Success); assert(XvMCCreateSurface(display, &context, &surface) == Success); - assert(XvMCCreateBlocks(display, &context, num_blocks, &blocks) == Success); - assert(XvMCCreateMacroBlocks(display, &context, num_macroblocks, ¯oblocks) == Success); - - for (b = 0; b < 6; ++b) - { - for (y = 0; y < 8; ++y) - { - for (x = 0; x < 8; ++x) - { - blocks.blocks[b * 64 + y * 8 + x] = 0xFFFF; - } - } - } - - for (y = 0; y < mheight; ++y) - { - for (x = 0; x < mwidth; ++x) + assert(XvMCCreateBlocks(display, &context, NUM_MACROBLOCKS * BLOCKS_PER_MACROBLOCK, &block_array) == Success); + assert(XvMCCreateMacroBlocks(display, &context, NUM_MACROBLOCKS, &mb_array) == Success); + + mb = mb_array.macro_blocks; + blocks = block_array.blocks; + + for (mby = 0; mby < INPUT_HEIGHT_IN_MACROBLOCKS; ++mby) + for (mbx = 0; mbx < INPUT_WIDTH_IN_MACROBLOCKS; ++mbx) { - macroblocks.macro_blocks[y * mwidth + x].x = x; - macroblocks.macro_blocks[y * mwidth + x].y = y; - macroblocks.macro_blocks[y * mwidth + x].index = (y * mwidth + x) * 6; - macroblocks.macro_blocks[y * mwidth + x].macroblock_type = XVMC_MB_TYPE_INTRA; - macroblocks.macro_blocks[y * mwidth + x].coded_block_pattern = 0x3F; - macroblocks.macro_blocks[y * mwidth + x].dct_type = XVMC_DCT_TYPE_FRAME; + mb->x = mbx; + mb->y = mby; + mb->macroblock_type = XVMC_MB_TYPE_INTRA; + /*mb->motion_type = ;*/ + /*mb->motion_vertical_field_select = ;*/ + mb->dct_type = XVMC_DCT_TYPE_FRAME; + /*mb->PMV[0][0][0] = ; + mb->PMV[0][0][1] = ; + mb->PMV[0][1][0] = ; + mb->PMV[0][1][1] = ; + mb->PMV[1][0][0] = ; + mb->PMV[1][0][1] = ; + mb->PMV[1][1][0] = ; + mb->PMV[1][1][1] = ;*/ + mb->index = (mby * INPUT_WIDTH_IN_MACROBLOCKS + mbx) * BLOCKS_PER_MACROBLOCK; + mb->coded_block_pattern = 0x3F; + + mb++; + + for (by = 0; by < MACROBLOCK_HEIGHT_IN_BLOCKS; ++by) + for (bx = 0; bx < MACROBLOCK_WIDTH_IN_BLOCKS; ++bx) + { + const int start = 16, stop = 235, range = stop - start; + + Gradient + ( + blocks, + (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))), + (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))), + 1 + ); + + blocks += BLOCK_SIZE; + } + + for (by = 0; by < MACROBLOCK_HEIGHT_IN_BLOCKS / 2; ++by) + for (bx = 0; bx < MACROBLOCK_WIDTH_IN_BLOCKS / 2; ++bx) + { + const int start = 16, stop = 240, range = stop - start; + + Gradient + ( + blocks, + (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))), + (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))), + 1 + ); + + blocks += BLOCK_SIZE; + + Gradient + ( + blocks, + (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))), + (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))), + 1 + ); + + blocks += BLOCK_SIZE; + } } - } - + + XSelectInput(display, window, ExposureMask | KeyPressMask); + XMapWindow(display, window); + XSync(display, 0); + /* Test NULL context */ - assert(XvMCRenderSurface(display, NULL, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, 1, 0, ¯oblocks, &blocks) == XvMCBadContext); + assert(XvMCRenderSurface(display, NULL, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == XvMCBadContext); /* Test NULL surface */ - assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, NULL, NULL, NULL, 0, 1, 0, ¯oblocks, &blocks) == XvMCBadSurface); + assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, NULL, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == XvMCBadSurface); /* Test bad picture structure */ - assert(XvMCRenderSurface(display, &context, 0, &surface, NULL, NULL, 0, 1, 0, ¯oblocks, &blocks) == BadValue); + assert(XvMCRenderSurface(display, &context, 0, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == BadValue); /* Test valid params */ - assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, num_macroblocks, 0, ¯oblocks, &blocks) == Success); - + assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == Success); + /* Test NULL surface */ - assert(XvMCPutSurface(display, NULL, window, 0, 0, width, height, 0, 0, width, height, XVMC_FRAME_PICTURE) == XvMCBadSurface); + assert(XvMCPutSurface(display, NULL, window, 0, 0, INPUT_WIDTH, INPUT_HEIGHT, 0, 0, output_width, output_height, XVMC_FRAME_PICTURE) == XvMCBadSurface); /* Test bad window */ - /* X halts with a bad drawable for some reason, doesn't return BadDrawable as expected */ + /* XXX: X halts with a bad drawable for some reason, doesn't return BadDrawable as expected */ /*assert(XvMCPutSurface(display, &surface, 0, 0, 0, width, height, 0, 0, width, height, XVMC_FRAME_PICTURE) == BadDrawable);*/ - /* Test valid params */ - assert(XvMCPutSurface(display, &surface, framebuffer, 0, 0, width, height, 0, 0, width, height, XVMC_FRAME_PICTURE) == Success); - - puts("Press any key to continue..."); - - while (!quit) + + if (prompt) { - XNextEvent(display, &event); - switch (event.type) + puts("Press any button to quit..."); + + while (!quit) { - case Expose: - { - XCopyArea - ( - display, - framebuffer, - window, - XDefaultGC(display, XDefaultScreen(display)), - 0, - 0, - width, - height, - 0, - 0 - ); - break; - } - case KeyPress: + if (XPending(display) > 0) { - quit = 1; - break; + XEvent event; + + XNextEvent(display, &event); + + switch (event.type) + { + case Expose: + { + /* Test valid params */ + assert + ( + XvMCPutSurface + ( + display, &surface, window, + 0, 0, INPUT_WIDTH, INPUT_HEIGHT, + 0, 0, output_width, output_height, + XVMC_FRAME_PICTURE + ) == Success + ); + break; + } + case KeyPress: + { + quit = 1; + break; + } + } } } } - - assert(XvMCDestroyBlocks(display, &blocks) == Success); - assert(XvMCDestroyMacroBlocks(display, ¯oblocks) == Success); - assert(XvMCDestroySurface(display, &surface) == Success); + + assert(XvMCDestroyBlocks(display, &block_array) == Success); + assert(XvMCDestroyMacroBlocks(display, &mb_array) == Success); + assert(XvMCDestroySurface(display, &surface) == Success); assert(XvMCDestroyContext(display, &context) == Success); - - XFreePixmap(display, framebuffer); + XvUngrabPort(display, port_num, CurrentTime); XDestroyWindow(display, window); XCloseDisplay(display); - + return 0; } - diff --git a/src/libXvMC/tests/testlib.c b/src/libXvMC/tests/testlib.c index 8672aa9999..59a03ca813 100644 --- a/src/libXvMC/tests/testlib.c +++ b/src/libXvMC/tests/testlib.c @@ -32,18 +32,18 @@ int GetPort int num_types; int ev_base, err_base; unsigned int i, j, k, l; - + if (!XvMCQueryExtension(display, &ev_base, &err_base)) return 0; if (XvQueryAdaptors(display, XDefaultRootWindow(display), &num_adaptors, &adaptor_info) != Success) return 0; - + for (i = 0; i < num_adaptors && !found_port; ++i) { if (adaptor_info[i].type & XvImageMask) { XvMCSurfaceInfo *surface_info = XvMCListSurfaceTypes(display, adaptor_info[i].base_id, &num_types); - + if (surface_info) { for (j = 0; j < num_types && !found_port; ++j) @@ -74,14 +74,46 @@ int GetPort } } } - + XFree(surface_info); } } } - + XvFreeAdaptorInfo(adaptor_info); - + return found_port; } +unsigned int align(unsigned int value, unsigned int alignment) +{ + return (value + alignment - 1) & ~(alignment - 1); +} + +/* From the glibc manual */ +int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) +{ + /* Perform the carry for the later subtraction by updating y. */ + if (x->tv_usec < y->tv_usec) + { + int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; + y->tv_usec -= 1000000 * nsec; + y->tv_sec += nsec; + } + if (x->tv_usec - y->tv_usec > 1000000) + { + int nsec = (x->tv_usec - y->tv_usec) / 1000000; + y->tv_usec += 1000000 * nsec; + y->tv_sec -= nsec; + } + + /* + * Compute the time remaining to wait. + * tv_usec is certainly positive. + */ + result->tv_sec = x->tv_sec - y->tv_sec; + result->tv_usec = x->tv_usec - y->tv_usec; + + /* Return 1 if result is negative. */ + return x->tv_sec < y->tv_sec; +} diff --git a/src/libXvMC/tests/testlib.h b/src/libXvMC/tests/testlib.h index c73845807e..af71ad74e1 100644 --- a/src/libXvMC/tests/testlib.h +++ b/src/libXvMC/tests/testlib.h @@ -7,6 +7,7 @@ void test(int pred, const char *pred_string, const char *doc_string, const char *file, unsigned int line); */ +#include <sys/time.h> #include <X11/Xlib.h> #include <X11/extensions/XvMClib.h> @@ -34,5 +35,8 @@ int GetPort unsigned int *intra_unsigned ); -#endif +unsigned int align(unsigned int value, unsigned int alignment); + +int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y); +#endif diff --git a/src/libXvMC/tests/xvmc_bench.c b/src/libXvMC/tests/xvmc_bench.c new file mode 100644 index 0000000000..16f6c21ae3 --- /dev/null +++ b/src/libXvMC/tests/xvmc_bench.c @@ -0,0 +1,271 @@ +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <error.h> +#include <sys/time.h> +#include "testlib.h" + +#define MACROBLOCK_WIDTH 16 +#define MACROBLOCK_HEIGHT 16 +#define BLOCKS_PER_MACROBLOCK 6 + +#define DEFAULT_INPUT_WIDTH 720 +#define DEFAULT_INPUT_HEIGHT 480 +#define DEFAULT_REPS 100 + +#define PIPELINE_STEP_MC 1 +#define PIPELINE_STEP_CSC 2 +#define PIPELINE_STEP_SWAP 4 + +#define MB_TYPE_I 1 +#define MB_TYPE_P 2 +#define MB_TYPE_B 4 + +struct Config +{ + unsigned int input_width; + unsigned int input_height; + unsigned int output_width; + unsigned int output_height; + unsigned int pipeline; + unsigned int mb_types; + unsigned int reps; +}; + +void ParseArgs(int argc, char **argv, struct Config *config) +{ + int fail = 0; + int i; + + config->input_width = DEFAULT_INPUT_WIDTH; + config->input_height = DEFAULT_INPUT_HEIGHT; + config->output_width = 0; + config->output_height = 0; + config->pipeline = 0; + config->mb_types = 0; + config->reps = DEFAULT_REPS; + + for (i = 1; i < argc && !fail; ++i) + { + if (!strcmp(argv[i], "-iw")) + { + if (sscanf(argv[++i], "%u", &config->input_width) != 1) + fail = 1; + } + else if (!strcmp(argv[i], "-ih")) + { + if (sscanf(argv[++i], "%u", &config->input_height) != 1) + fail = 1; + } + else if (!strcmp(argv[i], "-ow")) + { + if (sscanf(argv[++i], "%u", &config->output_width) != 1) + fail = 1; + } + else if (!strcmp(argv[i], "-oh")) + { + if (sscanf(argv[++i], "%u", &config->output_height) != 1) + fail = 1; + } + else if (!strcmp(argv[i], "-p")) + { + char *token = strtok(argv[++i], ","); + + while (token && !fail) + { + if (!strcmp(token, "mc")) + config->pipeline |= PIPELINE_STEP_MC; + else if (!strcmp(token, "csc")) + config->pipeline |= PIPELINE_STEP_CSC; + else if (!strcmp(token, "swp")) + config->pipeline |= PIPELINE_STEP_SWAP; + else + fail = 1; + + if (!fail) + token = strtok(NULL, ","); + } + } + else if (!strcmp(argv[i], "-mb")) + { + char *token = strtok(argv[++i], ","); + + while (token && !fail) + { + if (strcmp(token, "i")) + config->mb_types |= MB_TYPE_I; + else if (strcmp(token, "p")) + config->mb_types |= MB_TYPE_P; + else if (strcmp(token, "b")) + config->mb_types |= MB_TYPE_B; + else + fail = 1; + + if (!fail) + token = strtok(NULL, ","); + } + } + else if (!strcmp(argv[i], "-r")) + { + if (sscanf(argv[++i], "%u", &config->reps) != 1) + fail = 1; + } + else + fail = 1; + } + + if (fail) + error + ( + 1, 0, + "Bad argument.\n" + "\n" + "Usage: %s [options]\n" + "\t-iw <width>\tInput width\n" + "\t-ih <height>\tInput height\n" + "\t-ow <width>\tOutput width\n" + "\t-oh <height>\tOutput height\n" + "\t-p <pipeline>\tPipeline to test\n" + "\t-mb <mb type>\tMacroBlock types to use\n" + "\t-r <reps>\tRepetitions\n\n" + "\tPipeline steps: mc,csc,swap\n" + "\tMB types: i,p,b\n", + argv[0] + ); + + if (config->output_width == 0) + config->output_width = config->input_width; + if (config->output_height == 0) + config->output_height = config->input_height; + if (!config->pipeline) + config->pipeline = PIPELINE_STEP_MC | PIPELINE_STEP_CSC | PIPELINE_STEP_SWAP; + if (!config->mb_types) + config->mb_types = MB_TYPE_I | MB_TYPE_P | MB_TYPE_B; +} + +int main(int argc, char **argv) +{ + struct Config config; + Display *display; + Window root, window; + const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2}; + XvPortID port_num; + int surface_type_id; + unsigned int is_overlay, intra_unsigned; + int colorkey; + XvMCContext context; + XvMCSurface surface; + XvMCBlockArray block_array; + XvMCMacroBlockArray mb_array; + unsigned int mbw, mbh; + unsigned int mbx, mby; + unsigned int reps; + struct timeval start, stop, diff; + double diff_secs; + + ParseArgs(argc, argv, &config); + + mbw = align(config.input_width, MACROBLOCK_WIDTH) / MACROBLOCK_WIDTH; + mbh = align(config.input_height, MACROBLOCK_HEIGHT) / MACROBLOCK_HEIGHT; + + display = XOpenDisplay(NULL); + + if (!GetPort + ( + display, + config.input_width, + config.input_height, + XVMC_CHROMA_FORMAT_420, + mc_types, + 2, + &port_num, + &surface_type_id, + &is_overlay, + &intra_unsigned + )) + { + XCloseDisplay(display); + error(1, 0, "Error, unable to find a good port.\n"); + } + + if (is_overlay) + { + Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0); + XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey); + } + + root = XDefaultRootWindow(display); + window = XCreateSimpleWindow(display, root, 0, 0, config.output_width, config.output_height, 0, 0, colorkey); + + assert(XvMCCreateContext(display, port_num, surface_type_id, config.input_width, config.input_width, XVMC_DIRECT, &context) == Success); + assert(XvMCCreateSurface(display, &context, &surface) == Success); + assert(XvMCCreateBlocks(display, &context, mbw * mbh * BLOCKS_PER_MACROBLOCK, &block_array) == Success); + assert(XvMCCreateMacroBlocks(display, &context, mbw * mbh, &mb_array) == Success); + + for (mby = 0; mby < mbh; ++mby) + for (mbx = 0; mbx < mbw; ++mbx) + { + mb_array.macro_blocks[mby * mbw + mbx].x = mbx; + mb_array.macro_blocks[mby * mbw + mbx].y = mby; + mb_array.macro_blocks[mby * mbw + mbx].macroblock_type = XVMC_MB_TYPE_INTRA; + /*mb->motion_type = ;*/ + /*mb->motion_vertical_field_select = ;*/ + mb_array.macro_blocks[mby * mbw + mbx].dct_type = XVMC_DCT_TYPE_FRAME; + /*mb->PMV[0][0][0] = ; + mb->PMV[0][0][1] = ; + mb->PMV[0][1][0] = ; + mb->PMV[0][1][1] = ; + mb->PMV[1][0][0] = ; + mb->PMV[1][0][1] = ; + mb->PMV[1][1][0] = ; + mb->PMV[1][1][1] = ;*/ + mb_array.macro_blocks[mby * mbw + mbx].index = (mby * mbw + mbx) * BLOCKS_PER_MACROBLOCK; + mb_array.macro_blocks[mby * mbw + mbx].coded_block_pattern = 0x3F; + } + + XSelectInput(display, window, ExposureMask | KeyPressMask); + XMapWindow(display, window); + XSync(display, 0); + + gettimeofday(&start, NULL); + + for (reps = 0; reps < config.reps; ++reps) + { + if (config.pipeline & PIPELINE_STEP_MC) + { + assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, mbw * mbh, 0, &mb_array, &block_array) == Success); + assert(XvMCFlushSurface(display, &surface) == Success); + } + if (config.pipeline & PIPELINE_STEP_CSC) + assert(XvMCPutSurface(display, &surface, window, 0, 0, config.input_width, config.input_height, 0, 0, config.output_width, config.output_height, XVMC_FRAME_PICTURE) == Success); + } + + gettimeofday(&stop, NULL); + + timeval_subtract(&diff, &stop, &start); + diff_secs = (double)diff.tv_sec + (double)diff.tv_usec / 1000000.0; + + printf("XvMC Benchmark\n"); + printf("Input: %u,%u\nOutput: %u,%u\n", config.input_width, config.input_height, config.output_width, config.output_height); + printf("Pipeline: "); + if (config.pipeline & PIPELINE_STEP_MC) + printf("|mc|"); + if (config.pipeline & PIPELINE_STEP_CSC) + printf("|csc|"); + if (config.pipeline & PIPELINE_STEP_SWAP) + printf("|swap|"); + printf("\n"); + printf("Reps: %u\n", config.reps); + printf("Total time: %.2lf (%.2lf reps / sec)\n", diff_secs, config.reps / diff_secs); + + assert(XvMCDestroyBlocks(display, &block_array) == Success); + assert(XvMCDestroyMacroBlocks(display, &mb_array) == Success); + assert(XvMCDestroySurface(display, &surface) == Success); + assert(XvMCDestroyContext(display, &context) == Success); + + XvUngrabPort(display, port_num, CurrentTime); + XDestroyWindow(display, window); + XCloseDisplay(display); + + return 0; +} |