blob: 180dc39958b61587f86fad72489b3299c2c18ee6 [file] [log] [blame]
cdalton397536c2016-03-25 12:15:03 -07001/*
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 "GrGLBuffer.h"
9#include "GrGLGpu.h"
Robert Phillipsa5b39fa2017-06-08 15:34:16 -040010#include "GrGpuResourcePriv.h"
cdalton397536c2016-03-25 12:15:03 -070011#include "SkTraceMemoryDump.h"
12
13#define GL_CALL(X) GR_GL_CALL(this->glGpu()->glInterface(), X)
14#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->glGpu()->glInterface(), RET, X)
15
16#if GR_GL_CHECK_ALLOC_WITH_GET_ERROR
17 #define CLEAR_ERROR_BEFORE_ALLOC(iface) GrGLClearErr(iface)
18 #define GL_ALLOC_CALL(iface, call) GR_GL_CALL_NOERRCHECK(iface, call)
19 #define CHECK_ALLOC_ERROR(iface) GR_GL_GET_ERROR(iface)
20#else
21 #define CLEAR_ERROR_BEFORE_ALLOC(iface)
22 #define GL_ALLOC_CALL(iface, call) GR_GL_CALL(iface, call)
23 #define CHECK_ALLOC_ERROR(iface) GR_GL_NO_ERROR
24#endif
25
26#ifdef SK_DEBUG
27#define VALIDATE() this->validate()
28#else
29#define VALIDATE() do {} while(false)
30#endif
31
cdaltone2e71c22016-04-07 18:13:29 -070032GrGLBuffer* GrGLBuffer::Create(GrGLGpu* gpu, size_t size, GrBufferType intendedType,
33 GrAccessPattern accessPattern, const void* data) {
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040034 if (gpu->glCaps().transferBufferType() == GrGLCaps::kNone_TransferBufferType &&
35 (kXferCpuToGpu_GrBufferType == intendedType ||
36 kXferGpuToCpu_GrBufferType == intendedType)) {
37 return nullptr;
38 }
39
Hal Canary144caf52016-11-07 17:57:18 -050040 sk_sp<GrGLBuffer> buffer(new GrGLBuffer(gpu, size, intendedType, accessPattern, data));
csmartdalton485a1202016-07-13 10:16:32 -070041 if (0 == buffer->bufferID()) {
cdalton397536c2016-03-25 12:15:03 -070042 return nullptr;
43 }
44 return buffer.release();
45}
46
47// GL_STREAM_DRAW triggers an optimization in Chromium's GPU process where a client's vertex buffer
48// objects are implemented as client-side-arrays on tile-deferred architectures.
49#define DYNAMIC_DRAW_PARAM GR_GL_STREAM_DRAW
50
cdaltone2e71c22016-04-07 18:13:29 -070051inline static GrGLenum gr_to_gl_access_pattern(GrBufferType bufferType,
52 GrAccessPattern accessPattern) {
cdalton397536c2016-03-25 12:15:03 -070053 static const GrGLenum drawUsages[] = {
cdaltone2e71c22016-04-07 18:13:29 -070054 DYNAMIC_DRAW_PARAM, // TODO: Do we really want to use STREAM_DRAW here on non-Chromium?
55 GR_GL_STATIC_DRAW, // kStatic_GrAccessPattern
56 GR_GL_STREAM_DRAW // kStream_GrAccessPattern
cdalton397536c2016-03-25 12:15:03 -070057 };
cdaltone2e71c22016-04-07 18:13:29 -070058
cdalton397536c2016-03-25 12:15:03 -070059 static const GrGLenum readUsages[] = {
cdaltone2e71c22016-04-07 18:13:29 -070060 GR_GL_DYNAMIC_READ, // kDynamic_GrAccessPattern
61 GR_GL_STATIC_READ, // kStatic_GrAccessPattern
62 GR_GL_STREAM_READ // kStream_GrAccessPattern
cdalton397536c2016-03-25 12:15:03 -070063 };
cdaltone2e71c22016-04-07 18:13:29 -070064
cdalton397536c2016-03-25 12:15:03 -070065 GR_STATIC_ASSERT(0 == kDynamic_GrAccessPattern);
66 GR_STATIC_ASSERT(1 == kStatic_GrAccessPattern);
67 GR_STATIC_ASSERT(2 == kStream_GrAccessPattern);
68 GR_STATIC_ASSERT(SK_ARRAY_COUNT(drawUsages) == 1 + kLast_GrAccessPattern);
69 GR_STATIC_ASSERT(SK_ARRAY_COUNT(readUsages) == 1 + kLast_GrAccessPattern);
70
cdaltone2e71c22016-04-07 18:13:29 -070071 static GrGLenum const* const usageTypes[] = {
72 drawUsages, // kVertex_GrBufferType,
73 drawUsages, // kIndex_GrBufferType,
74 drawUsages, // kTexel_GrBufferType,
75 drawUsages, // kDrawIndirect_GrBufferType,
76 drawUsages, // kXferCpuToGpu_GrBufferType,
77 readUsages // kXferGpuToCpu_GrBufferType,
78 };
79
80 GR_STATIC_ASSERT(0 == kVertex_GrBufferType);
81 GR_STATIC_ASSERT(1 == kIndex_GrBufferType);
82 GR_STATIC_ASSERT(2 == kTexel_GrBufferType);
83 GR_STATIC_ASSERT(3 == kDrawIndirect_GrBufferType);
84 GR_STATIC_ASSERT(4 == kXferCpuToGpu_GrBufferType);
85 GR_STATIC_ASSERT(5 == kXferGpuToCpu_GrBufferType);
86 GR_STATIC_ASSERT(SK_ARRAY_COUNT(usageTypes) == kGrBufferTypeCount);
87
88 SkASSERT(bufferType >= 0 && bufferType <= kLast_GrBufferType);
cdalton397536c2016-03-25 12:15:03 -070089 SkASSERT(accessPattern >= 0 && accessPattern <= kLast_GrAccessPattern);
90
cdaltone2e71c22016-04-07 18:13:29 -070091 return usageTypes[bufferType][accessPattern];
cdalton397536c2016-03-25 12:15:03 -070092}
93
cdaltone2e71c22016-04-07 18:13:29 -070094GrGLBuffer::GrGLBuffer(GrGLGpu* gpu, size_t size, GrBufferType intendedType,
csmartdalton485a1202016-07-13 10:16:32 -070095 GrAccessPattern accessPattern, const void* data)
Robert Phillipsa5b39fa2017-06-08 15:34:16 -040096 : INHERITED(gpu, size, intendedType, accessPattern)
97 , fIntendedType(intendedType)
98 , fBufferID(0)
99 , fUsage(gr_to_gl_access_pattern(intendedType, accessPattern))
100 , fGLSizeInBytes(0)
101 , fHasAttachedToTexture(false) {
csmartdalton485a1202016-07-13 10:16:32 -0700102 GL_CALL(GenBuffers(1, &fBufferID));
103 if (fBufferID) {
104 GrGLenum target = gpu->bindBuffer(fIntendedType, this);
105 CLEAR_ERROR_BEFORE_ALLOC(gpu->glInterface());
106 // make sure driver can allocate memory for this buffer
107 GL_ALLOC_CALL(gpu->glInterface(), BufferData(target,
108 (GrGLsizeiptr) size,
109 data,
110 fUsage));
111 if (CHECK_ALLOC_ERROR(gpu->glInterface()) != GR_GL_NO_ERROR) {
112 GL_CALL(DeleteBuffers(1, &fBufferID));
113 fBufferID = 0;
cdalton397536c2016-03-25 12:15:03 -0700114 } else {
csmartdalton485a1202016-07-13 10:16:32 -0700115 fGLSizeInBytes = size;
cdalton397536c2016-03-25 12:15:03 -0700116 }
117 }
118 VALIDATE();
kkinnunen2e6055b2016-04-22 01:48:29 -0700119 this->registerWithCache(SkBudgeted::kYes);
Robert Phillipsa5b39fa2017-06-08 15:34:16 -0400120 if (!fBufferID) {
121 this->resourcePriv().removeScratchKey();
122 }
cdalton397536c2016-03-25 12:15:03 -0700123}
124
125inline GrGLGpu* GrGLBuffer::glGpu() const {
126 SkASSERT(!this->wasDestroyed());
127 return static_cast<GrGLGpu*>(this->getGpu());
128}
129
130inline const GrGLCaps& GrGLBuffer::glCaps() const {
131 return this->glGpu()->glCaps();
132}
133
134void GrGLBuffer::onRelease() {
135 if (!this->wasDestroyed()) {
136 VALIDATE();
137 // make sure we've not been abandoned or already released
csmartdalton485a1202016-07-13 10:16:32 -0700138 if (fBufferID) {
cdaltone2e71c22016-04-07 18:13:29 -0700139 GL_CALL(DeleteBuffers(1, &fBufferID));
cdalton397536c2016-03-25 12:15:03 -0700140 fBufferID = 0;
141 fGLSizeInBytes = 0;
cdalton74b8d322016-04-11 14:47:28 -0700142 this->glGpu()->notifyBufferReleased(this);
cdalton397536c2016-03-25 12:15:03 -0700143 }
144 fMapPtr = nullptr;
145 VALIDATE();
146 }
147
148 INHERITED::onRelease();
149}
150
151void GrGLBuffer::onAbandon() {
152 fBufferID = 0;
153 fGLSizeInBytes = 0;
154 fMapPtr = nullptr;
cdalton397536c2016-03-25 12:15:03 -0700155 VALIDATE();
156 INHERITED::onAbandon();
157}
158
159void GrGLBuffer::onMap() {
Robert Phillipsa5b39fa2017-06-08 15:34:16 -0400160 SkASSERT(fBufferID);
cdalton397536c2016-03-25 12:15:03 -0700161 if (this->wasDestroyed()) {
162 return;
163 }
164
165 VALIDATE();
166 SkASSERT(!this->isMapped());
167
cdaltone2e71c22016-04-07 18:13:29 -0700168 // TODO: Make this a function parameter.
169 bool readOnly = (kXferGpuToCpu_GrBufferType == fIntendedType);
cdalton397536c2016-03-25 12:15:03 -0700170
171 // Handling dirty context is done in the bindBuffer call
172 switch (this->glCaps().mapBufferType()) {
173 case GrGLCaps::kNone_MapBufferType:
174 break;
cdaltone2e71c22016-04-07 18:13:29 -0700175 case GrGLCaps::kMapBuffer_MapBufferType: {
176 GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
cdalton397536c2016-03-25 12:15:03 -0700177 // Let driver know it can discard the old data
csmartdalton485a1202016-07-13 10:16:32 -0700178 if (GR_GL_USE_BUFFER_DATA_NULL_HINT || fGLSizeInBytes != this->sizeInBytes()) {
179 GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
cdalton397536c2016-03-25 12:15:03 -0700180 }
cdaltone2e71c22016-04-07 18:13:29 -0700181 GL_CALL_RET(fMapPtr, MapBuffer(target, readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY));
cdalton397536c2016-03-25 12:15:03 -0700182 break;
cdaltone2e71c22016-04-07 18:13:29 -0700183 }
cdalton397536c2016-03-25 12:15:03 -0700184 case GrGLCaps::kMapBufferRange_MapBufferType: {
cdaltone2e71c22016-04-07 18:13:29 -0700185 GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
cdalton397536c2016-03-25 12:15:03 -0700186 // Make sure the GL buffer size agrees with fDesc before mapping.
csmartdalton485a1202016-07-13 10:16:32 -0700187 if (fGLSizeInBytes != this->sizeInBytes()) {
188 GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
cdalton397536c2016-03-25 12:15:03 -0700189 }
190 GrGLbitfield writeAccess = GR_GL_MAP_WRITE_BIT;
cdaltone2e71c22016-04-07 18:13:29 -0700191 if (kXferCpuToGpu_GrBufferType != fIntendedType) {
192 // TODO: Make this a function parameter.
cdalton397536c2016-03-25 12:15:03 -0700193 writeAccess |= GR_GL_MAP_INVALIDATE_BUFFER_BIT;
194 }
csmartdalton485a1202016-07-13 10:16:32 -0700195 GL_CALL_RET(fMapPtr, MapBufferRange(target, 0, this->sizeInBytes(),
cdalton397536c2016-03-25 12:15:03 -0700196 readOnly ? GR_GL_MAP_READ_BIT : writeAccess));
197 break;
198 }
cdaltone2e71c22016-04-07 18:13:29 -0700199 case GrGLCaps::kChromium_MapBufferType: {
200 GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
cdalton397536c2016-03-25 12:15:03 -0700201 // Make sure the GL buffer size agrees with fDesc before mapping.
csmartdalton485a1202016-07-13 10:16:32 -0700202 if (fGLSizeInBytes != this->sizeInBytes()) {
203 GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
cdalton397536c2016-03-25 12:15:03 -0700204 }
csmartdalton485a1202016-07-13 10:16:32 -0700205 GL_CALL_RET(fMapPtr, MapBufferSubData(target, 0, this->sizeInBytes(),
cdalton397536c2016-03-25 12:15:03 -0700206 readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY));
207 break;
cdaltone2e71c22016-04-07 18:13:29 -0700208 }
cdalton397536c2016-03-25 12:15:03 -0700209 }
csmartdalton485a1202016-07-13 10:16:32 -0700210 fGLSizeInBytes = this->sizeInBytes();
cdalton397536c2016-03-25 12:15:03 -0700211 VALIDATE();
212}
213
214void GrGLBuffer::onUnmap() {
Robert Phillipsa5b39fa2017-06-08 15:34:16 -0400215 SkASSERT(fBufferID);
cdalton397536c2016-03-25 12:15:03 -0700216 if (this->wasDestroyed()) {
217 return;
218 }
219
220 VALIDATE();
221 SkASSERT(this->isMapped());
222 if (0 == fBufferID) {
223 fMapPtr = nullptr;
224 return;
225 }
226 // bind buffer handles the dirty context
227 switch (this->glCaps().mapBufferType()) {
228 case GrGLCaps::kNone_MapBufferType:
229 SkDEBUGFAIL("Shouldn't get here.");
230 return;
231 case GrGLCaps::kMapBuffer_MapBufferType: // fall through
cdaltone2e71c22016-04-07 18:13:29 -0700232 case GrGLCaps::kMapBufferRange_MapBufferType: {
233 GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
234 GL_CALL(UnmapBuffer(target));
cdalton397536c2016-03-25 12:15:03 -0700235 break;
cdaltone2e71c22016-04-07 18:13:29 -0700236 }
cdalton397536c2016-03-25 12:15:03 -0700237 case GrGLCaps::kChromium_MapBufferType:
cdaltone2e71c22016-04-07 18:13:29 -0700238 this->glGpu()->bindBuffer(fIntendedType, this); // TODO: Is this needed?
cdalton397536c2016-03-25 12:15:03 -0700239 GL_CALL(UnmapBufferSubData(fMapPtr));
240 break;
241 }
242 fMapPtr = nullptr;
243}
244
245bool GrGLBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) {
Robert Phillipsa5b39fa2017-06-08 15:34:16 -0400246 SkASSERT(fBufferID);
cdalton397536c2016-03-25 12:15:03 -0700247 if (this->wasDestroyed()) {
248 return false;
249 }
250
251 SkASSERT(!this->isMapped());
cdalton397536c2016-03-25 12:15:03 -0700252 VALIDATE();
csmartdalton485a1202016-07-13 10:16:32 -0700253 if (srcSizeInBytes > this->sizeInBytes()) {
cdalton397536c2016-03-25 12:15:03 -0700254 return false;
255 }
csmartdalton485a1202016-07-13 10:16:32 -0700256 SkASSERT(srcSizeInBytes <= this->sizeInBytes());
cdalton397536c2016-03-25 12:15:03 -0700257 // bindbuffer handles dirty context
cdaltone2e71c22016-04-07 18:13:29 -0700258 GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
cdalton397536c2016-03-25 12:15:03 -0700259
260#if GR_GL_USE_BUFFER_DATA_NULL_HINT
csmartdalton485a1202016-07-13 10:16:32 -0700261 if (this->sizeInBytes() == srcSizeInBytes) {
cdaltone2e71c22016-04-07 18:13:29 -0700262 GL_CALL(BufferData(target, (GrGLsizeiptr) srcSizeInBytes, src, fUsage));
cdalton397536c2016-03-25 12:15:03 -0700263 } else {
264 // Before we call glBufferSubData we give the driver a hint using
265 // glBufferData with nullptr. This makes the old buffer contents
266 // inaccessible to future draws. The GPU may still be processing
267 // draws that reference the old contents. With this hint it can
268 // assign a different allocation for the new contents to avoid
269 // flushing the gpu past draws consuming the old contents.
270 // TODO I think we actually want to try calling bufferData here
csmartdalton485a1202016-07-13 10:16:32 -0700271 GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
cdaltone2e71c22016-04-07 18:13:29 -0700272 GL_CALL(BufferSubData(target, 0, (GrGLsizeiptr) srcSizeInBytes, src));
cdalton397536c2016-03-25 12:15:03 -0700273 }
csmartdalton485a1202016-07-13 10:16:32 -0700274 fGLSizeInBytes = this->sizeInBytes();
cdalton397536c2016-03-25 12:15:03 -0700275#else
276 // Note that we're cheating on the size here. Currently no methods
277 // allow a partial update that preserves contents of non-updated
278 // portions of the buffer (map() does a glBufferData(..size, nullptr..))
cdaltone2e71c22016-04-07 18:13:29 -0700279 GL_CALL(BufferData(target, srcSizeInBytes, src, fUsage));
cdalton397536c2016-03-25 12:15:03 -0700280 fGLSizeInBytes = srcSizeInBytes;
281#endif
282 VALIDATE();
283 return true;
284}
285
286void GrGLBuffer::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
287 const SkString& dumpName) const {
288 SkString buffer_id;
289 buffer_id.appendU32(this->bufferID());
290 traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_buffer",
291 buffer_id.c_str());
292}
293
294#ifdef SK_DEBUG
295
296void GrGLBuffer::validate() const {
cdalton397536c2016-03-25 12:15:03 -0700297 SkASSERT(0 != fBufferID || 0 == fGLSizeInBytes);
csmartdalton485a1202016-07-13 10:16:32 -0700298 SkASSERT(nullptr == fMapPtr || fGLSizeInBytes <= this->sizeInBytes());
cdalton397536c2016-03-25 12:15:03 -0700299}
300
301#endif