зеркало из https://github.com/AvaloniaUI/angle.git
Add ForceGPUSwitch to EGL_ANGLE_power_preference
eglHandleGPUSwitch() does not work with WebKit sandbox profile. The root cause is that we do not know the primary display, and as such we do not know which GPU drives this. Add eglForceGPUSwitchANGLE(display, gpuIDHigh, gpuIDLow). This lets the caller figure out the GPU in another process. Then the caller can just set the GPU in the sandboxed process. Add tests that are disabled by default until the runner and the infrastructure supports running the tests with automatic switching enabled. Bug: angleproject:7092 Change-Id: I316ee431156596effbdb89659a5e24291719a204 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3516274 Reviewed-by: Jonah Ryan-Davis <jonahr@google.com> Reviewed-by: Kenneth Russell <kbr@chromium.org> Commit-Queue: Kenneth Russell <kbr@chromium.org>
This commit is contained in:
Родитель
7c616871c7
Коммит
9637185c3d
|
@ -9,6 +9,7 @@ Name Strings
|
|||
Contributors
|
||||
|
||||
Kenneth Russell
|
||||
Kimmo Kinnunen
|
||||
|
||||
Contacts
|
||||
|
||||
|
@ -20,7 +21,7 @@ Status
|
|||
|
||||
Version
|
||||
|
||||
Version 1, April 16, 2019
|
||||
Version 3, March 10, 2022
|
||||
|
||||
Number
|
||||
|
||||
|
@ -49,6 +50,8 @@ New Procedures and Functions
|
|||
EGLDisplay dpy,
|
||||
EGLContext context);
|
||||
void eglHandleGPUSwitchANGLE(EGLDisplay dpy);
|
||||
void eglForceGPUSwitchANGLE(EGLDisplay dpy, EGLint gpuIDHigh,
|
||||
EGLint gpuIDLow);
|
||||
|
||||
New Tokens
|
||||
|
||||
|
@ -120,6 +123,31 @@ Additions to the EGL 1.4 Specification
|
|||
if |dpy| is an uninitialized display, an EGL_NOT_INITIALIZED error
|
||||
is generated.
|
||||
|
||||
eglForceGPUSwitchANGLE should be called with an explicit gpuID to transition
|
||||
between the low-power and high-power GPUs. This should be called if
|
||||
the environment is altered in such a way that eglHandleGPUSwitchANGLE
|
||||
will not work.
|
||||
On the macOS platform, the sandbox policy might prevent eglHandleGPUSwitchANGLE
|
||||
from obtaining the current main active GPU. In these cases, the gpuID can
|
||||
be obtained another way (e.g in other process) and communicated via
|
||||
eglForceGPUSwitchANGLE to the OpenGL display.
|
||||
If gpuID does not match any available GPUs in the system,
|
||||
nothing happens.
|
||||
|
||||
For calls to this function:
|
||||
|
||||
If |dpy| is not a valid display, an EGL_BAD_DISPLAY error is
|
||||
generated.
|
||||
|
||||
if |dpy| is an uninitialized display, an EGL_NOT_INITIALIZED error
|
||||
is generated.
|
||||
|
||||
|gpuIDHigh| the high 32 bits of the IOKit registry ID of the GPU to
|
||||
use for all contexts in the display.
|
||||
|
||||
|gpuIDLow| the low 32 bits of the IOKit registry ID of the GPU to
|
||||
use for all contexts in the display.
|
||||
|
||||
Issues
|
||||
|
||||
None yet.
|
||||
|
@ -132,3 +160,4 @@ Revision History
|
|||
2 June 5, 2020 kbr Add eglReleaseHighPowerGPUANGLE,
|
||||
eglReacquireHighPowerGPUANGLE, and
|
||||
eglHandleGPUSwitchANGLE
|
||||
3 March 10, 2022 kkinnunen Add eglForceGPUSwitchANGLE
|
||||
|
|
|
@ -282,10 +282,12 @@ EGLAPI EGLBoolean EGLAPIENTRY eglGetMscRateANGLE(EGLDisplay dpy,
|
|||
typedef void(EGLAPIENTRYP PFNEGLRELEASEHIGHPOWERGPUANGLEPROC) (EGLDisplay dpy, EGLContext ctx);
|
||||
typedef void(EGLAPIENTRYP PFNEGLREACQUIREHIGHPOWERGPUANGLEPROC) (EGLDisplay dpy, EGLContext ctx);
|
||||
typedef void(EGLAPIENTRYP PFNEGLHANDLEGPUSWITCHANGLEPROC) (EGLDisplay dpy);
|
||||
typedef void(EGLAPIENTRYP PFNEGLFORCEGPUSWITCHANGLEPROC) (EGLDisplay dpy, EGLint gpuIDHigh, EGLint gpuIDLow);
|
||||
#ifdef EGL_EGLEXT_PROTOTYPES
|
||||
EGLAPI void EGLAPIENTRY eglReleaseHighPowerGPUANGLE(EGLDisplay dpy, EGLContext ctx);
|
||||
EGLAPI void EGLAPIENTRY eglReacquireHighPowerGPUANGLE(EGLDisplay dpy, EGLContext ctx);
|
||||
EGLAPI void EGLAPIENTRY eglHandleGPUSwitchANGLE(EGLDisplay dpy);
|
||||
EGLAPI void EGLAPIENTRY eglForceGPUSwitchANGLE(EGLDisplay dpy, EGLint gpuIDHigh, EGLint gpuIDLow);
|
||||
#endif
|
||||
#endif /* EGL_ANGLE_power_preference */
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"scripts/egl.xml":
|
||||
"013c552e6c523abdcf268268ea47e9fe",
|
||||
"scripts/egl_angle_ext.xml":
|
||||
"72bf10ed3d23d5cdfa49934a0393b30d",
|
||||
"3618e835dbe1b28ef5ad20e7e36d1262",
|
||||
"scripts/extension_data/intel_630_linux.json":
|
||||
"513dabe561b92b577ec8433d263f8ba6",
|
||||
"scripts/extension_data/intel_630_win10.json":
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"scripts/egl.xml":
|
||||
"013c552e6c523abdcf268268ea47e9fe",
|
||||
"scripts/egl_angle_ext.xml":
|
||||
"72bf10ed3d23d5cdfa49934a0393b30d",
|
||||
"3618e835dbe1b28ef5ad20e7e36d1262",
|
||||
"scripts/generate_loader.py":
|
||||
"e67f4da64ba7f5cff39ba4e8926a05f8",
|
||||
"scripts/gl.xml":
|
||||
|
@ -16,21 +16,21 @@
|
|||
"scripts/wgl.xml":
|
||||
"c36001431919e1c435f1215a85f7e1db",
|
||||
"src/libEGL/egl_loader_autogen.cpp":
|
||||
"cac833213d037fa8d8a81c39b6bb1c56",
|
||||
"f8e305c5b9defa9ec419cac1a4c2247c",
|
||||
"src/libEGL/egl_loader_autogen.h":
|
||||
"6c1243c5956193a13ebc6658646877f2",
|
||||
"6e1f48d3358bd57cb17e9ca7c8d0f13a",
|
||||
"src/tests/restricted_traces/trace_egl_loader_autogen.cpp":
|
||||
"31143ac4b21d32854fa6603673c93937",
|
||||
"757d54a7afc30f8aa3d285ad2318f68c",
|
||||
"src/tests/restricted_traces/trace_egl_loader_autogen.h":
|
||||
"372c734043680041148d75e1810d63c5",
|
||||
"2a417d513f4ad2892ccc5c66e42e5759",
|
||||
"src/tests/restricted_traces/trace_gles_loader_autogen.cpp":
|
||||
"66d09a2dd240c073868fc14118186c69",
|
||||
"src/tests/restricted_traces/trace_gles_loader_autogen.h":
|
||||
"e6bdefb58de439b5b38d4d2546ae44e7",
|
||||
"util/egl_loader_autogen.cpp":
|
||||
"7134e5535bf520664b33ba5a34e46351",
|
||||
"6afbbc553222705dd77c48e7510250dd",
|
||||
"util/egl_loader_autogen.h":
|
||||
"07612f2570e6ed43f8ccdf32934d73b8",
|
||||
"3e1e6ea983aa952601d1b6de83161a8a",
|
||||
"util/gles_loader_autogen.cpp":
|
||||
"01482c56dd2c4410149feaa8bff21bbe",
|
||||
"util/gles_loader_autogen.h":
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"scripts/egl.xml":
|
||||
"013c552e6c523abdcf268268ea47e9fe",
|
||||
"scripts/egl_angle_ext.xml":
|
||||
"72bf10ed3d23d5cdfa49934a0393b30d",
|
||||
"3618e835dbe1b28ef5ad20e7e36d1262",
|
||||
"scripts/entry_point_packed_egl_enums.json":
|
||||
"a72ae855c6b403912103b519139951a1",
|
||||
"scripts/entry_point_packed_gl_enums.json":
|
||||
|
@ -20,9 +20,9 @@
|
|||
"scripts/wgl.xml":
|
||||
"c36001431919e1c435f1215a85f7e1db",
|
||||
"src/common/entry_points_enum_autogen.cpp":
|
||||
"ecc75a3167c60a45642f44852c921771",
|
||||
"f882ef34359bd438d01653ec0228b4a8",
|
||||
"src/common/entry_points_enum_autogen.h":
|
||||
"c3e69949e19486bed33badcfb9a05805",
|
||||
"e944a17f832d00a2ac9762ce957f370c",
|
||||
"src/libANGLE/Context_gl_1_autogen.h":
|
||||
"115d224fd28b0bc2b2800354bb57fcf3",
|
||||
"src/libANGLE/Context_gl_2_autogen.h":
|
||||
|
@ -76,7 +76,7 @@
|
|||
"src/libANGLE/validationCL_autogen.h":
|
||||
"0022d0cdb6a9e2ef4a59b71164f62333",
|
||||
"src/libANGLE/validationEGL_autogen.h":
|
||||
"9efb40631ea8b4779167f3ecab1b5794",
|
||||
"e980833db949005de05ebfda3b65a18b",
|
||||
"src/libANGLE/validationES1_autogen.h":
|
||||
"99af5e328690ae78d7724a80e94cfac5",
|
||||
"src/libANGLE/validationES2_autogen.h":
|
||||
|
@ -98,9 +98,9 @@
|
|||
"src/libANGLE/validationGL4_autogen.h":
|
||||
"0477150779497ad894973f0e4b830d6b",
|
||||
"src/libEGL/libEGL_autogen.cpp":
|
||||
"f94c18dc41b0ce55d56dc002a32bb6b7",
|
||||
"d2a4716a1e32416b64aa11da7294a2d1",
|
||||
"src/libEGL/libEGL_autogen.def":
|
||||
"fdd4a110a95c3a2fed33c4b5f110650d",
|
||||
"773be535c00e01e343b52561fca73a6b",
|
||||
"src/libGL/entry_points_gl_1_autogen.cpp":
|
||||
"8148ccb597c5c77db7d5e532c7152243",
|
||||
"src/libGL/entry_points_gl_1_autogen.h":
|
||||
|
@ -124,7 +124,7 @@
|
|||
"src/libGLESv2/cl_stubs_autogen.h":
|
||||
"6d880c6b65284192b5842f0e42ad2741",
|
||||
"src/libGLESv2/egl_ext_stubs_autogen.h":
|
||||
"0e33e7ae4c96995f674bff8cf92825ff",
|
||||
"8614c0f3e9bec09421f557c5bb7826ef",
|
||||
"src/libGLESv2/egl_get_labeled_object_data.json":
|
||||
"2f4148b2ddf34e62670e32c5e6da4937",
|
||||
"src/libGLESv2/egl_stubs_autogen.h":
|
||||
|
@ -138,9 +138,9 @@
|
|||
"src/libGLESv2/entry_points_egl_autogen.h":
|
||||
"3bc7a8df9deadd7cfd615d0cfad0c6a8",
|
||||
"src/libGLESv2/entry_points_egl_ext_autogen.cpp":
|
||||
"c9d5df7d303e13fe9b3f78dafa22eff0",
|
||||
"9acd4e2c7d4ae61adc2cc01029f1dd08",
|
||||
"src/libGLESv2/entry_points_egl_ext_autogen.h":
|
||||
"df2219883f43fc1c7a2b568f4f49185a",
|
||||
"5ce03067f75c6179d47fe85186dff646",
|
||||
"src/libGLESv2/entry_points_gles_1_0_autogen.cpp":
|
||||
"4cb9f5d56c003d1627365cfa34470edc",
|
||||
"src/libGLESv2/entry_points_gles_1_0_autogen.h":
|
||||
|
@ -168,11 +168,11 @@
|
|||
"src/libGLESv2/libGLESv2_autogen.cpp":
|
||||
"6a7e775b20563d405005cb1bbcf67e76",
|
||||
"src/libGLESv2/libGLESv2_autogen.def":
|
||||
"e49b6127cf3bdd546ed938d9c280bd5f",
|
||||
"14c09cde5374162e2c3dcd1947804f0d",
|
||||
"src/libGLESv2/libGLESv2_no_capture_autogen.def":
|
||||
"60d6dfc9890a30fa862153a9f1ac29e7",
|
||||
"0f9168c1ebb1f9c044b6249969a8ec0c",
|
||||
"src/libGLESv2/libGLESv2_with_capture_autogen.def":
|
||||
"d0915e85df4e78a5384ac1fc5a16b9e6",
|
||||
"4d77d1e5ceee453bd99a150f6a24aa80",
|
||||
"src/libOpenCL/libOpenCL_autogen.cpp":
|
||||
"10849978c910dc1af5dd4f0c815d1581"
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
"scripts/egl.xml":
|
||||
"013c552e6c523abdcf268268ea47e9fe",
|
||||
"scripts/egl_angle_ext.xml":
|
||||
"72bf10ed3d23d5cdfa49934a0393b30d",
|
||||
"3618e835dbe1b28ef5ad20e7e36d1262",
|
||||
"scripts/gen_proc_table.py":
|
||||
"8336449da7e36f45dd6d70c44add2ebf",
|
||||
"scripts/gl.xml":
|
||||
|
@ -20,7 +20,7 @@
|
|||
"src/libGLESv2/proc_table_cl_autogen.cpp":
|
||||
"ed003b0f041aaaa35b67d3fe07e61f91",
|
||||
"src/libGLESv2/proc_table_egl_autogen.cpp":
|
||||
"1fe7444ee1f5b6300d5d02b7eb378cc2",
|
||||
"c6b5d0b60395ccd33a1d9e38341eeef3",
|
||||
"src/libOpenCL/libOpenCL_autogen.map":
|
||||
"bc5f5cf48227149ed321258a16eff1d7"
|
||||
}
|
|
@ -113,6 +113,12 @@
|
|||
<proto><pytpe>void</pytpe> <name>eglHandleGPUSwitchANGLE</name></proto>
|
||||
<param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
|
||||
</command>
|
||||
<command>
|
||||
<proto><pytpe>void</pytpe> <name>eglForceGPUSwitchANGLE</name></proto>
|
||||
<param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
|
||||
<param><ptype>EGLint</ptype> <name>gpuIDHigh</name></param>
|
||||
<param><ptype>EGLint</ptype> <name>gpuIDLow</name></param>
|
||||
</command>
|
||||
<command>
|
||||
<proto><ptype>EGLBoolean</ptype> <name>eglQueryDisplayAttribANGLE</name></proto>
|
||||
<param><ptype>EGLDisplay</ptype> <name>dpy</name></param>
|
||||
|
@ -180,6 +186,7 @@
|
|||
<command name="eglReleaseHighPowerGPUANGLE"/>
|
||||
<command name="eglReacquireHighPowerGPUANGLE"/>
|
||||
<command name="eglHandleGPUSwitchANGLE"/>
|
||||
<command name="eglForceGPUSwitchANGLE"/>
|
||||
</require>
|
||||
</extension>
|
||||
<extension name="EGL_ANGLE_display_semaphore_share_group" supported="egl">
|
||||
|
|
|
@ -314,6 +314,8 @@ const char *GetEntryPointName(EntryPoint ep)
|
|||
return "eglDupNativeFenceFDANDROID";
|
||||
case EntryPoint::EGLExportVkImageANGLE:
|
||||
return "eglExportVkImageANGLE";
|
||||
case EntryPoint::EGLForceGPUSwitchANGLE:
|
||||
return "eglForceGPUSwitchANGLE";
|
||||
case EntryPoint::EGLGetCompositorTimingANDROID:
|
||||
return "eglGetCompositorTimingANDROID";
|
||||
case EntryPoint::EGLGetCompositorTimingSupportedANDROID:
|
||||
|
|
|
@ -163,6 +163,7 @@ enum class EntryPoint
|
|||
EGLDestroySyncKHR,
|
||||
EGLDupNativeFenceFDANDROID,
|
||||
EGLExportVkImageANGLE,
|
||||
EGLForceGPUSwitchANGLE,
|
||||
EGLGetCompositorTimingANDROID,
|
||||
EGLGetCompositorTimingSupportedANDROID,
|
||||
EGLGetConfigAttrib,
|
||||
|
|
|
@ -191,7 +191,7 @@ void GetIORegistryDevices(std::vector<GPUDeviceInfo> *devices)
|
|||
}
|
||||
}
|
||||
|
||||
void SetActiveGPUIndex(SystemInfo *info)
|
||||
void ForceGPUSwitchIndex(SystemInfo *info)
|
||||
{
|
||||
VendorID activeVendor = 0;
|
||||
DeviceID activeDevice = 0;
|
||||
|
@ -373,7 +373,7 @@ bool GetSystemInfo_mac(SystemInfo *info)
|
|||
// GPU instead of the non-intel GPU
|
||||
if (@available(macOS 10.13, *))
|
||||
{
|
||||
SetActiveGPUIndex(info);
|
||||
ForceGPUSwitchIndex(info);
|
||||
}
|
||||
|
||||
// Figure out whether this is a dual-GPU system.
|
||||
|
|
|
@ -2372,6 +2372,13 @@ Error Display::handleGPUSwitch()
|
|||
return NoError();
|
||||
}
|
||||
|
||||
Error Display::forceGPUSwitch(EGLint gpuIDHigh, EGLint gpuIDLow)
|
||||
{
|
||||
ANGLE_TRY(mImplementation->forceGPUSwitch(gpuIDHigh, gpuIDLow));
|
||||
initVendorString();
|
||||
return NoError();
|
||||
}
|
||||
|
||||
bool Display::supportsDmaBufFormat(EGLint format) const
|
||||
{
|
||||
return mImplementation->supportsDmaBufFormat(format);
|
||||
|
|
|
@ -303,6 +303,7 @@ class Display final : public LabeledObject,
|
|||
void returnZeroFilledBuffer(angle::ScratchBuffer zeroFilledBuffer);
|
||||
|
||||
egl::Error handleGPUSwitch();
|
||||
egl::Error forceGPUSwitch(EGLint gpuIDHigh, EGLint gpuIDLow);
|
||||
|
||||
std::mutex &getDisplayGlobalMutex() { return mDisplayGlobalMutex; }
|
||||
std::mutex &getProgramCacheMutex() { return mProgramCacheMutex; }
|
||||
|
|
|
@ -74,6 +74,11 @@ egl::Error DisplayImpl::handleGPUSwitch()
|
|||
return egl::NoError();
|
||||
}
|
||||
|
||||
egl::Error DisplayImpl::forceGPUSwitch(EGLint gpuIDHigh, EGLint gpuIDLow)
|
||||
{
|
||||
return egl::NoError();
|
||||
}
|
||||
|
||||
egl::Error DisplayImpl::validateClientBuffer(const egl::Config *configuration,
|
||||
EGLenum buftype,
|
||||
EGLClientBuffer clientBuffer,
|
||||
|
|
|
@ -120,6 +120,7 @@ class DisplayImpl : public EGLImplFactory, public angle::Subject
|
|||
const egl::DisplayState &getState() const { return mState; }
|
||||
|
||||
virtual egl::Error handleGPUSwitch();
|
||||
virtual egl::Error forceGPUSwitch(EGLint gpuIDHigh, EGLint gpuIDLow);
|
||||
|
||||
virtual bool isX11() const;
|
||||
|
||||
|
|
|
@ -105,6 +105,7 @@ class DisplayCGL : public DisplayGL
|
|||
egl::Error referenceDiscreteGPU();
|
||||
egl::Error unreferenceDiscreteGPU();
|
||||
egl::Error handleGPUSwitch() override;
|
||||
egl::Error forceGPUSwitch(EGLint gpuIDHigh, EGLint gpuIDLow) override;
|
||||
|
||||
private:
|
||||
egl::Error makeCurrentSurfaceless(gl::Context *context) override;
|
||||
|
@ -113,6 +114,7 @@ class DisplayCGL : public DisplayGL
|
|||
void generateCaps(egl::Caps *outCaps) const override;
|
||||
|
||||
void checkDiscreteGPUStatus();
|
||||
void setContextToGPU(uint64_t gpuID, GLint virtualScreen);
|
||||
|
||||
std::shared_ptr<RendererGL> mRenderer;
|
||||
|
||||
|
|
|
@ -50,9 +50,8 @@ using IORegistryGPUID = uint64_t;
|
|||
// Code from WebKit to set an OpenGL context to use a particular GPU by ID.
|
||||
// https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/platform/graphics/cocoa/GraphicsContextGLOpenGLCocoa.mm
|
||||
// Used with permission.
|
||||
static void SetGPUByRegistryID(CGLContextObj contextObj,
|
||||
CGLPixelFormatObj pixelFormatObj,
|
||||
IORegistryGPUID preferredGPUID)
|
||||
static std::optional<GLint> GetVirtualScreenByRegistryID(CGLPixelFormatObj pixelFormatObj,
|
||||
IORegistryGPUID gpuID)
|
||||
{
|
||||
if (@available(macOS 10.13, *))
|
||||
{
|
||||
|
@ -62,51 +61,65 @@ static void SetGPUByRegistryID(CGLContextObj contextObj,
|
|||
// registryID. CGLSetVirtualScreen can then be used to tell OpenGL which GPU it should be
|
||||
// using.
|
||||
|
||||
if (!contextObj || !preferredGPUID)
|
||||
return;
|
||||
|
||||
GLint virtualScreenCount = 0;
|
||||
CGLError error = CGLDescribePixelFormat(pixelFormatObj, 0, kCGLPFAVirtualScreenCount,
|
||||
&virtualScreenCount);
|
||||
ASSERT(error == kCGLNoError);
|
||||
|
||||
GLint firstAcceleratedScreen = -1;
|
||||
if (error != kCGLNoError)
|
||||
{
|
||||
NOTREACHED();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
for (GLint virtualScreen = 0; virtualScreen < virtualScreenCount; ++virtualScreen)
|
||||
{
|
||||
GLint displayMask = 0;
|
||||
error = CGLDescribePixelFormat(pixelFormatObj, virtualScreen, kCGLPFADisplayMask,
|
||||
&displayMask);
|
||||
ASSERT(error == kCGLNoError);
|
||||
|
||||
auto gpuID = angle::GetGpuIDFromOpenGLDisplayMask(displayMask);
|
||||
|
||||
if (gpuID == preferredGPUID)
|
||||
if (error != kCGLNoError)
|
||||
{
|
||||
error = CGLSetVirtualScreen(contextObj, virtualScreen);
|
||||
ASSERT(error == kCGLNoError);
|
||||
fprintf(stderr, "Context (%p) set to GPU with ID: (%lld).", contextObj, gpuID);
|
||||
return;
|
||||
NOTREACHED();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (firstAcceleratedScreen < 0)
|
||||
auto virtualScreenGPUID = angle::GetGpuIDFromOpenGLDisplayMask(displayMask);
|
||||
if (virtualScreenGPUID == gpuID)
|
||||
{
|
||||
GLint isAccelerated = 0;
|
||||
error = CGLDescribePixelFormat(pixelFormatObj, virtualScreen, kCGLPFAAccelerated,
|
||||
&isAccelerated);
|
||||
ASSERT(error == kCGLNoError);
|
||||
if (isAccelerated)
|
||||
firstAcceleratedScreen = virtualScreen;
|
||||
return virtualScreen;
|
||||
}
|
||||
}
|
||||
|
||||
// No registryID match found; set to first hardware-accelerated virtual screen.
|
||||
if (firstAcceleratedScreen >= 0)
|
||||
{
|
||||
error = CGLSetVirtualScreen(contextObj, firstAcceleratedScreen);
|
||||
ASSERT(error == kCGLNoError);
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static std::optional<GLint> GetFirstAcceleratedVirtualScreen(CGLPixelFormatObj pixelFormatObj)
|
||||
{
|
||||
if (@available(macOS 10.13, *))
|
||||
{
|
||||
GLint virtualScreenCount = 0;
|
||||
CGLError error = CGLDescribePixelFormat(pixelFormatObj, 0, kCGLPFAVirtualScreenCount,
|
||||
&virtualScreenCount);
|
||||
if (error != kCGLNoError)
|
||||
{
|
||||
NOTREACHED();
|
||||
return std::nullopt;
|
||||
}
|
||||
for (GLint virtualScreen = 0; virtualScreen < virtualScreenCount; ++virtualScreen)
|
||||
{
|
||||
GLint isAccelerated = 0;
|
||||
error = CGLDescribePixelFormat(pixelFormatObj, virtualScreen, kCGLPFAAccelerated,
|
||||
&isAccelerated);
|
||||
if (error != kCGLNoError)
|
||||
{
|
||||
NOTREACHED();
|
||||
return std::nullopt;
|
||||
}
|
||||
if (isAccelerated)
|
||||
{
|
||||
return virtualScreen;
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
@ -650,22 +663,56 @@ egl::Error DisplayCGL::handleGPUSwitch()
|
|||
uint64_t gpuID = angle::GetGpuIDFromDisplayID(kCGDirectMainDisplay);
|
||||
if (gpuID != mCurrentGPUID)
|
||||
{
|
||||
SetGPUByRegistryID(mContext, mPixelFormat, gpuID);
|
||||
// Performing the above operation seems to need a call to CGLSetCurrentContext to make
|
||||
// the context work properly again. Failing to do this returns null strings for
|
||||
// GL_VENDOR and GL_RENDERER.
|
||||
CGLUpdateContext(mContext);
|
||||
CGLSetCurrentContext(mContext);
|
||||
onStateChange(angle::SubjectMessage::SubjectChanged);
|
||||
mCurrentGPUID = gpuID;
|
||||
|
||||
mRenderer->handleGPUSwitch();
|
||||
auto virtualScreen = GetVirtualScreenByRegistryID(mPixelFormat, gpuID);
|
||||
if (!virtualScreen)
|
||||
{
|
||||
virtualScreen = GetFirstAcceleratedVirtualScreen(mPixelFormat);
|
||||
}
|
||||
if (virtualScreen)
|
||||
{
|
||||
setContextToGPU(gpuID, *virtualScreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return egl::NoError();
|
||||
}
|
||||
|
||||
egl::Error DisplayCGL::forceGPUSwitch(EGLint gpuIDHigh, EGLint gpuIDLow)
|
||||
{
|
||||
if (mSupportsGPUSwitching)
|
||||
{
|
||||
uint64_t gpuID = static_cast<uint64_t>(static_cast<uint32_t>(gpuIDHigh)) << 32 |
|
||||
static_cast<uint32_t>(gpuIDLow);
|
||||
if (gpuID != mCurrentGPUID)
|
||||
{
|
||||
auto virtualScreen = GetVirtualScreenByRegistryID(mPixelFormat, gpuID);
|
||||
if (virtualScreen)
|
||||
{
|
||||
setContextToGPU(gpuID, *virtualScreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
return egl::NoError();
|
||||
}
|
||||
|
||||
void DisplayCGL::setContextToGPU(uint64_t gpuID, GLint virtualScreen)
|
||||
{
|
||||
CGLError error = CGLSetVirtualScreen(mContext, virtualScreen);
|
||||
ASSERT(error == kCGLNoError);
|
||||
if (error == kCGLNoError)
|
||||
{
|
||||
// Performing the above operation seems to need a call to CGLSetCurrentContext to make
|
||||
// the context work properly again. Failing to do this returns null strings for
|
||||
// GL_VENDOR and GL_RENDERER.
|
||||
CGLUpdateContext(mContext);
|
||||
CGLSetCurrentContext(mContext);
|
||||
onStateChange(angle::SubjectMessage::SubjectChanged);
|
||||
mCurrentGPUID = gpuID;
|
||||
mRenderer->handleGPUSwitch();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rx
|
||||
|
||||
#endif // defined(ANGLE_PLATFORM_MACOS) || defined(ANGLE_PLATFORM_MACCATALYST)
|
||||
|
|
|
@ -363,7 +363,6 @@ namespace vk
|
|||
{
|
||||
const char *gLoaderLayersPathEnv = "VK_LAYER_PATH";
|
||||
const char *gLoaderICDFilenamesEnv = "VK_ICD_FILENAMES";
|
||||
const char *gANGLEPreferredDevice = "ANGLE_PREFERRED_DEVICE";
|
||||
|
||||
VkImageAspectFlags GetDepthStencilAspectFlags(const angle::Format &format)
|
||||
{
|
||||
|
|
|
@ -6234,6 +6234,15 @@ bool ValidateHandleGPUSwitchANGLE(const ValidationContext *val, const Display *d
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ValidateForceGPUSwitchANGLE(const ValidationContext *val,
|
||||
const Display *display,
|
||||
EGLint gpuIDHigh,
|
||||
EGLint gpuIDLow)
|
||||
{
|
||||
ANGLE_VALIDATION_TRY(ValidateDisplay(val, display));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ValidateGetCurrentDisplay(const ValidationContext *val)
|
||||
{
|
||||
return true;
|
||||
|
|
|
@ -250,6 +250,10 @@ bool ValidateReacquireHighPowerGPUANGLE(const ValidationContext *val,
|
|||
const egl::Display *dpyPacked,
|
||||
const gl::Context *ctxPacked);
|
||||
bool ValidateHandleGPUSwitchANGLE(const ValidationContext *val, const egl::Display *dpyPacked);
|
||||
bool ValidateForceGPUSwitchANGLE(const ValidationContext *val,
|
||||
const egl::Display *dpyPacked,
|
||||
EGLint gpuIDHigh,
|
||||
EGLint gpuIDLow);
|
||||
|
||||
// EGL_ANGLE_prepare_swap_buffers
|
||||
bool ValidatePrepareSwapBuffersANGLE(const ValidationContext *val,
|
||||
|
|
|
@ -68,6 +68,7 @@ PFNEGLCREATEDEVICEANGLEPROC l_EGL_CreateDeviceANGLE;
|
|||
PFNEGLRELEASEDEVICEANGLEPROC l_EGL_ReleaseDeviceANGLE;
|
||||
PFNEGLQUERYDISPLAYATTRIBANGLEPROC l_EGL_QueryDisplayAttribANGLE;
|
||||
PFNEGLQUERYSTRINGIANGLEPROC l_EGL_QueryStringiANGLE;
|
||||
PFNEGLFORCEGPUSWITCHANGLEPROC l_EGL_ForceGPUSwitchANGLE;
|
||||
PFNEGLHANDLEGPUSWITCHANGLEPROC l_EGL_HandleGPUSwitchANGLE;
|
||||
PFNEGLREACQUIREHIGHPOWERGPUANGLEPROC l_EGL_ReacquireHighPowerGPUANGLE;
|
||||
PFNEGLRELEASEHIGHPOWERGPUANGLEPROC l_EGL_ReleaseHighPowerGPUANGLE;
|
||||
|
@ -213,6 +214,8 @@ void LoadEGL_EGL(LoadProc loadProc)
|
|||
loadProc("EGL_QueryDisplayAttribANGLE"));
|
||||
l_EGL_QueryStringiANGLE =
|
||||
reinterpret_cast<PFNEGLQUERYSTRINGIANGLEPROC>(loadProc("EGL_QueryStringiANGLE"));
|
||||
l_EGL_ForceGPUSwitchANGLE =
|
||||
reinterpret_cast<PFNEGLFORCEGPUSWITCHANGLEPROC>(loadProc("EGL_ForceGPUSwitchANGLE"));
|
||||
l_EGL_HandleGPUSwitchANGLE =
|
||||
reinterpret_cast<PFNEGLHANDLEGPUSWITCHANGLEPROC>(loadProc("EGL_HandleGPUSwitchANGLE"));
|
||||
l_EGL_ReacquireHighPowerGPUANGLE = reinterpret_cast<PFNEGLREACQUIREHIGHPOWERGPUANGLEPROC>(
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
#define EGL_ReleaseDeviceANGLE l_EGL_ReleaseDeviceANGLE
|
||||
#define EGL_QueryDisplayAttribANGLE l_EGL_QueryDisplayAttribANGLE
|
||||
#define EGL_QueryStringiANGLE l_EGL_QueryStringiANGLE
|
||||
#define EGL_ForceGPUSwitchANGLE l_EGL_ForceGPUSwitchANGLE
|
||||
#define EGL_HandleGPUSwitchANGLE l_EGL_HandleGPUSwitchANGLE
|
||||
#define EGL_ReacquireHighPowerGPUANGLE l_EGL_ReacquireHighPowerGPUANGLE
|
||||
#define EGL_ReleaseHighPowerGPUANGLE l_EGL_ReleaseHighPowerGPUANGLE
|
||||
|
@ -183,6 +184,7 @@ ANGLE_NO_EXPORT extern PFNEGLCREATEDEVICEANGLEPROC l_EGL_CreateDeviceANGLE;
|
|||
ANGLE_NO_EXPORT extern PFNEGLRELEASEDEVICEANGLEPROC l_EGL_ReleaseDeviceANGLE;
|
||||
ANGLE_NO_EXPORT extern PFNEGLQUERYDISPLAYATTRIBANGLEPROC l_EGL_QueryDisplayAttribANGLE;
|
||||
ANGLE_NO_EXPORT extern PFNEGLQUERYSTRINGIANGLEPROC l_EGL_QueryStringiANGLE;
|
||||
ANGLE_NO_EXPORT extern PFNEGLFORCEGPUSWITCHANGLEPROC l_EGL_ForceGPUSwitchANGLE;
|
||||
ANGLE_NO_EXPORT extern PFNEGLHANDLEGPUSWITCHANGLEPROC l_EGL_HandleGPUSwitchANGLE;
|
||||
ANGLE_NO_EXPORT extern PFNEGLREACQUIREHIGHPOWERGPUANGLEPROC l_EGL_ReacquireHighPowerGPUANGLE;
|
||||
ANGLE_NO_EXPORT extern PFNEGLRELEASEHIGHPOWERGPUANGLEPROC l_EGL_ReleaseHighPowerGPUANGLE;
|
||||
|
|
|
@ -514,6 +514,12 @@ void EGLAPIENTRY eglHandleGPUSwitchANGLE(EGLDisplay dpy)
|
|||
return EGL_HandleGPUSwitchANGLE(dpy);
|
||||
}
|
||||
|
||||
void EGLAPIENTRY eglForceGPUSwitchANGLE(EGLDisplay dpy, EGLint gpuIDHigh, EGLint gpuIDLow)
|
||||
{
|
||||
EnsureEGLLoaded();
|
||||
return EGL_ForceGPUSwitchANGLE(dpy, gpuIDHigh, gpuIDLow);
|
||||
}
|
||||
|
||||
// EGL_ANGLE_prepare_swap_buffers
|
||||
EGLBoolean EGLAPIENTRY eglPrepareSwapBuffersANGLE(EGLDisplay dpy, EGLSurface surface)
|
||||
{
|
||||
|
|
|
@ -92,6 +92,7 @@ EXPORTS
|
|||
eglQueryStringiANGLE
|
||||
|
||||
; EGL_ANGLE_power_preference
|
||||
eglForceGPUSwitchANGLE
|
||||
eglHandleGPUSwitchANGLE
|
||||
eglReacquireHighPowerGPUANGLE
|
||||
eglReleaseHighPowerGPUANGLE
|
||||
|
|
|
@ -824,6 +824,16 @@ void HandleGPUSwitchANGLE(Thread *thread, Display *display)
|
|||
thread->setSuccess();
|
||||
}
|
||||
|
||||
void ForceGPUSwitchANGLE(Thread *thread, Display *display, EGLint gpuIDHigh, EGLint gpuIDLow)
|
||||
{
|
||||
ANGLE_EGL_TRY(thread, display->prepareForCall(), "eglForceGPUSwitchANGLE",
|
||||
GetDisplayIfValid(display));
|
||||
ANGLE_EGL_TRY(thread, display->forceGPUSwitch(gpuIDHigh, gpuIDLow), "eglForceGPUSwitchANGLE",
|
||||
GetDisplayIfValid(display));
|
||||
|
||||
thread->setSuccess();
|
||||
}
|
||||
|
||||
EGLBoolean QueryDisplayAttribANGLE(Thread *thread,
|
||||
Display *display,
|
||||
EGLint attribute,
|
||||
|
|
|
@ -246,6 +246,10 @@ EGLBoolean PrepareSwapBuffersANGLE(EGLDisplay dpy, EGLSurface surface);
|
|||
void ReleaseHighPowerGPUANGLE(Thread *thread, egl::Display *dpyPacked, gl::Context *ctxPacked);
|
||||
void ReacquireHighPowerGPUANGLE(Thread *thread, egl::Display *dpyPacked, gl::Context *ctxPacked);
|
||||
void HandleGPUSwitchANGLE(Thread *thread, egl::Display *dpyPacked);
|
||||
void ForceGPUSwitchANGLE(Thread *thread,
|
||||
egl::Display *dpyPacked,
|
||||
EGLint gpuIDHigh,
|
||||
EGLint gpuIDLow);
|
||||
EGLBoolean QueryDisplayAttribANGLE(Thread *thread,
|
||||
egl::Display *dpyPacked,
|
||||
EGLint attribute,
|
||||
|
|
|
@ -364,6 +364,23 @@ void EGLAPIENTRY EGL_HandleGPUSwitchANGLE(EGLDisplay dpy)
|
|||
HandleGPUSwitchANGLE(thread, dpyPacked);
|
||||
}
|
||||
|
||||
void EGLAPIENTRY EGL_ForceGPUSwitchANGLE(EGLDisplay dpy, EGLint gpuIDHigh, EGLint gpuIDLow)
|
||||
{
|
||||
|
||||
ANGLE_SCOPED_GLOBAL_LOCK();
|
||||
EGL_EVENT(ForceGPUSwitchANGLE, "dpy = 0x%016" PRIxPTR ", gpuIDHigh = %d, gpuIDLow = %d",
|
||||
(uintptr_t)dpy, gpuIDHigh, gpuIDLow);
|
||||
|
||||
Thread *thread = egl::GetCurrentThread();
|
||||
|
||||
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
|
||||
|
||||
ANGLE_EGL_VALIDATE_VOID(thread, ForceGPUSwitchANGLE, GetDisplayIfValid(dpyPacked), dpyPacked,
|
||||
gpuIDHigh, gpuIDLow);
|
||||
|
||||
ForceGPUSwitchANGLE(thread, dpyPacked, gpuIDHigh, gpuIDLow);
|
||||
}
|
||||
|
||||
// EGL_ANGLE_prepare_swap_buffers
|
||||
EGLBoolean EGLAPIENTRY EGL_PrepareSwapBuffersANGLE(EGLDisplay dpy, EGLSurface surface)
|
||||
{
|
||||
|
|
|
@ -78,6 +78,9 @@ ANGLE_EXPORT EGLBoolean EGLAPIENTRY EGL_QueryDisplayAttribANGLE(EGLDisplay dpy,
|
|||
ANGLE_EXPORT void EGLAPIENTRY EGL_ReleaseHighPowerGPUANGLE(EGLDisplay dpy, EGLContext ctx);
|
||||
ANGLE_EXPORT void EGLAPIENTRY EGL_ReacquireHighPowerGPUANGLE(EGLDisplay dpy, EGLContext ctx);
|
||||
ANGLE_EXPORT void EGLAPIENTRY EGL_HandleGPUSwitchANGLE(EGLDisplay dpy);
|
||||
ANGLE_EXPORT void EGLAPIENTRY EGL_ForceGPUSwitchANGLE(EGLDisplay dpy,
|
||||
EGLint gpuIDHigh,
|
||||
EGLint gpuIDLow);
|
||||
|
||||
// EGL_ANGLE_prepare_swap_buffers
|
||||
ANGLE_EXPORT EGLBoolean EGLAPIENTRY EGL_PrepareSwapBuffersANGLE(EGLDisplay dpy, EGLSurface surface);
|
||||
|
|
|
@ -1235,6 +1235,7 @@ EXPORTS
|
|||
EGL_QueryStringiANGLE
|
||||
|
||||
; EGL_ANGLE_power_preference
|
||||
EGL_ForceGPUSwitchANGLE
|
||||
EGL_HandleGPUSwitchANGLE
|
||||
EGL_ReacquireHighPowerGPUANGLE
|
||||
EGL_ReleaseHighPowerGPUANGLE
|
||||
|
|
|
@ -1235,6 +1235,7 @@ EXPORTS
|
|||
EGL_QueryStringiANGLE
|
||||
|
||||
; EGL_ANGLE_power_preference
|
||||
EGL_ForceGPUSwitchANGLE
|
||||
EGL_HandleGPUSwitchANGLE
|
||||
EGL_ReacquireHighPowerGPUANGLE
|
||||
EGL_ReleaseHighPowerGPUANGLE
|
||||
|
|
|
@ -1235,6 +1235,7 @@ EXPORTS
|
|||
EGL_QueryStringiANGLE
|
||||
|
||||
; EGL_ANGLE_power_preference
|
||||
EGL_ForceGPUSwitchANGLE
|
||||
EGL_HandleGPUSwitchANGLE
|
||||
EGL_ReacquireHighPowerGPUANGLE
|
||||
EGL_ReleaseHighPowerGPUANGLE
|
||||
|
|
|
@ -62,6 +62,7 @@ const ProcEntry g_procTable[] = {
|
|||
{"eglDestroySyncKHR", P(EGL_DestroySyncKHR)},
|
||||
{"eglDupNativeFenceFDANDROID", P(EGL_DupNativeFenceFDANDROID)},
|
||||
{"eglExportVkImageANGLE", P(EGL_ExportVkImageANGLE)},
|
||||
{"eglForceGPUSwitchANGLE", P(EGL_ForceGPUSwitchANGLE)},
|
||||
{"eglGetCompositorTimingANDROID", P(EGL_GetCompositorTimingANDROID)},
|
||||
{"eglGetCompositorTimingSupportedANDROID", P(EGL_GetCompositorTimingSupportedANDROID)},
|
||||
{"eglGetConfigAttrib", P(EGL_GetConfigAttrib)},
|
||||
|
@ -945,5 +946,5 @@ const ProcEntry g_procTable[] = {
|
|||
{"glWaitSync", P(GL_WaitSync)},
|
||||
{"glWeightPointerOES", P(GL_WeightPointerOES)}};
|
||||
|
||||
const size_t g_numProcs = 912;
|
||||
const size_t g_numProcs = 913;
|
||||
} // namespace egl
|
||||
|
|
|
@ -188,10 +188,13 @@ angle_end2end_tests_sources = [
|
|||
"test_utils/ANGLETest.h",
|
||||
"test_utils/MultiviewTest.cpp",
|
||||
"test_utils/MultiviewTest.h",
|
||||
"test_utils/system_info_util.cpp",
|
||||
"test_utils/system_info_util.h",
|
||||
]
|
||||
angle_end2end_tests_mac_sources = [
|
||||
"egl_tests/EGLDeviceCGLTest.cpp",
|
||||
"egl_tests/EGLIOSurfaceClientBufferTest.cpp",
|
||||
"egl_tests/EGLPowerPreferenceTest.cpp",
|
||||
"egl_tests/EGLSurfaceTestMac.mm",
|
||||
"gl_tests/ImageTestMetal.mm",
|
||||
]
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "common/string_utils.h"
|
||||
#include "gpu_info_util/SystemInfo.h"
|
||||
#include "test_utils/ANGLETest.h"
|
||||
#include "test_utils/system_info_util.h"
|
||||
#include "util/OSWindow.h"
|
||||
|
||||
using namespace angle;
|
||||
|
@ -25,51 +26,15 @@ class EGLDisplaySelectionTest : public ANGLETest
|
|||
|
||||
protected:
|
||||
// Returns the index of the low or high power GPU in SystemInfo depending on the argument.
|
||||
int findGPU(bool lowPower)
|
||||
int findGPU(bool lowPower) const
|
||||
{
|
||||
if (mSystemInfo.gpus.size() < 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i < static_cast<int>(mSystemInfo.gpus.size()); ++i)
|
||||
{
|
||||
if (lowPower && IsIntel(mSystemInfo.gpus[i].vendorId))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
// Return the high power GPU, i.e any non-intel GPU
|
||||
else if (!lowPower && !IsIntel(mSystemInfo.gpus[i].vendorId))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// Can't find GPU
|
||||
ASSERT(false);
|
||||
return 0;
|
||||
if (lowPower)
|
||||
return FindLowPowerGPU(mSystemInfo);
|
||||
return FindHighPowerGPU(mSystemInfo);
|
||||
}
|
||||
|
||||
// Returns the index of the active GPU in SystemInfo based on the renderer string.
|
||||
int findActiveGPU()
|
||||
{
|
||||
char *renderer = (char *)glGetString(GL_RENDERER);
|
||||
std::string rendererString(renderer);
|
||||
for (int i = 0; i < static_cast<int>(mSystemInfo.gpus.size()); ++i)
|
||||
{
|
||||
std::vector<std::string> vendorTokens;
|
||||
angle::SplitStringAlongWhitespace(VendorName(mSystemInfo.gpus[i].vendorId),
|
||||
&vendorTokens);
|
||||
for (std::string &token : vendorTokens)
|
||||
{
|
||||
if (rendererString.find(token) != std::string::npos)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Can't find active GPU
|
||||
ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
int findActiveGPU() const { return FindActiveOpenGLGPU(mSystemInfo); }
|
||||
|
||||
SystemInfo mSystemInfo;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
//
|
||||
// Copyright 2022 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.
|
||||
//
|
||||
// EGLPowerPreferenceTest.cpp:
|
||||
// Checks the implementation of EGL_ANGLE_power_preference.
|
||||
//
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <tuple>
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/string_utils.h"
|
||||
#include "gpu_info_util/SystemInfo.h"
|
||||
#include "test_utils/ANGLETest.h"
|
||||
#include "test_utils/angle_test_platform.h"
|
||||
#include "test_utils/system_info_util.h"
|
||||
#include "util/OSWindow.h"
|
||||
|
||||
using namespace angle;
|
||||
namespace
|
||||
{
|
||||
// TODO(anglebug.com/7093): Implement bundling of Info.plist to angle_end2end_tests
|
||||
// In the mean time, change this manually to true and cp src/tests/end2end_tests/mac/Info.plist
|
||||
// out/Debug/
|
||||
const bool testRunnerSupportsAutomaticGraphicsSwitching = false;
|
||||
} // namespace
|
||||
class EGLPowerPreferenceTest : public ANGLETest
|
||||
{
|
||||
public:
|
||||
void testSetUp() override { (void)GetSystemInfo(&mSystemInfo); }
|
||||
|
||||
protected:
|
||||
auto getGpuIdParts(size_t gpuIndex) const
|
||||
{
|
||||
uint64_t deviceId = mSystemInfo.gpus[gpuIndex].systemDeviceId;
|
||||
return std::make_tuple(GetSystemDeviceIdHighPart(deviceId),
|
||||
GetSystemDeviceIdLowPart(deviceId));
|
||||
}
|
||||
|
||||
EGLDisplay getDisplay() const { return getEGLWindow()->getDisplay(); }
|
||||
|
||||
SystemInfo mSystemInfo;
|
||||
};
|
||||
|
||||
TEST_P(EGLPowerPreferenceTest, ForceGPUSwitch)
|
||||
{
|
||||
ANGLE_SKIP_TEST_IF(!testRunnerSupportsAutomaticGraphicsSwitching);
|
||||
ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(getDisplay(), "EGL_ANGLE_power_preference"));
|
||||
size_t lowPower = FindLowPowerGPU(mSystemInfo);
|
||||
size_t highPower = FindHighPowerGPU(mSystemInfo);
|
||||
size_t initialGPU = FindActiveOpenGLGPU(mSystemInfo);
|
||||
ASSERT_TRUE(lowPower == initialGPU || highPower == initialGPU);
|
||||
|
||||
EGLint hi = 0;
|
||||
EGLint lo = 0;
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
std::tie(hi, lo) = getGpuIdParts(lowPower);
|
||||
eglForceGPUSwitchANGLE(getDisplay(), hi, lo);
|
||||
EXPECT_EQ(lowPower, FindActiveOpenGLGPU(mSystemInfo));
|
||||
std::tie(hi, lo) = getGpuIdParts(highPower);
|
||||
eglForceGPUSwitchANGLE(getDisplay(), hi, lo);
|
||||
EXPECT_EQ(highPower, FindActiveOpenGLGPU(mSystemInfo));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(EGLPowerPreferenceTest, HandleGPUSwitchAfterForceGPUSwitch)
|
||||
{
|
||||
ANGLE_SKIP_TEST_IF(!testRunnerSupportsAutomaticGraphicsSwitching);
|
||||
ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(getDisplay(), "EGL_ANGLE_power_preference"));
|
||||
size_t initialGPU = FindActiveOpenGLGPU(mSystemInfo);
|
||||
size_t changedGPU = FindLowPowerGPU(mSystemInfo);
|
||||
if (initialGPU == changedGPU)
|
||||
{
|
||||
changedGPU = FindHighPowerGPU(mSystemInfo);
|
||||
}
|
||||
EGLint hi = 0;
|
||||
EGLint lo = 0;
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
std::tie(hi, lo) = getGpuIdParts(changedGPU);
|
||||
eglForceGPUSwitchANGLE(getDisplay(), hi, lo);
|
||||
ASSERT_EQ(changedGPU, FindActiveOpenGLGPU(mSystemInfo));
|
||||
eglHandleGPUSwitchANGLE(getDisplay());
|
||||
ASSERT_EQ(initialGPU, FindActiveOpenGLGPU(mSystemInfo));
|
||||
}
|
||||
}
|
||||
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLPowerPreferenceTest);
|
||||
ANGLE_INSTANTIATE_TEST(EGLPowerPreferenceTest, ES2_OPENGL(), ES3_OPENGL());
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleName</key>
|
||||
<string>angle_end2end_tests</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.chromium.angle.angle_end2end_tests</string>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -72,6 +72,7 @@ ANGLE_TRACE_LOADER_EXPORT PFNEGLCREATEDEVICEANGLEPROC t_eglCreateDeviceANGLE;
|
|||
ANGLE_TRACE_LOADER_EXPORT PFNEGLRELEASEDEVICEANGLEPROC t_eglReleaseDeviceANGLE;
|
||||
ANGLE_TRACE_LOADER_EXPORT PFNEGLQUERYDISPLAYATTRIBANGLEPROC t_eglQueryDisplayAttribANGLE;
|
||||
ANGLE_TRACE_LOADER_EXPORT PFNEGLQUERYSTRINGIANGLEPROC t_eglQueryStringiANGLE;
|
||||
ANGLE_TRACE_LOADER_EXPORT PFNEGLFORCEGPUSWITCHANGLEPROC t_eglForceGPUSwitchANGLE;
|
||||
ANGLE_TRACE_LOADER_EXPORT PFNEGLHANDLEGPUSWITCHANGLEPROC t_eglHandleGPUSwitchANGLE;
|
||||
ANGLE_TRACE_LOADER_EXPORT PFNEGLREACQUIREHIGHPOWERGPUANGLEPROC t_eglReacquireHighPowerGPUANGLE;
|
||||
ANGLE_TRACE_LOADER_EXPORT PFNEGLRELEASEHIGHPOWERGPUANGLEPROC t_eglReleaseHighPowerGPUANGLE;
|
||||
|
@ -219,6 +220,8 @@ void LoadEGL(LoadProc loadProc)
|
|||
reinterpret_cast<PFNEGLQUERYDISPLAYATTRIBANGLEPROC>(loadProc("eglQueryDisplayAttribANGLE"));
|
||||
t_eglQueryStringiANGLE =
|
||||
reinterpret_cast<PFNEGLQUERYSTRINGIANGLEPROC>(loadProc("eglQueryStringiANGLE"));
|
||||
t_eglForceGPUSwitchANGLE =
|
||||
reinterpret_cast<PFNEGLFORCEGPUSWITCHANGLEPROC>(loadProc("eglForceGPUSwitchANGLE"));
|
||||
t_eglHandleGPUSwitchANGLE =
|
||||
reinterpret_cast<PFNEGLHANDLEGPUSWITCHANGLEPROC>(loadProc("eglHandleGPUSwitchANGLE"));
|
||||
t_eglReacquireHighPowerGPUANGLE = reinterpret_cast<PFNEGLREACQUIREHIGHPOWERGPUANGLEPROC>(
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
#define eglReleaseDeviceANGLE t_eglReleaseDeviceANGLE
|
||||
#define eglQueryDisplayAttribANGLE t_eglQueryDisplayAttribANGLE
|
||||
#define eglQueryStringiANGLE t_eglQueryStringiANGLE
|
||||
#define eglForceGPUSwitchANGLE t_eglForceGPUSwitchANGLE
|
||||
#define eglHandleGPUSwitchANGLE t_eglHandleGPUSwitchANGLE
|
||||
#define eglReacquireHighPowerGPUANGLE t_eglReacquireHighPowerGPUANGLE
|
||||
#define eglReleaseHighPowerGPUANGLE t_eglReleaseHighPowerGPUANGLE
|
||||
|
@ -189,6 +190,7 @@ ANGLE_TRACE_LOADER_EXPORT extern PFNEGLCREATEDEVICEANGLEPROC t_eglCreateDeviceAN
|
|||
ANGLE_TRACE_LOADER_EXPORT extern PFNEGLRELEASEDEVICEANGLEPROC t_eglReleaseDeviceANGLE;
|
||||
ANGLE_TRACE_LOADER_EXPORT extern PFNEGLQUERYDISPLAYATTRIBANGLEPROC t_eglQueryDisplayAttribANGLE;
|
||||
ANGLE_TRACE_LOADER_EXPORT extern PFNEGLQUERYSTRINGIANGLEPROC t_eglQueryStringiANGLE;
|
||||
ANGLE_TRACE_LOADER_EXPORT extern PFNEGLFORCEGPUSWITCHANGLEPROC t_eglForceGPUSwitchANGLE;
|
||||
ANGLE_TRACE_LOADER_EXPORT extern PFNEGLHANDLEGPUSWITCHANGLEPROC t_eglHandleGPUSwitchANGLE;
|
||||
ANGLE_TRACE_LOADER_EXPORT extern PFNEGLREACQUIREHIGHPOWERGPUANGLEPROC
|
||||
t_eglReacquireHighPowerGPUANGLE;
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// Copyright 2022 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.
|
||||
//
|
||||
// system_info_util.h:
|
||||
// Implementation of common test utilities for operating with SystemInfo.
|
||||
//
|
||||
|
||||
#include "system_info_util.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/string_utils.h"
|
||||
#include "gpu_info_util/SystemInfo.h"
|
||||
#include "util/util_gl.h"
|
||||
|
||||
using namespace angle;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
size_t findGPU(const SystemInfo &systemInfo, bool lowPower)
|
||||
{
|
||||
if (systemInfo.gpus.size() < 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
for (size_t i = 0; i < systemInfo.gpus.size(); ++i)
|
||||
{
|
||||
if (lowPower && IsIntel(systemInfo.gpus[i].vendorId))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
// Return the high power GPU, i.e any non-intel GPU
|
||||
else if (!lowPower && !IsIntel(systemInfo.gpus[i].vendorId))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// Can't find GPU
|
||||
ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
size_t FindLowPowerGPU(const SystemInfo &systemInfo)
|
||||
{
|
||||
return findGPU(systemInfo, true);
|
||||
}
|
||||
|
||||
size_t FindHighPowerGPU(const SystemInfo &systemInfo)
|
||||
{
|
||||
return findGPU(systemInfo, false);
|
||||
}
|
||||
|
||||
size_t FindActiveOpenGLGPU(const SystemInfo &systemInfo)
|
||||
{
|
||||
char *renderer = (char *)glGetString(GL_RENDERER);
|
||||
std::string rendererString(renderer);
|
||||
for (size_t i = 0; i < systemInfo.gpus.size(); ++i)
|
||||
{
|
||||
std::vector<std::string> vendorTokens;
|
||||
angle::SplitStringAlongWhitespace(VendorName(systemInfo.gpus[i].vendorId), &vendorTokens);
|
||||
for (std::string &token : vendorTokens)
|
||||
{
|
||||
if (rendererString.find(token) != std::string::npos)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Can't find active GPU
|
||||
ASSERT(false);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// Copyright 2022 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.
|
||||
//
|
||||
// system_info_util.h:
|
||||
// Implementation of common test utilities for operating with SystemInfo.
|
||||
//
|
||||
|
||||
#ifndef ANGLE_TESTS_SYSTEM_INFO_UTIL_H_
|
||||
#define ANGLE_TESTS_SYSTEM_INFO_UTIL_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace angle
|
||||
{
|
||||
struct SystemInfo;
|
||||
} // namespace angle
|
||||
|
||||
// Returns the index of the low power GPU in SystemInfo.
|
||||
size_t FindLowPowerGPU(const angle::SystemInfo &);
|
||||
|
||||
// Returns the index of the high power GPU in SystemInfo.
|
||||
size_t FindHighPowerGPU(const angle::SystemInfo &);
|
||||
|
||||
// Returns the index of the GPU in SystemInfo based on the OpenGL renderer string.
|
||||
size_t FindActiveOpenGLGPU(const angle::SystemInfo &);
|
||||
|
||||
#endif // ANGLE_TESTS_SYSTEM_INFO_UTIL_H_
|
|
@ -70,6 +70,7 @@ ANGLE_UTIL_EXPORT PFNEGLCREATEDEVICEANGLEPROC l_eglCreateDeviceANGLE;
|
|||
ANGLE_UTIL_EXPORT PFNEGLRELEASEDEVICEANGLEPROC l_eglReleaseDeviceANGLE;
|
||||
ANGLE_UTIL_EXPORT PFNEGLQUERYDISPLAYATTRIBANGLEPROC l_eglQueryDisplayAttribANGLE;
|
||||
ANGLE_UTIL_EXPORT PFNEGLQUERYSTRINGIANGLEPROC l_eglQueryStringiANGLE;
|
||||
ANGLE_UTIL_EXPORT PFNEGLFORCEGPUSWITCHANGLEPROC l_eglForceGPUSwitchANGLE;
|
||||
ANGLE_UTIL_EXPORT PFNEGLHANDLEGPUSWITCHANGLEPROC l_eglHandleGPUSwitchANGLE;
|
||||
ANGLE_UTIL_EXPORT PFNEGLREACQUIREHIGHPOWERGPUANGLEPROC l_eglReacquireHighPowerGPUANGLE;
|
||||
ANGLE_UTIL_EXPORT PFNEGLRELEASEHIGHPOWERGPUANGLEPROC l_eglReleaseHighPowerGPUANGLE;
|
||||
|
@ -214,6 +215,8 @@ void LoadEGL(LoadProc loadProc)
|
|||
reinterpret_cast<PFNEGLQUERYDISPLAYATTRIBANGLEPROC>(loadProc("eglQueryDisplayAttribANGLE"));
|
||||
l_eglQueryStringiANGLE =
|
||||
reinterpret_cast<PFNEGLQUERYSTRINGIANGLEPROC>(loadProc("eglQueryStringiANGLE"));
|
||||
l_eglForceGPUSwitchANGLE =
|
||||
reinterpret_cast<PFNEGLFORCEGPUSWITCHANGLEPROC>(loadProc("eglForceGPUSwitchANGLE"));
|
||||
l_eglHandleGPUSwitchANGLE =
|
||||
reinterpret_cast<PFNEGLHANDLEGPUSWITCHANGLEPROC>(loadProc("eglHandleGPUSwitchANGLE"));
|
||||
l_eglReacquireHighPowerGPUANGLE = reinterpret_cast<PFNEGLREACQUIREHIGHPOWERGPUANGLEPROC>(
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
#define eglReleaseDeviceANGLE l_eglReleaseDeviceANGLE
|
||||
#define eglQueryDisplayAttribANGLE l_eglQueryDisplayAttribANGLE
|
||||
#define eglQueryStringiANGLE l_eglQueryStringiANGLE
|
||||
#define eglForceGPUSwitchANGLE l_eglForceGPUSwitchANGLE
|
||||
#define eglHandleGPUSwitchANGLE l_eglHandleGPUSwitchANGLE
|
||||
#define eglReacquireHighPowerGPUANGLE l_eglReacquireHighPowerGPUANGLE
|
||||
#define eglReleaseHighPowerGPUANGLE l_eglReleaseHighPowerGPUANGLE
|
||||
|
@ -184,6 +185,7 @@ ANGLE_UTIL_EXPORT extern PFNEGLCREATEDEVICEANGLEPROC l_eglCreateDeviceANGLE;
|
|||
ANGLE_UTIL_EXPORT extern PFNEGLRELEASEDEVICEANGLEPROC l_eglReleaseDeviceANGLE;
|
||||
ANGLE_UTIL_EXPORT extern PFNEGLQUERYDISPLAYATTRIBANGLEPROC l_eglQueryDisplayAttribANGLE;
|
||||
ANGLE_UTIL_EXPORT extern PFNEGLQUERYSTRINGIANGLEPROC l_eglQueryStringiANGLE;
|
||||
ANGLE_UTIL_EXPORT extern PFNEGLFORCEGPUSWITCHANGLEPROC l_eglForceGPUSwitchANGLE;
|
||||
ANGLE_UTIL_EXPORT extern PFNEGLHANDLEGPUSWITCHANGLEPROC l_eglHandleGPUSwitchANGLE;
|
||||
ANGLE_UTIL_EXPORT extern PFNEGLREACQUIREHIGHPOWERGPUANGLEPROC l_eglReacquireHighPowerGPUANGLE;
|
||||
ANGLE_UTIL_EXPORT extern PFNEGLRELEASEHIGHPOWERGPUANGLEPROC l_eglReleaseHighPowerGPUANGLE;
|
||||
|
|
Загрузка…
Ссылка в новой задаче