Implement EGL_ANGLE_direct_composition extension
On D3D11, if dcomp.dll can be loaded then EGL_ANGLE_direct_composition
is exposed. Setting EGL_DIRECT_COMPOSITION_ANGLE as an attrib on a
surface will force it to use DirectComposition to draw to the screen,
possibly saving power.
BUG=524838
Change-Id: I3ea175a97bbca1a3388ffe52fdd1587a2f0c2ce7
Reviewed-on: https://chromium-review.googlesource.com/319214
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: John Bauman <jbauman@chromium.org>
diff --git a/include/EGL/eglext.h b/include/EGL/eglext.h
index 54cfb87..bf04b37 100644
--- a/include/EGL/eglext.h
+++ b/include/EGL/eglext.h
@@ -468,6 +468,11 @@
#define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1
#endif /* EGL_ANGLE_surface_d3d_texture_2d_share_handle */
+#ifndef EGL_ANGLE_direct_composition
+#define EGL_ANGLE_direct_composition 1
+#define EGL_DIRECT_COMPOSITION_ANGLE 0x33A5
+#endif /* EGL_ANGLE_direct_composition */
+
#ifndef EGL_ANGLE_platform_angle
#define EGL_ANGLE_platform_angle 1
#define EGL_PLATFORM_ANGLE_ANGLE 0x3202
diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp
index ca291a2..fef1218 100644
--- a/src/libANGLE/Caps.cpp
+++ b/src/libANGLE/Caps.cpp
@@ -621,7 +621,8 @@
glTexture3DImage(false),
glRenderbufferImage(false),
getAllProcAddresses(false),
- flexibleSurfaceCompatibility(false)
+ flexibleSurfaceCompatibility(false),
+ directComposition(false)
{
}
@@ -638,6 +639,7 @@
InsertExtensionString("EGL_ANGLE_window_fixed_size", windowFixedSize, &extensionStrings);
InsertExtensionString("EGL_ANGLE_keyed_mutex", keyedMutex, &extensionStrings);
InsertExtensionString("EGL_ANGLE_surface_orientation", surfaceOrientation, &extensionStrings);
+ InsertExtensionString("EGL_ANGLE_direct_composition", directComposition, &extensionStrings);
InsertExtensionString("EGL_NV_post_sub_buffer", postSubBuffer, &extensionStrings);
InsertExtensionString("EGL_KHR_create_context", createContext, &extensionStrings);
InsertExtensionString("EGL_EXT_device_query", deviceQuery, &extensionStrings);
diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h
index ecae714..8b5cb47 100644
--- a/src/libANGLE/Caps.h
+++ b/src/libANGLE/Caps.h
@@ -465,6 +465,9 @@
// EGL_ANGLE_flexible_surface_compatibility
bool flexibleSurfaceCompatibility;
+
+ // EGL_ANGLE_direct_composition
+ bool directComposition;
};
struct DeviceExtensions
diff --git a/src/libANGLE/Surface.cpp b/src/libANGLE/Surface.cpp
index dc754ff..b5ed0ff 100644
--- a/src/libANGLE/Surface.cpp
+++ b/src/libANGLE/Surface.cpp
@@ -49,6 +49,8 @@
mFlexibleSurfaceCompatibilityRequested =
(attributes.get(EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, EGL_FALSE) == EGL_TRUE);
+ mDirectComposition = (attributes.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE) == EGL_TRUE);
+
mFixedSize = (attributes.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE);
if (mFixedSize)
{
diff --git a/src/libANGLE/Surface.h b/src/libANGLE/Surface.h
index 813f2ef..e110f5d 100644
--- a/src/libANGLE/Surface.h
+++ b/src/libANGLE/Surface.h
@@ -84,6 +84,8 @@
}
EGLint getOrientation() const { return mOrientation; }
+ bool directComposition() const { return mDirectComposition; }
+
private:
virtual ~Surface();
rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override { return mImplementation; }
@@ -110,6 +112,8 @@
size_t mFixedWidth;
size_t mFixedHeight;
+ bool mDirectComposition;
+
EGLenum mTextureFormat;
EGLenum mTextureTarget;
diff --git a/src/libANGLE/renderer/d3d/DisplayD3D.cpp b/src/libANGLE/renderer/d3d/DisplayD3D.cpp
index 7c53c81..740bc76 100644
--- a/src/libANGLE/renderer/d3d/DisplayD3D.cpp
+++ b/src/libANGLE/renderer/d3d/DisplayD3D.cpp
@@ -173,6 +173,7 @@
EGLint height = attribs.get(EGL_HEIGHT, 0);
EGLint fixedSize = attribs.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE);
EGLint orientation = attribs.get(EGL_SURFACE_ORIENTATION_ANGLE, 0);
+ EGLint directComposition = attribs.get(EGL_DIRECT_COMPOSITION_ANGLE, EGL_FALSE);
if (!fixedSize)
{
@@ -181,7 +182,7 @@
}
return SurfaceD3D::createFromWindow(mRenderer, mDisplay, configuration, window, fixedSize,
- width, height, orientation);
+ directComposition, width, height, orientation);
}
SurfaceImpl *DisplayD3D::createPbufferSurface(const egl::Config *configuration,
diff --git a/src/libANGLE/renderer/d3d/SurfaceD3D.cpp b/src/libANGLE/renderer/d3d/SurfaceD3D.cpp
index 44c525b..6a8906f 100644
--- a/src/libANGLE/renderer/d3d/SurfaceD3D.cpp
+++ b/src/libANGLE/renderer/d3d/SurfaceD3D.cpp
@@ -24,7 +24,8 @@
SurfaceD3D *SurfaceD3D::createOffscreen(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLClientBuffer shareHandle,
EGLint width, EGLint height)
{
- return new SurfaceD3D(renderer, display, config, width, height, EGL_TRUE, 0, shareHandle, NULL);
+ return new SurfaceD3D(renderer, display, config, width, height, EGL_TRUE, 0, EGL_FALSE,
+ shareHandle, NULL);
}
SurfaceD3D *SurfaceD3D::createFromWindow(RendererD3D *renderer,
@@ -32,12 +33,13 @@
const egl::Config *config,
EGLNativeWindowType window,
EGLint fixedSize,
+ EGLint directComposition,
EGLint width,
EGLint height,
EGLint orientation)
{
return new SurfaceD3D(renderer, display, config, width, height, fixedSize, orientation,
- static_cast<EGLClientBuffer>(0), window);
+ directComposition, static_cast<EGLClientBuffer>(0), window);
}
SurfaceD3D::SurfaceD3D(RendererD3D *renderer,
@@ -47,6 +49,7 @@
EGLint height,
EGLint fixedSize,
EGLint orientation,
+ EGLint directComposition,
EGLClientBuffer shareHandle,
EGLNativeWindowType window)
: SurfaceImpl(),
@@ -58,7 +61,7 @@
mDepthStencilFormat(config->depthStencilFormat),
mSwapChain(nullptr),
mSwapIntervalDirty(true),
- mNativeWindow(window, config),
+ mNativeWindow(window, config, directComposition),
mWidth(width),
mHeight(height),
mSwapInterval(1),
diff --git a/src/libANGLE/renderer/d3d/SurfaceD3D.h b/src/libANGLE/renderer/d3d/SurfaceD3D.h
index a2929dc..b925bfc 100644
--- a/src/libANGLE/renderer/d3d/SurfaceD3D.h
+++ b/src/libANGLE/renderer/d3d/SurfaceD3D.h
@@ -30,6 +30,7 @@
const egl::Config *config,
EGLNativeWindowType window,
EGLint fixedSize,
+ EGLint directComposition,
EGLint width,
EGLint height,
EGLint orientation);
@@ -73,6 +74,7 @@
EGLint height,
EGLint fixedSize,
EGLint orientation,
+ EGLint directComposition,
EGLClientBuffer shareHandle,
EGLNativeWindowType window);
diff --git a/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h b/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h
index adaa9d9..f28ce4f 100644
--- a/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h
+++ b/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h
@@ -44,14 +44,21 @@
typedef IDXGIFactory DXGIFactory;
#endif
+typedef interface IDCompositionDevice IDCompositionDevice;
+typedef interface IDCompositionTarget IDCompositionTarget;
+typedef interface IDCompositionVisual IDCompositionVisual;
+
namespace rx
{
class NativeWindow
{
public:
- explicit NativeWindow(EGLNativeWindowType window, const egl::Config *config);
+ explicit NativeWindow(EGLNativeWindowType window,
+ const egl::Config *config,
+ bool directComposition);
+ ~NativeWindow();
bool initialize();
bool getClientRect(LPRECT rect);
bool isIconic();
@@ -63,11 +70,17 @@
inline EGLNativeWindowType getNativeWindow() const { return mWindow; }
+ void commitChange();
+
private:
EGLNativeWindowType mWindow;
-#if defined(ANGLE_ENABLE_WINDOWS_STORE)
+ bool mDirectComposition;
+ IDCompositionDevice *mDevice;
+ IDCompositionTarget *mCompositionTarget;
+ IDCompositionVisual *mVisual;
const egl::Config *mConfig;
+#if defined(ANGLE_ENABLE_WINDOWS_STORE)
std::shared_ptr<InspectableNativeWindow> mImpl;
#endif
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index 2db242c..c4ca8f3 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -499,6 +499,7 @@
mD3d11Module = NULL;
mDxgiModule = NULL;
+ mDCompModule = NULL;
mCreatedWithDeviceEXT = false;
mEGLDevice = nullptr;
@@ -765,6 +766,7 @@
TRACE_EVENT0("gpu.angle", "Renderer11::initialize (Load DLLs)");
mDxgiModule = LoadLibrary(TEXT("dxgi.dll"));
mD3d11Module = LoadLibrary(TEXT("d3d11.dll"));
+ mDCompModule = LoadLibrary(TEXT("dcomp.dll"));
if (mD3d11Module == nullptr || mDxgiModule == nullptr)
{
@@ -1089,6 +1091,7 @@
outExtensions->glRenderbufferImage = true;
outExtensions->flexibleSurfaceCompatibility = true;
+ outExtensions->directComposition = !!mDCompModule;
}
gl::Error Renderer11::flush()
@@ -2604,6 +2607,12 @@
mDxgiModule = NULL;
}
+ if (mDCompModule)
+ {
+ FreeLibrary(mDCompModule);
+ mDCompModule = NULL;
+ }
+
mCompiler.release();
}
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
index 4bfcbf3..8759f80 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
@@ -327,6 +327,7 @@
HMODULE mD3d11Module;
HMODULE mDxgiModule;
+ HMODULE mDCompModule;
std::vector<D3D_FEATURE_LEVEL> mAvailableFeatureLevels;
D3D_DRIVER_TYPE mDriverType;
bool mCreatedWithDeviceEXT;
diff --git a/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp b/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
index 21ce8bb..113bcdd 100644
--- a/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
@@ -821,6 +821,8 @@
ERR("Present failed with error code 0x%08X", result);
}
+ mNativeWindow.commitChange();
+
return EGL_SUCCESS;
}
diff --git a/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp b/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp
index 4f773bb..3f477b7 100644
--- a/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp
@@ -11,14 +11,31 @@
#include "common/debug.h"
+#include <initguid.h>
+#include <dcomp.h>
+
namespace rx
{
-NativeWindow::NativeWindow(EGLNativeWindowType window, const egl::Config *)
- : mWindow(window)
+NativeWindow::NativeWindow(EGLNativeWindowType window,
+ const egl::Config *config,
+ bool directComposition)
+ : mWindow(window),
+ mDirectComposition(directComposition),
+ mCompositionTarget(nullptr),
+ mDevice(nullptr),
+ mVisual(nullptr),
+ mConfig(config)
{
}
+NativeWindow::~NativeWindow()
+{
+ SafeRelease(mCompositionTarget);
+ SafeRelease(mDevice);
+ SafeRelease(mVisual);
+}
+
bool NativeWindow::initialize()
{
return true;
@@ -48,6 +65,83 @@
return E_INVALIDARG;
}
+ if (mDirectComposition)
+ {
+ HMODULE dcomp = ::GetModuleHandle(TEXT("dcomp.dll"));
+ if (!dcomp)
+ {
+ return E_INVALIDARG;
+ }
+
+ typedef HRESULT(WINAPI * PFN_DCOMPOSITION_CREATE_DEVICE)(
+ IDXGIDevice * dxgiDevice, REFIID iid, void **dcompositionDevice);
+ PFN_DCOMPOSITION_CREATE_DEVICE createDComp =
+ reinterpret_cast<PFN_DCOMPOSITION_CREATE_DEVICE>(
+ GetProcAddress(dcomp, "DCompositionCreateDevice"));
+ if (!createDComp)
+ {
+ return E_INVALIDARG;
+ }
+
+ if (!mDevice)
+ {
+ IDXGIDevice *dxgiDevice = d3d11::DynamicCastComObject<IDXGIDevice>(device);
+ HRESULT result = createDComp(dxgiDevice, __uuidof(IDCompositionDevice),
+ reinterpret_cast<void **>(&mDevice));
+ SafeRelease(dxgiDevice);
+
+ if (FAILED(result))
+ {
+ return result;
+ }
+ }
+
+ if (!mCompositionTarget)
+ {
+ HRESULT result = mDevice->CreateTargetForHwnd(mWindow, TRUE, &mCompositionTarget);
+ if (FAILED(result))
+ {
+ return result;
+ }
+ }
+
+ if (!mVisual)
+ {
+ HRESULT result = mDevice->CreateVisual(&mVisual);
+ if (FAILED(result))
+ {
+ return result;
+ }
+ }
+
+ IDXGIFactory2 *factory2 = d3d11::DynamicCastComObject<IDXGIFactory2>(factory);
+ DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
+ swapChainDesc.Width = width;
+ swapChainDesc.Height = height;
+ swapChainDesc.Format = format;
+ swapChainDesc.Stereo = FALSE;
+ swapChainDesc.SampleDesc.Count = 1;
+ swapChainDesc.SampleDesc.Quality = 0;
+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
+ swapChainDesc.BufferCount = 2;
+ swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
+ swapChainDesc.AlphaMode =
+ mConfig->alphaSize == 0 ? DXGI_ALPHA_MODE_IGNORE : DXGI_ALPHA_MODE_PREMULTIPLIED;
+ swapChainDesc.Flags = 0;
+ IDXGISwapChain1 *swapChain1 = nullptr;
+ HRESULT result =
+ factory2->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, &swapChain1);
+ if (SUCCEEDED(result))
+ {
+ *swapChain = static_cast<DXGISwapChain *>(swapChain1);
+ }
+ mVisual->SetContent(swapChain1);
+ mCompositionTarget->SetRoot(mVisual);
+ SafeRelease(factory2);
+ return result;
+ }
+
// Use IDXGIFactory2::CreateSwapChainForHwnd if DXGI 1.2 is available to create a DXGI_SWAP_EFFECT_SEQUENTIAL swap chain.
IDXGIFactory2 *factory2 = d3d11::DynamicCastComObject<IDXGIFactory2>(factory);
if (factory2 != nullptr)
@@ -96,4 +190,12 @@
return factory->CreateSwapChain(device, &swapChainDesc, swapChain);
}
+
+void NativeWindow::commitChange()
+{
+ if (mDevice)
+ {
+ mDevice->Commit();
+ }
+}
}
diff --git a/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp b/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp
index 5eb1d8c..47a6dae 100644
--- a/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp
@@ -11,12 +11,22 @@
namespace rx
{
-NativeWindow::NativeWindow(EGLNativeWindowType window, const egl::Config *config)
+NativeWindow::NativeWindow(EGLNativeWindowType window,
+ const egl::Config *config,
+ bool directComposition)
{
mWindow = window;
mConfig = config;
}
+NativeWindow::~NativeWindow()
+{
+}
+
+void NativeWindow::commitChange()
+{
+}
+
bool NativeWindow::initialize()
{
// If the native window type is a IPropertySet, extract the
diff --git a/src/libANGLE/validationEGL.cpp b/src/libANGLE/validationEGL.cpp
index a6d2313..67d1edc 100644
--- a/src/libANGLE/validationEGL.cpp
+++ b/src/libANGLE/validationEGL.cpp
@@ -385,6 +385,13 @@
case EGL_VG_ALPHA_FORMAT:
return Error(EGL_BAD_MATCH);
+ case EGL_DIRECT_COMPOSITION_ANGLE:
+ if (!displayExtensions.directComposition)
+ {
+ return Error(EGL_BAD_ATTRIBUTE);
+ }
+ break;
+
default:
return Error(EGL_BAD_ATTRIBUTE);
}
diff --git a/src/libGLESv2/entry_points_egl.cpp b/src/libGLESv2/entry_points_egl.cpp
index b67abe2..2b04611 100644
--- a/src/libGLESv2/entry_points_egl.cpp
+++ b/src/libGLESv2/entry_points_egl.cpp
@@ -447,6 +447,16 @@
}
*value = eglSurface->getOrientation();
break;
+ case EGL_DIRECT_COMPOSITION_ANGLE:
+ if (!display->getExtensions().directComposition)
+ {
+ SetGlobalError(Error(EGL_BAD_ATTRIBUTE,
+ "EGL_DIRECT_COMPOSITION_ANGLE cannot be used without "
+ "EGL_ANGLE_direct_composition support."));
+ return EGL_FALSE;
+ }
+ *value = eglSurface->directComposition();
+ break;
default:
SetGlobalError(Error(EGL_BAD_ATTRIBUTE));
return EGL_FALSE;