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