~mmach/netext73/webkit2gtk

« back to all changes in this revision

Viewing changes to Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGLManager.cpp

  • Committer: mmach
  • Date: 2023-06-16 17:21:37 UTC
  • Revision ID: netbit73@gmail.com-20230616172137-2rqx6yr96ga9g3kp
1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2018 Apple Inc. All rights reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without
 
5
 * modification, are permitted provided that the following conditions
 
6
 * are met:
 
7
 * 1. Redistributions of source code must retain the above copyright
 
8
 *    notice, this list of conditions and the following disclaimer.
 
9
 * 2. Redistributions in binary form must reproduce the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer in the
 
11
 *    documentation and/or other materials provided with the distribution.
 
12
 *
 
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 
14
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 
15
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
16
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 
17
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
18
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
19
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
20
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
21
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
22
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 
23
 * THE POSSIBILITY OF SUCH DAMAGE.
 
24
 */
 
25
 
 
26
#include "config.h"
 
27
 
 
28
#if ENABLE(GRAPHICS_CONTEXT_GL)
 
29
#include "GraphicsContextGLOpenGLManager.h"
 
30
 
 
31
#include "GraphicsContextGLOpenGL.h"
 
32
#include "Logging.h"
 
33
 
 
34
#if HAVE(APPLE_GRAPHICS_CONTROL)
 
35
#include <sys/sysctl.h>
 
36
#endif
 
37
 
 
38
#if PLATFORM(MAC) && (USE(OPENGL) || USE(ANGLE))
 
39
#include "SwitchingGPUClient.h"
 
40
#include <OpenGL/OpenGL.h>
 
41
#endif
 
