| // | |
| // Copyright 2014 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // DisplayD3D.cpp: D3D implementation of egl::Display | |
| #include "libANGLE/renderer/d3d/DisplayD3D.h" | |
| #include <EGL/eglext.h> | |
| #include "libANGLE/Config.h" | |
| #include "libANGLE/Context.h" | |
| #include "libANGLE/Display.h" | |
| #include "libANGLE/Surface.h" | |
| #include "libANGLE/Thread.h" | |
| #include "libANGLE/histogram_macros.h" | |
| #include "libANGLE/renderer/d3d/DeviceD3D.h" | |
| #include "libANGLE/renderer/d3d/EGLImageD3D.h" | |
| #include "libANGLE/renderer/d3d/RendererD3D.h" | |
| #include "libANGLE/renderer/d3d/SurfaceD3D.h" | |
| #include "libANGLE/renderer/d3d/SwapChainD3D.h" | |
| #if defined(ANGLE_ENABLE_D3D9) | |
| # include "libANGLE/renderer/d3d/d3d9/Renderer9.h" | |
| #endif // ANGLE_ENABLE_D3D9 | |
| #if defined(ANGLE_ENABLE_D3D11) | |
| # include "libANGLE/renderer/d3d/d3d11/Renderer11.h" | |
| #endif // ANGLE_ENABLE_D3D11 | |
| #if !defined(ANGLE_DEFAULT_D3D11) | |
| // Enables use of the Direct3D 11 API for a default display, when available | |
| # define ANGLE_DEFAULT_D3D11 1 | |
| #endif | |
| namespace rx | |
| { | |
| typedef RendererD3D *(*CreateRendererD3DFunction)(egl::Display *); | |
| template <typename RendererType> | |
| static RendererD3D *CreateTypedRendererD3D(egl::Display *display) | |
| { | |
| return new RendererType(display); | |
| } | |
| egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer) | |
| { | |
| ASSERT(outRenderer != nullptr); | |
| std::vector<CreateRendererD3DFunction> rendererCreationFunctions; | |
| if (display->getPlatform() == EGL_PLATFORM_ANGLE_ANGLE) | |
| { | |
| const auto &attribMap = display->getAttributeMap(); | |
| EGLNativeDisplayType nativeDisplay = display->getNativeDisplayId(); | |
| EGLint requestedDisplayType = static_cast<EGLint>( | |
| attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE)); | |
| #if defined(ANGLE_ENABLE_D3D11) | |
| if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE || | |
| nativeDisplay == EGL_D3D11_ONLY_DISPLAY_ANGLE || | |
| requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) | |
| { | |
| rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>); | |
| } | |
| #endif | |
| #if defined(ANGLE_ENABLE_D3D9) | |
| if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE || | |
| requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE) | |
| { | |
| rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>); | |
| } | |
| #endif | |
| if (nativeDisplay != EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE && | |
| nativeDisplay != EGL_D3D11_ONLY_DISPLAY_ANGLE && | |
| requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE) | |
| { | |
| // The default display is requested, try the D3D9 and D3D11 renderers, order them using | |
| // the definition of ANGLE_DEFAULT_D3D11 | |
| #if ANGLE_DEFAULT_D3D11 | |
| # if defined(ANGLE_ENABLE_D3D11) | |
| rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>); | |
| # endif | |
| # if defined(ANGLE_ENABLE_D3D9) | |
| rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>); | |
| # endif | |
| #else | |
| # if defined(ANGLE_ENABLE_D3D9) | |
| rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer9>); | |
| # endif | |
| # if defined(ANGLE_ENABLE_D3D11) | |
| rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>); | |
| # endif | |
| #endif | |
| } | |
| } | |
| else if (display->getPlatform() == EGL_PLATFORM_DEVICE_EXT) | |
| { | |
| #if defined(ANGLE_ENABLE_D3D11) | |
| if (display->getDevice()->getType() == EGL_D3D11_DEVICE_ANGLE) | |
| { | |
| rendererCreationFunctions.push_back(CreateTypedRendererD3D<Renderer11>); | |
| } | |
| #endif | |
| } | |
| else | |
| { | |
| UNIMPLEMENTED(); | |
| } | |
| for (size_t i = 0; i < rendererCreationFunctions.size(); i++) | |
| { | |
| RendererD3D *renderer = rendererCreationFunctions[i](display); | |
| egl::Error result = renderer->initialize(); | |
| #if defined(ANGLE_ENABLE_D3D11) | |
| if (renderer->getRendererClass() == RENDERER_D3D11) | |
| { | |
| ASSERT(result.getID() >= 0 && result.getID() < NUM_D3D11_INIT_ERRORS); | |
| ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D11InitializeResult", result.getID(), | |
| NUM_D3D11_INIT_ERRORS); | |
| } | |
| #endif | |
| #if defined(ANGLE_ENABLE_D3D9) | |
| if (renderer->getRendererClass() == RENDERER_D3D9) | |
| { | |
| ASSERT(result.getID() >= 0 && result.getID() < NUM_D3D9_INIT_ERRORS); | |
| ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.D3D9InitializeResult", result.getID(), | |
| NUM_D3D9_INIT_ERRORS); | |
| } | |
| #endif | |
| if (!result.isError()) | |
| { | |
| *outRenderer = renderer; | |
| return result; | |
| } | |
| // Failed to create the renderer, try the next | |
| SafeDelete(renderer); | |
| ERR() << "Failed to create D3D renderer: " << result.getMessage(); | |
| } | |
| return egl::EglNotInitialized() << "No available renderers."; | |
| } | |
| DisplayD3D::DisplayD3D(const egl::DisplayState &state) : DisplayImpl(state), mRenderer(nullptr) {} | |
| SurfaceImpl *DisplayD3D::createWindowSurface(const egl::SurfaceState &state, | |
| EGLNativeWindowType window, | |
| const egl::AttributeMap &attribs) | |
| { | |
| ASSERT(mRenderer != nullptr); | |
| return new WindowSurfaceD3D(state, mRenderer, mDisplay, window, attribs); | |
| } | |
| SurfaceImpl *DisplayD3D::createPbufferSurface(const egl::SurfaceState &state, | |
| const egl::AttributeMap &attribs) | |
| { | |
| ASSERT(mRenderer != nullptr); | |
| return new PbufferSurfaceD3D(state, mRenderer, mDisplay, 0, nullptr, attribs); | |
| } | |
| SurfaceImpl *DisplayD3D::createPbufferFromClientBuffer(const egl::SurfaceState &state, | |
| EGLenum buftype, | |
| EGLClientBuffer clientBuffer, | |
| const egl::AttributeMap &attribs) | |
| { | |
| ASSERT(mRenderer != nullptr); | |
| return new PbufferSurfaceD3D(state, mRenderer, mDisplay, buftype, clientBuffer, attribs); | |
| } | |
| SurfaceImpl *DisplayD3D::createPixmapSurface(const egl::SurfaceState &state, | |
| NativePixmapType nativePixmap, | |
| const egl::AttributeMap &attribs) | |
| { | |
| UNIMPLEMENTED(); | |
| return nullptr; | |
| } | |
| ImageImpl *DisplayD3D::createImage(const egl::ImageState &state, | |
| const gl::Context *context, | |
| EGLenum target, | |
| const egl::AttributeMap &attribs) | |
| { | |
| return new EGLImageD3D(state, target, attribs, mRenderer); | |
| } | |
| DeviceImpl *DisplayD3D::createDevice() | |
| { | |
| return mRenderer->createEGLDevice(); | |
| } | |
| rx::ContextImpl *DisplayD3D::createContext(const gl::State &state, | |
| gl::ErrorSet *errorSet, | |
| const egl::Config *configuration, | |
| const gl::Context *shareContext, | |
| const egl::AttributeMap &attribs) | |
| { | |
| ASSERT(mRenderer != nullptr); | |
| return mRenderer->createContext(state, errorSet); | |
| } | |
| StreamProducerImpl *DisplayD3D::createStreamProducerD3DTexture( | |
| egl::Stream::ConsumerType consumerType, | |
| const egl::AttributeMap &attribs) | |
| { | |
| ASSERT(mRenderer != nullptr); | |
| return mRenderer->createStreamProducerD3DTexture(consumerType, attribs); | |
| } | |
| ExternalImageSiblingImpl *DisplayD3D::createExternalImageSibling(const gl::Context *context, | |
| EGLenum target, | |
| EGLClientBuffer buffer, | |
| const egl::AttributeMap &attribs) | |
| { | |
| ASSERT(mRenderer != nullptr); | |
| return mRenderer->createExternalImageSibling(context, target, buffer, attribs); | |
| } | |
| egl::Error DisplayD3D::makeCurrent(egl::Surface *drawSurface, | |
| egl::Surface *readSurface, | |
| gl::Context *context) | |
| { | |
| return egl::NoError(); | |
| } | |
| egl::Error DisplayD3D::initialize(egl::Display *display) | |
| { | |
| ASSERT(mRenderer == nullptr && display != nullptr); | |
| mDisplay = display; | |
| ANGLE_TRY(CreateRendererD3D(display, &mRenderer)); | |
| return egl::NoError(); | |
| } | |
| void DisplayD3D::terminate() | |
| { | |
| SafeDelete(mRenderer); | |
| } | |
| egl::ConfigSet DisplayD3D::generateConfigs() | |
| { | |
| ASSERT(mRenderer != nullptr); | |
| return mRenderer->generateConfigs(); | |
| } | |
| bool DisplayD3D::testDeviceLost() | |
| { | |
| ASSERT(mRenderer != nullptr); | |
| return mRenderer->testDeviceLost(); | |
| } | |
| egl::Error DisplayD3D::restoreLostDevice(const egl::Display *display) | |
| { | |
| // Release surface resources to make the Reset() succeed | |
| for (egl::Surface *surface : mState.surfaceSet) | |
| { | |
| ASSERT(!surface->getBoundTexture()); | |
| SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface); | |
| surfaceD3D->releaseSwapChain(); | |
| } | |
| if (!mRenderer->resetDevice()) | |
| { | |
| return egl::EglBadAlloc(); | |
| } | |
| // Restore any surfaces that may have been lost | |
| for (const egl::Surface *surface : mState.surfaceSet) | |
| { | |
| SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface); | |
| ANGLE_TRY(surfaceD3D->resetSwapChain(display)); | |
| } | |
| return egl::NoError(); | |
| } | |
| bool DisplayD3D::isValidNativeWindow(EGLNativeWindowType window) const | |
| { | |
| return mRenderer->isValidNativeWindow(window); | |
| } | |
| egl::Error DisplayD3D::validateClientBuffer(const egl::Config *config, | |
| EGLenum buftype, | |
| EGLClientBuffer clientBuffer, | |
| const egl::AttributeMap &attribs) const | |
| { | |
| switch (buftype) | |
| { | |
| case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: | |
| return mRenderer->validateShareHandle(config, static_cast<HANDLE>(clientBuffer), | |
| attribs); | |
| case EGL_D3D_TEXTURE_ANGLE: | |
| return mRenderer->getD3DTextureInfo(config, static_cast<IUnknown *>(clientBuffer), | |
| attribs, nullptr, nullptr, nullptr, nullptr, | |
| nullptr); | |
| default: | |
| return DisplayImpl::validateClientBuffer(config, buftype, clientBuffer, attribs); | |
| } | |
| } | |
| egl::Error DisplayD3D::validateImageClientBuffer(const gl::Context *context, | |
| EGLenum target, | |
| EGLClientBuffer clientBuffer, | |
| const egl::AttributeMap &attribs) const | |
| { | |
| switch (target) | |
| { | |
| case EGL_D3D11_TEXTURE_ANGLE: | |
| { | |
| return mRenderer->getD3DTextureInfo(nullptr, static_cast<IUnknown *>(clientBuffer), | |
| attribs, nullptr, nullptr, nullptr, nullptr, | |
| nullptr); | |
| } | |
| default: | |
| return DisplayImpl::validateImageClientBuffer(context, target, clientBuffer, attribs); | |
| } | |
| } | |
| void DisplayD3D::generateExtensions(egl::DisplayExtensions *outExtensions) const | |
| { | |
| mRenderer->generateDisplayExtensions(outExtensions); | |
| } | |
| std::string DisplayD3D::getVendorString() const | |
| { | |
| std::string vendorString = "Google Inc."; | |
| if (mRenderer) | |
| { | |
| vendorString += " " + mRenderer->getVendorString(); | |
| } | |
| return vendorString; | |
| } | |
| void DisplayD3D::generateCaps(egl::Caps *outCaps) const | |
| { | |
| // Display must be initialized to generate caps | |
| ASSERT(mRenderer != nullptr); | |
| outCaps->textureNPOT = mRenderer->getNativeExtensions().textureNPOT; | |
| } | |
| egl::Error DisplayD3D::waitClient(const gl::Context *context) | |
| { | |
| for (egl::Surface *surface : mState.surfaceSet) | |
| { | |
| SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface); | |
| ANGLE_TRY(surfaceD3D->checkForOutOfDateSwapChain(this)); | |
| } | |
| return egl::NoError(); | |
| } | |
| egl::Error DisplayD3D::waitNative(const gl::Context *context, EGLint engine) | |
| { | |
| egl::Surface *drawSurface = context->getCurrentDrawSurface(); | |
| egl::Surface *readSurface = context->getCurrentReadSurface(); | |
| if (drawSurface != nullptr) | |
| { | |
| SurfaceD3D *drawSurfaceD3D = GetImplAs<SurfaceD3D>(drawSurface); | |
| ANGLE_TRY(drawSurfaceD3D->checkForOutOfDateSwapChain(this)); | |
| } | |
| if (readSurface != nullptr) | |
| { | |
| SurfaceD3D *readSurfaceD3D = GetImplAs<SurfaceD3D>(readSurface); | |
| ANGLE_TRY(readSurfaceD3D->checkForOutOfDateSwapChain(this)); | |
| } | |
| return egl::NoError(); | |
| } | |
| gl::Version DisplayD3D::getMaxSupportedESVersion() const | |
| { | |
| return mRenderer->getMaxSupportedESVersion(); | |
| } | |
| gl::Version DisplayD3D::getMaxConformantESVersion() const | |
| { | |
| return mRenderer->getMaxConformantESVersion(); | |
| } | |
| void DisplayD3D::handleResult(HRESULT hr, | |
| const char *message, | |
| const char *file, | |
| const char *function, | |
| unsigned int line) | |
| { | |
| ASSERT(FAILED(hr)); | |
| std::stringstream errorStream; | |
| errorStream << "Internal D3D11 error: " << gl::FmtHR(hr) << ", in " << file << ", " << function | |
| << ":" << line << ". " << message; | |
| mStoredErrorString = errorStream.str(); | |
| } | |
| void DisplayD3D::populateFeatureList(angle::FeatureList *features) | |
| { | |
| mRenderer->getFeatures().populateFeatureList(features); | |
| } | |
| } // namespace rx |