Line data Source code
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 "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 :
31 0 : GrGLBuffer* GrGLBuffer::Create(GrGLGpu* gpu, size_t size, GrBufferType intendedType,
32 : GrAccessPattern accessPattern, const void* data) {
33 0 : sk_sp<GrGLBuffer> buffer(new GrGLBuffer(gpu, size, intendedType, accessPattern, data));
34 0 : if (0 == buffer->bufferID()) {
35 0 : return nullptr;
36 : }
37 0 : 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 :
44 0 : inline static GrGLenum gr_to_gl_access_pattern(GrBufferType bufferType,
45 : GrAccessPattern accessPattern) {
46 : static const GrGLenum drawUsages[] = {
47 : 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
50 : };
51 :
52 : static const GrGLenum readUsages[] = {
53 : GR_GL_DYNAMIC_READ, // kDynamic_GrAccessPattern
54 : GR_GL_STATIC_READ, // kStatic_GrAccessPattern
55 : GR_GL_STREAM_READ // kStream_GrAccessPattern
56 : };
57 :
58 : 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 :
64 : 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 0 : SkASSERT(bufferType >= 0 && bufferType <= kLast_GrBufferType);
82 0 : SkASSERT(accessPattern >= 0 && accessPattern <= kLast_GrAccessPattern);
83 :
84 0 : return usageTypes[bufferType][accessPattern];
85 : }
86 :
87 0 : GrGLBuffer::GrGLBuffer(GrGLGpu* gpu, size_t size, GrBufferType intendedType,
88 0 : GrAccessPattern accessPattern, const void* data)
89 : : INHERITED(gpu, size, intendedType, accessPattern),
90 : fIntendedType(intendedType),
91 : fBufferID(0),
92 0 : fUsage(gr_to_gl_access_pattern(intendedType, accessPattern)),
93 : fGLSizeInBytes(0),
94 0 : fHasAttachedToTexture(false) {
95 0 : GL_CALL(GenBuffers(1, &fBufferID));
96 0 : if (fBufferID) {
97 0 : GrGLenum target = gpu->bindBuffer(fIntendedType, this);
98 0 : CLEAR_ERROR_BEFORE_ALLOC(gpu->glInterface());
99 : // make sure driver can allocate memory for this buffer
100 0 : GL_ALLOC_CALL(gpu->glInterface(), BufferData(target,
101 : (GrGLsizeiptr) size,
102 : data,
103 : fUsage));
104 0 : if (CHECK_ALLOC_ERROR(gpu->glInterface()) != GR_GL_NO_ERROR) {
105 0 : GL_CALL(DeleteBuffers(1, &fBufferID));
106 0 : fBufferID = 0;
107 : } else {
108 0 : fGLSizeInBytes = size;
109 : }
110 : }
111 0 : VALIDATE();
112 0 : this->registerWithCache(SkBudgeted::kYes);
113 0 : }
114 :
115 0 : inline GrGLGpu* GrGLBuffer::glGpu() const {
116 0 : SkASSERT(!this->wasDestroyed());
117 0 : return static_cast<GrGLGpu*>(this->getGpu());
118 : }
119 :
120 0 : inline const GrGLCaps& GrGLBuffer::glCaps() const {
121 0 : return this->glGpu()->glCaps();
122 : }
123 :
124 0 : void GrGLBuffer::onRelease() {
125 0 : if (!this->wasDestroyed()) {
126 0 : VALIDATE();
127 : // make sure we've not been abandoned or already released
128 0 : if (fBufferID) {
129 0 : GL_CALL(DeleteBuffers(1, &fBufferID));
130 0 : fBufferID = 0;
131 0 : fGLSizeInBytes = 0;
132 0 : this->glGpu()->notifyBufferReleased(this);
133 : }
134 0 : fMapPtr = nullptr;
135 0 : VALIDATE();
136 : }
137 :
138 0 : INHERITED::onRelease();
139 0 : }
140 :
141 0 : void GrGLBuffer::onAbandon() {
142 0 : fBufferID = 0;
143 0 : fGLSizeInBytes = 0;
144 0 : fMapPtr = nullptr;
145 0 : VALIDATE();
146 0 : INHERITED::onAbandon();
147 0 : }
148 :
149 0 : void GrGLBuffer::onMap() {
150 0 : if (this->wasDestroyed()) {
151 0 : return;
152 : }
153 :
154 0 : VALIDATE();
155 0 : SkASSERT(!this->isMapped());
156 :
157 : // TODO: Make this a function parameter.
158 0 : bool readOnly = (kXferGpuToCpu_GrBufferType == fIntendedType);
159 :
160 : // Handling dirty context is done in the bindBuffer call
161 0 : switch (this->glCaps().mapBufferType()) {
162 : case GrGLCaps::kNone_MapBufferType:
163 0 : break;
164 : case GrGLCaps::kMapBuffer_MapBufferType: {
165 0 : GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
166 : // Let driver know it can discard the old data
167 0 : if (GR_GL_USE_BUFFER_DATA_NULL_HINT || fGLSizeInBytes != this->sizeInBytes()) {
168 0 : GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
169 : }
170 0 : GL_CALL_RET(fMapPtr, MapBuffer(target, readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY));
171 0 : break;
172 : }
173 : case GrGLCaps::kMapBufferRange_MapBufferType: {
174 0 : GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
175 : // Make sure the GL buffer size agrees with fDesc before mapping.
176 0 : if (fGLSizeInBytes != this->sizeInBytes()) {
177 0 : GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
178 : }
179 0 : GrGLbitfield writeAccess = GR_GL_MAP_WRITE_BIT;
180 0 : if (kXferCpuToGpu_GrBufferType != fIntendedType) {
181 : // TODO: Make this a function parameter.
182 0 : writeAccess |= GR_GL_MAP_INVALIDATE_BUFFER_BIT;
183 : }
184 0 : GL_CALL_RET(fMapPtr, MapBufferRange(target, 0, this->sizeInBytes(),
185 : readOnly ? GR_GL_MAP_READ_BIT : writeAccess));
186 0 : break;
187 : }
188 : case GrGLCaps::kChromium_MapBufferType: {
189 0 : GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
190 : // Make sure the GL buffer size agrees with fDesc before mapping.
191 0 : if (fGLSizeInBytes != this->sizeInBytes()) {
192 0 : GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
193 : }
194 0 : GL_CALL_RET(fMapPtr, MapBufferSubData(target, 0, this->sizeInBytes(),
195 : readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY));
196 0 : break;
197 : }
198 : }
199 0 : fGLSizeInBytes = this->sizeInBytes();
200 0 : VALIDATE();
201 : }
202 :
203 0 : void GrGLBuffer::onUnmap() {
204 0 : if (this->wasDestroyed()) {
205 0 : return;
206 : }
207 :
208 0 : VALIDATE();
209 0 : SkASSERT(this->isMapped());
210 0 : if (0 == fBufferID) {
211 0 : fMapPtr = nullptr;
212 0 : return;
213 : }
214 : // bind buffer handles the dirty context
215 0 : switch (this->glCaps().mapBufferType()) {
216 : case GrGLCaps::kNone_MapBufferType:
217 0 : SkDEBUGFAIL("Shouldn't get here.");
218 0 : return;
219 : case GrGLCaps::kMapBuffer_MapBufferType: // fall through
220 : case GrGLCaps::kMapBufferRange_MapBufferType: {
221 0 : GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
222 0 : GL_CALL(UnmapBuffer(target));
223 0 : break;
224 : }
225 : case GrGLCaps::kChromium_MapBufferType:
226 0 : this->glGpu()->bindBuffer(fIntendedType, this); // TODO: Is this needed?
227 0 : GL_CALL(UnmapBufferSubData(fMapPtr));
228 0 : break;
229 : }
230 0 : fMapPtr = nullptr;
231 : }
232 :
233 0 : bool GrGLBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) {
234 0 : if (this->wasDestroyed()) {
235 0 : return false;
236 : }
237 :
238 0 : SkASSERT(!this->isMapped());
239 0 : VALIDATE();
240 0 : if (srcSizeInBytes > this->sizeInBytes()) {
241 0 : return false;
242 : }
243 0 : SkASSERT(srcSizeInBytes <= this->sizeInBytes());
244 : // bindbuffer handles dirty context
245 0 : GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
246 :
247 : #if GR_GL_USE_BUFFER_DATA_NULL_HINT
248 0 : if (this->sizeInBytes() == srcSizeInBytes) {
249 0 : GL_CALL(BufferData(target, (GrGLsizeiptr) srcSizeInBytes, src, fUsage));
250 : } 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
258 0 : GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
259 0 : GL_CALL(BufferSubData(target, 0, (GrGLsizeiptr) srcSizeInBytes, src));
260 : }
261 0 : fGLSizeInBytes = this->sizeInBytes();
262 : #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..))
266 : GL_CALL(BufferData(target, srcSizeInBytes, src, fUsage));
267 : fGLSizeInBytes = srcSizeInBytes;
268 : #endif
269 0 : VALIDATE();
270 0 : return true;
271 : }
272 :
273 0 : void GrGLBuffer::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
274 : const SkString& dumpName) const {
275 0 : SkString buffer_id;
276 0 : buffer_id.appendU32(this->bufferID());
277 0 : traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_buffer",
278 0 : buffer_id.c_str());
279 0 : }
280 :
281 : #ifdef SK_DEBUG
282 :
283 0 : void GrGLBuffer::validate() const {
284 0 : SkASSERT(0 != fBufferID || 0 == fGLSizeInBytes);
285 0 : SkASSERT(nullptr == fMapPtr || fGLSizeInBytes <= this->sizeInBytes());
286 0 : }
287 :
288 : #endif
|