| /* DirectDraw driver for User-based primary surfaces |
| * |
| * Copyright 2000 TransGaming Technologies Inc. |
| */ |
| |
| #include "config.h" |
| #include "debugtools.h" |
| #include <ddraw.h> |
| |
| #include <assert.h> |
| |
| #include "ddraw_private.h" |
| #include "ddraw/main.h" |
| #include "ddraw/user.h" |
| #include "dclipper/main.h" |
| #include "dpalette/main.h" |
| #include "dsurface/main.h" |
| #include "dsurface/dib.h" |
| #include "dsurface/user.h" |
| |
| DEFAULT_DEBUG_CHANNEL(ddraw); |
| |
| static ICOM_VTABLE(IDirectDraw7) User_DirectDraw_VTable; |
| |
| static const DDDEVICEIDENTIFIER2 user_device = |
| { |
| "User Driver", |
| "WINE DirectDraw on User (and GDI)", |
| { { 0x00010001, 0x00010001 } }, |
| 0, 0, 0, 0, |
| /* fe38440c-8969-4283-bc73-749e7bc3c2eb */ |
| {0xfe38440c,0x8969,0x428e, {0x73,0xbc,0x74,0x9e,0x7b,0xc3,0xc2,0xeb}}, |
| 0 |
| }; |
| |
| static const DDPIXELFORMAT pixelformats[] = |
| { |
| /* 8bpp paletted */ |
| { sizeof(DDPIXELFORMAT), DDPF_RGB|DDPF_PALETTEINDEXED8, 0, { 8 } }, |
| /* 15bpp 5/5/5 */ |
| { sizeof(DDPIXELFORMAT), DDPF_RGB, 0, { 16 }, { 0x7C00 }, { 0x3E0 }, |
| { 0x1F } }, |
| /* 16bpp 5/6/5 */ |
| { sizeof(DDPIXELFORMAT), DDPF_RGB, 0, { 16 }, { 0xF800 }, { 0x7E0 }, |
| { 0x1F } }, |
| /* 24bpp 8/8/8 */ |
| { sizeof(DDPIXELFORMAT), DDPF_RGB, 0, { 24 }, { 0xFF0000 }, |
| { 0x00FF00 }, { 0x0000FF } }, |
| /* 32bpp 8/8/8 */ |
| { sizeof(DDPIXELFORMAT), DDPF_RGB, 0, { 32 }, { 0xFF0000 }, |
| { 0x00FF00 }, { 0x0000FF } } |
| }; |
| |
| HRESULT User_DirectDraw_Create(const GUID* pGUID, LPDIRECTDRAW7* pIface, |
| IUnknown* pUnkOuter, BOOL ex); |
| HRESULT User_DirectDraw_Initialize(IDirectDrawImpl*, const GUID*); |
| |
| static const ddraw_driver user_driver = |
| { |
| &user_device, |
| 10, |
| User_DirectDraw_Create, |
| User_DirectDraw_Initialize |
| }; |
| |
| BOOL DDRAW_User_Init(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) |
| { |
| if (fdwReason == DLL_PROCESS_ATTACH) |
| DDRAW_register_driver(&user_driver); |
| |
| return TRUE; |
| } |
| |
| /* If you change this function, you probably want to change the enumeration |
| * code in EnumDisplayModes. */ |
| static BOOL |
| IsValidDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwBPP, |
| DWORD dwRefreshRate, DWORD dwFlags) |
| { |
| if (dwWidth > GetSystemMetrics(SM_CXSCREEN) |
| || dwHeight > GetSystemMetrics(SM_CYSCREEN)) |
| return FALSE; |
| |
| switch (dwBPP) |
| { |
| case 8: |
| case 15: |
| case 16: |
| case 24: |
| case 32: |
| break; |
| |
| default: |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| static const DDPIXELFORMAT* pixelformat_for_depth(DWORD depth) |
| { |
| switch (depth) |
| { |
| case 8: return pixelformats + 0; |
| case 15: return pixelformats + 1; |
| case 16: return pixelformats + 2; |
| case 24: return pixelformats + 3; |
| case 32: return pixelformats + 4; |
| default: return NULL; |
| } |
| } |
| |
| /* Not called from the vtable. */ |
| HRESULT User_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex) |
| { |
| HRESULT hr; |
| DWORD depth; |
| HDC hDC; |
| |
| TRACE("(%p,%d)\n",This,ex); |
| |
| hr = Main_DirectDraw_Construct(This, ex); |
| if (FAILED(hr)) return hr; |
| |
| This->final_release = User_DirectDraw_final_release; |
| |
| This->create_primary = User_DirectDraw_create_primary; |
| This->create_backbuffer = User_DirectDraw_create_backbuffer; |
| |
| hDC = CreateDCA("DISPLAY", NULL, NULL, NULL); |
| depth = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES); |
| DeleteDC(hDC); |
| |
| This->width = GetSystemMetrics(SM_CXSCREEN); |
| This->height = GetSystemMetrics(SM_CYSCREEN); |
| This->pitch = DDRAW_width_bpp_to_pitch(This->width, depth); |
| This->pixelformat = *pixelformat_for_depth(depth); |
| |
| This->orig_width = This->width; |
| This->orig_height = This->height; |
| This->orig_pitch = This->pitch; |
| This->orig_pixelformat = This->pixelformat; |
| |
| ICOM_INIT_INTERFACE(This, IDirectDraw7, User_DirectDraw_VTable); |
| |
| return S_OK; |
| } |
| |
| /* This function is called from DirectDrawCreate(Ex) on the most-derived |
| * class to start construction. |
| * Not called from the vtable. */ |
| HRESULT User_DirectDraw_Create(const GUID* pGUID, LPDIRECTDRAW7* pIface, |
| IUnknown* pUnkOuter, BOOL ex) |
| { |
| HRESULT hr; |
| IDirectDrawImpl* This; |
| |
| assert(pUnkOuter == NULL); |
| |
| This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, |
| sizeof(IDirectDrawImpl) + sizeof(User_DirectDrawImpl)); |
| if (This == NULL) return E_OUTOFMEMORY; |
| |
| /* Note that this relation does *not* hold true if the DD object was |
| * CoCreateInstanced then Initialized. */ |
| This->private = (User_DirectDrawImpl *)(This+1); |
| |
| hr = User_DirectDraw_Construct(This, ex); |
| if (FAILED(hr)) |
| HeapFree(GetProcessHeap(), 0, This); |
| else |
| *pIface = ICOM_INTERFACE(This, IDirectDraw7); |
| |
| return hr; |
| } |
| |
| /* This function is called from Uninit_DirectDraw_Initialize on the |
| * most-derived-class to start initialization. |
| * Not called from the vtable. */ |
| HRESULT User_DirectDraw_Initialize(IDirectDrawImpl *This, const GUID* guid) |
| { |
| HRESULT hr; |
| This->private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, |
| sizeof(User_DirectDrawImpl)); |
| if (This->private == NULL) return E_OUTOFMEMORY; |
| |
| hr = User_DirectDraw_Construct(This, TRUE); /* XXX ex? */ |
| if (FAILED(hr)) |
| { |
| HeapFree(GetProcessHeap(), 0, This->private); |
| return hr; |
| } |
| |
| return DD_OK; |
| } |
| |
| /* Called from an internal function pointer. */ |
| void User_DirectDraw_final_release(IDirectDrawImpl *This) |
| { |
| Main_DirectDraw_final_release(This); |
| } |
| |
| /* Compact: generic */ |
| /* CreateClipper: generic */ |
| /* CreatePalette: generic (with callback) */ |
| /* CreateSurface: generic (with callbacks) */ |
| |
| HRESULT |
| User_DirectDraw_create_primary(IDirectDrawImpl* This, |
| const DDSURFACEDESC2* pDDSD, |
| LPDIRECTDRAWSURFACE7* ppSurf, |
| IUnknown* pUnkOuter) |
| { |
| return User_DirectDrawSurface_Create(This, pDDSD, ppSurf, pUnkOuter); |
| } |
| |
| HRESULT |
| User_DirectDraw_create_backbuffer(IDirectDrawImpl* This, |
| const DDSURFACEDESC2* pDDSD, |
| LPDIRECTDRAWSURFACE7* ppSurf, |
| IUnknown* pUnkOuter, |
| IDirectDrawSurfaceImpl* primary) |
| { |
| return User_DirectDrawSurface_Create(This, pDDSD, ppSurf, pUnkOuter); |
| } |
| |
| /* DuplicateSurface: generic */ |
| |
| /* Derived from Xlib_IDirectDraw2Impl_EnumDisplayModes. |
| * Very fake: just enumerate some arbitrary modes. |
| * |
| * The screen sizes are plausible-looking screen sizes and will be limited |
| * by (virtual) screen size. |
| * |
| * The depths are whatever DIBsections support on the client side. |
| * Should they be limited by screen depth? |
| */ |
| HRESULT WINAPI |
| User_DirectDraw_EnumDisplayModes(LPDIRECTDRAW7 iface, DWORD dwFlags, |
| LPDDSURFACEDESC2 pDDSD, LPVOID context, |
| LPDDENUMMODESCALLBACK2 callback) |
| { |
| struct mode |
| { |
| int width; |
| int height; |
| }; |
| |
| static const struct mode modes[] = |
| { |
| { 512, 384 }, { 640, 400 }, { 640, 480 }, { 800, 600 }, { 1024, 768 }, |
| { 1152, 864 }, { 1280, 1024 }, { 1600, 1200 } |
| }; |
| |
| static const int num_modes = sizeof(modes)/sizeof(modes[0]); |
| |
| static const int num_pixelformats |
| = sizeof(pixelformats)/sizeof(pixelformats[0]); |
| |
| DDSURFACEDESC2 callback_sd; |
| |
| int max_width, max_height; |
| int i, j; |
| |
| TRACE("(%p)->(0x%08lx,%p,%p,%p)\n",iface,dwFlags,pDDSD,context,callback); |
| |
| /* Unfortunately this is the virtual screen size, not physical. */ |
| max_width = GetSystemMetrics(SM_CXSCREEN); |
| max_height = GetSystemMetrics(SM_CYSCREEN); |
| |
| ZeroMemory(&callback_sd, sizeof(callback_sd)); |
| callback_sd.dwSize = sizeof(callback_sd); |
| |
| callback_sd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_CAPS |
| | DDSD_PITCH; |
| |
| if (dwFlags & DDEDM_REFRESHRATES) |
| callback_sd.dwFlags |= DDSD_REFRESHRATE; |
| |
| callback_sd.u2.dwRefreshRate = 60.0; |
| |
| for (i = 0; i < num_modes; i++) |
| { |
| if (modes[i].width > max_width || modes[i].height > max_height) |
| continue; |
| |
| callback_sd.dwHeight = modes[i].height; |
| callback_sd.dwWidth = modes[i].width; |
| |
| TRACE("- mode: %ldx%ld\n", callback_sd.dwWidth, callback_sd.dwHeight); |
| for (j = 0; j < num_pixelformats; j++) |
| { |
| callback_sd.u1.lPitch |
| = DDRAW_width_bpp_to_pitch(modes[i].width, |
| pixelformats[j].u1.dwRGBBitCount); |
| |
| callback_sd.u4.ddpfPixelFormat = pixelformats[j]; |
| |
| callback_sd.ddsCaps.dwCaps = 0; |
| if (pixelformats[j].dwFlags & DDPF_PALETTEINDEXED8) /* ick */ |
| callback_sd.ddsCaps.dwCaps |= DDSCAPS_PALETTE; |
| |
| assert(IsValidDisplayMode(callback_sd.dwWidth, |
| callback_sd.dwHeight, |
| callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount, |
| 0, 0)); |
| |
| TRACE(" - %2ld bpp, R=%08lx G=%08lx B=%08lx\n", |
| callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount, |
| callback_sd.u4.ddpfPixelFormat.u2.dwRBitMask, |
| callback_sd.u4.ddpfPixelFormat.u3.dwGBitMask, |
| callback_sd.u4.ddpfPixelFormat.u4.dwBBitMask); |
| if (callback(&callback_sd, context) == DDENUMRET_CANCEL) |
| return DD_OK; |
| } |
| } |
| |
| return DD_OK; |
| } |
| |
| /* EnumSurfaces: generic */ |
| /* FlipToGDISurface: ??? */ |
| |
| HRESULT WINAPI |
| User_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps, |
| LPDDCAPS pHELCaps) |
| { |
| /* Based on my guesses for what is appropriate with some clues from the |
| * NVidia driver. Not everything is actually implemented yet. |
| * NV has but we don't: Overlays, Video Ports, DDCAPS_READSCANLINE, |
| * DDCAPS2_CERTIFIED (heh), DDSCAPS2_NONLOCALVIDMEM, DDSCAPS2_COPYFOURCC. |
| * It actually has no FX alpha caps. |
| * Oddly, it doesn't list DDPCAPS_PRIMARYSURFACE. |
| * And the HEL caps make little sense. |
| */ |
| #define BLIT_CAPS (DDCAPS_BLT | DDCAPS_BLTCOLORFILL | DDCAPS_BLTDEPTHFILL \ |
| | DDCAPS_BLTSTRETCH | DDCAPS_CANBLTSYSMEM | DDCAPS_CANCLIP \ |
| | DDCAPS_CANCLIPSTRETCHED | DDCAPS_COLORKEY \ |
| | DDCAPS_COLORKEYHWASSIST) |
| |
| #define CKEY_CAPS (DDCKEYCAPS_DESTBLT | DDCKEYCAPS_SRCBLT) |
| |
| #define FX_CAPS (DDFXCAPS_BLTALPHA | DDFXCAPS_BLTMIRRORLEFTRIGHT \ |
| | DDFXCAPS_BLTMIRRORUPDOWN | DDFXCAPS_BLTROTATION90 \ |
| | DDFXCAPS_BLTSHRINKX | DDFXCAPS_BLTSHRINKXN \ |
| | DDFXCAPS_BLTSHRINKY | DDFXCAPS_BLTSHRINKXN \ |
| | DDFXCAPS_BLTSTRETCHX | DDFXCAPS_BLTSTRETCHXN \ |
| | DDFXCAPS_BLTSTRETCHY | DDFXCAPS_BLTSTRETCHYN) |
| |
| #if 0 |
| #define ROPS { SRCCOPY, SRCPAINT, SRCAND, SRCINVERT, SRCERASE, NOTSRCCOPY, \ |
| NOTSRCERASE, MERGEPAINT, BLACKNESS, WHITENESS, } |
| #else |
| #define ROPS { 0, } |
| #endif |
| |
| static const DDCAPS caps = |
| { sizeof(DDCAPS), |
| DDCAPS_3D | DDCAPS_GDI | DDCAPS_PALETTE | BLIT_CAPS, |
| DDCAPS2_CANMANAGETEXTURE | DDCAPS2_CANRENDERWINDOWED | DDCAPS2_CERTIFIED |
| | DDCAPS2_NOPAGELOCKREQUIRED | DDCAPS2_PRIMARYGAMMA |
| | DDCAPS2_WIDESURFACES, |
| CKEY_CAPS, |
| FX_CAPS, |
| 0, /* dwFXAlphaCaps */ |
| DDPCAPS_8BIT | DDPCAPS_PRIMARYSURFACE, |
| 0, /* dwSVCaps */ |
| 0, /* ? dwAlphaBitConstBitDepths */ |
| 0, /* ? dwAlphaBitPixelPitDepths */ |
| 0, /* ? dwAlphaBltSurfaceBitDepths */ |
| 0, /* ? dwAlphaOverlayConstBitDepths */ |
| 0, /* ? dwAlphaOverlayPixelBitDepths */ |
| 0, /* ? dwAlphaOverlaySurfaceBitDepths */ |
| DDBD_16, /* ? dwZBufferBitDepths */ |
| 16*1024*1024, /* dwVidMemTotal */ |
| 16*1024*1024, /* dwVidMemFree */ |
| 0, /* dwMaxVisibleOverlays */ |
| 0, /* dwCurrVisibleOverlays */ |
| 0, /* dwNumFourCCCodes */ |
| 0, /* dwAlignBoundarySrc */ |
| 0, /* dwAlignSizeSrc */ |
| 0, /* dwAlignBoundaryDest */ |
| 0, /* dwAlignSizeDest */ |
| 0, /* dwAlignStrideAlign */ |
| ROPS, /* XXX dwRops[DD_ROP_SPACE] */ |
| { 0, }, /* XXX ddsOldCaps */ |
| 1000, /* dwMinOverlayStretch */ |
| 1000, /* dwMaxOverlayStretch */ |
| 1000, /* dwMinLiveVideoStretch */ |
| 1000, /* dwMaxLiveVideoStretch */ |
| 1000, /* dwMinHwCodecStretch */ |
| 1000, /* dwMaxHwCodecStretch */ |
| 0, 0, 0, /* dwReserved1, 2, 3 */ |
| BLIT_CAPS, /* dwSVBCaps */ |
| CKEY_CAPS, /* dwSVBCKeyCaps */ |
| FX_CAPS, /* dwSVBFXCaps */ |
| ROPS, /* dwSVBRops */ |
| BLIT_CAPS, /* dwVSBCaps */ |
| CKEY_CAPS, /* dwVSBCKeyCaps */ |
| FX_CAPS, /* dwVSBFXCaps */ |
| ROPS, /* dwVSBRops */ |
| BLIT_CAPS, /* dwSSBCaps */ |
| CKEY_CAPS, /* dwSSBCKeyCaps */ |
| FX_CAPS, /* dwSSBFXCaps */ |
| ROPS, /* dwSSBRops */ |
| 0, /* dwMaxVideoPorts */ |
| 0, /* dwCurrVideoPorts */ |
| 0, /* ? dwSVBCaps2 */ |
| BLIT_CAPS, /* ? dwNLVBCaps */ |
| 0, /* ? dwNLVBCaps2 */ |
| CKEY_CAPS, /* dwNLVBCKeyCaps */ |
| FX_CAPS, /* dwNLVBFXCaps */ |
| ROPS, /* dwNLVBRops */ |
| { /* ddsCaps */ |
| DDSCAPS_3DDEVICE | DDSCAPS_ALPHA | DDSCAPS_BACKBUFFER | DDSCAPS_FLIP |
| | DDSCAPS_FRONTBUFFER | DDSCAPS_MIPMAP | DDSCAPS_OFFSCREENPLAIN |
| | DDSCAPS_PALETTE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_SYSTEMMEMORY |
| | DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_VISIBLE |
| | DDSCAPS_ZBUFFER, |
| DDSCAPS2_CUBEMAP, |
| 0, |
| 0 |
| } |
| }; |
| |
| #undef BLIT_CAPS |
| #undef CKEY_CAPS |
| #undef FX_CAPS |
| #undef ROPS |
| |
| ICOM_THIS(IDirectDrawImpl, iface); |
| |
| TRACE("(%p)->(%p,%p)\n",This,pDriverCaps,pHELCaps); |
| if ((pDriverCaps != NULL && pDriverCaps->dwSize != sizeof(DDCAPS)) |
| || (pHELCaps != NULL && pHELCaps->dwSize != sizeof(DDCAPS))) |
| { |
| FIXME("unsupported structure versions: %lu/%lu vs %u\n", |
| pDriverCaps ? pDriverCaps->dwSize : sizeof(DDCAPS), |
| pHELCaps ? pHELCaps->dwSize : sizeof(DDCAPS), |
| sizeof(DDCAPS)); |
| /* The old DD caps structures are contained in the DX7 SDK, and since |
| * it's changed every version, we should probably try to support the |
| * old ones. */ |
| } |
| |
| if (pDriverCaps != NULL) |
| memcpy(pDriverCaps, &caps, pDriverCaps->dwSize); |
| |
| if (pHELCaps != NULL) |
| memcpy(pHELCaps, &caps, pHELCaps->dwSize); |
| |
| return DD_OK; |
| } |
| |
| HRESULT WINAPI |
| User_DirectDraw_GetDeviceIdentifier(LPDIRECTDRAW7 iface, |
| LPDDDEVICEIDENTIFIER2 pDDDI, |
| DWORD dwFlags) |
| { |
| TRACE("(%p)->(%p,%08lx)\n",iface,pDDDI,dwFlags); |
| *pDDDI = user_device; |
| return DD_OK; |
| } |
| |
| /* GetDisplayMode: generic */ |
| /* GetFourCCCodes: generic */ |
| /* GetGDISurface: ??? */ |
| /* GetMonitorFrequency: generic */ |
| /* GetScanLine: generic */ |
| /* GetSurfaceFromDC: generic */ |
| /* GetVerticalBlankStatus: generic */ |
| /* Initialize: generic */ |
| /* RestoreAllSurfaces: generic */ |
| /* RestoreDisplayMode: generic */ |
| /* SetCooperativeLevel: ??? */ |
| |
| HRESULT WINAPI |
| User_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth, |
| DWORD dwHeight, DWORD dwBPP, |
| DWORD dwRefreshRate, DWORD dwFlags) |
| { |
| ICOM_THIS(IDirectDrawImpl, iface); |
| |
| const DDPIXELFORMAT* pixelformat; |
| LONG pitch; |
| |
| TRACE("(%p)->(%ldx%ldx%ld,%ld Hz,%08lx)\n",This,dwWidth,dwHeight,dwBPP,dwRefreshRate,dwFlags); |
| if (!IsValidDisplayMode(dwWidth, dwHeight, dwBPP, dwRefreshRate, dwFlags)) |
| return DDERR_INVALIDMODE; |
| |
| pixelformat = pixelformat_for_depth(dwBPP); |
| if (pixelformat == NULL) |
| { |
| assert(0); |
| return DDERR_GENERIC; |
| } |
| |
| pitch = DDRAW_width_bpp_to_pitch(dwWidth, dwBPP); |
| |
| return Main_DirectDraw_SetDisplayMode(iface, dwWidth, dwHeight, pitch, |
| dwRefreshRate, dwFlags, pixelformat); |
| } |
| |
| /* StartModeTest: ??? */ |
| /* TestCooperativeLevel: generic? */ |
| /* WaitForVerticalBlank: ??? */ |
| |
| static ICOM_VTABLE(IDirectDraw7) User_DirectDraw_VTable = |
| { |
| Main_DirectDraw_QueryInterface, |
| Main_DirectDraw_AddRef, |
| Main_DirectDraw_Release, |
| Main_DirectDraw_Compact, |
| Main_DirectDraw_CreateClipper, |
| Main_DirectDraw_CreatePalette, |
| Main_DirectDraw_CreateSurface, |
| Main_DirectDraw_DuplicateSurface, |
| User_DirectDraw_EnumDisplayModes, |
| Main_DirectDraw_EnumSurfaces, |
| Main_DirectDraw_FlipToGDISurface, |
| User_DirectDraw_GetCaps, |
| Main_DirectDraw_GetDisplayMode, |
| Main_DirectDraw_GetFourCCCodes, |
| Main_DirectDraw_GetGDISurface, |
| Main_DirectDraw_GetMonitorFrequency, |
| Main_DirectDraw_GetScanLine, |
| Main_DirectDraw_GetVerticalBlankStatus, |
| Main_DirectDraw_Initialize, |
| Main_DirectDraw_RestoreDisplayMode, |
| Main_DirectDraw_SetCooperativeLevel, |
| User_DirectDraw_SetDisplayMode, |
| Main_DirectDraw_WaitForVerticalBlank, |
| Main_DirectDraw_GetAvailableVidMem, |
| Main_DirectDraw_GetSurfaceFromDC, |
| Main_DirectDraw_RestoreAllSurfaces, |
| Main_DirectDraw_TestCooperativeLevel, |
| User_DirectDraw_GetDeviceIdentifier, |
| Main_DirectDraw_StartModeTest, |
| Main_DirectDraw_EvaluateMode |
| }; |