xref: /trunk/main/canvas/source/directx/dx_9rm.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 #define MAX_TEXTURE_SIZE (2048)
30 #define MIN_TEXTURE_SIZE (32)
31 //#define FAKE_MAX_NUMBER_TEXTURES (2)
32 //#define FAKE_MAX_TEXTURE_SIZE (4096)
33 
34 #define VERTEX_BUFFER_SIZE (341*3) // 1023, the size of the internal
35                                    // vertex buffer (must be divisable
36                                    // by 3, as each triangle primitive
37                                    // has 3 vertices)
38 
39 
40 //////////////////////////////////////////////////////////////////////////////////
41 // includes
42 //////////////////////////////////////////////////////////////////////////////////
43 #include <vcl/syschild.hxx>
44 #include <vcl/window.hxx>
45 
46 #include <canvas/debug.hxx>
47 #include <canvas/verbosetrace.hxx>
48 #include <tools/diagnose_ex.h>
49 
50 #include <canvas/elapsedtime.hxx>
51 #include <canvas/canvastools.hxx>
52 #include <canvas/rendering/icolorbuffer.hxx>
53 #include <canvas/rendering/isurface.hxx>
54 #include <canvas/rendering/irendermodule.hxx>
55 #include <basegfx/numeric/ftools.hxx>
56 #include <basegfx/vector/b2dsize.hxx>
57 #include <basegfx/vector/b2isize.hxx>
58 #include <basegfx/point/b2ipoint.hxx>
59 #include <basegfx/range/b2irectangle.hxx>
60 #include <boost/scoped_ptr.hpp>
61 #include <com/sun/star/lang/NoSupportException.hpp>
62 
63 #include "dx_rendermodule.hxx"
64 #include "dx_config.hxx"
65 
66 #undef WB_LEFT
67 #undef WB_RIGHT
68 
69 #include "dx_impltools.hxx"
70 #include <vcl/sysdata.hxx>
71 
72 #if defined(DX_DEBUG_IMAGES)
73 # if OSL_DEBUG_LEVEL > 0
74 #  include <imdebug.h>
75 #  undef min
76 #  undef max
77 # endif
78 #endif
79 
80 using namespace ::com::sun::star;
81 
82 //////////////////////////////////////////////////////////////////////////////////
83 // 'dxcanvas' namespace
84 //////////////////////////////////////////////////////////////////////////////////
85 
86 namespace dxcanvas
87 {
88 	namespace
89 	{
90         //////////////////////////////////////////////////////////////////////////////////
91         // monitorSupport
92         //////////////////////////////////////////////////////////////////////////////////
93 
94         class monitorSupport
95         {
96         public:
97 
monitorSupport()98             monitorSupport() :
99                 mhLibrary(LoadLibrary("user32.dll")),
100                 mpMonitorFromWindow(NULL)
101             {
102                 if(mhLibrary)
103                     mpMonitorFromWindow = reinterpret_cast<fMonitorFromWindow>(
104                         GetProcAddress(
105                             mhLibrary,"MonitorFromWindow"));
106             }
107 
~monitorSupport()108             ~monitorSupport()
109             {
110                 if(mhLibrary)
111                     FreeLibrary(mhLibrary);
112                 mhLibrary=0;
113             }
114 
MonitorFromWindow(HWND hwnd)115             HMONITOR MonitorFromWindow( HWND hwnd )
116             {
117                 // return adapter_default in case something went wrong...
118                 if(!(mpMonitorFromWindow))
119                     return HMONITOR(0);
120                 // MONITOR_DEFAULTTONEAREST
121                 const DWORD dwFlags(0x00000002);
122                 return mpMonitorFromWindow(hwnd,dwFlags);
123             }
124         private:
125 
126             HINSTANCE mhLibrary;
127             typedef HMONITOR (WINAPI *fMonitorFromWindow )( HWND hwnd, DWORD dwFlags );
128             fMonitorFromWindow mpMonitorFromWindow;
129         };
130 
131         monitorSupport aMonitorSupport;
132 
133 
134 		class DXRenderModule;
135 
136 		//////////////////////////////////////////////////////////////////////////////////
137 		// DXSurface
138 		//////////////////////////////////////////////////////////////////////////////////
139 
140 		/** ISurface implemenation.
141 
142 			@attention holds the DXRenderModule via non-refcounted
143 			reference! This is safe with current state of affairs, since
144 			the canvas::PageManager holds surface and render module via
145 			shared_ptr (and makes sure all surfaces are deleted before its
146 			render module member goes out of scope).
147 		*/
148 		class DXSurface : public canvas::ISurface
149 		{
150 		public:
151 			DXSurface( DXRenderModule&           rRenderModule,
152                        const ::basegfx::B2ISize& rSize );
153 			~DXSurface();
154 
155 			virtual bool selectTexture();
156 			virtual bool isValid();
157 			virtual bool update( const ::basegfx::B2IPoint& rDestPos,
158 								const ::basegfx::B2IRange& rSourceRect,
159 								::canvas::IColorBuffer&    rSource );
160 			virtual ::basegfx::B2IVector getSize();
161 			COMReference<IDirect3DTexture9> getTexture() const;
162 
163 		private:
164 			/// Guard local methods against concurrent access to RenderModule
165 			class ImplRenderModuleGuard : private ::boost::noncopyable
166 			{
167 			public:
168 				explicit inline ImplRenderModuleGuard( DXRenderModule& rRenderModule );
169 				inline ~ImplRenderModuleGuard();
170 
171 			private:
172 				DXRenderModule& mrRenderModule;
173 			};
174 
175 			DXRenderModule&                  mrRenderModule;
176 			COMReference<IDirect3DTexture9>  mpTexture;
177 
178 			::basegfx::B2IVector             maSize;
179 		};
180 
181 
182 		//////////////////////////////////////////////////////////////////////////////////
183 		// DXRenderModule
184 		//////////////////////////////////////////////////////////////////////////////////
185 
186 		/// Default implementation of IDXRenderModule
187 		class DXRenderModule : public IDXRenderModule
188 		{
189         public:
190             explicit DXRenderModule( const ::Window& rWindow );
191 			~DXRenderModule();
192 
lock() const193             virtual void lock() const { maMutex.acquire(); }
unlock() const194             virtual void unlock() const { maMutex.release(); }
195 
196             virtual COMReference<IDirect3DSurface9>
197                 createSystemMemorySurface( const ::basegfx::B2IVector& rSize );
198 			virtual void disposing();
getHWND() const199 			virtual HWND getHWND() const { return mhWnd; }
200 			virtual void screenShot();
201 
202             virtual bool flip( const ::basegfx::B2IRectangle& rUpdateArea,
203                                const ::basegfx::B2IRectangle& rCurrWindowArea );
204 
205             virtual void resize( const ::basegfx::B2IRange& rect );
206             virtual ::basegfx::B2IVector getPageSize();
207             virtual ::canvas::ISurfaceSharedPtr createSurface( const ::basegfx::B2IVector& surfaceSize );
208             virtual void beginPrimitive( PrimitiveType eType );
209             virtual void endPrimitive();
210             virtual void pushVertex( const ::canvas::Vertex& vertex );
211             virtual bool isError();
212 
getDevice()213             COMReference<IDirect3DDevice9> getDevice() { return mpDevice; }
214 
215             void flushVertexCache();
216 			void commitVertexCache();
217 
218         private:
219 
220             bool create( const ::Window& rWindow );
221 			bool createDevice();
222             bool verifyDevice( const UINT nAdapter );
223 			UINT getAdapterFromWindow();
224 
225             /** This object represents the DirectX state machine.  In order
226                 to serialize access to DirectX's global state, a global
227                 mutex is required.
228             */
229             static ::osl::Mutex                         maMutex;
230 
231             HWND                                        mhWnd;
232             COMReference<IDirect3DDevice9>              mpDevice;
233             COMReference<IDirect3D9>                    mpDirect3D9;
234             COMReference<IDirect3DSwapChain9>           mpSwapChain;
235             COMReference<IDirect3DVertexBuffer9>        mpVertexBuffer;
236             ::canvas::ISurfaceSharedPtr                 mpTexture;
237             ::boost::scoped_ptr<SystemChildWindow>      mpWindow;
238             ::basegfx::B2IVector                        maSize;
239             typedef std::vector<canvas::Vertex>         vertexCache_t;
240             vertexCache_t                               maVertexCache;
241             std::size_t                                 mnCount;
242             int                                         mnBeginSceneCount;
243             bool                                        mbCanUseDynamicTextures;
244             bool                                        mbError;
245             PrimitiveType                               meType;
246             ::basegfx::B2IVector                        maPageSize;
247             D3DPRESENT_PARAMETERS                       mad3dpp;
248 
isDisposed() const249 			inline bool isDisposed() const { return (mhWnd==NULL); }
250 
251 			struct dxvertex
252 			{
253 				float x,y,z,rhw;
254 				DWORD diffuse;
255 				float u,v;
256 			};
257 
258 			std::size_t									maNumVertices;
259 			std::size_t                                 maWriteIndex;
260 			std::size_t                                 maReadIndex;
261 		};
262 
263 		::osl::Mutex DXRenderModule::maMutex;
264 
265 		//////////////////////////////////////////////////////////////////////////////////
266 		// DXSurface::ImplRenderModuleGuard
267 		//////////////////////////////////////////////////////////////////////////////////
268 
ImplRenderModuleGuard(DXRenderModule & rRenderModule)269 		inline DXSurface::ImplRenderModuleGuard::ImplRenderModuleGuard(
270 			DXRenderModule& rRenderModule ) :
271 			mrRenderModule( rRenderModule )
272 		{
273 			mrRenderModule.lock();
274 		}
275 
~ImplRenderModuleGuard()276 		inline DXSurface::ImplRenderModuleGuard::~ImplRenderModuleGuard()
277 		{
278 			mrRenderModule.unlock();
279 		}
280 
281 #ifdef FAKE_MAX_NUMBER_TEXTURES
282 		static sal_uInt32 gNumSurfaces = 0;
283 #endif
284 
fillRect(sal_uInt32 * pDest,sal_uInt32 dwWidth,sal_uInt32 dwHeight,sal_uInt32 dwPitch,sal_uInt32 dwColor)285         void fillRect( sal_uInt32 *pDest,
286                        sal_uInt32 dwWidth,
287                        sal_uInt32 dwHeight,
288                        sal_uInt32 dwPitch,
289                        sal_uInt32 dwColor )
290         {
291             for(sal_uInt32 i=0; i<dwWidth; ++i)
292             {
293                 pDest[i]=dwColor;
294                 pDest[((dwHeight-1)*dwPitch)+i]=dwColor;
295             }
296 
297             for(sal_uInt32 j=0; j<dwHeight; ++j)
298             {
299                 pDest[0]=dwColor;
300                 pDest[dwWidth-1]=dwColor;
301                 pDest += dwPitch;
302             }
303         }
304 
305 		//////////////////////////////////////////////////////////////////////////////////
306 		// DXSurface::DXSurface
307 		//////////////////////////////////////////////////////////////////////////////////
308 
DXSurface(DXRenderModule & rRenderModule,const::basegfx::B2ISize & rSize)309 		DXSurface::DXSurface( DXRenderModule&           rRenderModule,
310 							  const ::basegfx::B2ISize& rSize ) :
311             mrRenderModule(rRenderModule),
312             mpTexture(NULL),
313 			maSize()
314 		{
315 			ImplRenderModuleGuard aGuard( mrRenderModule );
316 
317 #ifdef FAKE_MAX_NUMBER_TEXTURES
318 			++gNumSurfaces;
319 			if(gNumSurfaces >= FAKE_MAX_NUMBER_TEXTURES)
320 				return;
321 #endif
322 
323 #ifdef FAKE_MAX_TEXTURE_SIZE
324 			if(rSize.getX() > FAKE_MAX_TEXTURE_SIZE)
325 				return;
326 			if(rSize.getY() > FAKE_MAX_TEXTURE_SIZE)
327 				return;
328 #endif
329 
330 			ENSURE_ARG_OR_THROW(rSize.getX() > 0 && rSize.getY() > 0,
331 							"DXSurface::DXSurface(): request for zero-sized surface");
332 
333 			COMReference<IDirect3DDevice9> pDevice(rRenderModule.getDevice());
334 
335 			IDirect3DTexture9 *pTexture(NULL);
336 			if(FAILED(pDevice->CreateTexture(
337 				rSize.getX(),
338 				rSize.getY(),
339 				1,0,D3DFMT_A8R8G8B8,
340 				D3DPOOL_MANAGED,
341 				&pTexture,NULL)))
342 				return;
343 
344 			mpTexture=COMReference<IDirect3DTexture9>(pTexture);
345             maSize = rSize;
346 		}
347 
348 		//////////////////////////////////////////////////////////////////////////////////
349 		// DXSurface::~DXSurface
350 		//////////////////////////////////////////////////////////////////////////////////
351 
~DXSurface()352 		DXSurface::~DXSurface()
353 		{
354 			ImplRenderModuleGuard aGuard( mrRenderModule );
355 
356 #ifdef FAKE_MAX_NUMBER_TEXTURES
357 			gNumSurfaces--;
358 #endif
359 		}
360 
361 		//////////////////////////////////////////////////////////////////////////////////
362 		// DXSurface::selectTexture
363 		//////////////////////////////////////////////////////////////////////////////////
364 
selectTexture()365 		bool DXSurface::selectTexture()
366 		{
367 			ImplRenderModuleGuard aGuard( mrRenderModule );
368 			mrRenderModule.flushVertexCache();
369 			COMReference<IDirect3DDevice9> pDevice(mrRenderModule.getDevice());
370 
371 			if( FAILED(pDevice->SetTexture(0,mpTexture.get())) )
372                 return false;
373 
374 			return true;
375 		}
376 
377 		//////////////////////////////////////////////////////////////////////////////////
378 		// DXSurface::isValid
379 		//////////////////////////////////////////////////////////////////////////////////
380 
isValid()381 		bool DXSurface::isValid()
382 		{
383 			ImplRenderModuleGuard aGuard( mrRenderModule );
384 
385 			if(!(mpTexture.is()))
386 				return false;
387 			return true;
388 		}
389 
390 		//////////////////////////////////////////////////////////////////////////////////
391 		// DXSurface::update
392 		//////////////////////////////////////////////////////////////////////////////////
393 
update(const::basegfx::B2IPoint & rDestPos,const::basegfx::B2IRange & rSourceRect,::canvas::IColorBuffer & rSource)394 		bool DXSurface::update( const ::basegfx::B2IPoint& rDestPos,
395 								const ::basegfx::B2IRange& rSourceRect,
396 								::canvas::IColorBuffer&    rSource )
397 		{
398 			ImplRenderModuleGuard aGuard( mrRenderModule );
399 
400 			// can't update if surface is not valid, that means
401 			// either not existent nor restored...
402 			if(!(isValid()))
403 				return false;
404 
405 			D3DLOCKED_RECT aLockedRect;
406 			RECT rect;
407 			rect.left = std::max(sal_Int32(0),rDestPos.getX());
408 			rect.top =  std::max(sal_Int32(0),rDestPos.getY());
409             // to avoid interpolation artifacts from other textures,
410             // the surface manager allocates one pixel gap between
411             // them. Clear that to transparent.
412 			rect.right = std::min(maSize.getX(),
413                                   rect.left + sal_Int32(rSourceRect.getWidth()+1));
414             rect.bottom = std::min(maSize.getY(),
415                                    rect.top + sal_Int32(rSourceRect.getHeight()+1));
416             const bool bClearRightColumn( rect.right < maSize.getX() );
417             const bool bClearBottomRow( rect.bottom < maSize.getY() );
418 
419 			if(SUCCEEDED(mpTexture->LockRect(0,&aLockedRect,&rect,D3DLOCK_NOSYSLOCK)))
420 			{
421 				if(sal_uInt8* pImage = rSource.lock())
422 				{
423 					switch( rSource.getFormat() )
424 					{
425 						case ::canvas::IColorBuffer::FMT_A8R8G8B8:
426 						{
427 							const std::size_t nSourceBytesPerPixel(4);
428 							const std::size_t nSourcePitchInBytes(rSource.getStride());
429 							pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
430 							pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
431 
432 							// calculate the destination memory address
433 							sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits;
434 
435 							const sal_uInt32 nNumBytesToCopy(
436 								static_cast<sal_uInt32>(
437 									rSourceRect.getWidth())*
438 								nSourceBytesPerPixel);
439 							const sal_uInt64 nNumLines(rSourceRect.getHeight());
440 
441 							for(sal_uInt32 i=0; i<nNumLines; ++i)
442 							{
443                                 rtl_copyMemory(pDst,pImage,nNumBytesToCopy);
444 
445                                 if( bClearRightColumn )
446                                 {
447                                     // to avoid interpolation artifacts
448                                     // from other textures, the surface
449                                     // manager allocates one pixel gap
450                                     // between them. Clear that to
451                                     // transparent.
452                                     pDst[nNumBytesToCopy] =
453                                         pDst[nNumBytesToCopy+1] =
454                                         pDst[nNumBytesToCopy+2] =
455                                         pDst[nNumBytesToCopy+3] = 0x00;
456                                 }
457                                 pDst += aLockedRect.Pitch;
458 								pImage += nSourcePitchInBytes;
459 							}
460 
461                             if( bClearBottomRow )
462                                 rtl_zeroMemory(pDst,nNumBytesToCopy+4);
463 						}
464 						break;
465 
466 						case ::canvas::IColorBuffer::FMT_R8G8B8:
467 						{
468 							const std::size_t nSourceBytesPerPixel(3);
469 							const std::size_t nSourcePitchInBytes(rSource.getStride());
470 							pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
471 							pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
472 
473 							// calculate the destination memory address
474 							sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits;
475 
476 							const sal_Int32 nNumColumns(
477                                 sal::static_int_cast<sal_Int32>(rSourceRect.getWidth()));
478 							const sal_Int32 nNumLines(
479                                 sal::static_int_cast<sal_Int32>(rSourceRect.getHeight()));
480 							for(sal_Int32 i=0; i<nNumLines; ++i)
481 							{
482 								sal_uInt32 *pDstScanline = reinterpret_cast<sal_uInt32 *>(pDst);
483 								sal_uInt8 *pSrcScanline = reinterpret_cast<sal_uInt8 *>(pImage);
484 
485                                 for(sal_Int32 x=0; x<nNumColumns; ++x)
486                                 {
487                                     sal_uInt32 color(0xFF000000);
488                                     color |= pSrcScanline[2]<<16;
489                                     color |= pSrcScanline[1]<<8;
490                                     color |= pSrcScanline[0];
491                                     pSrcScanline += 3;
492                                     *pDstScanline++ = color;
493                                 }
494                                 if( bClearRightColumn )
495                                     *pDstScanline++ = 0xFF000000;
496 
497 								pDst += aLockedRect.Pitch;
498 								pImage += nSourcePitchInBytes;
499 							}
500 
501                             if( bClearBottomRow )
502                                 rtl_zeroMemory(pDst,4*(nNumColumns+1));
503 						}
504 						break;
505 
506 						case ::canvas::IColorBuffer::FMT_X8R8G8B8:
507 						{
508 							const std::size_t nSourceBytesPerPixel(4);
509 							const std::size_t nSourcePitchInBytes(rSource.getStride());
510 							pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
511 							pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
512 
513 							// calculate the destination memory address
514 							sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits;
515 
516 							const sal_Int32 nNumLines(
517                                 sal::static_int_cast<sal_Int32>(rSourceRect.getHeight()));
518 							const sal_Int32 nNumColumns(
519                                 sal::static_int_cast<sal_Int32>(rSourceRect.getWidth()));
520 							for(sal_Int32 i=0; i<nNumLines; ++i)
521 							{
522 								sal_uInt32 *pSrc32 = reinterpret_cast<sal_uInt32 *>(pImage);
523 								sal_uInt32 *pDst32 = reinterpret_cast<sal_uInt32 *>(pDst);
524 								for(sal_Int32 j=0; j<nNumColumns; ++j)
525 									pDst32[j] = 0xFF000000 | pSrc32[j];
526 
527                                 if( bClearRightColumn )
528                                     pDst32[nNumColumns] = 0xFF000000;
529 
530 								pDst += aLockedRect.Pitch;
531 								pImage += nSourcePitchInBytes;
532 							}
533 
534                             if( bClearBottomRow )
535                                 rtl_zeroMemory(pDst,4*(nNumColumns+1));
536 						}
537 						break;
538 
539 						default:
540 							ENSURE_OR_RETURN_FALSE(false,
541 											"DXSurface::update(): Unknown/unimplemented buffer format" );
542 							break;
543 					}
544 
545 					rSource.unlock();
546 				}
547 
548 				return SUCCEEDED(mpTexture->UnlockRect(0));
549 			}
550 
551 			return true;
552 		}
553 
554 		//////////////////////////////////////////////////////////////////////////////////
555 		// DXSurface::getSize
556 		//////////////////////////////////////////////////////////////////////////////////
557 
getSize()558 		::basegfx::B2IVector DXSurface::getSize()
559 		{
560 			return maSize;
561 		}
562 
getTexture() const563         COMReference<IDirect3DTexture9> DXSurface::getTexture() const
564         {
565             return mpTexture;
566         }
567 
568 		//////////////////////////////////////////////////////////////////////////////////
569 		// DXRenderModule::DXRenderModule
570 		//////////////////////////////////////////////////////////////////////////////////
571 
DXRenderModule(const::Window & rWindow)572         DXRenderModule::DXRenderModule( const ::Window& rWindow ) :
573 	        mhWnd(0),
574 			mpDevice(),
575 			mpDirect3D9(),
576 			mpSwapChain(),
577             mpVertexBuffer(),
578 			mpTexture(),
579 			maSize(),
580             maVertexCache(),
581 			mnCount(0),
582 			mnBeginSceneCount(0),
583 			mbCanUseDynamicTextures(false),
584 			mbError( false ),
585 			meType( PRIMITIVE_TYPE_UNKNOWN ),
586 			maPageSize(),
587             mad3dpp(),
588 			maNumVertices( VERTEX_BUFFER_SIZE ),
589 			maWriteIndex(0),
590 			maReadIndex(0)
591 		{
592             // TODO(P2): get rid of those fine-grained locking
593 			::osl::MutexGuard aGuard( maMutex );
594 
595 			if(!(create(rWindow)))
596 			{
597 				throw lang::NoSupportException(
598 					::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
599                                          "Could not create DirectX device!") ),NULL);
600 			}
601 
602 			// allocate a single texture surface which can be used later.
603 			// we also use this to calibrate the page size.
604 			::basegfx::B2IVector aPageSize(maPageSize);
605 			while(true)
606 			{
607                 mpTexture = ::canvas::ISurfaceSharedPtr(
608                     new DXSurface(*this,aPageSize));
609                 if(mpTexture->isValid())
610 					break;
611 
612 				aPageSize.setX(aPageSize.getX()>>1);
613 				aPageSize.setY(aPageSize.getY()>>1);
614 				if((aPageSize.getX() < MIN_TEXTURE_SIZE) ||
615 				   (aPageSize.getY() < MIN_TEXTURE_SIZE))
616 				{
617 					throw lang::NoSupportException(
618 						::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
619 											"Could not create DirectX device - "
620                                             "insufficient texture space!") ),NULL);
621 				}
622 			}
623 			maPageSize=aPageSize;
624 
625 			IDirect3DVertexBuffer9 *pVB(NULL);
626 			DWORD aFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1);
627             if( FAILED(mpDevice->CreateVertexBuffer(sizeof(dxvertex)*maNumVertices,
628                                                     D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
629                                                     aFVF,
630                                                     D3DPOOL_DEFAULT,
631                                                     &pVB,
632                                                     NULL)) )
633             {
634                 throw lang::NoSupportException(
635                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
636                                          "Could not create DirectX device - out of memory!")),NULL);
637             }
638 
639 			mpVertexBuffer=COMReference<IDirect3DVertexBuffer9>(pVB);
640 		}
641 
642 		//////////////////////////////////////////////////////////////////////////////////
643 		// DXRenderModule::~DXRenderModule
644 		//////////////////////////////////////////////////////////////////////////////////
645 
~DXRenderModule()646 		DXRenderModule::~DXRenderModule()
647 		{
648 			disposing();
649 		}
650 
651 		//////////////////////////////////////////////////////////////////////////////////
652 		// DXRenderModule::disposing
653 		//////////////////////////////////////////////////////////////////////////////////
654 
disposing()655 		void DXRenderModule::disposing()
656 		{
657 			if(!(mhWnd))
658 				return;
659 
660 			mpTexture.reset();
661 			mpWindow.reset();
662 			mhWnd=NULL;
663 
664             // refrain from releasing the DX9 objects. We're the only
665             // ones holding references to them, and it might be
666             // dangerous to destroy the DX9 device, before all other
667             // objects are dead.
668 		}
669 
670 		//////////////////////////////////////////////////////////////////////////////////
671 		// DXRenderModule::create
672 		//////////////////////////////////////////////////////////////////////////////////
673 
create(const::Window & rWindow)674 		bool DXRenderModule::create( const ::Window& rWindow )
675 		{
676             // TODO(P2): get rid of those fine-grained locking
677 			::osl::MutexGuard aGuard( maMutex );
678 
679 			maVertexCache.reserve(1024);
680 
681 			mpWindow.reset(
682 				new SystemChildWindow(
683 				const_cast<Window *>(&rWindow), 0) );
684 
685 			// system child window must not receive mouse events
686 			mpWindow->SetMouseTransparent( TRUE );
687 
688 			// parent should receive paint messages as well
689 			// [PARENTCLIPMODE_NOCLIP], the argument is here
690 			// passed as plain numeric value since the stupid
691 			// define utilizes a USHORT cast.
692 			mpWindow->SetParentClipMode(0x0002);
693 
694 			// the system child window must not clear its background
695 			mpWindow->EnableEraseBackground( sal_False );
696 
697 			mpWindow->SetControlForeground();
698 			mpWindow->SetControlBackground();
699 			mpWindow->EnablePaint(sal_False);
700 
701 			const SystemEnvData *pData = mpWindow->GetSystemData();
702 			const HWND hwnd(reinterpret_cast<HWND>(pData->hWnd));
703 			mhWnd = const_cast<HWND>(hwnd);
704 
705 			ENSURE_OR_THROW( IsWindow( reinterpret_cast<HWND>(mhWnd) ),
706 							"DXRenderModule::create() No valid HWND given." );
707 
708 			// retrieve position and size of the parent window
709 			const ::Size &rSizePixel(rWindow.GetSizePixel());
710 
711 			// remember the size of the parent window, since we
712 			// need to use this for our child window.
713 			maSize.setX(static_cast<sal_Int32>(rSizePixel.Width()));
714 			maSize.setY(static_cast<sal_Int32>(rSizePixel.Height()));
715 
716 			// let the child window cover the same size as the parent window.
717 			mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY());
718 
719 			// TODO(F2): since we would like to share precious hardware
720 			// resources, the direct3d9 object should be global. each new
721 			// request for a canvas should only create a new swapchain.
722 			mpDirect3D9 = COMReference<IDirect3D9>(
723 				Direct3DCreate9(D3D_SDK_VERSION));
724 			if(!mpDirect3D9.is())
725 				return false;
726 
727 			// create a device from the direct3d9 object.
728 			if(!(createDevice()))
729 				return false;
730 
731 			mpWindow->Show();
732 
733 			return true;
734 		}
735 
736 		//////////////////////////////////////////////////////////////////////////////////
737 		// DXRenderModule::verifyDevice
738 		//////////////////////////////////////////////////////////////////////////////////
739 
verifyDevice(const UINT nAdapter)740 		bool DXRenderModule::verifyDevice( const UINT nAdapter )
741 		{
742 			ENSURE_OR_THROW( mpDirect3D9.is(),
743                               "DXRenderModule::verifyDevice() No valid device." );
744 
745 			// ask direct3d9 about the capabilities of hardware devices on a specific adapter.
746 			// here we decide if the underlying hardware of the machine 'is good enough'.
747 			// since we only need a tiny little fraction of what could be used, this
748 			// is basically a no-op.
749 			D3DCAPS9 aCaps;
750 			if(FAILED(mpDirect3D9->GetDeviceCaps(nAdapter,D3DDEVTYPE_HAL,&aCaps)))
751 				return false;
752 			if(!(aCaps.MaxTextureWidth))
753 				return false;
754 			if(!(aCaps.MaxTextureHeight))
755 				return false;
756 			maPageSize = ::basegfx::B2IVector(aCaps.MaxTextureWidth,aCaps.MaxTextureHeight);
757 
758             // check device against white & blacklist entries
759             D3DADAPTER_IDENTIFIER9 aIdent;
760 			if(FAILED(mpDirect3D9->GetAdapterIdentifier(nAdapter,0,&aIdent)))
761 				return false;
762 
763             DXCanvasItem aConfigItem;
764             DXCanvasItem::DeviceInfo aInfo;
765             aInfo.nVendorId = aIdent.VendorId;
766             aInfo.nDeviceId = aIdent.DeviceId;
767             aInfo.nDeviceSubSysId = aIdent.SubSysId;
768             aInfo.nDeviceRevision = aIdent.Revision;
769 
770             aInfo.nDriverId = HIWORD(aIdent.DriverVersion.HighPart);
771             aInfo.nDriverVersion = LOWORD(aIdent.DriverVersion.HighPart);
772             aInfo.nDriverSubVersion = HIWORD(aIdent.DriverVersion.LowPart);
773             aInfo.nDriverBuildId = LOWORD(aIdent.DriverVersion.LowPart);
774 
775             if( !aConfigItem.isDeviceUsable(aInfo) )
776                 return false;
777 
778             if( aConfigItem.isBlacklistCurrentDevice() )
779             {
780                 aConfigItem.blacklistDevice(aInfo);
781                 return false;
782             }
783 
784             aConfigItem.adaptMaxTextureSize(maPageSize);
785 
786 			mbCanUseDynamicTextures = (aCaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) != 0;
787 
788             return true;
789         }
790 
791 
792 		//////////////////////////////////////////////////////////////////////////////////
793 		// DXRenderModule::createDevice
794 		//////////////////////////////////////////////////////////////////////////////////
795 
createDevice()796 		bool DXRenderModule::createDevice()
797 		{
798 			// we expect that the caller provides us with a valid HWND
799 			ENSURE_OR_THROW( IsWindow(mhWnd),
800                               "DXRenderModule::createDevice() No valid HWND given." );
801 
802 			// we expect that the caller already created the direct3d9 object.
803 			ENSURE_OR_THROW( mpDirect3D9.is(),
804                               "DXRenderModule::createDevice() no direct3d?." );
805 
806 			// find the adapter identifier from the window.
807 			const UINT aAdapter(getAdapterFromWindow());
808 			if(aAdapter == static_cast<UINT>(-1))
809 				return false;
810 
811             // verify that device possibly works
812             if( !verifyDevice(aAdapter) )
813                 return false;
814 
815 			// query the display mode from the selected adapter.
816 			// we'll later request the backbuffer format to be same
817 			// same as the display format.
818 			D3DDISPLAYMODE d3ddm;
819 			mpDirect3D9->GetAdapterDisplayMode(aAdapter,&d3ddm);
820 
821 			// we need to use D3DSWAPEFFECT_COPY here since the canvas-api has
822 			// basically nothing to do with efficient resource handling. it tries
823 			// to avoid drawing whenevery possible, which is simply not the most
824 			// efficient way we could leverage the hardware in this case. it would
825 			// be far better to redraw the backbuffer each time we would like to
826 			// display the content of the backbuffer, but we need to face reality
827 			// here and follow how the canvas was designed.
828 
829 			// Strictly speaking, we don't need a full screen worth of
830 			// backbuffer here. We could also scale dynamically with
831 			// the current window size, but this will make it
832 			// necessary to temporarily have two buffers while copying
833 			// from the old to the new one. What's more, at the time
834 			// we need a larger buffer, DX might not have sufficient
835 			// resources available, and we're then left with too small
836 			// a back buffer, and no way of falling back to a
837 			// different canvas implementation.
838 			ZeroMemory( &mad3dpp, sizeof(mad3dpp) );
839             mad3dpp.BackBufferWidth = std::max(sal_Int32(maSize.getX()),
840                                                sal_Int32(d3ddm.Width));
841             mad3dpp.BackBufferHeight = std::max(sal_Int32(maSize.getY()),
842                                                 sal_Int32(d3ddm.Height));
843             mad3dpp.BackBufferCount = 1;
844 			mad3dpp.Windowed = TRUE;
845 			mad3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
846 			mad3dpp.BackBufferFormat = d3ddm.Format;
847 			mad3dpp.EnableAutoDepthStencil = FALSE;
848 			mad3dpp.hDeviceWindow = mhWnd;
849 			mad3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
850 
851 			// now create the device, first try hardware vertex processing,
852 			// then software vertex processing. if both queries fail, we give up
853 			// and indicate failure.
854 			IDirect3DDevice9 *pDevice(NULL);
855 			if(FAILED(mpDirect3D9->CreateDevice(aAdapter,
856 												D3DDEVTYPE_HAL,
857 												mhWnd,
858 												D3DCREATE_HARDWARE_VERTEXPROCESSING|
859                                                 D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE,
860 												&mad3dpp,
861 												&pDevice)))
862 				if(FAILED(mpDirect3D9->CreateDevice(aAdapter,
863 													D3DDEVTYPE_HAL,
864 													mhWnd,
865 													D3DCREATE_SOFTWARE_VERTEXPROCESSING|
866                                                     D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE,
867 													&mad3dpp,
868 													&pDevice)))
869 					return false;
870 
871 			// got it, store it in a safe place...
872 			mpDevice=COMReference<IDirect3DDevice9>(pDevice);
873 
874 			// After CreateDevice, the first swap chain already exists, so just get it...
875 			IDirect3DSwapChain9 *pSwapChain(NULL);
876 			pDevice->GetSwapChain(0,&pSwapChain);
877 			mpSwapChain=COMReference<IDirect3DSwapChain9>(pSwapChain);
878             if( !mpSwapChain.is() )
879                 return false;
880 
881 			// clear the render target [which is the backbuffer in this case].
882 			// we are forced to do this once, and furthermore right now.
883 			// please note that this is only possible since we created the
884 			// backbuffer with copy semantics [the content is preserved after
885 			// calls to Present()], which is an unnecessarily expensive operation.
886 			LPDIRECT3DSURFACE9 pBackBuffer = NULL;
887 			mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer);
888 			mpDevice->SetRenderTarget( 0, pBackBuffer );
889 			mpDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0L);
890 			pBackBuffer->Release();
891 
892 			return true;
893 		}
894 
895 		//////////////////////////////////////////////////////////////////////////////////
896 		// DXRenderModule::createSystemMemorySurface
897 		//////////////////////////////////////////////////////////////////////////////////
898 
createSystemMemorySurface(const::basegfx::B2IVector & rSize)899 		COMReference<IDirect3DSurface9> DXRenderModule::createSystemMemorySurface( const ::basegfx::B2IVector& rSize )
900 		{
901 			if(isDisposed())
902 				return COMReference<IDirect3DSurface9>(NULL);
903 
904 			// please note that D3DFMT_X8R8G8B8 is the only format we're
905 			// able to choose here, since GetDC() doesn't support any
906 			// other 32bit-format.
907 			IDirect3DSurface9 *pSurface(NULL);
908 			if( FAILED(mpDevice->CreateOffscreenPlainSurface(
909                            rSize.getX(),
910                            rSize.getY(),
911                            D3DFMT_X8R8G8B8,
912                            D3DPOOL_SYSTEMMEM,
913                            &pSurface,
914                            NULL)) )
915             {
916 				throw lang::NoSupportException(
917 					::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
918                                          "Could not create offscreen surface - out of mem!") ),NULL);
919             }
920 
921 			return COMReference<IDirect3DSurface9>(pSurface);
922 		}
923 
924 		//////////////////////////////////////////////////////////////////////////////////
925 		// DXRenderModule::flip
926 		//////////////////////////////////////////////////////////////////////////////////
927 
flip(const::basegfx::B2IRectangle & rUpdateArea,const::basegfx::B2IRectangle &)928 		bool DXRenderModule::flip( const ::basegfx::B2IRectangle& rUpdateArea,
929 								   const ::basegfx::B2IRectangle& /*rCurrWindowArea*/ )
930 		{
931             // TODO(P2): get rid of those fine-grained locking
932 			::osl::MutexGuard aGuard( maMutex );
933 
934 			if(isDisposed() || !mpSwapChain.is())
935 				return false;
936 
937 			flushVertexCache();
938 
939             // TODO(P2): Might be faster to actually pass update area here
940             RECT aRect =
941                 {
942                     rUpdateArea.getMinX(),
943                     rUpdateArea.getMinY(),
944                     rUpdateArea.getMaxX(),
945                     rUpdateArea.getMaxY()
946                 };
947 			HRESULT hr(mpSwapChain->Present(&aRect,&aRect,NULL,NULL,0));
948 			if(FAILED(hr))
949 			{
950 				if(hr != D3DERR_DEVICELOST)
951 					return false;
952 
953                 // interestingly enough, sometimes the Reset() below
954                 // *still* causes DeviceLost errors. So, cycle until
955                 // DX was kind enough to really reset the device...
956                 do
957                 {
958                     mpVertexBuffer.reset();
959                     hr = mpDevice->Reset(&mad3dpp);
960                     if(SUCCEEDED(hr))
961                     {
962                         IDirect3DVertexBuffer9 *pVB(NULL);
963                         DWORD aFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1);
964                         if( FAILED(mpDevice->CreateVertexBuffer(sizeof(dxvertex)*maNumVertices,
965                                                                 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
966                                                                 aFVF,
967                                                                 D3DPOOL_DEFAULT,
968                                                                 &pVB,
969                                                                 NULL)) )
970                         {
971                             throw lang::NoSupportException(
972                                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
973                                                      "Could not create DirectX device - out of memory!")),NULL);
974                         }
975                         mpVertexBuffer=COMReference<IDirect3DVertexBuffer9>(pVB);
976 
977                         // retry after the restore
978                         if(SUCCEEDED(mpSwapChain->Present(&aRect,&aRect,NULL,NULL,0)))
979                             return true;
980                     }
981 
982                     TimeValue aTimeout;
983                     aTimeout.Seconds=1;
984                     aTimeout.Nanosec=0;
985                     osl_waitThread(&aTimeout);
986                 }
987                 while(hr == D3DERR_DEVICELOST);
988 
989 				return false;
990 			}
991 
992 			return true;
993 		}
994 
995 		//////////////////////////////////////////////////////////////////////////////////
996 		// DXRenderModule::screenShot
997 		//////////////////////////////////////////////////////////////////////////////////
998 
screenShot()999 		void DXRenderModule::screenShot()
1000 		{
1001 		}
1002 
1003 		//////////////////////////////////////////////////////////////////////////////////
1004 		// DXRenderModule::resize
1005 		//////////////////////////////////////////////////////////////////////////////////
1006 
resize(const::basegfx::B2IRange & rect)1007 		void DXRenderModule::resize( const ::basegfx::B2IRange& rect )
1008 		{
1009             // TODO(P2): get rid of those fine-grained locking
1010 			::osl::MutexGuard aGuard( maMutex );
1011 
1012 			if(isDisposed())
1013 				return;
1014 
1015 			// don't do anything if the size didn't change.
1016 			if(maSize.getX() == static_cast<sal_Int32>(rect.getWidth()) &&
1017 			   maSize.getY() == static_cast<sal_Int32>(rect.getHeight()))
1018 			   return;
1019 
1020 			// TODO(Q2): use numeric cast to prevent overflow
1021 			maSize.setX(static_cast<sal_Int32>(rect.getWidth()));
1022 			maSize.setY(static_cast<sal_Int32>(rect.getHeight()));
1023 
1024 			mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY());
1025 
1026             // resize back buffer, if necessary
1027             // -------------------------------------------------------------
1028 
1029 			// don't attempt to create anything if the
1030 			// requested size is NULL.
1031 			if(!(maSize.getX()))
1032 				return;
1033 			if(!(maSize.getY()))
1034 				return;
1035 
1036             // backbuffer too small (might happen, if window is
1037             // maximized across multiple monitors)
1038             if( sal_Int32(mad3dpp.BackBufferWidth) < maSize.getX() ||
1039                 sal_Int32(mad3dpp.BackBufferHeight) < maSize.getY() )
1040             {
1041                 mad3dpp.BackBufferWidth = maSize.getX();
1042                 mad3dpp.BackBufferHeight = maSize.getY();
1043 
1044                 // clear before, save resources
1045                 mpSwapChain.reset();
1046 
1047                 IDirect3DSwapChain9 *pSwapChain(NULL);
1048                 if(FAILED(mpDevice->CreateAdditionalSwapChain(&mad3dpp,&pSwapChain)))
1049                     return;
1050                 mpSwapChain=COMReference<IDirect3DSwapChain9>(pSwapChain);
1051 
1052                 // clear the render target [which is the backbuffer in this case].
1053                 // we are forced to do this once, and furthermore right now.
1054                 // please note that this is only possible since we created the
1055                 // backbuffer with copy semantics [the content is preserved after
1056                 // calls to Present()], which is an unnecessarily expensive operation.
1057                 LPDIRECT3DSURFACE9 pBackBuffer = NULL;
1058                 mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer);
1059                 mpDevice->SetRenderTarget( 0, pBackBuffer );
1060                 mpDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0L);
1061                 pBackBuffer->Release();
1062             }
1063 		}
1064 
1065 		//////////////////////////////////////////////////////////////////////////////////
1066 		// DXRenderModule::getPageSize
1067 		//////////////////////////////////////////////////////////////////////////////////
1068 
getPageSize()1069 		::basegfx::B2IVector DXRenderModule::getPageSize()
1070 		{
1071             // TODO(P2): get rid of those fine-grained locking
1072 			::osl::MutexGuard aGuard( maMutex );
1073 			return maPageSize;
1074 		}
1075 
1076 		//////////////////////////////////////////////////////////////////////////////////
1077 		// DXRenderModule::createSurface
1078 		//////////////////////////////////////////////////////////////////////////////////
1079 
createSurface(const::basegfx::B2IVector & surfaceSize)1080 		::canvas::ISurfaceSharedPtr DXRenderModule::createSurface( const ::basegfx::B2IVector& surfaceSize )
1081 		{
1082             // TODO(P2): get rid of those fine-grained locking
1083 			::osl::MutexGuard aGuard( maMutex );
1084 
1085 			if(isDisposed())
1086 				return ::canvas::ISurfaceSharedPtr();
1087 
1088 			const ::basegfx::B2IVector& rPageSize( getPageSize() );
1089 			::basegfx::B2ISize aSize(surfaceSize);
1090 			if(!(aSize.getX()))
1091 				aSize.setX(rPageSize.getX());
1092 			if(!(aSize.getY()))
1093 				aSize.setY(rPageSize.getY());
1094 
1095 			if(mpTexture.use_count() == 1)
1096 				return mpTexture;
1097 
1098 			return ::canvas::ISurfaceSharedPtr( new DXSurface(*this,aSize) );
1099 		}
1100 
1101 		//////////////////////////////////////////////////////////////////////////////////
1102 		// DXRenderModule::beginPrimitive
1103 		//////////////////////////////////////////////////////////////////////////////////
1104 
beginPrimitive(PrimitiveType eType)1105 		void DXRenderModule::beginPrimitive( PrimitiveType eType )
1106 		{
1107             // TODO(P2): get rid of those fine-grained locking
1108 			::osl::MutexGuard aGuard( maMutex );
1109 
1110 			if(isDisposed())
1111 				return;
1112 
1113 			ENSURE_OR_THROW( !mnBeginSceneCount,
1114                               "DXRenderModule::beginPrimitive(): nested call" );
1115 
1116 			++mnBeginSceneCount;
1117 			meType=eType;
1118 			mnCount=0;
1119 		}
1120 
1121 		//////////////////////////////////////////////////////////////////////////////////
1122 		// DXRenderModule::endPrimitive
1123 		//////////////////////////////////////////////////////////////////////////////////
1124 
endPrimitive()1125 		void DXRenderModule::endPrimitive()
1126 		{
1127             // TODO(P2): get rid of those fine-grained locking
1128 			::osl::MutexGuard aGuard( maMutex );
1129 
1130 			if(isDisposed())
1131 				return;
1132 
1133 			--mnBeginSceneCount;
1134 			meType=PRIMITIVE_TYPE_UNKNOWN;
1135 			mnCount=0;
1136 		}
1137 
1138 		//////////////////////////////////////////////////////////////////////////////////
1139 		// DXRenderModule::pushVertex
1140 		//////////////////////////////////////////////////////////////////////////////////
1141 
pushVertex(const::canvas::Vertex & vertex)1142 		void DXRenderModule::pushVertex( const ::canvas::Vertex& vertex )
1143 		{
1144             // TODO(P2): get rid of those fine-grained locking
1145 			::osl::MutexGuard aGuard( maMutex );
1146 
1147 			if(isDisposed())
1148 				return;
1149 
1150 			switch(meType)
1151 			{
1152 				case PRIMITIVE_TYPE_TRIANGLE:
1153                 {
1154 					maVertexCache.push_back(vertex);
1155 					++mnCount;
1156 					mnCount &= 3;
1157 					break;
1158                 }
1159 
1160 				case PRIMITIVE_TYPE_QUAD:
1161                 {
1162 					if(mnCount == 3)
1163 					{
1164 						const std::size_t size(maVertexCache.size());
1165 						::canvas::Vertex v0(maVertexCache[size-1]);
1166 						::canvas::Vertex v2(maVertexCache[size-3]);
1167 						maVertexCache.push_back(v0);
1168 						maVertexCache.push_back(vertex);
1169 						maVertexCache.push_back(v2);
1170 						mnCount=0;
1171 					}
1172 					else
1173 					{
1174 						maVertexCache.push_back(vertex);
1175 						++mnCount;
1176 					}
1177 					break;
1178                 }
1179 
1180                 default:
1181                     OSL_ENSURE(false,
1182                                "DXRenderModule::pushVertex(): unexpected primitive type");
1183                     break;
1184 			}
1185 		}
1186 
1187 		//////////////////////////////////////////////////////////////////////////////////
1188 		// DXRenderModule::isError
1189 		//////////////////////////////////////////////////////////////////////////////////
1190 
isError()1191 		bool DXRenderModule::isError()
1192 		{
1193             // TODO(P2): get rid of those fine-grained locking
1194 			::osl::MutexGuard aGuard( maMutex );
1195 
1196 			return mbError;
1197 		}
1198 
1199 		//////////////////////////////////////////////////////////////////////////////////
1200 		// DXRenderModule::getAdapterFromWindow
1201 		//////////////////////////////////////////////////////////////////////////////////
1202 
getAdapterFromWindow()1203 		UINT DXRenderModule::getAdapterFromWindow()
1204 		{
1205 			HMONITOR hMonitor(aMonitorSupport.MonitorFromWindow(mhWnd));
1206 			UINT aAdapterCount(mpDirect3D9->GetAdapterCount());
1207 			for(UINT i=0; i<aAdapterCount; ++i)
1208 				if(hMonitor == mpDirect3D9->GetAdapterMonitor(i))
1209 					return i;
1210 			return static_cast<UINT>(-1);
1211 		}
1212 
1213 		//////////////////////////////////////////////////////////////////////////////////
1214 		// DXRenderModule::commitVertexCache
1215 		//////////////////////////////////////////////////////////////////////////////////
1216 
commitVertexCache()1217 		void DXRenderModule::commitVertexCache()
1218 		{
1219 			if(maReadIndex != maWriteIndex)
1220 			{
1221 				const std::size_t nVertexStride = sizeof(dxvertex);
1222 				const unsigned int nNumVertices = maWriteIndex-maReadIndex;
1223 				const unsigned int nNumPrimitives = nNumVertices / 3;
1224 
1225 				if(FAILED(mpDevice->SetStreamSource(0,mpVertexBuffer.get(),0,nVertexStride)))
1226 					return;
1227 
1228 				if(FAILED(mpDevice->SetFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)))
1229 					return;
1230 
1231 				if(FAILED(mpDevice->BeginScene()))
1232 					return;
1233 
1234 				mbError |= FAILED(mpDevice->DrawPrimitive(D3DPT_TRIANGLELIST,maReadIndex,nNumPrimitives));
1235 				mbError |= FAILED(mpDevice->EndScene());
1236 
1237 				maReadIndex += nNumVertices;
1238 			}
1239 		}
1240 
1241 		//////////////////////////////////////////////////////////////////////////////////
1242 		// DXRenderModule::flushVertexCache
1243 		//////////////////////////////////////////////////////////////////////////////////
1244 
flushVertexCache()1245 		void DXRenderModule::flushVertexCache()
1246 		{
1247 			if(!(maVertexCache.size()))
1248 				return;
1249 
1250 			mbError=true;
1251 
1252 			if( FAILED(mpDevice->SetRenderState(D3DRS_LIGHTING,FALSE)))
1253 				return;
1254 
1255 			// enable texture alpha blending
1256 			if( FAILED(mpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE)))
1257 				return;
1258 
1259 			mpDevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
1260 			mpDevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
1261 			mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSU ,D3DTADDRESS_CLAMP );
1262 			mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSV ,D3DTADDRESS_CLAMP );
1263 
1264 			// configure the fixed-function pipeline.
1265 			// the only 'feature' we need here is to modulate the alpha-channels
1266 			// from the texture and the interpolated diffuse color. the result
1267 			// will then be blended with the backbuffer.
1268 			// fragment color = texture color * diffuse.alpha.
1269 			mpDevice->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_MODULATE);
1270 			mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);
1271 			mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG2,D3DTA_DIFFUSE);
1272 
1273 			// normal combination of object...
1274 			if( FAILED(mpDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA)) )
1275 				return;
1276 
1277 			// ..and background color
1278 			if( FAILED(mpDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA)) )
1279 				return;
1280 
1281 			// disable backface culling; this enables us to mirror sprites
1282 			// by simply reverting the triangles, which, with enabled
1283 			// culling, would be invisible otherwise
1284 			if( FAILED(mpDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE)) )
1285 				return;
1286 
1287 			mbError=false;
1288 
1289 			std::size_t nSize(maVertexCache.size());
1290 			const std::size_t nVertexStride = sizeof(dxvertex);
1291 
1292 			const ::basegfx::B2IVector aPageSize(getPageSize());
1293 			const float nHalfPixelSizeX(0.5f/aPageSize.getX());
1294 			const float nHalfPixelSizeY(0.5f/aPageSize.getY());
1295             vertexCache_t::const_iterator it(maVertexCache.begin());
1296 
1297             while( nSize )
1298             {
1299                 DWORD dwLockFlags(D3DLOCK_NOOVERWRITE);
1300 
1301                 // Check to see if there's space for the current set of
1302                 // vertices in the buffer.
1303                 if( maNumVertices - maWriteIndex < nSize )
1304                 {
1305                     commitVertexCache();
1306                     dwLockFlags = D3DLOCK_DISCARD;
1307                     maWriteIndex = 0;
1308                     maReadIndex = 0;
1309                 }
1310 
1311                 dxvertex *vertices(NULL);
1312                 const std::size_t nNumVertices(
1313                     std::min(maNumVertices - maWriteIndex,
1314                              nSize));
1315                 if(FAILED(mpVertexBuffer->Lock(maWriteIndex*nVertexStride,
1316                                                nNumVertices*nVertexStride,
1317                                                (void **)&vertices,
1318                                                dwLockFlags)))
1319                     return;
1320 
1321                 std::size_t nIndex(0);
1322                 while( nIndex < nNumVertices )
1323                 {
1324                     dxvertex &dest = vertices[nIndex++];
1325                     dest.x=it->x;
1326                     dest.y=it->y;
1327                     dest.z=it->z;
1328                     dest.rhw=1;
1329                     const sal_uInt32 alpha(static_cast<sal_uInt32>(it->a*255.0f));
1330                     dest.diffuse=D3DCOLOR_ARGB(alpha,255,255,255);
1331                     dest.u=static_cast<float>(it->u + nHalfPixelSizeX);
1332                     dest.v=static_cast<float>(it->v + nHalfPixelSizeY);
1333                     ++it;
1334                 }
1335 
1336                 mpVertexBuffer->Unlock();
1337 
1338                 // Advance to the next position in the vertex buffer.
1339                 maWriteIndex += nNumVertices;
1340                 nSize -= nNumVertices;
1341 
1342                 commitVertexCache();
1343             }
1344 
1345             maVertexCache.clear();
1346 		}
1347 	}
1348 
1349 	//////////////////////////////////////////////////////////////////////////////////
1350 	// createRenderModule
1351 	//////////////////////////////////////////////////////////////////////////////////
1352 
createRenderModule(const::Window & rParent)1353 	IDXRenderModuleSharedPtr createRenderModule( const ::Window& rParent )
1354 	{
1355 		return IDXRenderModuleSharedPtr( new DXRenderModule(rParent) );
1356 	}
1357 }
1358 
1359 #endif
1360