xref: /aosp_15_r20/external/skia/tools/gpu/gl/GLTestContext.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2013 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "tools/gpu/gl/GLTestContext.h"
9 
10 #include "include/gpu/ganesh/GrDirectContext.h"
11 #include "include/gpu/ganesh/gl/GrGLDirectContext.h"
12 #include "src/gpu/ganesh/gl/GrGLUtil.h"
13 #include "tools/gpu/GpuTimer.h"
14 
15 namespace {
16 
17 class GLGpuTimer : public sk_gpu_test::GpuTimer {
18 public:
19     static std::unique_ptr<GLGpuTimer> MakeIfSupported(const sk_gpu_test::GLTestContext*);
20 
21     QueryStatus checkQueryStatus(sk_gpu_test::PlatformTimerQuery) override;
22     std::chrono::nanoseconds getTimeElapsed(sk_gpu_test::PlatformTimerQuery) override;
23     void deleteQuery(sk_gpu_test::PlatformTimerQuery) override;
24 
25 private:
26     GLGpuTimer(bool disjointSupport, const sk_gpu_test::GLTestContext*, const char* ext = "");
27     bool validate() const;
28 
29     sk_gpu_test::PlatformTimerQuery onQueueTimerStart() const override;
30     void onQueueTimerStop(sk_gpu_test::PlatformTimerQuery) const override;
31 
32     inline static constexpr GrGLenum GL_QUERY_RESULT            = 0x8866;
33     inline static constexpr GrGLenum GL_QUERY_RESULT_AVAILABLE  = 0x8867;
34     inline static constexpr GrGLenum GL_TIME_ELAPSED            = 0x88bf;
35     inline static constexpr GrGLenum GL_GPU_DISJOINT            = 0x8fbb;
36 
37     typedef void (GR_GL_FUNCTION_TYPE* GLGetIntegervProc) (GrGLenum, GrGLint*);
38     typedef void (GR_GL_FUNCTION_TYPE* GLGenQueriesProc) (GrGLsizei, GrGLuint*);
39     typedef void (GR_GL_FUNCTION_TYPE* GLDeleteQueriesProc) (GrGLsizei, const GrGLuint*);
40     typedef void (GR_GL_FUNCTION_TYPE* GLBeginQueryProc) (GrGLenum, GrGLuint);
41     typedef void (GR_GL_FUNCTION_TYPE* GLEndQueryProc) (GrGLenum);
42     typedef void (GR_GL_FUNCTION_TYPE* GLGetQueryObjectuivProc) (GrGLuint, GrGLenum, GrGLuint*);
43     typedef void (GR_GL_FUNCTION_TYPE* GLGetQueryObjectui64vProc) (GrGLuint, GrGLenum, GrGLuint64*);
44 
45     GLGetIntegervProc           fGLGetIntegerv;
46     GLGenQueriesProc            fGLGenQueries;
47     GLDeleteQueriesProc         fGLDeleteQueries;
48     GLBeginQueryProc            fGLBeginQuery;
49     GLEndQueryProc              fGLEndQuery;
50     GLGetQueryObjectuivProc     fGLGetQueryObjectuiv;
51     GLGetQueryObjectui64vProc   fGLGetQueryObjectui64v;
52 
53 
54     using INHERITED = sk_gpu_test::GpuTimer;
55 };
56 
MakeIfSupported(const sk_gpu_test::GLTestContext * ctx)57 std::unique_ptr<GLGpuTimer> GLGpuTimer::MakeIfSupported(const sk_gpu_test::GLTestContext* ctx) {
58     std::unique_ptr<GLGpuTimer> ret;
59     const GrGLInterface* gl = ctx->gl();
60     if (gl->fExtensions.has("GL_EXT_disjoint_timer_query")) {
61         ret.reset(new GLGpuTimer(true, ctx, "EXT"));
62     } else if (kGL_GrGLStandard == gl->fStandard &&
63                (GrGLGetVersion(gl) > GR_GL_VER(3,3) || gl->fExtensions.has("GL_ARB_timer_query"))) {
64         ret.reset(new GLGpuTimer(false, ctx));
65     } else if (gl->fExtensions.has("GL_EXT_timer_query")) {
66         ret.reset(new GLGpuTimer(false, ctx, "EXT"));
67     }
68     if (ret && !ret->validate()) {
69         ret = nullptr;
70     }
71     return ret;
72 }
73 
GLGpuTimer(bool disjointSupport,const sk_gpu_test::GLTestContext * ctx,const char * ext)74 GLGpuTimer::GLGpuTimer(bool disjointSupport, const sk_gpu_test::GLTestContext* ctx, const char* ext)
75     : INHERITED(disjointSupport) {
76     ctx->getGLProcAddress(&fGLGetIntegerv, "glGetIntegerv");
77     ctx->getGLProcAddress(&fGLGenQueries, "glGenQueries", ext);
78     ctx->getGLProcAddress(&fGLDeleteQueries, "glDeleteQueries", ext);
79     ctx->getGLProcAddress(&fGLBeginQuery, "glBeginQuery", ext);
80     ctx->getGLProcAddress(&fGLEndQuery, "glEndQuery", ext);
81     ctx->getGLProcAddress(&fGLGetQueryObjectuiv, "glGetQueryObjectuiv", ext);
82     ctx->getGLProcAddress(&fGLGetQueryObjectui64v, "glGetQueryObjectui64v", ext);
83 }
84 
validate() const85 bool GLGpuTimer::validate() const {
86     return fGLGetIntegerv && fGLGenQueries && fGLDeleteQueries && fGLBeginQuery && fGLEndQuery &&
87            fGLGetQueryObjectuiv && fGLGetQueryObjectui64v;
88 }
89 
onQueueTimerStart() const90 sk_gpu_test::PlatformTimerQuery GLGpuTimer::onQueueTimerStart() const {
91     GrGLuint queryID;
92     fGLGenQueries(1, &queryID);
93     if (!queryID) {
94         return sk_gpu_test::kInvalidTimerQuery;
95     }
96     if (this->disjointSupport()) {
97         // Clear the disjoint flag.
98         GrGLint disjoint;
99         fGLGetIntegerv(GL_GPU_DISJOINT, &disjoint);
100     }
101     fGLBeginQuery(GL_TIME_ELAPSED, queryID);
102     return static_cast<sk_gpu_test::PlatformTimerQuery>(queryID);
103 }
104 
onQueueTimerStop(sk_gpu_test::PlatformTimerQuery platformTimer) const105 void GLGpuTimer::onQueueTimerStop(sk_gpu_test::PlatformTimerQuery platformTimer) const {
106     if (sk_gpu_test::kInvalidTimerQuery == platformTimer) {
107         return;
108     }
109     fGLEndQuery(GL_TIME_ELAPSED);
110 }
111 
112 sk_gpu_test::GpuTimer::QueryStatus
checkQueryStatus(sk_gpu_test::PlatformTimerQuery platformTimer)113 GLGpuTimer::checkQueryStatus(sk_gpu_test::PlatformTimerQuery platformTimer) {
114     const GrGLuint queryID = static_cast<GrGLuint>(platformTimer);
115     if (!queryID) {
116         return QueryStatus::kInvalid;
117     }
118     GrGLuint available = 0;
119     fGLGetQueryObjectuiv(queryID, GL_QUERY_RESULT_AVAILABLE, &available);
120     if (!available) {
121         return QueryStatus::kPending;
122     }
123     if (this->disjointSupport()) {
124         GrGLint disjoint = 1;
125         fGLGetIntegerv(GL_GPU_DISJOINT, &disjoint);
126         if (disjoint) {
127             return QueryStatus::kDisjoint;
128         }
129     }
130     return QueryStatus::kAccurate;
131 }
132 
getTimeElapsed(sk_gpu_test::PlatformTimerQuery platformTimer)133 std::chrono::nanoseconds GLGpuTimer::getTimeElapsed(sk_gpu_test::PlatformTimerQuery platformTimer) {
134     SkASSERT(this->checkQueryStatus(platformTimer) >= QueryStatus::kDisjoint);
135     const GrGLuint queryID = static_cast<GrGLuint>(platformTimer);
136     GrGLuint64 nanoseconds;
137     fGLGetQueryObjectui64v(queryID, GL_QUERY_RESULT, &nanoseconds);
138     return std::chrono::nanoseconds(nanoseconds);
139 }
140 
deleteQuery(sk_gpu_test::PlatformTimerQuery platformTimer)141 void GLGpuTimer::deleteQuery(sk_gpu_test::PlatformTimerQuery platformTimer) {
142     const GrGLuint queryID = static_cast<GrGLuint>(platformTimer);
143     fGLDeleteQueries(1, &queryID);
144 }
145 
146 static_assert(sizeof(GrGLuint) <= sizeof(sk_gpu_test::PlatformTimerQuery));
147 
148 }  // anonymous namespace
149 
150 namespace sk_gpu_test {
151 
GLTestContext()152 GLTestContext::GLTestContext() : TestContext() {}
153 
~GLTestContext()154 GLTestContext::~GLTestContext() {
155     SkASSERT(!fGLInterface);
156     SkASSERT(!fOriginalGLInterface);
157 }
158 
isValid() const159 bool GLTestContext::isValid() const {
160     return SkToBool(this->gl());
161 }
162 
fence_is_supported(const GLTestContext * ctx)163 static bool fence_is_supported(const GLTestContext* ctx) {
164     if (kGL_GrGLStandard == ctx->gl()->fStandard) {
165         if (GrGLGetVersion(ctx->gl()) < GR_GL_VER(3, 2) &&
166             !ctx->gl()->hasExtension("GL_ARB_sync")) {
167             return false;
168         }
169         return true;
170     } else {
171         if (ctx->gl()->hasExtension("GL_APPLE_sync")) {
172             return true;
173         } else if (ctx->gl()->hasExtension("GL_NV_fence")) {
174             return true;
175         } else if (GrGLGetVersion(ctx->gl()) >= GR_GL_VER(3, 0)) {
176             return true;
177         } else {
178             return false;
179         }
180     }
181 }
182 
init(sk_sp<const GrGLInterface> gl)183 void GLTestContext::init(sk_sp<const GrGLInterface> gl) {
184     fGLInterface = std::move(gl);
185     fOriginalGLInterface = fGLInterface;
186     fFenceSupport = fence_is_supported(this);
187     fGpuTimer = GLGpuTimer::MakeIfSupported(this);
188 }
189 
teardown()190 void GLTestContext::teardown() {
191     fGLInterface.reset();
192     fOriginalGLInterface.reset();
193     INHERITED::teardown();
194 }
195 
testAbandon()196 void GLTestContext::testAbandon() {
197     INHERITED::testAbandon();
198 #if defined(GPU_TEST_UTILS)
199     if (fGLInterface) {
200         fGLInterface->abandon();
201         fOriginalGLInterface->abandon();
202     }
203 #endif
204 }
205 
overrideVersion(const char * version,const char * shadingLanguageVersion)206 void GLTestContext::overrideVersion(const char* version, const char* shadingLanguageVersion) {
207     // GrGLFunction has both a limited capture size and doesn't call a destructor when it is
208     // initialized with a lambda. So here we're trusting fOriginalGLInterface will be kept alive.
209     auto getString = [wrapped = &fOriginalGLInterface->fFunctions.fGetString,
210                       version,
211                       shadingLanguageVersion](GrGLenum name) {
212         if (name == GR_GL_VERSION) {
213             return reinterpret_cast<const GrGLubyte*>(version);
214         } else if (name == GR_GL_SHADING_LANGUAGE_VERSION) {
215             return reinterpret_cast<const GrGLubyte*>(shadingLanguageVersion);
216         }
217         return (*wrapped)(name);
218     };
219     auto newInterface = sk_make_sp<GrGLInterface>(*fOriginalGLInterface);
220     newInterface->fFunctions.fGetString = getString;
221     fGLInterface = std::move(newInterface);
222 }
223 
makeContext(const GrContextOptions & options)224 sk_sp<GrDirectContext> GLTestContext::makeContext(const GrContextOptions& options) {
225     return GrDirectContexts::MakeGL(fGLInterface, options);
226 }
227 
228 }  // namespace sk_gpu_test
229