Release 1.5.29.
[wine] / dlls / gdi32 / dibdrv / opengl.c
1 /*
2  * DIB driver OpenGL support
3  *
4  * Copyright 2012 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include "gdi_private.h"
25 #include "dibdrv.h"
26
27 #include "wine/library.h"
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(dib);
31
32 #ifdef SONAME_LIBOSMESA
33
34 #include "wine/wgl.h"
35 #include "wine/wgl_driver.h"
36
37 #define OSMESA_COLOR_INDEX      GL_COLOR_INDEX
38 #define OSMESA_RGBA             GL_RGBA
39 #define OSMESA_BGRA             0x1
40 #define OSMESA_ARGB             0x2
41 #define OSMESA_RGB              GL_RGB
42 #define OSMESA_BGR              0x4
43 #define OSMESA_RGB_565          0x5
44 #define OSMESA_ROW_LENGTH       0x10
45 #define OSMESA_Y_UP             0x11
46
47 typedef struct osmesa_context *OSMesaContext;
48
49 extern BOOL WINAPI GdiSetPixelFormat( HDC hdc, INT fmt, const PIXELFORMATDESCRIPTOR *pfd );
50
51 struct wgl_context
52 {
53     OSMesaContext context;
54     int           format;
55 };
56
57 static struct opengl_funcs opengl_funcs;
58
59 #define USE_GL_FUNC(name) #name,
60 static const char *opengl_func_names[] = { ALL_WGL_FUNCS };
61 #undef USE_GL_FUNC
62
63 static OSMesaContext (*pOSMesaCreateContextExt)( GLenum format, GLint depthBits, GLint stencilBits,
64                                                  GLint accumBits, OSMesaContext sharelist );
65 static void (*pOSMesaDestroyContext)( OSMesaContext ctx );
66 static void * (*pOSMesaGetProcAddress)( const char *funcName );
67 static GLboolean (*pOSMesaMakeCurrent)( OSMesaContext ctx, void *buffer, GLenum type,
68                                         GLsizei width, GLsizei height );
69 static void (*pOSMesaPixelStore)( GLint pname, GLint value );
70
71 static const struct
72 {
73     UINT mesa;
74     BYTE color_bits;
75     BYTE red_bits, red_shift;
76     BYTE green_bits, green_shift;
77     BYTE blue_bits, blue_shift;
78     BYTE alpha_bits, alpha_shift;
79     BYTE accum_bits;
80     BYTE depth_bits;
81     BYTE stencil_bits;
82 } pixel_formats[] =
83 {
84     { OSMESA_BGRA,     32,  8, 16, 8, 8,  8, 0,  8, 24,  16, 32, 8 },
85     { OSMESA_BGRA,     32,  8, 16, 8, 8,  8, 0,  8, 24,  16, 16, 8 },
86     { OSMESA_RGBA,     32,  8, 0,  8, 8,  8, 16, 8, 24,  16, 32, 8 },
87     { OSMESA_RGBA,     32,  8, 0,  8, 8,  8, 16, 8, 24,  16, 16, 8 },
88     { OSMESA_ARGB,     32,  8, 8,  8, 16, 8, 24, 8, 0,   16, 32, 8 },
89     { OSMESA_ARGB,     32,  8, 8,  8, 16, 8, 24, 8, 0,   16, 16, 8 },
90     { OSMESA_RGB,      24,  8, 0,  8, 8,  8, 16, 0, 0,   16, 32, 8 },
91     { OSMESA_RGB,      24,  8, 0,  8, 8,  8, 16, 0, 0,   16, 16, 8 },
92     { OSMESA_BGR,      24,  8, 16, 8, 8,  8, 0,  0, 0,   16, 32, 8 },
93     { OSMESA_BGR,      24,  8, 16, 8, 8,  8, 0,  0, 0,   16, 16, 8 },
94     { OSMESA_RGB_565,  16,  5, 0,  6, 5,  5, 11, 0, 0,   16, 32, 8 },
95     { OSMESA_RGB_565,  16,  5, 0,  6, 5,  5, 11, 0, 0,   16, 16, 8 },
96 };
97 static const int nb_formats = sizeof(pixel_formats) / sizeof(pixel_formats[0]);
98
99 static BOOL init_opengl(void)
100 {
101     static int init_done;
102     static void *osmesa_handle;
103     char buffer[200];
104     unsigned int i;
105
106     if (init_done) return (osmesa_handle != NULL);
107     init_done = 1;
108
109     osmesa_handle = wine_dlopen( SONAME_LIBOSMESA, RTLD_NOW, buffer, sizeof(buffer) );
110     if (osmesa_handle == NULL)
111     {
112         ERR( "Failed to load OSMesa: %s\n", buffer );
113         return FALSE;
114     }
115
116     for (i = 0; i < sizeof(opengl_func_names)/sizeof(opengl_func_names[0]); i++)
117     {
118         if (!(((void **)&opengl_funcs.gl)[i] = wine_dlsym( osmesa_handle, opengl_func_names[i], NULL, 0 )))
119         {
120             ERR( "%s not found in %s, disabling.\n", opengl_func_names[i], SONAME_LIBOSMESA );
121             goto failed;
122         }
123     }
124 #define LOAD_FUNCPTR(f) do if (!(p##f = (void *)wine_dlsym( osmesa_handle, #f, NULL, 0 ))) \
125     { \
126         ERR( "%s not found in %s, disabling.\n", #f, SONAME_LIBOSMESA ); \
127         goto failed; \
128     } while(0)
129
130     LOAD_FUNCPTR(OSMesaCreateContextExt);
131     LOAD_FUNCPTR(OSMesaDestroyContext);
132     LOAD_FUNCPTR(OSMesaGetProcAddress);
133     LOAD_FUNCPTR(OSMesaMakeCurrent);
134     LOAD_FUNCPTR(OSMesaPixelStore);
135 #undef LOAD_FUNCPTR
136
137     return TRUE;
138
139 failed:
140     wine_dlclose( osmesa_handle, NULL, 0 );
141     osmesa_handle = NULL;
142     return FALSE;
143 }
144
145 /**********************************************************************
146  *           dibdrv_wglDescribePixelFormat
147  */
148 static int dibdrv_wglDescribePixelFormat( HDC hdc, int fmt, UINT size, PIXELFORMATDESCRIPTOR *descr )
149 {
150     int ret = sizeof(pixel_formats) / sizeof(pixel_formats[0]);
151
152     if (fmt <= 0 || fmt > ret) return ret;
153     if (size < sizeof(*descr)) return 0;
154
155     memset( descr, 0, sizeof(*descr) );
156     descr->nSize            = sizeof(*descr);
157     descr->nVersion         = 1;
158     descr->dwFlags          = PFD_SUPPORT_GDI | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_BITMAP | PFD_GENERIC_FORMAT;
159     descr->iPixelType       = PFD_TYPE_RGBA;
160     descr->cColorBits       = pixel_formats[fmt - 1].color_bits;
161     descr->cRedBits         = pixel_formats[fmt - 1].red_bits;
162     descr->cRedShift        = pixel_formats[fmt - 1].red_shift;
163     descr->cGreenBits       = pixel_formats[fmt - 1].green_bits;
164     descr->cGreenShift      = pixel_formats[fmt - 1].green_shift;
165     descr->cBlueBits        = pixel_formats[fmt - 1].blue_bits;
166     descr->cBlueShift       = pixel_formats[fmt - 1].blue_shift;
167     descr->cAlphaBits       = pixel_formats[fmt - 1].alpha_bits;
168     descr->cAlphaShift      = pixel_formats[fmt - 1].alpha_shift;
169     descr->cAccumBits       = pixel_formats[fmt - 1].accum_bits;
170     descr->cAccumRedBits    = pixel_formats[fmt - 1].accum_bits / 4;
171     descr->cAccumGreenBits  = pixel_formats[fmt - 1].accum_bits / 4;
172     descr->cAccumBlueBits   = pixel_formats[fmt - 1].accum_bits / 4;
173     descr->cAccumAlphaBits  = pixel_formats[fmt - 1].accum_bits / 4;
174     descr->cDepthBits       = pixel_formats[fmt - 1].depth_bits;
175     descr->cStencilBits     = pixel_formats[fmt - 1].stencil_bits;
176     descr->cAuxBuffers      = 0;
177     descr->iLayerType       = PFD_MAIN_PLANE;
178     return ret;
179 }
180
181 /***********************************************************************
182  *              dibdrv_wglCopyContext
183  */
184 static BOOL dibdrv_wglCopyContext( struct wgl_context *src, struct wgl_context *dst, UINT mask )
185 {
186     FIXME( "not supported yet\n" );
187     return FALSE;
188 }
189
190 /***********************************************************************
191  *              dibdrv_wglCreateContext
192  */
193 static struct wgl_context *dibdrv_wglCreateContext( HDC hdc )
194 {
195     struct wgl_context *context;
196
197     if (!(context = HeapAlloc( GetProcessHeap(), 0, sizeof( *context )))) return NULL;
198     context->format = GetPixelFormat( hdc );
199     if (!context->format || context->format > nb_formats) context->format = 1;
200
201     if (!(context->context = pOSMesaCreateContextExt( pixel_formats[context->format - 1].mesa,
202                                                       pixel_formats[context->format - 1].depth_bits,
203                                                       pixel_formats[context->format - 1].stencil_bits,
204                                                       pixel_formats[context->format - 1].accum_bits, 0 )))
205     {
206         HeapFree( GetProcessHeap(), 0, context );
207         return NULL;
208     }
209     return context;
210 }
211
212 /***********************************************************************
213  *              dibdrv_wglDeleteContext
214  */
215 static void dibdrv_wglDeleteContext( struct wgl_context *context )
216 {
217     pOSMesaDestroyContext( context->context );
218     HeapFree( GetProcessHeap(), 0, context );
219 }
220
221 /***********************************************************************
222  *              dibdrv_wglGetPixelFormat
223  */
224 static int dibdrv_wglGetPixelFormat( HDC hdc )
225 {
226     DC *dc = get_dc_ptr( hdc );
227     int ret = 0;
228
229     if (dc)
230     {
231         ret = dc->pixel_format;
232         release_dc_ptr( dc );
233     }
234     return ret;
235 }
236
237 /***********************************************************************
238  *              dibdrv_wglGetProcAddress
239  */
240 static PROC dibdrv_wglGetProcAddress( const char *proc )
241 {
242     if (!strncmp( proc, "wgl", 3 )) return NULL;
243     return (PROC)pOSMesaGetProcAddress( proc );
244 }
245
246 /***********************************************************************
247  *              dibdrv_wglMakeCurrent
248  */
249 static BOOL dibdrv_wglMakeCurrent( HDC hdc, struct wgl_context *context )
250 {
251     HBITMAP bitmap;
252     BITMAPOBJ *bmp;
253     dib_info dib;
254     BOOL ret = FALSE;
255
256     if (!context)
257     {
258         pOSMesaMakeCurrent( NULL, NULL, GL_UNSIGNED_BYTE, 0, 0 );
259         return TRUE;
260     }
261
262     if (GetPixelFormat( hdc ) != context->format)
263         FIXME( "mismatched pixel formats %u/%u not supported yet\n",
264                GetPixelFormat( hdc ), context->format );
265
266     bitmap = GetCurrentObject( hdc, OBJ_BITMAP );
267     bmp = GDI_GetObjPtr( bitmap, OBJ_BITMAP );
268     if (!bmp) return FALSE;
269
270     if (init_dib_info_from_bitmapobj( &dib, bmp ))
271     {
272         char *bits;
273         int width = dib.rect.right - dib.rect.left;
274         int height = dib.rect.bottom - dib.rect.top;
275
276         if (dib.stride < 0)
277             bits = (char *)dib.bits.ptr + (dib.rect.bottom - 1) * dib.stride;
278         else
279             bits = (char *)dib.bits.ptr + dib.rect.top * dib.stride;
280         bits += dib.rect.left * dib.bit_count / 8;
281
282         TRACE( "context %p bits %p size %ux%u\n", context, bits, width, height );
283
284         ret = pOSMesaMakeCurrent( context->context, bits, GL_UNSIGNED_BYTE, width, height );
285         if (ret)
286         {
287             pOSMesaPixelStore( OSMESA_ROW_LENGTH, abs( dib.stride ) * 8 / dib.bit_count );
288             pOSMesaPixelStore( OSMESA_Y_UP, 1 );  /* Windows seems to assume bottom-up */
289         }
290     }
291     GDI_ReleaseObj( bitmap );
292     return ret;
293 }
294
295 /**********************************************************************
296  *           dibdrv_wglSetPixelFormat
297  */
298 static BOOL dibdrv_wglSetPixelFormat( HDC hdc, int fmt, const PIXELFORMATDESCRIPTOR *descr )
299 {
300     if (fmt <= 0 || fmt > nb_formats) return FALSE;
301     return GdiSetPixelFormat( hdc, fmt, descr );
302 }
303
304 /***********************************************************************
305  *              dibdrv_wglShareLists
306  */
307 static BOOL dibdrv_wglShareLists( struct wgl_context *org, struct wgl_context *dest )
308 {
309     FIXME( "not supported yet\n" );
310     return FALSE;
311 }
312
313 /***********************************************************************
314  *              dibdrv_wglSwapBuffers
315  */
316 static BOOL dibdrv_wglSwapBuffers( HDC hdc )
317 {
318     return TRUE;
319 }
320
321 static struct opengl_funcs opengl_funcs =
322 {
323     {
324         dibdrv_wglCopyContext,        /* p_wglCopyContext */
325         dibdrv_wglCreateContext,      /* p_wglCreateContext */
326         dibdrv_wglDeleteContext,      /* p_wglDeleteContext */
327         dibdrv_wglDescribePixelFormat,/* p_wglDescribePixelFormat */
328         dibdrv_wglGetPixelFormat,     /* p_wglGetPixelFormat */
329         dibdrv_wglGetProcAddress,     /* p_wglGetProcAddress */
330         dibdrv_wglMakeCurrent,        /* p_wglMakeCurrent */
331         dibdrv_wglSetPixelFormat,     /* p_wglSetPixelFormat */
332         dibdrv_wglShareLists,         /* p_wglShareLists */
333         dibdrv_wglSwapBuffers,        /* p_wglSwapBuffers */
334     }
335 };
336
337 /**********************************************************************
338  *           dibdrv_wine_get_wgl_driver
339  */
340 struct opengl_funcs *dibdrv_wine_get_wgl_driver( PHYSDEV dev, UINT version )
341 {
342     if (version != WINE_WGL_DRIVER_VERSION)
343     {
344         ERR( "version mismatch, opengl32 wants %u but dibdrv has %u\n", version, WINE_WGL_DRIVER_VERSION );
345         return NULL;
346     }
347
348     if (!init_opengl()) return (void *)-1;
349
350     return &opengl_funcs;
351 }
352
353 #else  /* SONAME_LIBOSMESA */
354
355 /**********************************************************************
356  *           dibdrv_wine_get_wgl_driver
357  */
358 struct opengl_funcs *dibdrv_wine_get_wgl_driver( PHYSDEV dev, UINT version )
359 {
360     static int warned;
361     if (!warned++) ERR( "OSMesa not compiled in, no OpenGL bitmap support\n" );
362     return (void *)-1;
363 }
364
365 #endif  /* SONAME_LIBOSMESA */