xref: /trunk/main/canvas/source/directx/dx_5rm.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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