Files
renderdoc/renderdoc/driver/dxgi/dxgi_wrapped.cpp
T
baldurk 92040f4636 Fix a crash with D3D11 SWAP_EFFECT_FLIP_DISCARD swapchains. Closes #2055
* DXGI is entangled with the API unfortunately, such that for D3D11
  DXGI_SWAP_EFFECT_FLIP_DISCARD can only access buffer 0 (like
  DXGI_SWAP_EFFECT_DISCARD) but for D3D12 it can access any buffer. This is
  naturally undocumented.
2020-09-20 11:23:06 +01:00

1498 lines
40 KiB
C++

/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2019-2020 Baldur Karlsson
* Copyright (c) 2014 Crytek
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include "dxgi_wrapped.h"
#include "core/core.h"
#include "serialise/serialiser.h"
#include "dxgi_common.h"
ID3D11Resource *UnwrapDXResource(void *dxObject);
IDXGIResource *UnwrapDXGIResource(void *dxgiObject);
WRAPPED_POOL_INST(WrappedIDXGIDevice4);
rdcarray<D3DDeviceCallback> WrappedIDXGISwapChain4::m_D3DCallbacks;
ID3DDevice *GetD3DDevice(IUnknown *pDevice)
{
ID3DDevice *wrapDevice = NULL;
if(WrappedIDXGIDevice4::IsAlloc(pDevice))
wrapDevice = ((WrappedIDXGIDevice4 *)(IDXGIDevice3 *)pDevice)->GetD3DDevice();
if(wrapDevice == NULL)
wrapDevice = WrappedIDXGISwapChain4::GetD3DDevice(pDevice);
return wrapDevice;
}
bool RefCountDXGIObject::HandleWrap(REFIID riid, void **ppvObject)
{
if(ppvObject == NULL || *ppvObject == NULL)
{
RDCWARN("HandleWrap called with NULL ppvObject");
return false;
}
// unknown GUID that we only want to print once to avoid log spam
// {79D2046C-22EF-451B-9E74-2245D9C760EA}
static const GUID Unknown_uuid = {
0x79d2046c, 0x22ef, 0x451b, {0x9e, 0x74, 0x22, 0x45, 0xd9, 0xc7, 0x60, 0xea}};
// ditto
// {9B7E4C04-342C-4106-A19F-4F2704F689F0}
static const GUID ID3D10Texture2D_uuid = {
0x9b7e4c04, 0x342c, 0x4106, {0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0}};
// unknown/undocumented internal interface
// {7abb6563-02bc-47c4-8ef9-acc4795edbcf}
static const GUID IDXGIAdapterInternal2_uuid = {
0x7abb6563, 0x02bc, 0x47c4, {0x8e, 0xf9, 0xac, 0xc4, 0x79, 0x5e, 0xdb, 0xcf}};
if(riid == __uuidof(IDXGIDevice))
{
// should have been handled elsewhere, so we can properly create this device
RDCERR("Unexpected uuid in RefCountDXGIObject::HandleWrap");
return false;
}
else if(riid == __uuidof(IDXGIAdapter))
{
IDXGIAdapter *real = (IDXGIAdapter *)(*ppvObject);
*ppvObject = (IDXGIAdapter *)(new WrappedIDXGIAdapter4(real));
return true;
}
else if(riid == __uuidof(IDXGIAdapter1))
{
IDXGIAdapter1 *real = (IDXGIAdapter1 *)(*ppvObject);
*ppvObject = (IDXGIAdapter1 *)(new WrappedIDXGIAdapter4(real));
return true;
}
else if(riid == __uuidof(IDXGIAdapter2))
{
IDXGIAdapter2 *real = (IDXGIAdapter2 *)(*ppvObject);
*ppvObject = (IDXGIAdapter2 *)(new WrappedIDXGIAdapter4(real));
return true;
}
else if(riid == __uuidof(IDXGIAdapter3))
{
IDXGIAdapter3 *real = (IDXGIAdapter3 *)(*ppvObject);
*ppvObject = (IDXGIAdapter3 *)(new WrappedIDXGIAdapter4(real));
return true;
}
else if(riid == __uuidof(IDXGIAdapter4))
{
IDXGIAdapter4 *real = (IDXGIAdapter4 *)(*ppvObject);
*ppvObject = (IDXGIAdapter4 *)(new WrappedIDXGIAdapter4(real));
return true;
}
else if(riid == __uuidof(IDXGIFactory))
{
// yes I know PRECISELY how fucked up this is. Speak to microsoft - after KB2670838 the internal
// D3D11 device creation function will pass in __uuidof(IDXGIFactory) then attempt to call
// EnumDevices1 (which is in the IDXGIFactory1 vtable). Doing this *should* be safe as using a
// IDXGIFactory1 like a IDXGIFactory should all just work by definition, but there's no way to
// know now if someone trying to create a IDXGIFactory really means it or not.
IDXGIFactory *real = (IDXGIFactory *)(*ppvObject);
*ppvObject = (IDXGIFactory *)(new WrappedIDXGIFactory(real));
return true;
}
else if(riid == __uuidof(IDXGIDevice1))
{
// should have been handled elsewhere, so we can properly create this device
RDCERR("Unexpected uuid in RefCountDXGIObject::HandleWrap");
return false;
}
else if(riid == __uuidof(IDXGIFactory1))
{
IDXGIFactory1 *real = (IDXGIFactory1 *)(*ppvObject);
*ppvObject = (IDXGIFactory1 *)(new WrappedIDXGIFactory(real));
return true;
}
else if(riid == __uuidof(IDXGIFactory2))
{
IDXGIFactory2 *real = (IDXGIFactory2 *)(*ppvObject);
*ppvObject = (IDXGIFactory2 *)(new WrappedIDXGIFactory(real));
return true;
}
else if(riid == __uuidof(IDXGIFactory3))
{
IDXGIFactory3 *real = (IDXGIFactory3 *)(*ppvObject);
*ppvObject = (IDXGIFactory3 *)(new WrappedIDXGIFactory(real));
return true;
}
else if(riid == __uuidof(IDXGIFactory4))
{
IDXGIFactory4 *real = (IDXGIFactory4 *)(*ppvObject);
*ppvObject = (IDXGIFactory4 *)(new WrappedIDXGIFactory(real));
return true;
}
else if(riid == __uuidof(IDXGIFactory5))
{
IDXGIFactory5 *real = (IDXGIFactory5 *)(*ppvObject);
*ppvObject = (IDXGIFactory5 *)(new WrappedIDXGIFactory(real));
return true;
}
else if(riid == __uuidof(IDXGIFactory6))
{
IDXGIFactory6 *real = (IDXGIFactory6 *)(*ppvObject);
*ppvObject = (IDXGIFactory6 *)(new WrappedIDXGIFactory(real));
return true;
}
else if(riid == __uuidof(IDXGIFactory7))
{
IDXGIFactory7 *real = (IDXGIFactory7 *)(*ppvObject);
*ppvObject = (IDXGIFactory7 *)(new WrappedIDXGIFactory(real));
return true;
}
else if(riid == ID3D10Texture2D_uuid)
{
static bool printed = false;
if(!printed)
{
printed = true;
RDCWARN("Querying IDXGIObject for unsupported D3D10 interface: %s", ToStr(riid).c_str());
}
return false;
}
else if(riid == IDXGIAdapterInternal2_uuid)
{
static bool printed = false;
if(!printed)
{
printed = true;
RDCWARN(
"Querying IDXGIObject for unsupported/undocumented IDXGIAdapterInternal2 interface: %s",
ToStr(riid).c_str());
}
return false;
}
else if(riid == Unknown_uuid)
{
static bool printed = false;
if(!printed)
{
printed = true;
RDCWARN("Querying IDXGIObject for unknown GUID: %s", ToStr(riid).c_str());
}
}
else
{
WarnUnknownGUID("IDXGIObject", riid);
}
return false;
}
HRESULT STDMETHODCALLTYPE RefCountDXGIObject::GetParent(
/* [in] */ REFIID riid,
/* [retval][out] */ void **ppParent)
{
HRESULT ret = m_pReal->GetParent(riid, ppParent);
if(SUCCEEDED(ret))
HandleWrap(riid, ppParent);
return ret;
}
HRESULT RefCountDXGIObject::WrapQueryInterface(IUnknown *real, REFIID riid, void **ppvObject)
{
HRESULT ret = real->QueryInterface(riid, ppvObject);
if(SUCCEEDED(ret))
HandleWrap(riid, ppvObject);
return ret;
}
WrappedIDXGISwapChain4::WrappedIDXGISwapChain4(IDXGISwapChain *real, HWND w, ID3DDevice *device)
: RefCountDXGIObject(real), m_pReal(real), m_pDevice(device), m_Wnd(w)
{
DXGI_SWAP_CHAIN_DESC desc;
real->GetDesc(&desc);
m_pDevice->AddRef();
m_pReal1 = NULL;
real->QueryInterface(__uuidof(IDXGISwapChain1), (void **)&m_pReal1);
m_pReal2 = NULL;
real->QueryInterface(__uuidof(IDXGISwapChain2), (void **)&m_pReal2);
m_pReal3 = NULL;
real->QueryInterface(__uuidof(IDXGISwapChain3), (void **)&m_pReal3);
m_pReal4 = NULL;
real->QueryInterface(__uuidof(IDXGISwapChain4), (void **)&m_pReal4);
WrapBuffersAfterResize();
HWND wnd = GetHWND();
if(wnd)
{
Keyboard::AddInputWindow(WindowingSystem::Win32, wnd);
RenderDoc::Inst().AddFrameCapturer(m_pDevice->GetFrameCapturerDevice(), wnd,
m_pDevice->GetFrameCapturer());
}
// we do a 'fake' present right at the start, so that we can capture frame 1, by
// going from this fake present to the first present.
m_pDevice->FirstFrame(this);
}
WrappedIDXGISwapChain4::~WrappedIDXGISwapChain4()
{
HWND wnd = GetHWND();
if(wnd)
{
Keyboard::RemoveInputWindow(WindowingSystem::Win32, wnd);
RenderDoc::Inst().RemoveFrameCapturer(m_pDevice->GetFrameCapturerDevice(), wnd);
}
m_pDevice->ReleaseSwapchainResources(this, 0, NULL, NULL);
SAFE_RELEASE(m_pDevice);
SAFE_RELEASE(m_pReal1);
SAFE_RELEASE(m_pReal2);
SAFE_RELEASE(m_pReal3);
SAFE_RELEASE(m_pReal4);
SAFE_RELEASE(m_pReal);
}
HRESULT STDMETHODCALLTYPE WrappedIDXGISwapChain4::QueryInterface(REFIID riid, void **ppvObject)
{
if(riid == __uuidof(IDXGISwapChain))
{
AddRef();
*ppvObject = (IDXGISwapChain *)this;
return S_OK;
}
else if(riid == __uuidof(IDXGISwapChain1))
{
if(m_pReal1)
{
AddRef();
*ppvObject = (IDXGISwapChain1 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGISwapChain2))
{
if(m_pReal2)
{
AddRef();
*ppvObject = (IDXGISwapChain2 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGISwapChain3))
{
if(m_pReal3)
{
AddRef();
*ppvObject = (IDXGISwapChain3 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGISwapChain4))
{
if(m_pReal4)
{
AddRef();
*ppvObject = (IDXGISwapChain4 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else
{
WarnUnknownGUID("IDXGISwapChain", riid);
}
return RefCountDXGIObject::QueryInterface(riid, ppvObject);
}
void WrappedIDXGISwapChain4::ReleaseBuffersForResize(UINT QueueCount, IUnknown *const *ppPresentQueue,
IUnknown **unwrappedQueues)
{
m_pDevice->ReleaseSwapchainResources(this, QueueCount, ppPresentQueue, unwrappedQueues);
}
void WrappedIDXGISwapChain4::WrapBuffersAfterResize()
{
DXGI_SWAP_CHAIN_DESC desc;
m_pReal->GetDesc(&desc);
int bufCount = desc.BufferCount;
// discard swap effects only allow querying buffer 0, but only on D3D11 - on D3D12 they can (and
// must) still query the full set of buffers.
if(m_pDevice->GetFrameCapturer()->GetFrameCaptureDriver() == RDCDriver::D3D11 &&
(desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD || desc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD))
{
bufCount = 1;
}
RDCASSERT(bufCount < MAX_NUM_BACKBUFFERS);
for(int i = 0; i < MAX_NUM_BACKBUFFERS; i++)
{
m_pBackBuffers[i] = NULL;
if(i < bufCount)
{
GetBuffer(i, m_pDevice->GetBackbufferUUID(), (void **)&m_pBackBuffers[i]);
m_pDevice->NewSwapchainBuffer(m_pBackBuffers[i]);
}
}
}
HRESULT WrappedIDXGISwapChain4::ResizeBuffers(
/* [in] */ UINT BufferCount,
/* [in] */ UINT Width,
/* [in] */ UINT Height,
/* [in] */ DXGI_FORMAT NewFormat,
/* [in] */ UINT SwapChainFlags)
{
ReleaseBuffersForResize(0, NULL, NULL);
HRESULT ret = m_pReal->ResizeBuffers(BufferCount, Width, Height, NewFormat, SwapChainFlags);
WrapBuffersAfterResize();
m_LastPresentedBuffer = -1;
return ret;
}
HRESULT STDMETHODCALLTYPE WrappedIDXGISwapChain4::GetContainingOutput(IDXGIOutput **ppOutput)
{
HRESULT ret = m_pReal->GetContainingOutput(ppOutput);
if(SUCCEEDED(ret) && ppOutput && *ppOutput)
*ppOutput = (IDXGIOutput *)(new WrappedIDXGIOutput6(this, *ppOutput));
return ret;
}
HRESULT WrappedIDXGISwapChain4::ResizeBuffers1(_In_ UINT BufferCount, _In_ UINT Width,
_In_ UINT Height, _In_ DXGI_FORMAT Format,
_In_ UINT SwapChainFlags,
_In_reads_(BufferCount) const UINT *pCreationNodeMask,
_In_reads_(BufferCount)
IUnknown *const *ppPresentQueue)
{
IUnknown **unwrappedQueues = NULL;
if(ppPresentQueue)
unwrappedQueues = new IUnknown *[BufferCount];
ReleaseBuffersForResize(BufferCount, ppPresentQueue, unwrappedQueues);
HRESULT ret = m_pReal3->ResizeBuffers1(BufferCount, Width, Height, Format, SwapChainFlags,
pCreationNodeMask, unwrappedQueues);
SAFE_DELETE_ARRAY(unwrappedQueues);
WrapBuffersAfterResize();
m_LastPresentedBuffer = -1;
return ret;
}
HRESULT WrappedIDXGISwapChain4::SetFullscreenState(
/* [in] */ BOOL Fullscreen,
/* [in] */ IDXGIOutput *pTarget)
{
WrappedIDXGIOutput6 *wrappedOutput = (WrappedIDXGIOutput6 *)pTarget;
IDXGIOutput *unwrappedOutput = wrappedOutput ? wrappedOutput->GetReal() : NULL;
if(RenderDoc::Inst().GetCaptureOptions().allowFullscreen)
return m_pReal->SetFullscreenState(Fullscreen, unwrappedOutput);
return S_OK;
}
HRESULT WrappedIDXGISwapChain4::GetFullscreenState(
/* [out] */ BOOL *pFullscreen,
/* [out] */ IDXGIOutput **ppTarget)
{
HRESULT ret = m_pReal->GetFullscreenState(pFullscreen, ppTarget);
if(SUCCEEDED(ret) && ppTarget && *ppTarget)
*ppTarget = (IDXGIOutput *)(new WrappedIDXGIOutput6(this, *ppTarget));
return ret;
}
HRESULT WrappedIDXGISwapChain4::GetBuffer(
/* [in] */ UINT Buffer,
/* [in] */ REFIID riid,
/* [out][in] */ void **ppSurface)
{
if(ppSurface == NULL)
return E_INVALIDARG;
// ID3D10Texture2D UUID {9B7E4C04-342C-4106-A19F-4F2704F689F0}
static const GUID ID3D10Texture2D_uuid = {
0x9b7e4c04, 0x342c, 0x4106, {0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0}};
// ID3D10Resource UUID {9B7E4C01-342C-4106-A19F-4F2704F689F0}
static const GUID ID3D10Resource_uuid = {
0x9b7e4c01, 0x342c, 0x4106, {0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0}};
IID uuid = riid;
if(uuid == ID3D10Texture2D_uuid || uuid == ID3D10Resource_uuid)
{
RDCERR("Querying swapchain buffers via D3D10 interface UUIDs is not supported");
return E_NOINTERFACE;
}
else if(uuid == __uuidof(IDXGISurface))
{
RDCWARN("Querying swapchain buffer for IDXGISurface. This query is ambiguous.");
// query as native format so that wrapping works as expected
uuid = m_pDevice->GetBackbufferUUID();
}
else if(uuid != __uuidof(ID3D11Texture2D) && uuid != __uuidof(ID3D11Texture2D1) &&
uuid != __uuidof(ID3D11Resource) && uuid != __uuidof(ID3D12Resource) &&
uuid != __uuidof(ID3D12Resource1))
{
RDCERR("Unsupported or unrecognised UUID passed to IDXGISwapChain::GetBuffer - %s",
ToStr(uuid).c_str());
return E_NOINTERFACE;
}
RDCASSERT(uuid == __uuidof(ID3D11Texture2D) || uuid == __uuidof(ID3D11Texture2D1) ||
uuid == __uuidof(ID3D11Resource) || uuid == __uuidof(ID3D12Resource) ||
uuid == __uuidof(ID3D12Resource1));
HRESULT ret = m_pReal->GetBuffer(Buffer, uuid, ppSurface);
{
IUnknown *realSurface = (IUnknown *)*ppSurface;
IUnknown *tex = realSurface;
if(FAILED(ret))
{
RDCERR("Failed to get swapchain backbuffer %d: HRESULT: %s", Buffer, ToStr(ret).c_str());
SAFE_RELEASE(realSurface);
tex = NULL;
}
else
{
DXGI_SWAP_CHAIN_DESC desc;
GetDesc(&desc);
tex = m_pDevice->WrapSwapchainBuffer(this, desc.BufferDesc.Format, Buffer, realSurface);
}
// if the original UUID was IDXGISurface, fixup for the expected interface being returned
if(tex && riid == __uuidof(IDXGISurface))
{
IDXGISurface *surf = NULL;
HRESULT hr = tex->QueryInterface(__uuidof(IDXGISurface), (void **)&surf);
RDCASSERTEQUAL(hr, S_OK);
tex->Release();
tex = surf;
}
*ppSurface = tex;
}
return ret;
}
HRESULT WrappedIDXGISwapChain4::GetDevice(
/* [in] */ REFIID riid,
/* [retval][out] */ void **ppDevice)
{
HRESULT ret = m_pReal->GetDevice(riid, ppDevice);
if(SUCCEEDED(ret))
{
// try one of the trivial wraps, we don't mind making a new one of those
if(m_pDevice->IsDeviceUUID(riid))
{
// probably they're asking for the device device.
*ppDevice = m_pDevice->GetDeviceInterface(riid);
m_pDevice->AddRef();
}
else if(riid == __uuidof(IDXGISwapChain))
{
// don't think anyone would try this, but what the hell.
*ppDevice = this;
AddRef();
}
else if(!HandleWrap(riid, ppDevice))
{
// can probably get away with returning the real result here,
// but it worries me a bit.
RDCUNIMPLEMENTED("Not returning trivial type");
}
}
return ret;
}
HRESULT WrappedIDXGISwapChain4::Present(
/* [in] */ UINT SyncInterval,
/* [in] */ UINT Flags)
{
if(!RenderDoc::Inst().GetCaptureOptions().allowVSync)
{
SyncInterval = 0;
}
if((Flags & DXGI_PRESENT_TEST) == 0)
{
TickLastPresentedBuffer();
m_pDevice->Present(this, SyncInterval, Flags);
}
return m_pReal->Present(SyncInterval, Flags);
}
HRESULT WrappedIDXGISwapChain4::Present1(UINT SyncInterval, UINT Flags,
const DXGI_PRESENT_PARAMETERS *pPresentParameters)
{
if(!RenderDoc::Inst().GetCaptureOptions().allowVSync)
{
SyncInterval = 0;
}
if((Flags & DXGI_PRESENT_TEST) == 0)
{
TickLastPresentedBuffer();
m_pDevice->Present(this, SyncInterval, Flags);
}
return m_pReal1->Present1(SyncInterval, Flags, pPresentParameters);
}
HRESULT STDMETHODCALLTYPE WrappedIDXGISwapChain4::GetRestrictToOutput(IDXGIOutput **ppRestrictToOutput)
{
HRESULT ret = m_pReal1->GetRestrictToOutput(ppRestrictToOutput);
if(SUCCEEDED(ret) && ppRestrictToOutput && *ppRestrictToOutput)
*ppRestrictToOutput = (IDXGIOutput *)(new WrappedIDXGIOutput6(this, *ppRestrictToOutput));
return ret;
}
WrappedIDXGIOutput6::WrappedIDXGIOutput6(RefCountDXGIObject *owner, IDXGIOutput *real)
: RefCountDXGIObject(real), m_Owner(owner), m_pReal(real)
{
SAFE_ADDREF(m_Owner);
m_pReal1 = NULL;
real->QueryInterface(__uuidof(IDXGIOutput1), (void **)&m_pReal1);
m_pReal2 = NULL;
real->QueryInterface(__uuidof(IDXGIOutput2), (void **)&m_pReal2);
m_pReal3 = NULL;
real->QueryInterface(__uuidof(IDXGIOutput3), (void **)&m_pReal3);
m_pReal4 = NULL;
real->QueryInterface(__uuidof(IDXGIOutput4), (void **)&m_pReal4);
m_pReal5 = NULL;
real->QueryInterface(__uuidof(IDXGIOutput5), (void **)&m_pReal5);
m_pReal6 = NULL;
real->QueryInterface(__uuidof(IDXGIOutput6), (void **)&m_pReal6);
}
WrappedIDXGIOutput6::~WrappedIDXGIOutput6()
{
SAFE_RELEASE(m_pReal1);
SAFE_RELEASE(m_pReal2);
SAFE_RELEASE(m_pReal3);
SAFE_RELEASE(m_pReal4);
SAFE_RELEASE(m_pReal5);
SAFE_RELEASE(m_pReal6);
SAFE_RELEASE(m_pReal);
SAFE_RELEASE(m_Owner);
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIOutput6::FindClosestMatchingMode(
const DXGI_MODE_DESC *pModeToMatch, DXGI_MODE_DESC *pClosestMatch, IUnknown *pConcernedDevice)
{
ID3DDevice *wrapDevice = GetD3DDevice(pConcernedDevice);
if(wrapDevice)
return m_pReal->FindClosestMatchingMode(pModeToMatch, pClosestMatch,
wrapDevice->GetRealIUnknown());
if(pConcernedDevice)
RDCERR("Unrecognised device in FindClosestMatchingMode()");
return E_INVALIDARG;
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIOutput6::TakeOwnership(IUnknown *pDevice, BOOL Exclusive)
{
ID3DDevice *wrapDevice = GetD3DDevice(pDevice);
if(wrapDevice)
return m_pReal->TakeOwnership(wrapDevice->GetRealIUnknown(), Exclusive);
// since this is supposed to be an internal function, allow passing through the pointer directly
// just in case
return m_pReal->TakeOwnership(pDevice, Exclusive);
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIOutput6::FindClosestMatchingMode1(
const DXGI_MODE_DESC1 *pModeToMatch, DXGI_MODE_DESC1 *pClosestMatch, IUnknown *pConcernedDevice)
{
ID3DDevice *wrapDevice = GetD3DDevice(pConcernedDevice);
if(wrapDevice)
return m_pReal1->FindClosestMatchingMode1(pModeToMatch, pClosestMatch,
wrapDevice->GetRealIUnknown());
if(pConcernedDevice)
RDCERR("Unrecognised device in FindClosestMatchingMode1()");
return E_INVALIDARG;
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIOutput6::GetDisplaySurfaceData1(IDXGIResource *pDestination)
{
return m_pReal1->GetDisplaySurfaceData1(UnwrapDXGIResource(pDestination));
}
HRESULT STDMETHODCALLTYPE
WrappedIDXGIOutput6::DuplicateOutput(IUnknown *pDevice, IDXGIOutputDuplication **ppOutputDuplication)
{
if(!ppOutputDuplication)
return E_INVALIDARG;
ID3DDevice *wrapDevice = GetD3DDevice(pDevice);
if(wrapDevice)
{
IDXGIOutputDuplication *dup = NULL;
HRESULT ret = m_pReal1->DuplicateOutput(wrapDevice->GetRealIUnknown(), &dup);
if(SUCCEEDED(ret) && dup)
dup = new WrappedIDXGIOutputDuplication(wrapDevice, dup);
*ppOutputDuplication = dup;
return ret;
}
if(pDevice)
RDCERR("Unrecognised device in DuplicateOutput()");
return E_INVALIDARG;
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIOutput6::CheckOverlaySupport(DXGI_FORMAT EnumFormat,
IUnknown *pConcernedDevice,
UINT *pFlags)
{
ID3DDevice *wrapDevice = GetD3DDevice(pConcernedDevice);
if(wrapDevice)
return m_pReal3->CheckOverlaySupport(EnumFormat, wrapDevice->GetRealIUnknown(), pFlags);
if(pConcernedDevice)
RDCERR("Unrecognised device in CheckOverlaySupport()");
return E_INVALIDARG;
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIOutput6::DuplicateOutput1(
IUnknown *pDevice, UINT Flags, UINT SupportedFormatsCount, const DXGI_FORMAT *pSupportedFormats,
IDXGIOutputDuplication **ppOutputDuplication)
{
if(!ppOutputDuplication)
return E_INVALIDARG;
ID3DDevice *wrapDevice = GetD3DDevice(pDevice);
if(wrapDevice)
{
IDXGIOutputDuplication *dup = NULL;
HRESULT ret = m_pReal5->DuplicateOutput1(wrapDevice->GetRealIUnknown(), Flags,
SupportedFormatsCount, pSupportedFormats, &dup);
if(SUCCEEDED(ret) && dup)
dup = new WrappedIDXGIOutputDuplication(wrapDevice, dup);
*ppOutputDuplication = dup;
return ret;
}
if(pDevice)
RDCERR("Unrecognised device in DuplicateOutput()");
return E_INVALIDARG;
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIOutput6::QueryInterface(REFIID riid, void **ppvObject)
{
if(riid == __uuidof(IDXGIOutput))
{
AddRef();
*ppvObject = (IDXGIOutput *)this;
return S_OK;
}
else if(riid == __uuidof(IDXGIOutput1))
{
if(m_pReal1)
{
AddRef();
*ppvObject = (IDXGIOutput1 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIOutput2))
{
if(m_pReal2)
{
AddRef();
*ppvObject = (IDXGIOutput2 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIOutput3))
{
if(m_pReal3)
{
AddRef();
*ppvObject = (IDXGIOutput3 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIOutput4))
{
if(m_pReal4)
{
AddRef();
*ppvObject = (IDXGIOutput4 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIOutput5))
{
if(m_pReal5)
{
AddRef();
*ppvObject = (IDXGIOutput5 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIOutput6))
{
if(m_pReal6)
{
AddRef();
*ppvObject = (IDXGIOutput6 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else
{
WarnUnknownGUID("IDXGIOutput", riid);
}
return RefCountDXGIObject::QueryInterface(riid, ppvObject);
}
WrappedIDXGIAdapter4::WrappedIDXGIAdapter4(IDXGIAdapter *real)
: RefCountDXGIObject(real), m_pReal(real)
{
m_pReal1 = NULL;
real->QueryInterface(__uuidof(IDXGIAdapter1), (void **)&m_pReal1);
m_pReal2 = NULL;
real->QueryInterface(__uuidof(IDXGIAdapter2), (void **)&m_pReal2);
m_pReal3 = NULL;
real->QueryInterface(__uuidof(IDXGIAdapter3), (void **)&m_pReal3);
m_pReal4 = NULL;
real->QueryInterface(__uuidof(IDXGIAdapter4), (void **)&m_pReal4);
}
WrappedIDXGIAdapter4::~WrappedIDXGIAdapter4()
{
SAFE_RELEASE(m_pReal1);
SAFE_RELEASE(m_pReal2);
SAFE_RELEASE(m_pReal3);
SAFE_RELEASE(m_pReal4);
SAFE_RELEASE(m_pReal);
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIAdapter4::QueryInterface(REFIID riid, void **ppvObject)
{
if(riid == __uuidof(IDXGIAdapter))
{
AddRef();
*ppvObject = (IDXGIAdapter *)this;
return S_OK;
}
else if(riid == __uuidof(IDXGIAdapter1))
{
if(m_pReal1)
{
AddRef();
*ppvObject = (IDXGIAdapter1 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIAdapter2))
{
if(m_pReal2)
{
AddRef();
*ppvObject = (IDXGIAdapter2 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIAdapter3))
{
if(m_pReal3)
{
AddRef();
*ppvObject = (IDXGIAdapter3 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIAdapter4))
{
if(m_pReal3)
{
AddRef();
*ppvObject = (IDXGIAdapter4 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else
{
WarnUnknownGUID("IDXGIAdapter", riid);
}
return RefCountDXGIObject::QueryInterface(riid, ppvObject);
}
WrappedIDXGIDevice4::WrappedIDXGIDevice4(IDXGIDevice *real, ID3DDevice *d3d)
: RefCountDXGIObject(real), m_pReal(real), m_pD3DDevice(d3d)
{
m_pD3DDevice->AddRef();
m_pReal1 = NULL;
real->QueryInterface(__uuidof(IDXGIDevice1), (void **)&m_pReal1);
m_pReal2 = NULL;
real->QueryInterface(__uuidof(IDXGIDevice2), (void **)&m_pReal2);
m_pReal3 = NULL;
real->QueryInterface(__uuidof(IDXGIDevice3), (void **)&m_pReal3);
m_pReal4 = NULL;
real->QueryInterface(__uuidof(IDXGIDevice4), (void **)&m_pReal4);
}
WrappedIDXGIDevice4::~WrappedIDXGIDevice4()
{
SAFE_RELEASE(m_pReal1);
SAFE_RELEASE(m_pReal2);
SAFE_RELEASE(m_pReal3);
SAFE_RELEASE(m_pReal4);
SAFE_RELEASE(m_pReal);
SAFE_RELEASE(m_pD3DDevice);
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIDevice4::QueryInterface(REFIID riid, void **ppvObject)
{
if(m_pD3DDevice->IsDeviceUUID(riid))
{
m_pD3DDevice->AddRef();
*ppvObject = m_pD3DDevice->GetDeviceInterface(riid);
return S_OK;
}
else if(riid == __uuidof(ID3D11Multithread))
{
// forward to the device as the lock is shared amongst all things
return m_pD3DDevice->QueryInterface(riid, ppvObject);
}
else if(riid == __uuidof(IDXGIDevice))
{
AddRef();
*ppvObject = (IDXGIDevice *)this;
return S_OK;
}
else if(riid == __uuidof(IDXGIDevice1))
{
if(m_pReal1)
{
AddRef();
*ppvObject = (IDXGIDevice1 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIDevice2))
{
if(m_pReal2)
{
AddRef();
*ppvObject = (IDXGIDevice2 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIDevice3))
{
if(m_pReal3)
{
AddRef();
*ppvObject = (IDXGIDevice3 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIDevice4))
{
if(m_pReal4)
{
AddRef();
*ppvObject = (IDXGIDevice4 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else
{
WarnUnknownGUID("IDXGIDevice", riid);
}
return RefCountDXGIObject::QueryInterface(riid, ppvObject);
}
rdcarray<IDXGIResource *> UnwrapResourceSet(UINT NumResources, IDXGIResource *const *ppResources)
{
rdcarray<IDXGIResource *> resources;
resources.resize(NumResources);
for(UINT i = 0; i < NumResources; i++)
{
WrappedDXGIInterface<WrappedIDXGIOutput6> *wrapped =
(WrappedDXGIInterface<WrappedIDXGIOutput6> *)ppResources[i];
resources[i] = UnwrapDXGIResource(wrapped->GetWrapped());
if(resources[i] == NULL)
{
RDCERR("Unrecognised resource %p!", ppResources[i]);
resources[i] = ppResources[i];
}
}
return resources;
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIDevice4::OfferResources(UINT NumResources,
IDXGIResource *const *ppResources,
DXGI_OFFER_RESOURCE_PRIORITY Priority)
{
rdcarray<IDXGIResource *> resources = UnwrapResourceSet(NumResources, ppResources);
return m_pReal2->OfferResources(NumResources, resources.data(), Priority);
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIDevice4::ReclaimResources(UINT NumResources,
IDXGIResource *const *ppResources,
BOOL *pDiscarded)
{
rdcarray<IDXGIResource *> resources = UnwrapResourceSet(NumResources, ppResources);
return m_pReal2->ReclaimResources(NumResources, resources.data(), pDiscarded);
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIDevice4::OfferResources1(UINT NumResources,
IDXGIResource *const *ppResources,
DXGI_OFFER_RESOURCE_PRIORITY Priority,
UINT Flags)
{
rdcarray<IDXGIResource *> resources = UnwrapResourceSet(NumResources, ppResources);
return m_pReal4->OfferResources1(NumResources, resources.data(), Priority, Flags);
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIDevice4::ReclaimResources1(UINT NumResources,
IDXGIResource *const *ppResources,
DXGI_RECLAIM_RESOURCE_RESULTS *pResults)
{
rdcarray<IDXGIResource *> resources = UnwrapResourceSet(NumResources, ppResources);
return m_pReal4->ReclaimResources1(NumResources, resources.data(), pResults);
}
WrappedIDXGIFactory::WrappedIDXGIFactory(IDXGIFactory *real)
: RefCountDXGIObject(real), m_pReal(real)
{
m_pReal1 = NULL;
real->QueryInterface(__uuidof(IDXGIFactory1), (void **)&m_pReal1);
m_pReal2 = NULL;
real->QueryInterface(__uuidof(IDXGIFactory2), (void **)&m_pReal2);
m_pReal3 = NULL;
real->QueryInterface(__uuidof(IDXGIFactory3), (void **)&m_pReal3);
m_pReal4 = NULL;
real->QueryInterface(__uuidof(IDXGIFactory4), (void **)&m_pReal4);
m_pReal5 = NULL;
real->QueryInterface(__uuidof(IDXGIFactory5), (void **)&m_pReal5);
m_pReal6 = NULL;
real->QueryInterface(__uuidof(IDXGIFactory6), (void **)&m_pReal6);
m_pReal7 = NULL;
real->QueryInterface(__uuidof(IDXGIFactory7), (void **)&m_pReal7);
}
WrappedIDXGIFactory::~WrappedIDXGIFactory()
{
SAFE_RELEASE(m_pReal1);
SAFE_RELEASE(m_pReal2);
SAFE_RELEASE(m_pReal3);
SAFE_RELEASE(m_pReal4);
SAFE_RELEASE(m_pReal5);
SAFE_RELEASE(m_pReal6);
SAFE_RELEASE(m_pReal7);
SAFE_RELEASE(m_pReal);
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIFactory::QueryInterface(REFIID riid, void **ppvObject)
{
// {713f394e-92ca-47e7-ab81-1159c2791e54}
static const GUID IDXGIFactoryDWM_uuid = {
0x713f394e, 0x92ca, 0x47e7, {0xab, 0x81, 0x11, 0x59, 0xc2, 0x79, 0x1e, 0x54}};
// {1ddd77aa-9a4a-4cc8-9e55-98c196bafc8f}
static const GUID IDXGIFactoryDWM8_uuid = {
0x1ddd77aa, 0x9a4a, 0x4cc8, {0x9e, 0x55, 0x98, 0xc1, 0x96, 0xba, 0xfc, 0x8f}};
if(riid == __uuidof(IDXGIFactory))
{
AddRef();
*ppvObject = (IDXGIFactory *)this;
return S_OK;
}
else if(riid == __uuidof(IDXGIFactory1))
{
if(m_pReal1)
{
AddRef();
*ppvObject = (IDXGIFactory1 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIFactory2))
{
if(m_pReal2)
{
AddRef();
*ppvObject = (IDXGIFactory2 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIFactory3))
{
if(m_pReal3)
{
AddRef();
*ppvObject = (IDXGIFactory3 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIFactory4))
{
if(m_pReal4)
{
AddRef();
*ppvObject = (IDXGIFactory4 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIFactory5))
{
if(m_pReal5)
{
AddRef();
*ppvObject = (IDXGIFactory5 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIFactory6))
{
if(m_pReal6)
{
AddRef();
*ppvObject = (IDXGIFactory6 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == __uuidof(IDXGIFactory7))
{
if(m_pReal7)
{
AddRef();
*ppvObject = (IDXGIFactory7 *)this;
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
else if(riid == IDXGIFactoryDWM_uuid)
{
RDCWARN("Blocking QueryInterface for IDXGIFactoryDWM");
return E_NOINTERFACE;
}
else if(riid == IDXGIFactoryDWM8_uuid)
{
RDCWARN("Blocking QueryInterface for IDXGIFactoryDWM8");
return E_NOINTERFACE;
}
else
{
WarnUnknownGUID("IDXGIFactory", riid);
}
return RefCountDXGIObject::QueryInterface(riid, ppvObject);
}
HRESULT WrappedIDXGIFactory::CreateSwapChain(IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc,
IDXGISwapChain **ppSwapChain)
{
ID3DDevice *wrapDevice = GetD3DDevice(pDevice);
if(wrapDevice)
{
DXGI_SWAP_CHAIN_DESC local = {};
DXGI_SWAP_CHAIN_DESC *desc = NULL;
if(pDesc)
{
local = *pDesc;
desc = &local;
}
local.BufferUsage |= DXGI_USAGE_RENDER_TARGET_OUTPUT;
if(!RenderDoc::Inst().GetCaptureOptions().allowFullscreen)
local.Windowed = TRUE;
HRESULT ret = m_pReal->CreateSwapChain(wrapDevice->GetRealIUnknown(), desc, ppSwapChain);
if(SUCCEEDED(ret))
{
*ppSwapChain =
new WrappedIDXGISwapChain4(*ppSwapChain, desc ? desc->OutputWindow : NULL, wrapDevice);
}
return ret;
}
RDCERR("Creating swap chain with non-hooked device!");
return m_pReal->CreateSwapChain(pDevice, pDesc, ppSwapChain);
}
HRESULT WrappedIDXGIFactory::CreateSwapChainForHwnd(
IUnknown *pDevice, HWND hWnd, const DXGI_SWAP_CHAIN_DESC1 *pDesc,
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc, IDXGIOutput *pRestrictToOutput,
IDXGISwapChain1 **ppSwapChain)
{
ID3DDevice *wrapDevice = GetD3DDevice(pDevice);
WrappedIDXGIOutput6 *wrappedOutput = (WrappedIDXGIOutput6 *)pRestrictToOutput;
IDXGIOutput *unwrappedOutput = wrappedOutput ? wrappedOutput->GetReal() : NULL;
if(wrapDevice)
{
DXGI_SWAP_CHAIN_DESC1 local;
DXGI_SWAP_CHAIN_DESC1 *desc = NULL;
if(pDesc)
{
local = *pDesc;
desc = &local;
}
local.BufferUsage |= DXGI_USAGE_RENDER_TARGET_OUTPUT;
if(!RenderDoc::Inst().GetCaptureOptions().allowFullscreen && pFullscreenDesc)
{
pFullscreenDesc = NULL;
}
HRESULT ret = m_pReal2->CreateSwapChainForHwnd(wrapDevice->GetRealIUnknown(), hWnd, desc,
pFullscreenDesc, unwrappedOutput, ppSwapChain);
if(SUCCEEDED(ret))
{
*ppSwapChain = new WrappedIDXGISwapChain4(*ppSwapChain, hWnd, wrapDevice);
}
return ret;
}
else
{
RDCERR("Creating swap chain with non-hooked device!");
}
return m_pReal2->CreateSwapChainForHwnd(pDevice, hWnd, pDesc, pFullscreenDesc, unwrappedOutput,
ppSwapChain);
}
HRESULT WrappedIDXGIFactory::CreateSwapChainForCoreWindow(IUnknown *pDevice, IUnknown *pWindow,
const DXGI_SWAP_CHAIN_DESC1 *pDesc,
IDXGIOutput *pRestrictToOutput,
IDXGISwapChain1 **ppSwapChain)
{
ID3DDevice *wrapDevice = GetD3DDevice(pDevice);
WrappedIDXGIOutput6 *wrappedOutput = (WrappedIDXGIOutput6 *)pRestrictToOutput;
IDXGIOutput *unwrappedOutput = wrappedOutput ? wrappedOutput->GetReal() : NULL;
if(!RenderDoc::Inst().GetCaptureOptions().allowFullscreen)
{
RDCWARN("Impossible to disallow fullscreen on call to CreateSwapChainForCoreWindow");
}
if(wrapDevice)
{
DXGI_SWAP_CHAIN_DESC1 local = {};
DXGI_SWAP_CHAIN_DESC1 *desc = NULL;
if(pDesc)
{
local = *pDesc;
desc = &local;
}
local.BufferUsage |= DXGI_USAGE_RENDER_TARGET_OUTPUT;
HRESULT ret = m_pReal2->CreateSwapChainForCoreWindow(wrapDevice->GetRealIUnknown(), pWindow,
desc, unwrappedOutput, ppSwapChain);
if(SUCCEEDED(ret))
{
HWND wnd = NULL;
(*ppSwapChain)->GetHwnd(&wnd);
if(wnd == NULL)
wnd = (HWND)pWindow;
*ppSwapChain = new WrappedIDXGISwapChain4(*ppSwapChain, wnd, wrapDevice);
}
return ret;
}
else
{
RDCERR("Creating swap chain with non-hooked device!");
}
return m_pReal2->CreateSwapChainForCoreWindow(pDevice, pWindow, pDesc, unwrappedOutput,
ppSwapChain);
}
HRESULT WrappedIDXGIFactory::CreateSwapChainForComposition(IUnknown *pDevice,
const DXGI_SWAP_CHAIN_DESC1 *pDesc,
IDXGIOutput *pRestrictToOutput,
IDXGISwapChain1 **ppSwapChain)
{
ID3DDevice *wrapDevice = GetD3DDevice(pDevice);
WrappedIDXGIOutput6 *wrappedOutput = (WrappedIDXGIOutput6 *)pRestrictToOutput;
IDXGIOutput *unwrappedOutput = wrappedOutput ? wrappedOutput->GetReal() : NULL;
if(!RenderDoc::Inst().GetCaptureOptions().allowFullscreen)
{
RDCWARN("Impossible to disallow fullscreen on call to CreateSwapChainForComposition");
}
if(wrapDevice)
{
DXGI_SWAP_CHAIN_DESC1 local = {};
DXGI_SWAP_CHAIN_DESC1 *desc = NULL;
if(pDesc)
{
local = *pDesc;
desc = &local;
}
local.BufferUsage |= DXGI_USAGE_RENDER_TARGET_OUTPUT;
HRESULT ret = m_pReal2->CreateSwapChainForComposition(wrapDevice->GetRealIUnknown(), desc,
unwrappedOutput, ppSwapChain);
if(SUCCEEDED(ret))
{
HWND wnd = NULL;
(*ppSwapChain)->GetHwnd(&wnd);
if(wnd == NULL)
wnd = (HWND)0x1;
*ppSwapChain = new WrappedIDXGISwapChain4(*ppSwapChain, wnd, wrapDevice);
}
return ret;
}
else
{
RDCERR("Creating swap chain with non-hooked device!");
}
return m_pReal2->CreateSwapChainForComposition(pDevice, pDesc, unwrappedOutput, ppSwapChain);
}
WrappedIDXGIOutputDuplication::WrappedIDXGIOutputDuplication(ID3DDevice *device,
IDXGIOutputDuplication *real)
: RefCountDXGIObject(real), m_Device(device), m_pReal(real)
{
}
WrappedIDXGIOutputDuplication::~WrappedIDXGIOutputDuplication()
{
SAFE_RELEASE(m_pReal);
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIOutputDuplication::AcquireNextFrame(
UINT TimeoutInMilliseconds, DXGI_OUTDUPL_FRAME_INFO *pFrameInfo, IDXGIResource **ppDesktopResource)
{
if(!ppDesktopResource)
return E_INVALIDARG;
IDXGIResource *desktop = NULL;
HRESULT ret = m_pReal->AcquireNextFrame(TimeoutInMilliseconds, pFrameInfo, &desktop);
if(SUCCEEDED(ret) && desktop)
desktop = m_Device->WrapExternalDXGIResource(desktop);
*ppDesktopResource = desktop;
return ret;
}
HRESULT STDMETHODCALLTYPE WrappedIDXGIOutputDuplication::QueryInterface(REFIID riid, void **ppvObject)
{
if(riid == __uuidof(IDXGIOutputDuplication))
{
AddRef();
*ppvObject = (IDXGIOutputDuplication *)this;
return S_OK;
}
else
{
WarnUnknownGUID("IDXGIOutputDuplication", riid);
}
return RefCountDXGIObject::QueryInterface(riid, ppvObject);
}