bsalomon@google.com | 27847de | 2011-02-22 20:59:41 +0000 | [diff] [blame] | 1 | /* |
| 2 | Copyright 2010 Google Inc. |
| 3 | |
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | you may not use this file except in compliance with the License. |
| 6 | You may obtain a copy of the License at |
| 7 | |
| 8 | http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | |
| 10 | Unless required by applicable law or agreed to in writing, software |
| 11 | distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | See the License for the specific language governing permissions and |
| 14 | limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include "GrGLConfig.h" |
| 18 | #include "GrTypes.h" |
| 19 | #include <stdio.h> |
| 20 | |
| 21 | bool has_gl_extension(const char* ext) { |
| 22 | const char* glstr = (const char*) glGetString(GL_EXTENSIONS); |
| 23 | |
| 24 | int extLength = strlen(ext); |
| 25 | |
| 26 | while (true) { |
| 27 | int n = strcspn(glstr, " "); |
| 28 | if (n == extLength && 0 == strncmp(ext, glstr, n)) { |
| 29 | return true; |
| 30 | } |
| 31 | if (0 == glstr[n]) { |
| 32 | return false; |
| 33 | } |
| 34 | glstr += n+1; |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | void gl_version(int* major, int* minor) { |
| 39 | const char* v = (const char*) glGetString(GL_VERSION); |
| 40 | if (NULL == v) { |
| 41 | GrAssert(0); |
| 42 | *major = 0; |
| 43 | *minor = 0; |
| 44 | return; |
| 45 | } |
| 46 | #if GR_SUPPORT_GLDESKTOP |
| 47 | int n = sscanf(v, "%d.%d", major, minor); |
| 48 | if (n != 2) { |
| 49 | GrAssert(0); |
| 50 | *major = 0; |
| 51 | *minor = 0; |
| 52 | return; |
| 53 | } |
| 54 | #else |
| 55 | char profile[2]; |
| 56 | int n = sscanf(v, "OpenGL ES-%c%c %d.%d", profile, profile+1, major, minor); |
| 57 | bool ok = 4 == n; |
| 58 | if (!ok) { |
| 59 | int n = sscanf(v, "OpenGL ES %d.%d", major, minor); |
| 60 | ok = 2 == n; |
| 61 | } |
| 62 | if (!ok) { |
| 63 | GrAssert(0); |
| 64 | *major = 0; |
| 65 | *minor = 0; |
| 66 | return; |
| 67 | } |
| 68 | #endif |
| 69 | } |
| 70 | |
| 71 | #if defined(GR_GL_PROC_ADDRESS_HEADER) |
| 72 | #include GR_GL_PROC_ADDRESS_HEADER |
| 73 | #endif |
| 74 | |
| 75 | typedef void (*glProc)(void); |
| 76 | |
| 77 | #define GET_PROC(EXT_STRUCT, PROC_NAME) \ |
| 78 | *(GrTCast<glProc*>(&(EXT_STRUCT-> PROC_NAME))) = (glProc)GR_GL_PROC_ADDRESS((gl ## PROC_NAME)); \ |
| 79 | GrAssert(NULL != EXT_STRUCT-> PROC_NAME) |
| 80 | |
| 81 | #define GET_SUFFIX_PROC(EXT_STRUCT, PROC_NAME, SUFFIX) \ |
| 82 | *(GrTCast<glProc*>(&(EXT_STRUCT-> PROC_NAME))) = (glProc)GR_GL_PROC_ADDRESS((gl ## PROC_NAME ## SUFFIX)); \ |
| 83 | GrAssert(NULL != EXT_STRUCT-> PROC_NAME) |
| 84 | |
| 85 | extern void GrGLInitExtensions(GrGLExts* exts) { |
| 86 | exts->GenFramebuffers = NULL; |
| 87 | exts->BindFramebuffer = NULL; |
| 88 | exts->FramebufferTexture2D = NULL; |
| 89 | exts->CheckFramebufferStatus = NULL; |
| 90 | exts->DeleteFramebuffers = NULL; |
| 91 | exts->RenderbufferStorage = NULL; |
| 92 | exts->GenRenderbuffers = NULL; |
| 93 | exts->DeleteRenderbuffers = NULL; |
| 94 | exts->FramebufferRenderbuffer = NULL; |
| 95 | exts->BindRenderbuffer = NULL; |
| 96 | exts->RenderbufferStorageMultisample = NULL; |
| 97 | exts->BlitFramebuffer = NULL; |
| 98 | exts->ResolveMultisampleFramebuffer = NULL; |
| 99 | exts->FramebufferTexture2DMultisample = NULL; |
| 100 | exts->MapBuffer = NULL; |
| 101 | exts->UnmapBuffer = NULL; |
| 102 | |
| 103 | GLint major, minor; |
| 104 | gl_version(&major, &minor); |
| 105 | |
| 106 | bool fboFound = false; |
| 107 | #if GR_SUPPORT_GLDESKTOP |
| 108 | #if defined(GL_VERSION_3_0) && GL_VERSION_3_0 |
| 109 | if (!fboFound && major >= 3) { // all of ARB_fbo is in 3.x |
| 110 | exts->GenFramebuffers = glGenFramebuffers; |
| 111 | exts->BindFramebuffer = glBindFramebuffer; |
| 112 | exts->FramebufferTexture2D = glFramebufferTexture2D; |
| 113 | exts->CheckFramebufferStatus = glCheckFramebufferStatus; |
| 114 | exts->DeleteFramebuffers = glDeleteFramebuffers; |
| 115 | exts->RenderbufferStorage = glRenderbufferStorage; |
| 116 | exts->GenRenderbuffers = glGenRenderbuffers; |
| 117 | exts->DeleteRenderbuffers = glDeleteRenderbuffers; |
| 118 | exts->FramebufferRenderbuffer = glFramebufferRenderbuffer; |
| 119 | exts->BindRenderbuffer = glBindRenderbuffer; |
| 120 | exts->RenderbufferStorageMultisample = glRenderbufferStorageMultisample; |
| 121 | exts->BlitFramebuffer = glBlitFramebuffer; |
| 122 | fboFound = true; |
| 123 | } |
| 124 | #endif |
| 125 | #if GL_ARB_framebuffer_object |
| 126 | if (!fboFound && has_gl_extension("GL_ARB_framebuffer_object")) { |
| 127 | // GL_ARB_framebuffer_object doesn't use ARB suffix. |
| 128 | GET_PROC(exts, GenFramebuffers); |
| 129 | GET_PROC(exts, BindFramebuffer); |
| 130 | GET_PROC(exts, FramebufferTexture2D); |
| 131 | GET_PROC(exts, CheckFramebufferStatus); |
| 132 | GET_PROC(exts, DeleteFramebuffers); |
| 133 | GET_PROC(exts, RenderbufferStorage); |
| 134 | GET_PROC(exts, GenRenderbuffers); |
| 135 | GET_PROC(exts, DeleteRenderbuffers); |
| 136 | GET_PROC(exts, FramebufferRenderbuffer); |
| 137 | GET_PROC(exts, BindRenderbuffer); |
| 138 | GET_PROC(exts, RenderbufferStorageMultisample); |
| 139 | GET_PROC(exts, BlitFramebuffer); |
| 140 | fboFound = true; |
| 141 | } |
| 142 | #endif |
| 143 | // Mac doesn't declare prototypes for EXT FBO extensions |
| 144 | #if GL_EXT_framebuffer_object && !GR_MAC_BUILD |
| 145 | if (!fboFound && has_gl_extension("GL_EXT_framebuffer_object")) { |
| 146 | GET_SUFFIX_PROC(exts, GenFramebuffers, EXT); |
| 147 | GET_SUFFIX_PROC(exts, BindFramebuffer, EXT); |
| 148 | GET_SUFFIX_PROC(exts, FramebufferTexture2D, EXT); |
| 149 | GET_SUFFIX_PROC(exts, CheckFramebufferStatus, EXT); |
| 150 | GET_SUFFIX_PROC(exts, DeleteFramebuffers, EXT); |
| 151 | GET_SUFFIX_PROC(exts, RenderbufferStorage, EXT); |
| 152 | GET_SUFFIX_PROC(exts, GenRenderbuffers, EXT); |
| 153 | GET_SUFFIX_PROC(exts, DeleteRenderbuffers, EXT); |
| 154 | GET_SUFFIX_PROC(exts, FramebufferRenderbuffer, EXT); |
| 155 | GET_SUFFIX_PROC(exts, BindRenderbuffer, EXT); |
| 156 | fboFound = true; |
| 157 | // check for fbo ms and fbo blit |
| 158 | #if GL_EXT_framebuffer_multisample |
| 159 | if (has_gl_extension("GL_EXT_framebuffer_multisample")) { |
| 160 | GET_SUFFIX_PROC(exts, RenderbufferStorageMultisample, EXT); |
| 161 | } |
| 162 | #endif |
| 163 | #if GL_EXT_framebuffer_blit |
| 164 | if (has_gl_extension("GL_EXT_framebuffer_blit")) { |
| 165 | GET_SUFFIX_PROC(exts, BlitFramebuffer, EXT); |
| 166 | } |
| 167 | #endif |
| 168 | } |
| 169 | #endif |
| 170 | if (!fboFound) { |
| 171 | // we require some form of FBO |
| 172 | GrAssert(!"No FBOs supported?"); |
| 173 | } |
| 174 | // we assume we have at least GL 1.5 or higher (VBOs introduced in 1.5) |
| 175 | exts->MapBuffer = glMapBuffer; |
| 176 | exts->UnmapBuffer = glUnmapBuffer; |
| 177 | #else // !GR_SUPPORT_GLDESKTOP |
| 178 | #if GR_SUPPORT_GLES2 |
| 179 | if (!fboFound && major >= 2) {// ES 2.0 supports FBO |
| 180 | exts->GenFramebuffers = glGenFramebuffers; |
| 181 | exts->BindFramebuffer = glBindFramebuffer; |
| 182 | exts->FramebufferTexture2D = glFramebufferTexture2D; |
| 183 | exts->CheckFramebufferStatus = glCheckFramebufferStatus; |
| 184 | exts->DeleteFramebuffers = glDeleteFramebuffers; |
| 185 | exts->RenderbufferStorage = glRenderbufferStorage; |
| 186 | exts->GenRenderbuffers = glGenRenderbuffers; |
| 187 | exts->DeleteRenderbuffers = glDeleteRenderbuffers; |
| 188 | exts->FramebufferRenderbuffer = glFramebufferRenderbuffer; |
| 189 | exts->BindRenderbuffer = glBindRenderbuffer; |
| 190 | fboFound = true; |
| 191 | } |
| 192 | #endif |
| 193 | #if GL_OES_framebuffer_object |
| 194 | if (!fboFound && has_gl_extension("GL_OES_framebuffer_object")) { |
| 195 | GET_SUFFIX_PROC(exts, GenFramebuffers, OES); |
| 196 | GET_SUFFIX_PROC(exts, BindFramebuffer, OES); |
| 197 | GET_SUFFIX_PROC(exts, FramebufferTexture2D, OES); |
| 198 | GET_SUFFIX_PROC(exts, CheckFramebufferStatus, OES); |
| 199 | GET_SUFFIX_PROC(exts, DeleteFramebuffers, OES); |
| 200 | GET_SUFFIX_PROC(exts, RenderbufferStorage, OES); |
| 201 | GET_SUFFIX_PROC(exts, GenRenderbuffers, OES); |
| 202 | GET_SUFFIX_PROC(exts, DeleteRenderbuffers, OES); |
| 203 | GET_SUFFIX_PROC(exts, FramebufferRenderbuffer, OES); |
| 204 | GET_SUFFIX_PROC(exts, BindRenderbuffer, OES); |
| 205 | } |
| 206 | #endif |
| 207 | |
| 208 | if (!fboFound) { |
| 209 | // we require some form of FBO |
| 210 | GrAssert(!"No FBOs supported?"); |
| 211 | } |
| 212 | |
| 213 | #if GL_APPLE_framebuffer_multisample |
| 214 | if (has_gl_extension("GL_APPLE_framebuffer_multisample")) { |
| 215 | GET_SUFFIX_PROC(exts, ResolveMultisampleFramebuffer, APPLE); |
| 216 | } |
| 217 | #endif |
| 218 | |
| 219 | #if GL_IMG_multisampled_render_to_texture |
| 220 | if (has_gl_extension("GL_IMG_multisampled_render_to_texture")) { |
| 221 | GET_SUFFIX_PROC(exts, FramebufferTexture2DMultisample, IMG); |
| 222 | } |
| 223 | #endif |
| 224 | |
| 225 | #if GL_OES_mapbuffer |
| 226 | if (has_gl_extension("GL_OES_mapbuffer")) { |
| 227 | GET_SUFFIX_PROC(exts, MapBuffer, OES); |
| 228 | GET_SUFFIX_PROC(exts, UnmapBuffer, OES); |
| 229 | } |
| 230 | #endif |
| 231 | #endif // !GR_SUPPORT_GLDESKTOP |
| 232 | } |
| 233 | |
| 234 | |
| 235 | /////////////////////////////////////////////////////////////////////////////// |
| 236 | |
| 237 | void GrGLCheckErr(const char* location, const char* call) { |
| 238 | uint32_t err = glGetError(); |
| 239 | if (GL_NO_ERROR != err) { |
| 240 | GrPrintf("---- glGetError %x", err); |
| 241 | if (NULL != location) { |
| 242 | GrPrintf(" at\n\t%s", location); |
| 243 | } |
| 244 | if (NULL != call) { |
| 245 | GrPrintf("\n\t\t%s", call); |
| 246 | } |
| 247 | GrPrintf("\n"); |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | /////////////////////////////////////////////////////////////////////////////// |
| 252 | |
| 253 | bool gLogCallsGL = !!(GR_GL_LOG_CALLS_START); |
| 254 | |
| 255 | bool gCheckErrorGL = !!(GR_GL_CHECK_ERROR_START); |