Coverage Report

Created: 2021-08-22 09:07

/src/skia/src/gpu/gl/GrGLBuffer.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2016 Google Inc.
3
 *
4
 * Use of this source code is governed by a BSD-style license that can be
5
 * found in the LICENSE file.
6
 */
7
8
#include "src/gpu/gl/GrGLBuffer.h"
9
10
#include "include/core/SkTraceMemoryDump.h"
11
#include "src/core/SkTraceEvent.h"
12
#include "src/gpu/GrGpuResourcePriv.h"
13
#include "src/gpu/gl/GrGLCaps.h"
14
#include "src/gpu/gl/GrGLGpu.h"
15
16
0
#define GL_CALL(X) GR_GL_CALL(this->glGpu()->glInterface(), X)
17
0
#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->glGpu()->glInterface(), RET, X)
18
19
#define GL_ALLOC_CALL(call)                                            \
20
0
    [&] {                                                              \
21
0
        if (this->glGpu()->glCaps().skipErrorChecks()) {               \
22
0
            GR_GL_CALL(this->glGpu()->glInterface(), call);            \
23
0
            return static_cast<GrGLenum>(GR_GL_NO_ERROR);              \
24
0
        } else {                                                       \
25
0
            this->glGpu()->clearErrorsAndCheckForOOM();                \
26
0
            GR_GL_CALL_NOERRCHECK(this->glGpu()->glInterface(), call); \
27
0
            return this->glGpu()->getErrorAndCheckForOOM();            \
28
0
        }                                                              \
29
0
    }()
Unexecuted instantiation: GrGLBuffer.cpp:GrGLBuffer::GrGLBuffer(GrGLGpu*, unsigned long, GrGpuBufferType, GrAccessPattern, void const*)::$_0::operator()() const
Unexecuted instantiation: GrGLBuffer.cpp:GrGLBuffer::onMap()::$_1::operator()() const
Unexecuted instantiation: GrGLBuffer.cpp:GrGLBuffer::onMap()::$_2::operator()() const
Unexecuted instantiation: GrGLBuffer.cpp:GrGLBuffer::onMap()::$_3::operator()() const
Unexecuted instantiation: GrGLBuffer.cpp:GrGLBuffer::onUpdateData(void const*, unsigned long)::$_4::operator()() const
Unexecuted instantiation: GrGLBuffer.cpp:GrGLBuffer::onUpdateData(void const*, unsigned long)::$_5::operator()() const
Unexecuted instantiation: GrGLBuffer.cpp:GrGLBuffer::onUpdateData(void const*, unsigned long)::$_6::operator()() const
Unexecuted instantiation: GrGLBuffer.cpp:GrGLBuffer::GrGLBuffer(GrGLGpu*, unsigned long, GrGpuBufferType, GrAccessPattern, void const*)::$_0::operator()() const
Unexecuted instantiation: GrGLBuffer.cpp:GrGLBuffer::onMap()::$_4::operator()() const
Unexecuted instantiation: GrGLBuffer.cpp:GrGLBuffer::onMap()::$_5::operator()() const
Unexecuted instantiation: GrGLBuffer.cpp:GrGLBuffer::onMap()::$_6::operator()() const
Unexecuted instantiation: GrGLBuffer.cpp:GrGLBuffer::onUpdateData(void const*, unsigned long)::$_12::operator()() const
Unexecuted instantiation: GrGLBuffer.cpp:GrGLBuffer::onUpdateData(void const*, unsigned long)::$_13::operator()() const
Unexecuted instantiation: GrGLBuffer.cpp:GrGLBuffer::onUpdateData(void const*, unsigned long)::$_14::operator()() const
30
31
#ifdef SK_DEBUG
32
0
#define VALIDATE() this->validate()
33
#else
34
0
#define VALIDATE() do {} while(false)
35
#endif
36
37
sk_sp<GrGLBuffer> GrGLBuffer::Make(GrGLGpu* gpu, size_t size, GrGpuBufferType intendedType,
38
0
                                   GrAccessPattern accessPattern, const void* data) {
39
0
    if (gpu->glCaps().transferBufferType() == GrGLCaps::TransferBufferType::kNone &&
40
0
        (GrGpuBufferType::kXferCpuToGpu == intendedType ||
41
0
         GrGpuBufferType::kXferGpuToCpu == intendedType)) {
42
0
        return nullptr;
43
0
    }
44
45
0
    sk_sp<GrGLBuffer> buffer(new GrGLBuffer(gpu, size, intendedType, accessPattern, data));
46
0
    if (0 == buffer->bufferID()) {
47
0
        return nullptr;
48
0
    }
49
0
    return buffer;
50
0
}
51
52
// GL_STREAM_DRAW triggers an optimization in Chromium's GPU process where a client's vertex buffer
53
// objects are implemented as client-side-arrays on tile-deferred architectures.
54
0
#define DYNAMIC_DRAW_PARAM GR_GL_STREAM_DRAW
55
56
inline static GrGLenum gr_to_gl_access_pattern(GrGpuBufferType bufferType,
57
                                               GrAccessPattern accessPattern,
58
0
                                               const GrGLCaps& caps) {
59
0
    auto drawUsage = [](GrAccessPattern pattern) {
60
0
        switch (pattern) {
61
0
            case kDynamic_GrAccessPattern:
62
                // TODO: Do we really want to use STREAM_DRAW here on non-Chromium?
63
0
                return DYNAMIC_DRAW_PARAM;
64
0
            case kStatic_GrAccessPattern:
65
0
                return GR_GL_STATIC_DRAW;
66
0
            case kStream_GrAccessPattern:
67
0
                return GR_GL_STREAM_DRAW;
68
0
        }
69
0
        SkUNREACHABLE;
70
0
    };
71
72
0
    auto readUsage = [](GrAccessPattern pattern) {
73
0
        switch (pattern) {
74
0
            case kDynamic_GrAccessPattern:
75
0
                return GR_GL_DYNAMIC_READ;
76
0
            case kStatic_GrAccessPattern:
77
0
                return GR_GL_STATIC_READ;
78
0
            case kStream_GrAccessPattern:
79
0
                return GR_GL_STREAM_READ;
80
0
        }
81
0
        SkUNREACHABLE;
82
0
    };
83
84
0
    auto usageType = [&drawUsage, &readUsage, &caps](GrGpuBufferType type,
85
0
                                                     GrAccessPattern pattern) {
86
        // GL_NV_pixel_buffer_object adds transfer buffers but not the related <usage> values.
87
0
        if (caps.transferBufferType() == GrGLCaps::TransferBufferType::kNV_PBO) {
88
0
            return drawUsage(pattern);
89
0
        }
90
0
        switch (type) {
91
0
            case GrGpuBufferType::kVertex:
92
0
            case GrGpuBufferType::kIndex:
93
0
            case GrGpuBufferType::kDrawIndirect:
94
0
            case GrGpuBufferType::kXferCpuToGpu:
95
0
            case GrGpuBufferType::kUniform:
96
0
                return drawUsage(pattern);
97
0
            case GrGpuBufferType::kXferGpuToCpu:
98
0
                return readUsage(pattern);
99
0
        }
100
0
        SkUNREACHABLE;
101
0
    };
102
103
0
    return usageType(bufferType, accessPattern);
104
0
}
105
106
GrGLBuffer::GrGLBuffer(GrGLGpu* gpu, size_t size, GrGpuBufferType intendedType,
107
                       GrAccessPattern accessPattern, const void* data)
