This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/gpu/metal/mtl_query.mm

123 lines
3.8 KiB
C++

/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*/
#include "mtl_query.hh"
namespace blender::gpu {
static const size_t VISIBILITY_COUNT_PER_BUFFER = 512;
/* defined in the documentation but not queryable programmatically:
* https://developer.apple.com/documentation/metal/mtlvisibilityresultmode/mtlvisibilityresultmodeboolean?language=objc
*/
static const size_t VISIBILITY_RESULT_SIZE_IN_BYTES = 8;
MTLQueryPool::MTLQueryPool()
{
allocate_buffer();
}
MTLQueryPool::~MTLQueryPool()
{
for (gpu::MTLBuffer *buf : buffer_) {
BLI_assert(buf);
buf->free();
}
}
void MTLQueryPool::allocate_buffer()
{
/* Allocate Metal buffer for visibility results. */
size_t buffer_size_in_bytes = VISIBILITY_COUNT_PER_BUFFER * VISIBILITY_RESULT_SIZE_IN_BYTES;
gpu::MTLBuffer *buffer = MTLContext::get_global_memory_manager().allocate_buffer(
buffer_size_in_bytes, true);
BLI_assert(buffer);
buffer_.append(buffer);
}
static inline MTLVisibilityResultMode to_mtl_type(GPUQueryType type)
{
if (type == GPU_QUERY_OCCLUSION) {
return MTLVisibilityResultModeBoolean;
}
BLI_assert(0);
return MTLVisibilityResultModeBoolean;
}
void MTLQueryPool::init(GPUQueryType type)
{
BLI_assert(initialized_ == false);
initialized_ = true;
type_ = type;
mtl_type_ = to_mtl_type(type);
query_issued_ = 0;
}
void MTLQueryPool::begin_query()
{
MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get());
/* Ensure our allocated buffer pool has enough space for the current queries. */
int query_id = query_issued_;
int requested_buffer = query_id / VISIBILITY_COUNT_PER_BUFFER;
if (requested_buffer >= buffer_.size()) {
allocate_buffer();
}
BLI_assert(requested_buffer < buffer_.size());
gpu::MTLBuffer *buffer = buffer_[requested_buffer];
/* Ensure visibility buffer is set on the context. If visibility buffer changes,
* we need to begin a new render pass with an updated reference in the
* MTLRenderPassDescriptor. */
ctx->set_visibility_buffer(buffer);
ctx->ensure_begin_render_pass();
id<MTLRenderCommandEncoder> rec = ctx->main_command_buffer.get_active_render_command_encoder();
[rec setVisibilityResultMode:mtl_type_
offset:(query_id % VISIBILITY_COUNT_PER_BUFFER) *
VISIBILITY_RESULT_SIZE_IN_BYTES];
query_issued_ += 1;
}
void MTLQueryPool::end_query()
{
MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get());
id<MTLRenderCommandEncoder> rec = ctx->main_command_buffer.get_active_render_command_encoder();
[rec setVisibilityResultMode:MTLVisibilityResultModeDisabled offset:0];
}
void MTLQueryPool::get_occlusion_result(MutableSpan<uint32_t> r_values)
{
MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get());
/* Create a blit encoder to synchronize the query buffer results between
* GPU and CPU when not using shared-memory. */
if ([ctx->device hasUnifiedMemory] == false) {
id<MTLBlitCommandEncoder> blit_encoder = ctx->main_command_buffer.ensure_begin_blit_encoder();
BLI_assert(blit_encoder);
for (gpu::MTLBuffer *buf : buffer_) {
[blit_encoder synchronizeResource:buf->get_metal_buffer()];
}
BLI_assert(ctx->get_inside_frame());
}
/* Wait for GPU operations to complete and for query buffer contents
* to be synchronized back to host memory. */
GPU_finish();
/* Iterate through all possible visibility buffers and copy results into provided
* container. */
for (const int i : IndexRange(query_issued_)) {
int requested_buffer = i / VISIBILITY_COUNT_PER_BUFFER;
const uint64_t *queries = static_cast<const uint64_t *>(
buffer_[requested_buffer]->get_host_ptr());
r_values[i] = static_cast<uint32_t>(queries[i % VISIBILITY_COUNT_PER_BUFFER]);
}
ctx->set_visibility_buffer(nullptr);
}
} // namespace blender::gpu