Example #1
0
/*****************************Private*Routine******************************\
* DDSurfEnumFunc
*
\**************************************************************************/
HRESULT WINAPI
DDSurfEnumFunc(
    LPDIRECTDRAWSURFACE7 pdds,
    DDSURFACEDESC2* pddsd,
    void* lpContext
    )
{
    LPDIRECTDRAWSURFACE7* ppdds = (LPDIRECTDRAWSURFACE7*)lpContext;

    DDSURFACEDESC2 ddsd;
    INITDDSTRUCT(ddsd);

    HRESULT hr = pdds->GetSurfaceDesc(&ddsd);
    if(SUCCEEDED(hr))
    {
        if(ddsd.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
        {
            *ppdds = pdds;
            return DDENUMRET_CANCEL;

        }
    }

    pdds->Release();
    return DDENUMRET_OK;
}
Example #2
0
//-------------------------------------------------------------------------
//  InitializeEnvironment
//  creates default allocator-presenter and sets D3D environment
//-------------------------------------------------------------------------
HRESULT CMultiSAP::InitializeEnvironment()
{
    HRESULT hr;
//    m_hMonitor = MonitorFromWindow(m_hwndApp, MONITOR_DEFAULTTOPRIMARY);

    hr = CreateDefaultAllocatorPresenter();
    if (hr != S_OK)
        return hr;

    BITMAPINFOHEADER  bi =
    {
        sizeof(BITMAPINFOHEADER), // biSize
            640,                      // biWidth
            480,                      // biHeight
            1,                        // biPlanes
            0,                        // biBitCount
            BI_RGB,                   // biCompression
            0,                        // biSizeImage,
            0,                        // biXpelsPerMeter
            0,                        // biYPelsPerMeter
            0,                        // biClrUsed
            0                         // biClrImportant
    };
    VMRALLOCATIONINFO ai =
    {
        AMAP_3D_TARGET,             // dwFlags
        &bi,                        // lpHdr
        NULL,                       // lpPicFmt
        {4, 3},                     // szAspectRatio
        1,                          // dwMinBuffers
        1,                          // dwMaxBuffers
        0,                          // dwInterlaceFlags
        {640, 480}                  // szNativeSize
    };

    DWORD dwBuffers = 0;
    LPDIRECTDRAWSURFACE7 lpDDSurf;
    hr = m_pAlloc->AllocateSurface(0, &ai, &dwBuffers, &lpDDSurf);
    if (hr != DD_OK)
        return hr;

    DDSURFACEDESC2 ddsd = {sizeof(DDSURFACEDESC2)};
    hr = lpDDSurf->GetSurfaceDesc(&ddsd);
    if (hr != DD_OK) {
        return hr;
    }

    //
    // Overlay surfaces have these flags set, we need to remove
    // these flags prior to calling GetAttachedSurface
    //
    ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_FRONTBUFFER | DDSCAPS_VISIBLE);

    hr = lpDDSurf->GetAttachedSurface(&ddsd.ddsCaps, &m_lpBackBuffer);


    m_lpBackBuffer->GetDDInterface((LPVOID *)&m_lpDDObj);

    //
    // get the h/w caps for this device
    //
    INITDDSTRUCT(m_ddHWCaps);
    m_lpDDObj->GetCaps(&m_ddHWCaps, NULL);

    //
    // Create the device. The device is created off of our back buffer, which
    // becomes the render target for the newly created device. Note that the
    // z-buffer must be created BEFORE the device
    //
    m_pD3DHelper = new CD3DHelper(m_lpBackBuffer, &hr);
    if(m_pD3DHelper == NULL || hr != DD_OK)
    {
        if(m_pD3DHelper == NULL)
        {
            hr = E_OUTOFMEMORY;
        }
        delete m_pD3DHelper;
    }

    SetRect(&m_rcDst, 0, 0, 640, 480);

#ifdef SPARKLE
    m_pSparkle = new CSparkle(m_lpDDObj);
    if (m_pSparkle)
        m_pSparkle->InitializeSparkle();
#endif

    return hr;
}
Example #3
0
/******************************Public*Routine******************************\
* PresentImage
*
\**************************************************************************/
STDMETHODIMP
CMpegMovie::PresentImage(
    DWORD_PTR dwUserID,
    VMRPRESENTATIONINFO* lpPresInfo
    )
{
#if 0
    LPDIRECTDRAWSURFACE7 lpSurface = lpPresInfo->lpSurf;
    const REFERENCE_TIME rtNow = lpPresInfo->rtStart;
    const DWORD dwSurfaceFlags = lpPresInfo->dwFlags;

    if(m_iDuration > 0)
    {
        HRESULT hr;
        RECT rs, rd;
        DDSURFACEDESC2 ddsdV;

        INITDDSTRUCT(ddsdV);
        hr = lpSurface->GetSurfaceDesc(&ddsdV);

        DDSURFACEDESC2 ddsdP;
        INITDDSTRUCT(ddsdP);
        hr = m_pddsPriText->GetSurfaceDesc(&ddsdP);

        FLOAT fPos = (FLOAT)m_iDuration / 30.0F;
        FLOAT fPosInv = 1.0F - fPos;

        SetRect(&rs, 0, 0,
            MulDiv((int)ddsdV.dwWidth, 30 - m_iDuration, 30),
            ddsdV.dwHeight);

        SetRect(&rd, 0, 0,
            MulDiv((int)ddsdP.dwWidth, 30 - m_iDuration, 30),
            ddsdP.dwHeight);

        hr = m_pddsRenderT->Blt(&rd, lpSurface,
            &rs, DDBLT_WAIT, NULL);

        SetRect(&rs, 0, 0,
            MulDiv((int)ddsdP.dwWidth, m_iDuration, 30),
            ddsdP.dwHeight);

        SetRect(&rd,
            (int)ddsdP.dwWidth - MulDiv((int)ddsdP.dwWidth, m_iDuration, 30),
            0,
            ddsdP.dwWidth,
            ddsdP.dwHeight);

        hr = m_pddsRenderT->Blt(&rd, m_pddsPriText,
            &rs, DDBLT_WAIT, NULL);

        //
        // need to wait for VBlank before blt-ing
        //
        {
            LPDIRECTDRAW lpdd;
            hr = m_pddsPrimary->GetDDInterface((LPVOID*)&lpdd);
            if(SUCCEEDED(hr))
            {
                DWORD dwScanLine;
                for(; ;)
                {
                    hr = lpdd->GetScanLine(&dwScanLine);

                    if(hr ==  DDERR_VERTICALBLANKINPROGRESS)
                    {
                        break;
                    }

                    if(FAILED(hr))
                    {
                        break;
                    }

                    if((LONG)dwScanLine>= rd.top)
                    {
                        if((LONG)dwScanLine <= rd.bottom)
                        {
                            continue;
                        }
                    }

                    break;
                }

                RELEASE(lpdd);
            }
        }

        hr = m_pddsPrimary->Blt(NULL, m_pddsRenderT,
            NULL, DDBLT_WAIT, NULL);

        m_iDuration--;
        if(m_iDuration == 0 && (ddsdV.ddsCaps.dwCaps & DDSCAPS_OVERLAY))
        {
            // need to get the color key visible again.
            InvalidateRect(m_hwndApp, NULL, FALSE);
        }
        return hr;
    }
    else
    {
        return m_lpDefIP->PresentImage(dwUserID, lpPresInfo);
    }
#endif

    return m_lpDefIP->PresentImage(dwUserID, lpPresInfo);
}
Example #4
0
bool SetupDDraw()
{
    logOutput << CurrentTimeString() << "called SetupDDraw()" << endl;

    if (!g_ddInterface)
    {
        logOutput << CurrentTimeString() << "SetupDDraw: DirectDraw interface not set, returning" << endl;
        return false;
    }

    bool bSuccess = true;

    bKillThread = false;

    if (hCopyThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CopyDDrawTextureThread, NULL, 0, NULL))
    {
        if (!(hCopyEvent = CreateEvent(NULL, FALSE, FALSE, NULL)))
        {
            logOutput << CurrentTimeString() << "SetupDDraw: CreateEvent failed, GetLastError = " << GetLastError() << endl;
            bSuccess = false;
        }
    }
    else
    {
        logOutput << CurrentTimeString() << "SetupDDraw: CreateThread failed, GetLastError = " << GetLastError() << endl;
        bSuccess = false;
    }

    if (bSuccess)
    {
        if (!ddUnlockFctMutex)
        {
            ddUnlockFctMutex = CreateMutex(NULL, FALSE, mutexName);
            if (!ddUnlockFctMutex)
            {
                RUNEVERYRESET logOutput << CurrentTimeString() << "SetupDDraw: CreateMutex failed, GetLastError = " << GetLastError() << endl;
                bSuccess = false;
            }
        }
    }

    if (bSuccess && !g_frontSurface)
    {
        RUNEVERYRESET logOutput << "SetupDDraw: frontSurface and surface descriptor not set, returning" << endl;
        CleanUpDDraw();
        return false;
    }
    else if (bSuccess)
    {
        LPDIRECTDRAWPALETTE palette = NULL;
        HRESULT err;
        if (SUCCEEDED(err = g_frontSurface->GetPalette(&palette)))
        {
            if (palette)
                SetupPalette(palette);
        }
        else if (err == DDERR_NOPALETTEATTACHED)
        {
            //logOutput << CurrentTimeString() << "No palette attached to primary surface" << endl;
        }
        else
        {
            logOutput << CurrentTimeString() << "Error retrieving palette" << endl;
            printDDrawError(err, "getFrontSurface");
        }
    }

    if (bSuccess && !g_surfaceDesc)
    {
        logOutput << CurrentTimeString() << "SetupDDraw: no surface descriptor found, creating a new one (not an error)" << endl;

        g_surfaceDesc = new DDSURFACEDESC2;
        g_surfaceDesc->dwSize = sizeof(DDSURFACEDESC);

        HRESULT hr;
        if (FAILED(hr = ((LPDIRECTDRAWSURFACE)g_frontSurface)->GetSurfaceDesc((LPDDSURFACEDESC)g_surfaceDesc)))
        {
            g_surfaceDesc->dwSize = sizeof(DDSURFACEDESC2);
            if (FAILED(g_frontSurface->GetSurfaceDesc(g_surfaceDesc)))
            {
                logOutput << CurrentTimeString() << "SetupDDraw: error getting surface descriptor" << endl;
                printDDrawError(hr, "SetupDDraw");
                bSuccess = false;
            }
        }
    }

    if (bSuccess && g_surfaceDesc)
    {
        const DDPIXELFORMAT& pf = g_surfaceDesc->ddpfPixelFormat;
        if (pf.dwFlags & DDPF_RGB)
        {
            if (pf.dwRGBBitCount == 16)
            {
                logOutput << CurrentTimeString() << "SetupDDraw: found 16bit format (using R5G6B5 conversion)" << endl;
                g_bConvert16to32 = true;
            }
            else if (pf.dwRGBBitCount == 32)
            {
                logOutput << CurrentTimeString() << "SetupDDraw: found 32bit format (using plain copy)" << endl;
                g_bUse32bitCapture = true;
            }
        }
        else if (pf.dwFlags & (DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED1))
        {
            logOutput << CurrentTimeString() << "SetupDDraw: front surface uses palette indices" << endl;
        }
    }

    if (bSuccess)
    {
        logOutput << CurrentTimeString() << "SetupDDraw: primary surface width = " << g_surfaceDesc->dwWidth << ", height = " << g_surfaceDesc->dwHeight << endl;
        g_dwSize = g_surfaceDesc->lPitch*g_surfaceDesc->dwHeight;
        ddrawCaptureInfo.captureType = CAPTURETYPE_MEMORY;
        ddrawCaptureInfo.cx = g_surfaceDesc->dwWidth;
        ddrawCaptureInfo.cy = g_surfaceDesc->dwHeight;
        ddrawCaptureInfo.pitch = 4 * ddrawCaptureInfo.cx;
        ddrawCaptureInfo.hwndCapture = (DWORD)hwndSender;
        ddrawCaptureInfo.format = GS_BGRA;
        DWORD g_dwCaptureSize = ddrawCaptureInfo.pitch*ddrawCaptureInfo.cy;
        ddrawCaptureInfo.bFlip = FALSE;
        ddrawCaptureInfo.mapID = InitializeSharedMemoryCPUCapture(g_dwCaptureSize, &ddrawCaptureInfo.mapSize, &copyData, textureBuffers);

        memcpy(infoMem, &ddrawCaptureInfo, sizeof(CaptureInfo));

        DDSURFACEDESC2 captureDesc;
        ZeroMemory(&captureDesc, sizeof(captureDesc));
        captureDesc.dwSize = sizeof(DDSURFACEDESC2);

        captureDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_PITCH;
        captureDesc.dwWidth = g_surfaceDesc->dwWidth;
        captureDesc.dwHeight = g_surfaceDesc->dwHeight;
        captureDesc.lPitch = g_surfaceDesc->lPitch;
        captureDesc.ddpfPixelFormat = g_surfaceDesc->ddpfPixelFormat;
        captureDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;

        HRESULT err;

        ddrawSurfaceCreate.Unhook();
        for (int i = 0; i < NUM_BUFFERS && bSuccess; i++)
        {
            if (FAILED(err = g_ddInterface->CreateSurface(&captureDesc, &ddCaptures[i], NULL)))
            {
                logOutput << CurrentTimeString() << "SetupDDraw: Could not create offscreen capture" << endl;
                printDDrawError(err, "SetupDDraw");
                bSuccess = false;
                break;
            }
        }
        ddrawSurfaceCreate.Rehook();

        if (bSuccess)
        {
            bHasTextures = true;

            SetEvent(hSignalReady);

            OSInitializeTimer();
        }
    }

    if (bSuccess)
    {
        logOutput << CurrentTimeString() << "SetupDDraw successfull" << endl;
        HookAll();
        return true;
    }
    else
    {
        logOutput << CurrentTimeString() << "SetupDDraw failed" << endl;
        CleanUpDDraw();
        return false;
    }
}
Example #5
0
/**
 * vdraw_ddraw_init(): Initialize the DirectDraw video subsystem.
 * @return 0 on success; non-zero on error.
 */
int vdraw_ddraw_init(void)
{
	DDSURFACEDESC2 ddsd;
	
	vdraw_ddraw_end();
	
	mdp_render_t *rendMode = get_mdp_render_t();
	const int scale = rendMode->scale;
	
	// Determine the window size using the scaling factor.
	if (scale <= 0)
		return -1;
	const int w = 320 * scale;
	const int h = 240 * scale;
	
	if (vdraw_get_fullscreen())
	{
		Res_X = w;
		Res_Y = h;
	}
	
	// Return value.
	int rval;
	
	// Initialize DirectDraw.
	// TODO: Initialize DirectDraw on the monitor with most of Gens/GS onscreen.
	LPDIRECTDRAW lpDD_Init;
	rval = DirectDrawCreate(NULL, &lpDD_Init, NULL);
	if (FAILED(rval))
	{
		LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
			"DirectDrawCreate() failed: 0x%08X", rval);
		return -2;
	}
	
	rval = lpDD_Init->QueryInterface(IID_IDirectDraw7, (LPVOID*)&lpDD);
	if (FAILED(rval))
	{
		if (lpDD_Init)
			lpDD_Init->Release();
		
		LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
			"lpDD_Init->QueryInterface(IID_IDirectDraw4) failed: 0x%08X", rval);
		LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
			"This can usually be fixed by upgrading DirectX.");
		return -3;
	}
	
	// Free the DirectDraw initialization object.
	lpDD_Init->Release();
	
	// Set the cooperative level.
	vdraw_ddraw_set_cooperative_level();
	
	// TODO: 15-bit color override. ("Force 555" or "Force 565" in the config file.)
	memset(&ddsd, 0, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);
	
	// TODO: Figure out what FS_No_Res_Change is for.
	// TODO: Figure out if this is correct.
	if (vdraw_get_fullscreen() /* && !FS_No_Res_Change*/)
	{
		// Use the color depth setting.
		// NOTE: "15-bit" color requires 16-bit to be specified.
		rval = lpDD->SetDisplayMode(Res_X, Res_Y, (bppOut == 15 ? 16 : bppOut), 0, 0);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDD->SetDisplayMode() failed: 0x%08X", rval);
			
			// If render mode is set to Normal, try using Double instead.
			if (rendMode_FS == RenderMgr::begin() && rendMode_FS != RenderMgr::end())
			{
				LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
					"Renderer is set to Normal; attempting to use Double instead.");
				rendMode_FS++;
				vdraw_set_renderer(rendMode_FS);
				vdraw_text_write("Normal rendering failed. Using Double.", 1500);
				Sync_Gens_Window_GraphicsMenu();
			}
			
			return -4;
		}
	}
	
