blob: 250c7119a927bff096c272d1d12f600d522296f5 [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"
10#include "SkTraceMemoryDump.h"
11
12#define GL_CALL(X) GR_GL_CALL(this->glGpu()->glInterface(), X)
13#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->glGpu()->glInterface(), RET, X)
14
15#if GR_GL_CHECK_ALLOC_WITH_GET_ERROR
16 #define CLEAR_ERROR_BEFORE_ALLOC(iface) GrGLClearErr(iface)
17 #define GL_ALLOC_CALL(iface, call) GR_GL_CALL_NOERRCHECK(iface, call)
18 #define CHECK_ALLOC_ERROR(iface) GR_GL_GET_ERROR(iface)
19#else
20 #define CLEAR_ERROR_BEFORE_ALLOC(iface)
21 #define GL_ALLOC_CALL(iface, call) GR_GL_CALL(iface, call)
22 #define CHECK_ALLOC_ERROR(iface) GR_GL_NO_ERROR
23#endif
24
25#ifdef SK_DEBUG
26#define VALIDATE() this->validate()
27#else
28#define VALIDATE() do {} while(false)
29#endif
30
cdaltone2e71c22016-04-07 18:13:29 -070031GrGLBuffer* GrGLBuffer::Create(GrGLGpu* gpu, size_t size, GrBufferType intendedType,
32 GrAccessPattern accessPattern, const void* data) {
Hal Canary144caf52016-11-07 17:57:18 -050033 sk_sp<GrGLBuffer> buffer(new GrGLBuffer(gpu, size, intendedType, accessPattern, data));
csmartdalton485a1202016-07-13 10:16:32 -070034 if (0 == buffer->bufferID()) {
cdalton397536c2016-03-25 12:15:03 -070035 return nullptr;
36 }
37 return buffer.release();
38}
39
40// GL_STREAM_DRAW triggers an optimization in Chromium's GPU process where a client's vertex buffer
41// objects are implemented as client-side-arrays on tile-deferred architectures.
42#define DYNAMIC_DRAW_PARAM GR_GL_STREAM_DRAW
43
cdaltone2e71c22016-04-07 18:13:29 -070044inline static GrGLenum gr_to_gl_access_pattern(GrBufferType bufferType,
45 GrAccessPattern accessPattern) {
cdalton397536c2016-03-25 12:15:03 -070046 static const GrGLenum drawUsages[] = {
cdaltone2e71c22016-04-07 18:13:29 -070047 DYNAMIC_DRAW_PARAM, // TODO: Do we really want to use STREAM_DRAW here on non-Chromium?
48 GR_GL_STATIC_DRAW, // kStatic_GrAccessPattern
49 GR_GL_STREAM_DRAW // kStream_GrAccessPattern
cdalton397536c2016-03-25 12:15:03 -070050 };
cdaltone2e71c22016-04-07 18:13:29 -070051
cdalton397536c2016-03-25 12:15:03 -070052 static const GrGLenum readUsages[] = {
cdaltone2e71c22016-04-07 18:13:29 -070053 GR_GL_DYNAMIC_READ, // kDynamic_GrAccessPattern
54 GR_GL_STATIC_READ, // kStatic_GrAccessPattern
55 GR_GL_STREAM_READ // kStream_GrAccessPattern
cdalton397536c2016-03-25 12:15:03 -070056 };
cdaltone2e71c22016-04-07 18:13:29 -070057
cdalton397536c2016-03-25 12:15:03 -070058 GR_STATIC_ASSERT(0 == kDynamic_GrAccessPattern);
59 GR_STATIC_ASSERT(1 == kStatic_GrAccessPattern);
60 GR_STATIC_ASSERT(2 == kStream_GrAccessPattern);
61 GR_STATIC_ASSERT(SK_ARRAY_COUNT(drawUsages) == 1 + kLast_GrAccessPattern);
62 GR_STATIC_ASSERT(SK_ARRAY_COUNT(readUsages) == 1 + kLast_GrAccessPattern);
63
cdaltone2e71c22016-04-07 18:13:29 -070064 static GrGLenum const* const usageTypes[] = {
65 drawUsages, // kVertex_GrBufferType,
66 drawUsages, // kIndex_GrBufferType,
67 drawUsages, // kTexel_GrBufferType,
68 drawUsages, // kDrawIndirect_GrBufferType,
69 drawUsages, // kXferCpuToGpu_GrBufferType,
70 readUsages // kXferGpuToCpu_GrBufferType,
71 };
72
73 GR_STATIC_ASSERT(0 == kVertex_GrBufferType);
74 GR_STATIC_ASSERT(1 == kIndex_GrBufferType);
75 GR_STATIC_ASSERT(2 == kTexel_GrBufferType);
76 GR_STATIC_ASSERT(3 == kDrawIndirect_GrBufferType);
77 GR_STATIC_ASSERT(4 == kXferCpuToGpu_GrBufferType);
78 GR_STATIC_ASSERT(5 == kXferGpuToCpu_GrBufferType);
79 GR_STATIC_ASSERT(SK_ARRAY_COUNT(usageTypes) == kGrBufferTypeCount);
80
81 SkASSERT(bufferType >= 0 && bufferType <= kLast_GrBufferType);
cdalton397536c2016-03-25 12:15:03 -070082 SkASSERT(accessPattern >= 0 && accessPattern <= kLast_GrAccessPattern);
83
cdaltone2e71c22016-04-07 18:13:29 -070084 return usageTypes[bufferType][accessPattern];
cdalton397536c2016-03-25 12:15:03 -070085}
86
cdaltone2e71c22016-04-07 18:13:29 -070087GrGLBuffer::GrGLBuffer(GrGLGpu* gpu, size_t size, GrBufferType intendedType,
csmartdalton485a1202016-07-13 10:16:32 -070088 GrAccessPattern accessPattern, const void* data)
89 : INHERITED(gpu, size, intendedType, accessPattern),
cdaltone2e71c22016-04-07 18:13:29 -070090 fIntendedType(intendedType),
cdalton397536c2016-03-25 12:15:03 -070091 fBufferID(0),
cdaltone2e71c22016-04-07 18:13:29 -070092 fUsage(gr_to_gl_access_pattern(intendedType, accessPattern)),
cdalton74b8d322016-04-11 14:47:28 -070093 fGLSizeInBytes(0),
94 fHasAttachedToTexture(false) {
csmartdalton485a1202016-07-13 10:16:32 -070095 GL_CALL(GenBuffers(1, &fBufferID));
96 if (fBufferID) {
97 GrGLenum target = gpu->bindBuffer(fIntendedType, this);
98 CLEAR_ERROR_BEFORE_ALLOC(gpu->glInterface());
99 // make sure driver can allocate memory for this buffer
100 GL_ALLOC_CALL(gpu->glInterface(), BufferData(target,
101 (GrGLsizeiptr) size,
102 data,
103 fUsage));
104 if (CHECK_ALLOC_ERROR(gpu->glInterface()) != GR_GL_NO_ERROR) {
105 GL_CALL(DeleteBuffers(1, &fBufferID));
106 fBufferID = 0;
cdalton397536c2016-03-25 12:15:03 -0700107 } else {
csmartdalton485a1202016-07-13 10:16:32 -0700108 fGLSizeInBytes = size;
cdalton397536c2016-03-25 12:15:03 -0700109 }
110 }
111 VALIDATE();
kkinnunen2e6055b2016-04-22 01:48:29 -0700112 this->registerWithCache(SkBudgeted::kYes);
cdalton397536c2016-03-25 12:15:03 -0700113}
114
115inline GrGLGpu* GrGLBuffer::glGpu() const {
116 SkASSERT(!this->wasDestroyed());
117 return static_cast<GrGLGpu*>(this->getGpu());
118}
119
120inline const GrGLCaps& GrGLBuffer::glCaps() const {
121 return this->glGpu()->glCaps();
122}
123
124void GrGLBuffer::onRelease() {
125 if (!this->wasDestroyed()) {
126 VALIDATE();
127 // make sure we've not been abandoned or already released
csmartdalton485a1202016-07-13 10:16:32 -0700128 if (fBufferID) {
cdaltone2e71c22016-04-07 18:13:29 -0700129 GL_CALL(DeleteBuffers(1, &fBufferID));
cdalton397536c2016-03-25 12:15:03 -0700130 fBufferID = 0;
131 fGLSizeInBytes = 0;
cdalton74b8d322016-04-11 14:47:28 -0700132 this->glGpu()->notifyBufferReleased(this);
cdalton397536c2016-03-25 12:15:03 -0700133 }
134 fMapPtr = nullptr;
135 VALIDATE();
136 }
137
138 INHERITED::onRelease();
139}
140
141void GrGLBuffer::onAbandon() {
142 fBufferID = 0;
143 fGLSizeInBytes = 0;
144 fMapPtr = nullptr;
cdalton397536c2016-03-25 12:15:03 -0700145 VALIDATE();
146 INHERITED::onAbandon();
147}
148
149void GrGLBuffer::onMap() {
150 if (this->wasDestroyed()) {
151 return;
152 }
153
154 VALIDATE();
155 SkASSERT(!this->isMapped());
156
cdaltone2e71c22016-04-07 18:13:29 -0700157 // TODO: Make this a function parameter.
158 bool readOnly = (kXferGpuToCpu_GrBufferType == fIntendedType);
cdalton397536c2016-03-25 12:15:03 -0700159
160 // Handling dirty context is done in the bindBuffer call
161 switch (this->glCaps().mapBufferType()) {
162 case GrGLCaps::kNone_MapBufferType:
163 break;
cdaltone2e71c22016-04-07 18:13:29 -0700164 case GrGLCaps::kMapBuffer_MapBufferType: {
165 GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
cdalton397536c2016-03-25 12:15:03 -0700166 // Let driver know it can discard the old data
csmartdalton485a1202016-07-13 10:16:32 -0700167 if (GR_GL_USE_BUFFER_DATA_NULL_HINT || fGLSizeInBytes != this->sizeInBytes()) {
168 GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
cdalton397536c2016-03-25 12:15:03 -0700169 }
cdaltone2e71c22016-04-07 18:13:29 -0700170 GL_CALL_RET(fMapPtr, MapBuffer(target, readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY));
cdalton397536c2016-03-25 12:15:03 -0700171 break;
cdaltone2e71c22016-04-07 18:13:29 -0700172 }
cdalton397536c2016-03-25 12:15:03 -0700173 case GrGLCaps::kMapBufferRange_MapBufferType: {
cdaltone2e71c22016-04-07 18:13:29 -0700174 GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
cdalton397536c2016-03-25 12:15:03 -0700175 // Make sure the GL buffer size agrees with fDesc before mapping.
csmartdalton485a1202016-07-13 10:16:32 -0700176 if (fGLSizeInBytes != this->sizeInBytes()) {
177 GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
cdalton397536c2016-03-25 12:15:03 -0700178 }
179 GrGLbitfield writeAccess = GR_GL_MAP_WRITE_BIT;
cdaltone2e71c22016-04-07 18:13:29 -0700180 if (kXferCpuToGpu_GrBufferType != fIntendedType) {
181 // TODO: Make this a function parameter.
cdalton397536c2016-03-25 12:15:03 -0700182 writeAccess |= GR_GL_MAP_INVALIDATE_BUFFER_BIT;
183 }
csmartdalton485a1202016-07-13 10:16:32 -0700184 GL_CALL_RET(fMapPtr, MapBufferRange(target, 0, this->sizeInBytes(),
cdalton397536c2016-03-25 12:15:03 -0700185 readOnly ? GR_GL_MAP_READ_BIT : writeAccess));
186 break;
187 }
cdaltone2e71c22016-04-07 18:13:29 -0700188 case GrGLCaps::kChromium_MapBufferType: {
189 GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
cdalton397536c2016-03-25 12:15:03 -0700190 // Make sure the GL buffer size agrees with fDesc before mapping.
csmartdalton485a1202016-07-13 10:16:32 -0700191 if (fGLSizeInBytes != this->sizeInBytes()) {
192 GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
cdalton397536c2016-03-25 12:15:03 -0700193 }
csmartdalton485a1202016-07-13 10:16:32 -0700194 GL_CALL_RET(fMapPtr, MapBufferSubData(target, 0, this->sizeInBytes(),
cdalton397536c2016-03-25 12:15:03 -0700195 readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY));
196 break;
cdaltone2e71c22016-04-07 18:13:29 -0700197 }
cdalton397536c2016-03-25 12:15:03 -0700198 }
csmartdalton485a1202016-07-13 10:16:32 -0700199 fGLSizeInBytes = this->sizeInBytes();
cdalton397536c2016-03-25 12:15:03 -0700200 VALIDATE();
201}
202
203void GrGLBuffer::onUnmap() {
204 if (this->wasDestroyed()) {
205 return;
206 }
207
208 VALIDATE();
209 SkASSERT(this->isMapped());
210 if (0 == fBufferID) {
211 fMapPtr = nullptr;
212 return;
213 }
214 // bind buffer handles the dirty context
215 switch (this->glCaps().mapBufferType()) {
216 case GrGLCaps::kNone_MapBufferType:
217 SkDEBUGFAIL("Shouldn't get here.");
218 return;
219 case GrGLCaps::kMapBuffer_MapBufferType: // fall through
cdaltone2e71c22016-04-07 18:13:29 -0700220 case GrGLCaps::kMapBufferRange_MapBufferType: {
221 GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
222 GL_CALL(UnmapBuffer(target));
cdalton397536c2016-03-25 12:15:03 -0700223 break;
cdaltone2e71c22016-04-07 18:13:29 -0700224 }
cdalton397536c2016-03-25 12:15:03 -0700225 case GrGLCaps::kChromium_MapBufferType:
cdaltone2e71c22016-04-07 18:13:29 -0700226 this->glGpu()->bindBuffer(fIntendedType, this); // TODO: Is this needed?
cdalton397536c2016-03-25 12:15:03 -0700227 GL_CALL(UnmapBufferSubData(fMapPtr));
228 break;
229 }
230 fMapPtr = nullptr;
231}
232
233bool GrGLBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) {
234 if (this->wasDestroyed()) {
235 return false;
236 }
237
238 SkASSERT(!this->isMapped());
cdalton397536c2016-03-25 12:15:03 -0700239 VALIDATE();
csmartdalton485a1202016-07-13 10:16:32 -0700240 if (srcSizeInBytes > this->sizeInBytes()) {
cdalton397536c2016-03-25 12:15:03 -0700241 return false;
242 }
csmartdalton485a1202016-07-13 10:16:32 -0700243 SkASSERT(srcSizeInBytes <= this->sizeInBytes());
cdalton397536c2016-03-25 12:15:03 -0700244 // bindbuffer handles dirty context
cdaltone2e71c22016-04-07 18:13:29 -0700245 GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
cdalton397536c2016-03-25 12:15:03 -0700246
247#if GR_GL_USE_BUFFER_DATA_NULL_HINT
csmartdalton485a1202016-07-13 10:16:32 -0700248 if (this->sizeInBytes() == srcSizeInBytes) {
cdaltone2e71c22016-04-07 18:13:29 -0700249 GL_CALL(BufferData(target, (GrGLsizeiptr) srcSizeInBytes, src, fUsage));
cdalton397536c2016-03-25 12:15:03 -0700250 } else {
251 // Before we call glBufferSubData we give the driver a hint using
252 // glBufferData with nullptr. This makes the old buffer contents
253 // inaccessible to future draws. The GPU may still be processing
254 // draws that reference the old contents. With this hint it can
255 // assign a different allocation for the new contents to avoid
256 // flushing the gpu past draws consuming the old contents.
257 // TODO I think we actually want to try calling bufferData here
csmartdalton485a1202016-07-13 10:16:32 -0700258 GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
cdaltone2e71c22016-04-07 18:13:29 -0700259 GL_CALL(BufferSubData(target, 0, (GrGLsizeiptr) srcSizeInBytes, src));
cdalton397536c2016-03-25 12:15:03 -0700260 }
csmartdalton485a1202016-07-13 10:16:32 -0700261 fGLSizeInBytes = this->sizeInBytes();
cdalton397536c2016-03-25 12:15:03 -0700262#else
263 // Note that we're cheating on the size here. Currently no methods
264 // allow a partial update that preserves contents of non-updated
265 // portions of the buffer (map() does a glBufferData(..size, nullptr..))
cdaltone2e71c22016-04-07 18:13:29 -0700266 GL_CALL(BufferData(target, srcSizeInBytes, src, fUsage));
cdalton397536c2016-03-25 12:15:03 -0700267 fGLSizeInBytes = srcSizeInBytes;
268#endif
269 VALIDATE();
270 return true;
271}
272
273void GrGLBuffer::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
274 const SkString& dumpName) const {
275 SkString buffer_id;
276 buffer_id.appendU32(this->bufferID());
277 traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_buffer",
278 buffer_id.c_str());
279}
280
281#ifdef SK_DEBUG
282
283void GrGLBuffer::validate() const {
cdalton397536c2016-03-25 12:15:03 -0700284 SkASSERT(0 != fBufferID || 0 == fGLSizeInBytes);
csmartdalton485a1202016-07-13 10:16:32 -0700285 SkASSERT(nullptr == fMapPtr || fGLSizeInBytes <= this->sizeInBytes());
cdalton397536c2016-03-25 12:15:03 -0700286}
287
288#endif