1 /* 2 Copyright 2011 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 18 #include "GrTypes.h" 19 #include "GrGLInterface.h" 20 #include "GrGLDefines.h" 21 22 #include <stdio.h> 23 24 GrGLInterface* gGLInterface = NULL; 25 26 void gl_version_from_string(int* major, int* minor, 27 const char* versionString) { 28 if (NULL == versionString) { 29 GrAssert(0); 30 *major = 0; 31 *minor = 0; 32 return; 33 } 34 35 int n = sscanf(versionString, "%d.%d", major, minor); 36 if (2 == n) { 37 return; 38 } 39 40 char profile[2]; 41 n = sscanf(versionString, "OpenGL ES-%c%c %d.%d", profile, profile+1, 42 major, minor); 43 bool ok = 4 == n; 44 if (!ok) { 45 n = sscanf(versionString, "OpenGL ES %d.%d", major, minor); 46 ok = 2 == n; 47 } 48 49 if (!ok) { 50 GrAssert(0); 51 *major = 0; 52 *minor = 0; 53 return; 54 } 55 } 56 57 bool has_gl_extension_from_string(const char* ext, 58 const char* extensionString) { 59 int extLength = strlen(ext); 60 61 while (true) { 62 int n = strcspn(extensionString, " "); 63 if (n == extLength && 0 == strncmp(ext, extensionString, n)) { 64 return true; 65 } 66 if (0 == extensionString[n]) { 67 return false; 68 } 69 extensionString += n+1; 70 } 71 72 return false; 73 } 74 75 76 GR_API void GrGLSetGLInterface(GrGLInterface* gl_interface) { 77 gGLInterface = gl_interface; 78 } 79 80 GR_API GrGLInterface* GrGLGetGLInterface() { 81 return gGLInterface; 82 } 83 84 bool has_gl_extension(const char* ext) { 85 const char* glstr = reinterpret_cast<const char*>( 86 GrGLGetGLInterface()->fGetString(GR_GL_EXTENSIONS)); 87 88 return has_gl_extension_from_string(ext, glstr); 89 } 90 91 void gl_version(int* major, int* minor) { 92 const char* v = reinterpret_cast<const char*>( 93 GrGLGetGLInterface()->fGetString(GR_GL_VERSION)); 94 gl_version_from_string(major, minor, v); 95 } 96 97 bool GrGLInterface::validateShaderFunctions() const { 98 // required for GrGpuGLShaders 99 if (NULL == fAttachShader || 100 NULL == fBindAttribLocation || 101 NULL == fCompileShader || 102 NULL == fCreateProgram || 103 NULL == fCreateShader || 104 NULL == fDeleteProgram || 105 NULL == fDeleteShader || 106 NULL == fDisableVertexAttribArray || 107 NULL == fEnableVertexAttribArray || 108 NULL == fGetProgramInfoLog || 109 NULL == fGetProgramiv || 110 NULL == fGetShaderInfoLog || 111 NULL == fGetShaderiv || 112 NULL == fGetUniformLocation || 113 NULL == fLinkProgram || 114 NULL == fShaderSource || 115 NULL == fUniform1f || 116 NULL == fUniform1i || 117 NULL == fUniform1fv || 118 NULL == fUniform1iv || 119 NULL == fUniform2f || 120 NULL == fUniform2i || 121 NULL == fUniform2fv || 122 NULL == fUniform2iv || 123 NULL == fUniform3f || 124 NULL == fUniform3i || 125 NULL == fUniform3fv || 126 NULL == fUniform3iv || 127 NULL == fUniform4f || 128 NULL == fUniform4i || 129 NULL == fUniform4fv || 130 NULL == fUniform4iv || 131 NULL == fUniformMatrix2fv || 132 NULL == fUniformMatrix3fv || 133 NULL == fUniformMatrix4fv || 134 NULL == fUseProgram || 135 NULL == fVertexAttrib4fv || 136 NULL == fVertexAttribPointer) { 137 return false; 138 } 139 return true; 140 } 141 142 bool GrGLInterface::validateFixedFunctions() const { 143 if (NULL == fClientActiveTexture || 144 NULL == fColor4ub || 145 NULL == fColorPointer || 146 NULL == fDisableClientState || 147 NULL == fEnableClientState || 148 NULL == fLoadMatrixf || 149 NULL == fMatrixMode || 150 NULL == fPointSize || 151 NULL == fShadeModel || 152 NULL == fTexCoordPointer || 153 NULL == fTexEnvi || 154 NULL == fVertexPointer) { 155 return false; 156 } 157 return true; 158 } 159 160 bool GrGLInterface::validate(GrEngine engine) const { 161 162 bool isDesktop = kDesktop_GrGLBinding == fBindingsExported; 163 164 // ES1 and 2 can be supported in the same interface 165 bool isES = ((kES1_GrGLBinding | kES2_GrGLBinding) & fBindingsExported && 166 !(~(kES1_GrGLBinding | kES2_GrGLBinding) & fBindingsExported)); 167 168 if (!isDesktop && !isES) { 169 return false; 170 } 171 172 // functions that are always required 173 if (NULL == fActiveTexture || 174 NULL == fBindBuffer || 175 NULL == fBindTexture || 176 NULL == fBlendFunc || 177 NULL == fBufferData || 178 NULL == fBufferSubData || 179 NULL == fClear || 180 NULL == fClearColor || 181 NULL == fClearStencil || 182 NULL == fColorMask || 183 NULL == fCullFace || 184 NULL == fDeleteBuffers || 185 NULL == fDeleteTextures || 186 NULL == fDepthMask || 187 NULL == fDisable || 188 NULL == fDrawArrays || 189 NULL == fDrawElements || 190 NULL == fEnable || 191 NULL == fFrontFace || 192 NULL == fGenBuffers || 193 NULL == fGenTextures || 194 NULL == fGetBufferParameteriv || 195 NULL == fGetError || 196 NULL == fGetIntegerv || 197 NULL == fGetString || 198 NULL == fPixelStorei || 199 NULL == fReadPixels || 200 NULL == fScissor || 201 NULL == fStencilFunc || 202 NULL == fStencilMask || 203 NULL == fStencilOp || 204 NULL == fTexImage2D || 205 NULL == fTexParameteri || 206 NULL == fTexSubImage2D || 207 NULL == fViewport || 208 NULL == fBindFramebuffer || 209 NULL == fBindRenderbuffer || 210 NULL == fCheckFramebufferStatus || 211 NULL == fDeleteFramebuffers || 212 NULL == fDeleteRenderbuffers || 213 NULL == fFramebufferRenderbuffer || 214 NULL == fFramebufferTexture2D || 215 NULL == fGenFramebuffers || 216 NULL == fGenRenderbuffers || 217 NULL == fRenderbufferStorage) { 218 return false; 219 } 220 221 switch (engine) { 222 case kOpenGL_Shaders_GrEngine: 223 if (kES1_GrGLBinding == fBindingsExported) { 224 return false; 225 } 226 if (!this->validateShaderFunctions()) { 227 return false; 228 } 229 break; 230 case kOpenGL_Fixed_GrEngine: 231 if (kES1_GrGLBinding == fBindingsExported) { 232 return false; 233 } 234 if (!this->validateFixedFunctions()) { 235 return false; 236 } 237 break; 238 default: 239 return false; 240 } 241 242 int major, minor; 243 const char* ext; 244 245 gl_version(&major, &minor); 246 ext = (const char*)fGetString(GR_GL_EXTENSIONS); 247 248 // Now check that baseline ES/Desktop fns not covered above are present 249 // and that we have fn pointers for any advertised extensions that we will 250 // try to use. 251 252 // these functions are part of ES2, we assume they are available 253 // On the desktop we assume they are available if the extension 254 // is present or GL version is high enough. 255 if ((kES2_GrGLBinding & fBindingsExported)) { 256 if (NULL == fBlendColor || 257 NULL == fStencilFuncSeparate || 258 NULL == fStencilMaskSeparate || 259 NULL == fStencilOpSeparate) { 260 return false; 261 } 262 } else if (kDesktop_GrGLBinding == fBindingsExported) { 263 if (major >= 2) { 264 if (NULL == fStencilFuncSeparate || 265 NULL == fStencilMaskSeparate || 266 NULL == fStencilOpSeparate) { 267 return false; 268 } 269 } 270 if (1 < major || (1 == major && 4 <= minor) || 271 has_gl_extension_from_string("GL_EXT_blend_color", ext)) { 272 if (NULL == fBlendColor) { 273 return false; 274 } 275 } 276 } 277 278 // optional function on desktop before 1.3 279 if (kDesktop_GrGLBinding != fBindingsExported || 280 (1 < major || (1 == major && 3 <= minor)) || 281 has_gl_extension_from_string("GL_ARB_texture_compression", ext)) { 282 if (NULL == fCompressedTexImage2D) { 283 return false; 284 } 285 } 286 287 // part of desktop GL 288 if (kDesktop_GrGLBinding == fBindingsExported && 289 NULL == fLineWidth) { 290 return false; 291 } 292 // FBO MSAA 293 if (kDesktop_GrGLBinding == fBindingsExported) { 294 // GL 3.0 and the ARB extension have multisample + blit 295 if ((major >= 3) || has_gl_extension_from_string("GL_ARB_framebuffer_object", ext)) { 296 if (NULL == fRenderbufferStorageMultisample || 297 NULL == fBlitFramebuffer) { 298 return false; 299 } 300 } else { 301 if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", ext) && 302 NULL == fBlitFramebuffer) { 303 return false; 304 } 305 if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", ext) && 306 NULL == fRenderbufferStorageMultisample) { 307 return false; 308 } 309 } 310 } else { 311 if (has_gl_extension_from_string("GL_CHROMIUM_framebuffer_multisample", ext)) { 312 if (NULL == fRenderbufferStorageMultisample || 313 NULL == fBlitFramebuffer) { 314 return false; 315 } 316 } 317 if (has_gl_extension_from_string("GL_APPLE_framebuffer_multisample", ext)) { 318 if (NULL == fRenderbufferStorageMultisample || 319 NULL == fResolveMultisampleFramebuffer) { 320 return false; 321 } 322 } 323 } 324 325 // On ES buffer mapping is an extension. On Desktop 326 // buffer mapping was part of original VBO extension 327 // which we require. 328 if (kDesktop_GrGLBinding == fBindingsExported || 329 has_gl_extension_from_string("GL_OES_mapbuffer", ext)) { 330 if (NULL == fMapBuffer || 331 NULL == fUnmapBuffer) { 332 return false; 333 } 334 } 335 336 // Dual source blending 337 if (kDesktop_GrGLBinding == fBindingsExported && 338 (has_gl_extension_from_string("GL_ARB_blend_func_extended", ext) || 339 (3 < major) || (3 == major && 3 <= minor))) { 340 if (NULL == fBindFragDataLocationIndexed) { 341 return false; 342 } 343 } 344 345 return true; 346 } 347 348