/PresentEngine.cpp Secret
Created
August 18, 2021 06:35
Star
You must be signed in to star a gist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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(¶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 | |
{ | |
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(¶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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment