755 lines
20 KiB
C++
755 lines
20 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PresentEngine.cpp: Defines the D3DPresentEngine object.
|
|
//
|
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "EVRPresenter.h"
|
|
|
|
const DWORD PRESENTER_BUFFER_COUNT = 3;
|
|
|
|
HRESULT FindAdapter(IDirect3D9 *pD3D9, HMONITOR hMonitor, UINT *puAdapterID);
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Constructor
|
|
//-----------------------------------------------------------------------------
|
|
|
|
D3DPresentEngine::D3DPresentEngine(HRESULT& hr) :
|
|
m_hwnd(NULL),
|
|
m_DeviceResetToken(0),
|
|
m_pD3D9(NULL),
|
|
m_pDevice(NULL),
|
|
m_pDeviceManager(NULL),
|
|
m_pSurfaceRepaint(NULL)
|
|
{
|
|
SetRectEmpty(&m_rcDestRect);
|
|
|
|
ZeroMemory(&m_DisplayMode, sizeof(m_DisplayMode));
|
|
|
|
hr = InitializeD3D();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CreateD3DDevice();
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Destructor
|
|
//-----------------------------------------------------------------------------
|
|
|
|
D3DPresentEngine::~D3DPresentEngine()
|
|
{
|
|
SAFE_RELEASE(m_pDevice);
|
|
SAFE_RELEASE(m_pSurfaceRepaint);
|
|
SAFE_RELEASE(m_pDeviceManager);
|
|
SAFE_RELEASE(m_pD3D9);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GetService
|
|
//
|
|
// Returns a service interface from the presenter engine.
|
|
// The presenter calls this method from inside it's implementation of
|
|
// IMFGetService::GetService.
|
|
//
|
|
// Classes that derive from D3DPresentEngine can override this method to return
|
|
// other interfaces. If you override this method, call the base method from the
|
|
// derived class.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT D3DPresentEngine::GetService(REFGUID guidService, REFIID riid, void** ppv)
|
|
{
|
|
assert(ppv != NULL);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (riid == __uuidof(IDirect3DDeviceManager9))
|
|
{
|
|
if (m_pDeviceManager == NULL)
|
|
{
|
|
hr = MF_E_UNSUPPORTED_SERVICE;
|
|
}
|
|
else
|
|
{
|
|
*ppv = m_pDeviceManager;
|
|
m_pDeviceManager->AddRef();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = MF_E_UNSUPPORTED_SERVICE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CheckFormat
|
|
//
|
|
// Queries whether the D3DPresentEngine can use a specified Direct3D format.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT D3DPresentEngine::CheckFormat(D3DFORMAT format)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
UINT uAdapter = D3DADAPTER_DEFAULT;
|
|
D3DDEVTYPE type = D3DDEVTYPE_HAL;
|
|
|
|
D3DDISPLAYMODE mode;
|
|
D3DDEVICE_CREATION_PARAMETERS params;
|
|
|
|
if (m_pDevice)
|
|
{
|
|
CHECK_HR(hr = m_pDevice->GetCreationParameters(¶ms));
|
|
|
|
uAdapter = params.AdapterOrdinal;
|
|
type = params.DeviceType;
|
|
|
|
}
|
|
|
|
CHECK_HR(hr = m_pD3D9->GetAdapterDisplayMode(uAdapter, &mode));
|
|
|
|
CHECK_HR(hr = m_pD3D9->CheckDeviceType(uAdapter, type, mode.Format, format, TRUE));
|
|
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// SetVideoWindow
|
|
//
|
|
// Sets the window where the video is drawn.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT D3DPresentEngine::SetVideoWindow(HWND hwnd)
|
|
{
|
|
// Assertions: EVRCustomPresenter checks these cases.
|
|
assert(IsWindow(hwnd));
|
|
assert(hwnd != m_hwnd);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
AutoLock lock(m_ObjectLock);
|
|
|
|
m_hwnd = hwnd;
|
|
|
|
UpdateDestRect();
|
|
|
|
// Recreate the device.
|
|
hr = CreateD3DDevice();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// SetDestinationRect
|
|
//
|
|
// Sets the region within the video window where the video is drawn.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT D3DPresentEngine::SetDestinationRect(const RECT& rcDest)
|
|
{
|
|
if (EqualRect(&rcDest, &m_rcDestRect))
|
|
{
|
|
return S_OK; // No change.
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
AutoLock lock(m_ObjectLock);
|
|
|
|
m_rcDestRect = rcDest;
|
|
|
|
UpdateDestRect();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CreateVideoSamples
|
|
//
|
|
// Creates video samples based on a specified media type.
|
|
//
|
|
// pFormat: Media type that describes the video format.
|
|
// videoSampleQueue: List that will contain the video samples.
|
|
//
|
|
// Note: For each video sample, the method creates a swap chain with a
|
|
// single back buffer. The video sample object holds a pointer to the swap
|
|
// chain's back buffer surface. The mixer renders to this surface, and the
|
|
// D3DPresentEngine renders the video frame by presenting the swap chain.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT D3DPresentEngine::CreateVideoSamples(
|
|
IMFMediaType *pFormat,
|
|
VideoSampleList& videoSampleQueue
|
|
)
|
|
{
|
|
if (m_hwnd == NULL)
|
|
{
|
|
return MF_E_INVALIDREQUEST;
|
|
}
|
|
|
|
if (pFormat == NULL)
|
|
{
|
|
return MF_E_UNEXPECTED;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
D3DPRESENT_PARAMETERS pp;
|
|
|
|
IDirect3DSwapChain9 *pSwapChain = NULL; // Swap chain
|
|
IMFSample *pVideoSample = NULL; // Sampl
|
|
|
|
AutoLock lock(m_ObjectLock);
|
|
|
|
ReleaseResources();
|
|
|
|
// Get the swap chain parameters from the media type.
|
|
CHECK_HR(hr = GetSwapChainPresentParameters(pFormat, &pp));
|
|
|
|
UpdateDestRect();
|
|
|
|
// Create the video samples.
|
|
for (int i = 0; i < PRESENTER_BUFFER_COUNT; i++)
|
|
{
|
|
// Create a new swap chain.
|
|
CHECK_HR(hr = m_pDevice->CreateAdditionalSwapChain(&pp, &pSwapChain));
|
|
|
|
// Create the video sample from the swap chain.
|
|
CHECK_HR(hr = CreateD3DSample(pSwapChain, &pVideoSample));
|
|
|
|
// Add it to the list.
|
|
CHECK_HR(hr = videoSampleQueue.InsertBack(pVideoSample));
|
|
|
|
// Set the swap chain pointer as a custom attribute on the sample. This keeps
|
|
// a reference count on the swap chain, so that the swap chain is kept alive
|
|
// for the duration of the sample's lifetime.
|
|
CHECK_HR(hr = pVideoSample->SetUnknown(MFSamplePresenter_SampleSwapChain, pSwapChain));
|
|
|
|
SAFE_RELEASE(pVideoSample);
|
|
SAFE_RELEASE(pSwapChain);
|
|
}
|
|
|
|
// Let the derived class create any additional D3D resources that it needs.
|
|
CHECK_HR(hr = OnCreateVideoSamples(pp));
|
|
|
|
done:
|
|
if (FAILED(hr))
|
|
{
|
|
ReleaseResources();
|
|
}
|
|
|
|
SAFE_RELEASE(pSwapChain);
|
|
SAFE_RELEASE(pVideoSample);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ReleaseResources
|
|
//
|
|
// Released Direct3D resources used by this object.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void D3DPresentEngine::ReleaseResources()
|
|
{
|
|
// Let the derived class release any resources it created.
|
|
OnReleaseResources();
|
|
|
|
SAFE_RELEASE(m_pSurfaceRepaint);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CheckDeviceState
|
|
//
|
|
// Tests the Direct3D device state.
|
|
//
|
|
// pState: Receives the state of the device (OK, reset, removed)
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT D3DPresentEngine::CheckDeviceState(DeviceState *pState)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
AutoLock lock(m_ObjectLock);
|
|
|
|
// Check the device state. Not every failure code is a critical failure.
|
|
hr = m_pDevice->CheckDeviceState(m_hwnd);
|
|
|
|
*pState = DeviceOK;
|
|
|
|
switch (hr)
|
|
{
|
|
case S_OK:
|
|
case S_PRESENT_OCCLUDED:
|
|
case S_PRESENT_MODE_CHANGED:
|
|
// state is DeviceOK
|
|
hr = S_OK;
|
|
break;
|
|
|
|
case D3DERR_DEVICELOST:
|
|
case D3DERR_DEVICEHUNG:
|
|
// Lost/hung device. Destroy the device and create a new one.
|
|
CHECK_HR(hr = CreateD3DDevice());
|
|
*pState = DeviceReset;
|
|
hr = S_OK;
|
|
break;
|
|
|
|
case D3DERR_DEVICEREMOVED:
|
|
// This is a fatal error.
|
|
*pState = DeviceRemoved;
|
|
break;
|
|
|
|
case E_INVALIDARG:
|
|
// CheckDeviceState can return E_INVALIDARG if the window is not valid
|
|
// We'll assume that the window was destroyed; we'll recreate the device
|
|
// if the application sets a new window.
|
|
hr = S_OK;
|
|
}
|
|
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// PresentSample
|
|
//
|
|
// Presents a video frame.
|
|
//
|
|
// pSample: Pointer to the sample that contains the surface to present. If
|
|
// this parameter is NULL, the method paints a black rectangle.
|
|
// llTarget: Target presentation time.
|
|
//
|
|
// This method is called by the scheduler and/or the presenter.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT D3DPresentEngine::PresentSample(IMFSample* pSample, LONGLONG llTarget)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
IMFMediaBuffer* pBuffer = NULL;
|
|
IDirect3DSurface9* pSurface = NULL;
|
|
IDirect3DSwapChain9* pSwapChain = NULL;
|
|
|
|
if (pSample)
|
|
{
|
|
// Get the buffer from the sample.
|
|
CHECK_HR(hr = pSample->GetBufferByIndex(0, &pBuffer));
|
|
|
|
// Get the surface from the buffer.
|
|
CHECK_HR(hr = MFGetService(pBuffer, MR_BUFFER_SERVICE, __uuidof(IDirect3DSurface9), (void**)&pSurface));
|
|
}
|
|
else if (m_pSurfaceRepaint)
|
|
{
|
|
// Redraw from the last surface.
|
|
pSurface = m_pSurfaceRepaint;
|
|
pSurface->AddRef();
|
|
}
|
|
|
|
if (pSurface)
|
|
{
|
|
// Get the swap chain from the surface.
|
|
CHECK_HR(hr = pSurface->GetContainer(__uuidof(IDirect3DSwapChain9), (LPVOID*)&pSwapChain));
|
|
|
|
// Present the swap chain.
|
|
CHECK_HR(hr = PresentSwapChain(pSwapChain, pSurface));
|
|
|
|
// Store this pointer in case we need to repaint the surface.
|
|
CopyComPointer(m_pSurfaceRepaint, pSurface);
|
|
}
|
|
else
|
|
{
|
|
// No surface. All we can do is paint a black rectangle.
|
|
PaintFrameWithGDI();
|
|
}
|
|
|
|
done:
|
|
SAFE_RELEASE(pSwapChain);
|
|
SAFE_RELEASE(pSurface);
|
|
SAFE_RELEASE(pBuffer);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICENOTRESET || hr == D3DERR_DEVICEHUNG)
|
|
{
|
|
// We failed because the device was lost. Fill the destination rectangle.
|
|
PaintFrameWithGDI();
|
|
|
|
// Ignore. We need to reset or re-create the device, but this method
|
|
// is probably being called from the scheduler thread, which is not the
|
|
// same thread that created the device. The Reset(Ex) method must be
|
|
// called from the thread that created the device.
|
|
|
|
// The presenter will detect the state when it calls CheckDeviceState()
|
|
// on the next sample.
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// private/protected methods
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// InitializeD3D
|
|
//
|
|
// Initializes Direct3D and the Direct3D device manager.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT D3DPresentEngine::InitializeD3D()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
assert(m_pD3D9 == NULL);
|
|
assert(m_pDeviceManager == NULL);
|
|
|
|
// Create Direct3D
|
|
CHECK_HR(hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3D9));
|
|
|
|
// Create the device manager
|
|
CHECK_HR(hr = DXVA2CreateDirect3DDeviceManager9(&m_DeviceResetToken, &m_pDeviceManager));
|
|
|
|
done:
|
|
return hr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CreateD3DDevice
|
|
//
|
|
// Creates the Direct3D device.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT D3DPresentEngine::CreateD3DDevice()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HWND hwnd = NULL;
|
|
HMONITOR hMonitor = NULL;
|
|
UINT uAdapterID = D3DADAPTER_DEFAULT;
|
|
DWORD vp = 0;
|
|
|
|
D3DCAPS9 ddCaps;
|
|
ZeroMemory(&ddCaps, sizeof(ddCaps));
|
|
|
|
IDirect3DDevice9Ex* pDevice = NULL;
|
|
|
|
// Hold the lock because we might be discarding an exisiting device.
|
|
AutoLock lock(m_ObjectLock);
|
|
|
|
if (!m_pD3D9 || !m_pDeviceManager)
|
|
{
|
|
return MF_E_NOT_INITIALIZED;
|
|
}
|
|
|
|
hwnd = GetDesktopWindow();
|
|
|
|
// Note: The presenter creates additional swap chains to present the
|
|
// video frames. Therefore, it does not use the device's implicit
|
|
// swap chain, so the size of the back buffer here is 1 x 1.
|
|
|
|
D3DPRESENT_PARAMETERS pp;
|
|
ZeroMemory(&pp, sizeof(pp));
|
|
|
|
pp.BackBufferWidth = 1;
|
|
pp.BackBufferHeight = 1;
|
|
pp.Windowed = TRUE;
|
|
pp.SwapEffect = D3DSWAPEFFECT_COPY;
|
|
pp.BackBufferFormat = D3DFMT_UNKNOWN;
|
|
pp.hDeviceWindow = hwnd;
|
|
pp.Flags = D3DPRESENTFLAG_VIDEO;
|
|
pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
|
|
|
|
// Find the monitor for this window.
|
|
if (m_hwnd)
|
|
{
|
|
hMonitor = MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTONEAREST);
|
|
|
|
// Find the corresponding adapter.
|
|
CHECK_HR(hr = FindAdapter(m_pD3D9, hMonitor, &uAdapterID));
|
|
}
|
|
|
|
// Get the device caps for this adapter.
|
|
CHECK_HR(hr = m_pD3D9->GetDeviceCaps(uAdapterID, D3DDEVTYPE_HAL, &ddCaps));
|
|
|
|
if(ddCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
|
|
{
|
|
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
|
|
}
|
|
else
|
|
{
|
|
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
|
|
}
|
|
|
|
// Create the device.
|
|
CHECK_HR(hr = m_pD3D9->CreateDeviceEx(
|
|
uAdapterID,
|
|
D3DDEVTYPE_HAL,
|
|
pp.hDeviceWindow,
|
|
vp | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
|
|
&pp,
|
|
NULL,
|
|
&pDevice
|
|
));
|
|
|
|
// Get the adapter display mode.
|
|
CHECK_HR(hr = m_pD3D9->GetAdapterDisplayMode(uAdapterID, &m_DisplayMode));
|
|
|
|
// Reset the D3DDeviceManager with the new device
|
|
CHECK_HR(hr = m_pDeviceManager->ResetDevice(pDevice, m_DeviceResetToken));
|
|
|
|
SAFE_RELEASE(m_pDevice);
|
|
|
|
m_pDevice = pDevice;
|
|
m_pDevice->AddRef();
|
|
|
|
done:
|
|
SAFE_RELEASE(pDevice);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CreateD3DSample
|
|
//
|
|
// Creates an sample object (IMFSample) to hold a Direct3D swap chain.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT D3DPresentEngine::CreateD3DSample(IDirect3DSwapChain9 *pSwapChain, IMFSample **ppVideoSample)
|
|
{
|
|
// Caller holds the object lock.
|
|
|
|
HRESULT hr = S_OK;
|
|
D3DCOLOR clrBlack = D3DCOLOR_ARGB(0xFF, 0x00, 0x00, 0x00);
|
|
|
|
IDirect3DSurface9* pSurface = NULL;
|
|
IMFSample* pSample = NULL;
|
|
|
|
// Get the back buffer surface.
|
|
CHECK_HR(hr = pSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pSurface));
|
|
|
|
// Fill it with black.
|
|
CHECK_HR(hr = m_pDevice->ColorFill(pSurface, NULL, clrBlack));
|
|
|
|
// Create the sample.
|
|
CHECK_HR(hr = MFCreateVideoSampleFromSurface(pSurface, &pSample));
|
|
|
|
// Return the pointer to the caller.
|
|
*ppVideoSample = pSample;
|
|
(*ppVideoSample)->AddRef();
|
|
|
|
done:
|
|
SAFE_RELEASE(pSurface);
|
|
SAFE_RELEASE(pSample);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// PresentSwapChain
|
|
//
|
|
// Presents a swap chain that contains a video frame.
|
|
//
|
|
// pSwapChain: Pointer to the swap chain.
|
|
// pSurface: Pointer to the swap chain's back buffer surface.
|
|
|
|
//
|
|
// Note: This method simply calls IDirect3DSwapChain9::Present, but a derived
|
|
// class could do something fancier.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT D3DPresentEngine::PresentSwapChain(IDirect3DSwapChain9* pSwapChain, IDirect3DSurface9* pSurface)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_hwnd == NULL)
|
|
{
|
|
return MF_E_INVALIDREQUEST;
|
|
}
|
|
|
|
hr = pSwapChain->Present(NULL, &m_rcDestRect, m_hwnd, NULL, 0);
|
|
|
|
LOG_MSG_IF_FAILED(L"D3DPresentEngine::PresentSwapChain, IDirect3DSwapChain9::Present failed.", hr);
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// PaintFrameWithGDI
|
|
//
|
|
// Fills the destination rectangle with black.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void D3DPresentEngine::PaintFrameWithGDI()
|
|
{
|
|
HDC hdc = GetDC(m_hwnd);
|
|
|
|
if (hdc)
|
|
{
|
|
HBRUSH hBrush = CreateSolidBrush(RGB(0, 0, 0));
|
|
|
|
if (hBrush)
|
|
{
|
|
FillRect(hdc, &m_rcDestRect, hBrush);
|
|
DeleteObject(hBrush);
|
|
}
|
|
|
|
ReleaseDC(m_hwnd, hdc);
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GetSwapChainPresentParameters
|
|
//
|
|
// Given a media type that describes the video format, fills in the
|
|
// D3DPRESENT_PARAMETERS for creating a swap chain.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT D3DPresentEngine::GetSwapChainPresentParameters(IMFMediaType *pType, D3DPRESENT_PARAMETERS* pPP)
|
|
{
|
|
// Caller holds the object lock.
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
UINT32 width = 0, height = 0;
|
|
DWORD d3dFormat = 0;
|
|
|
|
// Helper object for reading the proposed type.
|
|
VideoType videoType(pType);
|
|
|
|
if (m_hwnd == NULL)
|
|
{
|
|
return MF_E_INVALIDREQUEST;
|
|
}
|
|
|
|
ZeroMemory(pPP, sizeof(D3DPRESENT_PARAMETERS));
|
|
|
|
// Get some information about the video format.
|
|
CHECK_HR(hr = videoType.GetFrameDimensions(&width, &height));
|
|
CHECK_HR(hr = videoType.GetFourCC(&d3dFormat));
|
|
|
|
ZeroMemory(pPP, sizeof(D3DPRESENT_PARAMETERS));
|
|
pPP->BackBufferWidth = width;
|
|
pPP->BackBufferHeight = height;
|
|
pPP->Windowed = TRUE;
|
|
pPP->SwapEffect = D3DSWAPEFFECT_COPY;
|
|
pPP->BackBufferFormat = (D3DFORMAT)d3dFormat;
|
|
pPP->hDeviceWindow = m_hwnd;
|
|
pPP->Flags = D3DPRESENTFLAG_VIDEO;
|
|
pPP->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
|
|
|
|
D3DDEVICE_CREATION_PARAMETERS params;
|
|
CHECK_HR(hr = m_pDevice->GetCreationParameters(¶ms));
|
|
|
|
if (params.DeviceType != D3DDEVTYPE_HAL)
|
|
{
|
|
pPP->Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
|
|
}
|
|
|
|
done:
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// UpdateDestRect
|
|
//
|
|
// Updates the target rectangle by clipping it to the video window's client
|
|
// area.
|
|
//
|
|
// Called whenever the application sets the video window or the destination
|
|
// rectangle.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT D3DPresentEngine::UpdateDestRect()
|
|
{
|
|
if (m_hwnd == NULL)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
RECT rcView;
|
|
GetClientRect(m_hwnd, &rcView);
|
|
|
|
// Clip the destination rectangle to the window's client area.
|
|
if (m_rcDestRect.right > rcView.right)
|
|
{
|
|
m_rcDestRect.right = rcView.right;
|
|
}
|
|
|
|
if (m_rcDestRect.bottom > rcView.bottom)
|
|
{
|
|
m_rcDestRect.bottom = rcView.bottom;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Static functions
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// FindAdapter
|
|
//
|
|
// Given a handle to a monitor, returns the ordinal number that D3D uses to
|
|
// identify the adapter.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT FindAdapter(IDirect3D9 *pD3D9, HMONITOR hMonitor, UINT *puAdapterID)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
UINT cAdapters = 0;
|
|
UINT uAdapterID = (UINT)-1;
|
|
|
|
cAdapters = pD3D9->GetAdapterCount();
|
|
for (UINT i = 0; i < cAdapters; i++)
|
|
{
|
|
HMONITOR hMonitorTmp = pD3D9->GetAdapterMonitor(i);
|
|
|
|
if (hMonitorTmp == NULL)
|
|
{
|
|
break;
|
|
}
|
|
if (hMonitorTmp == hMonitor)
|
|
{
|
|
uAdapterID = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (uAdapterID != (UINT)-1)
|
|
{
|
|
*puAdapterID = uAdapterID;
|
|
hr = S_OK;
|
|
}
|
|
return hr;
|
|
}
|