diff --git a/src/d3d11/d3d11_blend.cpp b/src/d3d11/d3d11_blend.cpp index 6e56c385..90aeb478 100644 --- a/src/d3d11/d3d11_blend.cpp +++ b/src/d3d11/d3d11_blend.cpp @@ -21,7 +21,7 @@ namespace dxvk { m_msState.sampleMask = 0; // Set during bind m_msState.enableAlphaToCoverage = desc.AlphaToCoverageEnable; m_msState.enableAlphaToOne = VK_FALSE; - m_msState.enableSampleShading = VK_TRUE; + m_msState.enableSampleShading = VK_FALSE; m_msState.minSampleShading = 0.0f; // In 11_0, there is no logic op state. Later versions diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 5b81d179..d0b83ba5 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_context_imm.cpp b/src/d3d11/d3d11_context_imm.cpp index d6e068bd..cccbafc3 100644 --- a/src/d3d11/d3d11_context_imm.cpp +++ b/src/d3d11/d3d11_context_imm.cpp @@ -41,21 +41,23 @@ namespace dxvk { void STDMETHODCALLTYPE D3D11ImmediateContext::Flush() { - m_parent->FlushInitContext(); - m_drawCount = 0; - - // Add commands to flush the threaded - // context, then flush the command list - EmitCs([dev = m_device] (DxvkContext* ctx) { - dev->submitCommandList( - ctx->endRecording(), - nullptr, nullptr); + if (m_csChunk->commandCount() != 0) { + m_parent->FlushInitContext(); + m_drawCount = 0; - ctx->beginRecording( - dev->createCommandList()); - }); - - FlushCsChunk(); + // Add commands to flush the threaded + // context, then flush the command list + EmitCs([dev = m_device] (DxvkContext* ctx) { + dev->submitCommandList( + ctx->endRecording(), + nullptr, nullptr); + + ctx->beginRecording( + dev->createCommandList()); + }); + + FlushCsChunk(); + } } diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index 81589a73..184385f8 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 50d47c62..998311ec 100644 --- a/src/d3d11/d3d11_query.cpp +++ b/src/d3d11/d3d11_query.cpp @@ -7,19 +7,37 @@ 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: + m_query = new DxvkQuery( + VK_QUERY_TYPE_OCCLUSION, + VK_QUERY_CONTROL_PRECISE_BIT); + break; + + case D3D11_QUERY_OCCLUSION_PREDICATE: + m_query = new DxvkQuery( + VK_QUERY_TYPE_OCCLUSION, 0); + break; + + case D3D11_QUERY_TIMESTAMP: + m_query = new DxvkQuery( + VK_QUERY_TYPE_TIMESTAMP, 0); + break; + + case D3D11_QUERY_TIMESTAMP_DISJOINT: + break; + + case D3D11_QUERY_PIPELINE_STATISTICS: + m_query = new DxvkQuery( + VK_QUERY_TYPE_PIPELINE_STATISTICS, 0); + 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 +53,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 +111,118 @@ 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_EVENT: { + DxvkEventRevision rev = { m_event, revision }; + ctx->signalEvent(rev); + } break; + + case D3D11_QUERY_TIMESTAMP: { + DxvkQueryRevision rev = { m_query, 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; + 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 != nullptr + && 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: { + // FIXME return correct frequency + 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 682a210d..7d4d48e6 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_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index b449d72c..695ab56b 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -4,6 +4,7 @@ #include "dxvk_binding.h" #include "dxvk_descriptor.h" +#include "dxvk_event_tracker.h" #include "dxvk_lifetime.h" #include "dxvk_limits.h" #include "dxvk_pipelayout.h" @@ -85,12 +86,32 @@ namespace dxvk { m_queryTracker.trackQueryRange(std::move(queries)); } + /** + * \brief Adds an event revision to track + * + * The event will be signaled after the command + * buffer has finished executing on the GPU. + */ + void trackEvent(const DxvkEventRevision& event) { + m_eventTracker.trackEvent(event); + } + + /** + * \brief Signals tracked events + * + * Marks all tracked events as signaled. Call this after + * synchronizing with a fence for this command list. + */ + void signalEvents() { + m_eventTracker.signalEvents(); + } + /** * \brief Writes back query results * - * Uses the query range to write back query data - * after the command list has finished executing - * on the GPU. + * Writes back query data to all queries tracked by the + * query range tracker. Call this after synchronizing + * with a fence for this command list. */ void writeQueryData() { m_queryTracker.writeQueryData(); @@ -486,6 +507,7 @@ namespace dxvk { DxvkDescriptorAlloc m_descAlloc; DxvkStagingAlloc m_stagingAlloc; DxvkQueryTracker m_queryTracker; + DxvkEventTracker m_eventTracker; }; diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index b415ed01..4056f6e9 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -73,7 +73,7 @@ namespace dxvk { m_cmd->cmdBeginQuery( handle.queryPool, handle.queryId, - 0); + handle.flags); query.query->beginRecording(query.revision); this->insertActiveQuery(query); @@ -1201,6 +1201,11 @@ namespace dxvk { } + void DxvkContext::signalEvent(const DxvkEventRevision& event) { + m_cmd->trackEvent(event); + } + + void DxvkContext::writeTimestamp(const DxvkQueryRevision& query) { DxvkQueryHandle handle = this->allocQuery(query); @@ -1631,7 +1636,7 @@ namespace dxvk { DxvkQueryHandle DxvkContext::allocQuery(const DxvkQueryRevision& query) { const VkQueryType queryType = query.query->type(); - DxvkQueryHandle queryHandle = { VK_NULL_HANDLE, 0 }; + DxvkQueryHandle queryHandle = DxvkQueryHandle(); Rc queryPool = m_queryPools[queryType]; if (queryPool != nullptr) @@ -1676,7 +1681,7 @@ namespace dxvk { m_cmd->cmdBeginQuery( handle.queryPool, handle.queryId, - 0); + handle.flags); } } diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 0a4d0447..41f91624 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -5,6 +5,8 @@ #include "dxvk_cmdlist.h" #include "dxvk_context_state.h" #include "dxvk_data.h" +#include "dxvk_event.h" +#include "dxvk_query.h" #include "dxvk_query_pool.h" #include "dxvk_util.h" @@ -542,6 +544,13 @@ namespace dxvk { uint32_t attachment, const DxvkBlendMode& blendMode); + /** + * \brief Signals an event + * \param [in] event The event + */ + void signalEvent( + const DxvkEventRevision& event); + /** * \brief Writes to a timestamp query * \param [in] query The timestamp query diff --git a/src/dxvk/dxvk_event.cpp b/src/dxvk/dxvk_event.cpp index 1bf2099c..0f2aff70 100644 --- a/src/dxvk/dxvk_event.cpp +++ b/src/dxvk/dxvk_event.cpp @@ -14,13 +14,11 @@ namespace dxvk { } - void DxvkEvent::signalEvent(uint32_t revision) { + void DxvkEvent::signal(uint32_t revision) { std::unique_lock lock(m_mutex); - if (m_revision == revision) { + if (m_revision == revision) m_status = DxvkEventStatus::Signaled; - m_signal.notify_one(); - } } diff --git a/src/dxvk/dxvk_event.h b/src/dxvk/dxvk_event.h index d9df247c..325e1cea 100644 --- a/src/dxvk/dxvk_event.h +++ b/src/dxvk/dxvk_event.h @@ -1,12 +1,14 @@ #pragma once -#include #include #include "dxvk_include.h" namespace dxvk { + /** + * \brief Event status + */ enum class DxvkEventStatus { Reset = 0, Signaled = 1, @@ -36,7 +38,7 @@ namespace dxvk { * \brief Signals the event * \param [in] revision The revision ID */ - void signalEvent(uint32_t revision); + void signal(uint32_t revision); /** * \brief Queries event status @@ -46,12 +48,22 @@ namespace dxvk { private: - std::mutex m_mutex; - std::condition_variable m_signal; + std::mutex m_mutex; DxvkEventStatus m_status = DxvkEventStatus::Reset; uint32_t m_revision = 0; }; + /** + * \brief Event revision + * + * Stores the event object and the + * version ID for event operations. + */ + struct DxvkEventRevision { + Rc event; + uint32_t revision; + }; + } \ No newline at end of file diff --git a/src/dxvk/dxvk_event_tracker.cpp b/src/dxvk/dxvk_event_tracker.cpp new file mode 100644 index 00000000..09eb6840 --- /dev/null +++ b/src/dxvk/dxvk_event_tracker.cpp @@ -0,0 +1,30 @@ +#include "dxvk_event_tracker.h" + +namespace dxvk { + + DxvkEventTracker::DxvkEventTracker() { + + } + + + DxvkEventTracker::~DxvkEventTracker() { + + } + + + void DxvkEventTracker::trackEvent(const DxvkEventRevision& event) { + m_events.push_back(event); + } + + + void DxvkEventTracker::signalEvents() { + for (const DxvkEventRevision& event : m_events) + event.event->signal(event.revision); + } + + + void DxvkEventTracker::reset() { + m_events.clear(); + } + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_event_tracker.h b/src/dxvk/dxvk_event_tracker.h new file mode 100644 index 00000000..2939678a --- /dev/null +++ b/src/dxvk/dxvk_event_tracker.h @@ -0,0 +1,45 @@ +#pragma once + +#include "dxvk_event.h" + +namespace dxvk { + + /** + * \brief Event tracker + */ + class DxvkEventTracker { + + public: + + DxvkEventTracker(); + ~DxvkEventTracker(); + + /** + * \brief Adds an event to track + * \param [in] event The event revision + */ + void trackEvent(const DxvkEventRevision& event); + + /** + * \brief Signals tracked events + * + * Retrieves query data from the query pools + * and writes it back to the query objects. + */ + void signalEvents(); + + /** + * \brief Resets event tracker + * + * Releases all events from the tracker. + * Call this after signaling the events. + */ + void reset(); + + private: + + std::vector m_events; + + }; + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_query.cpp b/src/dxvk/dxvk_query.cpp index c90e1350..520b3928 100644 --- a/src/dxvk/dxvk_query.cpp +++ b/src/dxvk/dxvk_query.cpp @@ -2,8 +2,10 @@ namespace dxvk { - DxvkQuery::DxvkQuery(VkQueryType type) - : m_type(type) { + DxvkQuery::DxvkQuery( + VkQueryType type, + VkQueryControlFlags flags) + : m_type(type), m_flags(flags) { } @@ -13,7 +15,7 @@ namespace dxvk { } - uint32_t DxvkQuery::invalidate() { + uint32_t DxvkQuery::reset() { std::unique_lock lock(m_mutex); m_status = DxvkQueryStatus::Reset; @@ -57,7 +59,6 @@ namespace dxvk { m_status = DxvkQueryStatus::Pending; } else { m_status = DxvkQueryStatus::Available; - m_signal.notify_all(); } m_handle = DxvkQueryHandle(); @@ -110,10 +111,8 @@ namespace dxvk { Logger::err(str::format("DxvkQuery: Unhandled query type: ", m_type)); } - if (++m_queryIndex == m_queryCount && m_status == DxvkQueryStatus::Pending) { + if (++m_queryIndex == m_queryCount && m_status == DxvkQueryStatus::Pending) m_status = DxvkQueryStatus::Available; - m_signal.notify_all(); - } } } diff --git a/src/dxvk/dxvk_query.h b/src/dxvk/dxvk_query.h index 118df046..bf4fc410 100644 --- a/src/dxvk/dxvk_query.h +++ b/src/dxvk/dxvk_query.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include "dxvk_limits.h" @@ -78,8 +77,9 @@ namespace dxvk { * index of a single Vulkan query. */ struct DxvkQueryHandle { - VkQueryPool queryPool = VK_NULL_HANDLE; - uint32_t queryId = 0; + VkQueryPool queryPool = VK_NULL_HANDLE; + uint32_t queryId = 0; + VkQueryControlFlags flags = 0; }; /** @@ -93,7 +93,9 @@ namespace dxvk { public: - DxvkQuery(VkQueryType type); + DxvkQuery( + VkQueryType type, + VkQueryControlFlags flags); ~DxvkQuery(); /** @@ -104,6 +106,17 @@ namespace dxvk { return m_type; } + /** + * \brief Query control flags + * + * Flags that will be applied when + * calling \c vkCmdBeginQuery. + * \returns Query control flags + */ + VkQueryControlFlags flags() const { + return m_flags; + } + /** * \brief Resets the query object * @@ -113,7 +126,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 @@ -172,10 +185,10 @@ namespace dxvk { private: - const VkQueryType m_type; + const VkQueryType m_type; + const VkQueryControlFlags m_flags; - std::mutex m_mutex; - std::condition_variable m_signal; + std::mutex m_mutex; DxvkQueryStatus m_status = DxvkQueryStatus::Reset; DxvkQueryData m_data = {}; diff --git a/src/dxvk/dxvk_query_pool.cpp b/src/dxvk/dxvk_query_pool.cpp index 31826ee6..ac4f5e66 100644 --- a/src/dxvk/dxvk_query_pool.cpp +++ b/src/dxvk/dxvk_query_pool.cpp @@ -48,7 +48,10 @@ namespace dxvk { const uint32_t queryIndex = m_queryRangeOffset + m_queryRangeLength; if (queryIndex < m_queryCount) { - const DxvkQueryHandle result = { m_queryPool, queryIndex }; + DxvkQueryHandle result; + result.queryPool = m_queryPool; + result.queryId = queryIndex; + result.flags = query.query->flags(); query.query->associateQuery(query.revision, result); m_queries.at(queryIndex) = query; @@ -56,7 +59,7 @@ namespace dxvk { m_queryRangeLength += 1; return result; } else { - return DxvkQueryHandle { VK_NULL_HANDLE, 0 }; + return DxvkQueryHandle(); } } diff --git a/src/dxvk/dxvk_query_pool.h b/src/dxvk/dxvk_query_pool.h index 2c3110f7..cd6c4953 100644 --- a/src/dxvk/dxvk_query_pool.h +++ b/src/dxvk/dxvk_query_pool.h @@ -9,8 +9,6 @@ namespace dxvk { /** * \brief Query range - * - * */ struct DxvkQueryRange { Rc queryPool; diff --git a/src/dxvk/dxvk_queue.cpp b/src/dxvk/dxvk_queue.cpp index 26a2fb95..b1497ce2 100644 --- a/src/dxvk/dxvk_queue.cpp +++ b/src/dxvk/dxvk_queue.cpp @@ -58,7 +58,9 @@ namespace dxvk { entry.fence->wait(std::numeric_limits::max()); entry.cmdList->writeQueryData(); + entry.cmdList->signalEvents(); entry.cmdList->reset(); + m_device->recycleCommandList(entry.cmdList); } } diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index 2e1317a4..37b8824a 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -17,6 +17,7 @@ dxvk_src = files([ 'dxvk_device.cpp', 'dxvk_extensions.cpp', 'dxvk_event.cpp', + 'dxvk_event_tracker.cpp', 'dxvk_format.cpp', 'dxvk_framebuffer.cpp', 'dxvk_graphics.cpp', diff --git a/tests/d3d11/test_d3d11_triangle.cpp b/tests/d3d11/test_d3d11_triangle.cpp index 797c3011..258d825d 100644 --- a/tests/d3d11/test_d3d11_triangle.cpp +++ b/tests/d3d11/test_d3d11_triangle.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include "../test_utils.h" using namespace dxvk; @@ -242,6 +244,12 @@ public: &m_vertexFormat))) throw DxvkError("Failed to create input layout"); + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = D3D11_QUERY_OCCLUSION; + queryDesc.MiscFlags = 0; + + if (FAILED(m_device->CreateQuery(&queryDesc, &m_query))) + throw DxvkError("Failed to create occlusion query"); } @@ -275,11 +283,13 @@ public: UINT vsOffset = 0; // Test normal draws with base vertex + m_context->Begin(m_query.ptr()); m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_context->IASetInputLayout(m_vertexFormat.ptr()); m_context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &vsStride, &vsOffset); m_context->Draw(3, 0); m_context->Draw(3, 3); + m_context->End(m_query.ptr()); // Test instanced draws with base instance and base vertex vsOffset = 6 * sizeof(Vertex); @@ -302,6 +312,26 @@ public: m_context->OMSetRenderTargets(0, nullptr, nullptr); m_swapChain->Present(0, 0); + + // Test query results + while (true) { + UINT64 samplesPassed = 0; + + UINT queryStatus = m_context->GetData( + m_query.ptr(), &samplesPassed, sizeof(samplesPassed), + D3D11_ASYNC_GETDATA_DONOTFLUSH); + + if (queryStatus == S_OK) { + if (samplesPassed == 0) + std::cerr << "Occlusion query returned 0 samples" << std::endl; + break; + } else if (queryStatus == S_FALSE) { + std::this_thread::yield(); + } else { + std::cerr << "Occlusion query failed" << std::endl; + break; + } + } } @@ -354,6 +384,8 @@ private: Com m_vertexShader; Com m_pixelShader; + Com m_query; + D3D_FEATURE_LEVEL m_featureLevel; };