From 4fcb208a4fdd14091d122f9630c18335b8c2c2d3 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Mon, 6 Oct 2008 19:48:52 +0000 Subject: [PATCH] porting dcscreen blit from 2.8 git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@56132 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- Makefile.in | 28 ++++ configure | 2 +- configure.in | 2 +- include/wx/osx/carbon/dcscreen.h | 1 + include/wx/osx/private/glgrab.h | 12 ++ src/osx/carbon/dcscreen.cpp | 35 +++++ src/osx/core/glgrab.cpp | 214 +++++++++++++++++++++++++++++++ 7 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 include/wx/osx/private/glgrab.h create mode 100644 src/osx/core/glgrab.cpp diff --git a/Makefile.in b/Makefile.in index 9756a90fec..b76f485e08 100644 --- a/Makefile.in +++ b/Makefile.in @@ -11859,6 +11859,7 @@ COND_PLATFORM_MACOSX_1___OSX_CARBON_COCOA_SRC_OBJECTS = \ monodll_dcclient.o \ monodll_dcprint.o \ monodll_dcscreen.o \ + monodll_glgrab.o \ monodll_graphics.o \ monodll_dnd.o \ monodll_font.o \ @@ -12019,6 +12020,7 @@ COND_PLATFORM_MACOSX_1___OSX_CARBON_COCOA_SRC_OBJECTS_0 = \ monolib_dcclient.o \ monolib_dcprint.o \ monolib_dcscreen.o \ + monolib_glgrab.o \ monolib_graphics.o \ monolib_dnd.o \ monolib_font.o \ @@ -12179,6 +12181,7 @@ COND_PLATFORM_MACOSX_1___OSX_CARBON_COCOA_SRC_OBJECTS_8 = \ coredll_dcclient.o \ coredll_dcprint.o \ coredll_dcscreen.o \ + coredll_glgrab.o \ coredll_graphics.o \ coredll_dnd.o \ coredll_font.o \ @@ -12259,6 +12262,7 @@ COND_PLATFORM_MACOSX_1___OSX_CARBON_COCOA_SRC_OBJECTS_9 = \ corelib_dcclient.o \ corelib_dcprint.o \ corelib_dcscreen.o \ + corelib_glgrab.o \ corelib_graphics.o \ corelib_dnd.o \ corelib_font.o \ @@ -17929,6 +17933,12 @@ monodll_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONODLL_ODEP) @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@monodll_fontdlgosx.o: $(srcdir)/src/osx/carbon/fontdlgosx.mm $(MONODLL_ODEP) @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/osx/carbon/fontdlgosx.mm +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@monodll_glgrab.o: $(srcdir)/src/osx/core/glgrab.cpp $(MONODLL_ODEP) +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/osx/core/glgrab.cpp + +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@monodll_glgrab.o: $(srcdir)/src/osx/core/glgrab.cpp $(MONODLL_ODEP) +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/osx/core/glgrab.cpp + @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@monodll_statbrma.o: $(srcdir)/src/osx/carbon/statbrma.cpp $(MONODLL_ODEP) @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/osx/carbon/statbrma.cpp @@ -22597,6 +22607,12 @@ monolib_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONOLIB_ODEP) @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@monolib_fontdlgosx.o: $(srcdir)/src/osx/carbon/fontdlgosx.mm $(MONOLIB_ODEP) @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/osx/carbon/fontdlgosx.mm +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@monolib_glgrab.o: $(srcdir)/src/osx/core/glgrab.cpp $(MONOLIB_ODEP) +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/osx/core/glgrab.cpp + +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@monolib_glgrab.o: $(srcdir)/src/osx/core/glgrab.cpp $(MONOLIB_ODEP) +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/osx/core/glgrab.cpp + @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@monolib_statbrma.o: $(srcdir)/src/osx/carbon/statbrma.cpp $(MONOLIB_ODEP) @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/osx/carbon/statbrma.cpp @@ -27478,6 +27494,12 @@ coredll_win32.o: $(srcdir)/src/univ/themes/win32.cpp $(COREDLL_ODEP) @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@coredll_fontdlgosx.o: $(srcdir)/src/osx/carbon/fontdlgosx.mm $(COREDLL_ODEP) @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/osx/carbon/fontdlgosx.mm +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@coredll_glgrab.o: $(srcdir)/src/osx/core/glgrab.cpp $(COREDLL_ODEP) +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/osx/core/glgrab.cpp + +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@coredll_glgrab.o: $(srcdir)/src/osx/core/glgrab.cpp $(COREDLL_ODEP) +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/osx/core/glgrab.cpp + @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@coredll_statbrma.o: $(srcdir)/src/osx/carbon/statbrma.cpp $(COREDLL_ODEP) @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/osx/carbon/statbrma.cpp @@ -30973,6 +30995,12 @@ corelib_win32.o: $(srcdir)/src/univ/themes/win32.cpp $(CORELIB_ODEP) @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@corelib_fontdlgosx.o: $(srcdir)/src/osx/carbon/fontdlgosx.mm $(CORELIB_ODEP) @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/osx/carbon/fontdlgosx.mm +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@corelib_glgrab.o: $(srcdir)/src/osx/core/glgrab.cpp $(CORELIB_ODEP) +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/osx/core/glgrab.cpp + +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@corelib_glgrab.o: $(srcdir)/src/osx/core/glgrab.cpp $(CORELIB_ODEP) +@COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_COCOA_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/osx/core/glgrab.cpp + @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@corelib_statbrma.o: $(srcdir)/src/osx/carbon/statbrma.cpp $(CORELIB_ODEP) @COND_PLATFORM_MACOSX_1_TOOLKIT_OSX_CARBON_USE_GUI_1_WXUNIV_0@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/osx/carbon/statbrma.cpp diff --git a/configure b/configure index 2b7bb4201f..43017aedf7 100755 --- a/configure +++ b/configure @@ -46979,7 +46979,7 @@ if test "$wxUSE_MAC" = 1 ; then fi fi if test "$USE_DARWIN" = 1; then - LDFLAGS="$LDFLAGS -framework IOKit -framework Carbon -framework Cocoa -framework AudioToolbox -framework System" + LDFLAGS="$LDFLAGS -framework IOKit -framework Carbon -framework Cocoa -framework AudioToolbox -framework System -framework OpenGL" fi fi if test "$wxUSE_COCOA" = 1 ; then diff --git a/configure.in b/configure.in index 47c5f64a9e..342a8a1c0b 100644 --- a/configure.in +++ b/configure.in @@ -7355,7 +7355,7 @@ if test "$wxUSE_MAC" = 1 ; then fi fi if test "$USE_DARWIN" = 1; then - LDFLAGS="$LDFLAGS -framework IOKit -framework Carbon -framework Cocoa -framework AudioToolbox -framework System" + LDFLAGS="$LDFLAGS -framework IOKit -framework Carbon -framework Cocoa -framework AudioToolbox -framework System -framework OpenGL" fi fi if test "$wxUSE_COCOA" = 1 ; then diff --git a/include/wx/osx/carbon/dcscreen.h b/include/wx/osx/carbon/dcscreen.h index 76f1f54176..8bf2aa52f4 100644 --- a/include/wx/osx/carbon/dcscreen.h +++ b/include/wx/osx/carbon/dcscreen.h @@ -21,6 +21,7 @@ public: wxScreenDCImpl( wxDC *owner ); virtual ~wxScreenDCImpl(); + virtual wxBitmap DoGetAsBitmap(const wxRect *subrect) const; private: void* m_overlayWindow; diff --git a/include/wx/osx/private/glgrab.h b/include/wx/osx/private/glgrab.h new file mode 100644 index 0000000000..9961f51c2e --- /dev/null +++ b/include/wx/osx/private/glgrab.h @@ -0,0 +1,12 @@ +#include + +#if defined __cplusplus + extern "C" { +#endif + + CGImageRef grabViaOpenGL(CGDirectDisplayID display, CGRect srcRect); + +#if defined __cplusplus + } +#endif + diff --git a/src/osx/carbon/dcscreen.cpp b/src/osx/carbon/dcscreen.cpp index e544aa4ae4..3f0d549ce3 100644 --- a/src/osx/carbon/dcscreen.cpp +++ b/src/osx/carbon/dcscreen.cpp @@ -16,6 +16,7 @@ #include "wx/osx/private.h" #include "wx/graphics.h" +#include "wx/osx/private/glgrab.h" IMPLEMENT_ABSTRACT_CLASS(wxScreenDCImpl, wxWindowDCImpl) @@ -57,3 +58,37 @@ wxScreenDCImpl::~wxScreenDCImpl() DisposeWindow((WindowRef) m_overlayWindow ); #endif } + +wxBitmap wxScreenDCImpl::DoGetAsBitmap(const wxRect *subrect) const +{ + CGRect srcRect = CGRectMake(0, 0, m_width, m_height); + if (subrect) + { + srcRect.origin.x = subrect->GetX(); + srcRect.origin.y = subrect->GetY(); + srcRect.size.width = subrect->GetWidth(); + srcRect.size.height = subrect->GetHeight(); + } + + wxBitmap bmp = wxBitmap(srcRect.size.width, srcRect.size.height, 32); + + CGContextRef context = (CGContextRef)bmp.GetHBITMAP(); + + CGContextSaveGState(context); + + CGContextTranslateCTM( context, 0, m_height ); + CGContextScaleCTM( context, 1, -1 ); + + if ( subrect ) + srcRect = CGRectOffset( srcRect, -subrect->x, -subrect->y ) ; + + CGImageRef image = grabViaOpenGL(kCGNullDirectDisplay, srcRect); + + wxASSERT_MSG(image, wxT("wxScreenDC::GetAsBitmap - unable to get screenshot.")); + + CGContextDrawImage(context, srcRect, image); + + CGContextRestoreGState(context); + + return bmp; +} diff --git a/src/osx/core/glgrab.cpp b/src/osx/core/glgrab.cpp new file mode 100644 index 0000000000..4dff0202a8 --- /dev/null +++ b/src/osx/core/glgrab.cpp @@ -0,0 +1,214 @@ +/* + IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in + consideration of your agreement to the following terms, and your use, installation or modification + of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install or modify this Apple software. + + In consideration of your agreement to abide by the following terms, and subject to these + terms, Apple grants you a personal, non-exclusive license, under Apple\xd5s copyrights in + this original Apple software (the "Apple Software"), to use and modify the Apple Software, + with or without modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain this notice and + the following text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Computer, Inc. may be used + to endorse or promote products derived from the Apple Software without specific prior + written permission from Apple. Except as expressly tated in this notice, no other rights or + licenses, express or implied, are granted by Apple herein, including but not limited + to any patent rights that may be infringed by your derivative works or by other works + in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, + EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS + USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, + REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND + WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR + OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import +#import +#import + +#include "wx/osx/private/glgrab.h" + +extern CGColorSpaceRef wxMacGetGenericRGBColorSpace(); + +/* + * perform an in-place swap from Quadrant 1 to Quadrant III format + * (upside-down PostScript/GL to right side up QD/CG raster format) + * We do this in-place, which requires more copying, but will touch + * only half the pages. (Display grabs are BIG!) + * + * Pixel reformatting may optionally be done here if needed. + */ +static void swizzleBitmap(void * data, int rowBytes, int height) +{ + int top, bottom; + void * buffer; + void * topP; + void * bottomP; + void * base; + + + top = 0; + bottom = height - 1; + base = data; + buffer = malloc(rowBytes); + + + while ( top < bottom ) + { + topP = (void *)((top * rowBytes) + (intptr_t)base); + bottomP = (void *)((bottom * rowBytes) + (intptr_t)base); + + + /* + * Save and swap scanlines. + * + * This code does a simple in-place exchange with a temp buffer. + * If you need to reformat the pixels, replace the first two bcopy() + * calls with your own custom pixel reformatter. + */ + bcopy( topP, buffer, rowBytes ); + bcopy( bottomP, topP, rowBytes ); + bcopy( buffer, bottomP, rowBytes ); + + ++top; + --bottom; + } + free( buffer ); +} + + +/* + * Given a display ID and a rectangle on that display, generate a CGImageRef + * containing the display contents. + * + * srcRect is display-origin relative. + * + * This function uses a full screen OpenGL read-only context. + * By using OpenGL, we can read the screen using a DMA transfer + * when it's in millions of colors mode, and we can correctly read + * a microtiled full screen OpenGL context, such as a game or full + * screen video display. + * + * Returns a CGImageRef. When you are done with the CGImageRef, release it + * using CFRelease(). + * Returns NULL on an error. + */ + +CGImageRef grabViaOpenGL(CGDirectDisplayID display, CGRect srcRect) +{ + CGContextRef bitmap; + CGImageRef image; + void * data; + long bytewidth; + GLint width, height; + long bytes; + + CGLContextObj glContextObj; + CGLPixelFormatObj pixelFormatObj ; + GLint numPixelFormats ; + CGLPixelFormatAttribute attribs[] = + { + kCGLPFAFullScreen, + kCGLPFADisplayMask, + (CGLPixelFormatAttribute) 0, /* Display mask bit goes here */ + (CGLPixelFormatAttribute) 0 + } ; + + + if ( display == kCGNullDirectDisplay ) + display = CGMainDisplayID(); + attribs[2] = (CGLPixelFormatAttribute) CGDisplayIDToOpenGLDisplayMask(display); + + + /* Build a full-screen GL context */ + CGLChoosePixelFormat( attribs, &pixelFormatObj, &numPixelFormats ); + if ( pixelFormatObj == NULL ) // No full screen context support + return NULL; + CGLCreateContext( pixelFormatObj, NULL, &glContextObj ) ; + CGLDestroyPixelFormat( pixelFormatObj ) ; + if ( glContextObj == NULL ) + return NULL; + + + CGLSetCurrentContext( glContextObj ) ; + CGLSetFullScreen( glContextObj ) ; + + + glReadBuffer(GL_FRONT); + + + width = srcRect.size.width; + height = srcRect.size.height; + + + bytewidth = width * 4; // Assume 4 bytes/pixel for now + bytewidth = (bytewidth + 3) & ~3; // Align to 4 bytes + bytes = bytewidth * height; // width * height + + /* Build bitmap context */ + data = malloc(height * bytewidth); + if ( data == NULL ) + { + CGLSetCurrentContext( NULL ); + CGLClearDrawable( glContextObj ); // disassociate from full screen + CGLDestroyContext( glContextObj ); // and destroy the context + return NULL; + } + bitmap = CGBitmapContextCreate(data, width, height, 8, bytewidth, + wxMacGetGenericRGBColorSpace(), kCGImageAlphaNoneSkipFirst /* XRGB */); + + + /* Read framebuffer into our bitmap */ + glFinish(); /* Finish all OpenGL commands */ + glPixelStorei(GL_PACK_ALIGNMENT, 4); /* Force 4-byte alignment */ + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + glPixelStorei(GL_PACK_SKIP_ROWS, 0); + glPixelStorei(GL_PACK_SKIP_PIXELS, 0); + + /* + * Fetch the data in XRGB format, matching the bitmap context. + */ + glReadPixels((GLint)srcRect.origin.x, (GLint)srcRect.origin.y, width, height, + GL_BGRA, +#ifdef __BIG_ENDIAN__ + GL_UNSIGNED_INT_8_8_8_8_REV, // for PPC +#else + GL_UNSIGNED_INT_8_8_8_8, // for Intel! http://lists.apple.com/archives/quartz-dev/2006/May/msg00100.html +#endif + data); + /* + * glReadPixels generates a quadrant I raster, with origin in the lower left + * This isn't a problem for signal processing routines such as compressors, + * as they can simply use a negative 'advance' to move between scanlines. + * CGImageRef and CGBitmapContext assume a quadrant III raster, though, so we need to + * invert it. Pixel reformatting can also be done here. + */ + swizzleBitmap(data, bytewidth, height); + + + /* Make an image out of our bitmap; does a cheap vm_copy of the bitmap */ + image = CGBitmapContextCreateImage(bitmap); + + /* Get rid of bitmap */ + CFRelease(bitmap); + free(data); + + + /* Get rid of GL context */ + CGLSetCurrentContext( NULL ); + CGLClearDrawable( glContextObj ); // disassociate from full screen + CGLDestroyContext( glContextObj ); // and destroy the context + + /* Returned image has a reference count of 1 */ + return image; +} +