1 //////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // Nestopia - NES/Famicom emulator written in C++ 4 // 5 // Copyright (C) 2003-2008 Martin Freij 6 // 7 // This file is part of Nestopia. 8 // 9 // Nestopia is free software; you can redistribute it and/or modify 10 // it under the terms of the GNU General Public License as published by 11 // the Free Software Foundation; either version 2 of the License, or 12 // (at your option) any later version. 13 // 14 // Nestopia is distributed in the hope that it will be useful, 15 // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 // GNU General Public License for more details. 18 // 19 // You should have received a copy of the GNU General Public License 20 // along with Nestopia; if not, write to the Free Software 21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 // 23 //////////////////////////////////////////////////////////////////////////////////////// 24 25 #ifndef NST_DIRECTX_DIRECT2D_H 26 #define NST_DIRECTX_DIRECT2D_H 27 28 #pragma once 29 30 #include <set> 31 #include <vector> 32 #include "NstWindowRect.hpp" 33 #include "NstDirectX.hpp" 34 35 #ifdef NST_DEBUG 36 #define D3D_DEBUG_INFO 37 #endif 38 39 #include <d3d9.h> 40 #include <d3dx9.h> 41 42 namespace Nestopia 43 { 44 namespace DirectX 45 { 46 class Direct2D 47 { 48 public: 49 50 explicit Direct2D(HWND); 51 ~Direct2D(); 52 53 typedef Window::Rect Rect; 54 typedef Window::Point Point; 55 56 enum 57 { 58 MAX_SCANLINES = 100 59 }; 60 61 struct Mode 62 { 63 typedef std::set<uchar> Rates; 64 65 explicit Mode(uint=0,uint=0,uint=0); 66 67 enum 68 { 69 MIN_WIDTH = 256, 70 MIN_HEIGHT = 240, 71 DEFAULT_RATE = 60, 72 MAX_RATE = 120 73 }; 74 75 bool operator == (const Mode&) const; 76 bool operator < (const Mode&) const; 77 78 uint width, height, bpp; 79 Rates rates; 80 operator !=Nestopia::DirectX::Direct2D::Mode81 bool operator != (const Mode& mode) const 82 { 83 return !(*this == mode); 84 } 85 SizeNestopia::DirectX::Direct2D::Mode86 Point Size() const 87 { 88 return Point( width, height ); 89 } 90 }; 91 92 struct Adapter : BaseAdapter 93 { 94 typedef std::set<Mode> Modes; 95 96 enum DeviceType 97 { 98 DEVICE_HAL, 99 DEVICE_HEL 100 }; 101 102 enum Filter 103 { 104 FILTER_NONE, 105 FILTER_BILINEAR 106 }; 107 108 /** used to identify multiple monitors on the same video adapter */ 109 uint guidIndex; 110 uint ordinal; 111 DeviceType deviceType; 112 Point maxScreenSize; 113 bool videoMemScreen; 114 bool anyTextureSize; 115 bool canDoScanlineEffect; 116 bool intervalTwo; 117 bool intervalThree; 118 bool intervalFour; 119 bool modern; 120 uint filters; 121 Modes modes; 122 }; 123 124 typedef std::vector<Adapter> Adapters; 125 126 enum 127 { 128 RENDER_PICTURE = 0x01, 129 RENDER_FPS = 0x04, 130 RENDER_MSG = 0x08, 131 RENDER_NFO = 0x10 132 }; 133 134 void SelectAdapter(const Adapters::const_iterator); 135 void RenderScreen(uint); 136 bool CanSwitchFullscreen(const Adapter::Modes::const_iterator) const; 137 bool SwitchFullscreen(const Adapter::Modes::const_iterator); 138 bool SwitchWindowed(); 139 void UpdateWindowView(); 140 void UpdateWindowView(const Point&,const Rect&,uint,int,Adapter::Filter,bool); 141 void UpdateFullscreenView(const Rect&,const Point&,const Rect&,uint,int,Adapter::Filter,bool); 142 void UpdateFrameRate(uint,bool,bool); 143 void EnableDialogBoxMode(bool); 144 bool Repair(); 145 146 enum ScreenShotResult 147 { 148 SCREENSHOT_OK, 149 SCREENSHOT_UNSUPPORTED, 150 SCREENSHOT_ERROR 151 }; 152 153 ScreenShotResult SaveScreenShot(wcstring,uint) const; 154 155 private: 156 157 enum 158 { 159 INVALID_RECT = MAKE_HRESULT(SEVERITY_ERROR,0x123,2), 160 TSL_PATCHES = 32 161 }; 162 163 void FlushObjects(); 164 void InvalidateObjects(); 165 void ValidateObjects(); 166 167 class Base 168 { 169 public: 170 171 Base(); 172 ~Base(); 173 174 inline operator IDirect3D9& () const; 175 176 static uint FormatToBpp(D3DFORMAT); 177 static void FormatToMask(D3DFORMAT,ulong&,ulong&,ulong&); 178 179 private: 180 181 static IDirect3D9& Create(); 182 static const Adapters EnumerateAdapters(IDirect3D9&); 183 184 IDirect3D9& com; 185 const Adapters adapters; 186 187 public: 188 GetAdapters() const189 const Adapters& GetAdapters() const 190 { 191 return adapters; 192 } 193 GetAdapter(uint i) const194 const Adapter& GetAdapter(uint i) const 195 { 196 NST_ASSERT( i < adapters.size() ); 197 return adapters[i]; 198 } 199 }; 200 201 class Device 202 { 203 public: 204 205 Device(HWND,const Base&); 206 207 void Create(IDirect3D9&,const Adapter&); 208 209 bool CanSwitchFullscreen(const Mode&) const; 210 bool CanToggleDialogBoxMode(bool) const; 211 bool ResetFrameRate(uint,bool,bool,const Base&); 212 uint GetMaxMessageLength() const; 213 214 void SwitchFullscreen(const Mode&); 215 void SwitchWindowed(); 216 217 NST_SINGLE_CALL HRESULT RenderScreen(uint,uint,uint) const; 218 219 HRESULT ResetWindowClient(const Point&,HRESULT); 220 HRESULT ToggleDialogBoxMode(); 221 HRESULT Repair(HRESULT); 222 HRESULT Reset(); 223 224 inline operator IDirect3DDevice9& () const; 225 226 private: 227 228 void Prepare() const; 229 void LogDisplaySwitch() const; 230 uint GetRefreshRate() const; 231 DWORD GetPresentationFlags() const; 232 D3DSWAPEFFECT GetSwapEffect() const; 233 uint GetDesiredPresentationRate(const Mode&) const; 234 DWORD GetDesiredPresentationInterval(uint) const; 235 DWORD GetDesiredPresentationInterval() const; 236 bool GetDisplayMode(D3DDISPLAYMODE&) const; 237 238 struct Timing 239 { 240 Timing(); 241 242 bool autoHz; 243 bool vsync; 244 bool tripleBuffering; 245 uchar frameRate; 246 }; 247 248 class Fonts 249 { 250 public: 251 252 Fonts(); 253 254 void Create(const Device&); 255 void Destroy(bool); 256 void OnReset() const; 257 void OnLost() const; 258 259 NST_SINGLE_CALL void Render(const D3DPRESENT_PARAMETERS&,uint) const; 260 261 private: 262 263 class Font 264 { 265 public: 266 267 void Create(const Device&); 268 void Destroy(); 269 void Update(const GenericString&); 270 uint Width() const; 271 void OnReset() const; 272 void OnLost() const; 273 274 inline bool CanDraw() const; 275 inline void Draw(D3DCOLOR,DWORD,Rect) const; 276 277 private: 278 279 ComInterface<ID3DXFont> com; 280 HeapString string; 281 uint length; 282 283 public: 284 Clear()285 void Clear() 286 { 287 length = 0; 288 } 289 }; 290 291 Font fps; 292 Font msg; 293 Font nfo; 294 uint width; 295 296 public: 297 UpdateFps(const GenericString & string)298 void UpdateFps(const GenericString& string) 299 { 300 fps.Update( string ); 301 } 302 ClearFps()303 void ClearFps() 304 { 305 fps.Clear(); 306 } 307 UpdateMsg(const GenericString & string)308 void UpdateMsg(const GenericString& string) 309 { 310 msg.Update( string ); 311 } 312 ClearMsg()313 void ClearMsg() 314 { 315 msg.Clear(); 316 } 317 UpdateNfo(const GenericString & string)318 void UpdateNfo(const GenericString& string) 319 { 320 nfo.Update( string ); 321 } 322 ClearNfo()323 void ClearNfo() 324 { 325 nfo.Clear(); 326 } 327 Width() const328 uint Width() const 329 { 330 return width; 331 } 332 }; 333 334 ComInterface<IDirect3DDevice9> com; 335 Timing timing; 336 Fonts fonts; 337 uchar ordinal; 338 uchar intervalTwo; 339 uchar intervalThree; 340 uchar intervalFour; 341 D3DPRESENT_PARAMETERS presentation; 342 bool dialogBoxMode; 343 344 public: 345 GetOrdinal() const346 uint GetOrdinal() const 347 { 348 return ordinal; 349 } 350 ClearScreen() const351 HRESULT ClearScreen() const 352 { 353 return com->Clear( 0, NULL, D3DCLEAR_TARGET, 0, 1.f, 0 ); 354 } 355 PresentScreen() const356 HRESULT PresentScreen() const 357 { 358 return com->Present( NULL, NULL, NULL, NULL ); 359 } 360 GetPresentation() const361 const D3DPRESENT_PARAMETERS& GetPresentation() const 362 { 363 return presentation; 364 } 365 DrawFps(const GenericString & string)366 void DrawFps(const GenericString& string) 367 { 368 fonts.UpdateFps( string ); 369 } 370 ClearFps()371 void ClearFps() 372 { 373 fonts.ClearFps(); 374 } 375 DrawMsg(const GenericString & string)376 void DrawMsg(const GenericString& string) 377 { 378 fonts.UpdateMsg( string ); 379 } 380 ClearMsg()381 void ClearMsg() 382 { 383 fonts.ClearMsg(); 384 } 385 DrawNfo(const GenericString & string)386 void DrawNfo(const GenericString& string) 387 { 388 fonts.UpdateNfo( string ); 389 } 390 ClearNfo()391 void ClearNfo() 392 { 393 fonts.ClearNfo(); 394 } 395 EnableAutoFrequency(bool enable)396 void EnableAutoFrequency(bool enable) 397 { 398 timing.autoHz = enable; 399 } 400 ThrottleRequired(uint speed) const401 bool ThrottleRequired(uint speed) const 402 { 403 return 404 ( 405 presentation.PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE || 406 speed != timing.frameRate 407 ); 408 } 409 SmoothFrameRate() const410 bool SmoothFrameRate() const 411 { 412 return presentation.PresentationInterval != D3DPRESENT_INTERVAL_IMMEDIATE; 413 } 414 }; 415 416 class Textures 417 { 418 public: 419 420 explicit Textures(D3DFORMAT); 421 422 void Update(const Adapter&,const Point&,uint,Adapter::Filter,bool); 423 HRESULT Validate(IDirect3DDevice9&,const Adapter&,D3DFORMAT); 424 void Invalidate(); 425 void Flush(); 426 bool SaveToFile(wcstring,D3DXIMAGE_FILEFORMAT) const; 427 428 inline double GetScreenLeftU(uint) const; 429 inline double GetScreenRightU(uint) const; 430 inline double GetScreenTopV(uint) const; 431 inline double GetScreenBottomV(uint) const; 432 inline double GetEffectLeftU(uint) const; 433 inline double GetEffectRightU(uint) const; 434 inline double GetEffectTopV(uint) const; 435 inline double GetEffectBottomV(uint) const; 436 437 private: 438 439 class Texture : public ImplicitBool<Texture> 440 { 441 public: 442 443 void Invalidate(); 444 445 protected: 446 447 explicit Texture(uint,D3DFORMAT); 448 ~Texture(); 449 450 bool Validate(IDirect3DDevice9&,D3DFORMAT,bool); 451 452 static uint GetSquared(const Point&); 453 454 ComInterface<IDirect3DTexture9> com; 455 Object::Pod<D3DSURFACE_DESC> desc; 456 Point size; 457 const uint stage; 458 459 public: 460 operator !() const461 bool operator ! () const 462 { 463 return !com; 464 } 465 GetBitMask(ulong & r,ulong & g,ulong & b) const466 void GetBitMask(ulong& r,ulong& g,ulong& b) const 467 { 468 Base::FormatToMask( desc.Format, r, g, b ); 469 } 470 GetBitsPerPixel() const471 uint GetBitsPerPixel() const 472 { 473 return Base::FormatToBpp( desc.Format ); 474 } 475 Lock(D3DLOCKED_RECT & lockedRect) const476 NST_FORCE_INLINE HRESULT Lock(D3DLOCKED_RECT& lockedRect) const 477 { 478 const RECT rect = {0,0,size.x,size.y}; 479 480 if (com) 481 { 482 return com->LockRect 483 ( 484 0, 485 &lockedRect, 486 (desc.Usage & D3DUSAGE_DYNAMIC) ? NULL : &rect, 487 (desc.Usage & D3DUSAGE_DYNAMIC) ? (D3DLOCK_DISCARD|D3DLOCK_NOSYSLOCK) : D3DLOCK_NOSYSLOCK 488 ); 489 } 490 else 491 { 492 return D3DERR_DEVICELOST; 493 } 494 } 495 Unlock() const496 NST_FORCE_INLINE void Unlock() const 497 { 498 com->UnlockRect( 0 ); 499 } 500 }; 501 502 class ScreenTexture : public Texture 503 { 504 public: 505 506 explicit ScreenTexture(D3DFORMAT); 507 508 void Update(const Adapter&,Point,bool); 509 void Flush(); 510 bool Validate(IDirect3DDevice9&,D3DFORMAT,const Adapter&); 511 bool SaveToFile(wcstring,D3DXIMAGE_FILEFORMAT) const; 512 513 inline double GetLeftU(uint) const; 514 inline double GetRightU(uint) const; 515 inline double GetTopV(uint) const; 516 inline double GetBottomV(uint) const; 517 518 private: 519 520 bool useVidMem; 521 }; 522 523 class EffectTexture : public Texture 524 { 525 public: 526 527 explicit EffectTexture(D3DFORMAT); 528 529 void Update(const Adapter&,Point,uint); 530 bool Validate(IDirect3DDevice9&,D3DFORMAT); 531 532 inline double GetLeftU(uint) const; 533 inline double GetRightU(uint) const; 534 inline double GetTopV(uint) const; 535 inline double GetBottomV(uint) const; 536 537 private: 538 539 uint scanlines; 540 bool dirty; 541 }; 542 543 ScreenTexture screenTexture; 544 EffectTexture effectTexture; 545 Adapter::Filter filter; 546 547 public: 548 LockScreen(void * & data,long & pitch) const549 NST_FORCE_INLINE HRESULT LockScreen(void*& data,long& pitch) const 550 { 551 D3DLOCKED_RECT lockedRect; 552 const HRESULT hResult = screenTexture.Lock( lockedRect ); 553 554 if (SUCCEEDED(hResult)) 555 { 556 data = lockedRect.pBits; 557 pitch = lockedRect.Pitch; 558 } 559 560 return hResult; 561 } 562 UnlockScreen() const563 NST_FORCE_INLINE void UnlockScreen() const 564 { 565 screenTexture.Unlock(); 566 } 567 GetScreenBitMask(ulong & r,ulong & g,ulong & b) const568 void GetScreenBitMask(ulong& r,ulong& g,ulong& b) const 569 { 570 screenTexture.GetBitMask( r, g, b ); 571 } 572 GetScreenBitsPerPixel() const573 uint GetScreenBitsPerPixel() const 574 { 575 return screenTexture.GetBitsPerPixel(); 576 } 577 }; 578 579 class VertexBuffer 580 { 581 public: 582 583 VertexBuffer(); 584 ~VertexBuffer(); 585 586 void Update(const Rect&,const Rect&,int); 587 HRESULT Validate(IDirect3DDevice9&,const Textures&); 588 void Invalidate(); 589 590 inline uint NumVertices() const; 591 592 private: 593 594 enum 595 { 596 FVF = D3DFVF_XYZRHW|D3DFVF_TEX2 597 }; 598 599 #pragma pack(push,1) 600 601 struct Vertex 602 { 603 float x,y,z,rhw,u0,v0,u1,v1; 604 }; 605 606 #pragma pack(pop) 607 608 NST_COMPILE_ASSERT( sizeof(Vertex) == 32 ); 609 610 ComInterface<IDirect3DVertexBuffer9> com; 611 Rect rect; 612 Rect clip; 613 uint numVertices; 614 int screenCurvature; 615 bool dirty; 616 617 public: 618 GetRect() const619 const Rect& GetRect() const 620 { 621 return rect; 622 } 623 }; 624 625 class IndexBuffer 626 { 627 public: 628 629 IndexBuffer(); 630 ~IndexBuffer(); 631 632 void Update(bool); 633 HRESULT Validate(IDirect3DDevice9&); 634 void Invalidate(); 635 636 inline uint NumStrips() const; 637 638 private: 639 640 ComInterface<IDirect3DIndexBuffer9> com; 641 uint numStrips; 642 }; 643 644 Base base; 645 Device device; 646 Textures textures; 647 VertexBuffer vertexBuffer; 648 IndexBuffer indexBuffer; 649 HRESULT lastResult; 650 651 public: 652 ValidScreen() const653 bool ValidScreen() const 654 { 655 return SUCCEEDED(lastResult); 656 } 657 Windowed() const658 bool Windowed() const 659 { 660 return device.GetPresentation().Windowed; 661 } 662 ThrottleRequired(uint speed) const663 bool ThrottleRequired(uint speed) const 664 { 665 return device.ThrottleRequired( speed ) || FAILED(lastResult); 666 } 667 GetAdapters() const668 const Adapters& GetAdapters() const 669 { 670 return base.GetAdapters(); 671 } 672 GetAdapter() const673 const Adapter& GetAdapter() const 674 { 675 return base.GetAdapter( device.GetOrdinal() ); 676 } 677 GetBitsPerPixel() const678 uint GetBitsPerPixel() const 679 { 680 return textures.GetScreenBitsPerPixel(); 681 } 682 GetBitMask(ulong & r,ulong & g,ulong & b) const683 void GetBitMask(ulong& r,ulong& g,ulong& b) const 684 { 685 textures.GetScreenBitMask( r, g, b ); 686 } 687 GetScreenRect() const688 const Rect& GetScreenRect() const 689 { 690 return vertexBuffer.GetRect(); 691 } 692 LockScreen(void * & data,long & pitch)693 NST_FORCE_INLINE bool LockScreen(void*& data,long& pitch) 694 { 695 if (SUCCEEDED(lastResult)) 696 lastResult = textures.LockScreen( data, pitch ); 697 698 return SUCCEEDED(lastResult); 699 } 700 UnlockScreen() const701 NST_FORCE_INLINE void UnlockScreen() const 702 { 703 NST_VERIFY( SUCCEEDED(lastResult) ); 704 textures.UnlockScreen(); 705 } 706 ClearScreen()707 bool ClearScreen() 708 { 709 if (SUCCEEDED(lastResult)) 710 { 711 lastResult = device.ClearScreen(); 712 return SUCCEEDED(lastResult); 713 } 714 else 715 { 716 return lastResult == INVALID_RECT; 717 } 718 } 719 PresentScreen()720 bool PresentScreen() 721 { 722 if (SUCCEEDED(lastResult)) 723 { 724 lastResult = device.PresentScreen(); 725 return SUCCEEDED(lastResult); 726 } 727 else 728 { 729 return lastResult == INVALID_RECT; 730 } 731 } 732 DrawFps(const GenericString & string)733 void DrawFps(const GenericString& string) 734 { 735 device.DrawFps( string ); 736 } 737 ClearFps()738 void ClearFps() 739 { 740 device.ClearFps(); 741 } 742 DrawMsg(const GenericString & string)743 void DrawMsg(const GenericString& string) 744 { 745 device.DrawMsg( string ); 746 } 747 ClearMsg()748 void ClearMsg() 749 { 750 device.ClearMsg(); 751 } 752 DrawNfo(const GenericString & string)753 void DrawNfo(const GenericString& string) 754 { 755 device.DrawNfo( string ); 756 } 757 ClearNfo()758 void ClearNfo() 759 { 760 device.ClearNfo(); 761 } 762 EnableAutoFrequency(bool enable)763 void EnableAutoFrequency(bool enable) 764 { 765 device.EnableAutoFrequency( enable ); 766 } 767 GetMaxMessageLength() const768 uint GetMaxMessageLength() const 769 { 770 return device.GetMaxMessageLength(); 771 } 772 GetFullscreenDisplayMode() const773 const Point GetFullscreenDisplayMode() const 774 { 775 return Point( device.GetPresentation().BackBufferWidth, device.GetPresentation().BackBufferHeight ); 776 } 777 ModernGPU() const778 bool ModernGPU() const 779 { 780 return base.GetAdapters()[device.GetOrdinal()].modern; 781 } 782 SmoothFrameRate() const783 bool SmoothFrameRate() const 784 { 785 return device.SmoothFrameRate(); 786 } 787 }; 788 } 789 } 790 791 #endif 792