• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrGpuResourcePriv.h"
11 #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 
Create(GrGLGpu * gpu,size_t size,GrBufferType intendedType,GrAccessPattern accessPattern,const void * data)32 GrGLBuffer* GrGLBuffer::Create(GrGLGpu* gpu, size_t size, GrBufferType intendedType,
33                                GrAccessPattern accessPattern, const void* data) {
34     if (gpu->glCaps().transferBufferType() == GrGLCaps::kNone_TransferBufferType &&
35         (kXferCpuToGpu_GrBufferType == intendedType ||
36          kXferGpuToCpu_GrBufferType == intendedType)) {
37         return nullptr;
38     }
39 
40     sk_sp<GrGLBuffer> buffer(new GrGLBuffer(gpu, size, intendedType, accessPattern, data));
41     if (0 == buffer->bufferID()) {
42         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 
gr_to_gl_access_pattern(GrBufferType bufferType,GrAccessPattern accessPattern)51 inline static GrGLenum gr_to_gl_access_pattern(GrBufferType bufferType,
52                                                GrAccessPattern accessPattern) {
53     static const GrGLenum drawUsages[] = {
54         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
57     };
58 
59     static const GrGLenum readUsages[] = {
60         GR_GL_DYNAMIC_READ,  // kDynamic_GrAccessPattern
61         GR_GL_STATIC_READ,   // kStatic_GrAccessPattern
62         GR_GL_STREAM_READ    // kStream_GrAccessPattern
63     };
64 
65     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 
71     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);
89     SkASSERT(accessPattern >= 0 && accessPattern <= kLast_GrAccessPattern);
90 
91     return usageTypes[bufferType][accessPattern];
92 }
93 
GrGLBuffer(GrGLGpu * gpu,size_t size,GrBufferType intendedType,GrAccessPattern accessPattern,const void * data)94 GrGLBuffer::GrGLBuffer(GrGLGpu* gpu, size_t size, GrBufferType intendedType,
95                        GrAccessPattern accessPattern, const void* data)
96     : 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) {
102     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;
114         } else {
115             fGLSizeInBytes = size;
116         }
117     }
118     VALIDATE();
119     this->registerWithCache(SkBudgeted::kYes);
120     if (!fBufferID) {
121         this->resourcePriv().removeScratchKey();
122     }
123 }
124 
glGpu() const125 inline GrGLGpu* GrGLBuffer::glGpu() const {
126     SkASSERT(!this->wasDestroyed());
127     return static_cast<GrGLGpu*>(this->getGpu());
128 }
129 
glCaps() const130 inline const GrGLCaps& GrGLBuffer::glCaps() const {
131     return this->glGpu()->glCaps();
132 }
133 
onRelease()134 void GrGLBuffer::onRelease() {
135     if (!this->wasDestroyed()) {
136         VALIDATE();
137         // make sure we've not been abandoned or already released
138         if (fBufferID) {
139             GL_CALL(DeleteBuffers(1, &fBufferID));
140             fBufferID = 0;
141             fGLSizeInBytes = 0;
142             this->glGpu()->notifyBufferReleased(this);
143         }
144         fMapPtr = nullptr;
145         VALIDATE();
146     }
147 
148     INHERITED::onRelease();
149 }
150 
onAbandon()151 void GrGLBuffer::onAbandon() {
152     fBufferID = 0;
153     fGLSizeInBytes = 0;
154     fMapPtr = nullptr;
155     VALIDATE();
156     INHERITED::onAbandon();
157 }
158 
onMap()159 void GrGLBuffer::onMap() {
160     SkASSERT(fBufferID);
161     if (this->wasDestroyed()) {
162         return;
163     }
164 
165     VALIDATE();
166     SkASSERT(!this->isMapped());
167 
168     // TODO: Make this a function parameter.
169     bool readOnly = (kXferGpuToCpu_GrBufferType == fIntendedType);
170 
171     // Handling dirty context is done in the bindBuffer call
172     switch (this->glCaps().mapBufferType()) {
173         case GrGLCaps::kNone_MapBufferType:
174             break;
175         case GrGLCaps::kMapBuffer_MapBufferType: {
176             GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
177             // Let driver know it can discard the old data
178             if (this->glCaps().useBufferDataNullHint() || fGLSizeInBytes != this->sizeInBytes()) {
179                 GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
180             }
181             GL_CALL_RET(fMapPtr, MapBuffer(target, readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY));
182             break;
183         }
184         case GrGLCaps::kMapBufferRange_MapBufferType: {
185             GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
186             // Make sure the GL buffer size agrees with fDesc before mapping.
187             if (fGLSizeInBytes != this->sizeInBytes()) {
188                 GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
189             }
190             GrGLbitfield writeAccess = GR_GL_MAP_WRITE_BIT;
191             if (kXferCpuToGpu_GrBufferType != fIntendedType) {
192                 // TODO: Make this a function parameter.
193                 writeAccess |= GR_GL_MAP_INVALIDATE_BUFFER_BIT;
194             }
195             GL_CALL_RET(fMapPtr, MapBufferRange(target, 0, this->sizeInBytes(),
196                                                 readOnly ?  GR_GL_MAP_READ_BIT : writeAccess));
197             break;
198         }
199         case GrGLCaps::kChromium_MapBufferType: {
200             GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
201             // Make sure the GL buffer size agrees with fDesc before mapping.
202             if (fGLSizeInBytes != this->sizeInBytes()) {
203                 GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
204             }
205             GL_CALL_RET(fMapPtr, MapBufferSubData(target, 0, this->sizeInBytes(),
206                                                   readOnly ?  GR_GL_READ_ONLY : GR_GL_WRITE_ONLY));
207             break;
208         }
209     }
210     fGLSizeInBytes = this->sizeInBytes();
211     VALIDATE();
212 }
213 
onUnmap()214 void GrGLBuffer::onUnmap() {
215     SkASSERT(fBufferID);
216     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
232         case GrGLCaps::kMapBufferRange_MapBufferType: {
233             GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
234             GL_CALL(UnmapBuffer(target));
235             break;
236         }
237         case GrGLCaps::kChromium_MapBufferType:
238             this->glGpu()->bindBuffer(fIntendedType, this); // TODO: Is this needed?
239             GL_CALL(UnmapBufferSubData(fMapPtr));
240             break;
241     }
242     fMapPtr = nullptr;
243 }
244 
onUpdateData(const void * src,size_t srcSizeInBytes)245 bool GrGLBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) {
246     SkASSERT(fBufferID);
247     if (this->wasDestroyed()) {
248         return false;
249     }
250 
251     SkASSERT(!this->isMapped());
252     VALIDATE();
253     if (srcSizeInBytes > this->sizeInBytes()) {
254         return false;
255     }
256     SkASSERT(srcSizeInBytes <= this->sizeInBytes());
257     // bindbuffer handles dirty context
258     GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this);
259 
260     if (this->glCaps().useBufferDataNullHint()) {
261         if (this->sizeInBytes() == srcSizeInBytes) {
262             GL_CALL(BufferData(target, (GrGLsizeiptr) srcSizeInBytes, src, fUsage));
263         } 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
271             GL_CALL(BufferData(target, this->sizeInBytes(), nullptr, fUsage));
272             GL_CALL(BufferSubData(target, 0, (GrGLsizeiptr) srcSizeInBytes, src));
273         }
274         fGLSizeInBytes = this->sizeInBytes();
275     } 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..))
279         GL_CALL(BufferData(target, srcSizeInBytes, src, fUsage));
280         fGLSizeInBytes = srcSizeInBytes;
281     }
282     VALIDATE();
283     return true;
284 }
285 
setMemoryBacking(SkTraceMemoryDump * traceMemoryDump,const SkString & dumpName) const286 void 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 
validate() const296 void GrGLBuffer::validate() const {
297     SkASSERT(0 != fBufferID || 0 == fGLSizeInBytes);
298     SkASSERT(nullptr == fMapPtr || fGLSizeInBytes <= this->sizeInBytes());
299 }
300 
301 #endif
302