d3d9graphics.bmx 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. Strict
  2. Import BRL.Graphics
  3. Import Pub.DirectX
  4. Import BRL.LinkedList
  5. Import brl.systemdefault
  6. Private
  7. Global _wndClass$="BBDX9Device Window Class"
  8. Global _driver:TD3D9graphicsDriver
  9. Global _d3d:IDirect3D9
  10. Global _d3dCaps:D3DCAPS9
  11. Global _modes:TGraphicsMode[]
  12. Global _d3dDev:IDirect3DDevice9
  13. Global _d3dDevRefs:Int
  14. Global _presentParams:D3DPRESENT_PARAMETERS
  15. Global _graphics:TD3D9Graphics
  16. Global _autoRelease:TList
  17. Global _d3dOccQuery:IDirect3DQuery9
  18. Type TD3D9AutoRelease
  19. Field unk:IUnknown_
  20. End Type
  21. Function D3D9WndProc:Byte Ptr( hwnd:Byte Ptr,msg:UInt,wp:WParam,lp:LParam) "win32"
  22. bbSystemEmitOSEvent hwnd,msg,wp,lp,Null
  23. Select msg
  24. Case WM_CLOSE
  25. Return Null
  26. Case WM_SYSKEYDOWN
  27. If wp<>KEY_F4 Return Null
  28. End Select
  29. Return DefWindowProcW( hwnd,msg,wp,lp )
  30. End Function
  31. Function OpenD3DDevice:Int( hwnd:Byte Ptr,width:Int,height:Int,depth:Int,hertz:Int,flags:Int)
  32. If _d3dDevRefs
  33. If Not _presentParams.Windowed Return False
  34. If depth<>0 Return False
  35. _d3dDevRefs:+1
  36. Return True
  37. EndIf
  38. Local windowed:Int=(depth=0)
  39. Local fullscreen:Int=(depth<>0)
  40. Local pp:D3DPRESENT_PARAMETERS
  41. pp.BackBufferWidth = width
  42. pp.BackBufferHeight = height
  43. pp.BackBufferCount = 1
  44. pp.BackBufferFormat = (D3DFMT_X8R8G8B8 * fullscreen) + (D3DFMT_UNKNOWN * windowed)
  45. pp.MultiSampleType = D3DMULTISAMPLE_NONE
  46. pp.SwapEffect = (D3DSWAPEFFECT_DISCARD * fullscreen) + (D3DSWAPEFFECT_COPY * windowed)
  47. pp.hDeviceWindow = hwnd
  48. pp.Windowed = windowed
  49. pp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER
  50. pp.FullScreen_RefreshRateInHz = hertz * fullscreen
  51. pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE 'IMMEDIATE
  52. Local cflags:Int=D3DCREATE_FPU_PRESERVE
  53. '_d3dDev' = New IDirect3DDevice9
  54. 'OK, try hardware vertex processing...
  55. Local tflags:Int=D3DCREATE_PUREDEVICE|D3DCREATE_HARDWARE_VERTEXPROCESSING|cflags
  56. If _d3d.CreateDevice( 0,D3DDEVTYPE_HAL,hwnd,tflags,pp,_d3dDev )<0
  57. 'Failed! Try mixed vertex processing...
  58. tflags=D3DCREATE_MIXED_VERTEXPROCESSING|cflags
  59. If _d3d.CreateDevice( 0,D3DDEVTYPE_HAL,hwnd,tflags,pp,_d3dDev )<0
  60. 'Failed! Try software vertex processing...
  61. tflags=D3DCREATE_SOFTWARE_VERTEXPROCESSING|cflags
  62. If _d3d.CreateDevice( 0,D3DDEVTYPE_HAL,hwnd,tflags,pp,_d3dDev )<0
  63. _d3dDev = Null
  64. 'Failed! Go home and watch family guy instead...
  65. Return False
  66. EndIf
  67. EndIf
  68. EndIf
  69. _presentParams=pp
  70. _d3dDevRefs:+1
  71. _autoRelease=New TList
  72. 'Occlusion Query
  73. If Not _d3dOccQuery
  74. '_d3dOccQuery = New IDirect3DQuery9
  75. If _d3ddev.CreateQuery(9,_d3dOccQuery)<0 '9 hardcoded for D3DQUERYTYPE_OCCLUSION
  76. DebugLog "Cannot create Occlussion Query!"
  77. _d3dOccQuery = Null
  78. EndIf
  79. EndIf
  80. If _d3dOccQuery _d3dOccQuery.Issue(2) 'D3DISSUE_BEGIN
  81. Return True
  82. End Function
  83. Function CloseD3DDevice()
  84. _d3dDevRefs:-1
  85. If Not _d3dDevRefs
  86. For Local t:TD3D9AutoRelease=EachIn _autoRelease
  87. t.unk.Release_
  88. Next
  89. _autoRelease=Null
  90. If _d3dOccQuery _d3dOccQuery.Release_
  91. _d3dOccQuery = Null
  92. _d3dDev.Release_
  93. _d3dDev=Null
  94. ' _presentParams=null
  95. EndIf
  96. End Function
  97. Function ResetD3DDevice()
  98. If _d3dOccQuery
  99. _d3dOccQuery.Release_
  100. _d3dOccQuery = Null
  101. Else
  102. '_d3dOccQuery' = New IDirect3DQuery9
  103. End If
  104. If _d3dDev.Reset( _presentParams)<0
  105. Throw "_d3dDev.Reset failed"
  106. EndIf
  107. If _d3ddev.CreateQuery(9,_d3dOccQuery)<0
  108. _d3dOccQuery = Null
  109. DebugLog "Cannot create Occlussion Query!"
  110. EndIf
  111. If _d3dOccQuery _d3dOccQuery.Issue(2) 'D3DISSUE_BEGIN
  112. End Function
  113. Public
  114. Global UseDX9RenderLagFix:Int = 0
  115. Type TD3D9Graphics Extends TGraphics
  116. Method Attach:TD3D9Graphics( hwnd:Byte Ptr,flags:Int )
  117. Local rect:Int[4]
  118. GetClientRect hwnd,rect
  119. Local width:Int=rect[2]-rect[0]
  120. Local height:Int=rect[3]-rect[1]
  121. OpenD3DDevice hwnd,width,height,0,0,flags
  122. _hwnd=hwnd
  123. _width=width
  124. _height=height
  125. _flags=flags
  126. _attached=True
  127. Return Self
  128. End Method
  129. Method Create:TD3D9Graphics( width:Int,height:Int,depth:Int,hertz:Int,flags:Int)
  130. Local wstyle:Int
  131. If depth
  132. wstyle=WS_VISIBLE|WS_POPUP
  133. Else
  134. wstyle=WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX
  135. EndIf
  136. Local rect:Int[4]
  137. If Not depth
  138. Local desktopRect:Int[4]
  139. GetWindowRect GetDesktopWindow(),desktopRect
  140. rect[0]=desktopRect[2]/2-width/2;
  141. rect[1]=desktopRect[3]/2-height/2;
  142. rect[2]=rect[0]+width;
  143. rect[3]=rect[1]+height;
  144. AdjustWindowRect rect,wstyle,0
  145. EndIf
  146. Local hwnd:Byte Ptr=CreateWindowExW( 0,_wndClass,AppTitle,wstyle,rect[0],rect[1],rect[2]-rect[0],rect[3]-rect[1],Null,Null,GetModuleHandleA(Null),Null )
  147. If Not hwnd Return Null
  148. If Not depth
  149. GetClientRect hwnd,rect
  150. width=rect[2]-rect[0]
  151. height=rect[3]-rect[1]
  152. EndIf
  153. If Not OpenD3DDevice( hwnd,width,height,depth,hertz,flags )
  154. DestroyWindow hwnd
  155. Return Null
  156. EndIf
  157. _hwnd=hwnd
  158. _width=width
  159. _height=height
  160. _depth=depth
  161. _hertz=hertz
  162. _flags=flags
  163. Return Self
  164. End Method
  165. Method GetDirect3DDevice:IDirect3DDevice9()
  166. Return _d3dDev
  167. End Method
  168. Method ValidateSize()
  169. If _attached
  170. Local rect:Int[4]
  171. GetClientRect _hwnd,rect
  172. _width=rect[2]-rect[0]
  173. _height=rect[3]-rect[1]
  174. If _width>_presentParams.BackBufferWidth Or _height>_presentParams.BackBufferHeight
  175. _presentParams.BackBufferWidth = Max( _width,_presentParams.BackBufferWidth)
  176. _presentParams.BackBufferHeight = Max( _height,_presentParams.BackbufferHeight)
  177. ResetD3DDevice
  178. EndIf
  179. EndIf
  180. End Method
  181. 'NOTE: Returns 1 if flip was successful, otherwise device lost or reset...
  182. Method Flip:Int( sync:Int )
  183. Local reset:Int
  184. If sync sync=D3DPRESENT_INTERVAL_ONE Else sync=D3DPRESENT_INTERVAL_IMMEDIATE
  185. If sync<>_presentParams.PresentationInterval
  186. _presentParams.PresentationInterval = sync
  187. reset=True
  188. EndIf
  189. Select _d3dDev.TestCooperativeLevel()
  190. Case D3DERR_DRIVERINTERNALERROR
  191. Throw "D3D Internal Error"
  192. Case D3D_OK
  193. If reset
  194. ResetD3DDevice
  195. Else If _attached
  196. Local rect:Int[]=[0,0,_width,_height]
  197. Return _d3dDev.Present( rect,rect,_hwnd,Null )>=0
  198. Else
  199. Return _d3dDev.Present( Null,Null,_hwnd,Null )>=0
  200. EndIf
  201. Case D3DERR_DEVICENOTRESET
  202. ResetD3DDevice
  203. End Select
  204. End Method
  205. Method Driver:TGraphicsDriver() Override
  206. Return _driver
  207. End Method
  208. Method GetSettings:Int( width:Int Var,height:Int Var,depth:Int Var,hertz:Int Var,flags:Int Var ) Override
  209. '
  210. ValidateSize
  211. '
  212. width=_width
  213. height=_height
  214. depth=_depth
  215. hertz=_hertz
  216. flags=_flags
  217. End Method
  218. Method Close:Int() Override
  219. If Not _hwnd Return False
  220. CloseD3DDevice
  221. If Not _attached DestroyWindow( _hwnd )
  222. _hwnd=0
  223. End Method
  224. Method AutoRelease( unk:IUnknown_ )
  225. Local t:TD3D9AutoRelease=New TD3D9AutoRelease
  226. t.unk=unk
  227. _autoRelease.AddLast t
  228. End Method
  229. Method ReleaseNow( unk:IUnknown_ )
  230. For Local t:TD3D9AutoRelease=EachIn _autoRelease
  231. If t.unk=unk
  232. unk.Release_
  233. _autoRelease.Remove t
  234. Return
  235. EndIf
  236. Next
  237. End Method
  238. Field _hwnd:Byte Ptr
  239. Field _width:Int
  240. Field _height:Int
  241. Field _depth:Int
  242. Field _hertz:Int
  243. Field _flags:Int
  244. Field _attached:Int
  245. End Type
  246. Type TD3D9GraphicsDriver Extends TGraphicsDriver
  247. Method Create:TD3D9GraphicsDriver()
  248. 'create d3d9
  249. 'If Not d3d9Lib Return Null
  250. _d3d=Direct3DCreate9( 32 )
  251. If Not _d3d Return Null
  252. 'get caps
  253. '_d3dCaps=New D3DCAPS9
  254. If _d3d.GetDeviceCaps( D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,_d3dCaps)<0
  255. _d3d.Release_
  256. _d3d=Null
  257. Return Null
  258. EndIf
  259. 'enum graphics modes
  260. Local n:Int=_d3d.GetAdapterModeCount( D3DADAPTER_DEFAULT,D3DFMT_X8R8G8B8 )
  261. _modes=New TGraphicsMode[n]
  262. Local j:Int
  263. Local d3dmode:D3DDISPLAYMODE' = New D3DDISPLAYMODE
  264. For Local i:Int=0 Until n
  265. If _d3d.EnumAdapterModes( D3DADAPTER_DEFAULT,D3DFMT_X8R8G8B8,i,d3dmode)<0
  266. Continue
  267. EndIf
  268. Local Mode:TGraphicsMode=New TGraphicsMode
  269. Mode.width=d3dmode.Width
  270. Mode.height=d3dmode.Height
  271. Mode.hertz=d3dmode.RefreshRate
  272. Mode.depth=32
  273. _modes[j]=Mode
  274. j:+1
  275. Next
  276. _modes=_modes[..j]
  277. Local name:Short Ptr = _wndClass.ToWString()
  278. 'register wndclass
  279. Local wndclass:WNDCLASSW=New WNDCLASSW
  280. wndclass.SethInstance(GetModuleHandleW( Null ))
  281. wndclass.SetlpfnWndProc(D3D9WndProc)
  282. wndclass.SethCursor(LoadCursorW( Null,Short Ptr IDC_ARROW ))
  283. wndclass.SetlpszClassName(name)
  284. RegisterClassW wndclass.classPtr
  285. MemFree name
  286. Return Self
  287. End Method
  288. Method GraphicsModes:TGraphicsMode[]() Override
  289. Return _modes
  290. End Method
  291. Method AttachGraphics:TD3D9Graphics( widget:Byte Ptr,flags:Int ) Override
  292. Return New TD3D9Graphics.Attach( widget:Byte Ptr,flags:Int )
  293. End Method
  294. Method CreateGraphics:TD3D9Graphics( width:Int,height:Int,depth:Int,hertz:Int,flags:Int) Override
  295. Return New TD3D9Graphics.Create( width,height,depth,hertz,flags )
  296. End Method
  297. Method Graphics:TD3D9Graphics()
  298. Return _graphics
  299. End Method
  300. Method SetGraphics( g:TGraphics ) Override
  301. _graphics=TD3D9Graphics( g )
  302. End Method
  303. Method Flip( sync:Int ) Override
  304. Local present:Int = _graphics.Flip(sync)
  305. If UseDX9RenderLagFix Then
  306. Local pixelsdrawn:Int
  307. If _d3dOccQuery
  308. _d3dOccQuery.Issue(1) 'D3DISSUE_END
  309. While _d3dOccQuery.GetData( Varptr pixelsdrawn,4,1 )=1 'D3DGETDATA_FLUSH
  310. If _d3dOccQuery.GetData( Varptr pixelsdrawn,4,1 )<0 Exit
  311. Wend
  312. _d3dOccQuery.Issue(2) 'D3DISSUE_BEGIN
  313. EndIf
  314. End If
  315. Return present
  316. End Method
  317. Method GetDirect3D:IDirect3D9()
  318. Return _d3d
  319. End Method
  320. End Type
  321. Function D3D9GraphicsDriver:TD3D9GraphicsDriver()
  322. Global _done:Int
  323. If Not _done
  324. _driver=New TD3D9GraphicsDriver.Create()
  325. _done=True
  326. EndIf
  327. Return _driver
  328. End Function