blob: 335368a70c52072b3edf6542b0aecbb9bb02b542 [file] [log] [blame]
/*
* Copyright (c) 2008-2009 Intel Corporation. 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 above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* 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 PRECISION INSIGHT 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.
*/
/* gcc -o putsurface putsurface.c -lva -lva-x11 -I/usr/include/va */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "va.h"
#include "va_x11.h"
#include <assert.h>
#include <pthread.h>
/*currently, if XCheckWindowEvent was called in more than one thread, it would cause
* XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0.0"
* after 87 requests (83 known processed) with 0 events remaining.
*
* X Error of failed request: BadGC (invalid GC parameter)
* Major opcode of failed request: 60 (X_FreeGC)
* Resource id in failed request: 0x600034
* Serial number of failed request: 398
* Current serial number in output stream: 399
* The root cause is unknown. */
#define CHECK_VASTATUS(va_status,func) \
if (va_status != VA_STATUS_SUCCESS) { \
fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
exit(1); \
}
#include "loadsurface.h"
#define SURFACE_NUM 5
static VASurfaceID surface_id[SURFACE_NUM];
static int surface_width=352, surface_height=288;
static int win_width=352, win_height=288;
static Window win_thread0, win_thread1;
static Pixmap pixmap_thread0, pixmap_thread1;
static GC context_thread0, context_thread1;
static Display *x11_display;
static VADisplay *va_dpy;
static int multi_thread=0;
static int put_pixmap = 0;
static int test_clip = 0;
static int display_field = VA_FRAME_PICTURE;
static int check_event = 1;
static int verbose=0;
static pthread_mutex_t surface_mutex[SURFACE_NUM];
static pthread_mutex_t gmutex;
static int box_width=32;
static Pixmap create_pixmap(int width, int height)
{
int screen = DefaultScreen(x11_display);
Window root;
Pixmap pixmap;
XWindowAttributes attr;
root = RootWindow(x11_display, screen);
XGetWindowAttributes (x11_display, root, &attr);
printf("Create a pixmap from ROOT window %dx%d\n\n", attr.width, attr.height);
pixmap = XCreatePixmap(x11_display, root, attr.width, attr.height,
DefaultDepth(x11_display, DefaultScreen(x11_display)));
return pixmap;
}
static int create_window(int width, int height)
{
int screen = DefaultScreen(x11_display);
Window root, win;
root = RootWindow(x11_display, screen);
printf("Create window0 for thread0\n");
win_thread0 = win = XCreateSimpleWindow(x11_display, root, 0, 0, width, height,
0, 0, WhitePixel(x11_display, 0));
if (win) {
XSizeHints sizehints;
sizehints.width = width;
sizehints.height = height;
sizehints.flags = USSize;
XSetNormalHints(x11_display, win, &sizehints);
XSetStandardProperties(x11_display, win, "Thread 0", "Thread 0",
None, (char **)NULL, 0, &sizehints);
XMapWindow(x11_display, win);
}
context_thread0 = XCreateGC(x11_display, win, 0, 0);
XSelectInput(x11_display, win, KeyPressMask | StructureNotifyMask);
XSync(x11_display, False);
if (put_pixmap)
pixmap_thread0 = create_pixmap(width, height);
if (multi_thread == 0)
return 0;
printf("Create window1 for thread1\n");
win_thread1 = win = XCreateSimpleWindow(x11_display, root, width, 0, width, height,
0, 0, WhitePixel(x11_display, 0));
if (win) {
XSizeHints sizehints;
sizehints.width = width;
sizehints.height = height;
sizehints.flags = USSize;
XSetNormalHints(x11_display, win, &sizehints);
XSetStandardProperties(x11_display, win, "Thread 1", "Thread 1",
None, (char **)NULL, 0, &sizehints);
XMapWindow(x11_display, win);
}
if (put_pixmap)
pixmap_thread1 = create_pixmap(width, height);
context_thread1 = XCreateGC(x11_display, win, 0, 0);
XSelectInput(x11_display, win, KeyPressMask | StructureNotifyMask);
XSync(x11_display, False);
return 0;
}
static VASurfaceID get_next_free_surface(int *index)
{
VASurfaceStatus surface_status;
int i;
assert(index);
for (i=0; i<SURFACE_NUM; i++) {
surface_status = 0;
vaQuerySurfaceStatus(va_dpy, surface_id[i], &surface_status);
if (surface_status == VASurfaceReady)
{
if (0 == pthread_mutex_trylock(&surface_mutex[i]))
{
*index = i;
break;
}
}
}
if (i==SURFACE_NUM)
return VA_INVALID_SURFACE;
else
return surface_id[i];
}
/*
* Helper function for profiling purposes
*/
static unsigned long get_tick_count(void)
{
struct timeval tv;
if (gettimeofday(&tv, NULL))
return 0;
return tv.tv_usec/1000+tv.tv_sec*1000;
}
static int putsurface_thread(void *data)
{
int width=win_width, height=win_height;
Drawable draw;
Window win = (Window)data;
Pixmap pixmap = 0;
GC context = NULL;
int quit = 0;
VAStatus vaStatus;
int row_shift = 0;
int index = 0;
Bool is_event;
XEvent event;
unsigned int frame_num=0, start_time, putsurface_time;
VARectangle cliprects[2]; /* client supplied clip list */
if (win == win_thread0) {
printf("Enter into thread0\n\n");
pixmap = pixmap_thread0;
context = context_thread0;
}
if (win == win_thread1) {
printf("Enter into thread1\n\n");
pixmap = pixmap_thread1;
context = context_thread1;
}
if (put_pixmap) {
printf("vaPutSurface into a Pixmap, then copy into the Window\n\n");
draw = pixmap;
} else {
printf("vaPutSurface into a Window directly\n\n");
draw = win;
}
putsurface_time = 0;
while (!quit) {
VASurfaceID surface_id = VA_INVALID_SURFACE;
while (surface_id == VA_INVALID_SURFACE)
surface_id = get_next_free_surface(&index);
if (verbose) printf("Thread %x Display surface 0x%p,\n", (unsigned int)win, (void *)surface_id);
upload_surface(va_dpy, surface_id, box_width, row_shift, display_field);
start_time = get_tick_count();
vaStatus = vaPutSurface(va_dpy, surface_id, draw,
0,0,surface_width,surface_height,
0,0,width,height,
(test_clip==0)?NULL:&cliprects[0],
(test_clip==0)?0:2,
display_field);
CHECK_VASTATUS(vaStatus,"vaPutSurface");
putsurface_time += (get_tick_count() - start_time);
if ((frame_num % 0xff) == 0) {
fprintf(stderr, "%.2f FPS \r", 256000.0 / (float)putsurface_time);
putsurface_time = 0;
if (test_clip) {
srand((unsigned)time(NULL));
cliprects[0].x = (rand() % width);
cliprects[0].y = (rand() % height);
cliprects[0].width = (rand() % (width - cliprects[0].x));
cliprects[0].height = (rand() % (height - cliprects[0].y));
cliprects[1].x = (rand() % width);
cliprects[1].y = (rand() % height);
cliprects[1].width = (rand() % (width - cliprects[1].x));
cliprects[1].height = (rand() % (height - cliprects[1].y));
printf("\nTest clip (%d,%d, %d x %d) and (%d,%d, %d x %d) \n",
cliprects[0].x, cliprects[0].y, cliprects[0].width, cliprects[0].height,
cliprects[1].x, cliprects[1].y, cliprects[1].width, cliprects[1].height);
}
}
if (put_pixmap)
XCopyArea(x11_display, pixmap, win, context, 0, 0, width, height, 0, 0);
pthread_mutex_unlock(&surface_mutex[index]);
if (check_event) {
pthread_mutex_lock(&gmutex);
is_event = XCheckWindowEvent(x11_display, win, StructureNotifyMask|KeyPressMask,&event);
pthread_mutex_unlock(&gmutex);
if (is_event) {
/* bail on any focused key press */
if(event.type == KeyPress) {
quit = 1;
break;
}
/* rescale the video to fit the window */
if(event.type == ConfigureNotify) {
width = event.xconfigure.width;
height = event.xconfigure.height;
printf("Scale window to %dx%d\n", width, height);
}
}
}
row_shift++;
if (row_shift==(2*box_width)) row_shift= 0;
frame_num++;
}
pthread_exit(NULL);
}
int main(int argc,char **argv)
{
int major_ver, minor_ver;
VAStatus va_status;
pthread_t thread1;
int ret;
char c;
int i;
while ((c =getopt(argc,argv,"w:h:d:f:tcep?nv") ) != EOF) {
switch (c) {
case '?':
printf("putsurface <options>\n");
printf(" -p output to pixmap\n");
printf(" -d the dimension of black/write square box, default is 32\n");
printf(" -t multi-threads\n");
printf(" -e don't check X11 event\n");
printf(" -c test clipbox\n");
printf(" -f <1/2> top field, or bottom field\n");
printf(" -v verbose output\n");
exit(0);
break;
case 'w':
win_width = atoi(optarg);
break;
case 'h':
win_height = atoi(optarg);
break;
case 'd':
box_width = atoi(optarg);
break;
case 't':
multi_thread = 1;
printf("Two threads to do vaPutSurface\n");
break;
case 'e':
check_event = 0;
break;
case 'p':
put_pixmap = 1;
break;
case 'c':
test_clip = 1;
break;
case 'f':
if (atoi(optarg) == 1) {
printf("Display TOP field\n");
display_field = VA_TOP_FIELD;
} else if (atoi(optarg) == 2) {
printf("Display BOTTOM field\n");
display_field = VA_BOTTOM_FIELD;
} else
printf("The validate input for -f is: 1(top field)/2(bottom field)\n");
break;
case 'v':
verbose = 1;
printf("Enable verbose output\n");
break;
}
}
x11_display = XOpenDisplay(":0.0");
if (x11_display == NULL) {
fprintf(stderr, "Can't connect X server!\n");
exit(-1);
}
create_window(win_width, win_height);
va_dpy = vaGetDisplay(x11_display);
va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
CHECK_VASTATUS(va_status, "vaInitialize");
surface_width = win_width;
surface_height = win_height;
va_status = vaCreateSurfaces(va_dpy,surface_width, surface_height,
VA_RT_FORMAT_YUV420, SURFACE_NUM, &surface_id[0]);
CHECK_VASTATUS(va_status, "vaCreateSurfaces");
if (check_event)
pthread_mutex_init(&gmutex, NULL);
for(i = 0; i< SURFACE_NUM; i++)
pthread_mutex_init(&surface_mutex[i], NULL);
if (multi_thread == 1)
ret = pthread_create(&thread1, NULL, (void *)putsurface_thread, (void*)win_thread1);
putsurface_thread((void *)win_thread0);
if (multi_thread == 1)
pthread_join(thread1, (void **)&ret);
vaDestroySurfaces(va_dpy,&surface_id[0],SURFACE_NUM);
vaTerminate(va_dpy);
return 0;
}