/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "MacPixelFormatsAttribs.h" // // EmuGLContext inherit from NSOpenGLContext // and adds binding state for the context to know // if it was last bounded to a pbuffer or a window. // This is because after the context was bounded to // a Pbuffer, before we bind it to a window we must // release it form the pbuffer by calling the // clearDrawable method. We do not want to call clearDrawable // more than really needed since when it is called at a time // that a window is bounded to the context it will clear the // window content causing flickering effect. // Thererfore we call clearDrawable only when we bind the context // to a window and it was previously bound to a Pbuffer. // @interface EmuGLContext : NSOpenGLContext { @private int boundToPbuffer; int boundToWin; @public GLuint ytexForDecoder; GLuint uvtexForDecoder; } - (id) initWithFormat:(NSOpenGLPixelFormat *)pixelFormat shareContext:(NSOpenGLContext *)share; - (void) preBind:(int)forPbuffer; @end @implementation EmuGLContext - (id) initWithFormat:(NSOpenGLPixelFormat *)pixelFormat shareContext:(NSOpenGLContext *)share { self = [super initWithFormat:pixelFormat shareContext:share]; if (self != nil) { boundToPbuffer = 0; boundToWin = 0; ytexForDecoder = 0; uvtexForDecoder = 0; } return self; } - (void) preBind:(int)forPbuffer { if ((!forPbuffer && boundToPbuffer)) { [self clearDrawable]; } boundToPbuffer = forPbuffer; boundToWin = !boundToPbuffer; } @end int getAttrListLength(const NSOpenGLPixelFormatAttribute* list) { int count = 0; while (list[count++] != 0); return count ? (count - 1) : 0; } static const NSOpenGLPixelFormatAttribute core32TestProfile[] = { NSOpenGLPFAAccelerated, NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, NSOpenGLPFADoubleBuffer, NSOpenGLPFAColorSize ,32, NSOpenGLPFADepthSize ,24, NSOpenGLPFAStencilSize ,8, 0 }; static const NSOpenGLPixelFormatAttribute core41TestProfile[] = { NSOpenGLPFAAccelerated, NSOpenGLPFANoRecovery, NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core, NSOpenGLPFADoubleBuffer, NSOpenGLPFAColorSize ,32, NSOpenGLPFADepthSize ,24, NSOpenGLPFAStencilSize ,8, 0 }; int setupCoreProfileNativeFormats() { NSOpenGLPixelFormat* core41Supported = [[NSOpenGLPixelFormat alloc] initWithAttributes: core41TestProfile]; if (core41Supported) { setCoreProfileLevel(NSOpenGLProfileVersion4_1Core); [core41Supported release]; return (int)NSOpenGLProfileVersion4_1Core; } NSOpenGLPixelFormat* core32Supported = [[NSOpenGLPixelFormat alloc] initWithAttributes: core32TestProfile]; if (core32Supported) { setCoreProfileLevel(NSOpenGLProfileVersion3_2Core); [core32Supported release]; return (int)NSOpenGLProfileVersion3_2Core; } return (int)NSOpenGLProfileVersionLegacy; } int getNumPixelFormats(){ int size; const NSOpenGLPixelFormatAttribute* const* attrib_lists = getPixelFormatsAttributes(&size); return size; } void* finalizePixelFormat(bool coreProfile, int attribsId) { int size; const NSOpenGLPixelFormatAttribute* const* attrib_lists = getPixelFormatsAttributes(&size); assert(attribsId < size); const NSOpenGLPixelFormatAttribute* attrs = attrib_lists[attribsId]; const NSOpenGLPixelFormatAttribute* selected_variant = coreProfile ? getCoreProfileAttributes() : getLegacyProfileAttributes(); // Format it as |variant| |attribs| int variant_size = getAttrListLength(selected_variant); int attrib_size = getAttrListLength(attrs); int numAttribsTotal = attrib_size + variant_size + 1; // for trailing 0 NSOpenGLPixelFormatAttribute* newAttrs = malloc(sizeof(NSOpenGLPixelFormatAttribute) * numAttribsTotal); int variant_part_bytes = sizeof(NSOpenGLPixelFormatAttribute) * variant_size; int attribs_part_bytes = sizeof(NSOpenGLPixelFormatAttribute) * attrib_size; memcpy(newAttrs, selected_variant, variant_part_bytes); memcpy((char*)newAttrs + variant_part_bytes, attrs, attribs_part_bytes); newAttrs[numAttribsTotal - 1] = 0; void* finalizedFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes: newAttrs]; free(newAttrs); return finalizedFormat; } static bool sIsKeyValueAttrib(NSOpenGLPixelFormatAttribute attrib) { switch (attrib) { // These are the ones that take a value, according to the current // NSOpenGLPixelFormat docs case NSOpenGLPFAOpenGLProfile: case NSOpenGLPFAAuxBuffers: case NSOpenGLPFAColorSize: case NSOpenGLPFAAlphaSize: case NSOpenGLPFADepthSize: case NSOpenGLPFAStencilSize: case NSOpenGLPFAAccumSize: case NSOpenGLPFARendererID: case NSOpenGLPFAScreenMask: return true; default: return false; } } int getPixelFormatAttrib(int i, int _query) { NSOpenGLPixelFormatAttribute query = (NSOpenGLPixelFormatAttribute)_query; int size; const NSOpenGLPixelFormatAttribute* const* attrib_lists = getPixelFormatsAttributes(&size); int attributes_num = i % size; const NSOpenGLPixelFormatAttribute* attribs = attrib_lists[attributes_num]; int res = 0; while (*attribs) { if (sIsKeyValueAttrib(*attribs)) { if (query == *attribs) { return attribs[1]; } attribs += 2; } else { // these are boolean attribs. // their mere presence signals // that the query should return true. if (query == *attribs) { return 1; } attribs++; } } // return 0 if key not found---takes care of all boolean attribs, // and we depend on returning alpha=0 to make the default // config for GLSurfaceView happy. return 0; } void* nsCreateContext(void* format,void* share){ NSOpenGLPixelFormat* frmt = (NSOpenGLPixelFormat*)format; return [[EmuGLContext alloc] initWithFormat:frmt shareContext:share]; } void* nsGetLowLevelContext(void* context) { EmuGLContext* ctx = (EmuGLContext*)context; return ctx; } void nsCopyTexture(void* context, int from, int to, int width, int height) { EmuGLContext* ctx = (EmuGLContext*)context; if (glGetError() != GL_NO_ERROR) { // ignore } int tex1 = from; int tex2 = to; GLuint g_fb = 0; glGenFramebuffers(1, &g_fb); glBindFramebuffer(GL_FRAMEBUFFER, g_fb); glBindTexture(GL_TEXTURE_RECTANGLE, tex1); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, tex1, 0); if (glGetError() != GL_NO_ERROR) { return; } glBindTexture(GL_TEXTURE_2D, tex2); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, tex2, 0); if (glGetError() != GL_NO_ERROR) { return; } glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height); glBindTexture(GL_TEXTURE_RECTANGLE, 0); glBindTexture(GL_TEXTURE_2D, 0); if (glGetError() != GL_NO_ERROR) { return; } glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteFramebuffers(1, &g_fb); } void nsConvertVideoFrameToNV12Textures(void* context, void* iosurface, int Ytexd, int UVtexd) { EmuGLContext* ctx = (EmuGLContext*)context; CGLContextObj cgl_ctx = ctx.CGLContextObj; glEnable(GL_TEXTURE_RECTANGLE); IOSurfaceRef* surface = (IOSurfaceRef*)iosurface; GLsizei surface_w = (GLsizei)IOSurfaceGetWidth(surface); GLsizei surface_h = (GLsizei)IOSurfaceGetHeight(surface); if (!ctx->ytexForDecoder) { glGenTextures(1, &ctx->ytexForDecoder); } if (!ctx->uvtexForDecoder) { glGenTextures(1, &ctx->uvtexForDecoder); } GLuint Ytex = ctx->ytexForDecoder; GLuint UVtex = ctx->uvtexForDecoder; glBindTexture(GL_TEXTURE_RECTANGLE, Ytex); CGLError cglError = CGLTexImageIOSurface2D( cgl_ctx, GL_TEXTURE_RECTANGLE, GL_R8, surface_w, surface_h, GL_RED, GL_UNSIGNED_BYTE, surface, 0); if (cglError != kCGLNoError) { return; } glBindTexture(GL_TEXTURE_RECTANGLE, UVtex); cglError = CGLTexImageIOSurface2D(cgl_ctx, GL_TEXTURE_RECTANGLE, GL_RG8, surface_w / 2, surface_h / 2, GL_RG, GL_UNSIGNED_BYTE, surface, 1); if (cglError != kCGLNoError) { return; } glBindTexture(GL_TEXTURE_RECTANGLE, 0); nsCopyTexture(context, (int)Ytex, Ytexd, surface_w, surface_h); nsCopyTexture(context, (int)UVtex, UVtexd, surface_w/2, surface_h/2); } void nsPBufferMakeCurrent(void* context,void* nativePBuffer,int level){ EmuGLContext* ctx = (EmuGLContext *)context; NSOpenGLPixelBuffer* pbuff = (NSOpenGLPixelBuffer *)nativePBuffer; if(ctx == nil){ [NSOpenGLContext clearCurrentContext]; } else { if(pbuff != nil){ [ctx preBind:1]; [ctx setPixelBuffer:pbuff cubeMapFace:0 mipMapLevel:level currentVirtualScreen:0]; [ctx makeCurrentContext]; } else { // in this case, pbuffers deprecated and disabled. [ctx preBind:0]; [ctx makeCurrentContext]; } } } void nsWindowMakeCurrent(void* context,void* nativeWin){ EmuGLContext* ctx = (EmuGLContext *)context; NSView* win = (NSView *)nativeWin; if(ctx == nil){ [NSOpenGLContext clearCurrentContext]; } else if (win != nil) { [ctx preBind:0]; [ctx setView: win]; [ctx makeCurrentContext]; } } void nsSwapBuffers(){ NSOpenGLContext* ctx = [NSOpenGLContext currentContext]; if(ctx != nil){ [ctx flushBuffer]; } } void nsSwapInterval(int *interval){ NSOpenGLContext* ctx = [NSOpenGLContext currentContext]; if( ctx != nil){ [ctx setValues:interval forParameter:NSOpenGLCPSwapInterval]; } } void nsDestroyContext(void* context){ EmuGLContext *ctx = (EmuGLContext*)context; if(ctx != nil){ if (ctx->ytexForDecoder != 0) { glDeleteTextures(1, &ctx->ytexForDecoder); ctx->ytexForDecoder = 0; } if (ctx->uvtexForDecoder != 0) { glDeleteTextures(1, &ctx->uvtexForDecoder); ctx->uvtexForDecoder = 0; } [ctx release]; } } void* nsCreatePBuffer(GLenum target,GLenum format,int maxMip,int width,int height){ return [[NSOpenGLPixelBuffer alloc] initWithTextureTarget:target textureInternalFormat:format textureMaxMipMapLevel:maxMip pixelsWide:width pixelsHigh:height]; } void nsDestroyPBuffer(void* pbuffer){ NSOpenGLPixelBuffer *pbuf = (NSOpenGLPixelBuffer*)pbuffer; if(pbuf != nil){ [pbuf release]; } } bool nsGetWinDims(void* win,unsigned int* width,unsigned int* height){ NSView* view = (NSView*)win; if(view != nil){ NSRect rect = [view bounds]; *width = rect.size.width; *height = rect.size.height; return true; } return false; } bool nsCheckColor(void* win,int colorSize){ NSView* view = (NSView*)win; if(view != nil){ NSWindow* wnd = [view window]; if(wnd != nil){ NSWindowDepth limit = [wnd depthLimit]; NSWindowDepth defaultLimit = [NSWindow defaultDepthLimit]; int depth = (limit != 0) ? NSBitsPerPixelFromDepth(limit): NSBitsPerPixelFromDepth(defaultLimit); return depth >= colorSize; } } return false; } void* nsGetLayer(void* win) { NSView* view = (NSView*)win; return view.layer; }