00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "osxGraphicsPipe.h"
00013 #include "config_osxdisplay.h"
00014 #include "osxGraphicsWindow.h"
00015 #include "osxGraphicsBuffer.h"
00016 #include "osxGraphicsStateGuardian.h"
00017 #include "pnmImage.h"
00018 #include "subprocessWindow.h"
00019 #include "nativeWindowHandle.h"
00020 #import <Carbon/Carbon.h>
00021
00022
00023 #define GetModeWidth(mode) GetDictionaryLong((mode), kCGDisplayWidth)
00024 #define GetModeHeight(mode) GetDictionaryLong((mode), kCGDisplayHeight)
00025 #define GetModeRefreshRate(mode) GetDictionaryLong((mode), kCGDisplayRefreshRate)
00026 #define GetModeBitsPerPixel(mode) GetDictionaryLong((mode), kCGDisplayBitsPerPixel)
00027 #define GetModeSafeForHardware(mode) GetDictionaryBoolean((mode), kCGDisplayModeIsSafeForHardware)
00028 #define GetModeStretched(mode) GetDictionaryBoolean((mode), kCGDisplayModeIsStretched)
00029 #define MAX_DISPLAYS 32
00030
00031 Boolean GetDictionaryBoolean(CFDictionaryRef theDict, const void* key) {
00032
00033 Boolean value = false;
00034 CFBooleanRef boolRef;
00035 boolRef = (CFBooleanRef)CFDictionaryGetValue(theDict, key);
00036 if (boolRef != NULL)
00037 value = CFBooleanGetValue(boolRef);
00038 return value;
00039 }
00040
00041 long GetDictionaryLong(CFDictionaryRef theDict, const void* key) {
00042
00043 long value = 0;
00044 CFNumberRef numRef;
00045 numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
00046 if (numRef != NULL)
00047 CFNumberGetValue(numRef, kCFNumberLongType, &value);
00048 return value;
00049 }
00050
00051 static CFComparisonResult CompareModes (const void *val1,const void *val2,void *context) {
00052
00053 #pragma unused(context)
00054 CFDictionaryRef thisMode = (CFDictionaryRef)val1;
00055 CFDictionaryRef otherMode = (CFDictionaryRef)val2;
00056
00057 long width = GetModeWidth(thisMode);
00058 long otherWidth = GetModeWidth(otherMode);
00059 long height = GetModeHeight(thisMode);
00060 long otherHeight = GetModeHeight(otherMode);
00061
00062
00063 if (width * height < otherWidth * otherHeight) {
00064 return kCFCompareLessThan;
00065 } else if (width * height > otherWidth * otherHeight) {
00066 return kCFCompareGreaterThan;
00067 }
00068
00069
00070 long bitsPerPixel = GetModeBitsPerPixel(thisMode);
00071 long otherBitsPerPixel = GetModeBitsPerPixel(otherMode);
00072 if (bitsPerPixel < otherBitsPerPixel) {
00073 return kCFCompareLessThan;
00074 } else if (bitsPerPixel > otherBitsPerPixel) {
00075 return kCFCompareGreaterThan;
00076 }
00077
00078
00079 long refreshRate = GetModeRefreshRate(thisMode);
00080 long otherRefreshRate = GetModeRefreshRate(otherMode);
00081 if (refreshRate < otherRefreshRate) {
00082 return kCFCompareLessThan;
00083 } else if (refreshRate > otherRefreshRate) {
00084 return kCFCompareGreaterThan;
00085 }
00086
00087 return kCFCompareEqualTo;
00088 }
00089
00090 CFArrayRef GSCGDisplayAvailableModesUsefulForOpenGL(CGDirectDisplayID display) {
00091
00092 CFArrayRef availableModes = CGDisplayAvailableModes(display);
00093 unsigned int numberOfAvailableModes = CFArrayGetCount(availableModes);
00094
00095
00096 CFMutableArrayRef usefulModes = CFArrayCreateMutable(kCFAllocatorDefault, numberOfAvailableModes, NULL);
00097
00098
00099 long currentModeBitsPerPixel = GetModeBitsPerPixel(CGDisplayCurrentMode(display));
00100
00101 unsigned int i;
00102 for (i= 0; i<numberOfAvailableModes; ++i) {
00103
00104 CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, i);
00105
00106
00107
00108
00109
00110 long bitsPerPixel = GetModeBitsPerPixel(mode);
00111 Boolean safeForHardware = GetModeSafeForHardware(mode);
00112 Boolean stretched = GetModeStretched(mode);
00113
00114 if ((bitsPerPixel != currentModeBitsPerPixel) || (!safeForHardware) || (stretched)) {
00115 continue;
00116 }
00117
00118 long width = GetModeWidth(mode);
00119 long height = GetModeHeight(mode);
00120 long refreshRate = GetModeRefreshRate(mode);
00121 Boolean replaced = false;
00122 Boolean skipped = false;
00123
00124
00125
00126 unsigned int j;
00127 unsigned int currentNumberOfUsefulModes = CFArrayGetCount(usefulModes);
00128 for (j = 0; j < currentNumberOfUsefulModes; ++j) {
00129 CFDictionaryRef otherMode = (CFDictionaryRef)CFArrayGetValueAtIndex(usefulModes, j);
00130 long otherWidth = GetModeWidth(otherMode);
00131 long otherHeight = GetModeHeight(otherMode);
00132 if ((otherWidth == width) && (otherHeight == height)) {
00133 long otherRefreshRate = GetModeRefreshRate(otherMode);
00134 if (otherRefreshRate < refreshRate) {
00135
00136 const void* value = mode;
00137 CFArrayReplaceValues(usefulModes, CFRangeMake(j ,1), &value, 1);
00138 replaced = true;
00139 break;
00140 }
00141 else if (otherRefreshRate > refreshRate) {
00142 skipped = true;
00143 break;
00144 }
00145 }
00146 }
00147
00148 if (!replaced && !skipped) {
00149 CFArrayAppendValue(usefulModes, mode);
00150 }
00151 }
00152
00153 CFArraySortValues( usefulModes,
00154 CFRangeMake(0, CFArrayGetCount(usefulModes)),
00155 (CFComparatorFunction) CompareModes, NULL);
00156
00157 return usefulModes;
00158 }
00159
00160 TypeHandle osxGraphicsPipe::_type_handle;
00161
00162
00163
00164
00165
00166
00167 osxGraphicsPipe::
00168 osxGraphicsPipe() {
00169 CGRect display_bounds = CGDisplayBounds(kCGDirectMainDisplay);
00170 _display_width = CGRectGetWidth(display_bounds);
00171 _display_height = CGRectGetHeight(display_bounds);
00172
00173 CGDirectDisplayID display, displayArray[MAX_DISPLAYS] ;
00174 CGDisplayCount numDisplays;
00175 CFDictionaryRef displayMode;
00176 CFArrayRef displayModeArray;
00177 int number, i;
00178 CGGetActiveDisplayList (MAX_DISPLAYS, displayArray, &numDisplays);
00179 display = displayArray [numDisplays - 1];
00180 displayModeArray = GSCGDisplayAvailableModesUsefulForOpenGL( display );
00181 number = CFArrayGetCount( displayModeArray );
00182 DisplayMode *displays = new DisplayMode[ number ];
00183 for(i = 0; i < number; i++) {
00184 displayMode = (CFDictionaryRef) CFArrayGetValueAtIndex (displayModeArray, i);
00185 _display_information -> _total_display_modes++;
00186 displays[i].width = (signed int)GetModeWidth (displayMode);
00187 displays[i].height = (signed int)GetModeHeight (displayMode);
00188 displays[i].bits_per_pixel = (signed int)GetModeBitsPerPixel (displayMode);
00189 displays[i].refresh_rate = (signed int)GetModeRefreshRate (displayMode);
00190 }
00191 _display_information -> _display_mode_array = displays;
00192 }
00193
00194
00195
00196
00197
00198
00199 osxGraphicsPipe::
00200 ~osxGraphicsPipe() {
00201 }
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213 string osxGraphicsPipe::
00214 get_interface_name() const {
00215 return "OpenGL";
00216 }
00217
00218
00219
00220
00221
00222
00223
00224
00225 PT(GraphicsPipe) osxGraphicsPipe::
00226 pipe_constructor() {
00227 return new osxGraphicsPipe;
00228 }
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 GraphicsPipe::PreferredWindowThread
00239 osxGraphicsPipe::get_preferred_window_thread() const {
00240 return PWT_app;
00241 }
00242
00243
00244
00245
00246
00247
00248
00249
00250 CGImageRef osxGraphicsPipe::
00251 create_cg_image(const PNMImage &pnm_image) {
00252 size_t width = pnm_image.get_x_size();
00253 size_t height = pnm_image.get_y_size();
00254
00255 #ifdef PGM_BIGGRAYS
00256 size_t bytes_per_component = 2;
00257 #else
00258 size_t bytes_per_component = 1;
00259 #endif
00260 size_t bits_per_component = bytes_per_component * 8;
00261 size_t num_components = pnm_image.get_num_channels();
00262
00263 size_t bits_per_pixel = num_components * bits_per_component;
00264 size_t bytes_per_row = num_components * bytes_per_component * width;
00265
00266 size_t num_bytes = bytes_per_row * height;
00267 bool has_alpha;
00268 bool is_grayscale;
00269
00270 CFStringRef color_space_name = NULL;
00271 switch (pnm_image.get_color_type()) {
00272 case PNMImage::CT_grayscale:
00273 color_space_name = kCGColorSpaceGenericGray;
00274 has_alpha = false;
00275 is_grayscale = true;
00276 break;
00277
00278 case PNMImage::CT_two_channel:
00279 color_space_name = kCGColorSpaceGenericGray;
00280 has_alpha = true;
00281 is_grayscale = true;
00282 break;
00283
00284 case PNMImage::CT_color:
00285 color_space_name = kCGColorSpaceGenericRGB;
00286 has_alpha = false;
00287 is_grayscale = false;
00288 break;
00289
00290 case PNMImage::CT_four_channel:
00291 color_space_name = kCGColorSpaceGenericRGB;
00292 has_alpha = true;
00293 is_grayscale = false;
00294 break;
00295
00296 case PNMImage::CT_invalid:
00297
00298 nassertr(false, NULL);
00299 break;
00300 }
00301 nassertr(color_space_name != NULL, NULL);
00302
00303 CGColorSpaceRef color_space = CGColorSpaceCreateWithName(color_space_name);
00304 nassertr(color_space != NULL, NULL);
00305
00306 CGBitmapInfo bitmap_info = 0;
00307 #ifdef PGM_BIGGRAYS
00308 bitmap_info |= kCGBitmapByteOrder16Host;
00309 #endif
00310 if (has_alpha) {
00311 bitmap_info |= kCGImageAlphaLast;
00312 }
00313
00314
00315
00316 char *char_array = (char *)PANDA_MALLOC_ARRAY(num_bytes);
00317
00318 xelval *dp = (xelval *)char_array;
00319 for (size_t yi = 0; yi < height; ++yi) {
00320 for (size_t xi = 0; xi < width; ++xi) {
00321 if (is_grayscale) {
00322 *dp++ = (xelval)(pnm_image.get_gray(xi, yi) * PGM_MAXMAXVAL);
00323 } else {
00324 *dp++ = (xelval)(pnm_image.get_red(xi, yi) * PGM_MAXMAXVAL);
00325 *dp++ = (xelval)(pnm_image.get_green(xi, yi) * PGM_MAXMAXVAL);
00326 *dp++ = (xelval)(pnm_image.get_blue(xi, yi) * PGM_MAXMAXVAL);
00327 }
00328 if (has_alpha) {
00329 *dp++ = (xelval)(pnm_image.get_alpha(xi, yi) * PGM_MAXMAXVAL);
00330 }
00331 }
00332 }
00333 nassertr((void *)dp == (void *)(char_array + num_bytes), NULL);
00334
00335 CGDataProviderRef provider =
00336 CGDataProviderCreateWithData(NULL, char_array, num_bytes, release_data);
00337 nassertr(provider != NULL, NULL);
00338
00339 CGImageRef image = CGImageCreate
00340 (width, height, bits_per_component, bits_per_pixel, bytes_per_row,
00341 color_space, bitmap_info, provider,
00342 NULL, false, kCGRenderingIntentDefault);
00343 nassertr(image != NULL, NULL);
00344
00345 CGColorSpaceRelease(color_space);
00346 CGDataProviderRelease(provider);
00347
00348 return image;
00349 }
00350
00351
00352
00353
00354
00355
00356
00357 void osxGraphicsPipe::
00358 release_data(void *info, const void *data, size_t size) {
00359 char *char_array = (char *)data;
00360 PANDA_FREE_ARRAY(char_array);
00361 }
00362
00363
00364
00365
00366
00367
00368 PT(GraphicsOutput) osxGraphicsPipe::
00369 make_output(const string &name,
00370 const FrameBufferProperties &fb_prop,
00371 const WindowProperties &win_prop,
00372 int flags,
00373 GraphicsEngine *engine,
00374 GraphicsStateGuardian *gsg,
00375 GraphicsOutput *host,
00376 int retry,
00377 bool &precertify) {
00378 if (!_is_valid) {
00379 return NULL;
00380 }
00381
00382 osxGraphicsStateGuardian *osxgsg = 0;
00383 if (gsg != 0) {
00384 DCAST_INTO_R(osxgsg, gsg, NULL);
00385 }
00386
00387
00388
00389 if (retry == 0) {
00390 if (((flags&BF_require_parasite)!=0)||
00391 ((flags&BF_refuse_window)!=0)||
00392 ((flags&BF_resizeable)!=0)||
00393 ((flags&BF_size_track_host)!=0)||
00394 ((flags&BF_can_bind_color)!=0)||
00395 ((flags&BF_can_bind_every)!=0)) {
00396 return NULL;
00397 }
00398 WindowHandle *window_handle = win_prop.get_parent_window();
00399 if (window_handle != NULL) {
00400 osxdisplay_cat.info()
00401 << "Got parent_window " << *window_handle << "\n";
00402 #ifdef SUPPORT_SUBPROCESS_WINDOW
00403 WindowHandle::OSHandle *os_handle = window_handle->get_os_handle();
00404 if (os_handle != NULL &&
00405 os_handle->is_of_type(NativeWindowHandle::SubprocessHandle::get_class_type())) {
00406 return new SubprocessWindow(engine, this, name, fb_prop, win_prop,
00407 flags, gsg, host);
00408 }
00409 #endif // SUPPORT_SUBPROCESS_WINDOW
00410 }
00411 return new osxGraphicsWindow(engine, this, name, fb_prop, win_prop,
00412 flags, gsg, host);
00413 }
00414
00415
00416
00417 if (retry == 1) {
00418 if (!osx_support_gl_buffer) {
00419 return NULL;
00420 }
00421 if ((host==0)||
00422 ((flags&BF_require_parasite)!=0)||
00423 ((flags&BF_require_window)!=0)) {
00424 return NULL;
00425 }
00426
00427
00428 if ((flags & BF_fb_props_optional)==0) {
00429 if ((fb_prop.get_indexed_color() > 0)||
00430 (fb_prop.get_back_buffers() > 0)||
00431 (fb_prop.get_accum_bits() > 0)||
00432 (fb_prop.get_multisamples() > 0)) {
00433 return NULL;
00434 }
00435 }
00436
00437
00438 if ((osxgsg != 0) &&
00439 (osxgsg->is_valid()) &&
00440 (!osxgsg->needs_reset()) &&
00441 (osxgsg->_supports_framebuffer_object) &&
00442 (osxgsg->_glDrawBuffers != 0)&&
00443 (fb_prop.is_basic())) {
00444 precertify = true;
00445 }
00446 return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop, flags, gsg, host);
00447 }
00448
00449
00450 if (retry == 2) {
00451 if ((!support_render_texture)||
00452 ((flags&BF_require_parasite)!=0)||
00453 ((flags&BF_require_window)!=0)||
00454 ((flags&BF_resizeable)!=0)||
00455 ((flags&BF_size_track_host)!=0)||
00456 ((flags&BF_can_bind_every)!=0)) {
00457 return NULL;
00458 }
00459 return new osxGraphicsBuffer(engine, this, name, fb_prop, win_prop,
00460 flags, gsg, host);
00461 }
00462
00463
00464 return NULL;
00465 }
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476 PT(GraphicsStateGuardian) osxGraphicsPipe::
00477 make_callback_gsg(GraphicsEngine *engine) {
00478 return new osxGraphicsStateGuardian(engine, this, NULL);
00479 }