Skip to content

Instantly share code, notes, and snippets.

@axjxwright
Created August 18, 2021 06:35
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save axjxwright/7271a465e666335251e384519d8aefc3 to your computer and use it in GitHub Desktop.
//ciWMFVideoplayer addon written by Philippe Laulheret for Second Story (secondstory.com)
//Based upon Windows SDK samples
//MIT Licensing
//////////////////////////////////////////////////////////////////////////
//
// 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"
#include "cinder/app/App.h"
#include "cinder/Surface.h"
#include "cinder/gl/gl.h"
#include "cinder/Log.h"
#include "glad/glad_wgl.h"
#include "ciWMFVideoPlayer.h"
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),
gl_handleD3D(NULL),
d3d_shared_texture(NULL),
d3d_shared_surface(NULL),
d3d_system_surface(NULL)
{
SetRectEmpty(&m_rcDestRect);
ZeroMemory(&m_DisplayMode, sizeof(m_DisplayMode));
hr = InitializeD3D();
if (SUCCEEDED(hr))
{
hr = CreateD3DDevice();
}
//bool nvdxInteropEnabled = false;
//if(wglewIsSupported("WGL_NV_DX_interop"))
//{
// nvdxInteropEnabled = true;
//}
}
//-----------------------------------------------------------------------------
// Destructor
//-----------------------------------------------------------------------------
D3DPresentEngine::~D3DPresentEngine()
{
if (gl_handleD3D) {
releaseSharedTexture() ;
CI_LOG_I("Killing present engine.....");
if (wglDXCloseDeviceNV(gl_handleD3D))
{
CI_LOG_I( "SUCCESS" );
}
else {
CI_LOG_I( "FAILED closing handle" );
}
}
SAFE_RELEASE(m_pDevice);
SAFE_RELEASE(m_pSurfaceRepaint);
SAFE_RELEASE(m_pDeviceManager);
SAFE_RELEASE(m_pD3D9);
}
//-----------------------------------------------------------------------------
// Texture sharing code
//-----------------------------------------------------------------------------
bool D3DPresentEngine::createSharedTexture(int w, int h, int textureID)
{
_w = w;
_h = h;
if (gl_handleD3D == NULL ) gl_handleD3D = wglDXOpenDeviceNV(m_pDevice);
if (!gl_handleD3D)
{
CI_LOG_E( "Opening the shared device failed - Create SharedTexture Failed" );
return false;
}
gl_name=textureID;
HANDLE sharedHandle = NULL; //We need to create a shared handle for the ressource, otherwise the extension fails on ATI/Intel cards
HRESULT hr = m_pDevice->CreateTexture(w,h,1,D3DUSAGE_RENDERTARGET,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&d3d_shared_texture,&sharedHandle);
if (FAILED(hr))
{
CI_LOG_E( "Error creating D3DTexture" );
return false;
}
if (!sharedHandle)
{
CI_LOG_E( "Error creating D3D shared handle" );
return false;
}
wglDXSetResourceShareHandleNV(d3d_shared_texture,sharedHandle);
d3d_shared_texture->GetSurfaceLevel(0,&d3d_shared_surface);
if ( FAILED ( m_pDevice->CreateOffscreenPlainSurface ( w, h, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &d3d_system_surface, nullptr ) ) )
{
CI_LOG_E ( "Error creating system surface" );
return false;
}
gl_handle = wglDXRegisterObjectNV(gl_handleD3D, d3d_shared_texture,
gl_name,
GL_TEXTURE_RECTANGLE,
WGL_ACCESS_READ_ONLY_NV);
if (!gl_handle)
{
CI_LOG_E("Opening the shared texture failed - Create SharedTexture Failed");
return false;
}
return true;
}
void D3DPresentEngine::releaseSharedTexture()
{
if (!gl_handleD3D) return;
wglDXUnlockObjectsNV(gl_handleD3D, 1, &gl_handle);
//wglDXUnregisterObjectNV(gl_handleD3D,gl_handle); // Apparently causes access violations?
//glDeleteTextures(1, &gl_name);
SAFE_RELEASE(d3d_shared_surface);
SAFE_RELEASE(d3d_shared_texture);
SAFE_RELEASE ( d3d_system_surface );
}
bool D3DPresentEngine::lockSharedTexture()
{
if (!gl_handleD3D) return false;
if (!gl_handle) return false;
return wglDXLockObjectsNV(gl_handleD3D, 1, &gl_handle);
}
bool D3DPresentEngine::unlockSharedTexture()
{
if (!gl_handleD3D) return false;
if (!gl_handle) return false;
return wglDXUnlockObjectsNV(gl_handleD3D, 1, &gl_handle);
}
//-----------------------------------------------------------------------------
// 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(&params));
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
{
CI_LOG_W("Software Cap, No bueno :P");
//printf("Software cap, no bueno\n");
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)
{
//-----------------------------------------------------------------------------
// Copy latest D3D frame to our OpenGL/D3D shared surface...
//pSwapChain->GetFrontBufferData(d3d_shared_surface);
IDirect3DSurface9 *surface;
pSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&surface);
if (m_pDevice->StretchRect(surface,NULL,d3d_shared_surface,NULL,D3DTEXF_NONE) != D3D_OK)
{
CI_LOG_E("Error while copying texture to gl context");
//printf("ciWMFVideoplayer: Error while copying texture to gl context \n");
}
SAFE_RELEASE(surface);
{
HRESULT hr = m_pDevice->GetRenderTargetData ( d3d_shared_surface, d3d_system_surface );
if ( SUCCEEDED ( hr ) )
{
D3DLOCKED_RECT lockedRect;
hr = d3d_system_surface->LockRect ( &lockedRect, nullptr, D3DLOCK_READONLY );
if ( SUCCEEDED ( hr ) )
{
D3DSURFACE_DESC desc;
d3d_system_surface->GetDesc ( &desc );
ci::Surface8uRef surface = ci::Surface8u::create ( (uint8_t *)lockedRect.pBits, desc.Width, desc.Height, lockedRect.Pitch, ci::SurfaceChannelOrder::BGRA );
d3d_system_surface->UnlockRect ( );
// Here you'd need to somehow notify the main thread
// that a new surface is available. Since `surface` doesn't
// own the data exposed by the D3DLOCKED_RECT then you'll
// likely need to copy it or make sure it's handled before
// d3d_system_surface->UnlockRect ( ); is called (I think)
}
}
}
//-----------------------------------------------------------------------------
// Original code from the WMF EVRpresenter sample code...
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(&params));
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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment