ieframe: Use proper helpers for iface calls.
[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 #ifdef HAVE_GL_OSMESA_H
25 #include <GL/osmesa.h>
26 #undef APIENTRY
27 #undef GLAPI
28 #undef WINGDIAPI
29 #endif
30
31 #include "gdi_private.h"
32 #include "dibdrv.h"
33
34 #include "wine/library.h"
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(dib);
38
39 #ifdef SONAME_LIBOSMESA
40
41 #include "wine/wgl_driver.h"
42
43 struct wgl_context
44 {
45     OSMesaContext context;
46     int           format;
47 };
48
49 static struct opengl_funcs opengl_funcs;
50
51 #define USE_GL_FUNC(name) #name,
52 static const char *opengl_func_names[] = { ALL_WGL_FUNCS };
53 #undef USE_GL_FUNC
54
55 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
56 MAKE_FUNCPTR(OSMesaCreateContextExt)
57 MAKE_FUNCPTR(OSMesaDestroyContext)
58 MAKE_FUNCPTR(OSMesaGetProcAddress)
59 MAKE_FUNCPTR(OSMesaMakeCurrent)
60 MAKE_FUNCPTR(OSMesaPixelStore)
61 #undef MAKE_FUNCPTR
62
63 static const struct
64 {
65     UINT mesa;
66     BYTE color_bits;
67     BYTE red_bits, red_shift;
68     BYTE green_bits, green_shift;
69     BYTE blue_bits, blue_shift;
70     BYTE alpha_bits, alpha_shift;
71     BYTE accum_bits;
72     BYTE depth_bits;
73     BYTE stencil_bits;
74 } pixel_formats[] =
75 {
76     { OSMESA_BGRA,     32,  8, 16, 8, 8,  8, 0,  8, 24,  16, 32, 8 },
77     { OSMESA_BGRA,     32,  8, 16, 8, 8,  8, 0,  8, 24,  16, 16, 8 },
78     { OSMESA_RGBA,     32,  8, 0,  8, 8,  8, 16, 8, 24,  16, 32, 8 },
79     { OSMESA_RGBA,     32,  8, 0,  8, 8,  8, 16, 8, 24,  16, 16, 8 },
80     { OSMESA_ARGB,     32,  8, 8,  8, 16, 8, 24, 8, 0,   16, 32, 8 },
81     { OSMESA_ARGB,     32,  8, 8,  8, 16, 8, 24, 8, 0,   16, 16, 8 },
82     { OSMESA_RGB,      24,  8, 0,  8, 8,  8, 16, 0, 0,   16, 32, 8 },
83     { OSMESA_RGB,      24,  8, 0,  8, 8,  8, 16, 0, 0,   16, 16, 8 },
84     { OSMESA_BGR,      24,  8, 16, 8, 8,  8, 0,  0, 0,   16, 32, 8 },
85     { OSMESA_BGR,      24,  8, 16, 8, 8,  8, 0,  0, 0,   16, 16, 8 },
86     { OSMESA_RGB_565,  16,  5, 0,  6, 5,  5, 11, 0, 0,   16, 32, 8 },
87     { OSMESA_RGB_565,  16,  5, 0,  6, 5,  5, 11, 0, 0,   16, 16, 8 },
88 };
89 static const int nb_formats = sizeof(pixel_formats) / sizeof(pixel_formats[0]);
90
91 static BOOL init_opengl(void)
92 {
93     static int init_done;
94     static void *osmesa_handle;
95     char buffer[200];
96     unsigned int i;
97
98     if (init_done) return (osmesa_handle != NULL);
99     init_done = 1;
100
101     osmesa_handle = wine_dlopen( SONAME_LIBOSMESA, RTLD_NOW, buffer, sizeof(buffer) );
102     if (osmesa_handle == NULL)
103     {
104         ERR( "Failed to load OSMesa: %s\n", buffer );
105         return FALSE;
106     }
107
108     for (i = 0; i < sizeof(opengl_func_names)/sizeof(opengl_func_names[0]); i++)
109     {
110         if (!(((void **)&opengl_funcs.gl)[i] = wine_dlsym( osmesa_handle, opengl_func_names[i], NULL, 0 )))
111         {
112             ERR( "%s not found in %s, disabling.\n", opengl_func_names[i], SONAME_LIBOSMESA );
113             goto failed;
114         }
115     }
116 #define LOAD_FUNCPTR(f) do if (!(p##f = (void *)wine_dlsym( osmesa_handle, #f, NULL, 0 ))) \
117     { \
118         ERR( "%s not found in %s, disabling.\n", #f, SONAME_LIBOSMESA ); \
119         goto failed; \
120     } while(0)
121
122     LOAD_FUNCPTR(OSMesaCreateContextExt);
123     LOAD_FUNCPTR(OSMesaDestroyContext);
124     LOAD_FUNCPTR(OSMesaGetProcAddress);
125     LOAD_FUNCPTR(OSMesaMakeCurrent);
126     LOAD_FUNCPTR(OSMesaPixelStore);
127 #undef LOAD_FUNCPTR
128
129     return TRUE;
130
131 failed:
132     wine_dlclose( osmesa_handle, NULL, 0 );
133     osmesa_handle = NULL;
134     return FALSE;
135 }
136
137 /**********************************************************************
138  *           dibdrv_DescribePixelFormat
139  */
140 int dibdrv_DescribePixelFormat( PHYSDEV dev, int fmt, UINT size, PIXELFORMATDESCRIPTOR *descr )
141 {
142     int ret = sizeof(pixel_formats) / sizeof(pixel_formats[0]);
143
144     if (fmt <= 0 || fmt > ret) return ret;
145     if (size < sizeof(*descr)) return 0;
146
147     memset( descr, 0, sizeof(*descr) );
148     descr->nSize            = sizeof(*descr);
149     descr->nVersion         = 1;
150     descr->dwFlags          = PFD_SUPPORT_GDI | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_BITMAP | PFD_GENERIC_FORMAT;
151     descr->iPixelType       = PFD_TYPE_RGBA;
152     descr->cColorBits       = pixel_formats[fmt - 1].color_bits;
153     descr->cRedBits         = pixel_formats[fmt - 1].red_bits;
154     descr->cRedShift        = pixel_formats[fmt - 1].red_shift;
155     descr->cGreenBits       = pixel_formats[fmt - 1].green_bits;
156     descr->cGreenShift      = pixel_formats[fmt - 1].green_shift;
157     descr->cBlueBits        = pixel_formats[fmt - 1].blue_bits;
158     descr->cBlueShift       = pixel_formats[fmt - 1].blue_shift;
159     descr->cAlphaBits       = pixel_formats[fmt - 1].alpha_bits;
160     descr->cAlphaShift      = pixel_formats[fmt - 1].alpha_shift;
161     descr->cAccumBits       = pixel_formats[fmt - 1].accum_bits;
162     descr->cAccumRedBits    = pixel_formats[fmt - 1].accum_bits / 4;
163     descr->cAccumGreenBits  = pixel_formats[fmt - 1].accum_bits / 4;
164     descr->cAccumBlueBits   = pixel_formats[fmt - 1].accum_bits / 4;
165     descr->cAccumAlphaBits  = pixel_formats[fmt - 1].accum_bits / 4;
166     descr->cDepthBits       = pixel_formats[fmt - 1].depth_bits;
167     descr->cStencilBits     = pixel_formats[fmt - 1].stencil_bits;
168     descr->cAuxBuffers      = 0;
169     descr->iLayerType       = PFD_MAIN_PLANE;
170     return ret;
171 }
172
173 /**********************************************************************
174  *           dibdrv_SetPixelFormat
175  */
176 BOOL dibdrv_SetPixelFormat( PHYSDEV dev, int fmt, const PIXELFORMATDESCRIPTOR *descr )
177 {
178     DC *dc;
179     BOOL ret = TRUE;
180
181     if (fmt <= 0 || fmt > nb_formats) return FALSE;
182     dc = get_dc_ptr( dev->hdc );
183     if (!dc->pixel_format) dc->pixel_format = fmt;
184     else ret = (dc->pixel_format == fmt);
185     release_dc_ptr( dc );
186     return ret;
187 }
188
189 /***********************************************************************
190  *              dibdrv_wglCopyContext
191  */
192 static BOOL dibdrv_wglCopyContext( struct wgl_context *src, struct wgl_context *dst, UINT mask )
193 {
194     FIXME( "not supported yet\n" );
195     return FALSE;
196 }
197
198 /***********************************************************************
199  *              dibdrv_wglCreateContext
200  */
201 static struct wgl_context *dibdrv_wglCreateContext( HDC hdc )
202 {
203     struct wgl_context *context;
204
205     if (!(context = HeapAlloc( GetProcessHeap(), 0, sizeof( *context )))) return NULL;
206     context->format = GetPixelFormat( hdc );
207     if (!context->format || context->format > nb_formats) context->format = 1;
208
209     if (!(context->context = pOSMesaCreateContextExt( pixel_formats[context->format - 1].mesa,
210                                                       pixel_formats[context->format - 1].depth_bits,
211                                                       pixel_formats[context->format - 1].stencil_bits,
212                                                       pixel_formats[context->format - 1].accum_bits, 0 )))
213     {
214         HeapFree( GetProcessHeap(), 0, context );
215         return NULL;
216     }
217     return context;
218 }
219
220 /***********************************************************************
221  *              dibdrv_wglDeleteContext
222  */
223 static void dibdrv_wglDeleteContext( struct wgl_context *context )
224 {
225     pOSMesaDestroyContext( context->context );
226     HeapFree( GetProcessHeap(), 0, context );
227 }
228
229 /***********************************************************************
230  *              dibdrv_wglGetPixelFormat
231  */
232 static int dibdrv_wglGetPixelFormat( HDC hdc )
233 {
234     DC *dc = get_dc_ptr( hdc );
235     int ret = 0;
236
237     if (dc)
238     {
239         ret = dc->pixel_format;
240         release_dc_ptr( dc );
241     }
242     return ret;
243 }
244
245 /***********************************************************************
246  *              dibdrv_wglGetProcAddress
247  */
248 static PROC dibdrv_wglGetProcAddress( const char *proc )
249 {
250     if (!strncmp( proc, "wgl", 3 )) return NULL;
251     return (PROC)pOSMesaGetProcAddress( proc );
252 }
253
254 /***********************************************************************
255  *              dibdrv_wglMakeCurrent
256  */
257 static BOOL dibdrv_wglMakeCurrent( HDC hdc, struct wgl_context *context )
258 {
259     HBITMAP bitmap;
260     BITMAPOBJ *bmp;
261     dib_info dib;
262     BOOL ret = FALSE;
263
264     if (!context)
265     {
266         pOSMesaMakeCurrent( NULL, NULL, GL_UNSIGNED_BYTE, 0, 0 );
267         return TRUE;
268     }
269
270     if (GetPixelFormat( hdc ) != context->format)
271         FIXME( "mismatched pixel formats %u/%u not supported yet\n",
272                GetPixelFormat( hdc ), context->format );
273
274     bitmap = GetCurrentObject( hdc, OBJ_BITMAP );
275     bmp = GDI_GetObjPtr( bitmap, OBJ_BITMAP );
276     if (!bmp) return FALSE;
277
278     if (init_dib_info_from_bitmapobj( &dib, bmp ))
279     {
280         char *bits;
281         int width = dib.rect.right - dib.rect.left;
282         int height = dib.rect.bottom - dib.rect.top;
283
284         if (dib.stride < 0)
285             bits = (char *)dib.bits.ptr + (dib.rect.bottom - 1) * dib.stride;
286         else
287             bits = (char *)dib.bits.ptr + dib.rect.top * dib.stride;
288         bits += dib.rect.left * dib.bit_count / 8;
289
290         TRACE( "context %p bits %p size %ux%u\n", context, bits, width, height );
291
292         ret = pOSMesaMakeCurrent( context->context, bits, GL_UNSIGNED_BYTE, width, height );
293         if (ret)
294         {
295             pOSMesaPixelStore( OSMESA_ROW_LENGTH, abs( dib.stride ) * 8 / dib.bit_count );
296             pOSMesaPixelStore( OSMESA_Y_UP, 1 );  /* Windows seems to assume bottom-up */
297         }
298     }
299     GDI_ReleaseObj( bitmap );
300     return ret;
301 }
302
303 /***********************************************************************
304  *              dibdrv_wglShareLists
305  */
306 static BOOL dibdrv_wglShareLists( struct wgl_context *org, struct wgl_context *dest )
307 {
308     FIXME( "not supported yet\n" );
309     return FALSE;
310 }
311
312 static struct opengl_funcs opengl_funcs =
313 {
314     {
315         dibdrv_wglCopyContext,        /* p_wglCopyContext */
316         dibdrv_wglCreateContext,      /* p_wglCreateContext */
317         dibdrv_wglDeleteContext,      /* p_wglDeleteContext */
318         dibdrv_wglGetPixelFormat,     /* p_wglGetPixelFormat */
319         dibdrv_wglGetProcAddress,     /* p_wglGetProcAddress */
320         dibdrv_wglMakeCurrent,        /* p_wglMakeCurrent */
321         dibdrv_wglShareLists,         /* p_wglShareLists */
322     }
323 };
324
325 /**********************************************************************
326  *           dibdrv_wine_get_wgl_driver
327  */
328 struct opengl_funcs *dibdrv_wine_get_wgl_driver( PHYSDEV dev, UINT version )
329 {
330     if (version != WINE_WGL_DRIVER_VERSION)
331     {
332         ERR( "version mismatch, opengl32 wants %u but dibdrv has %u\n", version, WINE_WGL_DRIVER_VERSION );
333         return NULL;
334     }
335
336     if (!init_opengl()) return (void *)-1;
337
338     return &opengl_funcs;
339 }
340
341 #else  /* SONAME_LIBOSMESA */
342
343 /**********************************************************************
344  *           dibdrv_DescribePixelFormat
345  */
346 int dibdrv_DescribePixelFormat( PHYSDEV dev, int fmt, UINT size, PIXELFORMATDESCRIPTOR *descr )
347 {
348     return 0;
349 }
350
351 /**********************************************************************
352  *           dibdrv_SetPixelFormat
353  */
354 BOOL dibdrv_SetPixelFormat( PHYSDEV dev, int fmt, const PIXELFORMATDESCRIPTOR *descr )
355 {
356     return FALSE;
357 }
358
359 /**********************************************************************
360  *           dibdrv_wine_get_wgl_driver
361  */
362 struct opengl_funcs *dibdrv_wine_get_wgl_driver( PHYSDEV dev, UINT version )
363 {
364     ERR( "OSMesa not compiled in, no OpenGL bitmap support\n" );
365     return (void *)-1;
366 }
367
368 #endif  /* SONAME_LIBOSMESA */