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:
GLFenceSync()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 
SkGLContext()40 SkGLContext::SkGLContext()
41     : fCurrentFenceIdx(0) {
42     memset(fFrameFences, 0, sizeof(fFrameFences));
43 }
44 
~SkGLContext()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 
init(const GrGLInterface * gl,SkGpuFenceSync * fenceSync)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 
teardown()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 
makeCurrent() const76 void SkGLContext::makeCurrent() const {
77     this->onPlatformMakeCurrent();
78 }
79 
swapBuffers()80 void SkGLContext::swapBuffers() {
81     this->onPlatformSwapBuffers();
82 }
83 
waitOnSyncOrSwap()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 
testAbandon()102 void SkGLContext::testAbandon() {
103     if (fGL) {
104         fGL->abandon();
105     }
106     if (fFenceSync) {
107         memset(fFrameFences, 0, sizeof(fFrameFences));
108     }
109 }
110 
CreateIfSupported(const SkGLContext * ctx)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 
insertFence() const146 SkPlatformGpuFence SkGLContext::GLFenceSync::insertFence() const {
147     return fGLFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
148 }
149 
waitFence(SkPlatformGpuFence fence,bool flush) const150 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 
deleteFence(SkPlatformGpuFence fence) const155 void SkGLContext::GLFenceSync::deleteFence(SkPlatformGpuFence fence) const {
156     GLsync glsync = static_cast<GLsync>(fence);
157     fGLDeleteSync(glsync);
158 }
159 
createTextureRectangle(int width,int height,GrGLenum internalFormat,GrGLenum externalFormat,GrGLenum externalType,GrGLvoid * data)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