#if 0
	// Check the current color depth.
	unsigned char newBpp;
	lpDD->GetDisplayMode(&ddsd);
	switch (ddsd.ddpfPixelFormat.dwGBitMask)
	{
		case 0x03E0:
			// 15-bit color.
			newBpp = 15;
			break;
		case 0x07E0:
			// 16-bit color.
			newBpp = 16;
			break;
		case 0x00FF00:
		default:
			// 32-bit color.
			newBpp = 32;
			break;
	}
	
	if (newBpp != bppOut)
		vdraw_set_bpp(newBpp, false);
#endif
	
	// Clear ddsd.
	memset(&ddsd, 0x00, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);
	
	if (vdraw_get_fullscreen() && Video.VSync_FS)
	{
		ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
		ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
		ddsd.dwBackBufferCount = 2;
	}
	else
	{
		ddsd.dwFlags = DDSD_CAPS;
		ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
	}
	
	// Create the primary surface.
	rval = lpDD->CreateSurface(&ddsd, &lpDDS_Primary, NULL);
	if (FAILED(rval))
	{
		vdraw_ddraw_free_all(false);
		LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
			"lpDD->CreateSurface(&lpDDS_Primary) failed: 0x%08X", rval);
		return -5;
	}
	
	if (vdraw_get_fullscreen())
	{
		if (Video.VSync_FS)
		{
			ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
			
			rval = lpDDS_Primary->GetAttachedSurface(&ddsd.ddsCaps, &lpDDS_Flip);
			if (FAILED(rval))
			{
				vdraw_ddraw_free_all(false);
				LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
					"lpDDS_Primary->GetAttachSurface() failed: 0x%08X", rval);
				return -6;
			}
			
			lpDDS_Blit = lpDDS_Flip;
		}
		else
		{
			lpDDS_Blit = lpDDS_Primary;
		}
	}
	else
	{
		rval = lpDD->CreateClipper(0, &lpDDC_Clipper, NULL);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDD->CreateClipper() failed: 0x%08X", rval);
			return -7;
		}
		
		rval = lpDDC_Clipper->SetHWnd(0, gens_window);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDDC_Clipper->SetHWnd() failed: 0x%08X", rval);
			return -8;
		}
		
		rval = lpDDS_Primary->SetClipper(lpDDC_Clipper);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDDC_Primary->SetClipper() failed: 0x%08X", rval);
			return -9;
		}
	}
	
	// Clear ddsd again.
	memset(&ddsd, 0, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);
	ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
	
	// Determine the width and height.
	// NOTE: For DirectDraw, the actual 336 width is used.
	if (vdraw_ddraw_is_hw_render())
	{
		// Normal render mode. 320x240 [336x240]
		ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
		ddsd.dwWidth = 336;
		ddsd.dwHeight = 240;
	}
	else
	{
		// Larger than 1x.
		ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
		ddsd.dwWidth = w;
		ddsd.dwHeight = h;
	}
	
	// Set the pixel format.
	ddsd.dwFlags |= DDSD_PIXELFORMAT;
	ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
	ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
	ddsd.ddpfPixelFormat.dwFourCC = 0; // RGB
	ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0;
	
	// Bits per component.
	switch (bppOut)
	{
		case 15:
			// 15-bit color. (555)
			ddsd.ddpfPixelFormat.dwRGBBitCount = 16;
			ddsd.ddpfPixelFormat.dwRBitMask = 0x7C00;
			ddsd.ddpfPixelFormat.dwGBitMask = 0x03E0;
			ddsd.ddpfPixelFormat.dwBBitMask = 0x001F;
			break;
		
		case 16:
			// 16-bit color. (555)
			ddsd.ddpfPixelFormat.dwRGBBitCount = 16;
			ddsd.ddpfPixelFormat.dwRBitMask = 0xF800;
			ddsd.ddpfPixelFormat.dwGBitMask = 0x07E0;
			ddsd.ddpfPixelFormat.dwBBitMask = 0x001F;
			break;
		
		case 32:
		default:
			// 32-bit color.
			ddsd.ddpfPixelFormat.dwRGBBitCount = 32;
			ddsd.ddpfPixelFormat.dwRBitMask = 0xFF0000;
			ddsd.ddpfPixelFormat.dwGBitMask = 0x00FF00;
			ddsd.ddpfPixelFormat.dwBBitMask = 0x0000FF;
			break;
	}
	
	// Create the back surface.
	rval = lpDD->CreateSurface(&ddsd, &lpDDS_Back, NULL);
	if (FAILED(rval))
	{
		// Failed to create the back surface.
		// If we attempted to create it in video memory, try system memory instead.
		if (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
		{
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDD->CreateSurface(&lpDDS_Back, DDSCAPS_VIDEOMEMORY) failed: 0x%08X", rval);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"Attempting to use DDSCAPS_SYSTEMMEMORY instead.");
			ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY;
			ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
			rval = lpDD->CreateSurface(&ddsd, &lpDDS_Back, NULL);
			if (FAILED(rval))
			{
				// Failed to create the back surface in system memory.
				vdraw_ddraw_free_all(false);
				LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
					"lpDD->CreateSurface(&lpDDS_Back, DDSCAPS_SYSTEMMEMORY) failed: 0x%08X", rval);
				return -10;
			}
		}
		else
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDD->CreateSurface(&lpDDS_Back, DDSCAPS_SYSTEMMEMORY) failed: 0x%08X", rval);
			return -11;
		}
	}
	
	// TODO: Check if this is right.
	// I think this might be causing the frame counter flicker in full screen mode.
	//if (!vdraw_get_fullscreen() || (rendMode >= 1 && (/*FS_No_Res_Change ||*/ Res_X != 640 || Res_Y != 480)))
	if (!vdraw_get_fullscreen() || !vdraw_ddraw_is_hw_render())
		lpDDS_Blit = lpDDS_Back;
	
	if (vdraw_ddraw_is_hw_render())
	{
		// Normal rendering mode uses MD_Screen directly.
		memset(&ddsd, 0, sizeof(ddsd));
		ddsd.dwSize = sizeof(ddsd);
		
		// TODO: This causes issues if the selected color depth isn't the
		// same as the desktop color depth. This only affects windowed mode,
		// since in fullscreen, the desktop color depth is changed.
		rval = lpDDS_Back->GetSurfaceDesc(&ddsd);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDDS_Back->GetSurfaceDesc() failed: 0x%08X", rval);
			return -12;
		}
		
		ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_LPSURFACE | DDSD_PIXELFORMAT;
		ddsd.dwWidth = 336;
		ddsd.dwHeight = 240;
		
		if (ddsd.ddpfPixelFormat.dwRGBBitCount > 16)
		{
			// 32-bit color.
			ddsd.lpSurface = MD_Screen.u32;
			ddsd.lPitch = 336 * 4;
		}
		else
		{
			// 15-bit or 16-bit color.
			ddsd.lpSurface = MD_Screen.u16;
			ddsd.lPitch = 336 * 2;
		}
		
		rval = lpDDS_Back->SetSurfaceDesc(&ddsd, 0);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDDS_Back->SetSurfaceDesc() failed: 0x%08X", rval);
			return -13;
		}
	}
	
	// Initialize the destination rectangle.
	vdraw_ddraw_adjust_RectDest();
	
	// Reset the render mode.
	vdraw_reset_renderer(false);
	
	// Synchronize menus.
	Sync_Gens_Window();
	
	// vdraw_ddraw initialized.
	return 0;
}