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