Fixed a race condition on RPC worker thread creation, and a typo.
[wine] / dlls / ddraw / direct3d / mesa.c
1 /*
2  * Copyright 2000 Marcus Meissner
3  * Copyright 2000 Peter Hunnisett
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "config.h"
21
22 #include <assert.h>
23 #ifdef HAVE_UNISTD_H
24 # include <unistd.h>
25 #endif
26 #include <fcntl.h>
27 #include <string.h>
28 #include <stdio.h>
29
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
32 #include "d3d.h"
33 #include "ddraw.h"
34 #include "winerror.h"
35
36 #include "ddraw_private.h"
37 #include "d3d_private.h"
38 #include "mesa_private.h"
39 #include "main.h"
40
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
44
45 HRESULT WINAPI
46 GL_IDirect3DImpl_3_2T_1T_EnumDevices(LPDIRECT3D3 iface,
47                                      LPD3DENUMDEVICESCALLBACK lpEnumDevicesCallback,
48                                      LPVOID lpUserArg)
49 {
50     ICOM_THIS_FROM(IDirect3DImpl, IDirect3D3, iface);
51     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpEnumDevicesCallback, lpUserArg);
52
53     /* Call functions defined in d3ddevices.c */
54     if (d3ddevice_enumerate(lpEnumDevicesCallback, lpUserArg) != D3DENUMRET_OK)
55         return D3D_OK;
56
57     return D3D_OK;
58 }
59
60 HRESULT WINAPI
61 GL_IDirect3DImpl_3_2T_1T_CreateLight(LPDIRECT3D3 iface,
62                                      LPDIRECT3DLIGHT* lplpDirect3DLight,
63                                      IUnknown* pUnkOuter)
64 {
65     ICOM_THIS_FROM(IDirect3DImpl, IDirect3D3, iface);
66     IDirect3DGLImpl *glThis = (IDirect3DGLImpl *) This;
67     int fl;
68     IDirect3DLightImpl *d3dlimpl;
69     HRESULT ret_value;
70     
71     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lplpDirect3DLight, pUnkOuter);
72     for (fl = 0; fl < MAX_LIGHTS; fl++) {
73         if ((glThis->free_lights & (0x01 << fl)) != 0) {
74             glThis->free_lights &= ~(0x01 << fl);
75             break;
76         }
77     }
78     if (fl == MAX_LIGHTS) {
79         return DDERR_INVALIDPARAMS; /* No way to say 'max lights reached' ... */
80     }
81     ret_value = d3dlight_create(&d3dlimpl, This, GL_LIGHT0 + fl);
82     *lplpDirect3DLight = ICOM_INTERFACE(d3dlimpl, IDirect3DLight);
83
84     return ret_value;
85 }
86
87 HRESULT WINAPI
88 GL_IDirect3DImpl_3_2T_1T_CreateMaterial(LPDIRECT3D3 iface,
89                                         LPDIRECT3DMATERIAL3* lplpDirect3DMaterial3,
90                                         IUnknown* pUnkOuter)
91 {
92     IDirect3DMaterialImpl *D3Dmat_impl;
93     HRESULT ret_value;
94     ICOM_THIS_FROM(IDirect3DImpl, IDirect3D3, iface);
95     
96     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lplpDirect3DMaterial3, pUnkOuter);
97     ret_value = d3dmaterial_create(&D3Dmat_impl, This);
98
99     *lplpDirect3DMaterial3 = ICOM_INTERFACE(D3Dmat_impl, IDirect3DMaterial3);
100
101     return ret_value;
102 }
103
104 HRESULT WINAPI
105 GL_IDirect3DImpl_3_2T_1T_CreateViewport(LPDIRECT3D3 iface,
106                                         LPDIRECT3DVIEWPORT3* lplpD3DViewport3,
107                                         IUnknown* pUnkOuter)
108 {
109     IDirect3DViewportImpl *D3Dvp_impl;
110     HRESULT ret_value;
111     ICOM_THIS_FROM(IDirect3DImpl, IDirect3D3, iface);
112     
113     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lplpD3DViewport3, pUnkOuter);
114     ret_value = d3dviewport_create(&D3Dvp_impl, This);
115
116     *lplpD3DViewport3 = ICOM_INTERFACE(D3Dvp_impl, IDirect3DViewport3);
117
118     return ret_value;
119 }
120
121 static HRESULT
122 create_device_helper(IDirect3DImpl *This,
123                      REFCLSID iid,
124                      IDirectDrawSurfaceImpl *lpDDS,
125                      void **obj,
126                      int version) {
127     IDirect3DDeviceImpl *lpd3ddev;
128     HRESULT ret_value;
129
130     ret_value = d3ddevice_create(&lpd3ddev, This, lpDDS);
131     if (FAILED(ret_value)) return ret_value;
132     
133     if ((iid == NULL) ||
134         (IsEqualGUID(&IID_D3DDEVICE_OpenGL, iid)) ||
135         (IsEqualGUID(&IID_IDirect3DHALDevice, iid)) ||
136         (IsEqualGUID(&IID_IDirect3DTnLHalDevice, iid)) ||
137         (IsEqualGUID(&IID_IDirect3DRefDevice, iid))) {
138         switch (version) {
139             case 1:
140                 *obj = ICOM_INTERFACE(lpd3ddev, IDirect3DDevice);
141                 TRACE(" returning OpenGL D3DDevice %p.\n", *obj);
142                 return D3D_OK;
143
144             case 2:
145                 *obj = ICOM_INTERFACE(lpd3ddev, IDirect3DDevice2);
146                 TRACE(" returning OpenGL D3DDevice2 %p.\n", *obj);
147                 return D3D_OK;
148
149             case 3:
150                 *obj = ICOM_INTERFACE(lpd3ddev, IDirect3DDevice3);
151                 TRACE(" returning OpenGL D3DDevice3 %p.\n", *obj);
152                 return D3D_OK;
153
154             case 7:
155                 *obj = ICOM_INTERFACE(lpd3ddev, IDirect3DDevice7);
156                 TRACE(" returning OpenGL D3DDevice7 %p.\n", *obj);
157                 return D3D_OK;
158         }
159     }
160
161     *obj = NULL;
162     ERR(" Interface unknown when creating D3DDevice (%s)\n", debugstr_guid(iid));
163     IDirect3DDevice7_Release(ICOM_INTERFACE(lpd3ddev, IDirect3DDevice7));
164     return DDERR_INVALIDPARAMS;
165 }
166      
167
168 HRESULT WINAPI
169 GL_IDirect3DImpl_2_CreateDevice(LPDIRECT3D2 iface,
170                                 REFCLSID rclsid,
171                                 LPDIRECTDRAWSURFACE lpDDS,
172                                 LPDIRECT3DDEVICE2* lplpD3DDevice2)
173 {
174     ICOM_THIS_FROM(IDirect3DImpl, IDirect3D2, iface);
175     IDirectDrawSurfaceImpl *ddsurfaceimpl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface3, lpDDS);
176     TRACE("(%p/%p)->(%s,%p,%p)\n", This, iface, debugstr_guid(rclsid), lpDDS, lplpD3DDevice2);
177     return create_device_helper(This, rclsid, ddsurfaceimpl, (void **) lplpD3DDevice2, 2);
178 }
179
180 HRESULT WINAPI
181 GL_IDirect3DImpl_3_CreateDevice(LPDIRECT3D3 iface,
182                                 REFCLSID rclsid,
183                                 LPDIRECTDRAWSURFACE4 lpDDS,
184                                 LPDIRECT3DDEVICE3* lplpD3DDevice3,
185                                 LPUNKNOWN lpUnk)
186 {
187     ICOM_THIS_FROM(IDirect3DImpl, IDirect3D3, iface);
188     IDirectDrawSurfaceImpl *ddsurfaceimpl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpDDS);
189     TRACE("(%p/%p)->(%s,%p,%p)\n", This, iface, debugstr_guid(rclsid), lpDDS, lplpD3DDevice3);
190     return create_device_helper(This, rclsid, ddsurfaceimpl, (void **) lplpD3DDevice3, 3);
191 }
192
193 HRESULT WINAPI
194 GL_IDirect3DImpl_3_2T_1T_FindDevice(LPDIRECT3D3 iface,
195                                     LPD3DFINDDEVICESEARCH lpD3DDFS,
196                                     LPD3DFINDDEVICERESULT lpD3DFDR)
197 {
198     ICOM_THIS_FROM(IDirect3DImpl, IDirect3D3, iface);
199     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DDFS, lpD3DFDR);
200     return d3ddevice_find(This, lpD3DDFS, lpD3DFDR);
201 }
202
203 HRESULT WINAPI
204 GL_IDirect3DImpl_7_3T_EnumZBufferFormats(LPDIRECT3D7 iface,
205                                          REFCLSID riidDevice,
206                                          LPD3DENUMPIXELFORMATSCALLBACK lpEnumCallback,
207                                          LPVOID lpContext)
208 {
209     ICOM_THIS_FROM(IDirect3DImpl, IDirect3D7, iface);
210     DDPIXELFORMAT pformat;
211     
212     TRACE("(%p/%p)->(%s,%p,%p)\n", This, iface, debugstr_guid(riidDevice), lpEnumCallback, lpContext);
213
214     memset(&pformat, 0, sizeof(pformat));
215     pformat.dwSize = sizeof(DDPIXELFORMAT);
216     pformat.dwFourCC = 0;   
217     TRACE("Enumerating dummy ZBuffer format (16 bits)\n");
218     pformat.dwFlags = DDPF_ZBUFFER;
219     pformat.u1.dwZBufferBitDepth = 16;
220     pformat.u3.dwZBitMask =    0x0000FFFF;
221     pformat.u5.dwRGBZBitMask = 0x0000FFFF;
222
223     /* Whatever the return value, stop here.. */
224     lpEnumCallback(&pformat, lpContext);
225     
226     return D3D_OK;
227 }
228
229 HRESULT WINAPI
230 GL_IDirect3DImpl_7_EnumDevices(LPDIRECT3D7 iface,
231                                LPD3DENUMDEVICESCALLBACK7 lpEnumDevicesCallback,
232                                LPVOID lpUserArg)
233 {
234     ICOM_THIS_FROM(IDirect3DImpl, IDirect3D7, iface);
235     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpEnumDevicesCallback, lpUserArg);
236
237     if (d3ddevice_enumerate7(lpEnumDevicesCallback, lpUserArg) != D3DENUMRET_OK)
238         return D3D_OK;
239     
240     return D3D_OK;
241 }
242
243 HRESULT WINAPI
244 GL_IDirect3DImpl_7_CreateDevice(LPDIRECT3D7 iface,
245                                 REFCLSID rclsid,
246                                 LPDIRECTDRAWSURFACE7 lpDDS,
247                                 LPDIRECT3DDEVICE7* lplpD3DDevice)
248 {
249     ICOM_THIS_FROM(IDirect3DImpl, IDirect3D7, iface);
250     IDirectDrawSurfaceImpl *ddsurfaceimpl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpDDS);
251     TRACE("(%p/%p)->(%s,%p,%p)\n", This, iface, debugstr_guid(rclsid), lpDDS, lplpD3DDevice);
252     return create_device_helper(This, rclsid, ddsurfaceimpl, (void **) lplpD3DDevice, 7);
253 }
254
255 HRESULT WINAPI
256 GL_IDirect3DImpl_7_3T_CreateVertexBuffer(LPDIRECT3D7 iface,
257                                          LPD3DVERTEXBUFFERDESC lpD3DVertBufDesc,
258                                          LPDIRECT3DVERTEXBUFFER7* lplpD3DVertBuf,
259                                          DWORD dwFlags)
260 {
261     ICOM_THIS_FROM(IDirect3DImpl, IDirect3D7, iface);
262     IDirect3DVertexBufferImpl *vbimpl;
263     HRESULT res;
264     
265     TRACE("(%p/%p)->(%p,%p,%08lx)\n", This, iface, lpD3DVertBufDesc, lplpD3DVertBuf, dwFlags);
266
267     res = d3dvertexbuffer_create(&vbimpl, This, lpD3DVertBufDesc, dwFlags);
268
269     *lplpD3DVertBuf = ICOM_INTERFACE(vbimpl, IDirect3DVertexBuffer7);
270     
271     return res;
272 }
273
274 static void light_released(IDirect3DImpl *This, GLenum light_num)
275 {
276     IDirect3DGLImpl *glThis = (IDirect3DGLImpl *) This;
277     glThis->free_lights |= (light_num - GL_LIGHT0);
278 }
279
280 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
281 # define XCAST(fun)     (typeof(VTABLE_IDirect3D7.fun))
282 #else
283 # define XCAST(fun)     (void*)
284 #endif
285
286 ICOM_VTABLE(IDirect3D7) VTABLE_IDirect3D7 =
287 {
288     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
289     XCAST(QueryInterface) Main_IDirect3DImpl_7_3T_2T_1T_QueryInterface,
290     XCAST(AddRef) Main_IDirect3DImpl_7_3T_2T_1T_AddRef,
291     XCAST(Release) Main_IDirect3DImpl_7_3T_2T_1T_Release,
292     XCAST(EnumDevices) GL_IDirect3DImpl_7_EnumDevices,
293     XCAST(CreateDevice) GL_IDirect3DImpl_7_CreateDevice,
294     XCAST(CreateVertexBuffer) GL_IDirect3DImpl_7_3T_CreateVertexBuffer,
295     XCAST(EnumZBufferFormats) GL_IDirect3DImpl_7_3T_EnumZBufferFormats,
296     XCAST(EvictManagedTextures) Main_IDirect3DImpl_7_3T_EvictManagedTextures,
297 };
298
299 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
300 #undef XCAST
301 #endif
302
303
304 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
305 # define XCAST(fun)     (typeof(VTABLE_IDirect3D3.fun))
306 #else
307 # define XCAST(fun)     (void*)
308 #endif
309
310 ICOM_VTABLE(IDirect3D3) VTABLE_IDirect3D3 =
311 {
312     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
313     XCAST(QueryInterface) Thunk_IDirect3DImpl_3_QueryInterface,
314     XCAST(AddRef) Thunk_IDirect3DImpl_3_AddRef,
315     XCAST(Release) Thunk_IDirect3DImpl_3_Release,
316     XCAST(EnumDevices) GL_IDirect3DImpl_3_2T_1T_EnumDevices,
317     XCAST(CreateLight) GL_IDirect3DImpl_3_2T_1T_CreateLight,
318     XCAST(CreateMaterial) GL_IDirect3DImpl_3_2T_1T_CreateMaterial,
319     XCAST(CreateViewport) GL_IDirect3DImpl_3_2T_1T_CreateViewport,
320     XCAST(FindDevice) GL_IDirect3DImpl_3_2T_1T_FindDevice,
321     XCAST(CreateDevice) GL_IDirect3DImpl_3_CreateDevice,
322     XCAST(CreateVertexBuffer) Thunk_IDirect3DImpl_3_CreateVertexBuffer,
323     XCAST(EnumZBufferFormats) Thunk_IDirect3DImpl_3_EnumZBufferFormats,
324     XCAST(EvictManagedTextures) Thunk_IDirect3DImpl_3_EvictManagedTextures,
325 };
326
327 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
328 #undef XCAST
329 #endif
330
331
332 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
333 # define XCAST(fun)     (typeof(VTABLE_IDirect3D2.fun))
334 #else
335 # define XCAST(fun)     (void*)
336 #endif
337
338 ICOM_VTABLE(IDirect3D2) VTABLE_IDirect3D2 =
339 {
340     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
341     XCAST(QueryInterface) Thunk_IDirect3DImpl_2_QueryInterface,
342     XCAST(AddRef) Thunk_IDirect3DImpl_2_AddRef,
343     XCAST(Release) Thunk_IDirect3DImpl_2_Release,
344     XCAST(EnumDevices) Thunk_IDirect3DImpl_2_EnumDevices,
345     XCAST(CreateLight) Thunk_IDirect3DImpl_2_CreateLight,
346     XCAST(CreateMaterial) Thunk_IDirect3DImpl_2_CreateMaterial,
347     XCAST(CreateViewport) Thunk_IDirect3DImpl_2_CreateViewport,
348     XCAST(FindDevice) Thunk_IDirect3DImpl_2_FindDevice,
349     XCAST(CreateDevice) GL_IDirect3DImpl_2_CreateDevice,
350 };
351
352 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
353 #undef XCAST
354 #endif
355
356
357 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
358 # define XCAST(fun)     (typeof(VTABLE_IDirect3D.fun))
359 #else
360 # define XCAST(fun)     (void*)
361 #endif
362
363 ICOM_VTABLE(IDirect3D) VTABLE_IDirect3D =
364 {
365     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
366     XCAST(QueryInterface) Thunk_IDirect3DImpl_1_QueryInterface,
367     XCAST(AddRef) Thunk_IDirect3DImpl_1_AddRef,
368     XCAST(Release) Thunk_IDirect3DImpl_1_Release,
369     XCAST(Initialize) Main_IDirect3DImpl_1_Initialize,
370     XCAST(EnumDevices) Thunk_IDirect3DImpl_1_EnumDevices,
371     XCAST(CreateLight) Thunk_IDirect3DImpl_1_CreateLight,
372     XCAST(CreateMaterial) Thunk_IDirect3DImpl_1_CreateMaterial,
373     XCAST(CreateViewport) Thunk_IDirect3DImpl_1_CreateViewport,
374     XCAST(FindDevice) Thunk_IDirect3DImpl_1_FindDevice,
375 };
376
377 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
378 #undef XCAST
379 #endif
380
381 static HRESULT d3d_add_device(IDirect3DImpl *This, IDirect3DDeviceImpl *device)
382 {
383     if  (This->current_device == NULL) {
384         /* Create delayed textures now that we have an OpenGL context...
385            For that, go through all surface attached to our DDraw object and create
386            OpenGL textures for all textures.. */
387         IDirectDrawSurfaceImpl *surf = This->ddraw->surfaces;
388
389         while (surf != NULL) {
390             if (surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_TEXTURE) {
391                 /* Found a texture.. Now create the OpenGL part */
392                 d3dtexture_create(This, surf, FALSE, surf->mip_main);
393             }
394             surf = surf->next_ddraw;
395         }
396     }
397     /* For the moment, only one device 'supported'... */
398     This->current_device = device;
399
400     return DD_OK;
401 }
402
403 static HRESULT d3d_remove_device(IDirect3DImpl *This, IDirect3DDeviceImpl *device)
404 {
405     This->current_device = NULL;
406     return DD_OK;
407 }
408
409 HRESULT direct3d_create(IDirect3DImpl **obj, IDirectDrawImpl *ddraw)
410 {
411     IDirect3DImpl *object;
412     IDirect3DGLImpl *globject;
413     
414     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DGLImpl));
415     if (object == NULL) return DDERR_OUTOFMEMORY;
416
417     object->ref = 1;
418     object->ddraw = ddraw;
419     object->create_texture = d3dtexture_create;
420     object->added_device = d3d_add_device;
421     object->removed_device = d3d_remove_device;
422
423     ICOM_INIT_INTERFACE(object, IDirect3D,  VTABLE_IDirect3D);
424     ICOM_INIT_INTERFACE(object, IDirect3D2, VTABLE_IDirect3D2);
425     ICOM_INIT_INTERFACE(object, IDirect3D3, VTABLE_IDirect3D3);
426     ICOM_INIT_INTERFACE(object, IDirect3D7, VTABLE_IDirect3D7);
427
428     globject = (IDirect3DGLImpl *) object;
429     globject->free_lights = (0x01 << MAX_LIGHTS) - 1; /* There are, in total, 8 lights in OpenGL */
430     globject->light_released = light_released;
431
432     *obj = object;
433
434     TRACE(" creating implementation at %p.\n", *obj);
435     
436     return D3D_OK;
437 }