MVKOcclusionQueryCommandEncoderState validate occlusion query during encoding step.

This commit is contained in:
Bill Hollings 2020-02-16 17:10:30 -05:00
parent 73984ba20c
commit 860e1ef2fb
3 changed files with 35 additions and 44 deletions

View File

@ -563,13 +563,12 @@ public:
protected: protected:
void encodeImpl(uint32_t) override; void encodeImpl(uint32_t) override;
void resetImpl() override; void resetImpl() override;
bool validateOcclusionQuery(MVKOcclusionQueryPool* pQueryPool, uint32_t query);
void endCurrentOcclusionQuery();
id<MTLBuffer> _visibilityResultMTLBuffer = nil; id<MTLBuffer> _visibilityResultMTLBuffer = nil;
MTLVisibilityResultMode _mtlVisibilityResultMode = MTLVisibilityResultModeDisabled; MTLVisibilityResultMode _mtlVisibilityResultMode = MTLVisibilityResultModeDisabled;
NSUInteger _mtlVisibilityResultOffset = 0; NSUInteger _mtlVisibilityResultOffset = 0;
std::unordered_map<MVKQueryKey, id<MTLRenderCommandEncoder>> _mtlEncodersUsed; std::unordered_map<MVKQuerySpec, id<MTLRenderCommandEncoder>> _mtlEncodersUsed;
MVKQuerySpec _currentQuery;
}; };

View File

