Home | History | Annotate | Download | only in gl
      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 "GLTestContext.h"
      9 
     10 #include "GrContext.h"
     11 #include "GpuTimer.h"
     12 #include "gl/GrGLUtil.h"
     13 
     14 namespace {
     15 
     16 class GLFenceSync : public sk_gpu_test::FenceSync {
     17 public:
     18     static std::unique_ptr<FenceSync> MakeIfSupported(const sk_gpu_test::GLTestContext*);
     19 
     20     sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override;
     21     bool waitFence(sk_gpu_test::PlatformFence fence) const override;
     22     void deleteFence(sk_gpu_test::PlatformFence fence) const override;
     23 
     24 private:
     25     GLFenceSync(const sk_gpu_test::GLTestContext*, const char* ext = "");
     26 
     27     bool validate() const override { return fGLFenceSync && fGLClientWaitSync && fGLDeleteSync; }
     28 
     29     static constexpr GrGLenum GL_SYNC_GPU_COMMANDS_COMPLETE  = 0x9117;
     30     static constexpr GrGLenum GL_WAIT_FAILED                 = 0x911d;
     31     static constexpr GrGLbitfield GL_SYNC_FLUSH_COMMANDS_BIT = 0x00000001;
     32 
     33     typedef struct __GLsync *GLsync;
     34     GR_STATIC_ASSERT(sizeof(GLsync) <= sizeof(sk_gpu_test::PlatformFence));
     35 
     36     typedef GLsync (GR_GL_FUNCTION_TYPE* GLFenceSyncProc) (GrGLenum, GrGLbitfield);
     37     typedef GrGLenum (GR_GL_FUNCTION_TYPE* GLClientWaitSyncProc) (GLsync, GrGLbitfield, GrGLuint64);
     38     typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GLDeleteSyncProc) (GLsync);
     39 
     40     GLFenceSyncProc        fGLFenceSync;
     41     GLClientWaitSyncProc   fGLClientWaitSync;
     42     GLDeleteSyncProc       fGLDeleteSync;
     43 
     44     typedef FenceSync INHERITED;
     45 };
     46 
     47 class GLNVFenceSync : public sk_gpu_test::FenceSync {
     48 public:
     49     GLNVFenceSync(const sk_gpu_test::GLTestContext*);
     50 
     51     sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override;
     52     bool waitFence(sk_gpu_test::PlatformFence fence) const override;
     53     void deleteFence(sk_gpu_test::PlatformFence fence) const override;
     54 
     55 private:
     56     bool validate() const override {
     57         return fGLGenFencesNV && fGLDeleteFencesNV && fGLSetFenceNV && fGLFinishFenceNV;
     58     }
     59 
     60     static constexpr GrGLenum GL_ALL_COMPLETED_NV = 0x84F2;
     61 
     62     typedef GrGLvoid(GR_GL_FUNCTION_TYPE* GLGenFencesNVProc) (GrGLsizei, GrGLuint*);
     63     typedef GrGLvoid(GR_GL_FUNCTION_TYPE* GLDeleteFencesNVProc) (GrGLsizei, const GrGLuint*);
     64     typedef GrGLvoid(GR_GL_FUNCTION_TYPE* GLSetFenceNVProc) (GrGLuint, GrGLenum);
     65     typedef GrGLvoid(GR_GL_FUNCTION_TYPE* GLFinishFenceNVProc) (GrGLuint);
     66 
     67     GLGenFencesNVProc    fGLGenFencesNV;
     68     GLDeleteFencesNVProc fGLDeleteFencesNV;
     69     GLSetFenceNVProc     fGLSetFenceNV;
     70     GLFinishFenceNVProc  fGLFinishFenceNV;
     71 
     72     typedef FenceSync INHERITED;
     73 };
     74 
     75 std::unique_ptr<sk_gpu_test::FenceSync> GLFenceSync::MakeIfSupported(
     76         const sk_gpu_test::GLTestContext* ctx) {
     77     std::unique_ptr<FenceSync> ret;
     78     if (kGL_GrGLStandard == ctx->gl()->fStandard) {
     79         if (GrGLGetVersion(ctx->gl()) < GR_GL_VER(3,2) && !ctx->gl()->hasExtension("GL_ARB_sync")) {
     80             return nullptr;
     81         }
     82         ret.reset(new GLFenceSync(ctx));
     83     } else {
     84         if (ctx->gl()->hasExtension("GL_APPLE_sync")) {
     85             ret.reset(new GLFenceSync(ctx, "APPLE"));
     86         } else if (ctx->gl()->hasExtension("GL_NV_fence")) {
     87             ret.reset(new GLNVFenceSync(ctx));
     88         } else if (GrGLGetVersion(ctx->gl()) >= GR_GL_VER(3, 0)) {
     89             ret.reset(new GLFenceSync(ctx));
     90         } else {
     91             return nullptr;
     92         }
     93     }
     94     if (!ret->validate()) {
     95         ret = nullptr;
     96     }
     97     return ret;
     98 }
     99 
    100 GLFenceSync::GLFenceSync(const sk_gpu_test::GLTestContext* ctx, const char* ext) {
    101     ctx->getGLProcAddress(&fGLFenceSync, "glFenceSync", ext);
    102     ctx->getGLProcAddress(&fGLClientWaitSync, "glClientWaitSync", ext);
    103     ctx->getGLProcAddress(&fGLDeleteSync, "glDeleteSync", ext);
    104 }
    105 
    106 sk_gpu_test::PlatformFence GLFenceSync::insertFence() const {
    107     __GLsync* glsync = fGLFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
    108     return reinterpret_cast<sk_gpu_test::PlatformFence>(glsync);
    109 }
    110 
    111 bool GLFenceSync::waitFence(sk_gpu_test::PlatformFence fence) const {
    112     GLsync glsync = reinterpret_cast<GLsync>(fence);
    113     return GL_WAIT_FAILED != fGLClientWaitSync(glsync, GL_SYNC_FLUSH_COMMANDS_BIT, -1);
    114 }
    115 
    116 void GLFenceSync::deleteFence(sk_gpu_test::PlatformFence fence) const {
    117     GLsync glsync = reinterpret_cast<GLsync>(fence);
    118     fGLDeleteSync(glsync);
    119 }
    120 
    121 GLNVFenceSync::GLNVFenceSync(const sk_gpu_test::GLTestContext* ctx) {
    122     ctx->getGLProcAddress(&fGLGenFencesNV, "glGenFencesNV");
    123     ctx->getGLProcAddress(&fGLDeleteFencesNV, "glDeleteFencesNV");
    124     ctx->getGLProcAddress(&fGLSetFenceNV, "glSetFenceNV");
    125     ctx->getGLProcAddress(&fGLFinishFenceNV, "glFinishFenceNV");
    126 }
    127 
    128 sk_gpu_test::PlatformFence GLNVFenceSync::insertFence() const {
    129     GrGLuint fence;
    130     fGLGenFencesNV(1, &fence);
    131     fGLSetFenceNV(fence, GL_ALL_COMPLETED_NV);
    132     return fence;
    133 }
    134 
    135 bool GLNVFenceSync::waitFence(sk_gpu_test::PlatformFence fence) const {
    136     fGLFinishFenceNV(fence);
    137     return true;
    138 }
    139 
    140 void GLNVFenceSync::deleteFence(sk_gpu_test::PlatformFence fence) const {
    141     GrGLuint glFence = static_cast<GrGLuint>(fence);
    142     fGLDeleteFencesNV(1, &glFence);
    143 }
    144 
    145 class GLGpuTimer : public sk_gpu_test::GpuTimer {
    146 public:
    147     static std::unique_ptr<GLGpuTimer> MakeIfSupported(const sk_gpu_test::GLTestContext*);
    148 
    149     QueryStatus checkQueryStatus(sk_gpu_test::PlatformTimerQuery) override;
    150     std::chrono::nanoseconds getTimeElapsed(sk_gpu_test::PlatformTimerQuery) override;
    151     void deleteQuery(sk_gpu_test::PlatformTimerQuery) override;
    152 
    153 private:
    154     GLGpuTimer(bool disjointSupport, const sk_gpu_test::GLTestContext*, const char* ext = "");
    155 
    156     bool validate() const;
    157 
    158     sk_gpu_test::PlatformTimerQuery onQueueTimerStart() const override;
    159     void onQueueTimerStop(sk_gpu_test::PlatformTimerQuery) const override;
    160 
    161     static constexpr GrGLenum GL_QUERY_RESULT            = 0x8866;
    162     static constexpr GrGLenum GL_QUERY_RESULT_AVAILABLE  = 0x8867;
    163     static constexpr GrGLenum GL_TIME_ELAPSED            = 0x88bf;
    164     static constexpr GrGLenum GL_GPU_DISJOINT            = 0x8fbb;
    165 
    166     typedef void (GR_GL_FUNCTION_TYPE* GLGetIntegervProc) (GrGLenum, GrGLint*);
    167     typedef void (GR_GL_FUNCTION_TYPE* GLGenQueriesProc) (GrGLsizei, GrGLuint*);
    168     typedef void (GR_GL_FUNCTION_TYPE* GLDeleteQueriesProc) (GrGLsizei, const GrGLuint*);
    169     typedef void (GR_GL_FUNCTION_TYPE* GLBeginQueryProc) (GrGLenum, GrGLuint);
    170     typedef void (GR_GL_FUNCTION_TYPE* GLEndQueryProc) (GrGLenum);
    171     typedef void (GR_GL_FUNCTION_TYPE* GLGetQueryObjectuivProc) (GrGLuint, GrGLenum, GrGLuint*);
    172     typedef void (GR_GL_FUNCTION_TYPE* GLGetQueryObjectui64vProc) (GrGLuint, GrGLenum, GrGLuint64*);
    173 
    174     GLGetIntegervProc           fGLGetIntegerv;
    175     GLGenQueriesProc            fGLGenQueries;
    176     GLDeleteQueriesProc         fGLDeleteQueries;
    177     GLBeginQueryProc            fGLBeginQuery;
    178     GLEndQueryProc              fGLEndQuery;
    179     GLGetQueryObjectuivProc     fGLGetQueryObjectuiv;
    180     GLGetQueryObjectui64vProc   fGLGetQueryObjectui64v;
    181 
    182 
    183     typedef sk_gpu_test::GpuTimer INHERITED;
    184 };
    185 
    186 std::unique_ptr<GLGpuTimer> GLGpuTimer::MakeIfSupported(const sk_gpu_test::GLTestContext* ctx) {
    187     std::unique_ptr<GLGpuTimer> ret;
    188     const GrGLInterface* gl = ctx->gl();
    189     if (gl->fExtensions.has("GL_EXT_disjoint_timer_query")) {
    190         ret.reset(new GLGpuTimer(true, ctx, "EXT"));
    191     } else if (kGL_GrGLStandard == gl->fStandard &&
    192                (GrGLGetVersion(gl) > GR_GL_VER(3,3) || gl->fExtensions.has("GL_ARB_timer_query"))) {
    193         ret.reset(new GLGpuTimer(false, ctx));
    194     } else if (gl->fExtensions.has("GL_EXT_timer_query")) {
    195         ret.reset(new GLGpuTimer(false, ctx, "EXT"));
    196     }
    197     if (ret && !ret->validate()) {
    198         ret = nullptr;
    199     }
    200     return ret;
    201 }
    202 
    203 GLGpuTimer::GLGpuTimer(bool disjointSupport, const sk_gpu_test::GLTestContext* ctx, const char* ext)
    204     : INHERITED(disjointSupport) {
    205     ctx->getGLProcAddress(&fGLGetIntegerv, "glGetIntegerv");
    206     ctx->getGLProcAddress(&fGLGenQueries, "glGenQueries", ext);
    207     ctx->getGLProcAddress(&fGLDeleteQueries, "glDeleteQueries", ext);
    208     ctx->getGLProcAddress(&fGLBeginQuery, "glBeginQuery", ext);
    209     ctx->getGLProcAddress(&fGLEndQuery, "glEndQuery", ext);
    210     ctx->getGLProcAddress(&fGLGetQueryObjectuiv, "glGetQueryObjectuiv", ext);
    211     ctx->getGLProcAddress(&fGLGetQueryObjectui64v, "glGetQueryObjectui64v", ext);
    212 }
    213 
    214 bool GLGpuTimer::validate() const {
    215     return fGLGetIntegerv && fGLGenQueries && fGLDeleteQueries && fGLBeginQuery && fGLEndQuery &&
    216            fGLGetQueryObjectuiv && fGLGetQueryObjectui64v;
    217 }
    218 
    219 sk_gpu_test::PlatformTimerQuery GLGpuTimer::onQueueTimerStart() const {
    220     GrGLuint queryID;
    221     fGLGenQueries(1, &queryID);
    222     if (!queryID) {
    223         return sk_gpu_test::kInvalidTimerQuery;
    224     }
    225     if (this->disjointSupport()) {
    226         // Clear the disjoint flag.
    227         GrGLint disjoint;
    228         fGLGetIntegerv(GL_GPU_DISJOINT, &disjoint);
    229     }
    230     fGLBeginQuery(GL_TIME_ELAPSED, queryID);
    231     return static_cast<sk_gpu_test::PlatformTimerQuery>(queryID);
    232 }
    233 
    234 void GLGpuTimer::onQueueTimerStop(sk_gpu_test::PlatformTimerQuery platformTimer) const {
    235     if (sk_gpu_test::kInvalidTimerQuery == platformTimer) {
    236         return;
    237     }
    238     fGLEndQuery(GL_TIME_ELAPSED);
    239 }
    240 
    241 sk_gpu_test::GpuTimer::QueryStatus
    242 GLGpuTimer::checkQueryStatus(sk_gpu_test::PlatformTimerQuery platformTimer) {
    243     const GrGLuint queryID = static_cast<GrGLuint>(platformTimer);
    244     if (!queryID) {
    245         return QueryStatus::kInvalid;
    246     }
    247     GrGLuint available = 0;
    248     fGLGetQueryObjectuiv(queryID, GL_QUERY_RESULT_AVAILABLE, &available);
    249     if (!available) {
    250         return QueryStatus::kPending;
    251     }
    252     if (this->disjointSupport()) {
    253         GrGLint disjoint = 1;
    254         fGLGetIntegerv(GL_GPU_DISJOINT, &disjoint);
    255         if (disjoint) {
    256             return QueryStatus::kDisjoint;
    257         }
    258     }
    259     return QueryStatus::kAccurate;
    260 }
    261 
    262 std::chrono::nanoseconds GLGpuTimer::getTimeElapsed(sk_gpu_test::PlatformTimerQuery platformTimer) {
    263     SkASSERT(this->checkQueryStatus(platformTimer) >= QueryStatus::kDisjoint);
    264     const GrGLuint queryID = static_cast<GrGLuint>(platformTimer);
    265     GrGLuint64 nanoseconds;
    266     fGLGetQueryObjectui64v(queryID, GL_QUERY_RESULT, &nanoseconds);
    267     return std::chrono::nanoseconds(nanoseconds);
    268 }
    269 
    270 void GLGpuTimer::deleteQuery(sk_gpu_test::PlatformTimerQuery platformTimer) {
    271     const GrGLuint queryID = static_cast<GrGLuint>(platformTimer);
    272     fGLDeleteQueries(1, &queryID);
    273 }
    274 
    275 GR_STATIC_ASSERT(sizeof(GrGLuint) <= sizeof(sk_gpu_test::PlatformTimerQuery));
    276 
    277 }  // anonymous namespace
    278 
    279 namespace sk_gpu_test {
    280 
    281 GLTestContext::GLTestContext() : TestContext() {}
    282 
    283 GLTestContext::~GLTestContext() {
    284     SkASSERT(nullptr == fGL.get());
    285 }
    286 
    287 void GLTestContext::init(sk_sp<const GrGLInterface> gl, std::unique_ptr<FenceSync> fenceSync) {
    288     fGL = std::move(gl);
    289     fFenceSync = fenceSync ? std::move(fenceSync) : GLFenceSync::MakeIfSupported(this);
    290     fGpuTimer = GLGpuTimer::MakeIfSupported(this);
    291 }
    292 
    293 void GLTestContext::teardown() {
    294     fGL.reset(nullptr);
    295     INHERITED::teardown();
    296 }
    297 
    298 void GLTestContext::testAbandon() {
    299     INHERITED::testAbandon();
    300     if (fGL) {
    301         fGL->abandon();
    302     }
    303 }
    304 
    305 void GLTestContext::submit() {
    306     if (fGL) {
    307         GR_GL_CALL(fGL.get(), Flush());
    308     }
    309 }
    310 
    311 void GLTestContext::finish() {
    312     if (fGL) {
    313         GR_GL_CALL(fGL.get(), Finish());
    314     }
    315 }
    316 
    317 GrGLint GLTestContext::createTextureRectangle(int width, int height, GrGLenum internalFormat,
    318                                           GrGLenum externalFormat, GrGLenum externalType,
    319                                           GrGLvoid* data) {
    320     if (!(kGL_GrGLStandard == fGL->fStandard && GrGLGetVersion(fGL.get()) >= GR_GL_VER(3, 1)) &&
    321         !fGL->fExtensions.has("GL_ARB_texture_rectangle")) {
    322         return 0;
    323     }
    324 
    325     if  (GrGLGetGLSLVersion(fGL.get()) < GR_GLSL_VER(1, 40)) {
    326         return 0;
    327     }
    328 
    329     GrGLuint id;
    330     GR_GL_CALL(fGL.get(), GenTextures(1, &id));
    331     GR_GL_CALL(fGL.get(), BindTexture(GR_GL_TEXTURE_RECTANGLE, id));
    332     GR_GL_CALL(fGL.get(), TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_MAG_FILTER,
    333                                         GR_GL_NEAREST));
    334     GR_GL_CALL(fGL.get(), TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_MIN_FILTER,
    335                                         GR_GL_NEAREST));
    336     GR_GL_CALL(fGL.get(), TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_WRAP_S,
    337                                         GR_GL_CLAMP_TO_EDGE));
    338     GR_GL_CALL(fGL.get(), TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_WRAP_T,
    339                                         GR_GL_CLAMP_TO_EDGE));
    340     GR_GL_CALL(fGL.get(), TexImage2D(GR_GL_TEXTURE_RECTANGLE, 0, internalFormat, width, height, 0,
    341                                      externalFormat, externalType, data));
    342     return id;
    343 }
    344 
    345 sk_sp<GrContext> GLTestContext::makeGrContext(const GrContextOptions& options) {
    346     return GrContext::MakeGL(fGL, options);
    347 }
    348 
    349 }  // namespace sk_gpu_test
    350