1*8975f5c5SAndroid Build Coastguard Worker// 2*8975f5c5SAndroid Build Coastguard Worker// Copyright (c) 2020 The ANGLE Project Authors. All rights reserved. 3*8975f5c5SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style license that can be 4*8975f5c5SAndroid Build Coastguard Worker// found in the LICENSE file. 5*8975f5c5SAndroid Build Coastguard Worker// 6*8975f5c5SAndroid Build Coastguard Worker// QueryMtl.mm: 7*8975f5c5SAndroid Build Coastguard Worker// Defines the class interface for QueryMtl, implementing QueryImpl. 8*8975f5c5SAndroid Build Coastguard Worker// 9*8975f5c5SAndroid Build Coastguard Worker 10*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/QueryMtl.h" 11*8975f5c5SAndroid Build Coastguard Worker 12*8975f5c5SAndroid Build Coastguard Worker#include "libANGLE/renderer/metal/ContextMtl.h" 13*8975f5c5SAndroid Build Coastguard Worker 14*8975f5c5SAndroid Build Coastguard Workernamespace rx 15*8975f5c5SAndroid Build Coastguard Worker{ 16*8975f5c5SAndroid Build Coastguard WorkerQueryMtl::QueryMtl(gl::QueryType type) : QueryImpl(type) {} 17*8975f5c5SAndroid Build Coastguard Worker 18*8975f5c5SAndroid Build Coastguard WorkerQueryMtl::~QueryMtl() {} 19*8975f5c5SAndroid Build Coastguard Worker 20*8975f5c5SAndroid Build Coastguard Workervoid QueryMtl::onDestroy(const gl::Context *context) 21*8975f5c5SAndroid Build Coastguard Worker{ 22*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 23*8975f5c5SAndroid Build Coastguard Worker if (!getAllocatedVisibilityOffsets().empty()) 24*8975f5c5SAndroid Build Coastguard Worker { 25*8975f5c5SAndroid Build Coastguard Worker contextMtl->onOcclusionQueryDestroy(context, this); 26*8975f5c5SAndroid Build Coastguard Worker } 27*8975f5c5SAndroid Build Coastguard Worker mVisibilityResultBuffer = nullptr; 28*8975f5c5SAndroid Build Coastguard Worker} 29*8975f5c5SAndroid Build Coastguard Worker 30*8975f5c5SAndroid Build Coastguard Workerangle::Result QueryMtl::begin(const gl::Context *context) 31*8975f5c5SAndroid Build Coastguard Worker{ 32*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 33*8975f5c5SAndroid Build Coastguard Worker switch (getType()) 34*8975f5c5SAndroid Build Coastguard Worker { 35*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::AnySamples: 36*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::AnySamplesConservative: 37*8975f5c5SAndroid Build Coastguard Worker if (!mVisibilityResultBuffer) 38*8975f5c5SAndroid Build Coastguard Worker { 39*8975f5c5SAndroid Build Coastguard Worker // Allocate buffer 40*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(mtl::Buffer::MakeBuffer(contextMtl, mtl::kOcclusionQueryResultSize, 41*8975f5c5SAndroid Build Coastguard Worker nullptr, &mVisibilityResultBuffer)); 42*8975f5c5SAndroid Build Coastguard Worker 43*8975f5c5SAndroid Build Coastguard Worker ANGLE_MTL_OBJC_SCOPE 44*8975f5c5SAndroid Build Coastguard Worker { 45*8975f5c5SAndroid Build Coastguard Worker mVisibilityResultBuffer->get().label = 46*8975f5c5SAndroid Build Coastguard Worker [NSString stringWithFormat:@"QueryMtl=%p", this]; 47*8975f5c5SAndroid Build Coastguard Worker } 48*8975f5c5SAndroid Build Coastguard Worker } 49*8975f5c5SAndroid Build Coastguard Worker 50*8975f5c5SAndroid Build Coastguard Worker ANGLE_TRY(contextMtl->onOcclusionQueryBegin(context, this)); 51*8975f5c5SAndroid Build Coastguard Worker break; 52*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::TransformFeedbackPrimitivesWritten: 53*8975f5c5SAndroid Build Coastguard Worker mTransformFeedbackPrimitivesDrawn = 0; 54*8975f5c5SAndroid Build Coastguard Worker break; 55*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::TimeElapsed: 56*8975f5c5SAndroid Build Coastguard Worker { 57*8975f5c5SAndroid Build Coastguard Worker // End any command buffer being encoded, to get a clean boundary for beginning 58*8975f5c5SAndroid Build Coastguard Worker // measurement. 59*8975f5c5SAndroid Build Coastguard Worker contextMtl->flushCommandBuffer(mtl::NoWait); 60*8975f5c5SAndroid Build Coastguard Worker mtl::CommandQueue &queue = contextMtl->getDisplay()->cmdQueue(); 61*8975f5c5SAndroid Build Coastguard Worker if (mTimeElapsedEntry != 0) 62*8975f5c5SAndroid Build Coastguard Worker { 63*8975f5c5SAndroid Build Coastguard Worker queue.deleteTimeElapsedEntry(mTimeElapsedEntry); 64*8975f5c5SAndroid Build Coastguard Worker mTimeElapsedEntry = 0; 65*8975f5c5SAndroid Build Coastguard Worker } 66*8975f5c5SAndroid Build Coastguard Worker mTimeElapsedEntry = queue.allocateTimeElapsedEntry(); 67*8975f5c5SAndroid Build Coastguard Worker queue.setActiveTimeElapsedEntry(mTimeElapsedEntry); 68*8975f5c5SAndroid Build Coastguard Worker break; 69*8975f5c5SAndroid Build Coastguard Worker } 70*8975f5c5SAndroid Build Coastguard Worker default: 71*8975f5c5SAndroid Build Coastguard Worker UNIMPLEMENTED(); 72*8975f5c5SAndroid Build Coastguard Worker break; 73*8975f5c5SAndroid Build Coastguard Worker } 74*8975f5c5SAndroid Build Coastguard Worker 75*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 76*8975f5c5SAndroid Build Coastguard Worker} 77*8975f5c5SAndroid Build Coastguard Workerangle::Result QueryMtl::end(const gl::Context *context) 78*8975f5c5SAndroid Build Coastguard Worker{ 79*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 80*8975f5c5SAndroid Build Coastguard Worker switch (getType()) 81*8975f5c5SAndroid Build Coastguard Worker { 82*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::AnySamples: 83*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::AnySamplesConservative: 84*8975f5c5SAndroid Build Coastguard Worker contextMtl->onOcclusionQueryEnd(context, this); 85*8975f5c5SAndroid Build Coastguard Worker break; 86*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::TransformFeedbackPrimitivesWritten: 87*8975f5c5SAndroid Build Coastguard Worker onTransformFeedbackEnd(context); 88*8975f5c5SAndroid Build Coastguard Worker break; 89*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::TimeElapsed: 90*8975f5c5SAndroid Build Coastguard Worker { 91*8975f5c5SAndroid Build Coastguard Worker // End any command buffer being encoded, to get a clean boundary for ending measurement. 92*8975f5c5SAndroid Build Coastguard Worker contextMtl->flushCommandBuffer(mtl::NoWait); 93*8975f5c5SAndroid Build Coastguard Worker mtl::CommandQueue &queue = contextMtl->getDisplay()->cmdQueue(); 94*8975f5c5SAndroid Build Coastguard Worker queue.setActiveTimeElapsedEntry(0); 95*8975f5c5SAndroid Build Coastguard Worker break; 96*8975f5c5SAndroid Build Coastguard Worker } 97*8975f5c5SAndroid Build Coastguard Worker default: 98*8975f5c5SAndroid Build Coastguard Worker UNIMPLEMENTED(); 99*8975f5c5SAndroid Build Coastguard Worker break; 100*8975f5c5SAndroid Build Coastguard Worker } 101*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 102*8975f5c5SAndroid Build Coastguard Worker} 103*8975f5c5SAndroid Build Coastguard Workerangle::Result QueryMtl::queryCounter(const gl::Context *context) 104*8975f5c5SAndroid Build Coastguard Worker{ 105*8975f5c5SAndroid Build Coastguard Worker UNIMPLEMENTED(); 106*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 107*8975f5c5SAndroid Build Coastguard Worker} 108*8975f5c5SAndroid Build Coastguard Worker 109*8975f5c5SAndroid Build Coastguard Workertemplate <typename T> 110*8975f5c5SAndroid Build Coastguard Workerangle::Result QueryMtl::waitAndGetResult(const gl::Context *context, T *params) 111*8975f5c5SAndroid Build Coastguard Worker{ 112*8975f5c5SAndroid Build Coastguard Worker ASSERT(params); 113*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 114*8975f5c5SAndroid Build Coastguard Worker switch (getType()) 115*8975f5c5SAndroid Build Coastguard Worker { 116*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::AnySamples: 117*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::AnySamplesConservative: 118*8975f5c5SAndroid Build Coastguard Worker { 119*8975f5c5SAndroid Build Coastguard Worker ASSERT(mVisibilityResultBuffer); 120*8975f5c5SAndroid Build Coastguard Worker if (mVisibilityResultBuffer->hasPendingWorks(contextMtl)) 121*8975f5c5SAndroid Build Coastguard Worker { 122*8975f5c5SAndroid Build Coastguard Worker contextMtl->flushCommandBuffer(mtl::NoWait); 123*8975f5c5SAndroid Build Coastguard Worker } 124*8975f5c5SAndroid Build Coastguard Worker // map() will wait for the pending GPU works to finish 125*8975f5c5SAndroid Build Coastguard Worker const uint8_t *visibilityResultBytes = mVisibilityResultBuffer->mapReadOnly(contextMtl); 126*8975f5c5SAndroid Build Coastguard Worker uint64_t queryResult; 127*8975f5c5SAndroid Build Coastguard Worker memcpy(&queryResult, visibilityResultBytes, sizeof(queryResult)); 128*8975f5c5SAndroid Build Coastguard Worker mVisibilityResultBuffer->unmap(contextMtl); 129*8975f5c5SAndroid Build Coastguard Worker 130*8975f5c5SAndroid Build Coastguard Worker *params = queryResult ? GL_TRUE : GL_FALSE; 131*8975f5c5SAndroid Build Coastguard Worker } 132*8975f5c5SAndroid Build Coastguard Worker break; 133*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::TransformFeedbackPrimitivesWritten: 134*8975f5c5SAndroid Build Coastguard Worker *params = static_cast<T>(mTransformFeedbackPrimitivesDrawn); 135*8975f5c5SAndroid Build Coastguard Worker break; 136*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::TimeElapsed: 137*8975f5c5SAndroid Build Coastguard Worker { 138*8975f5c5SAndroid Build Coastguard Worker ASSERT(mTimeElapsedEntry != 0); 139*8975f5c5SAndroid Build Coastguard Worker mtl::CommandQueue &queue = contextMtl->getDisplay()->cmdQueue(); 140*8975f5c5SAndroid Build Coastguard Worker if (!queue.isTimeElapsedEntryComplete(mTimeElapsedEntry)) 141*8975f5c5SAndroid Build Coastguard Worker { 142*8975f5c5SAndroid Build Coastguard Worker contextMtl->flushCommandBuffer(mtl::WaitUntilFinished); 143*8975f5c5SAndroid Build Coastguard Worker } 144*8975f5c5SAndroid Build Coastguard Worker ASSERT(queue.isTimeElapsedEntryComplete(mTimeElapsedEntry)); 145*8975f5c5SAndroid Build Coastguard Worker double nanos = queue.getTimeElapsedEntryInSeconds(mTimeElapsedEntry) * 1e9; 146*8975f5c5SAndroid Build Coastguard Worker uint64_t result = static_cast<uint64_t>(nanos); 147*8975f5c5SAndroid Build Coastguard Worker *params = static_cast<T>(result); 148*8975f5c5SAndroid Build Coastguard Worker break; 149*8975f5c5SAndroid Build Coastguard Worker } 150*8975f5c5SAndroid Build Coastguard Worker default: 151*8975f5c5SAndroid Build Coastguard Worker UNIMPLEMENTED(); 152*8975f5c5SAndroid Build Coastguard Worker break; 153*8975f5c5SAndroid Build Coastguard Worker } 154*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 155*8975f5c5SAndroid Build Coastguard Worker} 156*8975f5c5SAndroid Build Coastguard Worker 157*8975f5c5SAndroid Build Coastguard Workerangle::Result QueryMtl::isResultAvailable(const gl::Context *context, bool *available) 158*8975f5c5SAndroid Build Coastguard Worker{ 159*8975f5c5SAndroid Build Coastguard Worker ASSERT(available); 160*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 161*8975f5c5SAndroid Build Coastguard Worker // glGetQueryObjectuiv implicitly flush any pending works related to the query 162*8975f5c5SAndroid Build Coastguard Worker switch (getType()) 163*8975f5c5SAndroid Build Coastguard Worker { 164*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::AnySamples: 165*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::AnySamplesConservative: 166*8975f5c5SAndroid Build Coastguard Worker ASSERT(mVisibilityResultBuffer); 167*8975f5c5SAndroid Build Coastguard Worker if (mVisibilityResultBuffer->hasPendingWorks(contextMtl)) 168*8975f5c5SAndroid Build Coastguard Worker { 169*8975f5c5SAndroid Build Coastguard Worker contextMtl->flushCommandBuffer(mtl::NoWait); 170*8975f5c5SAndroid Build Coastguard Worker } 171*8975f5c5SAndroid Build Coastguard Worker 172*8975f5c5SAndroid Build Coastguard Worker *available = !mVisibilityResultBuffer->isBeingUsedByGPU(contextMtl); 173*8975f5c5SAndroid Build Coastguard Worker break; 174*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::TransformFeedbackPrimitivesWritten: 175*8975f5c5SAndroid Build Coastguard Worker *available = true; 176*8975f5c5SAndroid Build Coastguard Worker break; 177*8975f5c5SAndroid Build Coastguard Worker case gl::QueryType::TimeElapsed: 178*8975f5c5SAndroid Build Coastguard Worker *available = 179*8975f5c5SAndroid Build Coastguard Worker contextMtl->getDisplay()->cmdQueue().isTimeElapsedEntryComplete(mTimeElapsedEntry); 180*8975f5c5SAndroid Build Coastguard Worker break; 181*8975f5c5SAndroid Build Coastguard Worker default: 182*8975f5c5SAndroid Build Coastguard Worker UNIMPLEMENTED(); 183*8975f5c5SAndroid Build Coastguard Worker break; 184*8975f5c5SAndroid Build Coastguard Worker } 185*8975f5c5SAndroid Build Coastguard Worker return angle::Result::Continue; 186*8975f5c5SAndroid Build Coastguard Worker} 187*8975f5c5SAndroid Build Coastguard Worker 188*8975f5c5SAndroid Build Coastguard Workerangle::Result QueryMtl::getResult(const gl::Context *context, GLint *params) 189*8975f5c5SAndroid Build Coastguard Worker{ 190*8975f5c5SAndroid Build Coastguard Worker return waitAndGetResult(context, params); 191*8975f5c5SAndroid Build Coastguard Worker} 192*8975f5c5SAndroid Build Coastguard Workerangle::Result QueryMtl::getResult(const gl::Context *context, GLuint *params) 193*8975f5c5SAndroid Build Coastguard Worker{ 194*8975f5c5SAndroid Build Coastguard Worker return waitAndGetResult(context, params); 195*8975f5c5SAndroid Build Coastguard Worker} 196*8975f5c5SAndroid Build Coastguard Workerangle::Result QueryMtl::getResult(const gl::Context *context, GLint64 *params) 197*8975f5c5SAndroid Build Coastguard Worker{ 198*8975f5c5SAndroid Build Coastguard Worker return waitAndGetResult(context, params); 199*8975f5c5SAndroid Build Coastguard Worker} 200*8975f5c5SAndroid Build Coastguard Workerangle::Result QueryMtl::getResult(const gl::Context *context, GLuint64 *params) 201*8975f5c5SAndroid Build Coastguard Worker{ 202*8975f5c5SAndroid Build Coastguard Worker return waitAndGetResult(context, params); 203*8975f5c5SAndroid Build Coastguard Worker} 204*8975f5c5SAndroid Build Coastguard Worker 205*8975f5c5SAndroid Build Coastguard Workervoid QueryMtl::resetVisibilityResult(ContextMtl *contextMtl) 206*8975f5c5SAndroid Build Coastguard Worker{ 207*8975f5c5SAndroid Build Coastguard Worker // Occlusion query buffer must be allocated in QueryMtl::begin 208*8975f5c5SAndroid Build Coastguard Worker ASSERT(mVisibilityResultBuffer); 209*8975f5c5SAndroid Build Coastguard Worker 210*8975f5c5SAndroid Build Coastguard Worker // Fill the query's buffer with zeros 211*8975f5c5SAndroid Build Coastguard Worker auto blitEncoder = contextMtl->getBlitCommandEncoder(); 212*8975f5c5SAndroid Build Coastguard Worker blitEncoder->fillBuffer(mVisibilityResultBuffer, NSMakeRange(0, mtl::kOcclusionQueryResultSize), 213*8975f5c5SAndroid Build Coastguard Worker 0); 214*8975f5c5SAndroid Build Coastguard Worker mVisibilityResultBuffer->syncContent(contextMtl, blitEncoder); 215*8975f5c5SAndroid Build Coastguard Worker} 216*8975f5c5SAndroid Build Coastguard Worker 217*8975f5c5SAndroid Build Coastguard Workervoid QueryMtl::onTransformFeedbackEnd(const gl::Context *context) 218*8975f5c5SAndroid Build Coastguard Worker{ 219*8975f5c5SAndroid Build Coastguard Worker gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); 220*8975f5c5SAndroid Build Coastguard Worker if (transformFeedback) 221*8975f5c5SAndroid Build Coastguard Worker { 222*8975f5c5SAndroid Build Coastguard Worker mTransformFeedbackPrimitivesDrawn += transformFeedback->getPrimitivesDrawn(); 223*8975f5c5SAndroid Build Coastguard Worker } 224*8975f5c5SAndroid Build Coastguard Worker} 225*8975f5c5SAndroid Build Coastguard Worker 226*8975f5c5SAndroid Build Coastguard Workervoid QueryMtl::onContextMakeCurrent(const gl::Context *context) 227*8975f5c5SAndroid Build Coastguard Worker{ 228*8975f5c5SAndroid Build Coastguard Worker // At present this should only be called for time elapsed queries. 229*8975f5c5SAndroid Build Coastguard Worker ASSERT(getType() == gl::QueryType::TimeElapsed); 230*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 231*8975f5c5SAndroid Build Coastguard Worker contextMtl->getDisplay()->cmdQueue().setActiveTimeElapsedEntry(mTimeElapsedEntry); 232*8975f5c5SAndroid Build Coastguard Worker} 233*8975f5c5SAndroid Build Coastguard Worker 234*8975f5c5SAndroid Build Coastguard Workervoid QueryMtl::onContextUnMakeCurrent(const gl::Context *context) 235*8975f5c5SAndroid Build Coastguard Worker{ 236*8975f5c5SAndroid Build Coastguard Worker // At present this should only be called for time elapsed queries. 237*8975f5c5SAndroid Build Coastguard Worker ASSERT(getType() == gl::QueryType::TimeElapsed); 238*8975f5c5SAndroid Build Coastguard Worker ContextMtl *contextMtl = mtl::GetImpl(context); 239*8975f5c5SAndroid Build Coastguard Worker contextMtl->getDisplay()->cmdQueue().setActiveTimeElapsedEntry(0); 240*8975f5c5SAndroid Build Coastguard Worker} 241*8975f5c5SAndroid Build Coastguard Worker 242*8975f5c5SAndroid Build Coastguard Worker} // namespace rx 243