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