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