/* * 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" #ifdef HAVE_GL_OSMESA_H #include <GL/osmesa.h> #undef APIENTRY #undef GLAPI #undef WINGDIAPI #endif #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_driver.h" 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 #define MAKE_FUNCPTR(f) static typeof(f) * p##f; MAKE_FUNCPTR(OSMesaCreateContextExt) MAKE_FUNCPTR(OSMesaDestroyContext) MAKE_FUNCPTR(OSMesaGetProcAddress) MAKE_FUNCPTR(OSMesaMakeCurrent) MAKE_FUNCPTR(OSMesaPixelStore) #undef MAKE_FUNCPTR 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 int init_done; static void *osmesa_handle; char buffer[200]; unsigned int i; if (init_done) return (osmesa_handle != NULL); init_done = 1; 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; } for (i = 0; i < sizeof(opengl_func_names)/sizeof(opengl_func_names[0]); i++) { if (!(((void **)&opengl_funcs.gl)[i] = wine_dlsym( osmesa_handle, opengl_func_names[i], NULL, 0 ))) { ERR( "%s not found in %s, disabling.\n", opengl_func_names[i], SONAME_LIBOSMESA ); goto failed; } } #define LOAD_FUNCPTR(f) do if (!(p##f = (void *)wine_dlsym( osmesa_handle, #f, NULL, 0 ))) \ { \ ERR( "%s not found in %s, disabling.\n", #f, SONAME_LIBOSMESA ); \ goto failed; \ } while(0) LOAD_FUNCPTR(OSMesaCreateContextExt); LOAD_FUNCPTR(OSMesaDestroyContext); LOAD_FUNCPTR(OSMesaGetProcAddress); LOAD_FUNCPTR(OSMesaMakeCurrent); LOAD_FUNCPTR(OSMesaPixelStore); #undef LOAD_FUNCPTR return TRUE; failed: wine_dlclose( osmesa_handle, NULL, 0 ); osmesa_handle = NULL; return FALSE; } /********************************************************************** * dibdrv_DescribePixelFormat */ int dibdrv_DescribePixelFormat( PHYSDEV dev, int fmt, UINT size, PIXELFORMATDESCRIPTOR *descr ) { int ret = sizeof(pixel_formats) / sizeof(pixel_formats[0]); if (fmt <= 0 || fmt > ret) return ret; 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_SetPixelFormat */ BOOL dibdrv_SetPixelFormat( PHYSDEV dev, int fmt, const PIXELFORMATDESCRIPTOR *descr ) { DC *dc; BOOL ret = TRUE; if (fmt <= 0 || fmt > nb_formats) return FALSE; dc = get_dc_ptr( dev->hdc ); if (!dc->pixel_format) dc->pixel_format = fmt; else ret = (dc->pixel_format == fmt); release_dc_ptr( dc ); 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 void dibdrv_wglDeleteContext( struct wgl_context *context ) { pOSMesaDestroyContext( context->context ); 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; 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 ); ret = pOSMesaMakeCurrent( context->context, bits, GL_UNSIGNED_BYTE, 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_wglShareLists */ static BOOL dibdrv_wglShareLists( struct wgl_context *org, struct wgl_context *dest ) { FIXME( "not supported yet\n" ); return FALSE; } static struct opengl_funcs opengl_funcs = { { dibdrv_wglCopyContext, /* p_wglCopyContext */ dibdrv_wglCreateContext, /* p_wglCreateContext */ dibdrv_wglDeleteContext, /* p_wglDeleteContext */ dibdrv_wglGetPixelFormat, /* p_wglGetPixelFormat */ dibdrv_wglGetProcAddress, /* p_wglGetProcAddress */ dibdrv_wglMakeCurrent, /* p_wglMakeCurrent */ dibdrv_wglShareLists, /* p_wglShareLists */ } }; /********************************************************************** * 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_DescribePixelFormat */ int dibdrv_DescribePixelFormat( PHYSDEV dev, int fmt, UINT size, PIXELFORMATDESCRIPTOR *descr ) { return 0; } /********************************************************************** * dibdrv_SetPixelFormat */ BOOL dibdrv_SetPixelFormat( PHYSDEV dev, int fmt, const PIXELFORMATDESCRIPTOR *descr ) { return FALSE; } /********************************************************************** * dibdrv_wine_get_wgl_driver */ struct opengl_funcs *dibdrv_wine_get_wgl_driver( PHYSDEV dev, UINT version ) { ERR( "OSMesa not compiled in, no OpenGL bitmap support\n" ); return (void *)-1; } #endif /* SONAME_LIBOSMESA */