1/* 2* Copyright (C) 2011 The Android Open Source Project 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#include <Cocoa/Cocoa.h> 17#include <OpenGL/OpenGL.h> 18#include <OpenGL/gl3.h> 19#include <stdio.h> 20#include "MacPixelFormatsAttribs.h" 21 22// 23// EmuGLContext inherit from NSOpenGLContext 24// and adds binding state for the context to know 25// if it was last bounded to a pbuffer or a window. 26// This is because after the context was bounded to 27// a Pbuffer, before we bind it to a window we must 28// release it form the pbuffer by calling the 29// clearDrawable method. We do not want to call clearDrawable 30// more than really needed since when it is called at a time 31// that a window is bounded to the context it will clear the 32// window content causing flickering effect. 33// Thererfore we call clearDrawable only when we bind the context 34// to a window and it was previously bound to a Pbuffer. 35// 36@interface EmuGLContext : NSOpenGLContext { 37 @private 38 int boundToPbuffer; 39 int boundToWin; 40 @public 41 GLuint ytexForDecoder; 42 GLuint uvtexForDecoder; 43} 44 45- (id) initWithFormat:(NSOpenGLPixelFormat *)pixelFormat shareContext:(NSOpenGLContext *)share; 46- (void) preBind:(int)forPbuffer; 47@end 48 49@implementation EmuGLContext 50- (id) initWithFormat:(NSOpenGLPixelFormat *)pixelFormat shareContext:(NSOpenGLContext *)share 51{ 52 self = [super initWithFormat:pixelFormat shareContext:share]; 53 if (self != nil) { 54 boundToPbuffer = 0; 55 boundToWin = 0; 56 ytexForDecoder = 0; 57 uvtexForDecoder = 0; 58 } 59 return self; 60} 61 62- (void) preBind:(int)forPbuffer 63{ 64 if ((!forPbuffer && boundToPbuffer)) { 65 [self clearDrawable]; 66 } 67 boundToPbuffer = forPbuffer; 68 boundToWin = !boundToPbuffer; 69} 70@end 71 72int getAttrListLength(const NSOpenGLPixelFormatAttribute* list) { 73 int count = 0; 74 while (list[count++] != 0); 75 return count ? (count - 1) : 0; 76} 77 78static const NSOpenGLPixelFormatAttribute core32TestProfile[] = { 79 NSOpenGLPFAAccelerated, 80 NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, 81 NSOpenGLPFADoubleBuffer, 82 NSOpenGLPFAColorSize ,32, 83 NSOpenGLPFADepthSize ,24, 84 NSOpenGLPFAStencilSize ,8, 85 0 86}; 87 88static const NSOpenGLPixelFormatAttribute core41TestProfile[] = { 89 NSOpenGLPFAAccelerated, 90 NSOpenGLPFANoRecovery, 91 NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core, 92 NSOpenGLPFADoubleBuffer, 93 NSOpenGLPFAColorSize ,32, 94 NSOpenGLPFADepthSize ,24, 95 NSOpenGLPFAStencilSize ,8, 96 0 97}; 98 99int setupCoreProfileNativeFormats() { 100 101 NSOpenGLPixelFormat* core41Supported = 102 [[NSOpenGLPixelFormat alloc] initWithAttributes: core41TestProfile]; 103 104 if (core41Supported) { 105 setCoreProfileLevel(NSOpenGLProfileVersion4_1Core); 106 [core41Supported release]; 107 return (int)NSOpenGLProfileVersion4_1Core; 108 } 109 110 NSOpenGLPixelFormat* core32Supported = 111 [[NSOpenGLPixelFormat alloc] initWithAttributes: core32TestProfile]; 112 113 if (core32Supported) { 114 setCoreProfileLevel(NSOpenGLProfileVersion3_2Core); 115 [core32Supported release]; 116 return (int)NSOpenGLProfileVersion3_2Core; 117 } 118 119 return (int)NSOpenGLProfileVersionLegacy; 120} 121 122int getNumPixelFormats(){ 123 int size; 124 const NSOpenGLPixelFormatAttribute* const* attrib_lists = 125 getPixelFormatsAttributes(&size); 126 return size; 127} 128 129void* finalizePixelFormat(bool coreProfile, 130 int attribsId) { 131 int size; 132 const NSOpenGLPixelFormatAttribute* const* attrib_lists = 133 getPixelFormatsAttributes(&size); 134 135 assert(attribsId < size); 136 137 const NSOpenGLPixelFormatAttribute* attrs = 138 attrib_lists[attribsId]; 139 140 const NSOpenGLPixelFormatAttribute* selected_variant = 141 coreProfile ? 142 getCoreProfileAttributes() : 143 getLegacyProfileAttributes(); 144 145 // Format it as |variant| |attribs| 146 int variant_size = 147 getAttrListLength(selected_variant); 148 int attrib_size = getAttrListLength(attrs); 149 int numAttribsTotal = attrib_size + variant_size + 1; // for trailing 0 150 151 NSOpenGLPixelFormatAttribute* newAttrs = 152 malloc(sizeof(NSOpenGLPixelFormatAttribute) * numAttribsTotal); 153 154 int variant_part_bytes = 155 sizeof(NSOpenGLPixelFormatAttribute) * variant_size; 156 int attribs_part_bytes = 157 sizeof(NSOpenGLPixelFormatAttribute) * attrib_size; 158 159 memcpy(newAttrs, selected_variant, variant_part_bytes); 160 memcpy((char*)newAttrs + variant_part_bytes, 161 attrs, attribs_part_bytes); 162 newAttrs[numAttribsTotal - 1] = 0; 163 164 void* finalizedFormat = 165 [[NSOpenGLPixelFormat alloc] initWithAttributes: newAttrs]; 166 167 free(newAttrs); 168 169 return finalizedFormat; 170} 171 172static bool sIsKeyValueAttrib(NSOpenGLPixelFormatAttribute attrib) { 173 switch (attrib) { 174 // These are the ones that take a value, according to the current 175 // NSOpenGLPixelFormat docs 176 case NSOpenGLPFAOpenGLProfile: 177 case NSOpenGLPFAAuxBuffers: 178 case NSOpenGLPFAColorSize: 179 case NSOpenGLPFAAlphaSize: 180 case NSOpenGLPFADepthSize: 181 case NSOpenGLPFAStencilSize: 182 case NSOpenGLPFAAccumSize: 183 case NSOpenGLPFARendererID: 184 case NSOpenGLPFAScreenMask: 185 return true; 186 default: 187 return false; 188 } 189} 190 191int getPixelFormatAttrib(int i, int _query) { 192 NSOpenGLPixelFormatAttribute query = 193 (NSOpenGLPixelFormatAttribute)_query; 194 int size; 195 const NSOpenGLPixelFormatAttribute* const* attrib_lists = getPixelFormatsAttributes(&size); 196 int attributes_num = i % size; 197 const NSOpenGLPixelFormatAttribute* attribs = attrib_lists[attributes_num]; 198 int res = 0; 199 while (*attribs) { 200 if (sIsKeyValueAttrib(*attribs)) { 201 if (query == *attribs) { 202 return attribs[1]; 203 } 204 attribs += 2; 205 } else { 206 // these are boolean attribs. 207 // their mere presence signals 208 // that the query should return true. 209 if (query == *attribs) { 210 return 1; 211 } 212 attribs++; 213 } 214 } 215 // return 0 if key not found---takes care of all boolean attribs, 216 // and we depend on returning alpha=0 to make the default 217 // config for GLSurfaceView happy. 218 return 0; 219} 220 221void* nsCreateContext(void* format,void* share){ 222 NSOpenGLPixelFormat* frmt = (NSOpenGLPixelFormat*)format; 223 return [[EmuGLContext alloc] initWithFormat:frmt shareContext:share]; 224} 225 226void* nsGetLowLevelContext(void* context) { 227 EmuGLContext* ctx = (EmuGLContext*)context; 228 return ctx; 229} 230 231void nsCopyTexture(void* context, int from, int to, int width, int height) { 232 EmuGLContext* ctx = (EmuGLContext*)context; 233 234 if (glGetError() != GL_NO_ERROR) { 235 // ignore 236 } 237 int tex1 = from; 238 int tex2 = to; 239 GLuint g_fb = 0; 240 glGenFramebuffers(1, &g_fb); 241 glBindFramebuffer(GL_FRAMEBUFFER, g_fb); 242 glBindTexture(GL_TEXTURE_RECTANGLE, tex1); 243 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 244 GL_TEXTURE_RECTANGLE, tex1, 0); 245 if (glGetError() != GL_NO_ERROR) { 246 return; 247 } 248 glBindTexture(GL_TEXTURE_2D, tex2); 249 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, 250 GL_TEXTURE_2D, tex2, 0); 251 if (glGetError() != GL_NO_ERROR) { 252 return; 253 } 254 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height); 255 256 glBindTexture(GL_TEXTURE_RECTANGLE, 0); 257 glBindTexture(GL_TEXTURE_2D, 0); 258 259 if (glGetError() != GL_NO_ERROR) { 260 return; 261 } 262 263 glBindFramebuffer(GL_FRAMEBUFFER, 0); 264 glDeleteFramebuffers(1, &g_fb); 265} 266 267void nsConvertVideoFrameToNV12Textures(void* context, 268 void* iosurface, 269 int Ytexd, 270 int UVtexd) { 271 EmuGLContext* ctx = (EmuGLContext*)context; 272 273 CGLContextObj cgl_ctx = ctx.CGLContextObj; 274 275 glEnable(GL_TEXTURE_RECTANGLE); 276 277 IOSurfaceRef* surface = (IOSurfaceRef*)iosurface; 278 279 GLsizei surface_w = (GLsizei)IOSurfaceGetWidth(surface); 280 GLsizei surface_h = (GLsizei)IOSurfaceGetHeight(surface); 281 282 if (!ctx->ytexForDecoder) { 283 glGenTextures(1, &ctx->ytexForDecoder); 284 } 285 if (!ctx->uvtexForDecoder) { 286 glGenTextures(1, &ctx->uvtexForDecoder); 287 } 288 GLuint Ytex = ctx->ytexForDecoder; 289 GLuint UVtex = ctx->uvtexForDecoder; 290 291 glBindTexture(GL_TEXTURE_RECTANGLE, Ytex); 292 CGLError cglError = CGLTexImageIOSurface2D( 293 cgl_ctx, GL_TEXTURE_RECTANGLE, GL_R8, surface_w, surface_h, GL_RED, 294 GL_UNSIGNED_BYTE, surface, 0); 295 296 if (cglError != kCGLNoError) { 297 return; 298 } 299 300 glBindTexture(GL_TEXTURE_RECTANGLE, UVtex); 301 cglError = CGLTexImageIOSurface2D(cgl_ctx, GL_TEXTURE_RECTANGLE, GL_RG8, 302 surface_w / 2, surface_h / 2, GL_RG, 303 GL_UNSIGNED_BYTE, surface, 1); 304 305 if (cglError != kCGLNoError) { 306 return; 307 } 308 glBindTexture(GL_TEXTURE_RECTANGLE, 0); 309 310 nsCopyTexture(context, (int)Ytex, Ytexd, surface_w, surface_h); 311 nsCopyTexture(context, (int)UVtex, UVtexd, surface_w/2, surface_h/2); 312} 313 314void nsPBufferMakeCurrent(void* context,void* nativePBuffer,int level){ 315 EmuGLContext* ctx = (EmuGLContext *)context; 316 NSOpenGLPixelBuffer* pbuff = (NSOpenGLPixelBuffer *)nativePBuffer; 317 if(ctx == nil){ 318 [NSOpenGLContext clearCurrentContext]; 319 } else { 320 if(pbuff != nil){ 321 [ctx preBind:1]; 322 [ctx setPixelBuffer:pbuff cubeMapFace:0 mipMapLevel:level currentVirtualScreen:0]; 323 [ctx makeCurrentContext]; 324 } else { 325 // in this case, pbuffers deprecated and disabled. 326 [ctx preBind:0]; 327 [ctx makeCurrentContext]; 328 } 329 } 330} 331 332void nsWindowMakeCurrent(void* context,void* nativeWin){ 333 EmuGLContext* ctx = (EmuGLContext *)context; 334 NSView* win = (NSView *)nativeWin; 335 if(ctx == nil){ 336 [NSOpenGLContext clearCurrentContext]; 337 } else if (win != nil) { 338 [ctx preBind:0]; 339 [ctx setView: win]; 340 [ctx makeCurrentContext]; 341 } 342} 343 344void nsSwapBuffers(){ 345 NSOpenGLContext* ctx = [NSOpenGLContext currentContext]; 346 if(ctx != nil){ 347 [ctx flushBuffer]; 348 } 349} 350 351void nsSwapInterval(int *interval){ 352 NSOpenGLContext* ctx = [NSOpenGLContext currentContext]; 353 if( ctx != nil){ 354 [ctx setValues:interval forParameter:NSOpenGLCPSwapInterval]; 355 } 356} 357 358 359void nsDestroyContext(void* context){ 360 EmuGLContext *ctx = (EmuGLContext*)context; 361 if(ctx != nil){ 362 if (ctx->ytexForDecoder != 0) { 363 glDeleteTextures(1, &ctx->ytexForDecoder); 364 ctx->ytexForDecoder = 0; 365 } 366 if (ctx->uvtexForDecoder != 0) { 367 glDeleteTextures(1, &ctx->uvtexForDecoder); 368 ctx->uvtexForDecoder = 0; 369 } 370 [ctx release]; 371 } 372} 373 374 375void* nsCreatePBuffer(GLenum target,GLenum format,int maxMip,int width,int height){ 376 return [[NSOpenGLPixelBuffer alloc] initWithTextureTarget:target 377 textureInternalFormat:format 378 textureMaxMipMapLevel:maxMip 379 pixelsWide:width pixelsHigh:height]; 380 381} 382 383void nsDestroyPBuffer(void* pbuffer){ 384 NSOpenGLPixelBuffer *pbuf = (NSOpenGLPixelBuffer*)pbuffer; 385 if(pbuf != nil){ 386 [pbuf release]; 387 } 388} 389 390bool nsGetWinDims(void* win,unsigned int* width,unsigned int* height){ 391 NSView* view = (NSView*)win; 392 if(view != nil){ 393 NSRect rect = [view bounds]; 394 *width = rect.size.width; 395 *height = rect.size.height; 396 return true; 397 } 398 return false; 399} 400 401bool nsCheckColor(void* win,int colorSize){ 402 NSView* view = (NSView*)win; 403 if(view != nil){ 404 NSWindow* wnd = [view window]; 405 if(wnd != nil){ 406 NSWindowDepth limit = [wnd depthLimit]; 407 NSWindowDepth defaultLimit = [NSWindow defaultDepthLimit]; 408 409 int depth = (limit != 0) ? NSBitsPerPixelFromDepth(limit): 410 NSBitsPerPixelFromDepth(defaultLimit); 411 return depth >= colorSize; 412 413 } 414 } 415 return false; 416 417} 418 419void* nsGetLayer(void* win) { 420 NSView* view = (NSView*)win; 421 return view.layer; 422} 423