| /* |
| * Test the GL_NV_texture_rectangle and GL_MESA_ycrcb_texture extensions and GLX_MESA_allocate-memory |
| * |
| * Dave Airlie - Feb 2005 |
| */ |
| |
| #include <assert.h> |
| #include <math.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <X11/Xlib.h> |
| #include <X11/keysym.h> |
| #define GL_GLEXT_PROTOTYPES |
| #include <GL/glx.h> |
| |
| #include "../util/readtex.c" /* I know, this is a hack. */ |
| |
| #define TEXTURE_FILE "../images/girl2.rgb" |
| |
| static GLfloat Xrot = 0, Yrot = 0, Zrot = 0; |
| static GLint ImgWidth, ImgHeight; |
| static GLushort *ImageYUV = NULL; |
| static void *glx_memory; |
| |
| static void DrawObject(void) |
| { |
| glBegin(GL_QUADS); |
| |
| glTexCoord2f(0, 0); |
| glVertex2f(-1.0, -1.0); |
| |
| glTexCoord2f(ImgWidth, 0); |
| glVertex2f(1.0, -1.0); |
| |
| glTexCoord2f(ImgWidth, ImgHeight); |
| glVertex2f(1.0, 1.0); |
| |
| glTexCoord2f(0, ImgHeight); |
| glVertex2f(-1.0, 1.0); |
| |
| glEnd(); |
| } |
| |
| |
| static void scr_Display( void ) |
| { |
| glClear( GL_COLOR_BUFFER_BIT ); |
| |
| glPushMatrix(); |
| glRotatef(Xrot, 1.0, 0.0, 0.0); |
| glRotatef(Yrot, 0.0, 1.0, 0.0); |
| glRotatef(Zrot, 0.0, 0.0, 1.0); |
| DrawObject(); |
| glPopMatrix(); |
| |
| } |
| |
| |
| static void Reshape( int width, int height ) |
| { |
| glViewport( 0, 0, width, height ); |
| glMatrixMode( GL_PROJECTION ); |
| glLoadIdentity(); |
| glFrustum( -1.0, 1.0, -1.0, 1.0, 10.0, 100.0 ); |
| glMatrixMode( GL_MODELVIEW ); |
| glLoadIdentity(); |
| glTranslatef( 0.0, 0.0, -15.0 ); |
| } |
| |
| static int queryClient(Display *dpy, int screen) |
| { |
| #ifdef GLX_MESA_allocate_memory |
| char *extensions; |
| |
| extensions = (char *)glXQueryExtensionsString(dpy, screen); |
| if (!extensions || !strstr(extensions,"GLX_MESA_allocate_memory")) { |
| return 0; |
| } |
| |
| return 1; |
| #else |
| return 0; |
| #endif |
| } |
| |
| static int |
| query_extension(char* extName) { |
| char *p = (char *) glGetString(GL_EXTENSIONS); |
| char *end = p + strlen(p); |
| while (p < end) { |
| int n = strcspn(p, " "); |
| if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0)) |
| return GL_TRUE; |
| p += (n + 1); |
| } |
| return GL_FALSE; |
| } |
| |
| static void Init( int argc, char *argv[] , Display *dpy, int screen, Window win) |
| { |
| GLuint texObj = 100; |
| const char *file; |
| void *glx_memory; |
| |
| if (!query_extension("GL_NV_texture_rectangle")) { |
| printf("Sorry, GL_NV_texture_rectangle is required\n"); |
| exit(0); |
| } |
| |
| if (!query_extension("GL_MESA_ycbcr_texture")) { |
| printf("Sorry, GL_MESA_ycbcr_texture is required\n"); |
| exit(0); |
| } |
| |
| if (!queryClient(dpy, screen)) { |
| printf("Sorry, GLX_MESA_allocate_memory is required\n"); |
| exit(0); |
| } |
| |
| glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, 1); |
| glBindTexture(GL_TEXTURE_RECTANGLE_NV, texObj); |
| #ifdef LINEAR_FILTER |
| /* linear filtering looks much nicer but is much slower for Mesa */ |
| glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| #else |
| glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| #endif |
| |
| if (argc > 1) |
| file = argv[1]; |
| else |
| file = TEXTURE_FILE; |
| |
| ImageYUV = LoadYUVImage(file, &ImgWidth, &ImgHeight); |
| if (!ImageYUV) { |
| printf("Couldn't read %s\n", TEXTURE_FILE); |
| exit(0); |
| } |
| |
| glx_memory = glXAllocateMemoryMESA(dpy, screen, ImgWidth * ImgHeight * 2, 0, 0 ,0); |
| if (!glx_memory) |
| { |
| fprintf(stderr,"Failed to allocate MESA memory\n"); |
| exit(-1); |
| } |
| |
| memcpy(glx_memory, ImageYUV, ImgWidth * ImgHeight * 2); |
| |
| printf("Image: %dx%d\n", ImgWidth, ImgHeight); |
| |
| glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, |
| GL_YCBCR_MESA, ImgWidth, ImgHeight, 0, |
| GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_APPLE, glx_memory); |
| |
| assert(glGetError() == GL_NO_ERROR); |
| |
| glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); |
| |
| glEnable(GL_TEXTURE_RECTANGLE_NV); |
| |
| glShadeModel(GL_FLAT); |
| glClearColor(0.3, 0.3, 0.4, 1.0); |
| |
| } |
| |
| /* |
| * Create an RGB, double-buffered window. |
| * Return the window and context handles. |
| */ |
| static void |
| make_window( Display *dpy, const char *name, |
| int x, int y, int width, int height, |
| Window *winRet, GLXContext *ctxRet) |
| { |
| int attribs[] = { GLX_RGBA, |
| GLX_RED_SIZE, 1, |
| GLX_GREEN_SIZE, 1, |
| GLX_BLUE_SIZE, 1, |
| GLX_DOUBLEBUFFER, |
| GLX_DEPTH_SIZE, 1, |
| None }; |
| int scrnum; |
| XSetWindowAttributes attr; |
| unsigned long mask; |
| Window root; |
| Window win; |
| GLXContext ctx; |
| XVisualInfo *visinfo; |
| |
| scrnum = DefaultScreen( dpy ); |
| root = RootWindow( dpy, scrnum ); |
| |
| visinfo = glXChooseVisual( dpy, scrnum, attribs ); |
| if (!visinfo) { |
| printf("Error: couldn't get an RGB, Double-buffered visual\n"); |
| exit(1); |
| } |
| |
| /* window attributes */ |
| attr.background_pixel = 0; |
| attr.border_pixel = 0; |
| attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone); |
| attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; |
| attr.override_redirect = 0; |
| mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect; |
| |
| win = XCreateWindow( dpy, root, 0, 0, width, height, |
| 0, visinfo->depth, InputOutput, |
| visinfo->visual, mask, &attr ); |
| |
| /* set hints and properties */ |
| { |
| XSizeHints sizehints; |
| sizehints.x = x; |
| sizehints.y = y; |
| sizehints.width = width; |
| sizehints.height = height; |
| sizehints.flags = USSize | USPosition; |
| XSetNormalHints(dpy, win, &sizehints); |
| XSetStandardProperties(dpy, win, name, name, |
| None, (char **)NULL, 0, &sizehints); |
| } |
| |
| ctx = glXCreateContext( dpy, visinfo, NULL, True ); |
| if (!ctx) { |
| printf("Error: glXCreateContext failed\n"); |
| exit(1); |
| } |
| |
| XFree(visinfo); |
| |
| *winRet = win; |
| *ctxRet = ctx; |
| } |
| |
| |
| static void |
| event_loop(Display *dpy, Window win) |
| { |
| while (1) { |
| while (XPending(dpy) > 0) { |
| XEvent event; |
| XNextEvent(dpy, &event); |
| switch (event.type) { |
| case Expose: |
| /* we'll redraw below */ |
| break; |
| case ConfigureNotify: |
| Reshape(event.xconfigure.width, event.xconfigure.height); |
| break; |
| case KeyPress: |
| { |
| char buffer[10]; |
| int r, code; |
| code = XLookupKeysym(&event.xkey, 0); |
| r = XLookupString(&event.xkey, buffer, sizeof(buffer), |
| NULL, NULL); |
| if (buffer[0] == 27) { |
| /* escape */ |
| return; |
| |
| } |
| } |
| } |
| } |
| |
| } |
| } |
| |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| Display *dpy; |
| Window win; |
| GLXContext ctx; |
| char *dpyName = NULL; |
| GLboolean printInfo = GL_FALSE; |
| int i; |
| |
| for (i = 1; i < argc; i++) { |
| if (strcmp(argv[i], "-display") == 0) { |
| dpyName = argv[i+1]; |
| i++; |
| } |
| else if (strcmp(argv[i], "-info") == 0) { |
| printInfo = GL_TRUE; |
| } |
| else |
| printf("Warrning: unknown parameter: %s\n", argv[i]); |
| } |
| |
| dpy = XOpenDisplay(dpyName); |
| if (!dpy) { |
| printf("Error: couldn't open display %s\n", |
| XDisplayName(dpyName)); |
| return -1; |
| } |
| |
| make_window(dpy, "yuvrect_client", 0, 0, 300, 300, &win, &ctx); |
| XMapWindow(dpy, win); |
| glXMakeCurrent(dpy, win, ctx); |
| |
| if (printInfo) { |
| printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); |
| printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION)); |
| printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR)); |
| printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS)); |
| } |
| |
| Init(argc, argv, dpy, DefaultScreen(dpy), win); |
| |
| scr_Display(); |
| glXSwapBuffers(dpy, win); |
| event_loop(dpy, win); |
| |
| glXFreeMemoryMESA(dpy, DefaultScreen(dpy), glx_memory); |
| glXDestroyContext(dpy, ctx); |
| XDestroyWindow(dpy, win); |
| XCloseDisplay(dpy); |
| |
| return 0; |
| } |