1// 2// Copyright (c) 2020 The ANGLE Project Authors. All rights reserved. 3// Use of this source code is governed by a BSD-style license that can be 4// found in the LICENSE file. 5// 6// QueryMtl.mm: 7// Defines the class interface for QueryMtl, implementing QueryImpl. 8// 9 10#include "libANGLE/renderer/metal/QueryMtl.h" 11 12#include "libANGLE/renderer/metal/ContextMtl.h" 13 14namespace rx 15{ 16QueryMtl::QueryMtl(gl::QueryType type) : QueryImpl(type), mTransformFeedbackPrimitivesDrawn(0) {} 17 18QueryMtl::~QueryMtl() {} 19 20void QueryMtl::onDestroy(const gl::Context *context) 21{ 22 ContextMtl *contextMtl = mtl::GetImpl(context); 23 if (!getAllocatedVisibilityOffsets().empty()) 24 { 25 contextMtl->onOcclusionQueryDestroy(context, this); 26 } 27 mVisibilityResultBuffer = nullptr; 28} 29 30angle::Result QueryMtl::begin(const gl::Context *context) 31{ 32 ContextMtl *contextMtl = mtl::GetImpl(context); 33 switch (getType()) 34 { 35 case gl::QueryType::AnySamples: 36 case gl::QueryType::AnySamplesConservative: 37 if (!mVisibilityResultBuffer) 38 { 39 // Allocate buffer 40 ANGLE_TRY(mtl::Buffer::MakeBuffer(contextMtl, mtl::kOcclusionQueryResultSize, 41 nullptr, &mVisibilityResultBuffer)); 42 43 ANGLE_MTL_OBJC_SCOPE 44 { 45 mVisibilityResultBuffer->get().label = 46 [NSString stringWithFormat:@"QueryMtl=%p", this]; 47 } 48 } 49 50 ANGLE_TRY(contextMtl->onOcclusionQueryBegin(context, this)); 51 break; 52 case gl::QueryType::TransformFeedbackPrimitivesWritten: 53 mTransformFeedbackPrimitivesDrawn = 0; 54 break; 55 default: 56 UNIMPLEMENTED(); 57 break; 58 } 59 60 return angle::Result::Continue; 61} 62angle::Result QueryMtl::end(const gl::Context *context) 63{ 64 ContextMtl *contextMtl = mtl::GetImpl(context); 65 switch (getType()) 66 { 67 case gl::QueryType::AnySamples: 68 case gl::QueryType::AnySamplesConservative: 69 contextMtl->onOcclusionQueryEnd(context, this); 70 break; 71 case gl::QueryType::TransformFeedbackPrimitivesWritten: 72 onTransformFeedbackEnd(context); 73 break; 74 default: 75 UNIMPLEMENTED(); 76 break; 77 } 78 return angle::Result::Continue; 79} 80angle::Result QueryMtl::queryCounter(const gl::Context *context) 81{ 82 UNIMPLEMENTED(); 83 return angle::Result::Continue; 84} 85 86template <typename T> 87angle::Result QueryMtl::waitAndGetResult(const gl::Context *context, T *params) 88{ 89 ASSERT(params); 90 ContextMtl *contextMtl = mtl::GetImpl(context); 91 switch (getType()) 92 { 93 case gl::QueryType::AnySamples: 94 case gl::QueryType::AnySamplesConservative: 95 { 96 ASSERT(mVisibilityResultBuffer); 97 if (mVisibilityResultBuffer->hasPendingWorks(contextMtl)) 98 { 99 contextMtl->flushCommandBuffer(mtl::NoWait); 100 } 101 // map() will wait for the pending GPU works to finish 102 const uint8_t *visibilityResultBytes = mVisibilityResultBuffer->mapReadOnly(contextMtl); 103 uint64_t queryResult; 104 memcpy(&queryResult, visibilityResultBytes, sizeof(queryResult)); 105 mVisibilityResultBuffer->unmap(contextMtl); 106 107 *params = queryResult ? GL_TRUE : GL_FALSE; 108 } 109 break; 110 case gl::QueryType::TransformFeedbackPrimitivesWritten: 111 *params = static_cast<T>(mTransformFeedbackPrimitivesDrawn); 112 break; 113 default: 114 UNIMPLEMENTED(); 115 break; 116 } 117 return angle::Result::Continue; 118} 119 120angle::Result QueryMtl::isResultAvailable(const gl::Context *context, bool *available) 121{ 122 ASSERT(available); 123 ContextMtl *contextMtl = mtl::GetImpl(context); 124 // glGetQueryObjectuiv implicitly flush any pending works related to the query 125 switch (getType()) 126 { 127 case gl::QueryType::AnySamples: 128 case gl::QueryType::AnySamplesConservative: 129 ASSERT(mVisibilityResultBuffer); 130 if (mVisibilityResultBuffer->hasPendingWorks(contextMtl)) 131 { 132 contextMtl->flushCommandBuffer(mtl::NoWait); 133 } 134 135 *available = !mVisibilityResultBuffer->isBeingUsedByGPU(contextMtl); 136 break; 137 case gl::QueryType::TransformFeedbackPrimitivesWritten: 138 *available = true; 139 break; 140 default: 141 UNIMPLEMENTED(); 142 break; 143 } 144 return angle::Result::Continue; 145} 146 147angle::Result QueryMtl::getResult(const gl::Context *context, GLint *params) 148{ 149 return waitAndGetResult(context, params); 150} 151angle::Result QueryMtl::getResult(const gl::Context *context, GLuint *params) 152{ 153 return waitAndGetResult(context, params); 154} 155angle::Result QueryMtl::getResult(const gl::Context *context, GLint64 *params) 156{ 157 return waitAndGetResult(context, params); 158} 159angle::Result QueryMtl::getResult(const gl::Context *context, GLuint64 *params) 160{ 161 return waitAndGetResult(context, params); 162} 163 164void QueryMtl::resetVisibilityResult(ContextMtl *contextMtl) 165{ 166 // Occlusion query buffer must be allocated in QueryMtl::begin 167 ASSERT(mVisibilityResultBuffer); 168 169 // Fill the query's buffer with zeros 170 auto blitEncoder = contextMtl->getBlitCommandEncoder(); 171 blitEncoder->fillBuffer(mVisibilityResultBuffer, NSMakeRange(0, mtl::kOcclusionQueryResultSize), 172 0); 173 mVisibilityResultBuffer->syncContent(contextMtl, blitEncoder); 174} 175 176void QueryMtl::onTransformFeedbackEnd(const gl::Context *context) 177{ 178 gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); 179 if (transformFeedback) 180 { 181 mTransformFeedbackPrimitivesDrawn += transformFeedback->getPrimitivesDrawn(); 182 } 183} 184 185} 186