Coverage Report

Created: 2024-05-20 07:14

/src/skia/tools/gpu/GrContextFactory.cpp
Line
Count
Source (jump to first uncovered line)
1
2
/*
3
 * Copyright 2014 Google Inc.
4
 *
5
 * Use of this source code is governed by a BSD-style license that can be
6
 * found in the LICENSE file.
7
 */
8
9
#include "include/gpu/GrDirectContext.h"
10
#include "src/gpu/ganesh/GrDirectContextPriv.h"
11
#include "tools/gpu/GrContextFactory.h"
12
#ifdef SK_GL
13
#include "tools/gpu/gl/GLTestContext.h"
14
#endif
15
16
#if SK_ANGLE
17
#include "tools/gpu/gl/angle/GLTestContext_angle.h"
18
#endif
19
#ifdef SK_VULKAN
20
#include "tools/gpu/vk/VkTestContext.h"
21
#endif
22
#ifdef SK_METAL
23
#include "tools/gpu/mtl/MtlTestContext.h"
24
#endif
25
#ifdef SK_DIRECT3D
26
#include "tools/gpu/d3d/D3DTestContext.h"
27
#endif
28
#include "src/gpu/ganesh/GrCaps.h"
29
#include "tools/gpu/mock/MockTestContext.h"
30
31
#if defined(SK_BUILD_FOR_WIN) && defined(SK_ENABLE_DISCRETE_GPU)
32
extern "C" {
33
    // NVIDIA documents that the presence and value of this symbol programmatically enable the high
34
    // performance GPU in laptops with switchable graphics.
35
    //   https://docs.nvidia.com/gameworks/content/technologies/desktop/optimus.htm
36
    // From testing, including this symbol, even if it is set to 0, we still get the NVIDIA GPU.
37
    _declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
38
39
    // AMD has a similar mechanism, although I don't have an AMD laptop, so this is untested.
40
    //   https://community.amd.com/thread/169965
41
    __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
42
}
43
#endif
44
45
bool gCreateProtectedContext = false;
46
47
namespace sk_gpu_test {
48
2.76k
GrContextFactory::GrContextFactory() {}
49
50
GrContextFactory::GrContextFactory(const GrContextOptions& opts)
51
0
    : fGlobalOptions(opts) {}
52
53
2.76k
GrContextFactory::~GrContextFactory() {
54
2.76k
    this->destroyContexts();
55
2.76k
}
56
57
2.76k
void GrContextFactory::destroyContexts() {
58
    // We must delete the test contexts in reverse order so that any child context is finished and
59
    // deleted before a parent context. This relies on the fact that when we make a new context we
60
    // append it to the end of fContexts array.
61
    // TODO: Look into keeping a dependency dag for contexts and deletion order
62
5.34k
    for (int i = fContexts.size() - 1; i >= 0; --i) {
63
2.58k
        Context& context = fContexts[i];
64
2.58k
        SkScopeExit restore(nullptr);
65
2.58k
        if (context.fTestContext) {
66
2.58k
            restore = context.fTestContext->makeCurrentAndAutoRestore();
67
2.58k
        }
68
2.58k
        if (!context.fGrContext->unique()) {
69
0
            context.fGrContext->releaseResourcesAndAbandonContext();
70
0
            context.fAbandoned = true;
71
0
        }
72
2.58k
        context.fGrContext->unref();
73
2.58k
        delete context.fTestContext;
74
2.58k
    }
75
2.76k
    fContexts.clear();
76
2.76k
}
77
78
0
void GrContextFactory::abandonContexts() {
79
    // We must abandon the test contexts in reverse order so that any child context is finished and
80
    // abandoned before a parent context. This relies on the fact that when we make a new context we
81
    // append it to the end of fContexts array.
82
    // TODO: Look into keeping a dependency dag for contexts and deletion order
83
0
    for (int i = fContexts.size() - 1; i >= 0; --i) {
84
0
        Context& context = fContexts[i];
85
0
        if (!context.fAbandoned) {
86
0
            if (context.fTestContext) {
87
0
                auto restore = context.fTestContext->makeCurrentAndAutoRestore();
88
0
                context.fTestContext->testAbandon();
89
0
            }
90
0
            GrBackendApi api = context.fGrContext->backend();
91
0
            bool requiresEarlyAbandon = api == GrBackendApi::kVulkan;
92
0
            if (requiresEarlyAbandon) {
93
0
                context.fGrContext->abandonContext();
94
0
            }
95
0
            if (context.fTestContext) {
96
0
                delete(context.fTestContext);
97
0
                context.fTestContext = nullptr;
98
0
            }
99
0
            if (!requiresEarlyAbandon) {
100
0
                context.fGrContext->abandonContext();
101
0
            }
102
0
            context.fAbandoned = true;
103
0
        }
104
0
    }
105
0
}
106
107
0
void GrContextFactory::releaseResourcesAndAbandonContexts() {
108
    // We must abandon the test contexts in reverse order so that any child context is finished and
109
    // abandoned before a parent context. This relies on the fact that when we make a new context we
110
    // append it to the end of fContexts array.
111
    // TODO: Look into keeping a dependency dag for contexts and deletion order
112
0
    for (int i = fContexts.size() - 1; i >= 0; --i) {
113
0
        Context& context = fContexts[i];
114
0
        SkScopeExit restore(nullptr);
115
0
        if (!context.fAbandoned) {
116
0
            if (context.fTestContext) {
117
0
                restore = context.fTestContext->makeCurrentAndAutoRestore();
118
0
            }
119
0
            context.fGrContext->releaseResourcesAndAbandonContext();
120
0
            if (context.fTestContext) {
121
0
                delete context.fTestContext;
122
0
                context.fTestContext = nullptr;
123
0
            }
124
0
            context.fAbandoned = true;
125
0
        }
126
0
    }
127
0
}
128
129
2.58k
GrDirectContext* GrContextFactory::get(ContextType type, ContextOverrides overrides) {
130
2.58k
    return this->getContextInfo(type, overrides).directContext();
131
2.58k
}
132
133
ContextInfo GrContextFactory::getContextInfoInternal(ContextType type, ContextOverrides overrides,
134
                                                     GrDirectContext* shareContext,
135
2.76k
                                                     uint32_t shareIndex) {
136
    // (shareIndex != 0) -> (shareContext != nullptr)
137
2.76k
    SkASSERT((shareIndex == 0) || (shareContext != nullptr));
138
139
2.76k
    for (int i = 0; i < fContexts.size(); ++i) {
140
0
        Context& context = fContexts[i];
141
0
        if (context.fType == type &&
142
0
            context.fOverrides == overrides &&
143
0
            context.fShareContext == shareContext &&
144
0
            context.fShareIndex == shareIndex &&
145
0
            !context.fAbandoned) {
146
0
            context.fTestContext->makeCurrent();
147
0
            return ContextInfo(context.fType, context.fTestContext, context.fGrContext,
148
0
                               context.fOptions);
149
0
        }
150
0
    }
151
152
    // If we're trying to create a context in a share group, find the primary context
153
2.76k
    Context* primaryContext = nullptr;
154
2.76k
    if (shareContext) {
155
0
        for (int i = 0; i < fContexts.size(); ++i) {
156
0
            if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
157
0
                primaryContext = &fContexts[i];
158
0
                break;
159
0
            }
160
0
        }
161
0
        SkASSERT(primaryContext && primaryContext->fType == type);
162
0
    }
163
164
2.76k
    std::unique_ptr<TestContext> testCtx;
165
2.76k
    GrBackendApi backend = skgpu::ganesh::ContextTypeBackend(type);
166
2.76k
    switch (backend) {
167
#ifdef SK_GL
168
        case GrBackendApi::kOpenGL: {
169
            GLTestContext* glShareContext = primaryContext
170
                    ? static_cast<GLTestContext*>(primaryContext->fTestContext) : nullptr;
171
            GLTestContext* glCtx;
172
            switch (type) {
173
                case ContextType::kGL:
174
                    glCtx = CreatePlatformGLTestContext(kGL_GrGLStandard, glShareContext);
175
                    break;
176
                case ContextType::kGLES:
177
                    glCtx = CreatePlatformGLTestContext(kGLES_GrGLStandard, glShareContext);
178
                    break;
179
#if SK_ANGLE
180
                case ContextType::kANGLE_D3D9_ES2:
181
                    glCtx = MakeANGLETestContext(ANGLEBackend::kD3D9, ANGLEContextVersion::kES2,
182
                                                 glShareContext).release();
183
                    // Chrome will only run on D3D9 with NVIDIA for 2012 and earlier drivers.
184
                    // (<= 269.73). We get shader link failures when testing on recent drivers
185
                    // using this backend.
186
                    if (glCtx) {
187
                        GrGLDriverInfo info = GrGLGetDriverInfo(glCtx->gl());
188
                        if (info.fANGLEVendor == GrGLVendor::kNVIDIA) {
189
                            delete glCtx;
190
                            return ContextInfo();
191
                        }
192
                    }
193
                    break;
194
                case ContextType::kANGLE_D3D11_ES2:
195
                    glCtx = MakeANGLETestContext(ANGLEBackend::kD3D11, ANGLEContextVersion::kES2,
196
                                                 glShareContext).release();
197
                    break;
198
                case ContextType::kANGLE_D3D11_ES3:
199
                    glCtx = MakeANGLETestContext(ANGLEBackend::kD3D11, ANGLEContextVersion::kES3,
200
                                                 glShareContext).release();
201
                    break;
202
                case ContextType::kANGLE_GL_ES2:
203
                    glCtx = MakeANGLETestContext(ANGLEBackend::kOpenGL, ANGLEContextVersion::kES2,
204
                                                 glShareContext).release();
205
                    break;
206
                case ContextType::kANGLE_GL_ES3:
207
                    glCtx = MakeANGLETestContext(ANGLEBackend::kOpenGL, ANGLEContextVersion::kES3,
208
                                                 glShareContext).release();
209
                    break;
210
                case ContextType::kANGLE_Metal_ES2:
211
                    glCtx = MakeANGLETestContext(ANGLEBackend::kMetal, ANGLEContextVersion::kES2,
212
                                                 glShareContext).release();
213
                    break;
214
                case ContextType::kANGLE_Metal_ES3:
215
                    glCtx = MakeANGLETestContext(ANGLEBackend::kMetal, ANGLEContextVersion::kES3,
216
                                                 glShareContext).release();
217
                    break;
218
#endif
219
                default:
220
                    return ContextInfo();
221
            }
222
            if (!glCtx) {
223
                return ContextInfo();
224
            }
225
            if (glCtx->gl()->fStandard == kGLES_GrGLStandard &&
226
                (overrides & ContextOverrides::kFakeGLESVersionAs2)) {
227
                glCtx->overrideVersion("OpenGL ES 2.0", "OpenGL ES GLSL ES 1.00");
228
            }
229
            testCtx.reset(glCtx);
230
            break;
231
        }
232
#endif  // SK_GL
233
0
#ifdef SK_VULKAN
234
0
        case GrBackendApi::kVulkan: {
235
0
            VkTestContext* vkSharedContext = primaryContext
236
0
                    ? static_cast<VkTestContext*>(primaryContext->fTestContext) : nullptr;
237
0
            SkASSERT(ContextType::kVulkan == type);
238
0
            testCtx.reset(CreatePlatformVkTestContext(vkSharedContext));
239
0
            if (!testCtx) {
240
0
                return ContextInfo();
241
0
            }
242
#ifdef SK_GL
243
            // We previously had an issue where the VkDevice destruction would occasionally hang
244
            // on systems with NVIDIA GPUs and having an existing GL context fixed it. Now (Feb
245
            // 2022) we still need the GL context to keep Vulkan/TSAN bots from running incredibly
246
            // slow. Perhaps this prevents repeated driver loading/unloading? Note that keeping
247
            // a persistent VkTestContext around instead was tried and did not work.
248
            if (!fSentinelGLContext) {
249
                fSentinelGLContext.reset(CreatePlatformGLTestContext(kGL_GrGLStandard));
250
                if (!fSentinelGLContext) {
251
                    fSentinelGLContext.reset(CreatePlatformGLTestContext(kGLES_GrGLStandard));
252
                }
253
            }
254
#endif
255
0
            break;
256
0
        }
257
0
#endif
258
#ifdef SK_METAL
259
        case GrBackendApi::kMetal: {
260
            MtlTestContext* mtlSharedContext = primaryContext
261
                    ? static_cast<MtlTestContext*>(primaryContext->fTestContext) : nullptr;
262
            SkASSERT(ContextType::kMetal == type);
263
            testCtx.reset(CreatePlatformMtlTestContext(mtlSharedContext));
264
            if (!testCtx) {
265
                return ContextInfo();
266
            }
267
            break;
268
        }
269
#endif
270
#ifdef SK_DIRECT3D
271
        case GrBackendApi::kDirect3D: {
272
            D3DTestContext* d3dSharedContext = primaryContext
273
                    ? static_cast<D3DTestContext*>(primaryContext->fTestContext) : nullptr;
274
            SkASSERT(ContextType::kDirect3D == type);
275
            testCtx.reset(CreatePlatformD3DTestContext(d3dSharedContext));
276
            if (!testCtx) {
277
                return ContextInfo();
278
            }
279
            break;
280
        }
281
#endif
282
2.58k
        case GrBackendApi::kMock: {
283
2.58k
            TestContext* sharedContext = primaryContext ? primaryContext->fTestContext : nullptr;
284
2.58k
            SkASSERT(ContextType::kMock == type);
285
2.58k
            testCtx.reset(CreateMockTestContext(sharedContext));
286
2.58k
            if (!testCtx) {
287
0
                return ContextInfo();
288
0
            }
289
2.58k
            break;
290
2.58k
        }
291
2.58k
        default:
292
184
            return ContextInfo();
293
2.76k
    }
294
295
2.58k
    SkASSERT(testCtx && testCtx->backend() == backend);
296
2.58k
    GrContextOptions grOptions = fGlobalOptions;
297
2.58k
    if (ContextOverrides::kAvoidStencilBuffers & overrides) {
298
0
        grOptions.fAvoidStencilBuffers = true;
299
0
    }
300
2.58k
    if (ContextOverrides::kReducedShaders & overrides) {
301
0
        grOptions.fReducedShaderVariations = true;
302
0
    }
303
2.58k
    sk_sp<GrDirectContext> grCtx;
304
2.58k
    {
305
2.58k
        auto restore = testCtx->makeCurrentAndAutoRestore();
306
2.58k
        grCtx = testCtx->makeContext(grOptions);
307
2.58k
    }
308
2.58k
    if (!grCtx) {
309
0
        return ContextInfo();
310
0
    }
311
312
2.58k
    if (shareContext) {
313
0
        SkASSERT(grCtx->directContextID() != shareContext->directContextID());
314
0
    }
315
316
    // We must always add new contexts by pushing to the back so that when we delete them we delete
317
    // them in reverse order in which they were made.
318
2.58k
    Context& context = fContexts.push_back();
319
2.58k
    context.fBackend = backend;
320
2.58k
    context.fTestContext = testCtx.release();
321
2.58k
    context.fGrContext = SkRef(grCtx.get());
322
2.58k
    context.fType = type;
323
2.58k
    context.fOverrides = overrides;
324
2.58k
    context.fAbandoned = false;
325
2.58k
    context.fShareContext = shareContext;
326
2.58k
    context.fShareIndex = shareIndex;
327
2.58k
    context.fOptions = grOptions;
328
2.58k
    context.fTestContext->makeCurrent();
329
2.58k
    return ContextInfo(context.fType, context.fTestContext, context.fGrContext, context.fOptions);
330
2.58k
}
331
332
2.76k
ContextInfo GrContextFactory::getContextInfo(ContextType type, ContextOverrides overrides) {
333
2.76k
    return this->getContextInfoInternal(type, overrides, nullptr, 0);
334
2.76k
}
335
336
ContextInfo GrContextFactory::getSharedContextInfo(GrDirectContext* shareContext,
337
0
                                                   uint32_t shareIndex) {
338
0
    SkASSERT(shareContext);
339
0
    for (int i = 0; i < fContexts.size(); ++i) {
340
0
        if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
341
0
            return this->getContextInfoInternal(fContexts[i].fType, fContexts[i].fOverrides,
342
0
                                                shareContext, shareIndex);
343
0
        }
344
0
    }
345
346
0
    return ContextInfo();
347
0
}
Unexecuted instantiation: sk_gpu_test::GrContextFactory::getSharedContextInfo(GrDirectContext*, unsigned int)
Unexecuted instantiation: sk_gpu_test::GrContextFactory::getSharedContextInfo(GrDirectContext*, unsigned int)
348
349
}  // namespace sk_gpu_test