1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
19 #include "VideoConfig.h"
21 #include "XFStructs.h"
26 LPDIRECT3D9 D3D
= NULL
; // Used to create the D3DDevice
27 LPDIRECT3DDEVICE9 dev
= NULL
; // Our rendering device
28 LPDIRECT3DSURFACE9 back_buffer
;
29 LPDIRECT3DSURFACE9 back_buffer_z
;
33 static int multisample
;
34 static int resolution
;
35 static int xres
, yres
;
36 static bool auto_depth_stencil
= false;
38 #define VENDOR_NVIDIA 4318
39 #define VENDOR_ATI 4098
41 bool bFrameInProgress
= false;
43 #define MAX_ADAPTERS 4
44 static Adapter adapters
[MAX_ADAPTERS
];
45 static int numAdapters
;
46 static int cur_adapter
;
48 // Value caches for state filtering
49 const int MaxTextureStages
= 9;
50 const int MaxRenderStates
= 210 + 46;
51 const int MaxTextureTypes
= 33;
52 const int MaxSamplerSize
= 13;
53 const int MaxSamplerTypes
= 15;
54 static bool m_RenderStatesSet
[MaxRenderStates
];
55 static DWORD m_RenderStates
[MaxRenderStates
];
56 static bool m_RenderStatesChanged
[MaxRenderStates
];
58 static DWORD m_TextureStageStates
[MaxTextureStages
][MaxTextureTypes
];
59 static bool m_TextureStageStatesSet
[MaxTextureStages
][MaxTextureTypes
];
60 static bool m_TextureStageStatesChanged
[MaxTextureStages
][MaxTextureTypes
];
62 static DWORD m_SamplerStates
[MaxSamplerSize
][MaxSamplerTypes
];
63 static bool m_SamplerStatesSet
[MaxSamplerSize
][MaxSamplerTypes
];
64 static bool m_SamplerStatesChanged
[MaxSamplerSize
][MaxSamplerTypes
];
66 LPDIRECT3DBASETEXTURE9 m_Textures
[16];
67 LPDIRECT3DVERTEXDECLARATION9 m_VtxDecl
;
68 LPDIRECT3DPIXELSHADER9 m_PixelShader
;
69 LPDIRECT3DVERTEXSHADER9 m_VertexShader
;
73 int GetNumAdapters() { return numAdapters
; }
74 const Adapter
&GetAdapter(int i
) { return adapters
[i
]; }
75 const Adapter
&GetCurAdapter() { return adapters
[cur_adapter
]; }
79 return GetCurAdapter().ident
.VendorId
== VENDOR_ATI
;
85 // Create the D3D object, which is needed to create the D3DDevice.
86 D3D
= Direct3DCreate9(D3D_SDK_VERSION
);
99 void EnableAlphaToCoverage()
101 // Each vendor has their own specific little hack.
102 if (GetCurAdapter().ident
.VendorId
== VENDOR_ATI
)
103 D3D::SetRenderState(D3DRS_POINTSIZE
, (D3DFORMAT
)MAKEFOURCC('A', '2', 'M', '1'));
105 D3D::SetRenderState(D3DRS_ADAPTIVETESS_Y
, (D3DFORMAT
)MAKEFOURCC('A', 'T', 'O', 'C'));
108 void InitPP(int adapter
, int f
, int aa_mode
, D3DPRESENT_PARAMETERS
*pp
)
110 ZeroMemory(pp
, sizeof(D3DPRESENT_PARAMETERS
));
111 pp
->hDeviceWindow
= hWnd
;
112 if (auto_depth_stencil
)
114 pp
->EnableAutoDepthStencil
= TRUE
;
115 pp
->AutoDepthStencilFormat
= D3DFMT_D24S8
;
117 pp
->EnableAutoDepthStencil
= FALSE
;
118 pp
->AutoDepthStencilFormat
= D3DFMT_UNKNOWN
;
120 pp
->BackBufferFormat
= D3DFMT_A8R8G8B8
;
121 if (aa_mode
>= (int)adapters
[adapter
].aa_levels
.size())
124 pp
->MultiSampleType
= adapters
[adapter
].aa_levels
[aa_mode
].ms_setting
;
125 pp
->MultiSampleQuality
= adapters
[adapter
].aa_levels
[aa_mode
].qual_setting
;
127 pp
->Flags
= auto_depth_stencil
? D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
: 0;
130 GetClientRect(hWnd
, &client
);
131 xres
= pp
->BackBufferWidth
= client
.right
- client
.left
;
132 yres
= pp
->BackBufferHeight
= client
.bottom
- client
.top
;
133 pp
->SwapEffect
= D3DSWAPEFFECT_DISCARD
;
134 pp
->PresentationInterval
= g_Config
.bVSync
? D3DPRESENT_INTERVAL_DEFAULT
: D3DPRESENT_INTERVAL_IMMEDIATE
;
140 numAdapters
= D3D::D3D
->GetAdapterCount();
142 for (int i
= 0; i
< std::min(MAX_ADAPTERS
, numAdapters
); i
++)
144 Adapter
&a
= adapters
[i
];
146 a
.resolutions
.clear();
147 D3D::D3D
->GetAdapterIdentifier(i
, 0, &a
.ident
);
148 bool isNvidia
= a
.ident
.VendorId
== VENDOR_NVIDIA
;
150 // Add SuperSamples modes
151 a
.aa_levels
.push_back(AALevel("None", D3DMULTISAMPLE_NONE
, 0));
152 a
.aa_levels
.push_back(AALevel("2.25x SSAA", D3DMULTISAMPLE_NONE
, 0));
153 a
.aa_levels
.push_back(AALevel("4x SSAA", D3DMULTISAMPLE_NONE
, 0));
154 a
.aa_levels
.push_back(AALevel("9x SSAA", D3DMULTISAMPLE_NONE
, 0));
155 //Add multisample modes
156 //disable them will they are not implemnted
159 if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType(
160 i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_2_SAMPLES, &qlevels))
162 a.aa_levels.push_back(AALevel("2x MSAA", D3DMULTISAMPLE_2_SAMPLES, 0));
164 if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType(
165 i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_2_SAMPLES, &qlevels))
167 a.aa_levels.push_back(AALevel("4x MSAA", D3DMULTISAMPLE_4_SAMPLES, 0));
169 if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType(
170 i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_8_SAMPLES, &qlevels))
172 a.aa_levels.push_back(AALevel("8x MSAA", D3DMULTISAMPLE_8_SAMPLES, 0));
177 if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType(
178 i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_4_SAMPLES, &qlevels))
182 // 8x, 8xQ are available
183 // See http://developer.nvidia.com/object/coverage-sampled-aa.html
184 a.aa_levels.push_back(AALevel("8x CSAA", D3DMULTISAMPLE_4_SAMPLES, 2));
185 a.aa_levels.push_back(AALevel("8xQ CSAA", D3DMULTISAMPLE_8_SAMPLES, 0));
188 if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType(
189 i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_8_SAMPLES, &qlevels))
193 // 16x, 16xQ are available
194 // See http://developer.nvidia.com/object/coverage-sampled-aa.html
195 a.aa_levels.push_back(AALevel("16x CSAA", D3DMULTISAMPLE_4_SAMPLES, 4));
196 a.aa_levels.push_back(AALevel("16xQ CSAA", D3DMULTISAMPLE_8_SAMPLES, 2));
201 // Determine if INTZ is supported. Code from ATI's doc.
202 // http://developer.amd.com/gpu_assets/Advanced%20DX9%20Capabilities%20for%20ATI%20Radeon%20Cards.pdf
203 a
.supports_intz
= D3D_OK
== D3D
->CheckDeviceFormat(
204 i
, D3DDEVTYPE_HAL
, D3DFMT_X8R8G8B8
,
205 D3DUSAGE_DEPTHSTENCIL
, D3DRTYPE_TEXTURE
, FOURCC_INTZ
);
206 // Also check for RAWZ (nvidia only, but the only option to get Z24 textures on sub GF8800
207 a
.supports_rawz
= D3D_OK
== D3D
->CheckDeviceFormat(
208 i
, D3DDEVTYPE_HAL
, D3DFMT_X8R8G8B8
,
209 D3DUSAGE_DEPTHSTENCIL
, D3DRTYPE_TEXTURE
, FOURCC_RAWZ
);
210 // Might as well check for RESZ and NULL too.
211 a
.supports_resz
= D3D_OK
== D3D
->CheckDeviceFormat(
212 i
, D3DDEVTYPE_HAL
, D3DFMT_X8R8G8B8
,
213 D3DUSAGE_DEPTHSTENCIL
, D3DRTYPE_TEXTURE
, FOURCC_RESZ
);
214 a
.supports_null
= D3D_OK
== D3D
->CheckDeviceFormat(
215 i
, D3DDEVTYPE_HAL
, D3DFMT_X8R8G8B8
,
216 D3DUSAGE_DEPTHSTENCIL
, D3DRTYPE_TEXTURE
, FOURCC_NULL
);
218 if (a
.aa_levels
.size() == 1)
220 strcpy(a
.aa_levels
[0].name
, "(Not supported on this device)");
222 int numModes
= D3D::D3D
->GetAdapterModeCount(i
, D3DFMT_X8R8G8B8
);
223 for (int m
= 0; m
< numModes
; m
++)
226 D3D::D3D
->EnumAdapterModes(i
, D3DFMT_X8R8G8B8
, m
, &mode
);
229 for (int x
= 0; x
< (int)a
.resolutions
.size(); x
++)
231 if (a
.resolutions
[x
].xres
== mode
.Width
&& a
.resolutions
[x
].yres
== mode
.Height
)
239 Resolution
&r
= found
==-1 ? temp
: a
.resolutions
[found
];
241 sprintf(r
.name
, "%ix%i", mode
.Width
, mode
.Height
);
242 r
.bitdepths
.insert(mode
.Format
);
243 r
.refreshes
.insert(mode
.RefreshRate
);
244 if (found
== -1 && mode
.Width
>= 640 && mode
.Height
>= 480)
247 r
.yres
= mode
.Height
;
248 a
.resolutions
.push_back(r
);
254 HRESULT
Create(int adapter
, HWND wnd
, int _resolution
, int aa_mode
, bool auto_depth
)
257 multisample
= aa_mode
;
258 resolution
= _resolution
;
259 auto_depth_stencil
= auto_depth
;
260 cur_adapter
= adapter
;
261 D3DPRESENT_PARAMETERS d3dpp
;
262 InitPP(adapter
, resolution
, aa_mode
, &d3dpp
);
264 if (FAILED(D3D
->CreateDevice(
268 D3DCREATE_HARDWARE_VERTEXPROCESSING
| D3DCREATE_PUREDEVICE
, //doesn't seem to make a difference
271 if (FAILED(D3D
->CreateDevice(
275 D3DCREATE_SOFTWARE_VERTEXPROCESSING
,
279 _T("Failed to initialize Direct3D."),
280 _T("Dolphin Direct3D plugin"), MB_OK
| MB_ICONERROR
);
285 dev
->GetDeviceCaps(&caps
);
286 dev
->GetRenderTarget(0, &back_buffer
);
287 if (dev
->GetDepthStencilSurface(&back_buffer_z
) == D3DERR_NOTFOUND
)
288 back_buffer_z
= NULL
;
289 D3D::SetRenderState(D3DRS_ZENABLE
, D3DZB_TRUE
);
290 D3D::SetRenderState(D3DRS_FILLMODE
, g_Config
.bWireFrame
? D3DFILL_WIREFRAME
: D3DFILL_SOLID
);
291 memset(m_Textures
, 0, sizeof(m_Textures
));
292 memset(m_TextureStageStatesSet
, 0, sizeof(m_TextureStageStatesSet
));
293 memset(m_RenderStatesSet
, 0, sizeof(m_RenderStatesSet
));
294 memset(m_SamplerStatesSet
, 0, sizeof(m_SamplerStatesSet
));
295 memset(m_TextureStageStatesChanged
, 0, sizeof(m_TextureStageStatesChanged
));
296 memset(m_RenderStatesChanged
, 0, sizeof(m_RenderStatesChanged
));
297 memset(m_SamplerStatesChanged
, 0, sizeof(m_SamplerStatesChanged
));
299 m_PixelShader
= NULL
;
300 m_VertexShader
= NULL
;
301 // Device state would normally be set here
308 back_buffer_z
->Release();
309 back_buffer_z
= NULL
;
310 back_buffer
->Release();
313 ULONG references
= dev
->Release();
315 ERROR_LOG(VIDEO
, "Unreleased references: %i.", references
);
320 const D3DCAPS9
&GetCaps()
325 const char *VertexShaderVersionString()
327 static const char *versions
[5] = {"ERROR", "vs_1_4", "vs_2_0", "vs_3_0", "vs_4_0"};
328 int version
= ((D3D::caps
.VertexShaderVersion
>> 8) & 0xFF);
329 return versions
[std::min(4, version
)];
332 const char *PixelShaderVersionString()
334 static const char *versions
[5] = {"ERROR", "ps_1_4", "ps_2_0", "ps_3_0", "ps_4_0"};
335 int version
= ((D3D::caps
.PixelShaderVersion
>> 8) & 0xFF);
336 return versions
[std::min(4, version
)];
339 LPDIRECT3DSURFACE9
GetBackBufferSurface()
344 LPDIRECT3DSURFACE9
GetBackBufferDepthSurface()
346 return back_buffer_z
;
349 void ShowD3DError(HRESULT err
)
353 case D3DERR_DEVICELOST
: PanicAlert("Device Lost"); break;
354 case D3DERR_INVALIDCALL
: PanicAlert("Invalid Call"); break;
355 case D3DERR_DRIVERINTERNALERROR
: PanicAlert("Driver Internal Error"); break;
356 case D3DERR_OUTOFVIDEOMEMORY
: PanicAlert("Out of vid mem"); break;
358 // MessageBoxA(0,"Other error or success","ERROR",0);
367 // ForgetCachedState();
369 // Can't keep a pointer around to the backbuffer surface when resetting.
371 back_buffer_z
->Release();
372 back_buffer_z
= NULL
;
373 back_buffer
->Release();
376 D3DPRESENT_PARAMETERS d3dpp
;
377 InitPP(cur_adapter
, resolution
, multisample
, &d3dpp
);
378 HRESULT hr
= dev
->Reset(&d3dpp
);
381 dev
->GetRenderTarget(0, &back_buffer
);
382 if (dev
->GetDepthStencilSurface(&back_buffer_z
) == D3DERR_NOTFOUND
)
383 back_buffer_z
= NULL
;
388 int GetBackBufferWidth()
393 int GetBackBufferHeight()
400 if (bFrameInProgress
)
402 PanicAlert("BeginFrame WTF");
405 bFrameInProgress
= true;
417 if (!bFrameInProgress
)
419 PanicAlert("EndFrame WTF");
422 bFrameInProgress
= false;
430 dev
->Present(NULL
, NULL
, NULL
, NULL
);
434 void ApplyCachedState()
436 for (int sampler
= 0; sampler
< 8; sampler
++)
438 for (int type
= 0; type
< MaxSamplerTypes
; type
++)
440 if(m_SamplerStatesSet
[sampler
][type
])
441 D3D::dev
->SetSamplerState(sampler
, (D3DSAMPLERSTATETYPE
)type
, m_SamplerStates
[sampler
][type
]);
445 for (int rs
= 0; rs
< MaxRenderStates
; rs
++)
447 if (m_RenderStatesSet
[rs
])
448 D3D::dev
->SetRenderState((D3DRENDERSTATETYPE
)rs
, m_RenderStates
[rs
]);
451 // We don't bother restoring these so let's just wipe the state copy
452 // so no stale state is around.
453 memset(m_Textures
, 0, sizeof(m_Textures
));
454 memset(m_TextureStageStatesSet
, 0, sizeof(m_TextureStageStatesSet
));
455 memset(m_TextureStageStatesChanged
, 0, sizeof(m_TextureStageStatesChanged
));
457 m_PixelShader
= NULL
;
458 m_VertexShader
= NULL
;
461 void SetTexture(DWORD Stage
, LPDIRECT3DBASETEXTURE9 pTexture
)
463 if (m_Textures
[Stage
] != pTexture
)
465 m_Textures
[Stage
] = pTexture
;
466 D3D::dev
->SetTexture(Stage
, pTexture
);
470 void RefreshRenderState(D3DRENDERSTATETYPE State
)
472 if(m_RenderStatesSet
[State
] && m_RenderStatesChanged
[State
])
474 D3D::dev
->SetRenderState(State
, m_RenderStates
[State
]);
475 m_RenderStatesChanged
[State
] = false;
479 void SetRenderState(D3DRENDERSTATETYPE State
, DWORD Value
)
481 if (m_RenderStates
[State
] != Value
|| !m_RenderStatesSet
[State
])
483 m_RenderStates
[State
] = Value
;
484 m_RenderStatesSet
[State
] = true;
485 m_RenderStatesChanged
[State
] = false;
486 D3D::dev
->SetRenderState(State
, Value
);
490 void ChangeRenderState(D3DRENDERSTATETYPE State
, DWORD Value
)
492 if (m_RenderStates
[State
] != Value
|| !m_RenderStatesSet
[State
])
494 m_RenderStatesChanged
[State
] = m_RenderStatesSet
[State
];
495 D3D::dev
->SetRenderState(State
, Value
);
499 m_RenderStatesChanged
[State
] = false;
503 void SetTextureStageState(DWORD Stage
, D3DTEXTURESTAGESTATETYPE Type
, DWORD Value
)
505 if (m_TextureStageStates
[Stage
][Type
] != Value
|| !m_TextureStageStatesSet
[Stage
][Type
])
507 m_TextureStageStates
[Stage
][Type
] = Value
;
508 m_TextureStageStatesSet
[Stage
][Type
]=true;
509 m_TextureStageStatesChanged
[Stage
][Type
]=false;
510 D3D::dev
->SetTextureStageState(Stage
, Type
, Value
);
514 void RefreshTextureStageState(DWORD Stage
, D3DTEXTURESTAGESTATETYPE Type
)
516 if(m_TextureStageStatesSet
[Stage
][Type
] && m_TextureStageStatesChanged
[Stage
][Type
])
518 D3D::dev
->SetTextureStageState(Stage
, Type
, m_TextureStageStates
[Stage
][Type
]);
519 m_TextureStageStatesChanged
[Stage
][Type
] = false;
523 void ChangeTextureStageState(DWORD Stage
, D3DTEXTURESTAGESTATETYPE Type
, DWORD Value
)
525 if (m_TextureStageStates
[Stage
][Type
] != Value
|| !m_TextureStageStatesSet
[Stage
][Type
])
527 m_TextureStageStatesChanged
[Stage
][Type
] = m_TextureStageStatesSet
[Stage
][Type
];
528 D3D::dev
->SetTextureStageState(Stage
, Type
, Value
);
532 m_TextureStageStatesChanged
[Stage
][Type
] = false;
536 void SetSamplerState(DWORD Sampler
, D3DSAMPLERSTATETYPE Type
, DWORD Value
)
538 if (m_SamplerStates
[Sampler
][Type
] != Value
|| !m_SamplerStatesSet
[Sampler
][Type
])
540 m_SamplerStates
[Sampler
][Type
] = Value
;
541 m_SamplerStatesSet
[Sampler
][Type
] = true;
542 m_SamplerStatesChanged
[Sampler
][Type
] = false;
543 D3D::dev
->SetSamplerState(Sampler
, Type
, Value
);
547 void RefreshSamplerState(DWORD Sampler
, D3DSAMPLERSTATETYPE Type
)
549 if(m_SamplerStatesSet
[Sampler
][Type
] && m_SamplerStatesChanged
[Sampler
][Type
])
551 D3D::dev
->SetSamplerState(Sampler
, Type
, m_SamplerStates
[Sampler
][Type
]);
552 m_SamplerStatesChanged
[Sampler
][Type
] = false;
556 void ChangeSamplerState(DWORD Sampler
, D3DSAMPLERSTATETYPE Type
, DWORD Value
)
558 if (m_SamplerStates
[Sampler
][Type
] != Value
|| !m_SamplerStatesSet
[Sampler
][Type
])
560 m_SamplerStatesChanged
[Sampler
][Type
] = m_SamplerStatesSet
[Sampler
][Type
];
561 D3D::dev
->SetSamplerState(Sampler
, Type
, Value
);
565 m_SamplerStatesChanged
[Sampler
][Type
] = false;
569 void RefreshVertexDeclaration()
573 D3D::dev
->SetVertexDeclaration(m_VtxDecl
);
577 void SetVertexDeclaration(LPDIRECT3DVERTEXDECLARATION9 decl
)
583 if (decl
!= m_VtxDecl
)
585 D3D::dev
->SetVertexDeclaration(decl
);
590 void RefreshVertexShader()
594 D3D::dev
->SetVertexShader(m_VertexShader
);
598 void SetVertexShader(LPDIRECT3DVERTEXSHADER9 shader
)
601 m_VertexShader
= NULL
;
604 if (shader
!= m_VertexShader
)
606 D3D::dev
->SetVertexShader(shader
);
607 m_VertexShader
= shader
;
611 void RefreshPixelShader()
615 D3D::dev
->SetPixelShader(m_PixelShader
);
619 void SetPixelShader(LPDIRECT3DPIXELSHADER9 shader
)
622 m_PixelShader
= NULL
;
625 if (shader
!= m_PixelShader
)
627 D3D::dev
->SetPixelShader(shader
);
628 m_PixelShader
= shader
;