Allow any UUID in DXGI swapchain GetBuffer()

* The only requirements are that we can get the interface as the one we want
  (ID3D11Texture or ID3D12Resource) so we query it straight away as that first.
  Then we also need to be able to convert from that to whatever the user
  requested, so we do that as a second step.
* Because this is all undocumented it's unknown if there's any combination of
  UUIDs that would fail this but might make sense in a different order (e.g.
  queried as the user's UUID first and then we fetch our interface off that).
This commit is contained in:
baldurk
2021-01-28 12:29:16 +00:00
parent 76fabedbe6
commit 3ac5b9a842
+31 -63
View File
@@ -462,81 +462,49 @@ HRESULT WrappedIDXGISwapChain4::GetBuffer(
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)
if(riid == ID3D10Texture2D_uuid || riid == ID3D10Resource_uuid)
{
RDCERR("Querying swapchain buffers via D3D10 interface UUIDs is not supported");
return E_NOINTERFACE;
}
else if(uuid == __uuidof(IDXGISurface) || uuid == __uuidof(IDXGIObject) ||
uuid == __uuidof(IUnknown))
{
RDCWARN("Querying swapchain buffer for ambiguous UUID.");
// 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))
IUnknown *unwrappedBackbuffer = NULL;
// query as the device's native backbuffer format
HRESULT ret =
m_pReal->GetBuffer(Buffer, m_pDevice->GetBackbufferUUID(), (void **)&unwrappedBackbuffer);
// if this fails we can't continue, the wrapping below assumes it's a native resource
if(FAILED(ret))
{
RDCERR("Unsupported or unrecognised UUID passed to IDXGISwapChain::GetBuffer - %s",
ToStr(uuid).c_str());
return E_NOINTERFACE;
RDCERR("Failed to get swapchain backbuffer %d as %s: HRESULT: %s", Buffer,
ToStr(m_pDevice->GetBackbufferUUID()).c_str(), ToStr(ret).c_str());
SAFE_RELEASE(unwrappedBackbuffer);
return ret;
}
HRESULT ret = m_pReal->GetBuffer(Buffer, uuid, ppSurface);
DXGI_SWAP_CHAIN_DESC desc;
GetDesc(&desc);
// this wraps and takes the reference, so unwrappedBackbuffer no longer holds a reference
IUnknown *wrappedBackbuffer =
m_pDevice->WrapSwapchainBuffer(this, desc.BufferDesc.Format, Buffer, unwrappedBackbuffer);
unwrappedBackbuffer = NULL;
// now query the original UUID the user wanted
ret = wrappedBackbuffer->QueryInterface(riid, ppSurface);
if(FAILED(ret) || *ppSurface == NULL)
{
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;
}
else if(tex && riid == __uuidof(IDXGIObject))
{
IDXGIObject *obj = NULL;
HRESULT hr = tex->QueryInterface(__uuidof(IDXGIObject), (void **)&obj);
RDCASSERTEQUAL(hr, S_OK);
tex->Release();
tex = obj;
}
else if(tex && riid == __uuidof(IUnknown))
{
IUnknown *obj = NULL;
HRESULT hr = tex->QueryInterface(__uuidof(IUnknown), (void **)&obj);
RDCASSERTEQUAL(hr, S_OK);
tex->Release();
tex = obj;
}
*ppSurface = tex;
RDCERR("Couldn't convert wrapped swapchain backbuffer %d to %s: HRESULT: %s", Buffer,
ToStr(riid).c_str(), ToStr(ret).c_str());
SAFE_RELEASE(wrappedBackbuffer);
return ret;
}
// now the reference is in ppSurface
SAFE_RELEASE(wrappedBackbuffer);
return ret;
}