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 <stdio.h> 17#include <Cocoa/Cocoa.h> 18#include <OpenGL/OpenGL.h> 19#include "MacPixelFormatsAttribs.h" 20 21// 22// EmuGLContext inherit from NSOpenGLContext 23// and adds binding state for the context to know 24// if it was last bounded to a pbuffer or a window. 25// This is because after the context was bounded to 26// a Pbuffer, before we bind it to a window we must 27// release it form the pbuffer by calling the 28// clearDrawable method. We do not want to call clearDrawable 29// more than really needed since when it is called at a time 30// that a window is bounded to the context it will clear the 31// window content causing flickering effect. 32// Thererfore we call clearDrawable only when we bind the context 33// to a window and it was previously bound to a Pbuffer. 34// 35@interface EmuGLContext : NSOpenGLContext { 36 @private 37 int boundToPbuffer; 38 int boundToWin; 39} 40 41- (id) initWithFormat:(NSOpenGLPixelFormat *)pixelFormat shareContext:(NSOpenGLContext *)share; 42- (void) preBind:(int)forPbuffer; 43@end 44 45@implementation EmuGLContext 46- (id) initWithFormat:(NSOpenGLPixelFormat *)pixelFormat shareContext:(NSOpenGLContext *)share 47{ 48 self = [super initWithFormat:pixelFormat shareContext:share]; 49 if (self != nil) { 50 boundToPbuffer = 0; 51 boundToWin = 0; 52 } 53 return self; 54} 55 56- (void) preBind:(int)forPbuffer 57{ 58 if ((!forPbuffer && boundToPbuffer)) { 59 [self clearDrawable]; 60 } 61 boundToPbuffer = forPbuffer; 62 boundToWin = !boundToPbuffer; 63} 64@end 65 66int getAttrListLength(const NSOpenGLPixelFormatAttribute* list) { 67 int count = 0; 68 while (list[count++] != 0); 69 return count ? (count - 1) : 0; 70} 71 72static const NSOpenGLPixelFormatAttribute core32TestProfile[] = { 73 NSOpenGLPFAAccelerated, 74 NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, 75 NSOpenGLPFADoubleBuffer, 76 NSOpenGLPFAColorSize ,32, 77 NSOpenGLPFADepthSize ,24, 78 NSOpenGLPFAStencilSize ,8, 79 0 80}; 81 82static const NSOpenGLPixelFormatAttribute core41TestProfile[] = { 83 NSOpenGLPFAAccelerated, 84 NSOpenGLPFANoRecovery, 85 NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core, 86 NSOpenGLPFADoubleBuffer, 87 NSOpenGLPFAColorSize ,32, 88 NSOpenGLPFADepthSize ,24, 89 NSOpenGLPFAStencilSize ,8, 90 0 91}; 92 93int setupCoreProfileNativeFormats() { 94 95 NSOpenGLPixelFormat* core41Supported = 96 [[NSOpenGLPixelFormat alloc] initWithAttributes: core41TestProfile]; 97 98 if (core41Supported) { 99 setCoreProfileLevel(NSOpenGLProfileVersion4_1Core); 100 [core41Supported release]; 101 return (int)NSOpenGLProfileVersion4_1Core; 102 } 103 104 NSOpenGLPixelFormat* core32Supported = 105 [[NSOpenGLPixelFormat alloc] initWithAttributes: core32TestProfile]; 106 107 if (core32Supported) { 108 setCoreProfileLevel(NSOpenGLProfileVersion3_2Core); 109 [core32Supported release]; 110 return (int)NSOpenGLProfileVersion3_2Core; 111 } 112 113 return (int)NSOpenGLProfileVersionLegacy; 114} 115 116int getNumPixelFormats(){ 117 int size; 118 const NSOpenGLPixelFormatAttribute* const* attrib_lists = 119 getPixelFormatsAttributes(&size); 120 return size; 121} 122 123void* finalizePixelFormat(bool coreProfile, 124 int attribsId) { 125 int size; 126 const NSOpenGLPixelFormatAttribute* const* attrib_lists = 127 getPixelFormatsAttributes(&size); 128 129 assert(attribsId < size); 130 131 const NSOpenGLPixelFormatAttribute* attrs = 132 attrib_lists[attribsId]; 133 134 const NSOpenGLPixelFormatAttribute* selected_variant = 135 coreProfile ? 136 getCoreProfileAttributes() : 137 getLegacyProfileAttributes(); 138 139 // Format it as |variant| |attribs| 140 int variant_size = 141 getAttrListLength(selected_variant); 142 int attrib_size = getAttrListLength(attrs); 143 int numAttribsTotal = attrib_size + variant_size + 1; // for trailing 0 144 145 NSOpenGLPixelFormatAttribute* newAttrs = 146 malloc(sizeof(NSOpenGLPixelFormatAttribute) * numAttribsTotal); 147 148 int variant_part_bytes = 149 sizeof(NSOpenGLPixelFormatAttribute) * variant_size; 150 int attribs_part_bytes = 151 sizeof(NSOpenGLPixelFormatAttribute) * attrib_size; 152 153 memcpy(newAttrs, selected_variant, variant_part_bytes); 154 memcpy((char*)newAttrs + variant_part_bytes, 155 attrs, attribs_part_bytes); 156 newAttrs[numAttribsTotal - 1] = 0; 157 158 void* finalizedFormat = 159 [[NSOpenGLPixelFormat alloc] initWithAttributes: newAttrs]; 160 161 free(newAttrs); 162 163 return finalizedFormat; 164} 165 166static bool sIsKeyValueAttrib(NSOpenGLPixelFormatAttribute attrib) { 167 switch (attrib) { 168 // These are the ones that take a value, according to the current 169 // NSOpenGLPixelFormat docs 170 case NSOpenGLPFAOpenGLProfile: 171 case NSOpenGLPFAAuxBuffers: 172 case NSOpenGLPFAColorSize: 173 case NSOpenGLPFAAlphaSize: 174 case NSOpenGLPFADepthSize: 175 case NSOpenGLPFAStencilSize: 176 case NSOpenGLPFAAccumSize: 177 case NSOpenGLPFARendererID: 178 case NSOpenGLPFAScreenMask: 179 return true; 180 default: 181 return false; 182 } 183} 184 185int getPixelFormatAttrib(int i, int _query) { 186 NSOpenGLPixelFormatAttribute query = 187 (NSOpenGLPixelFormatAttribute)_query; 188 int size; 189 const NSOpenGLPixelFormatAttribute* const* attrib_lists = getPixelFormatsAttributes(&size); 190 int attributes_num = i % size; 191 const NSOpenGLPixelFormatAttribute* attribs = attrib_lists[attributes_num]; 192 int res = 0; 193 while (*attribs) { 194 if (sIsKeyValueAttrib(*attribs)) { 195 if (query == *attribs) { 196 return attribs[1]; 197 } 198 attribs += 2; 199 } else { 200 // these are boolean attribs. 201 // their mere presence signals 202 // that the query should return true. 203 if (query == *attribs) { 204 return 1; 205 } 206 attribs++; 207 } 208 } 209 // return 0 if key not found---takes care of all boolean attribs, 210 // and we depend on returning alpha=0 to make the default 211 // config for GLSurfaceView happy. 212 return 0; 213} 214 215void* nsCreateContext(void* format,void* share){ 216 NSOpenGLPixelFormat* frmt = (NSOpenGLPixelFormat*)format; 217 return [[EmuGLContext alloc] initWithFormat:frmt shareContext:share]; 218} 219 220void nsPBufferMakeCurrent(void* context,void* nativePBuffer,int level){ 221 EmuGLContext* ctx = (EmuGLContext *)context; 222 NSOpenGLPixelBuffer* pbuff = (NSOpenGLPixelBuffer *)nativePBuffer; 223 if(ctx == nil){ 224 [NSOpenGLContext clearCurrentContext]; 225 } else { 226 if(pbuff != nil){ 227 [ctx preBind:1]; 228 [ctx setPixelBuffer:pbuff cubeMapFace:0 mipMapLevel:level currentVirtualScreen:0]; 229 [ctx makeCurrentContext]; 230 } else { 231 // in this case, pbuffers deprecated and disabled. 232 [ctx preBind:0]; 233 [ctx makeCurrentContext]; 234 } 235 } 236} 237 238void nsWindowMakeCurrent(void* context,void* nativeWin){ 239 EmuGLContext* ctx = (EmuGLContext *)context; 240 NSView* win = (NSView *)nativeWin; 241 if(ctx == nil){ 242 [NSOpenGLContext clearCurrentContext]; 243 } else if (win != nil) { 244 [ctx preBind:0]; 245 [ctx setView: win]; 246 [ctx makeCurrentContext]; 247 } 248} 249 250void nsSwapBuffers(){ 251 NSOpenGLContext* ctx = [NSOpenGLContext currentContext]; 252 if(ctx != nil){ 253 [ctx flushBuffer]; 254 } 255} 256 257void nsSwapInterval(int *interval){ 258 NSOpenGLContext* ctx = [NSOpenGLContext currentContext]; 259 if( ctx != nil){ 260 [ctx setValues:interval forParameter:NSOpenGLCPSwapInterval]; 261 } 262} 263 264 265void nsDestroyContext(void* context){ 266 EmuGLContext *ctx = (EmuGLContext*)context; 267 if(ctx != nil){ 268 [ctx release]; 269 } 270} 271 272 273void* nsCreatePBuffer(GLenum target,GLenum format,int maxMip,int width,int height){ 274 return [[NSOpenGLPixelBuffer alloc] initWithTextureTarget:target 275 textureInternalFormat:format 276 textureMaxMipMapLevel:maxMip 277 pixelsWide:width pixelsHigh:height]; 278 279} 280 281void nsDestroyPBuffer(void* pbuffer){ 282 NSOpenGLPixelBuffer *pbuf = (NSOpenGLPixelBuffer*)pbuffer; 283 if(pbuf != nil){ 284 [pbuf release]; 285 } 286} 287 288bool nsGetWinDims(void* win,unsigned int* width,unsigned int* height){ 289 NSView* view = (NSView*)win; 290 if(view != nil){ 291 NSRect rect = [view bounds]; 292 *width = rect.size.width; 293 *height = rect.size.height; 294 return true; 295 } 296 return false; 297} 298 299bool nsCheckColor(void* win,int colorSize){ 300 NSView* view = (NSView*)win; 301 if(view != nil){ 302 NSWindow* wnd = [view window]; 303 if(wnd != nil){ 304 NSWindowDepth limit = [wnd depthLimit]; 305 NSWindowDepth defaultLimit = [NSWindow defaultDepthLimit]; 306 307 int depth = (limit != 0) ? NSBitsPerPixelFromDepth(limit): 308 NSBitsPerPixelFromDepth(defaultLimit); 309 return depth >= colorSize; 310 311 } 312 } 313 return false; 314 315} 316