| /* |
| * DIB driver OpenGL support |
| * |
| * Copyright 2012 Alexandre Julliard |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "config.h" |
| #include "wine/port.h" |
| |
| #include "gdi_private.h" |
| #include "dibdrv.h" |
| |
| #include "wine/library.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(dib); |
| |
| #ifdef SONAME_LIBOSMESA |
| |
| #include "wine/wgl.h" |
| #include "wine/wgl_driver.h" |
| |
| #define OSMESA_COLOR_INDEX GL_COLOR_INDEX |
| #define OSMESA_RGBA GL_RGBA |
| #define OSMESA_BGRA 0x1 |
| #define OSMESA_ARGB 0x2 |
| #define OSMESA_RGB GL_RGB |
| #define OSMESA_BGR 0x4 |
| #define OSMESA_RGB_565 0x5 |
| #define OSMESA_ROW_LENGTH 0x10 |
| #define OSMESA_Y_UP 0x11 |
| |
| typedef struct osmesa_context *OSMesaContext; |
| |
| extern BOOL WINAPI GdiSetPixelFormat( HDC hdc, INT fmt, const PIXELFORMATDESCRIPTOR *pfd ); |
| |
| struct wgl_context |
| { |
| OSMesaContext context; |
| int format; |
| }; |
| |
| static struct opengl_funcs opengl_funcs; |
| |
| #define USE_GL_FUNC(name) #name, |
| static const char *opengl_func_names[] = { ALL_WGL_FUNCS }; |
| #undef USE_GL_FUNC |
| |
| static OSMesaContext (*pOSMesaCreateContextExt)( GLenum format, GLint depthBits, GLint stencilBits, |
| GLint accumBits, OSMesaContext sharelist ); |
| static void (*pOSMesaDestroyContext)( OSMesaContext ctx ); |
| static void * (*pOSMesaGetProcAddress)( const char *funcName ); |
| static GLboolean (*pOSMesaMakeCurrent)( OSMesaContext ctx, void *buffer, GLenum type, |
| GLsizei width, GLsizei height ); |
| static void (*pOSMesaPixelStore)( GLint pname, GLint value ); |
| |
| static const struct |
| { |
| UINT mesa; |
| BYTE color_bits; |
| BYTE red_bits, red_shift; |
| BYTE green_bits, green_shift; |
| BYTE blue_bits, blue_shift; |
| BYTE alpha_bits, alpha_shift; |
| BYTE accum_bits; |
| BYTE depth_bits; |
| BYTE stencil_bits; |
| } pixel_formats[] = |
| { |
| { OSMESA_BGRA, 32, 8, 16, 8, 8, 8, 0, 8, 24, 16, 32, 8 }, |
| { OSMESA_BGRA, 32, 8, 16, 8, 8, 8, 0, 8, 24, 16, 16, 8 }, |
| { OSMESA_RGBA, 32, 8, 0, 8, 8, 8, 16, 8, 24, 16, 32, 8 }, |
| { OSMESA_RGBA, 32, 8, 0, 8, 8, 8, 16, 8, 24, 16, 16, 8 }, |
| { OSMESA_ARGB, 32, 8, 8, 8, 16, 8, 24, 8, 0, 16, 32, 8 }, |
| { OSMESA_ARGB, 32, 8, 8, 8, 16, 8, 24, 8, 0, 16, 16, 8 }, |
| { OSMESA_RGB, 24, 8, 0, 8, 8, 8, 16, 0, 0, 16, 32, 8 }, |
| { OSMESA_RGB, 24, 8, 0, 8, 8, 8, 16, 0, 0, 16, 16, 8 }, |
| { OSMESA_BGR, 24, 8, 16, 8, 8, 8, 0, 0, 0, 16, 32, 8 }, |
| { OSMESA_BGR, 24, 8, 16, 8, 8, 8, 0, 0, 0, 16, 16, 8 }, |
| { OSMESA_RGB_565, 16, 5, 0, 6, 5, 5, 11, 0, 0, 16, 32, 8 }, |
| { OSMESA_RGB_565, 16, 5, 0, 6, 5, 5, 11, 0, 0, 16, 16, 8 }, |
| }; |
| static const int nb_formats = sizeof(pixel_formats) / sizeof(pixel_formats[0]); |
| |
| static BOOL init_opengl(void) |
| { |
| static BOOL init_done = FALSE; |
| static void *osmesa_handle; |
| char buffer[200]; |
| unsigned int i; |
| |
| if (init_done) return (osmesa_handle != NULL); |
| init_done = TRUE; |
| |
| osmesa_handle = wine_dlopen( SONAME_LIBOSMESA, RTLD_NOW, buffer, sizeof(buffer) ); |
| if (osmesa_handle == NULL) |
| { |
| ERR( "Failed to load OSMesa: %s\n", buffer ); |
| return FALSE; |
| } |
| |
| #define LOAD_FUNCPTR(f) do if (!(p##f = wine_dlsym( osmesa_handle, #f, buffer, sizeof(buffer) ))) \ |
| { \ |
| ERR( "%s not found in %s (%s), disabling.\n", #f, SONAME_LIBOSMESA, buffer ); \ |
| goto failed; \ |
| } while(0) |
| |
| LOAD_FUNCPTR(OSMesaCreateContextExt); |
| LOAD_FUNCPTR(OSMesaDestroyContext); |
| LOAD_FUNCPTR(OSMesaGetProcAddress); |
| LOAD_FUNCPTR(OSMesaMakeCurrent); |
| LOAD_FUNCPTR(OSMesaPixelStore); |
| #undef LOAD_FUNCPTR |
| |
| for (i = 0; i < sizeof(opengl_func_names)/sizeof(opengl_func_names[0]); i++) |
| { |
| if (!(((void **)&opengl_funcs.gl)[i] = pOSMesaGetProcAddress( opengl_func_names[i] ))) |
| { |
| ERR( "%s not found in %s, disabling.\n", opengl_func_names[i], SONAME_LIBOSMESA ); |
| goto failed; |
| } |
| } |
| |
| return TRUE; |
| |
| failed: |
| wine_dlclose( osmesa_handle, NULL, 0 ); |
| osmesa_handle = NULL; |
| return FALSE; |
| } |
| |
| /********************************************************************** |
| * dibdrv_wglDescribePixelFormat |
| */ |
| static int dibdrv_wglDescribePixelFormat( HDC hdc, int fmt, UINT size, PIXELFORMATDESCRIPTOR *descr ) |
| { |
| int ret = sizeof(pixel_formats) / sizeof(pixel_formats[0]); |
| |
| if (!descr) return ret; |
| if (fmt <= 0 || fmt > ret) return 0; |
| if (size < sizeof(*descr)) return 0; |
| |
| memset( descr, 0, sizeof(*descr) ); |
| descr->nSize = sizeof(*descr); |
| descr->nVersion = 1; |
| descr->dwFlags = PFD_SUPPORT_GDI | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_BITMAP | PFD_GENERIC_FORMAT; |
| descr->iPixelType = PFD_TYPE_RGBA; |
| descr->cColorBits = pixel_formats[fmt - 1].color_bits; |
| descr->cRedBits = pixel_formats[fmt - 1].red_bits; |
| descr->cRedShift = pixel_formats[fmt - 1].red_shift; |
| descr->cGreenBits = pixel_formats[fmt - 1].green_bits; |
| descr->cGreenShift = pixel_formats[fmt - 1].green_shift; |
| descr->cBlueBits = pixel_formats[fmt - 1].blue_bits; |
| descr->cBlueShift = pixel_formats[fmt - 1].blue_shift; |
| descr->cAlphaBits = pixel_formats[fmt - 1].alpha_bits; |
| descr->cAlphaShift = pixel_formats[fmt - 1].alpha_shift; |
| descr->cAccumBits = pixel_formats[fmt - 1].accum_bits; |
| descr->cAccumRedBits = pixel_formats[fmt - 1].accum_bits / 4; |
| descr->cAccumGreenBits = pixel_formats[fmt - 1].accum_bits / 4; |
| descr->cAccumBlueBits = pixel_formats[fmt - 1].accum_bits / 4; |
| descr->cAccumAlphaBits = pixel_formats[fmt - 1].accum_bits / 4; |
| descr->cDepthBits = pixel_formats[fmt - 1].depth_bits; |
| descr->cStencilBits = pixel_formats[fmt - 1].stencil_bits; |
| descr->cAuxBuffers = 0; |
| descr->iLayerType = PFD_MAIN_PLANE; |
| return ret; |
| } |
| |
| /*********************************************************************** |
| * dibdrv_wglCopyContext |
| */ |
| static BOOL dibdrv_wglCopyContext( struct wgl_context *src, struct wgl_context *dst, UINT mask ) |
| { |
| FIXME( "not supported yet\n" ); |
| return FALSE; |
| } |
| |
| /*********************************************************************** |
| * dibdrv_wglCreateContext |
| */ |
| static struct wgl_context *dibdrv_wglCreateContext( HDC hdc ) |
| { |
| struct wgl_context *context; |
| |
| if (!(context = HeapAlloc( GetProcessHeap(), 0, sizeof( *context )))) return NULL; |
| context->format = GetPixelFormat( hdc ); |
| if (!context->format || context->format > nb_formats) context->format = 1; |
| |
| if (!(context->context = pOSMesaCreateContextExt( pixel_formats[context->format - 1].mesa, |
| pixel_formats[context->format - 1].depth_bits, |
| pixel_formats[context->format - 1].stencil_bits, |
| pixel_formats[context->format - 1].accum_bits, 0 ))) |
| { |
| HeapFree( GetProcessHeap(), 0, context ); |
| return NULL; |
| } |
| return context; |
| } |
| |
| /*********************************************************************** |
| * dibdrv_wglDeleteContext |
| */ |
| static BOOL dibdrv_wglDeleteContext( struct wgl_context *context ) |
| { |
| pOSMesaDestroyContext( context->context ); |
| return HeapFree( GetProcessHeap(), 0, context ); |
| } |
| |
| /*********************************************************************** |
| * dibdrv_wglGetPixelFormat |
| */ |
| static int dibdrv_wglGetPixelFormat( HDC hdc ) |
| { |
| DC *dc = get_dc_ptr( hdc ); |
| int ret = 0; |
| |
| if (dc) |
| { |
| ret = dc->pixel_format; |
| release_dc_ptr( dc ); |
| } |
| return ret; |
| } |
| |
| /*********************************************************************** |
| * dibdrv_wglGetProcAddress |
| */ |
| static PROC dibdrv_wglGetProcAddress( const char *proc ) |
| { |
| if (!strncmp( proc, "wgl", 3 )) return NULL; |
| return (PROC)pOSMesaGetProcAddress( proc ); |
| } |
| |
| /*********************************************************************** |
| * dibdrv_wglMakeCurrent |
| */ |
| static BOOL dibdrv_wglMakeCurrent( HDC hdc, struct wgl_context *context ) |
| { |
| HBITMAP bitmap; |
| BITMAPOBJ *bmp; |
| dib_info dib; |
| GLenum type; |
| BOOL ret = FALSE; |
| |
| if (!context) |
| { |
| pOSMesaMakeCurrent( NULL, NULL, GL_UNSIGNED_BYTE, 0, 0 ); |
| return TRUE; |
| } |
| |
| if (GetPixelFormat( hdc ) != context->format) |
| FIXME( "mismatched pixel formats %u/%u not supported yet\n", |
| GetPixelFormat( hdc ), context->format ); |
| |
| bitmap = GetCurrentObject( hdc, OBJ_BITMAP ); |
| bmp = GDI_GetObjPtr( bitmap, OBJ_BITMAP ); |
| if (!bmp) return FALSE; |
| |
| if (init_dib_info_from_bitmapobj( &dib, bmp )) |
| { |
| char *bits; |
| int width = dib.rect.right - dib.rect.left; |
| int height = dib.rect.bottom - dib.rect.top; |
| |
| if (dib.stride < 0) |
| bits = (char *)dib.bits.ptr + (dib.rect.bottom - 1) * dib.stride; |
| else |
| bits = (char *)dib.bits.ptr + dib.rect.top * dib.stride; |
| bits += dib.rect.left * dib.bit_count / 8; |
| |
| TRACE( "context %p bits %p size %ux%u\n", context, bits, width, height ); |
| |
| if (pixel_formats[context->format - 1].mesa == OSMESA_RGB_565) |
| type = GL_UNSIGNED_SHORT_5_6_5; |
| else |
| type = GL_UNSIGNED_BYTE; |
| |
| ret = pOSMesaMakeCurrent( context->context, bits, type, width, height ); |
| if (ret) |
| { |
| pOSMesaPixelStore( OSMESA_ROW_LENGTH, abs( dib.stride ) * 8 / dib.bit_count ); |
| pOSMesaPixelStore( OSMESA_Y_UP, 1 ); /* Windows seems to assume bottom-up */ |
| } |
| } |
| GDI_ReleaseObj( bitmap ); |
| return ret; |
| } |
| |
| /********************************************************************** |
| * dibdrv_wglSetPixelFormat |
| */ |
| static BOOL dibdrv_wglSetPixelFormat( HDC hdc, int fmt, const PIXELFORMATDESCRIPTOR *descr ) |
| { |
| if (fmt <= 0 || fmt > nb_formats) return FALSE; |
| return GdiSetPixelFormat( hdc, fmt, descr ); |
| } |
| |
| /*********************************************************************** |
| * dibdrv_wglShareLists |
| */ |
| static BOOL dibdrv_wglShareLists( struct wgl_context *org, struct wgl_context *dest ) |
| { |
| FIXME( "not supported yet\n" ); |
| return FALSE; |
| } |
| |
| /*********************************************************************** |
| * dibdrv_wglSwapBuffers |
| */ |
| static BOOL dibdrv_wglSwapBuffers( HDC hdc ) |
| { |
| return TRUE; |
| } |
| |
| static struct opengl_funcs opengl_funcs = |
| { |
| { |
| dibdrv_wglCopyContext, /* p_wglCopyContext */ |
| dibdrv_wglCreateContext, /* p_wglCreateContext */ |
| dibdrv_wglDeleteContext, /* p_wglDeleteContext */ |
| dibdrv_wglDescribePixelFormat,/* p_wglDescribePixelFormat */ |
| dibdrv_wglGetPixelFormat, /* p_wglGetPixelFormat */ |
| dibdrv_wglGetProcAddress, /* p_wglGetProcAddress */ |
| dibdrv_wglMakeCurrent, /* p_wglMakeCurrent */ |
| dibdrv_wglSetPixelFormat, /* p_wglSetPixelFormat */ |
| dibdrv_wglShareLists, /* p_wglShareLists */ |
| dibdrv_wglSwapBuffers, /* p_wglSwapBuffers */ |
| } |
| }; |
| |
| /********************************************************************** |
| * dibdrv_wine_get_wgl_driver |
| */ |
| struct opengl_funcs *dibdrv_wine_get_wgl_driver( PHYSDEV dev, UINT version ) |
| { |
| if (version != WINE_WGL_DRIVER_VERSION) |
| { |
| ERR( "version mismatch, opengl32 wants %u but dibdrv has %u\n", version, WINE_WGL_DRIVER_VERSION ); |
| return NULL; |
| } |
| |
| if (!init_opengl()) return (void *)-1; |
| |
| return &opengl_funcs; |
| } |
| |
| #else /* SONAME_LIBOSMESA */ |
| |
| /********************************************************************** |
| * dibdrv_wine_get_wgl_driver |
| */ |
| struct opengl_funcs *dibdrv_wine_get_wgl_driver( PHYSDEV dev, UINT version ) |
| { |
| static int warned; |
| if (!warned++) ERR( "OSMesa not compiled in, no OpenGL bitmap support\n" ); |
| return (void *)-1; |
| } |
| |
| #endif /* SONAME_LIBOSMESA */ |