Home | History | Annotate | Download | only in gl
      1 
      2 /*
      3  * Copyright 2013 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "gl/SkGLContext.h"
      9 #include "GrGLUtil.h"
     10 #include "SkGpuFenceSync.h"
     11 
     12 class SkGLContext::GLFenceSync : public SkGpuFenceSync {
     13 public:
     14     static GLFenceSync* CreateIfSupported(const SkGLContext*);
     15 
     16     SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const override;
     17     bool waitFence(SkPlatformGpuFence fence, bool flush) const override;
     18     void deleteFence(SkPlatformGpuFence fence) const override;
     19 
     20 private:
     21     GLFenceSync() {}
     22 
     23     static const GrGLenum GL_SYNC_GPU_COMMANDS_COMPLETE  = 0x9117;
     24     static const GrGLenum GL_WAIT_FAILED                 = 0x911d;
     25     static const GrGLbitfield GL_SYNC_FLUSH_COMMANDS_BIT = 0x00000001;
     26 
     27     typedef struct __GLsync *GLsync;
     28 
     29     typedef GLsync (GR_GL_FUNCTION_TYPE* GLFenceSyncProc) (GrGLenum, GrGLbitfield);
     30     typedef GrGLenum (GR_GL_FUNCTION_TYPE* GLClientWaitSyncProc) (GLsync, GrGLbitfield, GrGLuint64);
     31     typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GLDeleteSyncProc) (GLsync);
     32 
     33     GLFenceSyncProc        fGLFenceSync;
     34     GLClientWaitSyncProc   fGLClientWaitSync;
     35     GLDeleteSyncProc       fGLDeleteSync;
     36 
     37     typedef SkGpuFenceSync INHERITED;
     38 };
     39 
     40 SkGLContext::SkGLContext()
     41     : fCurrentFenceIdx(0) {
     42     memset(fFrameFences, 0, sizeof(fFrameFences));
     43 }
     44 
     45 SkGLContext::~SkGLContext() {
     46     // Subclass should call teardown.
     47 #ifdef SK_DEBUG
     48     for (size_t i = 0; i < SK_ARRAY_COUNT(fFrameFences); i++) {
     49         SkASSERT(0 == fFrameFences[i]);
     50     }
     51 #endif
     52     SkASSERT(nullptr == fGL.get());
     53     SkASSERT(nullptr == fFenceSync.get());
     54 }
     55 
     56 void SkGLContext::init(const GrGLInterface* gl, SkGpuFenceSync* fenceSync) {
     57     SkASSERT(!fGL.get());
     58     fGL.reset(gl);
     59     fFenceSync.reset(fenceSync ? fenceSync : GLFenceSync::CreateIfSupported(this));
     60 }
     61 
     62 void SkGLContext::teardown() {
     63     if (fFenceSync) {
     64         for (size_t i = 0; i < SK_ARRAY_COUNT(fFrameFences); i++) {
     65             if (fFrameFences[i]) {
     66                 fFenceSync->deleteFence(fFrameFences[i]);
     67                 fFrameFences[i] = 0;
     68             }
     69         }
     70         fFenceSync.reset(nullptr);
     71     }
     72 
     73     fGL.reset(nullptr);
     74 }
     75 
     76 void SkGLContext::makeCurrent() const {
     77     this->onPlatformMakeCurrent();
     78 }
     79 
     80 void SkGLContext::swapBuffers() {
     81     this->onPlatformSwapBuffers();
     82 }
     83 
     84 void SkGLContext::waitOnSyncOrSwap() {
     85     if (!fFenceSync) {
     86         // Fallback on the platform SwapBuffers method for synchronization. This may have no effect.
     87         this->swapBuffers();
     88         return;
     89     }
     90 
     91     if (fFrameFences[fCurrentFenceIdx]) {
     92         if (!fFenceSync->waitFence(fFrameFences[fCurrentFenceIdx], true)) {
     93             SkDebugf("WARNING: Wait failed for fence sync. Timings might not be accurate.\n");
     94         }
     95         fFenceSync->deleteFence(fFrameFences[fCurrentFenceIdx]);
     96     }
     97 
     98     fFrameFences[fCurrentFenceIdx] = fFenceSync->insertFence();
     99     fCurrentFenceIdx = (fCurrentFenceIdx + 1) % SK_ARRAY_COUNT(fFrameFences);
    100 }
    101 
    102 void SkGLContext::testAbandon() {
    103     if (fGL) {
    104         fGL->abandon();
    105     }
    106     if (fFenceSync) {
    107         memset(fFrameFences, 0, sizeof(fFrameFences));
    108     }
    109 }
    110 
    111 SkGLContext::GLFenceSync* SkGLContext::GLFenceSync::CreateIfSupported(const SkGLContext* ctx) {
    112     SkAutoTDelete<GLFenceSync> ret(new GLFenceSync);
    113 
    114     if (kGL_GrGLStandard == ctx->gl()->fStandard) {
    115         const GrGLubyte* versionStr;
    116         SK_GL_RET(*ctx, versionStr, GetString(GR_GL_VERSION));
    117         GrGLVersion version = GrGLGetVersionFromString(reinterpret_cast<const char*>(versionStr));
    118         if (version < GR_GL_VER(3,2) && !ctx->gl()->hasExtension("GL_ARB_sync")) {
    119             return nullptr;
    120         }
    121         ret->fGLFenceSync = reinterpret_cast<GLFenceSyncProc>(
    122             ctx->onPlatformGetProcAddress("glFenceSync"));
    123         ret->fGLClientWaitSync = reinterpret_cast<GLClientWaitSyncProc>(
    124             ctx->onPlatformGetProcAddress("glClientWaitSync"));
    125         ret->fGLDeleteSync = reinterpret_cast<GLDeleteSyncProc>(
    126             ctx->onPlatformGetProcAddress("glDeleteSync"));
    127     } else {
    128         if (!ctx->gl()->hasExtension("GL_APPLE_sync")) {
    129             return nullptr;
    130         }
    131         ret->fGLFenceSync = reinterpret_cast<GLFenceSyncProc>(
    132             ctx->onPlatformGetProcAddress("glFenceSyncAPPLE"));
    133         ret->fGLClientWaitSync = reinterpret_cast<GLClientWaitSyncProc>(
    134             ctx->onPlatformGetProcAddress("glClientWaitSyncAPPLE"));
    135         ret->fGLDeleteSync = reinterpret_cast<GLDeleteSyncProc>(
    136             ctx->onPlatformGetProcAddress("glDeleteSyncAPPLE"));
    137     }
    138 
    139     if (!ret->fGLFenceSync || !ret->fGLClientWaitSync || !ret->fGLDeleteSync) {
    140         return nullptr;
    141     }
    142 
    143     return ret.detach();
    144 }
    145 
    146 SkPlatformGpuFence SkGLContext::GLFenceSync::insertFence() const {
    147     return fGLFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
    148 }
    149 
    150 bool SkGLContext::GLFenceSync::waitFence(SkPlatformGpuFence fence, bool flush) const {
    151     GLsync glsync = static_cast<GLsync>(fence);
    152     return GL_WAIT_FAILED != fGLClientWaitSync(glsync, flush ? GL_SYNC_FLUSH_COMMANDS_BIT : 0, -1);
    153 }
    154 
    155 void SkGLContext::GLFenceSync::deleteFence(SkPlatformGpuFence fence) const {
    156     GLsync glsync = static_cast<GLsync>(fence);
    157     fGLDeleteSync(glsync);
    158 }
    159 
    160 GrGLint SkGLContext::createTextureRectangle(int width, int height, GrGLenum internalFormat,
    161                                             GrGLenum externalFormat, GrGLenum externalType,
    162                                             GrGLvoid* data) {
    163     if (!(kGL_GrGLStandard == fGL->fStandard && GrGLGetVersion(fGL) >= GR_GL_VER(3, 1)) &&
    164         !fGL->fExtensions.has("GL_ARB_texture_rectangle")) {
    165         return 0;
    166     }
    167 
    168     if  (GrGLGetGLSLVersion(fGL) < GR_GLSL_VER(1, 40)) {
    169         return 0;
    170     }
    171 
    172     GrGLuint id;
    173     GR_GL_CALL(fGL, GenTextures(1, &id));
    174     GR_GL_CALL(fGL, BindTexture(GR_GL_TEXTURE_RECTANGLE, id));
    175     GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_MAG_FILTER,
    176                                   GR_GL_NEAREST));
    177     GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_MIN_FILTER,
    178                                   GR_GL_NEAREST));
    179     GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_WRAP_S,
    180                                   GR_GL_CLAMP_TO_EDGE));
    181     GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_WRAP_T,
    182                                   GR_GL_CLAMP_TO_EDGE));
    183     GR_GL_CALL(fGL, TexImage2D(GR_GL_TEXTURE_RECTANGLE, 0, internalFormat, width, height, 0,
    184                                externalFormat, externalType, data));
    185     return id;
    186 }
    187