blob: ace41a158c9224bcae31aa8a310da9362179836e [file] [log] [blame]
/*
* MVKQueryPool.h
*
* Copyright (c) 2015-2022 The Brenwill Workshop Ltd. (http://www.brenwill.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "MVKDevice.h"
#include "MVKSmallVector.h"
#include <mutex>
#include <condition_variable>
class MVKBuffer;
class MVKCommandBuffer;
class MVKCommandEncoder;
// The size of one query slot in bytes
#define kMVKQuerySlotSizeInBytes sizeof(uint64_t)
#define kMVKDefaultQueryCount 64
#pragma mark -
#pragma mark MVKQueryPool
/**
* Abstract class representing a Vulkan query pool.
* Subclasses are specialized for specific query types.
*/
class MVKQueryPool : public MVKVulkanAPIDeviceObject {
public:
/** Returns the Vulkan type of this object. */
VkObjectType getVkObjectType() override { return VK_OBJECT_TYPE_QUERY_POOL; }
/** Returns the debug report object type of this object. */
VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT; }
/** Begins the specified query. */
virtual void beginQuery(uint32_t query, VkQueryControlFlags flags, MVKCommandEncoder* cmdEncoder) {}
/** Ends the specified query. */
virtual void endQuery(uint32_t query, MVKCommandEncoder* cmdEncoder);
/** Finishes the specified queries and marks them as available. */
virtual void finishQueries(const MVKArrayRef<uint32_t> queries);
/** Resets the results and availability status of the specified queries. */
virtual void resetResults(uint32_t firstQuery, uint32_t queryCount, MVKCommandEncoder* cmdEncoder);
/** Copies the results of the specified queries into host memory. */
VkResult getResults(uint32_t firstQuery,
uint32_t queryCount,
size_t dataSize,
void* pData,
VkDeviceSize stride,
VkQueryResultFlags flags);
/** Encodes commands to copy the results of the specified queries into device memory. */
void encodeCopyResults(MVKCommandEncoder* cmdEncoder,
uint32_t firstQuery,
uint32_t queryCount,
MVKBuffer* destBuffer,
VkDeviceSize destOffset,
VkDeviceSize stride,
VkQueryResultFlags flags);
/**
* Defers a request to copy the results of the specified queries into device memory, to be
* encoded when all specified queries are ready.
*/
void deferCopyResults(uint32_t firstQuery,
uint32_t queryCount,
MVKBuffer* destBuffer,
VkDeviceSize destOffset,
VkDeviceSize stride,
VkQueryResultFlags flags);
/** Called from the MVKCmdBeginQuery command when it is added to the command buffer */
virtual void beginQueryAddedTo(uint32_t query, MVKCommandBuffer* cmdBuffer) {};
/** Returns whether all the queries in [firstQuery, endQuery) are available on the device. */
bool areQueriesDeviceAvailable(uint32_t firstQuery, uint32_t endQuery);
#pragma mark Construction
MVKQueryPool(MVKDevice* device,
const VkQueryPoolCreateInfo* pCreateInfo,
const uint32_t queryElementCount) : MVKVulkanAPIDeviceObject(device),
_availability(pCreateInfo->queryCount, Initial),
_queryElementCount(queryElementCount) {}
protected:
bool areQueriesHostAvailable(uint32_t firstQuery, uint32_t endQuery);
virtual NSData* getQuerySourceData(uint32_t firstQuery, uint32_t queryCount) { return nil; }
VkResult getResult(uint32_t query, NSData* srcData, uint32_t srcDataQueryOffset, void* pDstData, VkQueryResultFlags flags);
virtual id<MTLBuffer> getResultBuffer(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t queryCount, NSUInteger& offset) { return nil; }
virtual id<MTLComputeCommandEncoder> encodeComputeCopyResults(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t queryCount, uint32_t index) { return nil; }
virtual void encodeDirectCopyResults(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t queryCount,
MVKBuffer* destBuffer, VkDeviceSize destOffset, VkDeviceSize stride);
struct DeferredCopy {
uint32_t firstQuery;
uint32_t queryCount;
MVKBuffer* destBuffer;
VkDeviceSize destOffset;
VkDeviceSize stride;
VkQueryResultFlags flags;
};
/** The possible states of a query. */
enum Status {
Initial, /**< Initial state when created or reset. */
DeviceAvailable, /**< Query was ended and is available on the device. */
Available /**< Query is available to the host. */
};
MVKSmallVector<Status, kMVKDefaultQueryCount> _availability;
MVKSmallVector<DeferredCopy, 4> _deferredCopies;
uint32_t _queryElementCount;
std::mutex _availabilityLock;
std::condition_variable _availabilityBlocker;
std::mutex _deferredCopiesLock;
};
#pragma mark -
#pragma mark MVKOcclusionQueryPool
/** A Vulkan query pool for occlusion queries. */
class MVKOcclusionQueryPool : public MVKQueryPool {
public:
/** Returns the MTLBuffer used to hold occlusion query results. */
id<MTLBuffer> getVisibilityResultMTLBuffer();
/** Returns the offset of the specified query in the visibility MTLBuffer. */
NSUInteger getVisibilityResultOffset(uint32_t query);
void beginQuery(uint32_t query, VkQueryControlFlags flags, MVKCommandEncoder* cmdEncoder) override;
void endQuery(uint32_t query, MVKCommandEncoder* cmdEncoder) override;
void resetResults(uint32_t firstQuery, uint32_t queryCount, MVKCommandEncoder* cmdEncoder) override;
void beginQueryAddedTo(uint32_t query, MVKCommandBuffer* cmdBuffer) override;
#pragma mark Construction
MVKOcclusionQueryPool(MVKDevice* device, const VkQueryPoolCreateInfo* pCreateInfo);
~MVKOcclusionQueryPool() override;
protected:
void propagateDebugName() override;
NSData* getQuerySourceData(uint32_t firstQuery, uint32_t queryCount) override;
id<MTLBuffer> getResultBuffer(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t queryCount, NSUInteger& offset) override;
id<MTLComputeCommandEncoder> encodeComputeCopyResults(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t queryCount, uint32_t index) override;
id<MTLBuffer> _visibilityResultMTLBuffer;
uint32_t _queryIndexOffset;
};
#pragma mark -
#pragma mark MVKGPUCounterQueryPool
/** An abstract parent class for query pools that use Metal GPU counters if they are supported on the platform. */
class MVKGPUCounterQueryPool : public MVKQueryPool {
public:
/** Returns whether a MTLCounterBuffer is being used by this query pool. */
bool hasMTLCounterBuffer() { return _mtlCounterBuffer != nil; }
/**
* Returns the MTLCounterBuffer being used by this query pool,
* or returns nil if GPU counters are not supported.
* */
id<MTLCounterSampleBuffer> getMTLCounterBuffer() { return _mtlCounterBuffer; }
MVKGPUCounterQueryPool(MVKDevice* device, const VkQueryPoolCreateInfo* pCreateInfo);
~MVKGPUCounterQueryPool() override;
protected:
void initMTLCounterSampleBuffer(const VkQueryPoolCreateInfo* pCreateInfo,
id<MTLCounterSet> mtlCounterSet,
const char* queryTypeName);
id<MTLCounterSampleBuffer> _mtlCounterBuffer;
};
#pragma mark -
#pragma mark MVKTimestampQueryPool
/** A Vulkan query pool for timestamp queries. */
class MVKTimestampQueryPool : public MVKGPUCounterQueryPool {
public:
void endQuery(uint32_t query, MVKCommandEncoder* cmdEncoder) override;
void finishQueries(const MVKArrayRef<uint32_t> queries) override;
#pragma mark Construction
MVKTimestampQueryPool(MVKDevice* device, const VkQueryPoolCreateInfo* pCreateInfo);
protected:
void propagateDebugName() override {}
NSData* getQuerySourceData(uint32_t firstQuery, uint32_t queryCount) override;
id<MTLBuffer> getResultBuffer(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t queryCount, NSUInteger& offset) override;
id<MTLComputeCommandEncoder> encodeComputeCopyResults(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t queryCount, uint32_t index) override;
void encodeDirectCopyResults(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t queryCount,
MVKBuffer* destBuffer, VkDeviceSize destOffset, VkDeviceSize stride) override;
MVKSmallVector<uint64_t> _timestamps;
};
#pragma mark -
#pragma mark MVKPipelineStatisticsQueryPool
/** A Vulkan query pool for a query pool type that tracks pipeline statistics. */
class MVKPipelineStatisticsQueryPool : public MVKGPUCounterQueryPool {
public:
MVKPipelineStatisticsQueryPool(MVKDevice* device, const VkQueryPoolCreateInfo* pCreateInfo);
protected:
void propagateDebugName() override {}
};
#pragma mark -
#pragma mark MVKUnsupportedQueryPool
/** A Vulkan query pool for a query pool type that is unsupported in Metal. */
class MVKUnsupportedQueryPool : public MVKQueryPool {
public:
MVKUnsupportedQueryPool(MVKDevice* device, const VkQueryPoolCreateInfo* pCreateInfo);
protected:
void propagateDebugName() override {}
};