From 5334ff57bff0521bf3ad5b22ccd7f8c405aea6c9 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sun, 18 Feb 2018 22:34:23 +0100 Subject: [PATCH] [d3d11] Wired up D3D11Query to backend --- src/d3d11/d3d11_context.cpp | 36 +++++++- src/d3d11/d3d11_device.cpp | 27 +++++- src/d3d11/d3d11_query.cpp | 164 +++++++++++++++++++++++++++--------- src/d3d11/d3d11_query.h | 20 ++++- src/dxvk/dxvk_query.cpp | 2 +- src/dxvk/dxvk_query.h | 2 +- 6 files changed, 203 insertions(+), 48 deletions(-) diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 5b81d1790..d0b83ba57 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -150,12 +150,40 @@ namespace dxvk { void STDMETHODCALLTYPE D3D11DeviceContext::Begin(ID3D11Asynchronous *pAsync) { -// Logger::err("D3D11DeviceContext::Begin: Not implemented"); + Com query; + + if (SUCCEEDED(pAsync->QueryInterface(__uuidof(ID3D11Query), reinterpret_cast(&query)))) { + Com queryPtr = static_cast(query.ptr()); + + if (queryPtr->HasBeginEnabled()) { + const uint32_t revision = queryPtr->Reset(); + + EmitCs([revision, queryPtr] (DxvkContext* ctx) { + queryPtr->Begin(ctx, revision); + }); + } + } } void STDMETHODCALLTYPE D3D11DeviceContext::End(ID3D11Asynchronous *pAsync) { -// Logger::err("D3D11DeviceContext::End: Not implemented"); + Com query; + + if (SUCCEEDED(pAsync->QueryInterface(__uuidof(ID3D11Query), reinterpret_cast(&query)))) { + Com queryPtr = static_cast(query.ptr()); + + if (queryPtr->HasBeginEnabled()) { + EmitCs([queryPtr] (DxvkContext* ctx) { + queryPtr->End(ctx); + }); + } else { + const uint32_t revision = queryPtr->Reset(); + + EmitCs([revision, queryPtr] (DxvkContext* ctx) { + queryPtr->Signal(ctx, revision); + }); + } + } } @@ -174,6 +202,10 @@ namespace dxvk { return E_INVALIDARG; } + // Flush in order to make sure the query commands get dispatched + if ((GetDataFlags & D3D11_ASYNC_GETDATA_DONOTFLUSH) == 0) + Flush(); + // This method handles various different but incompatible interfaces, // so we have to find out what we are actually dealing with Com query; diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index 81589a737..184385f85 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -1086,9 +1086,19 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE D3D11Device::CreateQuery( const D3D11_QUERY_DESC* pQueryDesc, ID3D11Query** ppQuery) { + if (pQueryDesc->Query != D3D11_QUERY_EVENT + && pQueryDesc->Query != D3D11_QUERY_OCCLUSION + && pQueryDesc->Query != D3D11_QUERY_TIMESTAMP + && pQueryDesc->Query != D3D11_QUERY_TIMESTAMP_DISJOINT + && pQueryDesc->Query != D3D11_QUERY_PIPELINE_STATISTICS + && pQueryDesc->Query != D3D11_QUERY_OCCLUSION_PREDICATE) { + Logger::warn(str::format("D3D11Query: Unsupported query type ", pQueryDesc->Query)); + return E_INVALIDARG; + } + if (ppQuery == nullptr) return S_FALSE; - + try { *ppQuery = ref(new D3D11Query(this, *pQueryDesc)); return S_OK; @@ -1102,8 +1112,19 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE D3D11Device::CreatePredicate( const D3D11_QUERY_DESC* pPredicateDesc, ID3D11Predicate** ppPredicate) { - Logger::err("D3D11Device::CreatePredicate: Not implemented"); - return E_NOTIMPL; + if (pPredicateDesc->Query != D3D11_QUERY_OCCLUSION_PREDICATE) + return E_INVALIDARG; + + if (ppPredicate == nullptr) + return S_FALSE; + + try { + *ppPredicate = ref(new D3D11Query(this, *pPredicateDesc)); + return S_OK; + } catch (const DxvkError& e) { + Logger::err(e.message()); + return E_FAIL; + } } diff --git a/src/d3d11/d3d11_query.cpp b/src/d3d11/d3d11_query.cpp index 50d47c625..8330f733f 100644 --- a/src/d3d11/d3d11_query.cpp +++ b/src/d3d11/d3d11_query.cpp @@ -7,19 +7,29 @@ namespace dxvk { D3D11Device* device, const D3D11_QUERY_DESC& desc) : m_device(device), m_desc(desc) { - switch (desc.Query) { - // Other query types are currently unsupported + switch (m_desc.Query) { case D3D11_QUERY_EVENT: - case D3D11_QUERY_OCCLUSION: - case D3D11_QUERY_TIMESTAMP: - case D3D11_QUERY_TIMESTAMP_DISJOINT: - case D3D11_QUERY_OCCLUSION_PREDICATE: + m_event = new DxvkEvent(); break; - + + case D3D11_QUERY_OCCLUSION: + case D3D11_QUERY_OCCLUSION_PREDICATE: + m_query = new DxvkQuery(VK_QUERY_TYPE_OCCLUSION); + break; + + case D3D11_QUERY_TIMESTAMP: + m_query = new DxvkQuery(VK_QUERY_TYPE_TIMESTAMP); + break; + + case D3D11_QUERY_TIMESTAMP_DISJOINT: + break; + + case D3D11_QUERY_PIPELINE_STATISTICS: + m_query = new DxvkQuery(VK_QUERY_TYPE_PIPELINE_STATISTICS); + break; + default: - static bool errorShown = false; - if (!std::exchange(errorShown, true)) - Logger::warn(str::format("D3D11Query: Unsupported query type ", desc.Query)); + throw DxvkError(str::format("D3D11: Unhandled query type: ", desc.Query)); } } @@ -35,6 +45,9 @@ namespace dxvk { COM_QUERY_IFACE(riid, ppvObject, ID3D11Asynchronous); COM_QUERY_IFACE(riid, ppvObject, ID3D11Query); + if (m_desc.Query == D3D11_QUERY_OCCLUSION_PREDICATE) + COM_QUERY_IFACE(riid, ppvObject, ID3D11Predicate); + Logger::warn("D3D11Query: Unknown interface query"); return E_NOINTERFACE; } @@ -90,41 +103,112 @@ namespace dxvk { } + uint32_t D3D11Query::Reset() { + if (m_query != nullptr) + return m_query->reset(); + + if (m_event != nullptr) + return m_event->reset(); + + return 0; + } + + + bool D3D11Query::HasBeginEnabled() const { + return m_desc.Query == D3D11_QUERY_OCCLUSION + || m_desc.Query == D3D11_QUERY_OCCLUSION_PREDICATE + || m_desc.Query == D3D11_QUERY_PIPELINE_STATISTICS; + } + + + void D3D11Query::Begin(DxvkContext* ctx, uint32_t revision) { + m_revision = revision; + + if (m_query != nullptr) { + DxvkQueryRevision rev = { m_query, revision }; + ctx->beginQuery(rev); + } + } + + + void D3D11Query::End(DxvkContext* ctx) { + if (m_query != nullptr) { + DxvkQueryRevision rev = { m_query, m_revision }; + ctx->endQuery(rev); + } + } + + + void D3D11Query::Signal(DxvkContext* ctx, uint32_t revision) { + switch (m_desc.Query) { + case D3D11_QUERY_TIMESTAMP: { + DxvkQueryRevision rev = { m_query, m_revision }; + ctx->writeTimestamp(rev); + } break; + + default: + break; + } + } + + HRESULT STDMETHODCALLTYPE D3D11Query::GetData( void* pData, UINT GetDataFlags) { - static bool errorShown = false; - static UINT64 fakeTimestamp = 0; - - if (!std::exchange(errorShown, true)) - Logger::warn("D3D11Query::GetData: Stub"); - - if (pData == nullptr) - return S_OK; - - switch (m_desc.Query) { - case D3D11_QUERY_EVENT: - *static_cast(pData) = TRUE; - return S_OK; - - case D3D11_QUERY_OCCLUSION: - *static_cast(pData) = 1; - return S_OK; - - case D3D11_QUERY_TIMESTAMP: - *static_cast(pData) = fakeTimestamp++; - return S_OK; - - case D3D11_QUERY_TIMESTAMP_DISJOINT: - static_cast(pData)->Frequency = 1000; - static_cast(pData)->Disjoint = FALSE; - return S_OK; - - case D3D11_QUERY_OCCLUSION_PREDICATE: - *static_cast(pData) = TRUE; + Logger::info(str::format(m_desc.Query)); + if (m_desc.Query == D3D11_QUERY_EVENT) { + const bool signaled = m_event->getStatus() == DxvkEventStatus::Signaled; + if (pData != nullptr) + *static_cast(pData) = signaled; + + return signaled ? S_OK : S_FALSE; + } else { + DxvkQueryData queryData = {}; + + if (m_query->getData(queryData) != DxvkQueryStatus::Available) + return S_FALSE; + + if (pData == nullptr) return S_OK; + + switch (m_desc.Query) { + case D3D11_QUERY_OCCLUSION: + *static_cast(pData) = queryData.occlusion.samplesPassed; + return S_OK; - default: return E_INVALIDARG; + case D3D11_QUERY_OCCLUSION_PREDICATE: + *static_cast(pData) = queryData.occlusion.samplesPassed != 0; + return S_OK; + + case D3D11_QUERY_TIMESTAMP: + *static_cast(pData) = queryData.timestamp.time; + return S_OK; + + case D3D11_QUERY_TIMESTAMP_DISJOINT: { + auto data = static_cast(pData); + data->Frequency = 1000; + data->Disjoint = FALSE; + } return S_OK; + + case D3D11_QUERY_PIPELINE_STATISTICS: { + auto data = static_cast(pData); + data->IAVertices = queryData.statistic.iaVertices; + data->IAPrimitives = queryData.statistic.iaPrimitives; + data->VSInvocations = queryData.statistic.vsInvocations; + data->GSInvocations = queryData.statistic.gsInvocations; + data->GSPrimitives = queryData.statistic.gsPrimitives; + data->CInvocations = queryData.statistic.clipInvocations; + data->CPrimitives = queryData.statistic.clipPrimitives; + data->PSInvocations = queryData.statistic.fsInvocations; + data->HSInvocations = queryData.statistic.tcsPatches; + data->DSInvocations = queryData.statistic.tesInvocations; + data->CSInvocations = queryData.statistic.csInvocations; + } return S_OK; + + default: + Logger::err(str::format("D3D11: Unhandled query type in GetData: ", m_desc.Query)); + return E_INVALIDARG; + } } } diff --git a/src/d3d11/d3d11_query.h b/src/d3d11/d3d11_query.h index 682a210de..7d4d48e6c 100644 --- a/src/d3d11/d3d11_query.h +++ b/src/d3d11/d3d11_query.h @@ -2,9 +2,12 @@ #include "d3d11_device_child.h" +#include "../dxvk/dxvk_event.h" +#include "../dxvk/dxvk_query.h" + namespace dxvk { - class D3D11Query : public D3D11DeviceChild { + class D3D11Query : public D3D11DeviceChild { public: @@ -26,6 +29,16 @@ namespace dxvk { void STDMETHODCALLTYPE GetDesc( D3D11_QUERY_DESC *pDesc) final; + uint32_t Reset(); + + bool HasBeginEnabled() const; + + void Begin(DxvkContext* ctx, uint32_t revision); + + void End(DxvkContext* ctx); + + void Signal(DxvkContext* ctx, uint32_t revision); + HRESULT STDMETHODCALLTYPE GetData( void* pData, UINT GetDataFlags); @@ -35,6 +48,11 @@ namespace dxvk { D3D11Device* const m_device; D3D11_QUERY_DESC m_desc; + Rc m_query = nullptr; + Rc m_event = nullptr; + + uint32_t m_revision = 0; + }; } diff --git a/src/dxvk/dxvk_query.cpp b/src/dxvk/dxvk_query.cpp index c90e13502..b7f6a4170 100644 --- a/src/dxvk/dxvk_query.cpp +++ b/src/dxvk/dxvk_query.cpp @@ -13,7 +13,7 @@ namespace dxvk { } - uint32_t DxvkQuery::invalidate() { + uint32_t DxvkQuery::reset() { std::unique_lock lock(m_mutex); m_status = DxvkQueryStatus::Reset; diff --git a/src/dxvk/dxvk_query.h b/src/dxvk/dxvk_query.h index 118df0463..e71d3219f 100644 --- a/src/dxvk/dxvk_query.h +++ b/src/dxvk/dxvk_query.h @@ -113,7 +113,7 @@ namespace dxvk { * will take the revision number as an argument. * \returns The new query revision number */ - uint32_t invalidate(); + uint32_t reset(); /** * \brief Retrieves query data