108
        : INHERITED(gpu, size, intendedType, accessPattern)
109
        , fIntendedType(intendedType)
110
        , fBufferID(0)
111
        , fUsage(gr_to_gl_access_pattern(intendedType, accessPattern, gpu->glCaps()))
112
        , fGLSizeInBytes(0)
113
0
        , fHasAttachedToTexture(false) {
114
0
    GL_CALL(GenBuffers(1, &fBufferID));
115
0
    if (fBufferID) {
116
0
        GrGLenum target = gpu->bindBuffer(fIntendedType, this);
117
0
        GrGLenum error = GL_ALLOC_CALL(BufferData(target, (GrGLsizeiptr)size, data, fUsage));
118
0
        if (error != GR_GL_NO_ERROR) {
119
0
            GL_CALL(DeleteBuffers(1, &fBufferID));
120
0
            fBufferID = 0;
121
0
        } else {
122
0
            fGLSizeInBytes = size;
123
0
        }
124
0
    }
125
0
    VALIDATE();
126
0
    this->registerWithCache(SkBudgeted::kYes);
127
0
    if (!fBufferID) {
128
0
        this->resourcePriv().removeScratchKey();
129
0
    }
130
0
}
Unexecuted instantiation: GrGLBuffer::GrGLBuffer(GrGLGpu*, unsigned long, GrGpuBufferType, GrAccessPattern, void const*)
Unexecuted instantiation: GrGLBuffer::GrGLBuffer(GrGLGpu*, unsigned long, GrGpuBufferType, GrAccessPattern, void const*)
131
132
0
inline GrGLGpu* GrGLBuffer::glGpu() const {
133
0
    SkASSERT(!this->wasDestroyed());
134
0
    return static_cast<GrGLGpu*>(this->getGpu());
135
0
}
Unexecuted instantiation: GrGLBuffer::glGpu() const
Unexecuted instantiation: GrGLBuffer::glGpu() const
136
137
0
inline const GrGLCaps& GrGLBuffer::glCaps() const {
138
0
    return this->glGpu()->glCaps();
139
0
}
140
141
0
void GrGLBuffer::onRelease() {
142
0
    TRACE_EVENT0("skia.gpu", TRACE_FUNC);
143
144
0
    if (!this->wasDestroyed()) {
145
0
        VALIDATE();
146
        // make sure we've not been abandoned or already released
147
0
        if (fBufferID) {
148
0
            GL_CALL(DeleteBuffers(1, &fBufferID));
149
0
            fBufferID = 0;
150
0
            fGLSizeInBytes = 0;
151
0
        }
152
0
        fMapPtr = nullptr;
153
0
        VALIDATE();
154
0
    }
155
156
0
    INHERITED::onRelease();
157
0
}
Unexecuted instantiation: GrGLBuffer::onRelease()
Unexecuted instantiation: GrGLBuffer::onRelease()
158
159
0
void GrGLBuffer::onAbandon() {
160
0
    fBufferID = 0;
161
0
    fGLSizeInBytes = 0;
162
0
    fMapPtr = nullptr;
163
0
    VALIDATE();
164
0
    INHERITED::onAbandon();
165
0
}
166
167
0
void GrGLBuffer::onMap() {
168
0
    SkASSERT(fBufferID);
169
0
    SkASSERT(!this->wasDestroyed());
170
0
    VALIDATE();
171
0
    SkASSERT(!this->isMapped());
172
173
    // TODO: Make this a function parameter.
174
0
    bool readOnly = (GrGpuBufferType::kXferGpuToCpu == fIntendedType);
175
176
    // Handling dirty context is done in the bindBuffer call
177
0
    switch (this->glCaps().mapBufferType()) {
178
0
        case GrGLCaps::kNone_MapBufferType:
179
0
            return;
180
0
        case GrGLCaps::kMapBuffer_MapBufferType: {
181
0
            GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
182
0
            if (!readOnly) {
183
                // Let driver know it can discard the old data
184
0
                if (this->glCaps().useBufferDataNullHint() || fGLSizeInBytes != this->size()) {
185
0
                    GrGLenum error =
186
0
                            GL_ALLOC_CALL(BufferData(target, this->size(), nullptr, fUsage));
187
0
                    if (error != GR_GL_NO_ERROR) {
188
0
                        return;
189
0
                    }
190
0
                }
191
0
            }
192
0
            GL_CALL_RET(fMapPtr, MapBuffer(target, readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY));
193
0
            break;
194
0
        }
195
0
        case GrGLCaps::kMapBufferRange_MapBufferType: {
196
0
            GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
197
            // Make sure the GL buffer size agrees with fDesc before mapping.
198
0
            if (fGLSizeInBytes != this->size()) {
199
0
                GrGLenum error = GL_ALLOC_CALL(BufferData(target, this->size(), nullptr, fUsage));
200
0
                if (error != GR_GL_NO_ERROR) {
201
0
                    return;
202
0
                }
203
0
            }
204
0
            GrGLbitfield access;
205
0
            if (readOnly) {
206
0
                access = GR_GL_MAP_READ_BIT;
207
0
            } else {
208
0
                access = GR_GL_MAP_WRITE_BIT;
209
0
                if (GrGpuBufferType::kXferCpuToGpu != fIntendedType) {
210
                    // TODO: Make this a function parameter.
211
0
                    access |= GR_GL_MAP_INVALIDATE_BUFFER_BIT;
212
0
                }
213
0
            }
214
0
            GL_CALL_RET(fMapPtr, MapBufferRange(target, 0, this->size(), access));
215
0
            break;
216
0
        }
217
0
        case GrGLCaps::kChromium_MapBufferType: {
218
0
            GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
219
            // Make sure the GL buffer size agrees with fDesc before mapping.
220
0
            if (fGLSizeInBytes != this->size()) {
221
0
                GrGLenum error = GL_ALLOC_CALL(BufferData(target, this->size(), nullptr, fUsage));
222
0
                if (error != GR_GL_NO_ERROR) {
223
0
                    return;
224
0
                }
225
0
            }
226
0
            GL_CALL_RET(fMapPtr, MapBufferSubData(target, 0, this->size(),
227
0
                                                  readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY));
228
0
            break;
229
0
        }
230
0
    }
231
0
    fGLSizeInBytes = this->size();
232
0
    VALIDATE();
233
0
}
Unexecuted instantiation: GrGLBuffer::onMap()
Unexecuted instantiation: GrGLBuffer::onMap()
234
235
0
void GrGLBuffer::onUnmap() {
236
0
    SkASSERT(fBufferID);
237
0
    VALIDATE();
238
0
    SkASSERT(this->isMapped());
239
0
    if (0 == fBufferID) {
240
0
        fMapPtr = nullptr;
241
0
        return;
242
0
    }
243
    // bind buffer handles the dirty context
244
0
    switch (this->glCaps().mapBufferType()) {
245
0
        case GrGLCaps::kNone_MapBufferType:
246
0
            SkDEBUGFAIL("Shouldn't get here.");
247
0
            return;
248
0
        case GrGLCaps::kMapBuffer_MapBufferType: // fall through
249
0
        case GrGLCaps::kMapBufferRange_MapBufferType: {
250
0
            GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
251
0
            GL_CALL(UnmapBuffer(target));
252
0
            break;
253
0
        }
254
0
        case GrGLCaps::kChromium_MapBufferType:
255
0
            this->glGpu()->bindBuffer(fIntendedType, this); // TODO: Is this needed?
256
0
            GL_CALL(UnmapBufferSubData(fMapPtr));
257
0
            break;
258
0
    }
259
0
    fMapPtr = nullptr;
260
0
}
Unexecuted instantiation: GrGLBuffer::onUnmap()
Unexecuted instantiation: GrGLBuffer::onUnmap()
261
262
0
bool GrGLBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) {
263
0
    SkASSERT(fBufferID);
264
0
    if (this->wasDestroyed()) {
265
0
        return false;
266
0
    }
267
268
0
    SkASSERT(!this->isMapped());
269
0
    VALIDATE();
270
0
    if (srcSizeInBytes > this->size()) {
271
0
        return false;
272
0
    }
273
0
    SkASSERT(srcSizeInBytes <= this->size());
274
    // bindbuffer handles dirty context
275
0
    GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
276
277
0
    if (this->glCaps().useBufferDataNullHint()) {
278
0
        if (this->size() == srcSizeInBytes) {
279
0
            GrGLenum error =
280
0
                    GL_ALLOC_CALL(BufferData(target, (GrGLsizeiptr)srcSizeInBytes, src, fUsage));
281
0
            if (error != GR_GL_NO_ERROR) {
282
0
                return false;
283
0
            }
284
0
        } else {
285
            // Before we call glBufferSubData we give the driver a hint using
286
            // glBufferData with nullptr. This makes the old buffer contents
287
            // inaccessible to future draws. The GPU may still be processing
288
            // draws that reference the old contents. With this hint it can
289
            // assign a different allocation for the new contents to avoid
290
            // flushing the gpu past draws consuming the old contents.
291
            // TODO I think we actually want to try calling bufferData here
292
0
            GrGLenum error =
293
0
                    GL_ALLOC_CALL(BufferData(target, (GrGLsizeiptr)this->size(), nullptr, fUsage));
294
0
            if (error != GR_GL_NO_ERROR) {
295
0
                return false;
296
0
            }
297
0
            GL_CALL(BufferSubData(target, 0, (GrGLsizeiptr) srcSizeInBytes, src));
298
0
        }
299
0
        fGLSizeInBytes = this->size();
300
0
    } else {
301
        // Note that we're cheating on the size here. Currently no methods
302
        // allow a partial update that preserves contents of non-updated
303
        // portions of the buffer (map() does a glBufferData(..size, nullptr..))
304
0
        GrGLenum error =
305
0
                GL_ALLOC_CALL(BufferData(target, (GrGLsizeiptr)srcSizeInBytes, src, fUsage));
306
0
        if (error != GR_GL_NO_ERROR) {
307
0
            return false;
308
0
        }
309
0
        fGLSizeInBytes = srcSizeInBytes;
310
0
    }
311
0
    VALIDATE();
312
0
    return true;
313
0
}
Unexecuted instantiation: GrGLBuffer::onUpdateData(void const*, unsigned long)
Unexecuted instantiation: GrGLBuffer::onUpdateData(void const*, unsigned long)
314
315
void GrGLBuffer::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
316
0
                                       const SkString& dumpName) const {
317
0
    SkString buffer_id;
318
0
    buffer_id.appendU32(this->bufferID());
319
0
    traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_buffer",
320
0
                                      buffer_id.c_str());
321
0
}
322
323
#ifdef SK_DEBUG
324
325
0
void GrGLBuffer::validate() const {
326
0
    SkASSERT(0 != fBufferID || 0 == fGLSizeInBytes);
327
0
    SkASSERT(nullptr == fMapPtr || fGLSizeInBytes <= this->size());
328
0
}
329
330
#endif