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:
void encodeImpl(uint32_t) override;
void resetImpl() override;
bool validateOcclusionQuery(MVKOcclusionQueryPool* pQueryPool, uint32_t query);
void endCurrentOcclusionQuery();
id<MTLBuffer> _visibilityResultMTLBuffer = nil;
MTLVisibilityResultMode _mtlVisibilityResultMode = MTLVisibilityResultModeDisabled;
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) {
// If the occlusion query is not valid, don't set it up, and end the current query
if ( !validateOcclusionQuery(pQueryPool, query) ) {
endCurrentOcclusionQuery();
return;
}
_currentQuery.set(pQueryPool, query);
NSUInteger offset = pQueryPool->getVisibilityResultOffset(query);
NSUInteger maxOffset = _cmdEncoder->_pDeviceMetalFeatures->maxQueryBufferSize - kMVKQuerySlotSizeInBytes;
@ -874,42 +870,33 @@ void MVKOcclusionQueryCommandEncoderState::beginOcclusionQuery(MVKOcclusionQuery
}
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; }
void MVKOcclusionQueryCommandEncoderState::encodeImpl(uint32_t stage) {
if (stage != kMVKGraphicsStageRasterization) { return; }
[_cmdEncoder->_mtlRenderEncoder setVisibilityResultMode: _mtlVisibilityResultMode
offset: _mtlVisibilityResultOffset];
if (stage != kMVKGraphicsStageRasterization) { return; }
// 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() {
_currentQuery.reset();
_visibilityResultMTLBuffer = _cmdEncoder->_cmdBuffer->_initialVisibilityResultMTLBuffer;
_mtlVisibilityResultMode = MTLVisibilityResultModeDisabled;
_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.
*/
typedef struct MVKQueryKey {
MVKQueryPool* queryPool;
uint32_t query;
typedef struct MVKQuerySpec {
MVKQueryPool* queryPool = nullptr;
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);
}
std::size_t hash() const { return (size_t)queryPool ^ query; }
} MVKQueryKey;
} MVKQuerySpec;
namespace std {
template <>
struct hash<MVKQueryKey> {
std::size_t operator()(const MVKQueryKey& k) const { return k.hash(); }
struct hash<MVKQuerySpec> {
std::size_t operator()(const MVKQuerySpec& k) const { return k.hash(); }
};
}