1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // DisplayD3D.cpp: D3D implementation of egl::Display
8
9 #include "libANGLE/renderer/d3d/DisplayD3D.h"
10
11 #include <EGL/eglext.h>
12
13 #include "libANGLE/Config.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/Display.h"
16 #include "libANGLE/Surface.h"
17 #include "libANGLE/Thread.h"
18 #include "libANGLE/histogram_macros.h"
19 #include "libANGLE/renderer/d3d/DeviceD3D.h"
20 #include "libANGLE/renderer/d3d/EGLImageD3D.h"
21 #include "libANGLE/renderer/d3d/RendererD3D.h"
22 #include "libANGLE/renderer/d3d/SurfaceD3D.h"
23 #include "libANGLE/renderer/d3d/SwapChainD3D.h"
24
25 #if defined(ANGLE_ENABLE_D3D9)
26 # include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
27 #endif // ANGLE_ENABLE_D3D9
28
29 #if defined(ANGLE_ENABLE_D3D11)
30 # include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
31 #endif // ANGLE_ENABLE_D3D11
32
33 #if !defined(ANGLE_DEFAULT_D3D11)
34 // Enables use of the Direct3D 11 API for a default display, when available
35 # define ANGLE_DEFAULT_D3D11 1
36 #endif
37
38 namespace rx
39 {
40
41 typedef RendererD3D *(*CreateRendererD3DFunction)(egl::Display *);
42
43 template <typename RendererType>
CreateTypedRendererD3D(egl::Display * display)44 static RendererD3D *CreateTypedRendererD3D(egl::Display *display)
45 {
46 return new RendererType(display);
47 }
48
CreateRendererD3D(egl::Display * display,RendererD3D ** outRenderer)49 egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer)
50 {
51 ASSERT(outRenderer != nullptr);
52
53 std::vector<CreateRendererD3DFunction> rendererCreationFunctions;
54
55 if (display->getPlatform() == EGL_PLATFORM_ANGLE_ANGLE)
56 {
57 const auto &attribMap = display->getAttributeMap();
58 EGLNativeDisplayType nativeDisplay = display->getNativeDisplayId();
59
60 EGLint requestedDisplayType = static_cast<EGLint>(
61 attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE));
62
63 #if defined(ANGLE_ENABLE_D3D11)
64 if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ||
65 nativeDisplay == EGL_D3D11_ONLY_DISPLAY_ANGLE ||
66 requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
67 {
68 rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
69 }
70 #endif
71
72 #if defined(ANGLE_ENABLE_D3D9)
73 if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ||
74 requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE)
75 {
76 rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>);
77 }
78 #endif
79
80 if (nativeDisplay != EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE &&
81 nativeDisplay != EGL_D3D11_ONLY_DISPLAY_ANGLE &&
82 requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)
83 {
84 // The default display is requested, try the D3D9 and D3D11 renderers, order them using
85 // the definition of ANGLE_DEFAULT_D3D11
86 #if ANGLE_DEFAULT_D3D11
87 # if defined(ANGLE_ENABLE_D3D11)
88 rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
89 # endif
90 # if defined(ANGLE_ENABLE_D3D9)
91 rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>);
92 # endif
93 #else
94 # if defined(ANGLE_ENABLE_D3D9)
95 rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>);
96 # endif
97 # if defined(ANGLE_ENABLE_D3D11)
98 rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
99 # endif
100 #endif
101 }
102 }
103 else if (display->getPlatform() == EGL_PLATFORM_DEVICE_EXT)
104 {
105 #if defined(ANGLE_ENABLE_D3D11)
106 if (display->getDevice()->getType() == EGL_D3D11_DEVICE_ANGLE)
107 {
108 rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>);
109 }
110 #endif
111 }
112 else
113 {
114 UNIMPLEMENTED();
115 }
116
117 for (size_t i = 0; i < rendererCreationFunctions.size(); i++)
118 {
119 RendererD3D *renderer = rendererCreationFunctions[i](display);
120 egl::Error result = renderer->initialize();
121
122 #if defined(ANGLE_ENABLE_D3D11)
123 if (renderer->getRendererClass() == RENDERER_D3D11)
124 {
125 ASSERT(result.getID() >= 0 && result.getID() < NUM_D3D11_INIT_ERRORS);
126 ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D11InitializeResult", result.getID(),
127 NUM_D3D11_INIT_ERRORS);
128 }
129 #endif
130
131 #if defined(ANGLE_ENABLE_D3D9)
132 if (renderer->getRendererClass() == RENDERER_D3D9)
133 {
134 ASSERT(result.getID() >= 0 && result.getID() < NUM_D3D9_INIT_ERRORS);
135 ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D9InitializeResult", result.getID(),
136 NUM_D3D9_INIT_ERRORS);
137 }
138 #endif
139
140 if (!result.isError())
141 {
142 *outRenderer = renderer;
143 return result;
144 }
145
146 // Failed to create the renderer, try the next
147 SafeDelete(renderer);
148 ERR() << "Failed to create D3D renderer: " << result.getMessage();
149 }
150
151 return egl::EglNotInitialized() << "No available renderers.";
152 }
153
DisplayD3D(const egl::DisplayState & state)154 DisplayD3D::DisplayD3D(const egl::DisplayState &state) : DisplayImpl(state), mRenderer(nullptr) {}
155
createWindowSurface(const egl::SurfaceState & state,EGLNativeWindowType window,const egl::AttributeMap & attribs)156 SurfaceImpl *DisplayD3D::createWindowSurface(const egl::SurfaceState &state,
157 EGLNativeWindowType window,
158 const egl::AttributeMap &attribs)
159 {
160 ASSERT(mRenderer != nullptr);
161 return new WindowSurfaceD3D(state, mRenderer, mDisplay, window, attribs);
162 }
163
createPbufferSurface(const egl::SurfaceState & state,const egl::AttributeMap & attribs)164 SurfaceImpl *DisplayD3D::createPbufferSurface(const egl::SurfaceState &state,
165 const egl::AttributeMap &attribs)
166 {
167 ASSERT(mRenderer != nullptr);
168 return new PbufferSurfaceD3D(state, mRenderer, mDisplay, 0, nullptr, attribs);
169 }
170
createPbufferFromClientBuffer(const egl::SurfaceState & state,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs)171 SurfaceImpl *DisplayD3D::createPbufferFromClientBuffer(const egl::SurfaceState &state,
172 EGLenum buftype,
173 EGLClientBuffer clientBuffer,
174 const egl::AttributeMap &attribs)
175 {
176 ASSERT(mRenderer != nullptr);
177 return new PbufferSurfaceD3D(state, mRenderer, mDisplay, buftype, clientBuffer, attribs);
178 }
179
createPixmapSurface(const egl::SurfaceState & state,NativePixmapType nativePixmap,const egl::AttributeMap & attribs)180 SurfaceImpl *DisplayD3D::createPixmapSurface(const egl::SurfaceState &state,
181 NativePixmapType nativePixmap,
182 const egl::AttributeMap &attribs)
183 {
184 UNIMPLEMENTED();
185 return nullptr;
186 }
187
createImage(const egl::ImageState & state,const gl::Context * context,EGLenum target,const egl::AttributeMap & attribs)188 ImageImpl *DisplayD3D::createImage(const egl::ImageState &state,
189 const gl::Context *context,
190 EGLenum target,
191 const egl::AttributeMap &attribs)
192 {
193 return new EGLImageD3D(state, target, attribs, mRenderer);
194 }
195
createDevice()196 DeviceImpl *DisplayD3D::createDevice()
197 {
198 return mRenderer->createEGLDevice();
199 }
200
createContext(const gl::State & state,gl::ErrorSet * errorSet,const egl::Config * configuration,const gl::Context * shareContext,const egl::AttributeMap & attribs)201 rx::ContextImpl *DisplayD3D::createContext(const gl::State &state,
202 gl::ErrorSet *errorSet,
203 const egl::Config *configuration,
204 const gl::Context *shareContext,
205 const egl::AttributeMap &attribs)
206 {
207 ASSERT(mRenderer != nullptr);
208 return mRenderer->createContext(state, errorSet);
209 }
210
createStreamProducerD3DTexture(egl::Stream::ConsumerType consumerType,const egl::AttributeMap & attribs)211 StreamProducerImpl *DisplayD3D::createStreamProducerD3DTexture(
212 egl::Stream::ConsumerType consumerType,
213 const egl::AttributeMap &attribs)
214 {
215 ASSERT(mRenderer != nullptr);
216 return mRenderer->createStreamProducerD3DTexture(consumerType, attribs);
217 }
218
createExternalImageSibling(const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const egl::AttributeMap & attribs)219 ExternalImageSiblingImpl *DisplayD3D::createExternalImageSibling(const gl::Context *context,
220 EGLenum target,
221 EGLClientBuffer buffer,
222 const egl::AttributeMap &attribs)
223 {
224 ASSERT(mRenderer != nullptr);
225 return mRenderer->createExternalImageSibling(context, target, buffer, attribs);
226 }
227
createShareGroup()228 ShareGroupImpl *DisplayD3D::createShareGroup()
229 {
230 return new ShareGroupD3D();
231 }
232
makeCurrent(egl::Surface * drawSurface,egl::Surface * readSurface,gl::Context * context)233 egl::Error DisplayD3D::makeCurrent(egl::Surface *drawSurface,
234 egl::Surface *readSurface,
235 gl::Context *context)
236 {
237 return egl::NoError();
238 }
239
initialize(egl::Display * display)240 egl::Error DisplayD3D::initialize(egl::Display *display)
241 {
242 ASSERT(mRenderer == nullptr && display != nullptr);
243 mDisplay = display;
244 ANGLE_TRY(CreateRendererD3D(display, &mRenderer));
245 return egl::NoError();
246 }
247
terminate()248 void DisplayD3D::terminate()
249 {
250 SafeDelete(mRenderer);
251 }
252
generateConfigs()253 egl::ConfigSet DisplayD3D::generateConfigs()
254 {
255 ASSERT(mRenderer != nullptr);
256 return mRenderer->generateConfigs();
257 }
258
testDeviceLost()259 bool DisplayD3D::testDeviceLost()
260 {
261 ASSERT(mRenderer != nullptr);
262 return mRenderer->testDeviceLost();
263 }
264
restoreLostDevice(const egl::Display * display)265 egl::Error DisplayD3D::restoreLostDevice(const egl::Display *display)
266 {
267 // Release surface resources to make the Reset() succeed
268 for (egl::Surface *surface : mState.surfaceSet)
269 {
270 ASSERT(!surface->getBoundTexture());
271 SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
272 surfaceD3D->releaseSwapChain();
273 }
274
275 if (!mRenderer->resetDevice())
276 {
277 return egl::EglBadAlloc();
278 }
279
280 // Restore any surfaces that may have been lost
281 for (const egl::Surface *surface : mState.surfaceSet)
282 {
283 SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
284
285 ANGLE_TRY(surfaceD3D->resetSwapChain(display));
286 }
287
288 return egl::NoError();
289 }
290
isValidNativeWindow(EGLNativeWindowType window) const291 bool DisplayD3D::isValidNativeWindow(EGLNativeWindowType window) const
292 {
293 return mRenderer->isValidNativeWindow(window);
294 }
295
validateClientBuffer(const egl::Config * config,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const296 egl::Error DisplayD3D::validateClientBuffer(const egl::Config *config,
297 EGLenum buftype,
298 EGLClientBuffer clientBuffer,
299 const egl::AttributeMap &attribs) const
300 {
301 switch (buftype)
302 {
303 case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
304 return mRenderer->validateShareHandle(config, static_cast<HANDLE>(clientBuffer),
305 attribs);
306
307 case EGL_D3D_TEXTURE_ANGLE:
308 return mRenderer->getD3DTextureInfo(config, static_cast<IUnknown *>(clientBuffer),
309 attribs, nullptr, nullptr, nullptr, nullptr,
310 nullptr);
311
312 default:
313 return DisplayImpl::validateClientBuffer(config, buftype, clientBuffer, attribs);
314 }
315 }
316
validateImageClientBuffer(const gl::Context * context,EGLenum target,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const317 egl::Error DisplayD3D::validateImageClientBuffer(const gl::Context *context,
318 EGLenum target,
319 EGLClientBuffer clientBuffer,
320 const egl::AttributeMap &attribs) const
321 {
322 switch (target)
323 {
324 case EGL_D3D11_TEXTURE_ANGLE:
325 {
326 return mRenderer->getD3DTextureInfo(nullptr, static_cast<IUnknown *>(clientBuffer),
327 attribs, nullptr, nullptr, nullptr, nullptr,
328 nullptr);
329 }
330
331 default:
332 return DisplayImpl::validateImageClientBuffer(context, target, clientBuffer, attribs);
333 }
334 }
335
generateExtensions(egl::DisplayExtensions * outExtensions) const336 void DisplayD3D::generateExtensions(egl::DisplayExtensions *outExtensions) const
337 {
338 mRenderer->generateDisplayExtensions(outExtensions);
339 }
340
getVendorString() const341 std::string DisplayD3D::getVendorString() const
342 {
343 std::string vendorString = "Google Inc.";
344 if (mRenderer)
345 {
346 vendorString += " " + mRenderer->getVendorString();
347 }
348
349 return vendorString;
350 }
351
generateCaps(egl::Caps * outCaps) const352 void DisplayD3D::generateCaps(egl::Caps *outCaps) const
353 {
354 // Display must be initialized to generate caps
355 ASSERT(mRenderer != nullptr);
356
357 outCaps->textureNPOT = mRenderer->getNativeExtensions().textureNPOTOES;
358 }
359
waitClient(const gl::Context * context)360 egl::Error DisplayD3D::waitClient(const gl::Context *context)
361 {
362 for (egl::Surface *surface : mState.surfaceSet)
363 {
364 SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
365 ANGLE_TRY(surfaceD3D->checkForOutOfDateSwapChain(this));
366 }
367
368 return egl::NoError();
369 }
370
waitNative(const gl::Context * context,EGLint engine)371 egl::Error DisplayD3D::waitNative(const gl::Context *context, EGLint engine)
372 {
373 egl::Surface *drawSurface = context->getCurrentDrawSurface();
374 egl::Surface *readSurface = context->getCurrentReadSurface();
375
376 if (drawSurface != nullptr)
377 {
378 SurfaceD3D *drawSurfaceD3D = GetImplAs<SurfaceD3D>(drawSurface);
379 ANGLE_TRY(drawSurfaceD3D->checkForOutOfDateSwapChain(this));
380 }
381
382 if (readSurface != nullptr)
383 {
384 SurfaceD3D *readSurfaceD3D = GetImplAs<SurfaceD3D>(readSurface);
385 ANGLE_TRY(readSurfaceD3D->checkForOutOfDateSwapChain(this));
386 }
387
388 return egl::NoError();
389 }
390
getMaxSupportedESVersion() const391 gl::Version DisplayD3D::getMaxSupportedESVersion() const
392 {
393 return mRenderer->getMaxSupportedESVersion();
394 }
395
getMaxConformantESVersion() const396 gl::Version DisplayD3D::getMaxConformantESVersion() const
397 {
398 return mRenderer->getMaxConformantESVersion();
399 }
400
handleResult(HRESULT hr,const char * message,const char * file,const char * function,unsigned int line)401 void DisplayD3D::handleResult(HRESULT hr,
402 const char *message,
403 const char *file,
404 const char *function,
405 unsigned int line)
406 {
407 ASSERT(FAILED(hr));
408
409 std::stringstream errorStream;
410 errorStream << "Internal D3D11 error: " << gl::FmtHR(hr) << ", in " << file << ", " << function
411 << ":" << line << ". " << message;
412
413 mStoredErrorString = errorStream.str();
414 }
415
populateFeatureList(angle::FeatureList * features)416 void DisplayD3D::populateFeatureList(angle::FeatureList *features)
417 {
418 mRenderer->getFeatures().populateFeatureList(features);
419 }
420
421 } // namespace rx
422