jscript: Make String_toUpperCase generic.
[wine] / dlls / d3d8 / directx.c
1 /*
2  * IDirect3D8 implementation
3  *
4  * Copyright 2002-2004 Jason Edmeades
5  * Copyright 2003-2004 Raphael Junqueira
6  * Copyright 2004 Christian Costa
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24
25 #include <stdarg.h>
26
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
35
36 #include "d3d8_private.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(d3d8);
39
40 /* IDirect3D IUnknown parts follow: */
41 static HRESULT WINAPI IDirect3D8Impl_QueryInterface(LPDIRECT3D8 iface, REFIID riid,LPVOID *ppobj)
42 {
43     IDirect3D8Impl *This = (IDirect3D8Impl *)iface;
44
45     if (IsEqualGUID(riid, &IID_IUnknown)
46         || IsEqualGUID(riid, &IID_IDirect3D8)) {
47         IUnknown_AddRef(iface);
48         *ppobj = This;
49         return S_OK;
50     }
51
52     WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid),ppobj);
53     *ppobj = NULL;
54     return E_NOINTERFACE;
55 }
56
57 static ULONG WINAPI IDirect3D8Impl_AddRef(LPDIRECT3D8 iface) {
58     IDirect3D8Impl *This = (IDirect3D8Impl *)iface;
59     ULONG ref = InterlockedIncrement(&This->ref);
60
61     TRACE("(%p) : AddRef from %d\n", This, ref - 1);
62
63     return ref;
64 }
65
66 static ULONG WINAPI IDirect3D8Impl_Release(LPDIRECT3D8 iface) {
67     IDirect3D8Impl *This = (IDirect3D8Impl *)iface;
68     ULONG ref = InterlockedDecrement(&This->ref);
69
70     TRACE("(%p) : ReleaseRef to %d\n", This, ref);
71
72     if (ref == 0) {
73         TRACE("Releasing wined3d %p\n", This->WineD3D);
74         EnterCriticalSection(&d3d8_cs);
75         IWineD3D_Release(This->WineD3D);
76         LeaveCriticalSection(&d3d8_cs);
77         HeapFree(GetProcessHeap(), 0, This);
78     }
79
80     return ref;
81 }
82
83 /* IDirect3D8 Interface follow: */
84 static HRESULT WINAPI IDirect3D8Impl_RegisterSoftwareDevice (LPDIRECT3D8 iface, void* pInitializeFunction) {
85     IDirect3D8Impl *This = (IDirect3D8Impl *)iface;
86     HRESULT hr;
87     TRACE("(%p)->(%p)\n", This, pInitializeFunction);
88
89     EnterCriticalSection(&d3d8_cs);
90     hr = IWineD3D_RegisterSoftwareDevice(This->WineD3D, pInitializeFunction);
91     LeaveCriticalSection(&d3d8_cs);
92     return hr;
93 }
94
95 static UINT WINAPI IDirect3D8Impl_GetAdapterCount (LPDIRECT3D8 iface) {
96     IDirect3D8Impl *This = (IDirect3D8Impl *)iface;
97     HRESULT hr;
98     TRACE("(%p)\n", This);
99
100     EnterCriticalSection(&d3d8_cs);
101     hr = IWineD3D_GetAdapterCount(This->WineD3D);
102     LeaveCriticalSection(&d3d8_cs);
103     return hr;
104 }
105
106 static HRESULT WINAPI IDirect3D8Impl_GetAdapterIdentifier(LPDIRECT3D8 iface,
107         UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER8 *pIdentifier)
108 {
109     IDirect3D8Impl *This = (IDirect3D8Impl *)iface;
110     WINED3DADAPTER_IDENTIFIER adapter_id;
111     HRESULT hr;
112
113     TRACE("(%p)->(%d,%08x, %p\n", This, Adapter, Flags, pIdentifier);
114
115     adapter_id.driver = pIdentifier->Driver;
116     adapter_id.driver_size = sizeof(pIdentifier->Driver);
117     adapter_id.description = pIdentifier->Description;
118     adapter_id.description_size = sizeof(pIdentifier->Description);
119     adapter_id.device_name = NULL; /* d3d9 only */
120     adapter_id.device_name_size = 0; /* d3d9 only */
121
122     EnterCriticalSection(&d3d8_cs);
123     hr = IWineD3D_GetAdapterIdentifier(This->WineD3D, Adapter, Flags, &adapter_id);
124     LeaveCriticalSection(&d3d8_cs);
125
126     pIdentifier->DriverVersion = adapter_id.driver_version;
127     pIdentifier->VendorId = adapter_id.vendor_id;
128     pIdentifier->DeviceId = adapter_id.device_id;
129     pIdentifier->SubSysId = adapter_id.subsystem_id;
130     pIdentifier->Revision = adapter_id.revision;
131     memcpy(&pIdentifier->DeviceIdentifier, &adapter_id.device_identifier, sizeof(pIdentifier->DeviceIdentifier));
132     pIdentifier->WHQLLevel = adapter_id.whql_level;
133
134     return hr;
135 }
136
137 static UINT WINAPI IDirect3D8Impl_GetAdapterModeCount (LPDIRECT3D8 iface,UINT Adapter) {
138     IDirect3D8Impl *This = (IDirect3D8Impl *)iface;
139     HRESULT hr;
140     TRACE("(%p)->(%d)\n", This, Adapter);
141
142     EnterCriticalSection(&d3d8_cs);
143     hr = IWineD3D_GetAdapterModeCount(This->WineD3D, Adapter, 0 /* format */);
144     LeaveCriticalSection(&d3d8_cs);
145     return hr;
146 }
147
148 static HRESULT WINAPI IDirect3D8Impl_EnumAdapterModes (LPDIRECT3D8 iface, UINT Adapter, UINT Mode, D3DDISPLAYMODE* pMode) {
149     IDirect3D8Impl *This = (IDirect3D8Impl *)iface;
150     HRESULT hr;
151     TRACE("(%p)->(%d, %d, %p)\n", This, Adapter, Mode, pMode);
152
153     EnterCriticalSection(&d3d8_cs);
154     hr = IWineD3D_EnumAdapterModes(This->WineD3D, Adapter, WINED3DFMT_UNKNOWN, Mode, (WINED3DDISPLAYMODE *) pMode);
155     LeaveCriticalSection(&d3d8_cs);
156
157     if (SUCCEEDED(hr)) pMode->Format = d3dformat_from_wined3dformat(pMode->Format);
158
159     return hr;
160 }
161
162 static HRESULT WINAPI IDirect3D8Impl_GetAdapterDisplayMode (LPDIRECT3D8 iface, UINT Adapter, D3DDISPLAYMODE* pMode) {
163     IDirect3D8Impl *This = (IDirect3D8Impl *)iface;
164     HRESULT hr;
165     TRACE("(%p)->(%d,%p)\n", This, Adapter, pMode);
166
167     EnterCriticalSection(&d3d8_cs);
168     hr = IWineD3D_GetAdapterDisplayMode(This->WineD3D, Adapter, (WINED3DDISPLAYMODE *) pMode);
169     LeaveCriticalSection(&d3d8_cs);
170
171     if (SUCCEEDED(hr)) pMode->Format = d3dformat_from_wined3dformat(pMode->Format);
172
173     return hr;
174 }
175
176 static HRESULT  WINAPI  IDirect3D8Impl_CheckDeviceType            (LPDIRECT3D8 iface,
177                                                             UINT Adapter, D3DDEVTYPE CheckType, D3DFORMAT DisplayFormat,
178                                                             D3DFORMAT BackBufferFormat, BOOL Windowed) {
179     IDirect3D8Impl *This = (IDirect3D8Impl *)iface;
180     HRESULT hr;
181     TRACE("(%p)->(%d, %d, %d, %d, %s)\n", This, Adapter, CheckType, DisplayFormat, BackBufferFormat, Windowed ? "true" : "false");
182
183     EnterCriticalSection(&d3d8_cs);
184     hr = IWineD3D_CheckDeviceType(This->WineD3D, Adapter, CheckType, wined3dformat_from_d3dformat(DisplayFormat),
185             wined3dformat_from_d3dformat(BackBufferFormat), Windowed);
186     LeaveCriticalSection(&d3d8_cs);
187     return hr;
188 }
189
190 static HRESULT  WINAPI  IDirect3D8Impl_CheckDeviceFormat          (LPDIRECT3D8 iface,
191                                                             UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat,
192                                                             DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) {
193     IDirect3D8Impl *This = (IDirect3D8Impl *)iface;
194     HRESULT hr;
195     WINED3DRESOURCETYPE WineD3DRType;
196     TRACE("(%p)->(%d, %d, %d, %08x, %d, %d)\n", This, Adapter, DeviceType, AdapterFormat, Usage, RType, CheckFormat);
197
198     switch(RType) {
199         case D3DRTYPE_VERTEXBUFFER:
200         case D3DRTYPE_INDEXBUFFER:
201             WineD3DRType = WINED3DRTYPE_BUFFER;
202             break;
203
204         default:
205             WineD3DRType = RType;
206             break;
207     }
208
209     EnterCriticalSection(&d3d8_cs);
210     hr = IWineD3D_CheckDeviceFormat(This->WineD3D, Adapter, DeviceType, wined3dformat_from_d3dformat(AdapterFormat),
211             Usage, WineD3DRType, wined3dformat_from_d3dformat(CheckFormat), SURFACE_OPENGL);
212     LeaveCriticalSection(&d3d8_cs);
213     return hr;
214 }
215
216 static HRESULT  WINAPI  IDirect3D8Impl_CheckDeviceMultiSampleType(LPDIRECT3D8 iface,
217                                                            UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat,
218                                                            BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType) {
219     IDirect3D8Impl *This = (IDirect3D8Impl *)iface;
220     HRESULT hr;
221     TRACE("(%p)-<(%d, %d, %d, %s, %d)\n", This, Adapter, DeviceType, SurfaceFormat, Windowed ? "true" : "false", MultiSampleType);
222
223     EnterCriticalSection(&d3d8_cs);
224     hr = IWineD3D_CheckDeviceMultiSampleType(This->WineD3D, Adapter, DeviceType,
225             wined3dformat_from_d3dformat(SurfaceFormat), Windowed, (WINED3DMULTISAMPLE_TYPE) MultiSampleType, NULL);
226     LeaveCriticalSection(&d3d8_cs);
227     return hr;
228 }
229
230 static HRESULT  WINAPI  IDirect3D8Impl_CheckDepthStencilMatch(LPDIRECT3D8 iface, 
231                                                        UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat,
232                                                        D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) {
233     IDirect3D8Impl *This = (IDirect3D8Impl *)iface;
234     HRESULT hr;
235     TRACE("(%p)-<(%d, %d, %d, %d, %d)\n", This, Adapter, DeviceType, AdapterFormat, RenderTargetFormat, DepthStencilFormat);
236
237     EnterCriticalSection(&d3d8_cs);
238     hr = IWineD3D_CheckDepthStencilMatch(This->WineD3D, Adapter, DeviceType,
239             wined3dformat_from_d3dformat(AdapterFormat), wined3dformat_from_d3dformat(RenderTargetFormat),
240             wined3dformat_from_d3dformat(DepthStencilFormat));
241     LeaveCriticalSection(&d3d8_cs);
242     return hr;
243 }
244
245 static HRESULT  WINAPI  IDirect3D8Impl_GetDeviceCaps(LPDIRECT3D8 iface, UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS8* pCaps) {
246     IDirect3D8Impl *This = (IDirect3D8Impl *)iface;
247     HRESULT hrc = D3D_OK;
248     WINED3DCAPS *pWineCaps;
249
250     TRACE("(%p) Relay %d %u %p\n", This, Adapter, DeviceType, pCaps);
251
252     if(NULL == pCaps){
253         return D3DERR_INVALIDCALL;
254     }
255     pWineCaps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINED3DCAPS));
256     if(pWineCaps == NULL){
257         return D3DERR_INVALIDCALL; /*well this is what MSDN says to return*/
258     }
259     EnterCriticalSection(&d3d8_cs);
260     hrc = IWineD3D_GetDeviceCaps(This->WineD3D, Adapter, DeviceType, pWineCaps);
261     LeaveCriticalSection(&d3d8_cs);
262     WINECAPSTOD3D8CAPS(pCaps, pWineCaps)
263     HeapFree(GetProcessHeap(), 0, pWineCaps);
264
265     /* D3D8 doesn't support SM 2.0 or higher, so clamp to 1.x */
266     if(pCaps->PixelShaderVersion > D3DPS_VERSION(1,4)){
267         pCaps->PixelShaderVersion = D3DPS_VERSION(1,4);
268     }
269     if(pCaps->VertexShaderVersion > D3DVS_VERSION(1,1)){
270         pCaps->VertexShaderVersion = D3DVS_VERSION(1,1);
271     }
272     pCaps->MaxVertexShaderConst = min(D3D8_MAX_VERTEX_SHADER_CONSTANTF, pCaps->MaxVertexShaderConst);
273
274     TRACE("(%p) returning %p\n", This, pCaps);
275     return hrc;
276 }
277
278 static HMONITOR WINAPI  IDirect3D8Impl_GetAdapterMonitor(LPDIRECT3D8 iface, UINT Adapter) {
279     IDirect3D8Impl *This = (IDirect3D8Impl *)iface;
280     HMONITOR ret;
281     TRACE("(%p)->(%d)\n", This, Adapter);
282
283     EnterCriticalSection(&d3d8_cs);
284     ret = IWineD3D_GetAdapterMonitor(This->WineD3D, Adapter);
285     LeaveCriticalSection(&d3d8_cs);
286     return ret;
287 }
288
289 ULONG WINAPI D3D8CB_DestroyRenderTarget(IWineD3DSurface *pSurface) {
290     IDirect3DSurface8Impl* surfaceParent;
291     TRACE("(%p) call back\n", pSurface);
292
293     IWineD3DSurface_GetParent(pSurface, (IUnknown **) &surfaceParent);
294     surfaceParent->isImplicit = FALSE;
295     /* Surface had refcount of 0 GetParent addrefed to 1, so 1 Release is enough */
296     return IDirect3DSurface8_Release((IDirect3DSurface8*) surfaceParent);
297 }
298
299 ULONG WINAPI D3D8CB_DestroySwapChain(IWineD3DSwapChain *pSwapChain) {
300     IUnknown* swapChainParent;
301     TRACE("(%p) call back\n", pSwapChain);
302
303     IWineD3DSwapChain_GetParent(pSwapChain, &swapChainParent);
304     IUnknown_Release(swapChainParent);
305     return IUnknown_Release(swapChainParent);
306 }
307
308 ULONG WINAPI D3D8CB_DestroyDepthStencilSurface(IWineD3DSurface *pSurface) {
309     IDirect3DSurface8Impl* surfaceParent;
310     TRACE("(%p) call back\n", pSurface);
311
312     IWineD3DSurface_GetParent(pSurface, (IUnknown **) &surfaceParent);
313     surfaceParent->isImplicit = FALSE;
314     /* Surface had refcount of 0 GetParent addrefed to 1, so 1 Release is enough */
315     return IDirect3DSurface8_Release((IDirect3DSurface8*) surfaceParent);
316 }
317
318 static HRESULT WINAPI IDirect3D8Impl_CreateDevice(LPDIRECT3D8 iface, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow,
319                                             DWORD BehaviourFlags, D3DPRESENT_PARAMETERS* pPresentationParameters,
320                                             IDirect3DDevice8** ppReturnedDeviceInterface) {
321
322     IDirect3D8Impl       *This   = (IDirect3D8Impl *)iface;
323     IDirect3DDevice8Impl *object = NULL;
324     WINED3DPRESENT_PARAMETERS localParameters;
325     HRESULT hr;
326     TRACE("(%p) Relay\n", This);
327
328     /* Check the validity range of the adapter parameter */
329     if (Adapter >= IDirect3D8Impl_GetAdapterCount(iface)) {
330         *ppReturnedDeviceInterface = NULL;
331         return D3DERR_INVALIDCALL;
332     }
333
334     /* Allocate the storage for the device object */
335     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDevice8Impl));
336     if (NULL == object) {
337         FIXME("Allocation of memory failed\n");
338         *ppReturnedDeviceInterface = NULL;
339         return D3DERR_OUTOFVIDEOMEMORY;
340     }
341
342     object->lpVtbl = &Direct3DDevice8_Vtbl;
343     object->device_parent_vtbl = &d3d8_wined3d_device_parent_vtbl;
344     object->ref = 1;
345     object->handle_table.entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
346             D3D8_INITIAL_HANDLE_TABLE_SIZE * sizeof(*object->handle_table.entries));
347     object->handle_table.table_size = D3D8_INITIAL_HANDLE_TABLE_SIZE;
348     *ppReturnedDeviceInterface = (IDirect3DDevice8 *)object;
349
350     /* Allocate an associated WineD3DDevice object */
351     EnterCriticalSection(&d3d8_cs);
352     hr = IWineD3D_CreateDevice(This->WineD3D, Adapter, DeviceType, hFocusWindow, BehaviourFlags,
353             (IUnknown *)object, (IWineD3DDeviceParent *)&object->device_parent_vtbl, &object->WineD3DDevice);
354
355     if (hr != D3D_OK) {
356         HeapFree(GetProcessHeap(), 0, object);
357         *ppReturnedDeviceInterface = NULL;
358         LeaveCriticalSection(&d3d8_cs);
359         return hr;
360     }
361
362     TRACE("(%p) : Created Device %p\n", This, object);
363
364     localParameters.BackBufferWidth                             = pPresentationParameters->BackBufferWidth;
365     localParameters.BackBufferHeight                            = pPresentationParameters->BackBufferHeight;
366     localParameters.BackBufferFormat                            = wined3dformat_from_d3dformat(pPresentationParameters->BackBufferFormat);
367     localParameters.BackBufferCount                             = pPresentationParameters->BackBufferCount;
368     localParameters.MultiSampleType                             = pPresentationParameters->MultiSampleType;
369     localParameters.MultiSampleQuality                          = 0; /* d3d9 only */
370     localParameters.SwapEffect                                  = pPresentationParameters->SwapEffect;
371     localParameters.hDeviceWindow                               = pPresentationParameters->hDeviceWindow;
372     localParameters.Windowed                                    = pPresentationParameters->Windowed;
373     localParameters.EnableAutoDepthStencil                      = pPresentationParameters->EnableAutoDepthStencil;
374     localParameters.AutoDepthStencilFormat                      = wined3dformat_from_d3dformat(pPresentationParameters->AutoDepthStencilFormat);
375     localParameters.Flags                                       = pPresentationParameters->Flags;
376     localParameters.FullScreen_RefreshRateInHz                  = pPresentationParameters->FullScreen_RefreshRateInHz;
377     localParameters.PresentationInterval                        = pPresentationParameters->FullScreen_PresentationInterval;
378     localParameters.AutoRestoreDisplayMode                      = TRUE;
379
380     if(BehaviourFlags & D3DCREATE_MULTITHREADED) {
381         IWineD3DDevice_SetMultithreaded(object->WineD3DDevice);
382     }
383
384     hr = IWineD3DDevice_Init3D(object->WineD3DDevice, &localParameters);
385     LeaveCriticalSection(&d3d8_cs);
386
387     pPresentationParameters->BackBufferWidth                    = localParameters.BackBufferWidth;
388     pPresentationParameters->BackBufferHeight                   = localParameters.BackBufferHeight;
389     pPresentationParameters->BackBufferFormat                   = d3dformat_from_wined3dformat(localParameters.BackBufferFormat);
390     pPresentationParameters->BackBufferCount                    = localParameters.BackBufferCount;
391     pPresentationParameters->MultiSampleType                    = localParameters.MultiSampleType;
392     pPresentationParameters->SwapEffect                         = localParameters.SwapEffect;
393     pPresentationParameters->hDeviceWindow                      = localParameters.hDeviceWindow;
394     pPresentationParameters->Windowed                           = localParameters.Windowed;
395     pPresentationParameters->EnableAutoDepthStencil             = localParameters.EnableAutoDepthStencil;
396     pPresentationParameters->AutoDepthStencilFormat             = d3dformat_from_wined3dformat(localParameters.AutoDepthStencilFormat);
397     pPresentationParameters->Flags                              = localParameters.Flags;
398     pPresentationParameters->FullScreen_RefreshRateInHz         = localParameters.FullScreen_RefreshRateInHz;
399     pPresentationParameters->FullScreen_PresentationInterval    = localParameters.PresentationInterval;
400
401     if (hr != D3D_OK) {
402         FIXME("(%p) D3D Initialization failed for WineD3DDevice %p\n", This, object->WineD3DDevice);
403         HeapFree(GetProcessHeap(), 0, object);
404         *ppReturnedDeviceInterface = NULL;
405     }
406
407     object->declArraySize = 16;
408     object->decls = HeapAlloc(GetProcessHeap(), 0, object->declArraySize * sizeof(*object->decls));
409     if(!object->decls) {
410         ERR("Out of memory\n");
411         EnterCriticalSection(&d3d8_cs);
412         IWineD3DDevice_Release(object->WineD3DDevice);
413         LeaveCriticalSection(&d3d8_cs);
414         HeapFree(GetProcessHeap(), 0, object);
415         *ppReturnedDeviceInterface = NULL;
416         hr = E_OUTOFMEMORY;
417     }
418     return hr;
419 }
420
421 const IDirect3D8Vtbl Direct3D8_Vtbl =
422 {
423     /* IUnknown */
424     IDirect3D8Impl_QueryInterface,
425     IDirect3D8Impl_AddRef,
426     IDirect3D8Impl_Release,
427     /* IDirect3D8 */
428     IDirect3D8Impl_RegisterSoftwareDevice,
429     IDirect3D8Impl_GetAdapterCount,
430     IDirect3D8Impl_GetAdapterIdentifier,
431     IDirect3D8Impl_GetAdapterModeCount,
432     IDirect3D8Impl_EnumAdapterModes,
433     IDirect3D8Impl_GetAdapterDisplayMode,
434     IDirect3D8Impl_CheckDeviceType,
435     IDirect3D8Impl_CheckDeviceFormat,
436     IDirect3D8Impl_CheckDeviceMultiSampleType,
437     IDirect3D8Impl_CheckDepthStencilMatch,
438     IDirect3D8Impl_GetDeviceCaps,
439     IDirect3D8Impl_GetAdapterMonitor,
440     IDirect3D8Impl_CreateDevice
441 };