1 /* DirectDraw driver for User-based primary surfaces
3 * Copyright 2000-2001 TransGaming Technologies Inc.
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.
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.
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
21 #include "wine/debug.h"
27 #include "ddraw_private.h"
28 #include "ddraw/main.h"
29 #include "ddraw/user.h"
30 #include "dclipper/main.h"
31 #include "dpalette/main.h"
32 #include "dsurface/main.h"
33 #include "dsurface/dib.h"
34 #include "dsurface/user.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
38 static ICOM_VTABLE(IDirectDraw7) User_DirectDraw_VTable;
40 static const DDDEVICEIDENTIFIER2 user_device =
44 { { 0x00010001, 0x00010001 } },
46 /* fe38440c-8969-4283-bc73-749e7bc3c2eb */
47 {0xfe38440c,0x8969,0x428e, {0x73,0xbc,0x74,0x9e,0x7b,0xc3,0xc2,0xeb}},
51 static const DDPIXELFORMAT pixelformats[] =
54 { sizeof(DDPIXELFORMAT), DDPF_RGB|DDPF_PALETTEINDEXED8, 0, { 8 } },
56 { sizeof(DDPIXELFORMAT), DDPF_RGB, 0, { 16 }, { 0x7C00 }, { 0x3E0 },
59 { sizeof(DDPIXELFORMAT), DDPF_RGB, 0, { 16 }, { 0xF800 }, { 0x7E0 },
62 { sizeof(DDPIXELFORMAT), DDPF_RGB, 0, { 24 }, { 0xFF0000 },
63 { 0x00FF00 }, { 0x0000FF } },
65 { sizeof(DDPIXELFORMAT), DDPF_RGB, 0, { 32 }, { 0xFF0000 },
66 { 0x00FF00 }, { 0x0000FF } }
69 HRESULT User_DirectDraw_Create(const GUID* pGUID, LPDIRECTDRAW7* pIface,
70 IUnknown* pUnkOuter, BOOL ex);
71 HRESULT User_DirectDraw_Initialize(IDirectDrawImpl*, const GUID*);
73 static const ddraw_driver user_driver =
77 User_DirectDraw_Create,
78 User_DirectDraw_Initialize
81 BOOL DDRAW_User_Init(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
83 if (fdwReason == DLL_PROCESS_ATTACH)
84 DDRAW_register_driver(&user_driver);
89 /* If you change this function, you probably want to change the enumeration
90 * code in EnumDisplayModes. */
92 IsValidDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwBPP,
93 DWORD dwRefreshRate, DWORD dwFlags)
95 if (dwWidth > GetSystemMetrics(SM_CXSCREEN)
96 || dwHeight > GetSystemMetrics(SM_CYSCREEN))
115 static const DDPIXELFORMAT* pixelformat_for_depth(DWORD depth)
119 case 8: return pixelformats + 0;
120 case 15: return pixelformats + 1;
121 case 16: return pixelformats + 2;
122 case 24: return pixelformats + 3;
123 case 32: return pixelformats + 4;
124 default: return NULL;
128 /* Not called from the vtable. */
129 HRESULT User_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex)
135 TRACE("(%p,%d)\n",This,ex);
137 hr = Main_DirectDraw_Construct(This, ex);
138 if (FAILED(hr)) return hr;
140 This->final_release = User_DirectDraw_final_release;
142 This->create_primary = User_DirectDraw_create_primary;
143 This->create_backbuffer = User_DirectDraw_create_backbuffer;
145 hDC = CreateDCA("DISPLAY", NULL, NULL, NULL);
146 depth = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
149 This->width = GetSystemMetrics(SM_CXSCREEN);
150 This->height = GetSystemMetrics(SM_CYSCREEN);
151 This->pitch = DDRAW_width_bpp_to_pitch(This->width, depth);
152 This->pixelformat = *pixelformat_for_depth(depth);
154 This->orig_width = This->width;
155 This->orig_height = This->height;
156 This->orig_pitch = This->pitch;
157 This->orig_pixelformat = This->pixelformat;
159 ICOM_INIT_INTERFACE(This, IDirectDraw7, User_DirectDraw_VTable);
162 #define BLIT_CAPS (DDCAPS_BLT | DDCAPS_BLTCOLORFILL | DDCAPS_BLTDEPTHFILL \
163 | DDCAPS_BLTSTRETCH | DDCAPS_CANBLTSYSMEM | DDCAPS_CANCLIP \
164 | DDCAPS_CANCLIPSTRETCHED | DDCAPS_COLORKEY \
165 | DDCAPS_COLORKEYHWASSIST)
166 #define CKEY_CAPS (DDCKEYCAPS_DESTBLT | DDCKEYCAPS_SRCBLT)
167 #define FX_CAPS (DDFXCAPS_BLTALPHA | DDFXCAPS_BLTMIRRORLEFTRIGHT \
168 | DDFXCAPS_BLTMIRRORUPDOWN | DDFXCAPS_BLTROTATION90 \
169 | DDFXCAPS_BLTSHRINKX | DDFXCAPS_BLTSHRINKXN \
170 | DDFXCAPS_BLTSHRINKY | DDFXCAPS_BLTSHRINKXN \
171 | DDFXCAPS_BLTSTRETCHX | DDFXCAPS_BLTSTRETCHXN \
172 | DDFXCAPS_BLTSTRETCHY | DDFXCAPS_BLTSTRETCHYN)
173 This->caps.dwCaps |= DDCAPS_GDI | DDCAPS_PALETTE | BLIT_CAPS;
174 This->caps.dwCaps2 |= DDCAPS2_CERTIFIED | DDCAPS2_NOPAGELOCKREQUIRED |
175 DDCAPS2_PRIMARYGAMMA | DDCAPS2_WIDESURFACES;
176 This->caps.dwCKeyCaps |= CKEY_CAPS;
177 This->caps.dwFXCaps |= FX_CAPS;
178 This->caps.dwPalCaps |= DDPCAPS_8BIT | DDPCAPS_PRIMARYSURFACE;
179 This->caps.dwVidMemTotal = 16*1024*1024;
180 This->caps.dwVidMemFree = 16*1024*1024;
181 This->caps.dwSVBCaps |= BLIT_CAPS;
182 This->caps.dwSVBCKeyCaps |= CKEY_CAPS;
183 This->caps.dwSVBFXCaps |= FX_CAPS;
184 This->caps.dwVSBCaps |= BLIT_CAPS;
185 This->caps.dwVSBCKeyCaps |= CKEY_CAPS;
186 This->caps.dwVSBFXCaps |= FX_CAPS;
187 This->caps.dwSSBCaps |= BLIT_CAPS;
188 This->caps.dwSSBCKeyCaps |= CKEY_CAPS;
189 This->caps.dwSSBFXCaps |= FX_CAPS;
190 This->caps.ddsCaps.dwCaps |= DDSCAPS_ALPHA | DDSCAPS_BACKBUFFER |
191 DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER |
192 DDSCAPS_OFFSCREENPLAIN | DDSCAPS_PALETTE |
193 DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY |
194 DDSCAPS_VIDEOMEMORY | DDSCAPS_VISIBLE;
195 This->caps.ddsOldCaps.dwCaps = This->caps.ddsCaps.dwCaps;
203 /* This function is called from DirectDrawCreate(Ex) on the most-derived
204 * class to start construction.
205 * Not called from the vtable. */
206 HRESULT User_DirectDraw_Create(const GUID* pGUID, LPDIRECTDRAW7* pIface,
207 IUnknown* pUnkOuter, BOOL ex)
210 IDirectDrawImpl* This;
212 assert(pUnkOuter == NULL);
214 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
215 sizeof(IDirectDrawImpl) + sizeof(User_DirectDrawImpl));
216 if (This == NULL) return E_OUTOFMEMORY;
218 /* Note that this relation does *not* hold true if the DD object was
219 * CoCreateInstanced then Initialized. */
220 This->private = (User_DirectDrawImpl *)(This+1);
222 hr = User_DirectDraw_Construct(This, ex);
224 HeapFree(GetProcessHeap(), 0, This);
226 *pIface = ICOM_INTERFACE(This, IDirectDraw7);
231 /* This function is called from Uninit_DirectDraw_Initialize on the
232 * most-derived-class to start initialization.
233 * Not called from the vtable. */
234 HRESULT User_DirectDraw_Initialize(IDirectDrawImpl *This, const GUID* guid)
237 This->private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
238 sizeof(User_DirectDrawImpl));
239 if (This->private == NULL) return E_OUTOFMEMORY;
241 hr = User_DirectDraw_Construct(This, TRUE); /* XXX ex? */
244 HeapFree(GetProcessHeap(), 0, This->private);
251 /* Called from an internal function pointer. */
252 void User_DirectDraw_final_release(IDirectDrawImpl *This)
254 Main_DirectDraw_final_release(This);
257 /* Compact: generic */
258 /* CreateClipper: generic */
259 /* CreatePalette: generic (with callback) */
260 /* CreateSurface: generic (with callbacks) */
263 User_DirectDraw_create_primary(IDirectDrawImpl* This,
264 const DDSURFACEDESC2* pDDSD,
265 LPDIRECTDRAWSURFACE7* ppSurf,
268 return User_DirectDrawSurface_Create(This, pDDSD, ppSurf, pUnkOuter);
272 User_DirectDraw_create_backbuffer(IDirectDrawImpl* This,
273 const DDSURFACEDESC2* pDDSD,
274 LPDIRECTDRAWSURFACE7* ppSurf,
276 IDirectDrawSurfaceImpl* primary)
278 return User_DirectDrawSurface_Create(This, pDDSD, ppSurf, pUnkOuter);
281 /* DuplicateSurface: generic */
283 /* Derived from Xlib_IDirectDraw2Impl_EnumDisplayModes.
284 * Very fake: just enumerate some arbitrary modes.
286 * The screen sizes are plausible-looking screen sizes and will be limited
287 * by (virtual) screen size.
289 * The depths are whatever DIBsections support on the client side.
290 * Should they be limited by screen depth?
293 User_DirectDraw_EnumDisplayModes(LPDIRECTDRAW7 iface, DWORD dwFlags,
294 LPDDSURFACEDESC2 pDDSD, LPVOID context,
295 LPDDENUMMODESCALLBACK2 callback)
303 static const struct mode modes[] =
305 { 512, 384 }, { 640, 400 }, { 640, 480 }, { 800, 600 }, { 1024, 768 },
306 { 1152, 864 }, { 1280, 1024 }, { 1600, 1200 }
309 static const int num_modes = sizeof(modes)/sizeof(modes[0]);
311 static const int num_pixelformats
312 = sizeof(pixelformats)/sizeof(pixelformats[0]);
314 DDSURFACEDESC2 callback_sd;
316 int max_width, max_height;
319 TRACE("(%p)->(0x%08lx,%p,%p,%p)\n",iface,dwFlags,pDDSD,context,callback);
321 /* Unfortunately this is the virtual screen size, not physical. */
322 max_width = GetSystemMetrics(SM_CXSCREEN);
323 max_height = GetSystemMetrics(SM_CYSCREEN);
325 ZeroMemory(&callback_sd, sizeof(callback_sd));
326 callback_sd.dwSize = sizeof(callback_sd);
328 callback_sd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_CAPS
331 if (dwFlags & DDEDM_REFRESHRATES)
332 callback_sd.dwFlags |= DDSD_REFRESHRATE;
334 callback_sd.u2.dwRefreshRate = 60.0;
336 for (i = 0; i < num_modes; i++)
338 if (modes[i].width > max_width || modes[i].height > max_height)
341 callback_sd.dwHeight = modes[i].height;
342 callback_sd.dwWidth = modes[i].width;
344 TRACE("- mode: %ldx%ld\n", callback_sd.dwWidth, callback_sd.dwHeight);
345 for (j = 0; j < num_pixelformats; j++)
347 callback_sd.u1.lPitch
348 = DDRAW_width_bpp_to_pitch(modes[i].width,
349 pixelformats[j].u1.dwRGBBitCount);
351 callback_sd.u4.ddpfPixelFormat = pixelformats[j];
353 callback_sd.ddsCaps.dwCaps = 0;
354 if (pixelformats[j].dwFlags & DDPF_PALETTEINDEXED8) /* ick */
355 callback_sd.ddsCaps.dwCaps |= DDSCAPS_PALETTE;
357 assert(IsValidDisplayMode(callback_sd.dwWidth,
358 callback_sd.dwHeight,
359 callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount,
362 TRACE(" - %2ld bpp, R=%08lx G=%08lx B=%08lx\n",
363 callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount,
364 callback_sd.u4.ddpfPixelFormat.u2.dwRBitMask,
365 callback_sd.u4.ddpfPixelFormat.u3.dwGBitMask,
366 callback_sd.u4.ddpfPixelFormat.u4.dwBBitMask);
367 if (callback(&callback_sd, context) == DDENUMRET_CANCEL)
375 /* EnumSurfaces: generic */
376 /* FlipToGDISurface: ??? */
380 User_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps,
383 /* Based on my guesses for what is appropriate with some clues from the
384 * NVidia driver. Not everything is actually implemented yet.
385 * NV has but we don't: Overlays, Video Ports, DDCAPS_READSCANLINE,
386 * DDCAPS2_CERTIFIED (heh), DDSCAPS2_NONLOCALVIDMEM, DDSCAPS2_COPYFOURCC.
387 * It actually has no FX alpha caps.
388 * Oddly, it doesn't list DDPCAPS_PRIMARYSURFACE.
389 * And the HEL caps make little sense.
391 #define BLIT_CAPS (DDCAPS_BLT | DDCAPS_BLTCOLORFILL | DDCAPS_BLTDEPTHFILL \
392 | DDCAPS_BLTSTRETCH | DDCAPS_CANBLTSYSMEM | DDCAPS_CANCLIP \
393 | DDCAPS_CANCLIPSTRETCHED | DDCAPS_COLORKEY \
394 | DDCAPS_COLORKEYHWASSIST)
396 #define CKEY_CAPS (DDCKEYCAPS_DESTBLT | DDCKEYCAPS_SRCBLT)
398 #define FX_CAPS (DDFXCAPS_BLTALPHA | DDFXCAPS_BLTMIRRORLEFTRIGHT \
399 | DDFXCAPS_BLTMIRRORUPDOWN | DDFXCAPS_BLTROTATION90 \
400 | DDFXCAPS_BLTSHRINKX | DDFXCAPS_BLTSHRINKXN \
401 | DDFXCAPS_BLTSHRINKY | DDFXCAPS_BLTSHRINKXN \
402 | DDFXCAPS_BLTSTRETCHX | DDFXCAPS_BLTSTRETCHXN \
403 | DDFXCAPS_BLTSTRETCHY | DDFXCAPS_BLTSTRETCHYN)
406 #define ROPS { SRCCOPY, SRCPAINT, SRCAND, SRCINVERT, SRCERASE, NOTSRCCOPY, \
407 NOTSRCERASE, MERGEPAINT, BLACKNESS, WHITENESS, }
412 static const DDCAPS caps =
414 DDCAPS_3D | DDCAPS_GDI | DDCAPS_PALETTE | BLIT_CAPS,
415 DDCAPS2_CANMANAGETEXTURE | DDCAPS2_CANRENDERWINDOWED | DDCAPS2_CERTIFIED
416 | DDCAPS2_NOPAGELOCKREQUIRED | DDCAPS2_PRIMARYGAMMA
417 | DDCAPS2_WIDESURFACES,
420 0, /* dwFXAlphaCaps */
421 DDPCAPS_8BIT | DDPCAPS_PRIMARYSURFACE,
423 0, /* ? dwAlphaBitConstBitDepths */
424 0, /* ? dwAlphaBitPixelPitDepths */
425 0, /* ? dwAlphaBltSurfaceBitDepths */
426 0, /* ? dwAlphaOverlayConstBitDepths */
427 0, /* ? dwAlphaOverlayPixelBitDepths */
428 0, /* ? dwAlphaOverlaySurfaceBitDepths */
429 DDBD_16, /* ? dwZBufferBitDepths */
430 16*1024*1024, /* dwVidMemTotal */
431 16*1024*1024, /* dwVidMemFree */
432 0, /* dwMaxVisibleOverlays */
433 0, /* dwCurrVisibleOverlays */
434 0, /* dwNumFourCCCodes */
435 0, /* dwAlignBoundarySrc */
436 0, /* dwAlignSizeSrc */
437 0, /* dwAlignBoundaryDest */
438 0, /* dwAlignSizeDest */
439 0, /* dwAlignStrideAlign */
440 ROPS, /* XXX dwRops[DD_ROP_SPACE] */
441 { 0, }, /* XXX ddsOldCaps */
442 1000, /* dwMinOverlayStretch */
443 1000, /* dwMaxOverlayStretch */
444 1000, /* dwMinLiveVideoStretch */
445 1000, /* dwMaxLiveVideoStretch */
446 1000, /* dwMinHwCodecStretch */
447 1000, /* dwMaxHwCodecStretch */
448 0, 0, 0, /* dwReserved1, 2, 3 */
449 BLIT_CAPS, /* dwSVBCaps */
450 CKEY_CAPS, /* dwSVBCKeyCaps */
451 FX_CAPS, /* dwSVBFXCaps */
452 ROPS, /* dwSVBRops */
453 BLIT_CAPS, /* dwVSBCaps */
454 CKEY_CAPS, /* dwVSBCKeyCaps */
455 FX_CAPS, /* dwVSBFXCaps */
456 ROPS, /* dwVSBRops */
457 BLIT_CAPS, /* dwSSBCaps */
458 CKEY_CAPS, /* dwSSBCKeyCaps */
459 FX_CAPS, /* dwSSBFXCaps */
460 ROPS, /* dwSSBRops */
461 0, /* dwMaxVideoPorts */
462 0, /* dwCurrVideoPorts */
463 0, /* ? dwSVBCaps2 */
464 BLIT_CAPS, /* ? dwNLVBCaps */
465 0, /* ? dwNLVBCaps2 */
466 CKEY_CAPS, /* dwNLVBCKeyCaps */
467 FX_CAPS, /* dwNLVBFXCaps */
468 ROPS, /* dwNLVBRops */
470 DDSCAPS_3DDEVICE | DDSCAPS_ALPHA | DDSCAPS_BACKBUFFER | DDSCAPS_FLIP
471 | DDSCAPS_FRONTBUFFER | DDSCAPS_MIPMAP | DDSCAPS_OFFSCREENPLAIN
472 | DDSCAPS_PALETTE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY
473 | DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_VISIBLE
486 ICOM_THIS(IDirectDrawImpl, iface);
488 TRACE("(%p)->(%p,%p)\n",This,pDriverCaps,pHELCaps);
490 if (pDriverCaps != NULL)
491 DD_STRUCT_COPY_BYSIZE(pDriverCaps,&caps);
493 if (pHELCaps != NULL)
494 DD_STRUCT_COPY_BYSIZE(pHELCaps,&caps);
501 User_DirectDraw_GetDeviceIdentifier(LPDIRECTDRAW7 iface,
502 LPDDDEVICEIDENTIFIER2 pDDDI,
505 TRACE("(%p)->(%p,%08lx)\n",iface,pDDDI,dwFlags);
506 *pDDDI = user_device;
510 /* GetDisplayMode: generic */
511 /* GetFourCCCodes: generic */
512 /* GetGDISurface: ??? */
513 /* GetMonitorFrequency: generic */
514 /* GetScanLine: generic */
515 /* GetSurfaceFromDC: generic */
516 /* GetVerticalBlankStatus: generic */
517 /* Initialize: generic */
518 /* RestoreAllSurfaces: generic */
519 /* RestoreDisplayMode: generic */
520 /* SetCooperativeLevel: ??? */
523 User_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth,
524 DWORD dwHeight, DWORD dwBPP,
525 DWORD dwRefreshRate, DWORD dwFlags)
527 ICOM_THIS(IDirectDrawImpl, iface);
529 const DDPIXELFORMAT* pixelformat;
532 TRACE("(%p)->(%ldx%ldx%ld,%ld Hz,%08lx)\n",This,dwWidth,dwHeight,dwBPP,dwRefreshRate,dwFlags);
533 if (!IsValidDisplayMode(dwWidth, dwHeight, dwBPP, dwRefreshRate, dwFlags))
534 return DDERR_INVALIDMODE;
536 pixelformat = pixelformat_for_depth(dwBPP);
537 if (pixelformat == NULL)
540 return DDERR_GENERIC;
543 pitch = DDRAW_width_bpp_to_pitch(dwWidth, dwBPP);
545 return Main_DirectDraw_SetDisplayMode(iface, dwWidth, dwHeight, pitch,
546 dwRefreshRate, dwFlags, pixelformat);
549 /* StartModeTest: ??? */
550 /* TestCooperativeLevel: generic? */
551 /* WaitForVerticalBlank: ??? */
553 static ICOM_VTABLE(IDirectDraw7) User_DirectDraw_VTable =
555 Main_DirectDraw_QueryInterface,
556 Main_DirectDraw_AddRef,
557 Main_DirectDraw_Release,
558 Main_DirectDraw_Compact,
559 Main_DirectDraw_CreateClipper,
560 Main_DirectDraw_CreatePalette,
561 Main_DirectDraw_CreateSurface,
562 Main_DirectDraw_DuplicateSurface,
563 User_DirectDraw_EnumDisplayModes,
564 Main_DirectDraw_EnumSurfaces,
565 Main_DirectDraw_FlipToGDISurface,
566 Main_DirectDraw_GetCaps,
567 Main_DirectDraw_GetDisplayMode,
568 Main_DirectDraw_GetFourCCCodes,
569 Main_DirectDraw_GetGDISurface,
570 Main_DirectDraw_GetMonitorFrequency,
571 Main_DirectDraw_GetScanLine,
572 Main_DirectDraw_GetVerticalBlankStatus,
573 Main_DirectDraw_Initialize,
574 Main_DirectDraw_RestoreDisplayMode,
575 Main_DirectDraw_SetCooperativeLevel,
576 User_DirectDraw_SetDisplayMode,
577 Main_DirectDraw_WaitForVerticalBlank,
578 Main_DirectDraw_GetAvailableVidMem,
579 Main_DirectDraw_GetSurfaceFromDC,
580 Main_DirectDraw_RestoreAllSurfaces,
581 Main_DirectDraw_TestCooperativeLevel,
582 User_DirectDraw_GetDeviceIdentifier,
583 Main_DirectDraw_StartModeTest,
584 Main_DirectDraw_EvaluateMode