• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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