@ -855,11 +855,7 @@ void MVKComputeResourcesCommandEncoderState::resetImpl() {
void MVKOcclusionQueryCommandEncoderState::beginOcclusionQuery(MVKOcclusionQueryPool* pQueryPool, uint32_t query, VkQueryControlFlags flags) { void MVKOcclusionQueryCommandEncoderState::beginOcclusionQuery(MVKOcclusionQueryPool* pQueryPool, uint32_t query, VkQueryControlFlags flags) {
// If the occlusion query is not valid, don't set it up, and end the current query _currentQuery.set(pQueryPool, query);
if ( !validateOcclusionQuery(pQueryPool, query) ) {
endCurrentOcclusionQuery();
return;
}
NSUInteger offset = pQueryPool->getVisibilityResultOffset(query); NSUInteger offset = pQueryPool->getVisibilityResultOffset(query);
NSUInteger maxOffset = _cmdEncoder->_pDeviceMetalFeatures->maxQueryBufferSize - kMVKQuerySlotSizeInBytes; NSUInteger maxOffset = _cmdEncoder->_pDeviceMetalFeatures->maxQueryBufferSize - kMVKQuerySlotSizeInBytes;
@ -874,42 +870,33 @@ void MVKOcclusionQueryCommandEncoderState::beginOcclusionQuery(MVKOcclusionQuery
} }
void MVKOcclusionQueryCommandEncoderState::endOcclusionQuery(MVKOcclusionQueryPool* pQueryPool, uint32_t query) { void MVKOcclusionQueryCommandEncoderState::endOcclusionQuery(MVKOcclusionQueryPool* pQueryPool, uint32_t query) {
endCurrentOcclusionQuery(); reset();
} }
void MVKOcclusionQueryCommandEncoderState::endCurrentOcclusionQuery() {
_mtlVisibilityResultMode = MTLVisibilityResultModeDisabled;
_mtlVisibilityResultOffset = 0;
markDirty();
}
bool MVKOcclusionQueryCommandEncoderState::validateOcclusionQuery(MVKOcclusionQueryPool* pQueryPool, uint32_t query) {
// If the query was already used for the current Metal render encoder, log an error and return the query as invalid
id<MTLRenderCommandEncoder> currMTLRendEnc = _cmdEncoder->_mtlRenderEncoder;
if (currMTLRendEnc) {
MVKQueryKey qKey = {pQueryPool, query};
if (_mtlEncodersUsed[qKey] == currMTLRendEnc) {
MVKLogError("vkCmdBeginQuery(): Metal does not support using the same query more than once within a single Vulkan render subpass.");
return false;
}
_mtlEncodersUsed[qKey] = currMTLRendEnc; // Remember which MTLRenderEncoder was used for this query
}
return true;
}
// If the MTLBuffer has not yet been set, see if the command buffer is configured with it
id<MTLBuffer> MVKOcclusionQueryCommandEncoderState::getVisibilityResultMTLBuffer() { return _visibilityResultMTLBuffer; } id<MTLBuffer> MVKOcclusionQueryCommandEncoderState::getVisibilityResultMTLBuffer() { return _visibilityResultMTLBuffer; }
void MVKOcclusionQueryCommandEncoderState::encodeImpl(uint32_t stage) { void MVKOcclusionQueryCommandEncoderState::encodeImpl(uint32_t stage) {
if (stage != kMVKGraphicsStageRasterization) { return; } if (stage != kMVKGraphicsStageRasterization) { return; }
[_cmdEncoder->_mtlRenderEncoder setVisibilityResultMode: _mtlVisibilityResultMode
offset: _mtlVisibilityResultOffset]; // Metal does not allow a query to be run twice on a single render encoder.
// If the query is active and was already used for the current Metal render encoder,
// log an error and terminate the current query. Remember which MTLRenderEncoder
// was used for this query to test for this situation on future queries.
if (_mtlVisibilityResultMode != MTLVisibilityResultModeDisabled) {
id<MTLRenderCommandEncoder> currMTLRendEnc = _cmdEncoder->_mtlRenderEncoder;
if (currMTLRendEnc == _mtlEncodersUsed[_currentQuery]) {
MVKLogError("vkCmdBeginQuery(): Metal does not support using the same occlusion query more than once within a single Vulkan render subpass.");
resetImpl();
}
_mtlEncodersUsed[_currentQuery] = currMTLRendEnc;
}
[_cmdEncoder->_mtlRenderEncoder setVisibilityResultMode: _mtlVisibilityResultMode
offset: _mtlVisibilityResultOffset];
} }
void MVKOcclusionQueryCommandEncoderState::resetImpl() { void MVKOcclusionQueryCommandEncoderState::resetImpl() {
_currentQuery.reset();
_visibilityResultMTLBuffer = _cmdEncoder->_cmdBuffer->_initialVisibilityResultMTLBuffer; _visibilityResultMTLBuffer = _cmdEncoder->_cmdBuffer->_initialVisibilityResultMTLBuffer;
_mtlVisibilityResultMode = MTLVisibilityResultModeDisabled; _mtlVisibilityResultMode = MTLVisibilityResultModeDisabled;
_mtlVisibilityResultOffset = 0; _mtlVisibilityResultOffset = 0;

View File

@ -331,24 +331,29 @@ namespace std {
} }
/** /**
* Key for looking up query results. * Spec for a query.
* *
* This structure can be used as a key in a std::map and std::unordered_map. * This structure can be used as a key in a std::map and std::unordered_map.
*/ */
typedef struct MVKQueryKey { typedef struct MVKQuerySpec {
MVKQueryPool* queryPool; MVKQueryPool* queryPool = nullptr;
uint32_t query; uint32_t query = 0;
bool operator==(const MVKQueryKey& rhs) const { inline void set(MVKQueryPool* qryPool, uint32_t qry) { queryPool = qryPool; query = qry; }
inline void reset() { set(nullptr, 0); }
bool operator==(const MVKQuerySpec& rhs) const {
return (queryPool == rhs.queryPool) && (query == rhs.query); return (queryPool == rhs.queryPool) && (query == rhs.query);
} }
std::size_t hash() const { return (size_t)queryPool ^ query; } std::size_t hash() const { return (size_t)queryPool ^ query; }
} MVKQueryKey;
} MVKQuerySpec;
namespace std { namespace std {
template <> template <>
struct hash<MVKQueryKey> { struct hash<MVKQuerySpec> {
std::size_t operator()(const MVKQueryKey& k) const { return k.hash(); } std::size_t operator()(const MVKQuerySpec& k) const { return k.hash(); }
}; };
} }