D3DQueryFactory.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Gr/D3D/D3DQueryFactory.h>
  6. #include <AnKi/Gr/D3D/D3DGrManager.h>
  7. namespace anki {
  8. Error QueryFactory::newQuery(QueryHandle& handle)
  9. {
  10. LockGuard lock(m_mtx);
  11. // Find a not-full chunk
  12. BlockArray::Iterator chunkIt = m_chunkArray.getEnd();
  13. for(auto it = m_chunkArray.getBegin(); it != m_chunkArray.getEnd(); ++it)
  14. {
  15. if(it->getAllocationCount() < kMaxQueriesPerQueryChunk)
  16. {
  17. // Found one
  18. if(chunkIt == m_chunkArray.getEnd())
  19. {
  20. chunkIt = it;
  21. }
  22. else if(it->getAllocationCount() > chunkIt->getAllocationCount())
  23. {
  24. // To decrease fragmentation use the most full chunk
  25. chunkIt = it;
  26. }
  27. }
  28. }
  29. if(chunkIt == m_chunkArray.getEnd())
  30. {
  31. // Create new chunk
  32. chunkIt = m_chunkArray.emplace();
  33. Chunk& chunk = *chunkIt;
  34. BufferInitInfo buffInit("QueryBuffer");
  35. buffInit.m_mapAccess = BufferMapAccessBit::kRead;
  36. buffInit.m_usage = BufferUsageBit::kTransferDestination;
  37. buffInit.m_size = kMaxQueriesPerQueryChunk * m_resultStructSize64 * sizeof(U64);
  38. chunk.m_resultsBuffer = GrManager::getSingleton().newBuffer(buffInit);
  39. chunk.m_resultsBufferCpuAddr = static_cast<U64*>(chunk.m_resultsBuffer->map(0, buffInit.m_size, BufferMapAccessBit::kRead));
  40. const D3D12_QUERY_HEAP_DESC desc = {.Type = m_type, .Count = kMaxQueriesPerQueryChunk, .NodeMask = 0};
  41. ANKI_D3D_CHECK(getDevice().CreateQueryHeap(&desc, IID_PPV_ARGS(&chunk.m_heap)));
  42. }
  43. ANKI_ASSERT(chunkIt != m_chunkArray.getEnd());
  44. // Allocate from chunk
  45. BitSet<kMaxQueriesPerQueryChunk, U64> freeBits = ~chunkIt->m_allocationMask;
  46. const U32 freeIndex = freeBits.getLeastSignificantBit();
  47. ANKI_ASSERT(freeIndex < kMaxU32);
  48. chunkIt->m_allocationMask.set(freeIndex);
  49. chunkIt->m_queryWritten.unset(freeIndex);
  50. handle.m_chunkIndex = U16(chunkIt.getArrayIndex());
  51. handle.m_queryIndex = U16(freeIndex);
  52. #if ANKI_ASSERTIONS_ENABLED
  53. handle.m_type = m_type;
  54. #endif
  55. return Error::kNone;
  56. }
  57. void QueryFactory::deleteQuery(QueryHandle& handle)
  58. {
  59. ANKI_ASSERT(handle.isValid() && handle.m_type == m_type);
  60. LockGuard lock(m_mtx);
  61. BlockArray::Iterator chunkIt = m_chunkArray.indexToIterator(handle.m_chunkIndex);
  62. if(chunkIt->m_fenceArr[handle.m_queryIndex].isCreated())
  63. {
  64. ANKI_ASSERT(chunkIt->m_fenceArr[handle.m_queryIndex]->done() && "Trying to delete while the query is in flight");
  65. chunkIt->m_fenceArr[handle.m_queryIndex].reset(nullptr);
  66. }
  67. // Free
  68. ANKI_ASSERT(chunkIt->m_allocationMask.get(handle.m_queryIndex));
  69. chunkIt->m_allocationMask.unset(handle.m_queryIndex);
  70. // Free the chunk
  71. if(chunkIt->getAllocationCount() == 0)
  72. {
  73. safeRelease(chunkIt->m_heap);
  74. chunkIt->m_resultsBuffer->unmap();
  75. m_chunkArray.erase(chunkIt);
  76. }
  77. handle = {};
  78. }
  79. Bool QueryFactory::getResult(QueryHandle handle, U64& result)
  80. {
  81. ANKI_ASSERT(handle.isValid() && handle.m_type == m_type);
  82. auto it = m_chunkArray.indexToIterator(handle.m_chunkIndex);
  83. ANKI_ASSERT(it->m_queryWritten.get(handle.m_queryIndex) && "Trying to get the result of a query that wasn't written");
  84. const Bool available = (it->m_fenceArr[handle.m_queryIndex].isCreated()) ? it->m_fenceArr[handle.m_queryIndex]->done() : true;
  85. if(available)
  86. {
  87. result = it->m_resultsBufferCpuAddr[handle.m_queryIndex * m_resultStructSize64 + m_resultMemberOffset64];
  88. it->m_fenceArr[handle.m_queryIndex].reset(nullptr);
  89. }
  90. else
  91. {
  92. result = 0;
  93. }
  94. return available;
  95. }
  96. void QueryFactory::postSubmitWork(QueryHandle handle, MicroFence* fence)
  97. {
  98. ANKI_ASSERT(handle.isValid() && handle.m_type == m_type && fence);
  99. auto it = m_chunkArray.indexToIterator(handle.m_chunkIndex);
  100. ANKI_ASSERT(!it->m_queryWritten.get(handle.m_queryIndex) && "A query can only be written once");
  101. ANKI_ASSERT(!it->m_fenceArr[handle.m_queryIndex].isCreated());
  102. it->m_fenceArr[handle.m_queryIndex].reset(fence);
  103. it->m_queryWritten.set(handle.m_queryIndex);
  104. }
  105. } // end namespace anki