зеркало из https://github.com/AvaloniaUI/angle.git
Reland "Define and expose EGL_ANGLE_power_preference extension."
This is a reland of ac58e63295
The original CL was reverted in a rush because I thought there was an
uninitialized variable bug, but upon later re-review this turned out to
not be the case.
Original change's description:
> Define and expose EGL_ANGLE_power_preference extension.
>
> Allows application to select the integrated or discrete GPU on
> dual-GPU macOS systems.
>
> Tested by modifying the example program at:
> https://github.com/grorg/ANGLEIOSurfaceTest
>
> and verifying that both integrated and discrete GPUs can be selected.
> (The changes to that program will be upstreamed once some build issues
> are resolved.)
>
> Bug: 2813
> Change-Id: Ibeb17778512896456d220e9bc4cf8f222aa57057
> Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1570081
> Commit-Queue: Kenneth Russell <kbr@chromium.org>
> Reviewed-by: Geoff Lang <geofflang@chromium.org>
Bug: 2813
Tbr: geofflang@chromium.org
Tbr: cwallez@chromium.org
Change-Id: Iea000dd718f4f4b4f57237adb1dc44381b10106b
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1575419
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Commit-Queue: Kenneth Russell <kbr@chromium.org>
This commit is contained in:
Родитель
145ec7fa7c
Коммит
51386f4a5e
|
@ -0,0 +1,85 @@
|
|||
Name
|
||||
|
||||
ANGLE_power_preference
|
||||
|
||||
Name Strings
|
||||
|
||||
EGL_ANGLE_power_preference
|
||||
|
||||
Contributors
|
||||
|
||||
Kenneth Russell
|
||||
|
||||
Contacts
|
||||
|
||||
Kenneth Russell, Google Inc. (kbr 'at' google.com)
|
||||
|
||||
Status
|
||||
|
||||
Draft
|
||||
|
||||
Version
|
||||
|
||||
Version 1, April 16, 2019
|
||||
|
||||
Number
|
||||
|
||||
EGL Extension #??
|
||||
|
||||
Dependencies
|
||||
|
||||
This extension is written against the wording of the EGL 1.4
|
||||
Specification.
|
||||
|
||||
Overview
|
||||
|
||||
This extension allows selection of the high- or low-power GPU on
|
||||
dual-GPU systems, specifically on macOS.
|
||||
|
||||
New Types
|
||||
|
||||
None
|
||||
|
||||
New Procedures and Functions
|
||||
|
||||
None
|
||||
|
||||
New Tokens
|
||||
|
||||
Accepted as an attribute name in the <*attrib_list> argument to
|
||||
eglCreateContext:
|
||||
|
||||
EGL_POWER_PREFERENCE_ANGLE 0x3482
|
||||
|
||||
Accepted as an attribute value in the <*attrib_list> argument to
|
||||
eglCreateContext:
|
||||
|
||||
EGL_LOW_POWER_ANGLE 0x0001
|
||||
EGL_HIGH_POWER_ANGLE 0x0002
|
||||
|
||||
Additions to the EGL 1.4 Specification
|
||||
|
||||
Add the following to section 3.7.1 "Creating Rendering Contexts":
|
||||
|
||||
EGL_POWER_PREFERENCE_ANGLE indicates whether the context should be
|
||||
created on the integrated (low-power) or discrete (high-power) GPU
|
||||
on dual-GPU systems. EGL_POWER_PREFERENCE_ANGLE is only a legal
|
||||
context creation attribute when the EGL_ANGLE_power_preference
|
||||
extension is advertised. The valid values for this attribute are
|
||||
EGL_LOW_POWER_ANGLE and EGL_HIGH_POWER_ANGLE. If this extension is
|
||||
advertised and this context creation attribute is not specified,
|
||||
the default value is EGL_LOW_POWER_ANGLE.
|
||||
|
||||
The containing application must set the
|
||||
NSSupportsAutomaticGraphicsSwitching attribute to true in its
|
||||
Info.plist in order for this extension to operate as advertised.
|
||||
|
||||
Issues
|
||||
|
||||
None yet.
|
||||
|
||||
Revision History
|
||||
|
||||
Rev. Date Author Changes
|
||||
---- ------------- --------- ----------------------------------------
|
||||
1 Apr 16, 2019 kbr Initial version
|
|
@ -202,6 +202,13 @@ EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncValuesCHROMIUM(EGLDisplay dpy,
|
|||
#endif
|
||||
#endif /* EGL_CHROMIUM_get_sync_values */
|
||||
|
||||
#ifndef EGL_ANGLE_power_preference
|
||||
#define EGL_ANGLE_power_preference 1
|
||||
#define EGL_POWER_PREFERENCE_ANGLE 0x3482
|
||||
#define EGL_LOW_POWER_ANGLE 0x0001
|
||||
#define EGL_HIGH_POWER_ANGLE 0x0002
|
||||
#endif /* EGL_ANGLE_power_preference */
|
||||
|
||||
// clang-format on
|
||||
|
||||
#endif // INCLUDE_EGL_EGLEXT_ANGLE_
|
||||
|
|
|
@ -67,6 +67,8 @@ struct SystemInfo
|
|||
|
||||
bool isOptimus = false;
|
||||
bool isAMDSwitchable = false;
|
||||
// Only true on dual-GPU Mac laptops.
|
||||
bool isMacSwitchable = false;
|
||||
|
||||
// Only available on Android
|
||||
std::string machineManufacturer;
|
||||
|
|
|
@ -164,6 +164,19 @@ bool GetSystemInfo(SystemInfo *info)
|
|||
|
||||
FindPrimaryGPU(info);
|
||||
|
||||
// Figure out whether this is a dual-GPU system.
|
||||
//
|
||||
// TODO(kbr): this code was ported over from Chromium, and its correctness
|
||||
// could be improved - need to use Mac-specific APIs to determine whether
|
||||
// offline renderers are allowed, and whether these two GPUs are really the
|
||||
// integrated/discrete GPUs in a laptop.
|
||||
if (info->gpus.size() == 2 &&
|
||||
((IsIntel(info->gpus[0].vendorId) && !IsIntel(info->gpus[1].vendorId)) ||
|
||||
(!IsIntel(info->gpus[0].vendorId) && IsIntel(info->gpus[1].vendorId))))
|
||||
{
|
||||
info->isMacSwitchable = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ EGLAttrib AttributeMap::get(EGLAttrib key) const
|
|||
EGLAttrib AttributeMap::get(EGLAttrib key, EGLAttrib defaultValue) const
|
||||
{
|
||||
auto iter = mAttributes.find(key);
|
||||
return (mAttributes.find(key) != mAttributes.end()) ? iter->second : defaultValue;
|
||||
return (iter != mAttributes.end()) ? iter->second : defaultValue;
|
||||
}
|
||||
|
||||
EGLint AttributeMap::getAsInt(EGLAttrib key) const
|
||||
|
|
|
@ -1391,7 +1391,8 @@ DisplayExtensions::DisplayExtensions()
|
|||
blobCache(false),
|
||||
imageNativeBuffer(false),
|
||||
getFrameTimestamps(false),
|
||||
recordable(false)
|
||||
recordable(false),
|
||||
powerPreference(false)
|
||||
{}
|
||||
|
||||
std::vector<std::string> DisplayExtensions::getStrings() const
|
||||
|
@ -1444,7 +1445,8 @@ std::vector<std::string> DisplayExtensions::getStrings() const
|
|||
InsertExtensionString("EGL_ANDROID_blob_cache", blobCache, &extensionStrings);
|
||||
InsertExtensionString("EGL_ANDROID_image_native_buffer", imageNativeBuffer, &extensionStrings);
|
||||
InsertExtensionString("EGL_ANDROID_get_frame_timestamps", getFrameTimestamps, &extensionStrings);
|
||||
InsertExtensionString("EGL_ANDROID_recordable", recordable, &extensionStrings);
|
||||
InsertExtensionString("EGL_ANDROID_recordable", recordable, &extensionStrings);
|
||||
InsertExtensionString("EGL_ANGLE_power_preference", powerPreference, &extensionStrings);
|
||||
// TODO(jmadill): Enable this when complete.
|
||||
//InsertExtensionString("KHR_create_context_no_error", createContextNoError, &extensionStrings);
|
||||
// clang-format on
|
||||
|
|
|
@ -870,6 +870,9 @@ struct DisplayExtensions
|
|||
|
||||
// EGL_ANDROID_recordable
|
||||
bool recordable;
|
||||
|
||||
// EGL_ANGLE_power_preference
|
||||
bool powerPreference;
|
||||
};
|
||||
|
||||
struct DeviceExtensions
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// Copyright 2019 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.
|
||||
//
|
||||
// ContextCGL:
|
||||
// Mac-specific subclass of ContextGL.
|
||||
//
|
||||
|
||||
#include "libANGLE/renderer/gl/cgl/ContextCGL.h"
|
||||
|
||||
#include "libANGLE/Context.h"
|
||||
#include "libANGLE/Display.h"
|
||||
#include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
|
||||
|
||||
namespace rx
|
||||
{
|
||||
|
||||
ContextCGL::ContextCGL(const gl::State &state,
|
||||
gl::ErrorSet *errorSet,
|
||||
const std::shared_ptr<RendererGL> &renderer,
|
||||
bool usesDiscreteGPU)
|
||||
: ContextGL(state, errorSet, renderer), mUsesDiscreteGpu(usesDiscreteGPU)
|
||||
{}
|
||||
|
||||
void ContextCGL::onDestroy(const gl::Context *context)
|
||||
{
|
||||
if (mUsesDiscreteGpu)
|
||||
{
|
||||
egl::Display *display = context->getDisplay();
|
||||
// TODO(kbr): if the context is created and destroyed without ever
|
||||
// making it current, it is possible to leak retentions of the
|
||||
// discrete GPU.
|
||||
if (display)
|
||||
{
|
||||
GetImplAs<DisplayCGL>(display)->unreferenceDiscreteGPU();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rx
|
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// Copyright 2019 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.
|
||||
//
|
||||
// ContextCGL:
|
||||
// Mac-specific subclass of ContextGL.
|
||||
//
|
||||
|
||||
#ifndef LIBANGLE_RENDERER_GL_CGL_CONTEXTCGL_H_
|
||||
#define LIBANGLE_RENDERER_GL_CGL_CONTEXTCGL_H_
|
||||
|
||||
#include "libANGLE/renderer/gl/ContextGL.h"
|
||||
#include "libANGLE/renderer/gl/RendererGL.h"
|
||||
|
||||
namespace rx
|
||||
{
|
||||
|
||||
class ContextCGL : public ContextGL
|
||||
{
|
||||
public:
|
||||
ContextCGL(const gl::State &state,
|
||||
gl::ErrorSet *errorSet,
|
||||
const std::shared_ptr<RendererGL> &renderer,
|
||||
bool usesDiscreteGPU);
|
||||
|
||||
void onDestroy(const gl::Context *context) override;
|
||||
|
||||
private:
|
||||
bool mUsesDiscreteGpu;
|
||||
};
|
||||
|
||||
} // namespace rx
|
||||
|
||||
#endif // LIBANGLE_RENDERER_GL_CGL_CONTEXTCGL_H_
|
|
@ -74,6 +74,11 @@ class DisplayCGL : public DisplayGL
|
|||
|
||||
WorkerContext *createWorkerContext(std::string *infoLog);
|
||||
|
||||
// Support for dual-GPU MacBook Pros. If the context was created
|
||||
// preferring the high-power GPU, unreference that GPU during
|
||||
// context destruction.
|
||||
void unreferenceDiscreteGPU();
|
||||
|
||||
private:
|
||||
egl::Error makeCurrentSurfaceless(gl::Context *context) override;
|
||||
|
||||
|
@ -85,6 +90,9 @@ class DisplayCGL : public DisplayGL
|
|||
egl::Display *mEGLDisplay;
|
||||
CGLContextObj mContext;
|
||||
CGLPixelFormatObj mPixelFormat;
|
||||
bool mSupportsGPUSwitching;
|
||||
CGLPixelFormatObj mDiscreteGPUPixelFormat;
|
||||
int mDiscreteGPURefs;
|
||||
};
|
||||
|
||||
} // namespace rx
|
||||
|
|
|
@ -13,8 +13,9 @@
|
|||
#include <dlfcn.h>
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "gpu_info_util/SystemInfo.h"
|
||||
#include "libANGLE/Display.h"
|
||||
#include "libANGLE/renderer/gl/ContextGL.h"
|
||||
#include "libANGLE/renderer/gl/cgl/ContextCGL.h"
|
||||
#include "libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.h"
|
||||
#include "libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h"
|
||||
#include "libANGLE/renderer/gl/cgl/RendererCGL.h"
|
||||
|
@ -49,7 +50,13 @@ class FunctionsGLCGL : public FunctionsGL
|
|||
};
|
||||
|
||||
DisplayCGL::DisplayCGL(const egl::DisplayState &state)
|
||||
: DisplayGL(state), mEGLDisplay(nullptr), mContext(nullptr), mPixelFormat(nullptr)
|
||||
: DisplayGL(state),
|
||||
mEGLDisplay(nullptr),
|
||||
mContext(nullptr),
|
||||
mPixelFormat(nullptr),
|
||||
mSupportsGPUSwitching(false),
|
||||
mDiscreteGPUPixelFormat(nullptr),
|
||||
mDiscreteGPURefs(0)
|
||||
{}
|
||||
|
||||
DisplayCGL::~DisplayCGL() {}
|
||||
|
@ -58,13 +65,25 @@ egl::Error DisplayCGL::initialize(egl::Display *display)
|
|||
{
|
||||
mEGLDisplay = display;
|
||||
|
||||
angle::SystemInfo info;
|
||||
if (!angle::GetSystemInfo(&info))
|
||||
{
|
||||
return egl::EglNotInitialized() << "Unable to query ANGLE's SystemInfo.";
|
||||
}
|
||||
mSupportsGPUSwitching = info.isMacSwitchable;
|
||||
|
||||
{
|
||||
// TODO(cwallez) investigate which pixel format we want
|
||||
CGLPixelFormatAttribute attribs[] = {
|
||||
kCGLPFAOpenGLProfile, static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_3_2_Core),
|
||||
static_cast<CGLPixelFormatAttribute>(0)};
|
||||
std::vector<CGLPixelFormatAttribute> attribs;
|
||||
attribs.push_back(kCGLPFAOpenGLProfile);
|
||||
attribs.push_back(static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_3_2_Core));
|
||||
if (mSupportsGPUSwitching)
|
||||
{
|
||||
attribs.push_back(kCGLPFAAllowOfflineRenderers);
|
||||
}
|
||||
attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
|
||||
GLint nVirtualScreens = 0;
|
||||
CGLChoosePixelFormat(attribs, &mPixelFormat, &nVirtualScreens);
|
||||
CGLChoosePixelFormat(attribs.data(), &mPixelFormat, &nVirtualScreens);
|
||||
|
||||
if (mPixelFormat == nullptr)
|
||||
{
|
||||
|
@ -161,7 +180,29 @@ ContextImpl *DisplayCGL::createContext(const gl::State &state,
|
|||
const gl::Context *shareContext,
|
||||
const egl::AttributeMap &attribs)
|
||||
{
|
||||
return new ContextGL(state, errorSet, mRenderer);
|
||||
bool usesDiscreteGPU = false;
|
||||
|
||||
if (attribs.get(EGL_POWER_PREFERENCE_ANGLE, EGL_LOW_POWER_ANGLE) == EGL_HIGH_POWER_ANGLE)
|
||||
{
|
||||
// Should have been rejected by validation if not supported.
|
||||
ASSERT(mSupportsGPUSwitching);
|
||||
// Create discrete pixel format if necessary.
|
||||
if (!mDiscreteGPUPixelFormat)
|
||||
{
|
||||
CGLPixelFormatAttribute discreteAttribs[] = {static_cast<CGLPixelFormatAttribute>(0)};
|
||||
GLint numPixelFormats = 0;
|
||||
if (CGLChoosePixelFormat(discreteAttribs, &mDiscreteGPUPixelFormat, &numPixelFormats) !=
|
||||
kCGLNoError)
|
||||
{
|
||||
ERR() << "Error choosing discrete pixel format.";
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
++mDiscreteGPURefs;
|
||||
usesDiscreteGPU = true;
|
||||
}
|
||||
|
||||
return new ContextCGL(state, errorSet, mRenderer, usesDiscreteGPU);
|
||||
}
|
||||
|
||||
DeviceImpl *DisplayCGL::createDevice()
|
||||
|
@ -288,6 +329,11 @@ void DisplayCGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
|
|||
// Contexts are virtualized so textures can be shared globally
|
||||
outExtensions->displayTextureShareGroup = true;
|
||||
|
||||
if (mSupportsGPUSwitching)
|
||||
{
|
||||
outExtensions->powerPreference = true;
|
||||
}
|
||||
|
||||
DisplayGL::generateExtensions(outExtensions);
|
||||
}
|
||||
|
||||
|
@ -370,4 +416,14 @@ WorkerContext *DisplayCGL::createWorkerContext(std::string *infoLog)
|
|||
|
||||
return new WorkerContextCGL(context);
|
||||
}
|
||||
|
||||
void DisplayCGL::unreferenceDiscreteGPU()
|
||||
{
|
||||
ASSERT(mDiscreteGPURefs > 0);
|
||||
if (--mDiscreteGPURefs == 0)
|
||||
{
|
||||
CGLDestroyPixelFormat(mDiscreteGPUPixelFormat);
|
||||
mDiscreteGPUPixelFormat = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1127,6 +1127,20 @@ Error ValidateCreateContext(Display *display,
|
|||
}
|
||||
break;
|
||||
|
||||
case EGL_POWER_PREFERENCE_ANGLE:
|
||||
if (!display->getExtensions().powerPreference)
|
||||
{
|
||||
return EglBadAttribute() << "Attribute EGL_POWER_PREFERENCE_ANGLE "
|
||||
"requires EGL_ANGLE_power_preference.";
|
||||
}
|
||||
if (value != EGL_LOW_POWER_ANGLE && value != EGL_HIGH_POWER_ANGLE)
|
||||
{
|
||||
return EglBadAttribute()
|
||||
<< "EGL_POWER_PREFERENCE_ANGLE must be "
|
||||
"either EGL_LOW_POWER_ANGLE or EGL_HIGH_POWER_ANGLE.";
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return EglBadAttribute() << "Unknown attribute.";
|
||||
}
|
||||
|
|
|
@ -747,6 +747,8 @@ libangle_gl_egl_android_sources = [
|
|||
]
|
||||
|
||||
libangle_gl_cgl_sources = [
|
||||
"src/libANGLE/renderer/gl/cgl/ContextCGL.cpp",
|
||||
"src/libANGLE/renderer/gl/cgl/ContextCGL.h",
|
||||
"src/libANGLE/renderer/gl/cgl/DisplayCGL.mm",
|
||||
"src/libANGLE/renderer/gl/cgl/DisplayCGL.h",
|
||||
"src/libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.mm",
|
||||
|
|
Загрузка…
Ссылка в новой задаче