From 134227aa8ccd822e2a836042ba734213c5b15023 Mon Sep 17 00:00:00 2001 From: egladil Date: Thu, 25 Oct 2007 23:45:03 +0000 Subject: [PATCH] (svn r11342) -Fix: [OSX] The cocoa driver incorrectly assumed that the blitter always was 8bpp. Now both 8bpp and 32bpp blitters can be used. The driver will check the blitter screen depth. In fullscreen it will select a proper video mode for this depth, and in windowed mode it will simply skip doing fake 8bpp. --- src/os/macosx/splash.cpp | 64 ++++++++++++++++++--------- src/video/cocoa_v.mm | 96 +++++++++++++++++++++++++++++----------- 2 files changed, 113 insertions(+), 47 deletions(-) diff --git a/src/os/macosx/splash.cpp b/src/os/macosx/splash.cpp index 30eed880d2..45973c7814 100644 --- a/src/os/macosx/splash.cpp +++ b/src/os/macosx/splash.cpp @@ -8,6 +8,7 @@ #include "../../functions.h" #include "../../gfx.h" #include "../../fileio.h" +#include "../../blitter/factory.hpp" #include "splash.h" @@ -36,7 +37,7 @@ void DisplaySplashImage() png_colorp palette; int num_palette; png_bytep *row_pointers; - uint8 *src, *dst; + uint8 *src; uint y; uint xoff, yoff; int i; @@ -103,33 +104,56 @@ void DisplaySplashImage() row_pointers = png_get_rows(png_ptr, info_ptr); - memset(_screen.dst_ptr, 0xff, _screen.pitch * _screen.height); - if (width > (uint) _screen.width) width = _screen.width; if (height > (uint) _screen.height) height = _screen.height; xoff = (_screen.width - width) / 2; yoff = (_screen.height - height) / 2; - for (y = 0; y < height; y++) { - src = row_pointers[y]; - dst = ((uint8 *) _screen.dst_ptr) + (yoff + y) * _screen.pitch + xoff; - memcpy(dst, src, width); + switch (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth()) { + case 8: { + uint8 *dst; + + memset(_screen.dst_ptr, 0xff, _screen.pitch * _screen.height); + + for (y = 0; y < height; y++) { + src = row_pointers[y]; + dst = ((uint8 *) _screen.dst_ptr) + (yoff + y) * _screen.pitch + xoff; + + memcpy(dst, src, width); + } + + for (i = 0; i < num_palette; i++) { + _cur_palette[i].r = palette[i].red; + _cur_palette[i].g = palette[i].green; + _cur_palette[i].b = palette[i].blue; + } + + _cur_palette[0xff].r = 0; + _cur_palette[0xff].g = 0; + _cur_palette[0xff].b = 0; + + _pal_first_dirty = 0; + _pal_count_dirty = 256; + } + break; + case 32: { + uint32 *dst; + int x; + + memset(_screen.dst_ptr, 0xff000000, _screen.pitch * _screen.height * 4); + + for (y = 0; y < height; y++) { + src = row_pointers[y]; + dst = ((uint32 *) _screen.dst_ptr) + (yoff + y) * _screen.pitch + xoff; + + for (x = 0; x < width; x++) + dst[x] = palette[src[x]].blue | (palette[src[x]].green << 8) | (palette[src[x]].red << 16) | 0xff000000; + } + } + break; } - for (i = 0; i < num_palette; i++) { - _cur_palette[i].r = palette[i].red; - _cur_palette[i].g = palette[i].green; - _cur_palette[i].b = palette[i].blue; - } - - _cur_palette[0xff].r = 0; - _cur_palette[0xff].g = 0; - _cur_palette[0xff].b = 0; - - _pal_first_dirty = 0; - _pal_count_dirty = 256; - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return; diff --git a/src/video/cocoa_v.mm b/src/video/cocoa_v.mm index 0b9ec1786c..0a23871dc6 100644 --- a/src/video/cocoa_v.mm +++ b/src/video/cocoa_v.mm @@ -157,12 +157,14 @@ static struct CocoaVideoData { CFArrayRef mode_list; /* list of available fullscreen modes */ CGDirectPaletteRef palette; /* palette of an 8-bit display */ + uint32 blitter_bpp; + uint32 device_width; uint32 device_height; uint32 device_bpp; void *realpixels; - uint8 *pixels; + void *pixels; uint32 width; uint32 height; uint32 pitch; @@ -900,7 +902,7 @@ static void QZ_SetPortAlphaOpaque() /* Allocate new buffer */ free(_cocoa_video_data.pixels); - _cocoa_video_data.pixels = (uint8*)malloc(newViewFrame.size.width * newViewFrame.size.height); + _cocoa_video_data.pixels = malloc(newViewFrame.size.width * newViewFrame.size.height * _cocoa_video_data.blitter_bpp / 8); assert(_cocoa_video_data.pixels != NULL); @@ -1019,28 +1021,54 @@ static void QZ_UpdateWindowPalette(uint start, uint count) static inline void QZ_WindowBlitIndexedPixelsToView32(uint left, uint top, uint right, uint bottom) { - const uint32* pal = _cocoa_video_data.palette32; - const uint8* src = _cocoa_video_data.pixels; uint32* dst = (uint32*)_cocoa_video_data.realpixels; uint width = _cocoa_video_data.width; uint pitch = _cocoa_video_data.pitch / 4; uint x; uint y; - for (y = top; y < bottom; y++) { - for (x = left; x < right; x++) { - dst[y * pitch + x] = pal[src[y * width + x]]; - } + switch (_cocoa_video_data.blitter_bpp) { + case 8: { + const uint32* pal = _cocoa_video_data.palette32; + const uint8* src = (uint8*) _cocoa_video_data.pixels; + + for (y = top; y < bottom; y++) { + for (x = left; x < right; x++) { + dst[y * pitch + x] = pal[src[y * width + x]]; + } + } + } + break; + case 32: { + const uint32* src = (uint32*) _cocoa_video_data.pixels; + + dst += top * pitch + left; + src += top * width + left; + + for (y = top; y < bottom; y++, dst+= pitch, src+= width) + memcpy(dst, src, (right - left) * 4); + } + break; } } +/** + * This function copies pixels from the screen buffer in 16bpp windowed mode. It assumes + * that the blitter is 8bpp since the driver only supports 8 and 32 bpp blitters, and we + * don't allow a blitter with a higer bpp than the display in windowed mode. + * + * @param left The x coord for the left edge of the box to blit. + * @param top The y coord for the top edge of the box to blit. + * @param right The x coord for the right edge of the box to blit. + * @param bottom The y coord for the bottom edge of the box to blit. + */ static inline void QZ_WindowBlitIndexedPixelsToView16(uint left, uint top, uint right, uint bottom) { - const uint16* pal = _cocoa_video_data.palette16; - const uint8* src = _cocoa_video_data.pixels; - uint16* dst = (uint16*)_cocoa_video_data.realpixels; - uint width = _cocoa_video_data.width; - uint pitch = _cocoa_video_data.pitch / 2; + const uint16* pal = _cocoa_video_data.palette16; + const uint8* src = (uint8*) _cocoa_video_data.pixels; + uint16* dst = (uint16*)_cocoa_video_data.realpixels; + uint width = _cocoa_video_data.width; + uint pitch = _cocoa_video_data.pitch / 2; uint x; uint y; @@ -1164,6 +1192,10 @@ static const char* QZ_SetVideoWindowed(uint width, uint height) NSRect contentRect; BOOL isCustom = NO; + if (_cocoa_video_data.blitter_bpp > _cocoa_video_data.device_bpp) { + error("Cocoa: Cannot use a blitter with a higer screen depth than the display when running in windowed mode."); + } + if (width > _cocoa_video_data.device_width) width = _cocoa_video_data.device_width; if (height > _cocoa_video_data.device_height) @@ -1251,7 +1283,7 @@ static const char* QZ_SetVideoWindowed(uint width, uint height) } free(_cocoa_video_data.pixels); - _cocoa_video_data.pixels = (uint8*)malloc(width * height); + _cocoa_video_data.pixels = malloc(width * height * _cocoa_video_data.blitter_bpp / 8); if (_cocoa_video_data.pixels == NULL) return "Failed to allocate 8-bit buffer"; _cocoa_video_data.fullscreen = false; @@ -1362,13 +1394,13 @@ static const char* QZ_SetVideoFullScreen(int width, int height) if (_cocoa_video_data.isset) QZ_UnsetVideoMode(); /* See if requested mode exists */ - _cocoa_video_data.mode = CGDisplayBestModeForParameters(_cocoa_video_data.display_id, 8, width, height, &exact_match); + _cocoa_video_data.mode = CGDisplayBestModeForParameters(_cocoa_video_data.display_id, _cocoa_video_data.blitter_bpp, width, height, &exact_match); /* If the mode wasn't an exact match, check if it has the right bpp, and update width and height */ if (!exact_match) { number = (const __CFNumber*) CFDictionaryGetValue(_cocoa_video_data.mode, kCGDisplayBitsPerPixel); CFNumberGetValue(number, kCFNumberSInt32Type, &bpp); - if (bpp != 8) { + if ((uint) bpp != _cocoa_video_data.blitter_bpp) { errstr = "Failed to find display resolution"; goto ERR_NO_MATCH; } @@ -1397,7 +1429,7 @@ static const char* QZ_SetVideoFullScreen(int width, int height) goto ERR_NO_SWITCH; } - _cocoa_video_data.realpixels = (uint8*)CGDisplayBaseAddress(_cocoa_video_data.display_id); + _cocoa_video_data.realpixels = CGDisplayBaseAddress(_cocoa_video_data.display_id); _cocoa_video_data.pitch = CGDisplayBytesPerRow(_cocoa_video_data.display_id); _cocoa_video_data.width = CGDisplayPixelsWide(_cocoa_video_data.display_id); @@ -1405,13 +1437,13 @@ static const char* QZ_SetVideoFullScreen(int width, int height) _cocoa_video_data.fullscreen = true; /* Setup double-buffer emulation */ - _cocoa_video_data.pixels = (uint8*)malloc(width * height); + _cocoa_video_data.pixels = malloc(width * height * _cocoa_video_data.blitter_bpp / 8); if (_cocoa_video_data.pixels == NULL) { errstr = "Failed to allocate memory for double buffering"; goto ERR_DOUBLEBUF; } - if (!CGDisplayCanSetPalette(_cocoa_video_data.display_id)) { + if (_cocoa_video_data.blitter_bpp == 8 && !CGDisplayCanSetPalette(_cocoa_video_data.display_id)) { errstr = "Not an indexed display mode."; goto ERR_NOT_INDEXED; } @@ -1507,11 +1539,12 @@ static void QZ_WaitForVerticalBlank() static void QZ_DrawScreen() { - const uint8* src = _cocoa_video_data.pixels; - uint8* dst = (uint8*)_cocoa_video_data.realpixels; - uint pitch = _cocoa_video_data.pitch; - uint width = _cocoa_video_data.width; - uint num_dirty = _cocoa_video_data.num_dirty_rects; + const uint8* src = (uint8*) _cocoa_video_data.pixels; + uint8* dst = (uint8*)_cocoa_video_data.realpixels; + uint pitch = _cocoa_video_data.pitch; + uint width = _cocoa_video_data.width; + uint num_dirty = _cocoa_video_data.num_dirty_rects; + uint bytesperpixel = _cocoa_video_data.blitter_bpp / 8; uint i; /* Check if we need to do anything */ @@ -1534,7 +1567,7 @@ static void QZ_DrawScreen() uint bottom = _cocoa_video_data.dirty_rects[i].bottom; for (; y < bottom; y++) { - memcpy(dst + y * pitch + left, src + y * width + left, length); + memcpy(dst + y * pitch + left * bytesperpixel, src + y * width * bytesperpixel + left * bytesperpixel, length * bytesperpixel); } } @@ -1563,7 +1596,7 @@ static int QZ_ListFullscreenModes(OTTDPoint* mode_list, int max_modes) number = (const __CFNumber*)CFDictionaryGetValue(onemode, kCGDisplayBitsPerPixel); CFNumberGetValue (number, kCFNumberSInt32Type, &bpp); - if (bpp != 8) continue; + if ((uint) bpp != _cocoa_video_data.blitter_bpp) continue; number = (const __CFNumber*)CFDictionaryGetValue(onemode, kCGDisplayWidth); CFNumberGetValue(number, kCFNumberSInt32Type, &intvalue); @@ -1774,10 +1807,19 @@ static const char* QZ_SetVideoModeAndRestoreOnFailure(uint width, uint height, b static void QZ_VideoInit() { - if (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() == 0) error("Can't use a blitter that blits 0 bpp for normal visuals"); memset(&_cocoa_video_data, 0, sizeof(_cocoa_video_data)); + _cocoa_video_data.blitter_bpp = BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(); + DEBUG(driver, 1, "Cocoa: Blitter bpp %d", _cocoa_video_data.blitter_bpp); + + if (_cocoa_video_data.blitter_bpp == 0) error("Can't use a blitter that blits 0 bpp for normal visuals"); + + + if (_cocoa_video_data.blitter_bpp != 8 && _cocoa_video_data.blitter_bpp != 32) { + error("Cocoa: This video driver only supports 8 and 32 bpp blitters."); + } + /* Initialize the video settings; this data persists between mode switches */ _cocoa_video_data.display_id = kCGDirectMainDisplay; _cocoa_video_data.save_mode = CGDisplayCurrentMode(_cocoa_video_data.display_id);