1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-05 11:52:10 +01:00
dxvk/src/d3d11/d3d11_query.cpp

356 lines
11 KiB
C++
Raw Normal View History

2017-12-29 22:20:31 +01:00
#include "d3d11_device.h"
#include "d3d11_query.h"
namespace dxvk {
D3D11Query::D3D11Query(
2019-09-16 15:13:48 +02:00
D3D11Device* device,
const D3D11_QUERY_DESC1& desc)
2021-01-07 20:08:55 +00:00
: D3D11DeviceChild<ID3D11Query1>(device),
m_desc(desc),
m_state(D3D11_VK_QUERY_INITIAL),
m_d3d10(this) {
2021-01-07 20:08:55 +00:00
Rc<DxvkDevice> dxvkDevice = m_parent->GetDXVKDevice();
2018-02-18 22:34:23 +01:00
switch (m_desc.Query) {
case D3D11_QUERY_EVENT:
m_event[0] = dxvkDevice->createGpuEvent();
2018-02-18 22:34:23 +01:00
break;
case D3D11_QUERY_OCCLUSION:
m_query[0] = dxvkDevice->createGpuQuery(
VK_QUERY_TYPE_OCCLUSION,
2018-11-17 10:48:18 +01:00
VK_QUERY_CONTROL_PRECISE_BIT, 0);
break;
2018-02-18 22:34:23 +01:00
case D3D11_QUERY_OCCLUSION_PREDICATE:
m_query[0] = dxvkDevice->createGpuQuery(
2018-11-17 10:48:18 +01:00
VK_QUERY_TYPE_OCCLUSION, 0, 0);
2018-02-18 22:34:23 +01:00
break;
case D3D11_QUERY_TIMESTAMP:
m_query[0] = dxvkDevice->createGpuQuery(
2018-11-17 10:48:18 +01:00
VK_QUERY_TYPE_TIMESTAMP, 0, 0);
2018-02-18 22:34:23 +01:00
break;
case D3D11_QUERY_TIMESTAMP_DISJOINT:
for (uint32_t i = 0; i < 2; i++) {
m_query[i] = dxvkDevice->createGpuQuery(
VK_QUERY_TYPE_TIMESTAMP, 0, 0);
}
break;
2018-02-18 22:34:23 +01:00
case D3D11_QUERY_PIPELINE_STATISTICS:
m_query[0] = dxvkDevice->createGpuQuery(
2018-11-17 10:48:18 +01:00
VK_QUERY_TYPE_PIPELINE_STATISTICS, 0, 0);
2018-02-18 22:34:23 +01:00
break;
case D3D11_QUERY_SO_STATISTICS:
case D3D11_QUERY_SO_STATISTICS_STREAM0:
case D3D11_QUERY_SO_OVERFLOW_PREDICATE:
case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM0:
// FIXME it is technically incorrect to map
// SO_OVERFLOW_PREDICATE to the first stream,
// but this is good enough for D3D10 behaviour
m_query[0] = dxvkDevice->createGpuQuery(
VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 0);
break;
case D3D11_QUERY_SO_STATISTICS_STREAM1:
case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM1:
m_query[0] = dxvkDevice->createGpuQuery(
VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 1);
break;
case D3D11_QUERY_SO_STATISTICS_STREAM2:
case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM2:
m_query[0] = dxvkDevice->createGpuQuery(
VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 2);
break;
case D3D11_QUERY_SO_STATISTICS_STREAM3:
case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM3:
m_query[0] = dxvkDevice->createGpuQuery(
VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 0, 3);
break;
default:
2018-02-18 22:34:23 +01:00
throw DxvkError(str::format("D3D11: Unhandled query type: ", desc.Query));
}
2017-12-29 22:20:31 +01:00
}
D3D11Query::~D3D11Query() {
2017-12-29 22:20:31 +01:00
}
HRESULT STDMETHODCALLTYPE D3D11Query::QueryInterface(REFIID riid, void** ppvObject) {
if (ppvObject == nullptr)
return E_POINTER;
*ppvObject = nullptr;
2017-12-29 22:20:31 +01:00
if (riid == __uuidof(IUnknown)
|| riid == __uuidof(ID3D11DeviceChild)
|| riid == __uuidof(ID3D11Asynchronous)
2019-09-16 15:13:48 +02:00
|| riid == __uuidof(ID3D11Query)
|| riid == __uuidof(ID3D11Query1)) {
*ppvObject = ref(this);
return S_OK;
}
2018-08-12 00:20:17 +02:00
if (riid == __uuidof(IUnknown)
|| riid == __uuidof(ID3D10DeviceChild)
|| riid == __uuidof(ID3D10Asynchronous)
|| riid == __uuidof(ID3D10Query)) {
*ppvObject = ref(&m_d3d10);
return S_OK;
}
2018-02-18 22:34:23 +01:00
2018-08-12 00:20:17 +02:00
if (m_desc.Query == D3D11_QUERY_OCCLUSION_PREDICATE) {
if (riid == __uuidof(ID3D11Predicate)) {
2019-09-16 15:13:48 +02:00
*ppvObject = AsPredicate(ref(this));
2018-08-12 00:20:17 +02:00
return S_OK;
}
if (riid == __uuidof(ID3D10Predicate)) {
*ppvObject = ref(&m_d3d10);
return S_OK;
}
}
if (logQueryInterfaceError(__uuidof(ID3D11Query), riid)) {
Logger::warn("D3D11Query: Unknown interface query");
Logger::warn(str::format(riid));
}
2017-12-29 22:20:31 +01:00
return E_NOINTERFACE;
}
UINT STDMETHODCALLTYPE D3D11Query::GetDataSize() {
switch (m_desc.Query) {
case D3D11_QUERY_EVENT:
return sizeof(BOOL);
case D3D11_QUERY_OCCLUSION:
return sizeof(UINT64);
case D3D11_QUERY_TIMESTAMP:
return sizeof(UINT64);
case D3D11_QUERY_TIMESTAMP_DISJOINT:
return sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT);
case D3D11_QUERY_PIPELINE_STATISTICS:
return sizeof(D3D11_QUERY_DATA_PIPELINE_STATISTICS);
case D3D11_QUERY_OCCLUSION_PREDICATE:
return sizeof(BOOL);
case D3D11_QUERY_SO_STATISTICS:
case D3D11_QUERY_SO_STATISTICS_STREAM0:
case D3D11_QUERY_SO_STATISTICS_STREAM1:
case D3D11_QUERY_SO_STATISTICS_STREAM2:
case D3D11_QUERY_SO_STATISTICS_STREAM3:
return sizeof(D3D11_QUERY_DATA_SO_STATISTICS);
case D3D11_QUERY_SO_OVERFLOW_PREDICATE:
case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM0:
case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM1:
case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM2:
case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM3:
return sizeof(BOOL);
}
Logger::err("D3D11Query: Failed to query data size");
return 0;
}
2019-09-16 15:13:48 +02:00
void STDMETHODCALLTYPE D3D11Query::GetDesc(D3D11_QUERY_DESC* pDesc) {
pDesc->Query = m_desc.Query;
pDesc->MiscFlags = m_desc.MiscFlags;
}
void STDMETHODCALLTYPE D3D11Query::GetDesc1(D3D11_QUERY_DESC1* pDesc) {
2017-12-29 22:20:31 +01:00
*pDesc = m_desc;
}
2018-11-17 10:48:18 +01:00
void D3D11Query::Begin(DxvkContext* ctx) {
switch (m_desc.Query) {
case D3D11_QUERY_EVENT:
case D3D11_QUERY_TIMESTAMP:
break;
2018-11-17 10:48:18 +01:00
case D3D11_QUERY_TIMESTAMP_DISJOINT:
ctx->writeTimestamp(m_query[1]);
2018-11-17 10:48:18 +01:00
break;
default:
ctx->beginQuery(m_query[0]);
2018-02-18 22:34:23 +01:00
}
}
void D3D11Query::End(DxvkContext* ctx) {
switch (m_desc.Query) {
2018-11-17 10:48:18 +01:00
case D3D11_QUERY_EVENT:
ctx->signalGpuEvent(m_event[0]);
2018-11-17 10:48:18 +01:00
break;
2018-11-17 10:48:18 +01:00
case D3D11_QUERY_TIMESTAMP:
case D3D11_QUERY_TIMESTAMP_DISJOINT:
ctx->writeTimestamp(m_query[0]);
2018-02-18 22:34:23 +01:00
break;
2018-11-17 10:48:18 +01:00
default:
ctx->endQuery(m_query[0]);
2018-02-18 22:34:23 +01:00
}
m_resetCtr.fetch_sub(1, std::memory_order_release);
2018-02-18 22:34:23 +01:00
}
bool STDMETHODCALLTYPE D3D11Query::DoBegin() {
if (!IsScoped() || m_state == D3D11_VK_QUERY_BEGUN)
return false;
m_state = D3D11_VK_QUERY_BEGUN;
return true;
}
bool STDMETHODCALLTYPE D3D11Query::DoEnd() {
// Apparently the D3D11 runtime implicitly begins the query
// if it is in the wrong state at the time End is called, so
// let the caller react to it instead of just failing here.
bool result = m_state == D3D11_VK_QUERY_BEGUN || !IsScoped();
m_state = D3D11_VK_QUERY_ENDED;
m_resetCtr.fetch_add(1, std::memory_order_acquire);
return result;
}
2018-02-18 22:34:23 +01:00
HRESULT STDMETHODCALLTYPE D3D11Query::GetData(
void* pData,
UINT GetDataFlags) {
if (m_state != D3D11_VK_QUERY_ENDED)
return DXGI_ERROR_INVALID_CALL;
if (m_resetCtr != 0u)
return S_FALSE;
2018-02-18 22:34:23 +01:00
if (m_desc.Query == D3D11_QUERY_EVENT) {
DxvkGpuEventStatus status = m_event[0]->test();
if (status == DxvkGpuEventStatus::Invalid)
return DXGI_ERROR_INVALID_CALL;
bool signaled = status == DxvkGpuEventStatus::Signaled;
if (pData != nullptr)
*static_cast<BOOL*>(pData) = signaled;
return signaled ? S_OK : S_FALSE;
2018-02-18 22:34:23 +01:00
} else {
std::array<DxvkQueryData, MaxGpuQueries> queryData = { };
for (uint32_t i = 0; i < MaxGpuQueries && m_query[i] != nullptr; i++) {
DxvkGpuQueryStatus status = m_query[i]->getData(queryData[i]);
2018-11-17 10:48:18 +01:00
if (status == DxvkGpuQueryStatus::Invalid
|| status == DxvkGpuQueryStatus::Failed)
return DXGI_ERROR_INVALID_CALL;
2018-11-17 10:48:18 +01:00
if (status == DxvkGpuQueryStatus::Pending)
return S_FALSE;
}
2018-02-18 22:34:23 +01:00
if (pData == nullptr)
return S_OK;
2018-02-18 22:34:23 +01:00
switch (m_desc.Query) {
case D3D11_QUERY_OCCLUSION:
*static_cast<UINT64*>(pData) = queryData[0].occlusion.samplesPassed;
2018-02-18 22:34:23 +01:00
return S_OK;
case D3D11_QUERY_OCCLUSION_PREDICATE:
*static_cast<BOOL*>(pData) = queryData[0].occlusion.samplesPassed != 0;
2018-02-18 22:34:23 +01:00
return S_OK;
case D3D11_QUERY_TIMESTAMP:
*static_cast<UINT64*>(pData) = queryData[0].timestamp.time;
2018-02-18 22:34:23 +01:00
return S_OK;
case D3D11_QUERY_TIMESTAMP_DISJOINT: {
auto data = static_cast<D3D11_QUERY_DATA_TIMESTAMP_DISJOINT*>(pData);
data->Frequency = GetTimestampQueryFrequency();
data->Disjoint = queryData[0].timestamp.time < queryData[1].timestamp.time;
2018-02-18 22:34:23 +01:00
} return S_OK;
2018-02-18 22:34:23 +01:00
case D3D11_QUERY_PIPELINE_STATISTICS: {
auto data = static_cast<D3D11_QUERY_DATA_PIPELINE_STATISTICS*>(pData);
data->IAVertices = queryData[0].statistic.iaVertices;
data->IAPrimitives = queryData[0].statistic.iaPrimitives;
data->VSInvocations = queryData[0].statistic.vsInvocations;
data->GSInvocations = queryData[0].statistic.gsInvocations;
data->GSPrimitives = queryData[0].statistic.gsPrimitives;
data->CInvocations = queryData[0].statistic.clipInvocations;
data->CPrimitives = queryData[0].statistic.clipPrimitives;
data->PSInvocations = queryData[0].statistic.fsInvocations;
data->HSInvocations = queryData[0].statistic.tcsPatches;
data->DSInvocations = queryData[0].statistic.tesInvocations;
data->CSInvocations = queryData[0].statistic.csInvocations;
2018-02-18 22:34:23 +01:00
} return S_OK;
case D3D11_QUERY_SO_STATISTICS:
case D3D11_QUERY_SO_STATISTICS_STREAM0:
case D3D11_QUERY_SO_STATISTICS_STREAM1:
case D3D11_QUERY_SO_STATISTICS_STREAM2:
case D3D11_QUERY_SO_STATISTICS_STREAM3: {
auto data = static_cast<D3D11_QUERY_DATA_SO_STATISTICS*>(pData);
data->NumPrimitivesWritten = queryData[0].xfbStream.primitivesWritten;
data->PrimitivesStorageNeeded = queryData[0].xfbStream.primitivesNeeded;
} return S_OK;
2018-02-18 22:34:23 +01:00
case D3D11_QUERY_SO_OVERFLOW_PREDICATE:
case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM0:
case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM1:
case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM2:
case D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM3: {
auto data = static_cast<BOOL*>(pData);
*data = queryData[0].xfbStream.primitivesNeeded
> queryData[0].xfbStream.primitivesWritten;
} return S_OK;
2018-02-18 22:34:23 +01:00
default:
Logger::err(str::format("D3D11: Unhandled query type in GetData: ", m_desc.Query));
return E_INVALIDARG;
}
}
}
UINT64 D3D11Query::GetTimestampQueryFrequency() const {
2021-01-07 20:08:55 +00:00
Rc<DxvkDevice> device = m_parent->GetDXVKDevice();
Rc<DxvkAdapter> adapter = device->adapter();
VkPhysicalDeviceLimits limits = adapter->deviceProperties().limits;
return uint64_t(1'000'000'000.0f / limits.timestampPeriod);
}
2019-09-16 16:04:06 +02:00
HRESULT D3D11Query::ValidateDesc(const D3D11_QUERY_DESC1* pDesc) {
if (pDesc->Query >= D3D11_QUERY_PIPELINE_STATISTICS
&& pDesc->ContextType > D3D11_CONTEXT_TYPE_3D)
return E_INVALIDARG;
return S_OK;
}
2017-12-29 22:20:31 +01:00
}