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