/***************************************************************************\ * * File: DxManager.cpp * * Description: * DxManager.cpp implements the process-wide DirectX manager used for all * DirectDraw, Direct3D, and DirectX Transforms services. * * * History: * 1/18/2000: JStall: Created * * Copyright (C) 2000 by Microsoft Corporation. All rights reserved. * \***************************************************************************/ #include "stdafx.h" #include "Services.h" #include "DxManager.h" #include "GdiCache.h" #include "Buffer.h" #include "ResourceManager.h" /***************************************************************************\ ***************************************************************************** * * class DxManager * ***************************************************************************** \***************************************************************************/ //------------------------------------------------------------------------------ DxManager::DxManager() { m_cDDrawRef = 0; m_cDxTxRef = 0; } //------------------------------------------------------------------------------ DxManager::~DxManager() { #if DBG if (m_hDllDxDraw != NULL) { Trace("DUser Warning: Application did not call UninitGadgetComponent() to\n"); Trace(" deinitialize properly\n"); } #endif // DBG } /***************************************************************************\ * * DxManager::Init * * Init() initializes the DxManager by loading COM and core DirectX services. * \***************************************************************************/ HRESULT DxManager::Init(GUID * pguidDriver) { if (m_hDllDxDraw == NULL) { // // Normal DirectDraw does not need COM to be initialized. // m_hDllDxDraw = LoadLibrary("ddraw.dll"); if (m_hDllDxDraw == NULL) { return DU_E_GENERIC; } // // Load the functions. // // NOTE: On older versions of DirectDraw, DirectDrawCreateEx() doesn't // exist. We need to specifically check this. // m_pfnCreate = (DirectDrawCreateProc) GetProcAddress(m_hDllDxDraw, _T("DirectDrawCreate")); m_pfnCreateEx = (DirectDrawCreateExProc) GetProcAddress(m_hDllDxDraw, _T("DirectDrawCreateEx")); if (m_pfnCreate == NULL) { goto errorexit; } // // First, try creating the most advance interface. // HRESULT hr; if (m_pfnCreateEx != NULL) { hr = (m_pfnCreateEx)(pguidDriver, (void **) &m_pDD7, IID_IDirectDraw7, NULL); if (SUCCEEDED(hr)) { AssertReadPtr(m_pDD7); m_pDD7->SetCooperativeLevel(NULL, DDSCL_NORMAL); // // Try to get an IDirectDraw interface as well. // m_pDD7->QueryInterface(IID_IDirectDraw, (void **) &m_pDD); { HRESULT hRet; DDSURFACEDESC2 ddsd; IDirectDrawSurface7 * pDD; ZeroMemory(&ddsd, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; hRet = m_pDD7->CreateSurface(&ddsd, &pDD, NULL); if (hRet == DD_OK) pDD->Release(); } } else { // // Explicitly set to NULL // m_pDD7 = NULL; } } // // If can't create advanced interface, go for backup // if (m_pDD7 == NULL) { AssertReadPtr(m_pfnCreate); hr = (m_pfnCreate)(pguidDriver, &m_pDD, NULL); if (SUCCEEDED(hr)) { m_pDD->SetCooperativeLevel(NULL, DDSCL_NORMAL); } else { // // Unable to initialize DirectDraw, so need to bail. // goto errorexit; } } } m_cDDrawRef++; return S_OK; errorexit: Uninit(); return DU_E_GENERIC; } //------------------------------------------------------------------------------ void DxManager::Uninit() { if (m_cDDrawRef <= 0) { return; } m_cDDrawRef--; if (m_cDDrawRef <= 0) { // // Can't call Release() on the IDirectDraw interfaces here b/c we are // shutting down and their v-tbl's are messed up. Bummer. // SafeRelease(m_pDD7); SafeRelease(m_pDD); if (m_hDllDxDraw != NULL) { FreeLibrary(m_hDllDxDraw); m_hDllDxDraw = NULL; } m_pfnCreate = NULL; m_pfnCreateEx = NULL; } } //------------------------------------------------------------------------------ HRESULT DxManager::InitDxTx() { AssertMsg(IsInit(), "DxManager must be first initialized"); if (m_pdxXformFac == NULL) { // // DxTx needs COM to be initialized first. // if (!GetComManager()->Init(ComManager::sCOM)) { return DU_E_GENERIC; } // Build and initialize a Transform Factory HRESULT hr; hr = GetComManager()->CreateInstance(CLSID_DXTransformFactory, NULL, IID_IDXTransformFactory, (void **)&m_pdxXformFac); if (FAILED(hr) || (m_pdxXformFac == NULL)) { goto Error; } hr = m_pdxXformFac->SetService(SID_SDirectDraw, m_pDD, FALSE); if (FAILED(hr)) { goto Error; } // Build a Surface Factory hr = m_pdxXformFac->QueryService(SID_SDXSurfaceFactory, IID_IDXSurfaceFactory, (void **)&m_pdxSurfFac); if (FAILED(hr) || (m_pdxSurfFac == NULL)) { goto Error; } } m_cDxTxRef++; return S_OK; Error: SafeRelease(m_pdxSurfFac); SafeRelease(m_pdxXformFac); return DU_E_GENERIC; } //------------------------------------------------------------------------------ void DxManager::UninitDxTx() { if (m_cDxTxRef <= 0) { return; } m_cDxTxRef--; if (m_cDxTxRef <= 0) { GetBufferManager()->FlushTrxBuffers(); SafeRelease(m_pdxSurfFac); SafeRelease(m_pdxXformFac); } } //------------------------------------------------------------------------------ HRESULT DxManager::BuildSurface(SIZE sizePxl, IDirectDrawSurface7 * pddSurfNew) { AssertMsg(IsInit(), "DxManager must be first initialized"); AssertMsg(m_pDD7 != NULL, "Must have DX7"); #if 0 HDC hdc = GetGdiCache()->GetTempDC(); int nBitDepth = GetDeviceCaps(hdc, BITSPIXEL); #endif DDSURFACEDESC2 ddsd; ZeroMemory(&ddsd, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; ddsd.dwWidth = sizePxl.cx; ddsd.dwHeight = sizePxl.cy; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; #if 0 GetGdiCache()->ReleaseTempDC(hdc); #endif // TODO: Want to optimize where this surface is being created return m_pDD7->CreateSurface(&ddsd, &pddSurfNew, NULL); } //------------------------------------------------------------------------------ HRESULT DxManager::BuildDxSurface(SIZE sizePxl, REFGUID guidFormat, IDXSurface ** ppdxSurfNew) { AssertWritePtr(ppdxSurfNew); CDXDBnds bnds; bnds.SetXYSize(sizePxl.cx, sizePxl.cy); HRESULT hr = GetSurfaceFactory()->CreateSurface(m_pDD, NULL, &guidFormat, &bnds, 0, NULL, IID_IDXSurface, (void**)ppdxSurfNew); if (FAILED(hr)) { return hr; } AssertMsg(*ppdxSurfNew != NULL, "Ensure valid surface"); return TRUE; } /***************************************************************************\ ***************************************************************************** * * class DxSurface * ***************************************************************************** \***************************************************************************/ //------------------------------------------------------------------------------ DxSurface::DxSurface() { m_pdxSurface = NULL; m_sizePxl.cx = 0; m_sizePxl.cy = 0; } //------------------------------------------------------------------------------ DxSurface::~DxSurface() { SafeRelease(m_pdxSurface); } /***************************************************************************\ * * DxSurface::Create * * Create() initializes a new instance of DxSurface. * \***************************************************************************/ HRESULT DxSurface::Create(SIZE sizePxl) { HRESULT hr; // // Build the surface // #if 0 m_guidFormat = DDPF_ARGB32; m_sf = DXPF_ARGB32; #elif 0 m_guidFormat = DDPF_PMARGB32 m_sf = DXPF_PMARGB32 #elif 1 m_guidFormat = DDPF_RGB565; m_sf = DXPF_RGB565; #elif 0 m_guidFormat = DDPF_RGB555; m_sf = DXPF_RGB555; #elif 0 m_guidFormat = DDPF_ARGB4444; m_sf = DXPF_ARGB4444; #endif hr = GetDxManager()->BuildDxSurface(sizePxl, m_guidFormat, &m_pdxSurface); if (FAILED(hr)) { return hr; } DXPMSAMPLE sam; sam.Red = 0xC0; sam.Green = 0x00; sam.Blue = 0x00; sam.Alpha = 0xFF; DXFillSurface(m_pdxSurface, sam, FALSE); m_sizePxl.cx = sizePxl.cx; m_sizePxl.cy = sizePxl.cy; return S_OK; } /***************************************************************************\ * * DxSurface::CopyDC * * CopyDC() copies a given HDC into the DxSurface, converting properly from * the GDI object into the Dx object. * \***************************************************************************/ BOOL DxSurface::CopyDC( IN HDC hdcSrc, // HDC to copy bits from IN const RECT & rcCrop) // Area to copy { HRESULT hr; // Check parameters if (m_pdxSurface == NULL) { return FALSE; } if (hdcSrc == NULL) { return FALSE; } // // Copy the bitmap to the surface // BOOL fSuccess = FALSE; IDXDCLock * pdxLock = NULL; #if 0 { DXPMSAMPLE sam; sam.Red = 0x00; sam.Green = 0x00; sam.Blue = 0x00; sam.Alpha = 0xFF; DXFillSurface(m_pdxSurface, sam, FALSE); } #endif pdxLock = NULL; hr = m_pdxSurface->LockSurfaceDC(NULL, INFINITE, DXLOCKF_READWRITE, &pdxLock); if (FAILED(hr) || (pdxLock == NULL)) { goto Cleanup; } { HDC hdcSurface = pdxLock->GetDC(); BitBlt(hdcSurface, 0, 0, rcCrop.right - rcCrop.left, rcCrop.bottom - rcCrop.top, hdcSrc, rcCrop.left, rcCrop.top, SRCCOPY); } pdxLock->Release(); fSuccess = FixAlpha(); Cleanup: return fSuccess; } /***************************************************************************\ * * DxSurface::CopyBitmap * * CopyBitmap() copies a given HBITMAP into the DxSurface, converting * properly from the GDI object into the Dx object. * \***************************************************************************/ BOOL DxSurface::CopyBitmap( IN HBITMAP hbmpSrc, // Bitmap to copy from IN const RECT * prcCrop) // Optional cropping area { HRESULT hr; // Check parameters if (m_pdxSurface == NULL) { return FALSE; } if (hbmpSrc == NULL) { return FALSE; } // // Determine the area to copy // BITMAP bmpInfo; if (GetObject(hbmpSrc, sizeof(bmpInfo), &bmpInfo) == 0) { return FALSE; } POINT ptSrcOffset; SIZE sizeBmp; ptSrcOffset.x = 0; ptSrcOffset.y = 0; sizeBmp.cx = bmpInfo.bmWidth; sizeBmp.cy = bmpInfo.bmHeight; if (prcCrop != NULL) { SIZE sizeCrop; sizeCrop.cx = prcCrop->right - prcCrop->left; sizeCrop.cy = prcCrop->bottom - prcCrop->top; ptSrcOffset.x = prcCrop->left; ptSrcOffset.y = prcCrop->top; sizeBmp.cx = min(sizeBmp.cx, sizeCrop.cx); sizeBmp.cy = min(sizeBmp.cy, sizeCrop.cy); } // // Copy the bitmap to the surface // BOOL fSuccess = FALSE; HDC hdcBitmap = NULL; IDXDCLock * pdxLock = NULL; hdcBitmap = GetGdiCache()->GetCompatibleDC(); if (hdcBitmap == NULL) { goto Cleanup; } #if 0 { DXPMSAMPLE sam; sam.Red = 0x00; sam.Green = 0x00; sam.Blue = 0x00; sam.Alpha = 0xFF; DXFillSurface(m_pdxSurface, sam, FALSE); } #endif hr = m_pdxSurface->LockSurfaceDC(NULL, INFINITE, DXLOCKF_READWRITE, &pdxLock); if (FAILED(hr) || (pdxLock == NULL)) { goto Cleanup; } { HDC hdcSurface = pdxLock->GetDC(); HBITMAP hbmpOld = (HBITMAP) SelectObject(hdcBitmap, hbmpSrc); BitBlt(hdcSurface, 0, 0, sizeBmp.cx, sizeBmp.cy, hdcBitmap, ptSrcOffset.x, ptSrcOffset.y, SRCCOPY); SelectObject(hdcBitmap, hbmpOld); } pdxLock->Release(); fSuccess = FixAlpha(); Cleanup: if (hdcBitmap != NULL) { GetGdiCache()->ReleaseCompatibleDC(hdcBitmap); } return fSuccess; } /***************************************************************************\ * * DxSurface::FixAlpha * * FixAlpha() fixes the alpha values in a surface. This usually needs to be * done after copying a GDI HBITMAP to a DXSurface, depending on the format. * \***************************************************************************/ BOOL DxSurface::FixAlpha() { IDXARGBReadWritePtr * pRW; HRESULT hr = m_pdxSurface->LockSurface(NULL, INFINITE, DXLOCKF_READWRITE, __uuidof(IDXARGBReadWritePtr), (void **)&pRW, NULL); if (FAILED(hr)) { return FALSE; } BOOL fSuccess = FALSE; if (!TestFlag(m_sf, DXPF_TRANSLUCENCY)) { // // Sample doesn't have any alpha, so okay // fSuccess = TRUE; } else if (m_sf == DXPF_ARGB32) { // // Format is 8:8:8:8 with alpha in MSB. // Need to use Unpack() to get bits. // Each pixel is 32 bits. // DXSAMPLE * psam; for (int y = 0; y < m_sizePxl.cy; y++) { pRW->MoveToRow(y); psam = pRW->Unpack(NULL, m_sizePxl.cx, FALSE); Assert(psam != NULL); int x = m_sizePxl.cx; while (x-- > 0) { *psam = *psam | 0xFF000000; psam++; } } fSuccess = TRUE; } else if (m_sf == DXPF_PMARGB32) { // // Format is 8:8:8:8 with alpha in MSB. // Need to use UnpackPremult() to get bits. // Each pixel is 32 bits // DXPMSAMPLE * psam; for (int y = 0; y < m_sizePxl.cy; y++) { pRW->MoveToRow(y); psam = pRW->UnpackPremult(NULL, m_sizePxl.cx, FALSE); Assert(psam != NULL); int x = m_sizePxl.cx; while (x-- > 0) { *psam = *psam | 0xFF000000; psam++; } } fSuccess = TRUE; } else if (m_sf == DXPF_ARGB4444) { // // Format is 4:4:4:4 with alpha in MSN. // Need to use Unpack() to get bits. // Each pixel is 16 bits // int cb = m_sizePxl.cx * sizeof(DXSAMPLE); DXSAMPLE * rgam = (DXSAMPLE *) _alloca(cb); DXSAMPLE * psam; for (int y = 0; y < m_sizePxl.cy; y++) { pRW->MoveToRow(y); psam = pRW->Unpack(rgam, m_sizePxl.cx, FALSE); Assert(psam != NULL); int x = m_sizePxl.cx; while (x-- > 0) { *psam = *psam | 0xFF000000; psam++; } pRW->PackAndMove(rgam, m_sizePxl.cx); } fSuccess = TRUE; } pRW->Release(); return fSuccess; }