xref: /aoo41x/main/canvas/source/directx/dx_5rm.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_canvas.hxx"
30 
31 #if DIRECTX_VERSION < 0x0900
32 
33 // Nvidia GeForce Go 6800 crashes with a bluescreen if we take the
34 // maximum texture size, which would be twice as large. this behaviors
35 // has only been observed on directx5.
36 // This value is simply the maximum size for textures we request from
37 // the system, it has absolutely nothing to do with the size of primitives
38 // we're able to render, both concepts are totally independent from each other.
39 #define MAX_TEXTURE_SIZE (2048)
40 #define MIN_TEXTURE_SIZE (32)
41 //#define FAKE_MAX_NUMBER_TEXTURES (2)
42 //#define FAKE_MAX_TEXTURE_SIZE (512)
43 
44 //////////////////////////////////////////////////////////////////////////////////
45 // includes
46 //////////////////////////////////////////////////////////////////////////////////
47 #include <vcl/syschild.hxx>
48 #include <vcl/window.hxx>
49 #include <canvas/debug.hxx>
50 #include <canvas/verbosetrace.hxx>
51 #include <canvas/elapsedtime.hxx>
52 #include <canvas/canvastools.hxx>
53 #include <canvas/rendering/icolorbuffer.hxx>
54 #include <canvas/rendering/isurface.hxx>
55 #include <canvas/rendering/irendermodule.hxx>
56 #include <tools/diagnose_ex.h>
57 #include <basegfx/numeric/ftools.hxx>
58 #include <basegfx/vector/b2dsize.hxx>
59 #include <basegfx/vector/b2isize.hxx>
60 #include <basegfx/point/b2ipoint.hxx>
61 #include <basegfx/range/b2irectangle.hxx>
62 #include <boost/scoped_ptr.hpp>
63 #include <com/sun/star/lang/NoSupportException.hpp>
64 
65 #define COMPILE_MULTIMON_STUBS
66 
67 #include "dx_rendermodule.hxx"
68 #include "dx_surfacegraphics.hxx"
69 #include <vcl/sysdata.hxx>
70 
71 #undef WB_LEFT
72 #undef WB_RIGHT
73 
74 #include "dx_impltools.hxx"
75 #include <malloc.h>
76 
77 #if defined(DX_DEBUG_IMAGES)
78 # if OSL_DEBUG_LEVEL > 0
79 #  include <imdebug.h>
80 #  undef min
81 #  undef max
82 # endif
83 #endif
84 
85 #undef COMPILE_MULTIMON_STUBS
86 
87 #include <stdio.h>
88 
89 #define MONITOR_DEFAULTTONULL       0x00000000
90 #define MONITOR_DEFAULTTOPRIMARY    0x00000001
91 #define MONITOR_DEFAULTTONEAREST    0x00000002
92 
93 using namespace ::com::sun::star;
94 
95 //////////////////////////////////////////////////////////////////////////////////
96 // 'dxcanvas' namespace
97 //////////////////////////////////////////////////////////////////////////////////
98 
99 namespace dxcanvas
100 {
101 	namespace
102 	{
103         bool doBlit( const ::basegfx::B2IPoint& rDestPos,
104                      IDirectDrawSurface&        rOutSurface,
105                      const ::basegfx::B2IRange& rSourceArea,
106                      IDirectDrawSurface&        rSourceSurface,
107                      DDBLTFX*                   pBltFx,
108                      bool                       bForceSoftware )
109         {
110             if( !bForceSoftware )
111             {
112                 // blit surface to backbuffer
113                 RECT aOutRect =
114                     {
115                         rDestPos.getX(),
116                         rDestPos.getY(),
117                         rDestPos.getX() + static_cast<sal_Int32>(rSourceArea.getWidth()),
118                         rDestPos.getY() + static_cast<sal_Int32>(rSourceArea.getHeight()),
119                     };
120                 RECT aSourceRect =
121                     {
122                         rSourceArea.getMinX(),
123                         rSourceArea.getMinY(),
124                         rSourceArea.getMaxX(),
125                         rSourceArea.getMaxY()
126                     };
127 
128                 if( SUCCEEDED(rOutSurface.Blt( &aOutRect,
129                                                &rSourceSurface,
130                                                &aSourceRect,
131                                                DDBLT_WAIT,
132                                                pBltFx )) )
133                 {
134                     return true;
135                 }
136             }
137 
138             // failed, or forced to use SW copy. attempt manual copy.
139             bool bResult = false;
140 
141             // lock source surface
142             DDSURFACEDESC aDescSrc;
143             rtl_fillMemory(&aDescSrc,sizeof(DDSURFACEDESC),0);
144             aDescSrc.dwSize = sizeof(DDSURFACEDESC);
145             const DWORD dwSrcFlags = DDLOCK_NOSYSLOCK|
146                 DDLOCK_SURFACEMEMORYPTR|
147                 DDLOCK_WAIT|
148                 DDLOCK_READONLY;
149             if(SUCCEEDED(rSourceSurface.Lock(NULL,
150                                              &aDescSrc,
151                                              dwSrcFlags,
152                                              NULL)))
153             {
154                 // lock destination surface
155                 DDSURFACEDESC aDescDst;
156                 rtl_fillMemory(&aDescDst,sizeof(DDSURFACEDESC),0);
157                 aDescDst.dwSize = sizeof(DDSURFACEDESC);
158                 const DWORD dwDstFlags = DDLOCK_NOSYSLOCK|
159                     DDLOCK_SURFACEMEMORYPTR|
160                     DDLOCK_WAIT|
161                     DDLOCK_WRITEONLY;
162                 if(SUCCEEDED(rOutSurface.Lock(NULL,
163                                               &aDescDst,
164                                               dwDstFlags,
165                                               NULL)))
166                 {
167                     sal_uInt32 nSrcFormat;
168                     nSrcFormat  = ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwRGBAlphaBitMask)<<12;
169                     nSrcFormat |= ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwRBitMask)<<8;
170                     nSrcFormat |= ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwGBitMask)<<4;
171                     nSrcFormat |= ::canvas::tools::bitcount32(aDescSrc.ddpfPixelFormat.dwBBitMask);
172 
173                     sal_uInt32 nDstFormat;
174                     nDstFormat  = ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwRGBAlphaBitMask)<<12;
175                     nDstFormat |= ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwRBitMask)<<8;
176                     nDstFormat |= ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwGBitMask)<<4;
177                     nDstFormat |= ::canvas::tools::bitcount32(aDescDst.ddpfPixelFormat.dwBBitMask);
178 
179                     // TODO(E1): Use numeric_cast to catch overflow here
180                     const sal_uInt32 nWidth( static_cast<sal_uInt32>(
181                                                    rSourceArea.getWidth() ) );
182                     const sal_uInt32 nHeight( static_cast<sal_uInt32>(
183                                                     rSourceArea.getHeight() ) );
184 
185                     if((nSrcFormat == 0x8888) && (nDstFormat == 0x0565))
186                     {
187                         // medium range 8888 to 0565 pixel format conversion.
188                         bResult = true;
189                         sal_uInt8 *pSrcSurface = (sal_uInt8 *)aDescSrc.lpSurface +
190                             rSourceArea.getMinY()*aDescSrc.lPitch +
191                             (rSourceArea.getMinX()<<2);
192                         sal_uInt8 *pDstSurface = (sal_uInt8 *)aDescDst.lpSurface +
193                             rDestPos.getY()*aDescDst.lPitch +
194                             (rDestPos.getX()<<1);
195                         for(sal_uInt32 y=0; y<nHeight; ++y)
196                         {
197                             sal_uInt32 *pSrcScanline = (sal_uInt32 *)pSrcSurface;
198                             sal_uInt16 *pDstScanline = (sal_uInt16 *)pDstSurface;
199                             for(sal_uInt32 x=0; x<nWidth; ++x)
200                             {
201                                 sal_uInt32 srcPixel = *pSrcScanline++;
202                                 sal_uInt16 dstPixel;
203                                 dstPixel  = (sal_uInt16)((srcPixel & 0x0000F8) >> 3);
204                                 dstPixel |= (srcPixel & 0x00FC00) >> 5;
205                                 dstPixel |= (srcPixel & 0xF80000) >> 8;
206                                 *pDstScanline++ = dstPixel;
207                             }
208                             pSrcSurface += aDescSrc.lPitch;
209                             pDstSurface += aDescDst.lPitch;
210                         }
211                     }
212                     else if((nSrcFormat == 0x8888) && (nDstFormat == 0x0888))
213                     {
214                         // medium range 8888 to 0888 pixel format conversion.
215                         bResult = true;
216                         sal_uInt8 *pSrcSurface = (sal_uInt8 *)aDescSrc.lpSurface +
217                             rSourceArea.getMinY()*aDescSrc.lPitch +
218                             (rSourceArea.getMinX()<<2);
219                         sal_uInt8 *pDstSurface = (sal_uInt8 *)aDescDst.lpSurface +
220                             rDestPos.getY()*aDescDst.lPitch +
221                             (rDestPos.getX()<<2);
222                         for(sal_uInt32 y=0; y<nHeight; ++y)
223                         {
224                             sal_uInt32 *pSrcScanline = (sal_uInt32 *)pSrcSurface;
225                             sal_uInt16 *pDstScanline = (sal_uInt16 *)pDstSurface;
226                             for(sal_uInt32 x=0; x<nWidth; ++x)
227                             {
228                                 *pDstScanline++ = (sal_uInt16)*pSrcScanline++;
229                             }
230                             pSrcSurface += aDescSrc.lPitch;
231                             pDstSurface += aDescDst.lPitch;
232                         }
233                     }
234                     else if((nSrcFormat == 0x8888) && (nDstFormat == 0x1555))
235                     {
236                         // medium range 8888 to 1555 pixel format conversion.
237                         bResult = true;
238                         sal_uInt8 *pSrcSurface = (sal_uInt8 *)aDescSrc.lpSurface +
239                             rSourceArea.getMinY()*aDescSrc.lPitch +
240                             (rSourceArea.getMinX()<<2);
241                         sal_uInt8 *pDstSurface = (sal_uInt8 *)aDescDst.lpSurface +
242                             rDestPos.getY()*aDescDst.lPitch +
243                             (rDestPos.getX()<<1);
244                         for(sal_uInt32 y=0; y<nHeight; ++y)
245                         {
246                             sal_uInt32 *pSrcScanline = (sal_uInt32*)pSrcSurface;
247                             sal_uInt16 *pDstScanline = (sal_uInt16 *)pDstSurface;
248                             for(sal_uInt32 x=0; x<nWidth; ++x)
249                             {
250                                 sal_uInt32 srcPixel = *pSrcScanline++;
251                                 sal_uInt16 dstPixel;
252                                 dstPixel  = (sal_uInt16)((srcPixel & 0x000000F8) >> 3);
253                                 dstPixel |= (srcPixel & 0x0000F800) >> 6;
254                                 dstPixel |= (srcPixel & 0x00F80000) >> 9;
255                                 dstPixel |= (srcPixel & 0x80000000) >> 16;
256                                 *pDstScanline++ = dstPixel;
257                             }
258                             pSrcSurface += aDescSrc.lPitch;
259                             pDstSurface += aDescDst.lPitch;
260                         }
261                     }
262 
263                     // unlock destination surface
264                     rOutSurface.Unlock(NULL);
265                 }
266 
267                 // unlock source surface
268                 rSourceSurface.Unlock(NULL);
269             }
270 
271             return bResult;
272         }
273 
274 		void dumpSurface( const COMReference<IDirectDrawSurface> &pSurface, const char *szFilename )
275 		{
276 			if(!(pSurface.get()))
277 				return;
278 
279 			DDSURFACEDESC aSurfaceDesc;
280 			rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 );
281 			aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
282 
283 			if( FAILED(pSurface->Lock( NULL,
284 										&aSurfaceDesc,
285 										DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY,
286 										NULL)) )
287 				return;
288 
289 			const std::size_t dwBitmapSize(aSurfaceDesc.dwWidth*aSurfaceDesc.dwHeight*4);
290 			sal_uInt8 *pBuffer = static_cast<sal_uInt8 *>(_alloca(dwBitmapSize));
291 			if(pBuffer)
292 			{
293 				sal_uInt8 *pSource = reinterpret_cast<sal_uInt8 *>(aSurfaceDesc.lpSurface);
294 				sal_uInt8 *pDest = reinterpret_cast<sal_uInt8 *>(pBuffer);
295 				const std::size_t dwDestPitch(aSurfaceDesc.dwWidth<<2);
296 				pDest += aSurfaceDesc.dwHeight*dwDestPitch;
297 				for(sal_uInt32 y=0; y<aSurfaceDesc.dwHeight; ++y)
298 				{
299 					pDest -= dwDestPitch;
300 					rtl_copyMemory( pDest, pSource, dwDestPitch );
301 					pSource += aSurfaceDesc.lPitch;
302 				}
303 
304 				if(FILE *fp = fopen(szFilename,"wb"))
305 				{
306 					BITMAPINFOHEADER bitmapInfo;
307 
308 					bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
309 					bitmapInfo.biWidth = aSurfaceDesc.dwWidth;
310 					bitmapInfo.biHeight = aSurfaceDesc.dwHeight;
311 					bitmapInfo.biPlanes = 1;
312 					bitmapInfo.biBitCount = 32;
313 					bitmapInfo.biCompression = BI_RGB;
314 					bitmapInfo.biSizeImage = 0;
315 					bitmapInfo.biXPelsPerMeter = 0;
316 					bitmapInfo.biYPelsPerMeter = 0;
317 					bitmapInfo.biClrUsed = 0;
318 					bitmapInfo.biClrImportant = 0;
319 
320 					const std::size_t dwFileSize(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwBitmapSize);
321 
322 					BITMAPFILEHEADER header;
323 					header.bfType = 'MB';
324 					header.bfSize = dwFileSize;
325 					header.bfReserved1 = 0;
326 					header.bfReserved2 = 0;
327 					header.bfOffBits = sizeof(BITMAPFILEHEADER) + bitmapInfo.biSize;
328 
329 					fwrite(&header,1,sizeof(BITMAPFILEHEADER),fp);
330 					fwrite(&bitmapInfo,1,sizeof(BITMAPINFOHEADER),fp);
331 					fwrite(pBuffer,1,dwBitmapSize,fp);
332 
333 					fclose(fp);
334 				}
335 			}
336 
337 			pSurface->Unlock(NULL);
338 		}
339 
340 		void clearSurface( const COMReference<IDirectDrawSurface>& pSurface )
341 		{
342 			if(!(pSurface.is()))
343 				return;
344 
345 			DDBLTFX aBltFx;
346 
347 			rtl_fillMemory( &aBltFx,
348 							sizeof(DDBLTFX), 0 );
349 			aBltFx.dwSize = sizeof(DDBLTFX);
350 			aBltFx.dwFillColor = 0;
351 
352 			pSurface->Blt( NULL,
353                            NULL,
354                            NULL,
355                            DDBLT_COLORFILL | DDBLT_WAIT,
356                            &aBltFx );
357 		}
358 
359 		// Define struct for MonitorEntry
360 		struct MonitorEntry
361 		{
362  			GUID                 mnGUID;
363  			HMONITOR             mhMonitor;
364             MONITORINFO   maMonitorInfo;
365 		};
366 
367 		// define type for MonitorList
368         typedef ::std::vector< MonitorEntry > MonitorList;
369 
370  		// Win32 system callback for DirectDrawEnumerateExA call
371  		BOOL WINAPI EnumerateExA_Callback( GUID FAR* lpGUID,
372                                            LPSTR     /*lpDriverDescription*/,
373                                            LPSTR     /*lpDriverName*/,
374                                            LPVOID    lpContext,
375                                            HMONITOR  hMonitor )
376 		{
377 			if(lpGUID)
378 			{
379  				MonitorList* pMonitorList = (MonitorList*)lpContext;
380 				MonitorEntry aEntry;
381 
382  				aEntry.mnGUID = *lpGUID;
383  				aEntry.mhMonitor = hMonitor;
384                 aEntry.maMonitorInfo.cbSize = sizeof(MONITORINFO);
385                 GetMonitorInfo( hMonitor,
386                                 &aEntry.maMonitorInfo );
387 
388 				pMonitorList->push_back(aEntry);
389 			}
390 
391 			return DDENUMRET_OK;
392 		}
393 
394         void fillMonitorList( MonitorList& rMonitorList )
395         {
396             // Try to fill MonitorList. If neither lib or call to
397             // DirectDrawEnumerateExA does not exist, it's an old
398             // DX version (< 5.0), or system does not support
399             // multiple monitors.
400             HINSTANCE hInstance = LoadLibrary("ddraw.dll");
401 
402             if(hInstance)
403             {
404                 LPDIRECTDRAWENUMERATEEX lpDDEnumEx =
405                     (LPDIRECTDRAWENUMERATEEX)GetProcAddress(hInstance,"DirectDrawEnumerateExA");
406 
407                 if(lpDDEnumEx)
408                     lpDDEnumEx( (LPDDENUMCALLBACKEXA) EnumerateExA_Callback,
409                                 &rMonitorList,
410                                 DDENUM_ATTACHEDSECONDARYDEVICES );
411 
412                 FreeLibrary(hInstance);
413             }
414         }
415 
416         IDirectDraw2* createDirectDraw( const MonitorList& rMonitorList,
417                                         MONITORINFO&       rMonitorInfo,
418                                         HWND        renderWindow )
419         {
420  			GUID* gpSelectedDriverGUID = NULL;
421 
422             // if we have multiple monitors, choose a gpSelectedDriverGUID from monitor list
423             HMONITOR hMonitor = MonitorFromWindow(renderWindow,
424                                                   MONITOR_DEFAULTTONEAREST);
425 
426             MonitorList::const_iterator       aCurr = rMonitorList.begin();
427             const MonitorList::const_iterator aEnd = rMonitorList.end();
428             while( !gpSelectedDriverGUID && aCurr != aEnd )
429             {
430                 if(hMonitor == aCurr->mhMonitor)
431                 {
432                     // This is the monitor we are running on
433                     gpSelectedDriverGUID = const_cast<GUID*>(&aCurr->mnGUID);
434                     rMonitorInfo = aCurr->maMonitorInfo;
435                 }
436 
437                 ++aCurr;
438             }
439 
440             IDirectDraw* pDirectDraw;
441             if( FAILED( DirectDrawCreate( gpSelectedDriverGUID, &pDirectDraw, NULL )))
442                 return NULL;
443 
444             IDirectDraw2* pDirectDraw2;
445             if( FAILED( pDirectDraw->QueryInterface( IID_IDirectDraw2, (LPVOID*)&pDirectDraw2 )))
446                 return NULL;
447 
448 			// queryInterface bumped up the refcount, so release the
449 			// reference to the original IDirectDraw interface.
450 			pDirectDraw->Release();
451 
452             return pDirectDraw2;
453         }
454 
455         HRESULT WINAPI EnumTextureFormatsCallback( LPDDSURFACEDESC 	pSurfaceDesc,
456                                                    LPVOID			pContext		)
457         {
458             // dirty cast of given context back to result ModeSelectContext
459             DDPIXELFORMAT* pResult = (DDPIXELFORMAT*)pContext;
460 
461             if( pResult == NULL || pSurfaceDesc == NULL )
462                 return DDENUMRET_CANCEL;
463 
464             VERBOSE_TRACE( "EnumTextureFormatsCallback: advertised texture format has dwRGBBitCount %d, dwRBitMask %x, "
465                            "dwGBitMask %x, dwBBitMask %x and dwRGBAlphaBitMask %x. The format uses %s alpha.",
466                            pSurfaceDesc->ddpfPixelFormat.dwRGBBitCount,
467                            pSurfaceDesc->ddpfPixelFormat.dwRBitMask,
468                            pSurfaceDesc->ddpfPixelFormat.dwGBitMask,
469                            pSurfaceDesc->ddpfPixelFormat.dwBBitMask,
470                            pSurfaceDesc->ddpfPixelFormat.dwRGBAlphaBitMask,
471                            pSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_ALPHAPREMULT ? "premultiplied" : "non-premultiplied" );
472 
473             // Only accept RGB surfaces with alpha channel
474             if( (DDPF_ALPHAPIXELS | DDPF_RGB) ==
475                 (pSurfaceDesc->ddpfPixelFormat.dwFlags & (DDPF_ALPHAPIXELS | DDPF_RGB)) )
476             {
477 				// ignore formats with the DDPF_ALPHAPREMULT flag
478 				if(!(pSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_ALPHAPREMULT))
479 				{
480 					// take widest alpha channel available
481 					if( pSurfaceDesc->ddpfPixelFormat.dwAlphaBitDepth > pResult->dwAlphaBitDepth )
482 					{
483 						// take new format
484 						rtl_copyMemory( pResult, &pSurfaceDesc->ddpfPixelFormat, sizeof(DDPIXELFORMAT) );
485 					}
486 					else if( pSurfaceDesc->ddpfPixelFormat.dwAlphaBitDepth == pResult->dwAlphaBitDepth )
487 					{
488 						// tie-breaking: take highest bitcount
489 						if( pSurfaceDesc->ddpfPixelFormat.dwRGBBitCount > pResult->dwRGBBitCount )
490 						{
491 							// take new format
492 							rtl_copyMemory( pResult, &pSurfaceDesc->ddpfPixelFormat, sizeof(DDPIXELFORMAT) );
493 						}
494 					}
495 				}
496             }
497 
498             return DDENUMRET_OK;
499         }
500 
501 		class DXRenderModule;
502 
503 		//////////////////////////////////////////////////////////////////////////////////
504 		// DXSurface
505 		//////////////////////////////////////////////////////////////////////////////////
506 
507 		/** ISurface implemenation.
508 
509 			@attention holds the DXRenderModule via non-refcounted
510 			reference! This is safe with current state of affairs, since
511 			the canvas::PageManager holds surface and render module via
512 			shared_ptr (and makes sure all surfaces are deleted before its
513 			render module member goes out of scope).
514 		*/
515 		class DXSurface : public canvas::ISurface
516 		{
517 		public:
518 			DXSurface( DXRenderModule&           rRenderModule,
519                        const ::basegfx::B2ISize& rSize );
520 			~DXSurface();
521 
522 			virtual bool selectTexture();
523 			virtual bool isValid();
524 			virtual bool update( const ::basegfx::B2IPoint& rDestPos,
525                                  const ::basegfx::B2IRange& rSourceRect,
526                                  ::canvas::IColorBuffer&    rSource );
527 			virtual ::basegfx::B2IVector getSize();
528 
529 		private:
530 			/// Guard local methods against concurrent acces to RenderModule
531 			class ImplRenderModuleGuard : private ::boost::noncopyable
532 			{
533 			public:
534 				explicit inline ImplRenderModuleGuard( DXRenderModule& rRenderModule );
535 				inline ~ImplRenderModuleGuard();
536 
537 			private:
538 				DXRenderModule& mrRenderModule;
539 			};
540 
541 			DXRenderModule&                         mrRenderModule;
542 
543 			COMReference<IDirectDrawSurface> mpSurface;
544 			COMReference<IDirect3DTexture2>  mpTexture;
545 
546 			::basegfx::B2IVector maSize;
547 		};
548 
549 		//////////////////////////////////////////////////////////////////////////////////
550 		// DXRenderModule
551 		//////////////////////////////////////////////////////////////////////////////////
552 
553 		/// Default implementation of IDXRenderModule
554 		class DXRenderModule : public IDXRenderModule
555 		{
556         public:
557             explicit DXRenderModule( const ::Window& rWindow );
558 
559             virtual void lock() const { maMutex.acquire(); }
560             virtual void unlock() const { maMutex.release(); }
561 
562             virtual COMReference<IDirectDrawSurface>
563                 createSystemMemorySurface( const ::basegfx::B2IVector& rSize );
564 
565             virtual bool flip( const ::basegfx::B2IRectangle& rUpdateArea,
566                                const ::basegfx::B2IRectangle& rCurrWindowArea );
567 
568             virtual void resize( const ::basegfx::B2IRange& rect );
569 			virtual HWND getHWND() const { return mhWnd; }
570 			virtual void disposing();
571 			virtual void screenShot();
572             virtual ::basegfx::B2IVector getPageSize();
573             virtual ::canvas::ISurfaceSharedPtr createSurface( const ::basegfx::B2IVector& surfaceSize );
574             virtual void beginPrimitive( PrimitiveType eType );
575             virtual void endPrimitive();
576             virtual void pushVertex( const ::canvas::Vertex& vertex );
577             virtual bool isError();
578 
579             const D3DDEVICEDESC&             getDeviceDesc() const { return maDeviceDesc; }
580             const DDPIXELFORMAT&             getTextureFormat() const { return maTextureFormat; }
581             COMReference<IDirectDraw2>       getDirectDraw() { return mpDirectDraw; }
582             COMReference< IDirect3DDevice2 > getDevice() { return mpDirect3DDevice; }
583 
584             void flushVertexCache();
585 
586             struct ModeSelectContext
587             {
588                 DDSURFACEDESC selectedDesc;
589                 ::basegfx::B2ISize	 requestedSize;
590             };
591 
592             /** Query actual size of the device
593 
594                 This is especially interesting for fullscreen devices
595             */
596             ::basegfx::B2ISize getFramebufferSize() const;
597 
598             /** Query the amount of memory available for new surfaces
599 
600                 This might differ from getAvailableTextureMem()
601                 @see getAvailableTextureMem()
602 
603                 @param bWithAGPMema
604                 When true, returned value includes non-local,
605                 i.e. AGP-able memory, too.
606 
607                 @return the amount of free surface mem
608             */
609             std::size_t	  getAvailableSurfaceMem( bool bWithAGPMem=true ) const;
610 
611             /** Query the amount of memory available for new textures
612 
613                 This might differ from getAvailableSurfaceMem()
614                 @see getAvailableSurfaceMem()
615 
616                 @param bWithAGPMema
617                 When true, returned value includes non-local,
618                 i.e. AGP-able memory, too.
619 
620                 @return the amount of free texture mem
621             */
622             std::size_t     getAvailableTextureMem( bool bWithAGPMem=true ) const;
623 
624         private:
625             bool queryCaps();
626             bool validateCaps();
627             bool setup3DDevice();
628             unsigned int getDisplayFormat() const;
629 
630             void convert2Screen( ::basegfx::B2IPoint& io_rDestPos,
631                                  ::basegfx::B2IRange& io_rDestArea );
632 
633             void renderInfoText( const ::rtl::OUString& rStr,
634                                  const Gdiplus::PointF& rPos ) const;
635             void renderFPSCounter() const;
636             void renderMemAvailable() const;
637 
638             bool create( const ::Window& rWindow );
639             bool validateMainSurfaces();
640 
641             /** This object represents the DirectX state machine.  In order
642                 to serialize access to DirectX's global state, a global
643                 mutex is required.
644             */
645             static ::osl::Mutex						maMutex;
646 
647             HWND                                    mhWnd;
648 			::boost::scoped_ptr<SystemChildWindow>	mpWindow;
649 			::basegfx::B2IVector					maSize;
650 
651             ModeSelectContext						maSelectedFullscreenMode;
652             DDPIXELFORMAT                           maTextureFormat;
653 
654             MONITORINFO                             maMonitorInfo; // monitor info for mpDirectDraw's monitor
655             COMReference<IDirectDraw2>              mpDirectDraw;
656             COMReference<IDirectDrawSurface>        mpPrimarySurface;
657             COMReference<IDirectDrawSurface>        mpBackBufferSurface;
658 
659             COMReference< IDirect3D2 >              mpDirect3D;
660             COMReference< IDirect3DDevice2 >        mpDirect3DDevice;
661 
662             mutable ::canvas::tools::ElapsedTime	maLastUpdate;	// for the frame counter
663 
664             D3DDEVICEDESC                           maDeviceDesc;
665 
666             typedef std::vector<canvas::Vertex>	    vertexCache_t;
667             vertexCache_t							maVertexCache;
668             std::size_t								mnCount;
669 
670             int                                     mnBeginSceneCount;
671 
672             const bool								mbPageFlipping;
673             bool 									mbHasNoTearingBlt;
674             bool									mbError;
675             PrimitiveType							meType;
676 
677 			::canvas::ISurfaceSharedPtr				mpTexture;
678 			::basegfx::B2IVector					maPageSize;
679 		};
680 
681 		::osl::Mutex DXRenderModule::maMutex;
682 
683 		//////////////////////////////////////////////////////////////////////////////////
684 		// DXSurface::ImplRenderModuleGuard
685 		//////////////////////////////////////////////////////////////////////////////////
686 
687 		inline DXSurface::ImplRenderModuleGuard::ImplRenderModuleGuard(
688 			DXRenderModule& rRenderModule ) :
689 			mrRenderModule( rRenderModule )
690 		{
691 			mrRenderModule.lock();
692 		}
693 
694 		inline DXSurface::ImplRenderModuleGuard::~ImplRenderModuleGuard()
695 		{
696 			mrRenderModule.unlock();
697 		}
698 
699 #ifdef FAKE_MAX_NUMBER_TEXTURES
700 		static sal_uInt32 gNumSurfaces = 0;
701 #endif
702 
703         void fillRect( sal_uInt32 *pDest,
704                        sal_uInt32 dwWidth,
705                        sal_uInt32 dwHeight,
706                        sal_uInt32 dwPitch,
707                        sal_uInt32 dwColor )
708         {
709             for(sal_uInt32 i=0; i<dwWidth; ++i)
710             {
711                 pDest[i]=dwColor;
712                 pDest[((dwHeight-1)*dwPitch)+i]=dwColor;
713             }
714 
715             for(sal_uInt32 j=0; j<dwHeight; ++j)
716             {
717                 pDest[0]=dwColor;
718                 pDest[dwWidth-1]=dwColor;
719                 pDest += dwPitch;
720             }
721         }
722 
723 		//////////////////////////////////////////////////////////////////////////////////
724 		// DXSurface::DXSurface
725 		//////////////////////////////////////////////////////////////////////////////////
726 
727 		DXSurface::DXSurface( DXRenderModule&           rRenderModule,
728 							  const ::basegfx::B2ISize& rSize ) :
729             mrRenderModule(rRenderModule),
730             mpTexture(NULL),
731             mpSurface(NULL),
732 			maSize()
733 		{
734 			ImplRenderModuleGuard aGuard( mrRenderModule );
735 
736 #ifdef FAKE_MAX_NUMBER_TEXTURES
737 			++gNumSurfaces;
738 			if(gNumSurfaces >= FAKE_MAX_NUMBER_TEXTURES)
739 				return;
740 #endif
741 
742 #ifdef FAKE_MAX_TEXTURE_SIZE
743 			if(rSize.getX() > FAKE_MAX_TEXTURE_SIZE)
744 				return;
745 			if(rSize.getY() > FAKE_MAX_TEXTURE_SIZE)
746 				return;
747 #endif
748 
749 			ENSURE_ARG_OR_THROW(rSize.getX() > 0 && rSize.getY() > 0,
750 							"DXSurface::DXSurface(): request for zero-sized surface");
751 
752 			const D3DDEVICEDESC &deviceDesc = rRenderModule.getDeviceDesc();
753 
754 			DDSURFACEDESC aSurfaceDesc;
755 			rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 );
756 			aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
757 			aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
758 			aSurfaceDesc.dwWidth = ::std::min(deviceDesc.dwMaxTextureWidth,::canvas::tools::nextPow2(rSize.getX()));
759 			aSurfaceDesc.dwHeight = ::std::min(deviceDesc.dwMaxTextureHeight,::canvas::tools::nextPow2(rSize.getY()));
760 			aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE |
761 										  DDSCAPS_VIDEOMEMORY |
762 										  DDSCAPS_LOCALVIDMEM;
763 			rtl_copyMemory(&aSurfaceDesc.ddpfPixelFormat,&rRenderModule.getTextureFormat(),sizeof(DDPIXELFORMAT));
764 
765 	        IDirectDrawSurface *pSurface;
766 			COMReference<IDirectDraw2> pDirectDraw(rRenderModule.getDirectDraw());
767 			HRESULT hr = pDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL);
768 			if(FAILED(hr))
769 			{
770 				// if the call failed due to 'out of videomemory',
771 				// retry with request for AGP memory.
772 				if(DDERR_OUTOFVIDEOMEMORY == hr)
773 				{
774 					aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE |
775 												  DDSCAPS_VIDEOMEMORY |
776 												  DDSCAPS_NONLOCALVIDMEM;
777 					hr = pDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL);
778 				}
779 			}
780 
781 			if(SUCCEEDED(hr))
782 			{
783 				IDirect3DTexture2* pTexture;
784 				if( FAILED(pSurface->QueryInterface(IID_IDirect3DTexture2, (LPVOID *)&pTexture)) )
785 				{
786 					pSurface->Release();
787 					return;
788 				}
789 
790 				maSize.setX(aSurfaceDesc.dwWidth);
791 				maSize.setY(aSurfaceDesc.dwHeight);
792 
793 				mpSurface=COMReference<IDirectDrawSurface>(pSurface);
794 				mpTexture=COMReference<IDirect3DTexture2>(pTexture);
795 
796 				// #122683# Clear texture, to avoid ugly artifacts at the
797 				// border to invisible sprite areas (note that the textures
798 				// are usually only partly utilized).
799 				clearSurface( mpSurface );
800 			}
801 		}
802 
803 		//////////////////////////////////////////////////////////////////////////////////
804 		// DXSurface::~DXSurface
805 		//////////////////////////////////////////////////////////////////////////////////
806 
807 		DXSurface::~DXSurface()
808 		{
809 			ImplRenderModuleGuard aGuard( mrRenderModule );
810 
811 #ifdef FAKE_MAX_NUMBER_TEXTURES
812 			gNumSurfaces--;
813 #endif
814 		}
815 
816 		//////////////////////////////////////////////////////////////////////////////////
817 		// DXSurface::selectTexture
818 		//////////////////////////////////////////////////////////////////////////////////
819 
820 		bool DXSurface::selectTexture()
821 		{
822 			ImplRenderModuleGuard aGuard( mrRenderModule );
823 
824 			mrRenderModule.flushVertexCache();
825 
826             D3DTEXTUREHANDLE aTextureHandle;
827             if(FAILED(mpTexture->GetHandle(
828                           mrRenderModule.getDevice().get(),
829                           &aTextureHandle)))
830             {
831 				return false;
832             }
833 
834 			// select texture for next primitive
835             if(FAILED(mrRenderModule.getDevice()->SetRenderState(
836                           D3DRENDERSTATE_TEXTUREHANDLE,aTextureHandle)))
837             {
838 				return false;
839             }
840 
841 #if defined(DX_DEBUG_IMAGES)
842 # if OSL_DEBUG_LEVEL > 0
843 			if( mpSurface.is() )
844             {
845                 DDSURFACEDESC aSurfaceDesc;
846                 rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 );
847                 aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
848 
849                 if( SUCCEEDED(mpSurface->Lock( NULL,
850                                                &aSurfaceDesc,
851                                                DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_READONLY,
852                                                NULL)) )
853                 {
854                     imdebug( "rgba w=%d h=%d %p",
855                              aSurfaceDesc.dwWidth,
856                              aSurfaceDesc.dwHeight,
857                              aSurfaceDesc.lpSurface );
858 
859                     mpSurface->Unlock(NULL);
860                 }
861             }
862 # endif
863 #endif
864 
865 			return true;
866 		}
867 
868 		//////////////////////////////////////////////////////////////////////////////////
869 		// DXSurface::isValid
870 		//////////////////////////////////////////////////////////////////////////////////
871 
872 		bool DXSurface::isValid()
873 		{
874 			ImplRenderModuleGuard aGuard( mrRenderModule );
875 
876 			if(!(mpSurface.is()))
877 				return false;
878 
879 			if(mpSurface->IsLost() == DDERR_SURFACELOST)
880             {
881 				mpSurface->Restore();
882 				return false;
883 			}
884 
885 			return true;
886 		}
887 
888 		//////////////////////////////////////////////////////////////////////////////////
889 		// DXSurface::update
890 		//////////////////////////////////////////////////////////////////////////////////
891 
892 		bool DXSurface::update( const ::basegfx::B2IPoint& rDestPos,
893 								const ::basegfx::B2IRange& rSourceRect,
894 								::canvas::IColorBuffer&    rSource )
895 		{
896 			ImplRenderModuleGuard aGuard( mrRenderModule );
897 
898 			// can't update if surface is not valid, that means
899 			// either not existent nor restored...
900 			if(!(isValid()))
901 				return false;
902 
903 			DDSURFACEDESC aSurfaceDesc;
904 			rtl_fillMemory( &aSurfaceDesc,sizeof(DDSURFACEDESC),0 );
905 			aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
906 
907 			// TODO(P2): only lock the region we want to update
908 			if( FAILED(mpSurface->Lock( NULL,
909                                         &aSurfaceDesc,
910                                         DDLOCK_NOSYSLOCK|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT|DDLOCK_WRITEONLY,
911                                         NULL)) )
912 				return false;
913 
914 			if(sal_uInt8* pImage = rSource.lock())
915 			{
916 				switch( rSource.getFormat() )
917 				{
918 					case ::canvas::IColorBuffer::FMT_A8R8G8B8:
919                     {
920                         const std::size_t nSourceBytesPerPixel(4);
921                         const std::size_t nSourcePitchInBytes(rSource.getStride());
922                         pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
923                         pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
924 
925                         // calculate the destination memory address
926                         sal_uInt8 *pDst = ((sal_uInt8*)aSurfaceDesc.lpSurface+
927                                            (rDestPos.getY()*aSurfaceDesc.lPitch) +
928                                            (4*rDestPos.getX()));
929 
930                         const sal_uInt32 nNumBytesToCopy(
931                             static_cast<sal_uInt32>(
932                                 rSourceRect.getWidth())*
933                             nSourceBytesPerPixel);
934                         const sal_uInt64 nNumLines(rSourceRect.getHeight());
935 
936                         for(sal_uInt32 i=0; i<nNumLines; ++i)
937                         {
938                             rtl_copyMemory(pDst,pImage,nNumBytesToCopy);
939 
940                             pDst += aSurfaceDesc.lPitch;
941                             pImage += nSourcePitchInBytes;
942                         }
943                     }
944                     break;
945 
946 					case ::canvas::IColorBuffer::FMT_R8G8B8:
947                     {
948                         const std::size_t nSourceBytesPerPixel(3);
949                         const std::size_t nSourcePitchInBytes(rSource.getStride());
950                         pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
951                         pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
952 
953                         // calculate the destination memory address
954                         sal_uInt8 *pDst = ((sal_uInt8*)aSurfaceDesc.lpSurface+
955                                            (rDestPos.getY()*aSurfaceDesc.lPitch) +
956                                            (4*rDestPos.getX()));
957 
958                         const sal_uInt64 nNumColumns(rSourceRect.getWidth());
959                         const sal_uInt64 nNumLines(rSourceRect.getHeight());
960                         for(sal_uInt32 i=0; i<nNumLines; ++i)
961                         {
962                             sal_uInt32 *pDstScanline = reinterpret_cast<sal_uInt32 *>(pDst);
963                             sal_uInt8 *pSrcScanline = reinterpret_cast<sal_uInt8 *>(pImage);
964                             for(sal_uInt32 x=0; x<nNumColumns; ++x)
965                             {
966                                 sal_uInt32 color(0xFF000000);
967                                 color |= pSrcScanline[2]<<16;
968                                 color |= pSrcScanline[1]<<8;
969                                 color |= pSrcScanline[0];
970                                 pSrcScanline += 3;
971                                 *pDstScanline++ = color;
972                             }
973 
974                             pDst += aSurfaceDesc.lPitch;
975                             pImage += nSourcePitchInBytes;
976                         }
977                     }
978                     break;
979 
980 					case ::canvas::IColorBuffer::FMT_X8R8G8B8:
981                     {
982                         const std::size_t nSourceBytesPerPixel(4);
983                         const std::size_t nSourcePitchInBytes(rSource.getStride());
984                         pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
985                         pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
986 
987                         // calculate the destination memory address
988                         sal_uInt8 *pDst = ((sal_uInt8*)aSurfaceDesc.lpSurface+
989                                            (rDestPos.getY()*aSurfaceDesc.lPitch) +
990                                            (4*rDestPos.getX()));
991 
992                         const sal_uInt64 nNumLines(rSourceRect.getHeight());
993 
994                         for(sal_uInt32 i=0; i<nNumLines; ++i)
995                         {
996                             sal_uInt32 *pSrc32 = reinterpret_cast<sal_uInt32 *>(pImage);
997                             sal_uInt32 *pDst32 = reinterpret_cast<sal_uInt32 *>(pDst);
998                             for(sal_uInt32 j=0; j<rSourceRect.getWidth(); ++j)
999                                 pDst32[j] = 0xFF000000 | pSrc32[j];
1000 
1001                             pDst += aSurfaceDesc.lPitch;
1002                             pImage += nSourcePitchInBytes;
1003                         }
1004                     }
1005                     break;
1006 
1007 					default:
1008 						ENSURE_OR_RETURN_FALSE(false,
1009                                           "DXSurface::update(): Unknown/unimplemented buffer format" );
1010 						break;
1011 				}
1012 
1013 				rSource.unlock();
1014 			}
1015 
1016 			return SUCCEEDED(mpSurface->Unlock(NULL));
1017 		}
1018 
1019 		//////////////////////////////////////////////////////////////////////////////////
1020 		// DXSurface::getSize
1021 		//////////////////////////////////////////////////////////////////////////////////
1022 
1023 		::basegfx::B2IVector DXSurface::getSize()
1024 		{
1025 			return maSize;
1026 		}
1027 
1028 		//////////////////////////////////////////////////////////////////////////////////
1029 		// DXRenderModule::DXRenderModule
1030 		//////////////////////////////////////////////////////////////////////////////////
1031 
1032 		DXRenderModule::DXRenderModule( const ::Window& rWindow ) :
1033 	        mhWnd(0),
1034             mpWindow(),
1035             maSize(),
1036 			maSelectedFullscreenMode(),
1037 	        maTextureFormat(),
1038             maMonitorInfo(),
1039 	        mpDirectDraw(),
1040 			mpPrimarySurface(),
1041 			mpBackBufferSurface(),
1042 			mpDirect3D(),
1043 			mpDirect3DDevice(),
1044 			maLastUpdate(),
1045 			maDeviceDesc(),
1046             maVertexCache(),
1047 			mnCount(0),
1048 			mnBeginSceneCount(0),
1049 			mbPageFlipping( false ),
1050 			mbHasNoTearingBlt( false ),
1051 			mbError( false ),
1052 			meType( PRIMITIVE_TYPE_UNKNOWN ),
1053 			mpTexture(),
1054 			maPageSize()
1055 		{
1056             // TODO(P2): get rid of those fine-grained locking
1057 			::osl::MutexGuard aGuard( maMutex );
1058 
1059 			if(!(create(rWindow)))
1060 			{
1061 				throw lang::NoSupportException(
1062 					::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
1063                                          "Could not create DirectX device!") ),NULL);
1064 			}
1065 
1066 			// allocate a single texture surface which can be used later.
1067 			// we also use this to calibrate the page size.
1068 			::basegfx::B2IVector aPageSize(
1069 				::std::min(
1070 					static_cast<sal_uInt32>(maDeviceDesc.dwMaxTextureWidth),
1071 					static_cast<sal_uInt32>(MAX_TEXTURE_SIZE)),
1072 				::std::min(
1073 					static_cast<sal_uInt32>(maDeviceDesc.dwMaxTextureHeight),
1074 					static_cast<sal_uInt32>(MAX_TEXTURE_SIZE)));
1075 			while(true)
1076 			{
1077 				mpTexture = ::canvas::ISurfaceSharedPtr(
1078 					new DXSurface(*this,aPageSize));
1079 				if(mpTexture->isValid())
1080 					break;
1081 
1082 				aPageSize.setX(aPageSize.getX()>>1);
1083 				aPageSize.setY(aPageSize.getY()>>1);
1084 				if((aPageSize.getX() < MIN_TEXTURE_SIZE) ||
1085 				   (aPageSize.getY() < MIN_TEXTURE_SIZE))
1086 				{
1087 					throw lang::NoSupportException(
1088 						::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
1089 											"Could not create DirectX device!") ),NULL);
1090 				}
1091 			}
1092 			maPageSize=aPageSize;
1093 		}
1094 
1095 		//////////////////////////////////////////////////////////////////////////////////
1096 		// DXRenderModule::create
1097 		//////////////////////////////////////////////////////////////////////////////////
1098 
1099 		bool DXRenderModule::create( const ::Window& rWindow )
1100 		{
1101             // TODO(P2): get rid of those fine-grained locking
1102 			::osl::MutexGuard aGuard( maMutex );
1103 
1104 			maVertexCache.reserve(1024);
1105 
1106 			mpWindow.reset(
1107 				new SystemChildWindow(
1108 				const_cast<Window *>(&rWindow), 0) );
1109 
1110 			// system child window must not receive mouse events
1111 			mpWindow->SetMouseTransparent( sal_True );
1112 
1113 			// parent should receive paint messages as well
1114 			// [PARENTCLIPMODE_NOCLIP], the argument is here
1115 			// passed as plain numeric value since the stupid
1116 			// define utilizes a USHORT cast.
1117 			mpWindow->SetParentClipMode(0x0002);
1118 
1119 			// the system child window must not clear its background
1120 			mpWindow->EnableEraseBackground( sal_False );
1121 
1122 			mpWindow->SetControlForeground();
1123 			mpWindow->SetControlBackground();
1124 			mpWindow->EnablePaint(sal_False);
1125 
1126 			const SystemEnvData *pData = mpWindow->GetSystemData();
1127 			const HWND hwnd(reinterpret_cast<HWND>(pData->hWnd));
1128 			mhWnd = const_cast<HWND>(hwnd);
1129 
1130 			ENSURE_OR_THROW( IsWindow( reinterpret_cast<HWND>(mhWnd) ),
1131                               "DXRenderModuleDXRenderModuleWin32() No valid HWND given." );
1132 
1133 			// retrieve position and size of the parent window
1134 			const ::Size &rSizePixel(rWindow.GetSizePixel());
1135 
1136 			// remember the size of the parent window, since we
1137 			// need to use this for our child window.
1138 			maSize.setX(static_cast<sal_Int32>(rSizePixel.Width()));
1139 			maSize.setY(static_cast<sal_Int32>(rSizePixel.Height()));
1140 
1141 			// let the child window cover the same size as the parent window.
1142 			mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY());
1143 
1144             MonitorList aMonitorList;
1145             fillMonitorList( aMonitorList );
1146 
1147  			mpDirectDraw = COMReference<IDirectDraw2>(
1148                 createDirectDraw(aMonitorList, maMonitorInfo, mhWnd));
1149 
1150 			if(!mpDirectDraw.is())
1151 				return false;
1152 
1153 			if( !queryCaps() )
1154 			{
1155 				// go defunct, and exit
1156 				VERBOSE_TRACE( "Device::Device(): GetCaps failed" );
1157 				mpDirectDraw.reset();
1158 				return false;
1159 			}
1160 
1161 			if( !validateCaps() )
1162 			{
1163 				// go defunct, and exit
1164 				VERBOSE_TRACE( "Device::Device(): Insufficient DirectX capabilities, failed" );
1165 				mpDirectDraw.reset();
1166 				return false;
1167 			}
1168 
1169 			if( FAILED( mpDirectDraw->SetCooperativeLevel( mhWnd,
1170                                                            DDSCL_NORMAL|DDSCL_MULTITHREADED|DDSCL_FPUPRESERVE ) ) )
1171 			{
1172 				// go defunct, and exit
1173 				VERBOSE_TRACE( "Device::Device(): SetCooperativeLevel failed" );
1174 				mpDirectDraw.reset();
1175 				return false;
1176 			}
1177 
1178 			// setup query struct
1179 			rtl_fillMemory( &maSelectedFullscreenMode.selectedDesc,
1180 							sizeof(DDSURFACEDESC), 0 );
1181 			maSelectedFullscreenMode.selectedDesc.dwSize = sizeof(DDSURFACEDESC);
1182 
1183 			// read current display mode, e.g. for screen dimension
1184 			if( FAILED( mpDirectDraw->GetDisplayMode( &maSelectedFullscreenMode.selectedDesc )) )
1185 			{
1186 				// go defunct, and exit
1187 				VERBOSE_TRACE( "Device::Device(): GetDisplayMode failed" );
1188 				mpDirectDraw.reset();
1189 				return false;
1190 			}
1191 
1192 			// check for supported primary surface formats...
1193 			unsigned int nDisplayFormat = getDisplayFormat() & 0x00000FFF;
1194 			if(nDisplayFormat != 0x888 && nDisplayFormat != 0x565)
1195             {
1196 				// go defunct, and exit
1197 				VERBOSE_TRACE( "Device::Device(): Unsupported DisplayFormat" );
1198 				mpDirectDraw.reset();
1199 				return false;
1200 			}
1201 
1202 			// create primary surface reference
1203 			DDSURFACEDESC 		aSurfaceDesc;
1204 			IDirectDrawSurface* pPrimarySurface;
1205 
1206 			rtl_fillMemory( &aSurfaceDesc,
1207 							sizeof(DDSURFACEDESC), 0 );
1208 			aSurfaceDesc.dwSize = sizeof(aSurfaceDesc);
1209 			aSurfaceDesc.dwFlags = DDSD_CAPS;
1210 			aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE;
1211 
1212 			if( FAILED(mpDirectDraw->CreateSurface(&aSurfaceDesc, &pPrimarySurface, NULL)) )
1213 			{
1214 				// go defunct, and exit
1215 				VERBOSE_TRACE( "Device::Device(): CreateSurface failed" );
1216 				mpDirectDraw.reset();
1217 				return false;
1218 			}
1219 
1220 			mpPrimarySurface = COMReference< IDirectDrawSurface >(pPrimarySurface);
1221 
1222 			// create a Clipper and associate it with the primary surface
1223 			// and the render window
1224 			LPDIRECTDRAWCLIPPER pClipper;
1225 			if( FAILED(mpDirectDraw->CreateClipper( 0, &pClipper, NULL )) )
1226 			{
1227 				// go defunct, and exit
1228 				VERBOSE_TRACE( "Device::Device(): CreateClipper failed" );
1229 				mpPrimarySurface.reset();
1230 				mpDirectDraw.reset();
1231 				return false;
1232 			}
1233 			if( FAILED(pClipper->SetHWnd(0, mhWnd)) )
1234 			{
1235 				// go defunct, and exit
1236 				VERBOSE_TRACE( "Device::Device(): Clipper->SetHWnd failed" );
1237 				pClipper->Release();
1238 				mpPrimarySurface.reset();
1239 				mpDirectDraw.reset();
1240 				return false;
1241 			}
1242 			if( FAILED(mpPrimarySurface->SetClipper( pClipper )) )
1243 			{
1244 				// go defunct, and exit
1245 				VERBOSE_TRACE( "Device::Device(): SetClipper failed" );
1246 				pClipper->Release();
1247 				mpPrimarySurface.reset();
1248 				mpDirectDraw.reset();
1249 				return false;
1250 			}
1251 
1252 			// clipper is now owned by mpPrimarySurface, release our reference
1253 			pClipper->Release();
1254 
1255 			// TODO(F3): Check whether palette needs any setup here
1256 
1257 			// get us a backbuffer for simulated flipping
1258 			IDirectDrawSurface* pSurface;
1259 
1260 			// Strictly speaking, we don't need a full screen worth of
1261 			// backbuffer here. We could also scale dynamically with
1262 			// the current window size, but this will make it
1263 			// necessary to temporarily have two buffers while copying
1264 			// from the old to the new one. What's more, at the time
1265 			// we need a larger buffer, DX might not have sufficient
1266 			// resources available, and we're then left with too small
1267 			// a back buffer, and no way of falling back to a
1268 			// different canvas implementation.
1269 			const ::basegfx::B2ISize aSize( getFramebufferSize() );
1270 
1271 			rtl_fillMemory( &aSurfaceDesc,
1272 							sizeof(DDSURFACEDESC), 0 );
1273 			aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
1274 			aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
1275 			aSurfaceDesc.dwHeight= aSize.getY();
1276 			aSurfaceDesc.dwWidth = aSize.getX();
1277 
1278 			aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
1279 
1280 			HRESULT nRes = mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL);
1281 
1282 			if( FAILED( nRes ) )
1283 			{
1284 				if( nRes == DDERR_OUTOFVIDEOMEMORY )
1285 				{
1286 					// local vid mem failed. Maybe AGP mem works?
1287 					aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM;
1288 					if( FAILED(mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL)) )
1289 					{
1290 						// no chance, go defunct, and exit
1291 						VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer failed" );
1292 						mpPrimarySurface.reset();
1293 						mpDirectDraw.reset();
1294 						return false;
1295 					}
1296 
1297 					VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer reverted to non-local video mem" );
1298 				}
1299 				else
1300 				{
1301 					// no chance, go defunct, and exit
1302 					VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer failed" );
1303 					mpPrimarySurface.reset();
1304 					mpDirectDraw.reset();
1305 					return false;
1306 				}
1307 			}
1308 
1309 			VERBOSE_TRACE( "Device::Device(): created backbuffer of size %d times %d pixel",
1310                            aSurfaceDesc.dwWidth,
1311                            aSurfaceDesc.dwHeight );
1312 
1313 			mpBackBufferSurface = COMReference< IDirectDrawSurface >(pSurface);
1314 			clearSurface(mpBackBufferSurface);
1315 
1316 			if( !setup3DDevice() )
1317 			{
1318 				// go defunct, and exit
1319 				VERBOSE_TRACE( "Device::Device(): setup3DDevice failed" );
1320 				mpBackBufferSurface.reset();
1321 				mpPrimarySurface.reset();
1322 				mpDirectDraw.reset();
1323 				return false;
1324 			}
1325 
1326 			mpWindow->Show();
1327 
1328 			return true;
1329 		}
1330 
1331 		//////////////////////////////////////////////////////////////////////////////////
1332 		// DXRenderModule::getSize
1333 		//////////////////////////////////////////////////////////////////////////////////
1334 
1335 		::basegfx::B2ISize DXRenderModule::getFramebufferSize() const
1336 		{
1337             return mpDirectDraw.is() ?
1338                 ::basegfx::B2ISize( maSelectedFullscreenMode.selectedDesc.dwWidth,
1339                                     maSelectedFullscreenMode.selectedDesc.dwHeight ) :
1340                 ::basegfx::B2ISize();
1341 		}
1342 
1343 		//////////////////////////////////////////////////////////////////////////////////
1344 		// DXRenderModule::setup3DDevice
1345 		//////////////////////////////////////////////////////////////////////////////////
1346 
1347 		bool DXRenderModule::setup3DDevice()
1348 		{
1349 			// create and setup 3D device
1350 			// ==========================
1351 			LPDIRECT3D2	pDirect3D;
1352 			if( FAILED( mpDirectDraw->QueryInterface( IID_IDirect3D2, (LPVOID*)&pDirect3D ) ) )
1353 			{
1354 				// go defunct, and exit
1355 				VERBOSE_TRACE( "Device::setup3DDevice(): QueryInterface() for Direct3D failed" );
1356 				return false;
1357 			}
1358 
1359 			mpDirect3D = COMReference< IDirect3D2 >(pDirect3D);
1360 
1361 			LPDIRECT3DDEVICE2 pDirect3DDevice;
1362 			// try HW-accelerated device first
1363 			if( FAILED(mpDirect3D->CreateDevice( IID_IDirect3DHALDevice,
1364                                                  mpBackBufferSurface.get(),
1365                                                  &pDirect3DDevice )) )
1366 			{
1367 				// no HW 3D support - go defunct, and exit
1368 				VERBOSE_TRACE( "Device::setup3DDevice(): CreateDevice() for HW Direct3D rendering failed" );
1369 				mpDirect3D.reset();
1370 				return false;
1371 			}
1372 
1373 			D3DDEVICEDESC aHELDeviceDesc;
1374 			rtl_fillMemory(&maDeviceDesc,sizeof(maDeviceDesc),0);
1375 			rtl_fillMemory(&aHELDeviceDesc,sizeof(aHELDeviceDesc),0);
1376 			maDeviceDesc.dwSize = sizeof(maDeviceDesc);
1377 			aHELDeviceDesc.dwSize = sizeof(aHELDeviceDesc);
1378 			if(FAILED(pDirect3DDevice->GetCaps(&maDeviceDesc,&aHELDeviceDesc)))
1379             {
1380 				// go defunct, and exit
1381 				VERBOSE_TRACE( "Device::setup3DDevice(): GetCaps() for Direct3DDevice failed" );
1382 				mpDirect3D.reset();
1383 				return false;
1384 			}
1385 
1386 			mpDirect3DDevice = COMReference< IDirect3DDevice2 >(pDirect3DDevice);
1387 
1388 			// select appropriate texture format (_need_ alpha channel here)
1389 			rtl_fillMemory( &maTextureFormat,
1390 							sizeof(DDPIXELFORMAT), 0 );
1391 			maTextureFormat.dwSize = sizeof(DDPIXELFORMAT);
1392 			if( SUCCEEDED(mpDirect3DDevice->EnumTextureFormats( EnumTextureFormatsCallback, &maTextureFormat )) )
1393 			{
1394 				bool bSupportedFormat = true;
1395 				if((maTextureFormat.dwFlags & (DDPF_ALPHAPIXELS | DDPF_RGB)) != (DDPF_ALPHAPIXELS | DDPF_RGB))
1396 					bSupportedFormat = false;
1397 				else if(maTextureFormat.dwRGBAlphaBitMask != 0xFF000000)
1398 					bSupportedFormat = false;
1399 				else if(maTextureFormat.dwRBitMask != 0x00FF0000)
1400 					bSupportedFormat = false;
1401 				else if(maTextureFormat.dwGBitMask != 0x0000FF00)
1402 					bSupportedFormat = false;
1403 				else if(maTextureFormat.dwBBitMask != 0x000000FF)
1404 					bSupportedFormat = false;
1405 
1406 				if(bSupportedFormat)
1407                 {
1408 					VERBOSE_TRACE( "Device::setup3DDevice(): chose texture format dwRGBBitCount %d, dwRBitMask %x, "
1409                                    "dwGBitMask %x, dwBBitMask %x and dwRGBAlphaBitMask %x. The texture uses %s alpha.",
1410                                    maTextureFormat.dwRGBBitCount,
1411                                    maTextureFormat.dwRBitMask,
1412                                    maTextureFormat.dwGBitMask,
1413                                    maTextureFormat.dwBBitMask,
1414                                    maTextureFormat.dwRGBAlphaBitMask,
1415                                    maTextureFormat.dwFlags & DDPF_ALPHAPREMULT ? "premultiplied" : "non-premultiplied" );
1416 
1417 					// setup the device (with as much as we can possibly do here)
1418 					// ==========================================================
1419 
1420 					LPDIRECT3DVIEWPORT2	pViewport;
1421 
1422 					if( SUCCEEDED(mpDirect3D->CreateViewport( &pViewport, NULL )) )
1423 					{
1424 						if( SUCCEEDED(mpDirect3DDevice->AddViewport( pViewport )) )
1425 						{
1426 							// setup viewport (to whole backbuffer)
1427 							D3DVIEWPORT2 aViewport;
1428 
1429 							aViewport.dwSize = sizeof(D3DVIEWPORT2);
1430 							aViewport.dwX = 0;
1431 							aViewport.dwY = 0;
1432 							aViewport.dwWidth = maSelectedFullscreenMode.selectedDesc.dwWidth;
1433 							aViewport.dwHeight = maSelectedFullscreenMode.selectedDesc.dwHeight;
1434 							aViewport.dvClipX = -1.0;
1435 							aViewport.dvClipY =  -1.0;
1436 							aViewport.dvClipWidth  = 2.0;
1437 							aViewport.dvClipHeight = 2.0;
1438 							aViewport.dvMinZ = 0.0;
1439 							aViewport.dvMaxZ = 1.0;
1440 
1441 							if( SUCCEEDED(pViewport->SetViewport2( &aViewport )) )
1442 							{
1443 								if( SUCCEEDED(mpDirect3DDevice->SetCurrentViewport( pViewport )) )
1444 								{
1445 									// Viewport was handed over to 3DDevice, thus we can release now
1446 									pViewport->Release();
1447 
1448 									// currently, no need for any
1449 									// matrix or light source
1450 									// setup, since we only render
1451 									// transformed&lighted
1452 									// vertices
1453 
1454 									// done; successfully
1455 									return true;
1456 								}
1457 								else
1458 								{
1459 									VERBOSE_TRACE( "Device::setup3DDevice(): SetCurrentViewport failed" );
1460 								}
1461 							}
1462 							else
1463 							{
1464 								VERBOSE_TRACE( "Device::setup3DDevice(): SetViewport2 failed" );
1465 							}
1466 						}
1467 						else
1468 						{
1469 							VERBOSE_TRACE( "Device::setup3DDevice(): AddViewport failed" );
1470 						}
1471 
1472 						pViewport->Release();
1473 					}
1474 					else
1475 					{
1476 						VERBOSE_TRACE( "Device::setup3DDevice(): CreateViewport failed" );
1477 					}
1478 				}
1479 				else
1480 				{
1481 					VERBOSE_TRACE( "Device::setup3DDevice(): No supported pixelformat" );
1482 				}
1483 			}
1484 			else
1485 			{
1486 				VERBOSE_TRACE( "Device::setup3DDevice(): EnumTextureFormats failed" );
1487 			}
1488 
1489 			// go defunct, and exit
1490 			mpDirect3DDevice.reset();
1491 			mpDirect3D.reset();
1492 
1493 			return false;
1494 		}
1495 
1496 		//////////////////////////////////////////////////////////////////////////////////
1497 		// DXRenderModule::queryCaps
1498 		//////////////////////////////////////////////////////////////////////////////////
1499 
1500 		bool DXRenderModule::queryCaps()
1501 		{
1502 			DDCAPS	aHWCaps;
1503 			DDCAPS	aHELCaps;
1504 
1505 			rtl_fillMemory( &aHWCaps,
1506 							sizeof(aHWCaps), 0 );
1507 			rtl_fillMemory( &aHELCaps,
1508 							sizeof(aHELCaps), 0 );
1509 			aHWCaps.dwSize = sizeof( aHWCaps );
1510 			aHELCaps.dwSize = sizeof( aHELCaps );
1511 
1512 			if( FAILED( mpDirectDraw->GetCaps( &aHWCaps,
1513 											&aHELCaps ) ) )
1514 			{
1515 				return false;
1516 			}
1517 
1518 			mbHasNoTearingBlt = aHWCaps.dwFXCaps & DDBLTFX_NOTEARING;
1519 
1520 			VERBOSE_TRACE( "dxcanvas initialization: %d bytes VRAM free for surfaces (%d with AGP mem), "
1521                            "%d bytes VRAM free for textures (%d with AGP mem)",
1522                            getAvailableSurfaceMem( false ),
1523                            getAvailableSurfaceMem( true ),
1524                            getAvailableTextureMem( false ),
1525                            getAvailableTextureMem( true ) );
1526 
1527 			return true;
1528 		}
1529 
1530 		//////////////////////////////////////////////////////////////////////////////////
1531 		// DXRenderModule::validateCaps
1532 		//////////////////////////////////////////////////////////////////////////////////
1533 
1534 		bool DXRenderModule::validateCaps()
1535 		{
1536 			// TODO(E3): Validate HW capabilities. Depending on primary
1537 			// surface size, reject HW e.g. on the grounds of insufficient
1538 			// VRAM.
1539 
1540 			// setup query struct
1541 			DDSURFACEDESC desc;
1542 			rtl_fillMemory(&desc,sizeof(DDSURFACEDESC),0);
1543 			desc.dwSize = sizeof(DDSURFACEDESC);
1544 
1545 			// read current display mode, e.g. for screen dimension
1546 			if(FAILED( mpDirectDraw->GetDisplayMode(&desc)))
1547 				return false;
1548 
1549 			// simple heuristic: we need at least 3 times the desktop
1550 			// resolution based on ARGB color values...
1551 			std::size_t nMinimumVRAMSize = ((desc.dwWidth*desc.dwHeight)<<2)*3;
1552 			if(getAvailableSurfaceMem() < nMinimumVRAMSize)
1553 				return false;
1554 
1555 			return true;
1556 		}
1557 
1558 		//////////////////////////////////////////////////////////////////////////////////
1559 		// DXRenderModule::getDisplayFormat
1560 		//////////////////////////////////////////////////////////////////////////////////
1561 
1562 		unsigned int DXRenderModule::getDisplayFormat() const
1563 		{
1564 			unsigned int nFormat;
1565 			nFormat  = ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwRGBAlphaBitMask)<<12;
1566 			nFormat |= ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwRBitMask)<<8;
1567 			nFormat |= ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwGBitMask)<<4;
1568 			nFormat |= ::canvas::tools::bitcount32(maSelectedFullscreenMode.selectedDesc.ddpfPixelFormat.dwBBitMask);
1569 			return nFormat;
1570 		}
1571 
1572 		//////////////////////////////////////////////////////////////////////////////////
1573 		// DXRenderModule::getAvailableSurfaceMem
1574 		//////////////////////////////////////////////////////////////////////////////////
1575 
1576 		std::size_t DXRenderModule::getAvailableSurfaceMem( bool bWithAGPMem ) const
1577 		{
1578 			if( !mpDirectDraw.is() )
1579 				return 0;
1580 
1581 			std::size_t nRes( 0 );
1582 
1583 			DDSCAPS aSurfaceCaps;
1584 			DWORD	nTotal, nFree;
1585 
1586 			// real VRAM (const_cast, since GetAvailableVidMem is non-const)
1587 			aSurfaceCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
1588 			if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) )
1589 				return 0;
1590 
1591 			nRes += nFree;
1592 
1593 			if( bWithAGPMem )
1594 			{
1595 				// AGP RAM (const_cast, since GetAvailableVidMem is non-const)
1596 				aSurfaceCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM;
1597 				if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) )
1598 					return 0;
1599 
1600 				nRes += nFree;
1601 			}
1602 
1603 			return nRes;
1604 		}
1605 
1606 		//////////////////////////////////////////////////////////////////////////////////
1607 		// DXRenderModule::getAvailableTextureMem
1608 		//////////////////////////////////////////////////////////////////////////////////
1609 
1610 		std::size_t DXRenderModule::getAvailableTextureMem( bool bWithAGPMem ) const
1611 		{
1612 			if( !mpDirectDraw.is() )
1613 				return 0;
1614 
1615 			std::size_t nRes( 0 );
1616 
1617 			DDSCAPS aSurfaceCaps;
1618 			DWORD	nTotal, nFree;
1619 
1620 			// TODO(F1): Check if flags are applicable
1621 
1622 			// real VRAM (const_cast, since GetAvailableVidMem is non-const)
1623 			aSurfaceCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
1624 			if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) )
1625 				return 0;
1626 
1627 			nRes += nFree;
1628 
1629 			if( bWithAGPMem )
1630 			{
1631 				// AGP RAM (const_cast, since GetAvailableVidMem is non-const)
1632 				aSurfaceCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM;
1633 				if( FAILED(const_cast<IDirectDraw2&>(*mpDirectDraw).GetAvailableVidMem( &aSurfaceCaps, &nTotal, &nFree )) )
1634 					return 0;
1635 
1636 				nRes += nFree;
1637 			}
1638 
1639 			// TODO(F1): Add pool mem
1640 
1641 			return nRes;
1642 		}
1643 
1644 		//////////////////////////////////////////////////////////////////////////////////
1645 		// DXRenderModule::convert2Screen
1646 		//////////////////////////////////////////////////////////////////////////////////
1647 
1648 		void DXRenderModule::convert2Screen( ::basegfx::B2IPoint& io_rDestPos,
1649 											 ::basegfx::B2IRange& io_rDestArea )
1650 		{
1651 			POINT aPoint = { 0, 0 };
1652 			ClientToScreen( mhWnd, &aPoint );
1653 
1654             // i52230 make sure given screen coordinate is relative to
1655             // this monitor's area (the device rendering is always
1656             // contained to a single monitor)
1657             aPoint.x -= maMonitorInfo.rcMonitor.left;
1658             aPoint.y -= maMonitorInfo.rcMonitor.top;
1659 
1660 			io_rDestPos.setX( io_rDestPos.getX() + aPoint.x );
1661 			io_rDestPos.setY( io_rDestPos.getY() + aPoint.y );
1662 
1663 			const ::basegfx::B2ISize& rSize( getFramebufferSize() );
1664 
1665 			// calc output bounds (clip against framebuffer bounds)
1666 			io_rDestArea = ::basegfx::B2IRange(
1667 				::std::max( sal_Int32(0),
1668 							::std::min( sal_Int32(rSize.getX()),
1669                                         sal_Int32(io_rDestArea.getMinX() + aPoint.x) ) ),
1670 				::std::max( sal_Int32(0),
1671 							::std::min( sal_Int32(rSize.getY()),
1672 										sal_Int32(io_rDestArea.getMinY() + aPoint.y) ) ),
1673 				::std::max( sal_Int32(0),
1674 							::std::min( sal_Int32(rSize.getX()),
1675 										sal_Int32(io_rDestArea.getMaxX() + aPoint.x) ) ),
1676 				::std::max( sal_Int32(0),
1677 							::std::min( sal_Int32(rSize.getY()),
1678 										sal_Int32(io_rDestArea.getMaxY() + aPoint.y) ) ) );
1679 		}
1680 
1681 		//////////////////////////////////////////////////////////////////////////////////
1682 		// DXRenderModule::createSystemMemorySurface
1683 		//////////////////////////////////////////////////////////////////////////////////
1684 
1685 		COMReference<IDirectDrawSurface> DXRenderModule::createSystemMemorySurface( const ::basegfx::B2IVector& rSize )
1686 		{
1687 			DDSURFACEDESC 		aSurfaceDesc;
1688 			IDirectDrawSurface* pSurface;
1689 
1690 			aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
1691 			aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;;
1692 			aSurfaceDesc.dwWidth = rSize.getX();
1693 			aSurfaceDesc.dwHeight= rSize.getY();
1694 
1695 			rtl_copyMemory( &aSurfaceDesc.ddpfPixelFormat, &maTextureFormat, sizeof(DDPIXELFORMAT) );
1696 
1697 			aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
1698 
1699 			HRESULT nRes = mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL);
1700 			if(FAILED(nRes))
1701 				return COMReference<IDirectDrawSurface>(NULL);
1702 
1703 			return COMReference<IDirectDrawSurface>(pSurface);
1704 		}
1705 
1706 		//////////////////////////////////////////////////////////////////////////////////
1707 		// DXRenderModule::flip
1708 		//////////////////////////////////////////////////////////////////////////////////
1709 
1710 		bool DXRenderModule::flip( const ::basegfx::B2IRectangle& rUpdateArea,
1711 								   const ::basegfx::B2IRectangle& rCurrWindowArea )
1712 		{
1713             // TODO(P2): get rid of those fine-grained locking
1714 			::osl::MutexGuard aGuard( maMutex );
1715 
1716 			// see if the main surfaces got lost. if so, try to
1717 			// restore them. bail out if this operation fails.
1718 			if(!(validateMainSurfaces()))
1719 				return false;
1720 
1721 			flushVertexCache();
1722 
1723 			ENSURE_OR_THROW( !mnBeginSceneCount,
1724                               "Device::flip(): within 3D scene" );
1725 
1726 			// TODO(E3): handle DX errors more thoroughly. For fullscreen
1727 			// exclusive mode, actually even our primary surface can get
1728 			// lost and needs restore!
1729 
1730 			if( mpDirectDraw.is() &&
1731 				mpPrimarySurface.is() &&
1732 				mpBackBufferSurface.is() )
1733 			{
1734 				// ignore area and offset for page flipping device
1735 				if( mbPageFlipping )
1736 				{
1737 #if defined(VERBOSE) && defined(DBG_UTIL)
1738 					renderFPSCounter();
1739 					renderMemAvailable();
1740 #endif
1741 					VERBOSE_TRACE( "Device::flip(): Using true page flipping" );
1742 
1743 					// use true page flipping. Hopefully, the 3D hardware
1744 					// is flushed on this flip call (rumours have it that
1745 					// way), otherwise, perform the Lock hack as for the
1746 					// Blt below.
1747 					if( SUCCEEDED(mpPrimarySurface->Flip( NULL, DDFLIP_WAIT )) )
1748 						return true;
1749 				}
1750 				else
1751 				{
1752 					VERBOSE_TRACE( "Device::flip(): Using blt for page flipping" );
1753 
1754 					// determine actual window position
1755 					::basegfx::B2IPoint aDestPoint( rUpdateArea.getMinimum() );
1756 					::basegfx::B2IRange aSourceArea( rUpdateArea );
1757 					::basegfx::B2IRange aDestArea( 0,0,
1758                                                    static_cast<sal_Int32>(rCurrWindowArea.getWidth()),
1759                                                    static_cast<sal_Int32>(rCurrWindowArea.getHeight()) );
1760 					convert2Screen( aDestPoint, aDestArea );
1761 
1762 					// perform clipping
1763 					if( !::canvas::tools::clipBlit( aSourceArea,
1764 													aDestPoint,
1765 													rUpdateArea,
1766 													aDestArea ) )
1767 						return true; // fully clipped, but still, in a way,
1768 									 // successful.
1769 
1770 					// TODO(P1): Rumours have it that the 3D hardware
1771 					// _might_ still be rendering with flaky drivers,
1772 					// which don't flush properly on Blt(). It was said,
1773 					// that 'usually', it works to lock the 3D render
1774 					// target (the backbuffer in this case). OTOH, I've
1775 					// found that this tends to degrade performance
1776 					// significantly on complying cards...
1777 
1778 					// TODO(P1): Up until rev. 1.3, this method contained
1779 					// code to make sure the blit will start _immediately_
1780 					// after the Blt call. If this is not warranted, wait
1781 					// for the next vsync. As this case was found to be
1782 					// extremely seldom, kicked out (what's more, there's
1783 					// simply no guarantee that the blitter will be
1784 					// available at any point in the code - Windows still
1785 					// is a preemptive multi-processing environment. And
1786 					// _if_ we're competing with someone over the blitter,
1787 					// we will do so the next VBLANK interval, and the
1788 					// following...)
1789 
1790                     // screen update seems to be smoother when waiting
1791                     // for vblank in every case - even when blitter
1792                     // supports the DDBLTFX_NOTEARING flag.
1793                     if( FAILED(mpDirectDraw->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,
1794                                                                   NULL)) )
1795                         return false;
1796 
1797 					DDBLTFX  aBltFx;
1798 					DDBLTFX* pBltFX = NULL;
1799 					if( mbHasNoTearingBlt )
1800 					{
1801 						// Blt can internally schedule for no-tearing
1802 						// ===========================================
1803 
1804 						rtl_fillMemory( &aBltFx,
1805 										sizeof(aBltFx), 0 );
1806 						aBltFx.dwSize = sizeof(aBltFx);
1807 						aBltFx.dwDDFX = DDBLTFX_NOTEARING;
1808 
1809 						pBltFX = &aBltFx;
1810 					}
1811 
1812 					if( doBlit( aDestPoint,
1813                                 *mpPrimarySurface,
1814                                 aSourceArea,
1815                                 *mpBackBufferSurface,
1816                                 pBltFX,false ) )
1817 					{
1818 #if defined(VERBOSE) && defined(DBG_UTIL)
1819 						renderFPSCounter();
1820 						renderMemAvailable();
1821 #endif
1822 						return true;
1823 					}
1824 				}
1825 			}
1826 			return false;
1827 		}
1828 
1829 		//////////////////////////////////////////////////////////////////////////////////
1830 		// DXRenderModule::disposing
1831 		//////////////////////////////////////////////////////////////////////////////////
1832 
1833 		void DXRenderModule::disposing()
1834 		{
1835 			if(!(mhWnd))
1836 				return;
1837 
1838 			mpTexture.reset();
1839 			mpWindow.reset();
1840 			mhWnd=NULL;
1841 
1842             // refrain from releasing the DX5 objects - deleting the
1843             // DX5 device seems to kill the whole engine, including
1844             // all objects we might still hold references to
1845             // (surfaces, e.g.)
1846 		}
1847 
1848 		//////////////////////////////////////////////////////////////////////////////////
1849 		// DXRenderModule::screenshot
1850 		//////////////////////////////////////////////////////////////////////////////////
1851 
1852 		void DXRenderModule::screenShot()
1853 		{
1854 			if(!(mpBackBufferSurface.get()))
1855 				return;
1856 			char filename[256];
1857 			static sal_uInt32 counter = 0;
1858 			sprintf(filename,"c:\\shot%d.bmp",counter++);
1859 			dumpSurface(mpBackBufferSurface,filename);
1860 		}
1861 
1862 		//////////////////////////////////////////////////////////////////////////////////
1863 		// DXRenderModule::validateMainSurfaces
1864 		//////////////////////////////////////////////////////////////////////////////////
1865 
1866 		bool DXRenderModule::validateMainSurfaces()
1867 		{
1868 			if(mpPrimarySurface.get()) {
1869 				if(mpPrimarySurface->IsLost() == DDERR_SURFACELOST) {
1870 					if(FAILED(mpPrimarySurface->Restore()))
1871 						return false;
1872 				}
1873 			}
1874 
1875 			if(mpBackBufferSurface.get()) {
1876 				if(mpBackBufferSurface->IsLost() == DDERR_SURFACELOST)
1877                 {
1878 					// TODO(F1): simply restoring the backbuffer does not
1879 					// work as expected, we need to re-create everything
1880 					// from scratch. find out why...
1881 					//if(SUCCEEDED(mpBackBufferSurface->Restore()))
1882 					//	return setup3DDevice();
1883 
1884 					mpBackBufferSurface.reset();
1885 
1886 					// get us a backbuffer for simulated flipping
1887 					IDirectDrawSurface* pSurface;
1888 
1889 					// TODO(P2): Strictly speaking, we don't need a full screen worth of
1890 					// backbuffer here. We could also scale dynamically with the current
1891 					// window size, but this will make it necessary to temporarily have two
1892 					// buffers while copying from the old to the new one. YMMV.
1893 					const ::basegfx::B2ISize aSize( getFramebufferSize() );
1894 
1895 					DDSURFACEDESC aSurfaceDesc;
1896 					rtl_fillMemory( &aSurfaceDesc, sizeof(DDSURFACEDESC), 0 );
1897 					aSurfaceDesc.dwSize = sizeof(DDSURFACEDESC);
1898 					aSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
1899 					aSurfaceDesc.dwHeight= aSize.getY();
1900 					aSurfaceDesc.dwWidth = aSize.getX();
1901 
1902 					aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
1903 
1904 					HRESULT nRes = mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL);
1905 
1906 					if( FAILED( nRes ) )
1907 					{
1908 						if( nRes == DDERR_OUTOFVIDEOMEMORY )
1909 						{
1910 							// local vid mem failed. Maybe AGP mem works?
1911 							aSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM;
1912 							if( FAILED(mpDirectDraw->CreateSurface(&aSurfaceDesc, &pSurface, NULL)) )
1913 							{
1914 								// no chance
1915 								return false;
1916 							}
1917 
1918 							VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer reverted to non-local video mem" );
1919 						}
1920 						else
1921 						{
1922 							// no chance
1923 							VERBOSE_TRACE( "Device::Device(): CreateSurface for backbuffer failed" );
1924 							return false;
1925 						}
1926 					}
1927 
1928 					VERBOSE_TRACE( "Device::Device(): created backbuffer of size %d times %d pixel",
1929                                    aSurfaceDesc.dwWidth,
1930                                    aSurfaceDesc.dwHeight );
1931 
1932 					mpBackBufferSurface = COMReference< IDirectDrawSurface >(pSurface);
1933 
1934 					return setup3DDevice();
1935 				}
1936 			}
1937 
1938 			return true;
1939 		}
1940 
1941         void DXRenderModule::renderInfoText( const ::rtl::OUString& rStr,
1942                                              const Gdiplus::PointF& rPos ) const
1943         {
1944             ENSURE_OR_THROW( !mnBeginSceneCount,
1945                               "Device::renderInfoText(): within 3D scene" );
1946 
1947             // render text directly to primary surface
1948             GraphicsSharedPtr pGraphics;
1949 
1950             if( mbPageFlipping )
1951             {
1952                 // render on top of backbuffer. We have
1953                 // page flipping, anyway, thus this will
1954                 // cost us nothing.
1955                 pGraphics = createSurfaceGraphics( mpBackBufferSurface );
1956             }
1957             else
1958             {
1959                 // render FPS directly to front buffer.
1960                 // That saves us another explicit blit,
1961                 // and for me, the FPS counter can blink,
1962                 // if it likes to...
1963                 pGraphics = createSurfaceGraphics( mpPrimarySurface );
1964             }
1965 
1966             if( !mbPageFlipping )
1967             {
1968                 // clear background. We might be doing optimized redraws,
1969                 // and the background under the FPS count will then not be
1970                 // cleared.
1971                 Gdiplus::SolidBrush aBrush(
1972                     Gdiplus::Color( 255, 255, 255 ) );
1973 
1974                 pGraphics->FillRectangle( &aBrush,
1975                                           rPos.X, rPos.Y, 80.0, 20.0 );
1976             }
1977 
1978             Gdiplus::SolidBrush aBrush(
1979                 Gdiplus::Color( 255, 0, 255 ) );
1980             Gdiplus::Font aFont( NULL,
1981                                  16,
1982                                  Gdiplus::FontStyleRegular,
1983                                  Gdiplus::UnitWorld,
1984                                  NULL );
1985             pGraphics->DrawString( reinterpret_cast<LPCWSTR>(rStr.getStr()),
1986                                    rStr.getLength(),
1987                                    &aFont,
1988                                    rPos,
1989                                    &aBrush );
1990         }
1991 
1992 		//////////////////////////////////////////////////////////////////////////////////
1993 		// DXRenderModule::renderMemAvailable
1994 		//////////////////////////////////////////////////////////////////////////////////
1995 
1996 		void DXRenderModule::renderMemAvailable() const
1997 		{
1998 			ENSURE_OR_THROW( !mnBeginSceneCount,
1999                               "DXRenderModule::renderMemAvailable(): within 3D scene" );
2000 
2001 			const double nSurfaceMem( getAvailableSurfaceMem()/1024 );
2002 
2003 			::rtl::OUString text( ::rtl::math::doubleToUString( nSurfaceMem,
2004 																rtl_math_StringFormat_F,
2005 																2,'.',NULL,' ') );
2006 
2007 			// pad with leading space
2008 			while( text.getLength() < 6 )
2009 				text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text;
2010 
2011 			text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("S: ")) + text;
2012 
2013 			renderInfoText( text,
2014 							Gdiplus::PointF( 0.0, 20) );
2015 
2016 
2017 			const double nTexMem( getAvailableTextureMem()/1024 );
2018 
2019 			text = ::rtl::math::doubleToUString( nTexMem,
2020 												rtl_math_StringFormat_F,
2021 												2,'.',NULL,' ');
2022 			// pad with leading space
2023 			while( text.getLength() < 6 )
2024 				text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text;
2025 
2026 			text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("T: ")) + text;
2027 
2028 			renderInfoText( text,
2029 							Gdiplus::PointF( 0.0, 40) );
2030 
2031 			VERBOSE_TRACE( "dxcanvas: %f free surface mem, %f free texture mem",
2032                            nSurfaceMem, nTexMem );
2033 		}
2034 
2035 		//////////////////////////////////////////////////////////////////////////////////
2036 		// DXRenderModule::renderFPSCounter
2037 		//////////////////////////////////////////////////////////////////////////////////
2038 
2039 		void DXRenderModule::renderFPSCounter() const
2040 		{
2041 			ENSURE_OR_THROW( !mnBeginSceneCount,
2042                               "DXRenderModule::ren    derFPSCounter(): within 3D scene" );
2043 
2044 			const double denominator( maLastUpdate.getElapsedTime() );
2045 			maLastUpdate.reset();
2046 
2047 			::rtl::OUString text( ::rtl::math::doubleToUString( denominator == 0.0 ? 100.0 : 1.0/denominator,
2048 																rtl_math_StringFormat_F,
2049 																2,'.',NULL,' ') );
2050 
2051 			// pad with leading space
2052 			while( text.getLength() < 6 )
2053 				text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text;
2054 
2055 			text += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" fps"));
2056 
2057 			renderInfoText( text,
2058 							Gdiplus::PointF() );
2059 
2060 			VERBOSE_TRACE( "dxcanvas: %f FPS",
2061                            denominator == 0.0 ? 100.0 : 1.0/denominator );
2062 		}
2063 
2064 		//////////////////////////////////////////////////////////////////////////////////
2065 		// DXRenderModule::resize
2066 		//////////////////////////////////////////////////////////////////////////////////
2067 
2068 		void DXRenderModule::resize( const ::basegfx::B2IRange& rect )
2069 		{
2070             // TODO(P2): get rid of those fine-grained locking
2071 			::osl::MutexGuard aGuard( maMutex );
2072 
2073 			if( mhWnd==0 )
2074 				return;
2075 
2076 			// don't do anything if the size didn't change.
2077 			if(maSize.getX() == static_cast<sal_Int32>(rect.getWidth()) &&
2078 			   maSize.getY() == static_cast<sal_Int32>(rect.getHeight()))
2079 			   return;
2080 
2081 			// TODO(Q2): use numeric cast to prevent overflow
2082 			maSize.setX(static_cast<sal_Int32>(rect.getWidth()));
2083 			maSize.setY(static_cast<sal_Int32>(rect.getHeight()));
2084 
2085 			mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY());
2086 		}
2087 
2088 		//////////////////////////////////////////////////////////////////////////////////
2089 		// DXRenderModule::getPageSize
2090 		//////////////////////////////////////////////////////////////////////////////////
2091 
2092 		::basegfx::B2IVector DXRenderModule::getPageSize()
2093 		{
2094             // TODO(P2): get rid of those fine-grained locking
2095 			::osl::MutexGuard aGuard( maMutex );
2096 			return maPageSize;
2097 		}
2098 
2099 		::canvas::ISurfaceSharedPtr DXRenderModule::createSurface( const ::basegfx::B2IVector& surfaceSize )
2100 		{
2101             // TODO(P2): get rid of those fine-grained locking
2102 			::osl::MutexGuard aGuard( maMutex );
2103 
2104 			const ::basegfx::B2IVector& rPageSize( getPageSize() );
2105 			::basegfx::B2ISize aSize(surfaceSize);
2106 			if(!(aSize.getX()))
2107 				aSize.setX(rPageSize.getX());
2108 			if(!(aSize.getY()))
2109 				aSize.setY(rPageSize.getY());
2110 
2111 			if(mpTexture.use_count() == 1)
2112 				return mpTexture;
2113 
2114 			return ::canvas::ISurfaceSharedPtr(
2115 				new DXSurface(*this,
2116                               aSize) );
2117 		}
2118 
2119 		void DXRenderModule::beginPrimitive( PrimitiveType eType )
2120 		{
2121             // TODO(P2): get rid of those fine-grained locking
2122 			::osl::MutexGuard aGuard( maMutex );
2123 
2124 			ENSURE_OR_THROW( !mnBeginSceneCount,
2125                               "DXRenderModule::beginPrimitive(): nested call" );
2126 
2127 			++mnBeginSceneCount;
2128 			meType=eType;
2129 			mnCount=0;
2130 		}
2131 
2132 		void DXRenderModule::endPrimitive()
2133 		{
2134             // TODO(P2): get rid of those fine-grained locking
2135 			::osl::MutexGuard aGuard( maMutex );
2136 
2137 			--mnBeginSceneCount;
2138 			meType=PRIMITIVE_TYPE_UNKNOWN;
2139 			mnCount=0;
2140 		}
2141 
2142 		void DXRenderModule::pushVertex( const ::canvas::Vertex& vertex )
2143 		{
2144             // TODO(P2): get rid of those fine-grained locking
2145 			::osl::MutexGuard aGuard( maMutex );
2146 
2147 			switch(meType)
2148 			{
2149 				case PRIMITIVE_TYPE_TRIANGLE:
2150                 {
2151 					maVertexCache.push_back(vertex);
2152 					++mnCount;
2153 					mnCount &= 3;
2154 					break;
2155                 }
2156 
2157 				case PRIMITIVE_TYPE_QUAD:
2158                 {
2159 					if(mnCount == 3)
2160 					{
2161 						const std::size_t size(maVertexCache.size());
2162 						::canvas::Vertex v0(maVertexCache[size-1]);
2163 						::canvas::Vertex v2(maVertexCache[size-3]);
2164 						maVertexCache.push_back(v0);
2165 						maVertexCache.push_back(vertex);
2166 						maVertexCache.push_back(v2);
2167 						mnCount=0;
2168 					}
2169 					else
2170 					{
2171 						maVertexCache.push_back(vertex);
2172 						++mnCount;
2173 					}
2174 					break;
2175                 }
2176 
2177                 default:
2178                     OSL_ENSURE( false,
2179                                 "DXRenderModule::pushVertex(): unexpected primitive types" );
2180                     break;
2181 			}
2182 		}
2183 
2184 		bool DXRenderModule::isError()
2185 		{
2186             // TODO(P2): get rid of those fine-grained locking
2187 			::osl::MutexGuard aGuard( maMutex );
2188 
2189 			return mbError;
2190 		}
2191 
2192 		void DXRenderModule::flushVertexCache()
2193 		{
2194 			if(!(maVertexCache.size()))
2195 				return;
2196 
2197 			mbError=true;
2198 
2199 			if( FAILED(mpDirect3DDevice->BeginScene()) )
2200 				return;
2201 
2202 			// enable texture alpha blending
2203 			if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE)))
2204 				return;
2205 
2206 			// enable texture alpha modulation, for honoring fAlpha
2207 			if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND,
2208 														D3DTBLEND_MODULATEALPHA)) )
2209 				return;
2210 
2211 			// enable texture magnification filtering (don't care if this
2212 			// fails, it's just visually more pleasant)
2213 			mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMAG,
2214                                              D3DFILTER_LINEAR);
2215 
2216 			// enable texture minification filtering (don't care if this
2217 			// fails, it's just visually more pleasant)
2218 			mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREMIN,
2219                                              D3DFILTER_LINEAR);
2220 
2221 			// enable subpixel texture output (don't care if this
2222 			// fails, it's just visually more pleasant)
2223  			mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_SUBPIXEL,
2224                                              TRUE);
2225 
2226 			// normal combination of object...
2227 			if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND,
2228 														D3DBLEND_SRCALPHA)) )
2229 				return;
2230 
2231 			// ..and background color
2232 			if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND,
2233 														D3DBLEND_INVSRCALPHA)) )
2234 				return;
2235 
2236 			// disable backface culling; this enables us to mirror sprites
2237 			// by simply reverting the triangles, which, with enabled
2238 			// culling, would be invisible otherwise
2239 			if( FAILED(mpDirect3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE,
2240 														D3DCULL_NONE)) )
2241 				return;
2242 
2243 			mbError=false;
2244 
2245  			const float nHalfPixelSizeX(0.5f/maPageSize.getX());
2246  			const float nHalfPixelSizeY(0.5f/maPageSize.getY());
2247 			sal_uInt32 nIndex(0);
2248 			const std::size_t size(maVertexCache.size());
2249             D3DTLVERTEX *vertices = static_cast<D3DTLVERTEX *>(_alloca(sizeof(D3DTLVERTEX)*size));
2250 			vertexCache_t::const_iterator it(maVertexCache.begin());
2251 			while(it != maVertexCache.end())
2252 			{
2253 				vertices[nIndex++] = D3DTLVERTEX(
2254 					D3DVECTOR(static_cast<D3DVALUE>(it->x),
2255 							  static_cast<D3DVALUE>(it->y),
2256 							  static_cast<D3DVALUE>(it->z)),
2257 					1,
2258 					D3DRGBA(1,1,1,it->a),
2259 					D3DRGBA(0,0,0,0),
2260 					static_cast<float>(it->u + nHalfPixelSizeX),
2261 					static_cast<float>(it->v + nHalfPixelSizeY));
2262 				++it;
2263 			}
2264 
2265 			maVertexCache.clear();
2266 
2267 			mbError |= FAILED(mpDirect3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
2268 															  D3DVT_TLVERTEX,
2269 															  (LPVOID)vertices,
2270 															  size,
2271 															  0));
2272 
2273 			mbError |= FAILED(mpDirect3DDevice->EndScene());
2274 		}
2275 	}
2276 
2277 	IDXRenderModuleSharedPtr createRenderModule( const ::Window& rParent )
2278 	{
2279 		return IDXRenderModuleSharedPtr( new DXRenderModule(rParent) );
2280 	}
2281 }
2282 
2283 #endif
2284