1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
6 
7 Copyright (c) 2000-2014 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 #include "OgreD3D11Device.h"
29 #include "OgreException.h"
30 
31 namespace Ogre
32 {
33     //---------------------------------------------------------------------
34     D3D11Device::eExceptionsErrorLevel D3D11Device::mExceptionsErrorLevel = D3D11Device::D3D_NO_EXCEPTION;
35     //---------------------------------------------------------------------
D3D11Device()36     D3D11Device::D3D11Device()
37     {
38         mDriverVersion.QuadPart = 0;
39     }
40     //---------------------------------------------------------------------
~D3D11Device()41     D3D11Device::~D3D11Device()
42     {
43         ReleaseAll();
44     }
45     //---------------------------------------------------------------------
ReleaseAll()46     void D3D11Device::ReleaseAll()
47     {
48         // Clear state
49         if (mImmediateContext)
50         {
51             mImmediateContext->Flush();
52             mImmediateContext->ClearState();
53         }
54 #if OGRE_D3D11_PROFILING
55         mPerf.Reset();
56 #endif
57         mInfoQueue.Reset();
58         mClassLinkage.Reset();
59         mImmediateContext.Reset();
60         mD3D11Device.Reset();
61         mDXGIFactory.Reset();
62         mDriverVersion.QuadPart = 0;
63     }
64     //---------------------------------------------------------------------
TransferOwnership(ID3D11DeviceN * d3d11device)65     void D3D11Device::TransferOwnership(ID3D11DeviceN* d3d11device)
66     {
67         assert(mD3D11Device.Get() != d3d11device);
68         ReleaseAll();
69 
70         if (d3d11device)
71         {
72             HRESULT hr = S_OK;
73 
74             mD3D11Device.Attach(d3d11device);
75 
76             // get DXGI factory from device
77             ComPtr<IDXGIDeviceN> pDXGIDevice;
78             ComPtr<IDXGIAdapterN> pDXGIAdapter;
79             if(SUCCEEDED(mD3D11Device.As(&pDXGIDevice))
80             && SUCCEEDED(pDXGIDevice->GetParent(__uuidof(IDXGIAdapterN), (void **)pDXGIAdapter.GetAddressOf())))
81             {
82                 pDXGIAdapter->GetParent(__uuidof(IDXGIFactoryN), (void **)mDXGIFactory.ReleaseAndGetAddressOf());
83 
84                 // We intentionally check for ID3D10Device support instead of ID3D11Device as CheckInterfaceSupport() is not supported for later.
85                 // We hope, that there would be one UMD for both D3D10 and D3D11, or two different but with the same version number,
86                 // or with different but correlated version numbers, so that blacklisting could be done with high confidence level.
87                 if(FAILED(pDXGIAdapter->CheckInterfaceSupport(IID_ID3D10Device /* intentionally D3D10, not D3D11 */, &mDriverVersion)))
88                     mDriverVersion.QuadPart = 0;
89             }
90 
91 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
92             mD3D11Device->GetImmediateContext(mImmediateContext.ReleaseAndGetAddressOf());
93 #elif OGRE_PLATFORM == OGRE_PLATFORM_WINRT
94             mD3D11Device->GetImmediateContext1(mImmediateContext.ReleaseAndGetAddressOf());
95 #endif
96 
97 #if OGRE_D3D11_PROFILING
98             hr = mImmediateContext.As(&mPerf);
99             if(FAILED(hr) || !mPerf->GetStatus())
100                 mPerf.Reset();
101 #endif
102 
103             hr = mD3D11Device.As(&mInfoQueue);
104             if (SUCCEEDED(hr))
105             {
106                 mInfoQueue->ClearStoredMessages();
107                 mInfoQueue->ClearRetrievalFilter();
108                 mInfoQueue->ClearStorageFilter();
109 
110                 D3D11_INFO_QUEUE_FILTER filter;
111                 ZeroMemory(&filter, sizeof(D3D11_INFO_QUEUE_FILTER));
112                 std::vector<D3D11_MESSAGE_SEVERITY> severityList;
113 
114                 switch(mExceptionsErrorLevel)
115                 {
116                 case D3D_NO_EXCEPTION:
117                     severityList.push_back(D3D11_MESSAGE_SEVERITY_CORRUPTION);
118                 case D3D_CORRUPTION:
119                     severityList.push_back(D3D11_MESSAGE_SEVERITY_ERROR);
120                 case D3D_ERROR:
121                     severityList.push_back(D3D11_MESSAGE_SEVERITY_WARNING);
122                 case D3D_WARNING:
123                 case D3D_INFO:
124                     severityList.push_back(D3D11_MESSAGE_SEVERITY_INFO);
125                 default:
126                     break;
127                 }
128 
129 
130                 if (severityList.size() > 0)
131                 {
132                     filter.DenyList.NumSeverities = severityList.size();
133                     filter.DenyList.pSeverityList = &severityList[0];
134                 }
135 
136                 mInfoQueue->AddStorageFilterEntries(&filter);
137                 mInfoQueue->AddRetrievalFilterEntries(&filter);
138             }
139 
140             // If feature level is 11, create class linkage
141             if (mD3D11Device->GetFeatureLevel() == D3D_FEATURE_LEVEL_11_0)
142             {
143                 hr = mD3D11Device->CreateClassLinkage(mClassLinkage.ReleaseAndGetAddressOf());
144             }
145         }
146     }
147     //---------------------------------------------------------------------
throwIfFailed(HRESULT hr,const char * desc,const char * src)148     void D3D11Device::throwIfFailed(HRESULT hr, const char* desc, const char* src)
149     {
150         if(FAILED(hr) || isError())
151         {
152             String description = std::string(desc).append("\nError Description:").append(getErrorDescription(hr));
153             OGRE_EXCEPT_EX(Exception::ERR_RENDERINGAPI_ERROR, hr, description, src);
154         }
155     }
156     //---------------------------------------------------------------------
getErrorDescription(const HRESULT lastResult) const157     String D3D11Device::getErrorDescription(const HRESULT lastResult /* = NO_ERROR */) const
158     {
159         if (!mD3D11Device)
160         {
161             return "NULL device";
162         }
163 
164         if (D3D_NO_EXCEPTION == mExceptionsErrorLevel)
165         {
166             return "infoQ exceptions are turned off";
167         }
168 
169         String res;
170 
171         switch (lastResult)
172         {
173         case NO_ERROR:
174             break;
175         case E_INVALIDARG:
176             res.append("invalid parameters were passed.\n");
177             break;
178         default:
179             res = StringUtil::format("hr = 0x%08X\n", lastResult);
180         }
181 
182         if (mInfoQueue)
183         {
184             UINT64 numStoredMessages = mInfoQueue->GetNumStoredMessages();
185             for (UINT64 i = 0 ; i < numStoredMessages ; i++ )
186             {
187                 // Get the size of the message
188                 SIZE_T messageLength = 0;
189                 mInfoQueue->GetMessage(i, NULL, &messageLength);
190                 // Allocate space and get the message
191                 D3D11_MESSAGE * pMessage = (D3D11_MESSAGE*)malloc(messageLength);
192                 mInfoQueue->GetMessage(i, pMessage, &messageLength);
193                 res = res + pMessage->pDescription + "\n";
194                 free(pMessage);
195             }
196         }
197 
198         return res;
199     }
200     //---------------------------------------------------------------------
_getErrorsFromQueue() const201     bool D3D11Device::_getErrorsFromQueue() const
202     {
203         if (mInfoQueue)
204         {
205             UINT64 numStoredMessages = mInfoQueue->GetNumStoredMessages();
206 
207             if (D3D_INFO == mExceptionsErrorLevel && numStoredMessages > 0)
208             {
209                 // if D3D_INFO we don't need to loop if the numStoredMessages > 0
210                 return true;
211             }
212             for (UINT64 i = 0 ; i < numStoredMessages ; i++ )
213             {
214                 // Get the size of the message
215                 SIZE_T messageLength = 0;
216                 mInfoQueue->GetMessage(i, NULL, &messageLength);
217                 // Allocate space and get the message
218                 D3D11_MESSAGE * pMessage = (D3D11_MESSAGE*)malloc(messageLength);
219                 mInfoQueue->GetMessage(i, pMessage, &messageLength);
220 
221                 bool res = false;
222                 switch(pMessage->Severity)
223                 {
224                 case D3D11_MESSAGE_SEVERITY_CORRUPTION:
225                     if (D3D_CORRUPTION == mExceptionsErrorLevel)
226                     {
227                         res = true;
228                     }
229                     break;
230                 case D3D11_MESSAGE_SEVERITY_ERROR:
231                     switch(mExceptionsErrorLevel)
232                     {
233                     case D3D_INFO:
234                     case D3D_WARNING:
235                     case D3D_ERROR:
236                         res = true;
237                     }
238                     break;
239                 case D3D11_MESSAGE_SEVERITY_WARNING:
240                     switch(mExceptionsErrorLevel)
241                     {
242                     case D3D_INFO:
243                     case D3D_WARNING:
244                         res = true;
245                     }
246                     break;
247                 }
248 
249                 free(pMessage);
250                 if (res)
251                 {
252                     // we don't need to loop anymore...
253                     return true;
254                 }
255 
256             }
257 
258             clearStoredErrorMessages();
259 
260             return false;
261 
262         }
263         else
264         {
265             return false;
266         }
267     }
268     //---------------------------------------------------------------------
clearStoredErrorMessages() const269     void D3D11Device::clearStoredErrorMessages() const
270     {
271         if (mD3D11Device && D3D_NO_EXCEPTION != mExceptionsErrorLevel)
272         {
273             if (mInfoQueue)
274             {
275                 mInfoQueue->ClearStoredMessages();
276             }
277         }
278     }
279     //---------------------------------------------------------------------
getExceptionsErrorLevel()280     const D3D11Device::eExceptionsErrorLevel D3D11Device::getExceptionsErrorLevel()
281     {
282         return mExceptionsErrorLevel;
283     }
284     //---------------------------------------------------------------------
setExceptionsErrorLevel(const eExceptionsErrorLevel exceptionsErrorLevel)285     void D3D11Device::setExceptionsErrorLevel( const eExceptionsErrorLevel exceptionsErrorLevel )
286     {
287         mExceptionsErrorLevel = exceptionsErrorLevel;
288     }
289     //---------------------------------------------------------------------
setExceptionsErrorLevel(const Ogre::String & exceptionsErrorLevel)290     void D3D11Device::setExceptionsErrorLevel( const Ogre::String& exceptionsErrorLevel )
291     {
292         eExceptionsErrorLevel onlyIfDebugMode = OGRE_DEBUG_MODE ? D3D11Device::D3D_ERROR : D3D11Device::D3D_NO_EXCEPTION;
293         if("No information queue exceptions" == exceptionsErrorLevel)       setExceptionsErrorLevel(onlyIfDebugMode);
294         else if("Corruption" == exceptionsErrorLevel)                       setExceptionsErrorLevel(D3D11Device::D3D_CORRUPTION);
295         else if("Error" == exceptionsErrorLevel)                            setExceptionsErrorLevel(D3D11Device::D3D_ERROR);
296         else if("Warning" == exceptionsErrorLevel)                          setExceptionsErrorLevel(D3D11Device::D3D_WARNING);
297         else if("Info (exception on any message)" == exceptionsErrorLevel)  setExceptionsErrorLevel(D3D11Device::D3D_INFO);
298         else                                                                setExceptionsErrorLevel(onlyIfDebugMode);
299     }
300     //---------------------------------------------------------------------
parseFeatureLevel(const Ogre::String & value,D3D_FEATURE_LEVEL fallback)301     D3D_FEATURE_LEVEL D3D11Device::parseFeatureLevel(const Ogre::String& value, D3D_FEATURE_LEVEL fallback)
302     {
303         if(value == "9.1")  return D3D_FEATURE_LEVEL_9_1;
304         if(value == "9.2")  return D3D_FEATURE_LEVEL_9_2;
305         if(value == "9.3")  return D3D_FEATURE_LEVEL_9_3;
306         if(value == "10.0") return D3D_FEATURE_LEVEL_10_0;
307         if(value == "10.1") return D3D_FEATURE_LEVEL_10_1;
308         if(value == "11.0") return D3D_FEATURE_LEVEL_11_0;
309         return fallback;
310     }
311     //---------------------------------------------------------------------
parseDriverType(const Ogre::String & driverTypeName,D3D_DRIVER_TYPE fallback)312     D3D_DRIVER_TYPE D3D11Device::parseDriverType(const Ogre::String& driverTypeName, D3D_DRIVER_TYPE fallback)
313     {
314         if("Hardware" == driverTypeName) return D3D_DRIVER_TYPE_HARDWARE;
315         if("Software" == driverTypeName) return D3D_DRIVER_TYPE_SOFTWARE;
316         if("Warp" == driverTypeName)     return D3D_DRIVER_TYPE_WARP;
317         return fallback;
318     }
319     //---------------------------------------------------------------------
IsDeviceLost()320     bool D3D11Device::IsDeviceLost()
321     {
322         HRESULT hr = mD3D11Device->GetDeviceRemovedReason();
323         if(FAILED(hr))
324             return true;
325         return false;
326     }
327 }