Cleanup code that is strange or difficult to parse.
[wine] / dlls / ddraw / ddraw / hal.c
1 /*      DirectDraw HAL driver
2  *
3  * Copyright 2001 TransGaming Technologies Inc.
4  */
5
6 #include "config.h"
7
8 #include "debugtools.h"
9 #include "ddraw.h"
10 #include "ddrawi.h"
11 #include "d3dhal.h"
12
13 #include <assert.h>
14 #include <stdlib.h>
15
16 #include "ddraw_private.h"
17 #include "ddraw/main.h"
18 #include "ddraw/user.h"
19 #include "ddraw/hal.h"
20 #include "dclipper/main.h"
21 #include "dpalette/main.h"
22 #include "dpalette/hal.h"
23 #include "dsurface/main.h"
24 #include "dsurface/dib.h"
25 #include "dsurface/user.h"
26 #include "dsurface/hal.h"
27
28 DEFAULT_DEBUG_CHANNEL(ddraw);
29
30 static ICOM_VTABLE(IDirectDraw7) HAL_DirectDraw_VTable;
31
32 static DDVERSIONDATA hal_version;
33 static DD32BITDRIVERDATA hal_driverdata;
34 static HINSTANCE hal_instance;
35
36 static const DDDEVICEIDENTIFIER2 hal_device = 
37 {
38     "display",
39     "DirectDraw HAL",
40     { { 0x00010001, 0x00010001 } },
41     0, 0, 0, 0,
42     /* 40c1b248-9d7d-4a29-b7d7-4cd8109f3d5d */
43     {0x40c1b248,0x9d7d,0x4a29,{0xd7,0xb7,0x4c,0xd8,0x10,0x9f,0x3d,0x5d}},
44     0
45 };
46
47 HRESULT HAL_DirectDraw_Create(const GUID* pGUID, LPDIRECTDRAW7* pIface,
48                               IUnknown* pUnkOuter, BOOL ex);
49 HRESULT HAL_DirectDraw_Initialize(IDirectDrawImpl*, const GUID*);
50
51 static const ddraw_driver hal_driver =
52 {
53     &hal_device,
54     100, /* we prefer the HAL */
55     HAL_DirectDraw_Create,
56     HAL_DirectDraw_Initialize
57 };
58
59 static DDHAL_CALLBACKS dd_cbs;
60 static DDRAWI_DIRECTDRAW_GBL dd_gbl;
61
62 static D3DHAL_GLOBALDRIVERDATA d3d_hal_data;
63 static D3DHAL_D3DEXTENDEDCAPS d3d_hal_extcaps;
64 static D3DHAL_CALLBACKS d3d_hal_cbs1;
65 static D3DHAL_CALLBACKS2 d3d_hal_cbs2;
66
67 /* in real windoze, these entry points are 16-bit, but we can work in 32-bit */
68 static BOOL WINAPI set_hal_info(LPDDHALINFO lpDDHalInfo, BOOL reset)
69 {
70     dd_cbs.HALDD        = *lpDDHalInfo->lpDDCallbacks;
71     dd_cbs.HALDDSurface = *lpDDHalInfo->lpDDSurfaceCallbacks;
72     dd_cbs.HALDDPalette = *lpDDHalInfo->lpDDPaletteCallbacks;
73     if (lpDDHalInfo->lpDDExeBufCallbacks)
74         dd_cbs.HALDDExeBuf      = *lpDDHalInfo->lpDDExeBufCallbacks;
75
76     dd_gbl.lpDDCBtmp = &dd_cbs;
77
78     dd_gbl.ddCaps                = lpDDHalInfo->ddCaps;
79     dd_gbl.dwMonitorFrequency    = lpDDHalInfo->dwMonitorFrequency;
80     dd_gbl.vmiData               = lpDDHalInfo->vmiData;
81     dd_gbl.dwModeIndex           = lpDDHalInfo->dwModeIndex;
82     /* FIXME: dwNumFourCC */
83     dd_gbl.lpdwFourCC            = lpDDHalInfo->lpdwFourCC;
84     dd_gbl.dwNumModes            = lpDDHalInfo->dwNumModes;
85     dd_gbl.lpModeInfo            = lpDDHalInfo->lpModeInfo;
86     /* FIXME: dwFlags */
87     dd_gbl.dwPDevice             = (DWORD)lpDDHalInfo->lpPDevice;
88     dd_gbl.hInstance             = lpDDHalInfo->hInstance;
89     /* DirectX 2 */
90     if (lpDDHalInfo->lpD3DGlobalDriverData)
91         memcpy(&d3d_hal_data, (LPVOID)lpDDHalInfo->lpD3DGlobalDriverData, sizeof(D3DDEVICEDESC_V1));
92     else
93         memset(&d3d_hal_data, 0, sizeof(D3DDEVICEDESC_V1));
94     dd_gbl.lpD3DGlobalDriverData = (ULONG_PTR)&d3d_hal_data;
95
96     if (lpDDHalInfo->lpD3DHALCallbacks)
97         memcpy(&d3d_hal_cbs1, (LPVOID)lpDDHalInfo->lpD3DHALCallbacks, sizeof(D3DHAL_CALLBACKS));
98     else
99         memset(&d3d_hal_cbs1, 0, sizeof(D3DDEVICEDESC_V1));
100     dd_gbl.lpD3DHALCallbacks     = (ULONG_PTR)&d3d_hal_cbs1;
101
102     if (lpDDHalInfo->dwFlags & DDHALINFO_GETDRIVERINFOSET) {
103         DDHAL_GETDRIVERINFODATA data;
104         data.dwSize = sizeof(DDHAL_GETDRIVERINFODATA);
105         data.dwFlags = 0; /* ? */
106         data.dwContext = hal_driverdata.dwContext; /* ? */
107
108         data.guidInfo = GUID_D3DExtendedCaps;
109         data.dwExpectedSize = sizeof(D3DHAL_D3DEXTENDEDCAPS);
110         data.lpvData = &d3d_hal_extcaps;
111         data.dwActualSize = 0;
112         data.ddRVal = 0;
113         lpDDHalInfo->GetDriverInfo(&data);
114         d3d_hal_extcaps.dwSize = data.dwActualSize;
115         dd_gbl.lpD3DExtendedCaps = (ULONG_PTR)&d3d_hal_extcaps;
116
117         data.guidInfo = GUID_D3DCallbacks2;
118         data.dwExpectedSize = sizeof(D3DHAL_CALLBACKS2);
119         data.lpvData = &d3d_hal_cbs2;
120         data.dwActualSize = 0;
121         data.ddRVal = 0;
122         lpDDHalInfo->GetDriverInfo(&data);
123         d3d_hal_cbs2.dwSize = data.dwActualSize;
124         dd_gbl.lpD3DHALCallbacks2 = (ULONG_PTR)&d3d_hal_cbs2;
125     }
126
127 #ifdef HAVE_OPENGL
128     if (d3d_hal_data.hwCaps.dwFlags & D3DDD_WINE_OPENGL_DEVICE) {
129         /*GL_DirectDraw_Init(&dd_gbl);*/
130     }
131 #endif
132
133     return FALSE;
134 }
135
136 static DDHALDDRAWFNS hal_funcs = {
137     sizeof(DDHALDDRAWFNS),
138     set_hal_info,
139     NULL, /* VidMemAlloc */
140     NULL  /* VidMemFree */
141 };
142
143 /* Called from DllInit, which is synchronised so there are no threading
144  * concerns. */
145 static BOOL initialize(void)
146 {
147     DCICMD cmd;
148     INT ncmd = DCICOMMAND;
149     BOOL ret;
150     HDC dc = CreateDCA("DISPLAY", NULL, NULL, NULL);
151     INT ver = Escape(dc, QUERYESCSUPPORT, sizeof(ncmd), (LPVOID)&ncmd, NULL);
152     if (ver != DD_HAL_VERSION) {
153         DeleteDC(dc);
154         TRACE("DirectDraw HAL not available\n");
155         return FALSE;
156     }
157     cmd.dwVersion = DD_VERSION;
158     cmd.dwReserved = 0;
159
160     /* the DDNEWCALLBACKFNS is supposed to give the 16-bit driver entry points
161      * in ddraw16.dll, but since Wine doesn't have or use 16-bit display drivers,
162      * we'll just work in 32-bit, who'll notice... */
163     cmd.dwCommand = DDNEWCALLBACKFNS;
164     cmd.dwParam1 = (DWORD)&hal_funcs;
165     ExtEscape(dc, DCICOMMAND, sizeof(cmd), (LPVOID)&cmd, 0, NULL);
166
167     /* next, exchange version information */
168     cmd.dwCommand = DDVERSIONINFO;
169     cmd.dwParam1 = DD_RUNTIME_VERSION; /* not sure what should *really* go here */
170     ExtEscape(dc, DCICOMMAND, sizeof(cmd), (LPVOID)&cmd, sizeof(hal_version), (LPVOID)&hal_version);
171
172     /* get 32-bit driver data (dll name and entry point) */
173     cmd.dwCommand = DDGET32BITDRIVERNAME;
174     ExtEscape(dc, DCICOMMAND, sizeof(cmd), (LPVOID)&cmd, sizeof(hal_driverdata), (LPVOID)&hal_driverdata);
175     /* we're supposed to load the DLL in hal_driverdata.szName, then GetProcAddress
176      * the hal_driverdata.szEntryPoint, and call it with hal_driverdata.dwContext
177      * as a parameter... but since this is only more remains from the 16-bit world,
178      * we'll ignore it */
179
180     /* finally, initialize the driver object */
181     cmd.dwCommand = DDCREATEDRIVEROBJECT;
182     ret = ExtEscape(dc, DCICOMMAND, sizeof(cmd), (LPVOID)&cmd, sizeof(hal_instance), (LPVOID)&hal_instance);
183     if (ret) {
184         /* the driver should have called our set_hal_info now */
185         if (!dd_gbl.lpDDCBtmp) ret = FALSE;
186     }
187
188     /* init done */
189     DeleteDC(dc);
190
191     TRACE("%s DirectDraw HAL\n", ret ? "enabling" : "disabling");
192
193     return ret;
194 }
195
196 static void cleanup(void)
197 {
198     DDHAL_DESTROYDRIVERDATA data;
199     data.lpDD = NULL;
200     data.ddRVal = 0;
201     data.DestroyDriver = dd_cbs.HALDD.DestroyDriver;
202     data.DestroyDriver(&data);
203 }
204
205 static DWORD choose_mode(DWORD dwWidth, DWORD dwHeight, DWORD dwBPP,
206                          DWORD dwRefreshRate, DWORD dwFlags)
207 {
208     int best = -1;
209     int i;
210
211     if (!dd_gbl.dwNumModes) return 0;
212
213 /* let's support HALs that cannot switch depths (XVidMode),
214  * these should return dwBPP == 0 for all their resolutions */
215 #define BPP_MATCH(dd, bpp) ((!(dd)) || ((dd) == bpp))
216
217 /* FIXME: we should try to match the refresh rate too */
218
219     /* Choose the smallest mode that is large enough. */
220     for (i=0; i < dd_gbl.dwNumModes; i++)
221     {
222         if (dd_gbl.lpModeInfo[i].dwWidth >= dwWidth &&
223             dd_gbl.lpModeInfo[i].dwHeight >= dwHeight &&
224             BPP_MATCH(dd_gbl.lpModeInfo[i].dwBPP, dwBPP))
225         {
226             if (best == -1) best = i;
227             else
228             {
229                 if (dd_gbl.lpModeInfo[i].dwWidth < dd_gbl.lpModeInfo[best].dwWidth ||
230                     dd_gbl.lpModeInfo[i].dwHeight < dd_gbl.lpModeInfo[best].dwHeight)
231                     best = i;
232             }
233         }
234     }
235
236     if (best == -1)
237     {
238         TRACE("all modes too small\n");
239         /* ok, let's use the largest */
240
241         for (i=0; i < dd_gbl.dwNumModes; i++)
242         {
243             if (BPP_MATCH(dd_gbl.lpModeInfo[i].dwBPP, dwBPP))
244             {
245                 if (best == -1) best = i;
246                 else
247                 {
248                     if (dd_gbl.lpModeInfo[i].dwWidth > dd_gbl.lpModeInfo[best].dwWidth ||
249                         dd_gbl.lpModeInfo[i].dwHeight > dd_gbl.lpModeInfo[best].dwHeight)
250                         best = i;
251                 }
252             }
253         }
254     }
255 #undef BPP_MATCH
256
257     if (best == -1)
258     {
259         ERR("requested color depth (%ld) not available, try reconfiguring X server\n", dwBPP);
260         return dd_gbl.dwModeIndex;
261     }
262
263     TRACE("using mode %d\n", best);
264
265     return best;
266 }
267
268 static HRESULT set_mode(IDirectDrawImpl *This, DWORD dwMode)
269 {
270     HRESULT hr = DD_OK;
271
272     if (dwMode != dd_gbl.dwModeIndex)
273     {
274         DDHAL_SETMODEDATA data;
275         data.lpDD = &dd_gbl;
276         data.dwModeIndex = dwMode;
277         data.ddRVal = 0;
278         data.SetMode = dd_cbs.HALDD.SetMode;
279         data.inexcl = 0;
280         data.useRefreshRate = FALSE;
281         if (data.SetMode)
282             data.SetMode(&data);
283         hr = data.ddRVal;
284         if (SUCCEEDED(hr))
285             dd_gbl.dwModeIndex = dwMode;
286     }
287     return hr;
288 }
289
290 static HRESULT set_exclusive_mode(IDirectDrawImpl *This, DWORD dwEnterExcl)
291 {
292     DDHAL_SETEXCLUSIVEMODEDATA data;
293
294     data.lpDD = &dd_gbl;
295     data.dwEnterExcl = dwEnterExcl;
296     data.dwReserved = 0;
297     data.ddRVal = 0;
298     data.SetExclusiveMode = dd_cbs.HALDD.SetExclusiveMode;
299     if (data.SetExclusiveMode)
300         data.SetExclusiveMode(&data);
301     return data.ddRVal;
302 }
303
304 BOOL DDRAW_HAL_Init(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
305 {
306     if (fdwReason == DLL_PROCESS_ATTACH)
307     {
308         if (initialize())
309             DDRAW_register_driver(&hal_driver);
310     }
311     else if (fdwReason == DLL_PROCESS_DETACH)
312     {
313         cleanup();
314     }
315
316     return TRUE;
317 }
318
319 /* Not called from the vtable. */
320 HRESULT HAL_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex)
321 {
322     HRESULT hr;
323
324     TRACE("(%p)\n", This);
325
326     hr = User_DirectDraw_Construct(This, ex);
327     if (FAILED(hr)) return hr;
328
329     This->local.lpGbl = &dd_gbl;
330
331     This->final_release = HAL_DirectDraw_final_release;
332     This->set_exclusive_mode = set_exclusive_mode;
333
334     This->create_palette = HAL_DirectDrawPalette_Create;
335
336     This->create_primary    = HAL_DirectDraw_create_primary;
337     This->create_backbuffer = HAL_DirectDraw_create_backbuffer;
338     This->create_texture    = HAL_DirectDraw_create_texture;
339
340     ICOM_INIT_INTERFACE(This, IDirectDraw7, HAL_DirectDraw_VTable);
341
342     /* merge HAL caps */
343     This->caps.dwCaps |= dd_gbl.ddCaps.dwCaps;
344     This->caps.dwCaps2 |= dd_gbl.ddCaps.dwCaps2;
345     This->caps.dwCKeyCaps |= dd_gbl.ddCaps.dwCKeyCaps;
346     This->caps.dwFXCaps |= dd_gbl.ddCaps.dwFXCaps;
347     This->caps.dwPalCaps |= dd_gbl.ddCaps.dwPalCaps;
348     /* FIXME: merge more caps */
349     This->caps.ddsCaps.dwCaps |= dd_gbl.ddCaps.ddsCaps.dwCaps;
350     This->caps.ddsCaps.dwCaps2 |= dd_gbl.ddsCapsMore.dwCaps2;
351     This->caps.ddsCaps.dwCaps3 |= dd_gbl.ddsCapsMore.dwCaps3;
352     This->caps.ddsCaps.dwCaps4 |= dd_gbl.ddsCapsMore.dwCaps4;
353     This->caps.ddsOldCaps.dwCaps = This->caps.ddsCaps.dwCaps;
354
355     return S_OK;
356 }
357
358 /* This function is called from DirectDrawCreate(Ex) on the most-derived
359  * class to start construction.
360  * Not called from the vtable. */
361 HRESULT HAL_DirectDraw_Create(const GUID* pGUID, LPDIRECTDRAW7* pIface,
362                               IUnknown* pUnkOuter, BOOL ex)
363 {
364     HRESULT hr;
365     IDirectDrawImpl* This;
366
367     TRACE("\n");
368
369     assert(pUnkOuter == NULL);
370
371     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
372                      sizeof(IDirectDrawImpl)
373                      + sizeof(HAL_DirectDrawImpl));
374     if (This == NULL) return E_OUTOFMEMORY;
375
376     /* Note that this relation does *not* hold true if the DD object was
377      * CoCreateInstanced then Initialized. */
378     This->private = (HAL_DirectDrawImpl *)(This+1);
379
380     hr = HAL_DirectDraw_Construct(This, ex);
381     if (FAILED(hr))
382         HeapFree(GetProcessHeap(), 0, This);
383     else
384         *pIface = ICOM_INTERFACE(This, IDirectDraw7);
385
386     return hr;
387 }
388
389 /* This function is called from Uninit_DirectDraw_Initialize on the
390  * most-derived-class to start initialization.
391  * Not called from the vtable. */
392 HRESULT HAL_DirectDraw_Initialize(IDirectDrawImpl *This, const GUID* guid)
393 {
394     HRESULT hr;
395
396     TRACE("\n");
397
398     This->private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
399                               sizeof(HAL_DirectDrawImpl));
400     if (This->private == NULL) return E_OUTOFMEMORY;
401
402     hr = HAL_DirectDraw_Construct(This, TRUE); /* XXX ex? */
403     if (FAILED(hr))
404     {
405         HeapFree(GetProcessHeap(), 0, This->private);
406         return hr;
407     }
408
409     return DD_OK;
410 }
411
412 /* Called from an internal function pointer. */
413 void HAL_DirectDraw_final_release(IDirectDrawImpl *This)
414 {
415     if (dd_gbl.dwFlags & DDRAWI_MODECHANGED) set_mode(This, dd_gbl.dwModeIndexOrig);
416     User_DirectDraw_final_release(This);
417 }
418
419 HRESULT HAL_DirectDraw_create_primary(IDirectDrawImpl* This,
420                                       const DDSURFACEDESC2* pDDSD,
421                                       LPDIRECTDRAWSURFACE7* ppSurf,
422                                       IUnknown* pUnkOuter)
423 {
424     if (This->cooperative_level & DDSCL_EXCLUSIVE)
425         return HAL_DirectDrawSurface_Create(This, pDDSD, ppSurf, pUnkOuter);
426     else
427         return User_DirectDrawSurface_Create(This, pDDSD, ppSurf, pUnkOuter);
428 }
429
430 HRESULT HAL_DirectDraw_create_backbuffer(IDirectDrawImpl* This,
431                                          const DDSURFACEDESC2* pDDSD,
432                                          LPDIRECTDRAWSURFACE7* ppSurf,
433                                          IUnknown* pUnkOuter,
434                                          IDirectDrawSurfaceImpl* primary)
435 {
436     if (This->cooperative_level & DDSCL_EXCLUSIVE)
437         return HAL_DirectDrawSurface_Create(This, pDDSD, ppSurf, pUnkOuter);
438     else
439         return User_DirectDrawSurface_Create(This, pDDSD, ppSurf, pUnkOuter);
440 }
441
442 HRESULT HAL_DirectDraw_create_texture(IDirectDrawImpl* This,
443                                       const DDSURFACEDESC2* pDDSD,
444                                       LPDIRECTDRAWSURFACE7* ppSurf,
445                                       LPUNKNOWN pOuter,
446                                       DWORD dwMipMapLevel)
447 {
448     return HAL_DirectDrawSurface_Create(This, pDDSD, ppSurf, pOuter);
449 }
450
451 HRESULT WINAPI
452 HAL_DirectDraw_GetDeviceIdentifier(LPDIRECTDRAW7 iface,
453                                    LPDDDEVICEIDENTIFIER2 pDDDI,
454                                    DWORD dwFlags)
455 {
456     *pDDDI = hal_device;
457     return DD_OK;
458 }
459
460 HRESULT WINAPI
461 HAL_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface)
462 {
463     ICOM_THIS(IDirectDrawImpl, iface);
464     HRESULT hr;
465
466     TRACE("(%p)\n", iface);
467
468     if (!(dd_gbl.dwFlags & DDRAWI_MODECHANGED)) return DD_OK;
469
470     hr = Main_DirectDraw_RestoreDisplayMode(iface);
471     if (SUCCEEDED(hr)) {
472         hr = set_mode(This, dd_gbl.dwModeIndexOrig);
473         if (SUCCEEDED(hr)) dd_gbl.dwFlags &= ~DDRAWI_MODECHANGED;
474     }
475
476     return hr;
477 }
478
479 HRESULT WINAPI
480 HAL_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth,
481                               DWORD dwHeight, DWORD dwBPP,
482                               DWORD dwRefreshRate, DWORD dwFlags)
483 {
484     ICOM_THIS(IDirectDrawImpl, iface);
485
486     HRESULT hr;
487
488     TRACE("(%p)->(%ldx%ldx%ld,%ld Hz,%08lx)\n",This,dwWidth,dwHeight,dwBPP,dwRefreshRate,dwFlags);
489     hr = User_DirectDraw_SetDisplayMode(iface, dwWidth, dwHeight, dwBPP,
490                                         dwRefreshRate, dwFlags);      
491
492     if (SUCCEEDED(hr)) {
493         if (!(dd_gbl.dwFlags & DDRAWI_MODECHANGED)) dd_gbl.dwModeIndexOrig = dd_gbl.dwModeIndex;
494         hr = set_mode(This, choose_mode(dwWidth, dwHeight, dwBPP, dwRefreshRate, dwFlags));
495         if (SUCCEEDED(hr)) dd_gbl.dwFlags |= DDRAWI_MODECHANGED;
496     }
497
498     return hr;
499 }
500
501 static ICOM_VTABLE(IDirectDraw7) HAL_DirectDraw_VTable =
502 {
503     Main_DirectDraw_QueryInterface,
504     Main_DirectDraw_AddRef,
505     Main_DirectDraw_Release,
506     Main_DirectDraw_Compact,
507     Main_DirectDraw_CreateClipper,
508     Main_DirectDraw_CreatePalette,
509     Main_DirectDraw_CreateSurface,
510     Main_DirectDraw_DuplicateSurface,
511     User_DirectDraw_EnumDisplayModes,
512     Main_DirectDraw_EnumSurfaces,
513     Main_DirectDraw_FlipToGDISurface,
514     Main_DirectDraw_GetCaps,
515     Main_DirectDraw_GetDisplayMode,
516     Main_DirectDraw_GetFourCCCodes,
517     Main_DirectDraw_GetGDISurface,
518     Main_DirectDraw_GetMonitorFrequency,
519     Main_DirectDraw_GetScanLine,
520     Main_DirectDraw_GetVerticalBlankStatus,
521     Main_DirectDraw_Initialize,
522     HAL_DirectDraw_RestoreDisplayMode,
523     Main_DirectDraw_SetCooperativeLevel,
524     HAL_DirectDraw_SetDisplayMode,
525     Main_DirectDraw_WaitForVerticalBlank,
526     Main_DirectDraw_GetAvailableVidMem,
527     Main_DirectDraw_GetSurfaceFromDC,
528     Main_DirectDraw_RestoreAllSurfaces,
529     Main_DirectDraw_TestCooperativeLevel,
530     HAL_DirectDraw_GetDeviceIdentifier,
531     Main_DirectDraw_StartModeTest,
532     Main_DirectDraw_EvaluateMode
533 };