42
 
 
43
namespace WebCore {
 
44
 
 
45
#if HAVE(APPLE_GRAPHICS_CONTROL)
 
46
 
 
47
enum {
 
48
    kAGCOpen,
 
49
    kAGCClose
 
50
};
 
51
 
 
52
static io_connect_t attachToAppleGraphicsControl()
 
53
{
 
54
    mach_port_t masterPort = MACH_PORT_NULL;
 
55
    
 
56
    if (IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS)
 
57
        return MACH_PORT_NULL;
 
58
    
 
59
    CFDictionaryRef classToMatch = IOServiceMatching("AppleGraphicsControl");
 
60
    if (!classToMatch)
 
61
        return MACH_PORT_NULL;
 
62
    
 
63
    kern_return_t kernResult;
 
64
    io_iterator_t iterator;
 
65
    if ((kernResult = IOServiceGetMatchingServices(masterPort, classToMatch, &iterator)) != KERN_SUCCESS)
 
66
        return MACH_PORT_NULL;
 
67
    
 
68
    io_service_t serviceObject = IOIteratorNext(iterator);
 
69
    IOObjectRelease(iterator);
 
70
    if (!serviceObject)
 
71
        return MACH_PORT_NULL;
 
72
    
 
73
    io_connect_t dataPort;
 
74
    IOObjectRetain(serviceObject);
 
75
    kernResult = IOServiceOpen(serviceObject, mach_task_self(), 0, &dataPort);
 
76
    IOObjectRelease(serviceObject);
 
77
    
 
78
    return (kernResult == KERN_SUCCESS) ? dataPort : MACH_PORT_NULL;
 
79
}
 
80
 
 
81
static bool hasMuxCapability()
 
82
{
 
83
    io_connect_t dataPort = attachToAppleGraphicsControl();
 
84
    
 
85
    if (dataPort == MACH_PORT_NULL)
 
86
        return false;
 
87
    
 
88
    bool result;
 
89
    if (IOConnectCallScalarMethod(dataPort, kAGCOpen, nullptr, 0, nullptr, nullptr) == KERN_SUCCESS) {
 
90
        IOConnectCallScalarMethod(dataPort, kAGCClose, nullptr, 0, nullptr, nullptr);
 
91
        result = true;
 
92
    } else
 
93
        result = false;
 
94
    
 
95
    IOServiceClose(dataPort);
 
96
    
 
97
    if (result) {
 
98
        // This is detecting Mac hardware with an Intel g575 GPU, which
 
99
        // we don't want to make available to muxing.
 
100
        // Based on information from Apple's OpenGL team, such devices
 
101
        // have four or fewer processors.
 
102
        // <rdar://problem/30060378>
 
103
        int names[2] = { CTL_HW, HW_NCPU };
 
104
        int cpuCount;
 
105
        size_t cpuCountLength = sizeof(cpuCount);
 
106
        sysctl(names, 2, &cpuCount, &cpuCountLength, nullptr, 0);
 
107
        result = cpuCount > 4;
 
108
    }
 
109
    
 
110
    return result;
 
111
}
 
112
 
 
113
bool hasLowAndHighPowerGPUs()
 
114
{
 
115
    static bool canMux = hasMuxCapability();
 
116
    return canMux;
 
117
}
 
118
#endif // HAVE(APPLE_GRAPHICS_CONTROL)
 
119
 
 
120
GraphicsContextGLOpenGLManager& GraphicsContextGLOpenGLManager::sharedManager()
 
121
{
 
122
    static NeverDestroyed<GraphicsContextGLOpenGLManager> s_manager;
 
123
    return s_manager;
 
124
}
 
125
 
 
126
#if PLATFORM(MAC)
 
127
void GraphicsContextGLOpenGLManager::displayWasReconfigured(CGDirectDisplayID, CGDisplayChangeSummaryFlags flags, void*)
 
128
{
 
129
    LOG(WebGL, "GraphicsContextGLOpenGLManager::displayWasReconfigured");
 
130
    if (flags & kCGDisplaySetModeFlag)
 
131
        GraphicsContextGLOpenGLManager::sharedManager().updateAllContexts();
 
132
}
 
133
#endif
 
134
 
 
135
void GraphicsContextGLOpenGLManager::updateAllContexts()
 
136
{
 
137
#if PLATFORM(MAC) && (USE(OPENGL) || USE(ANGLE))
 
138
    for (const auto& context : m_contexts) {
 
139
        context->updateCGLContext();
 
140
        context->dispatchContextChangedNotification();
 
141
    }
 
142
#endif
 
143
}
 
144
 
 
145
#if PLATFORM(MAC)
 
146
void GraphicsContextGLOpenGLManager::screenDidChange(PlatformDisplayID displayID, const HostWindow* window)
 
147
{
 
148
    for (const auto& contextAndWindow : m_contextWindowMap) {
 
149
        if (contextAndWindow.value == window) {
 
150
            contextAndWindow.key->screenDidChange(displayID);
 
151
            LOG(WebGL, "Changing context (%p) to display (%d).", contextAndWindow.key, displayID);
 
152
        }
 
153
    }
 
154
}
 
155
#endif
 
156
 
 
157
void GraphicsContextGLOpenGLManager::addContext(GraphicsContextGLOpenGL* context, HostWindow* window)
 
158
{
 
159
    ASSERT(context);
 
160
    if (!context)
 
161
        return;
 
162
 
 
163
#if PLATFORM(MAC) && !ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
 
164
    if (!m_contexts.size())
 
165
        CGDisplayRegisterReconfigurationCallback(displayWasReconfigured, nullptr);
 
166
#endif
 
167
 
 
168
    ASSERT(!m_contexts.contains(context));
 
169
    m_contexts.append(context);
 
170
    m_contextWindowMap.set(context, window);
 
171
}
 
172
 
 
173
void GraphicsContextGLOpenGLManager::removeContext(GraphicsContextGLOpenGL* context)
 
174
{
 
175
    if (!m_contexts.contains(context))
 
176
        return;
 
177
    m_contexts.removeFirst(context);
 
178
    m_contextWindowMap.remove(context);
 
179
    removeContextRequiringHighPerformance(context);
 
180
    
 
181
#if PLATFORM(MAC) && !ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
 
182
    if (!m_contexts.size())
 
183
        CGDisplayRemoveReconfigurationCallback(displayWasReconfigured, nullptr);
 
184
#endif
 
185
}
 
186
 
 
187
HostWindow* GraphicsContextGLOpenGLManager::hostWindowForContext(GraphicsContextGLOpenGL* context) const
 
188
{
 
189
    ASSERT(m_contextWindowMap.contains(context));
 
190
    return m_contextWindowMap.get(context);
 
191
}
 
192
 
 
193
void GraphicsContextGLOpenGLManager::addContextRequiringHighPerformance(GraphicsContextGLOpenGL* context)
 
194
{
 
195
    ASSERT(context);
 
196
    if (!context)
 
197
        return;
 
198
    
 
199
    ASSERT(m_contexts.contains(context));
 
200
    ASSERT(!m_contextsRequiringHighPerformance.contains(context));
 
201
    
 
202
    LOG(WebGL, "This context (%p) requires the high-performance GPU.", context);
 
203
    m_contextsRequiringHighPerformance.add(context);
 
204
    
 
205
    updateHighPerformanceState();
 
206
}
 
207
 
 
208
void GraphicsContextGLOpenGLManager::removeContextRequiringHighPerformance(GraphicsContextGLOpenGL* context)
 
209
{
 
210
    if (!context)
 
211
        return;
 
212
 
 
213
    if (!m_contextsRequiringHighPerformance.contains(context))
 
214
        return;
 
215
    
 
216
    LOG(WebGL, "This context (%p) no longer requires the high-performance GPU.", context);
 
217
    m_contextsRequiringHighPerformance.remove(context);
 
218
    
 
219
    updateHighPerformanceState();
 
220
}
 
221
 
 
222
void GraphicsContextGLOpenGLManager::updateHighPerformanceState()
 
223
{
 
224
#if PLATFORM(MAC) && (USE(OPENGL) || USE(ANGLE))
 
225
    if (!hasLowAndHighPowerGPUs())
 
226
        return;
 
227
    
 
228
    if (m_contextsRequiringHighPerformance.size()) {
 
229
        
 
230
        if (m_disableHighPerformanceGPUTimer.isActive()) {
 
231
            LOG(WebGL, "Cancel pending timer for turning off high-performance GPU.");
 
232
            m_disableHighPerformanceGPUTimer.stop();
 
233
        }
 
234
 
 
235
        if (!m_requestingHighPerformance) {
 
236
            LOG(WebGL, "Request the high-performance GPU.");
 
237
            m_requestingHighPerformance = true;
 
238
#if PLATFORM(MAC)
 
239
            SwitchingGPUClient::singleton().requestHighPerformanceGPU();
 
240
#endif
 
241
        }
 
242
 
 
243
    } else {
 
244
        // Don't immediately turn off the high-performance GPU. The user might be
 
245
        // swapping back and forth between tabs or windows, and we don't want to cause
 
246
        // churn if we can avoid it.
 
247
        if (!m_disableHighPerformanceGPUTimer.isActive()) {
 
248
            LOG(WebGL, "Set a timer to release the high-performance GPU.");
 
249
            // FIXME: Expose this value as a Setting, which would require this class
 
250
            // to reference a frame, page or document.
 
251
            static const Seconds timeToKeepHighPerformanceGPUAlive { 10_s };
 
252
            m_disableHighPerformanceGPUTimer.startOneShot(timeToKeepHighPerformanceGPUAlive);
 
253
        }
 
254
    }
 
255
#endif
 
256
}
 
257
 
 
258
void GraphicsContextGLOpenGLManager::disableHighPerformanceGPUTimerFired()
 
259
{
 
260
    if (m_contextsRequiringHighPerformance.size())
 
261
        return;
 
262
 
 
263
    m_requestingHighPerformance = false;
 
264
#if PLATFORM(MAC) && (USE(OPENGL) || USE(ANGLE))
 
265
    SwitchingGPUClient::singleton().releaseHighPerformanceGPU();
 
266
#endif
 
267
}
 
268
 
 
269
void GraphicsContextGLOpenGLManager::recycleContextIfNecessary()
 
270
{
 
271
    if (hasTooManyContexts()) {
 
272
        LOG(WebGL, "GraphicsContextGLOpenGLManager recycled context (%p).", m_contexts[0]);
 
273
        m_contexts[0]->recycleContext();
 
274
    }
 
275
}
 
276
 
 
277
} // namespace WebCore
 
278
 
 
279
#endif // ENABLE(GRAPHICS_CONTEXT_GL)