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