Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: src/gpu/gl/GrGLBuffer.cpp

Issue 1825393002: Consolidate GPU buffer implementations (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: asserts Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/gpu/gl/GrGLBuffer.h ('k') | src/gpu/gl/GrGLBufferImpl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 GrGLBuffer* GrGLBuffer::Create(GrGLGpu* gpu, GrBufferType type, size_t size,
32 GrAccessPattern accessPattern) {
33 static const int kIsVertexOrIndex = (1 << kVertex_GrBufferType) | (1 << kInd ex_GrBufferType);
34 bool cpuBacked = gpu->glCaps().useNonVBOVertexAndIndexDynamicData() &&
35 kDynamic_GrAccessPattern == accessPattern &&
36 ((kIsVertexOrIndex >> type) & 1);
37 SkAutoTUnref<GrGLBuffer> buffer(new GrGLBuffer(gpu, type, size, accessPatter n, cpuBacked));
38 if (!cpuBacked && 0 == buffer->fBufferID) {
39 return nullptr;
40 }
41 return buffer.release();
42 }
43
44 // GL_STREAM_DRAW triggers an optimization in Chromium's GPU process where a cli ent's vertex buffer
45 // objects are implemented as client-side-arrays on tile-deferred architectures.
46 #define DYNAMIC_DRAW_PARAM GR_GL_STREAM_DRAW
47
48 inline static void get_target_and_usage(GrBufferType type, GrAccessPattern acces sPattern,
49 const GrGLCaps& caps, GrGLenum* target, GrGLenum* usage) {
50 static const GrGLenum nonXferTargets[] = {
51 GR_GL_ARRAY_BUFFER,
52 GR_GL_ELEMENT_ARRAY_BUFFER
53 };
54 GR_STATIC_ASSERT(0 == kVertex_GrBufferType);
55 GR_STATIC_ASSERT(1 == kIndex_GrBufferType);
56
57 static const GrGLenum drawUsages[] = {
58 DYNAMIC_DRAW_PARAM, // TODO: Do we really want to use STREAM_DRAW here o n non-Chromium?
59 GR_GL_STATIC_DRAW,
60 GR_GL_STREAM_DRAW
61 };
62 static const GrGLenum readUsages[] = {
63 GR_GL_DYNAMIC_READ,
64 GR_GL_STATIC_READ,
65 GR_GL_STREAM_READ
66 };
67 GR_STATIC_ASSERT(0 == kDynamic_GrAccessPattern);
68 GR_STATIC_ASSERT(1 == kStatic_GrAccessPattern);
69 GR_STATIC_ASSERT(2 == kStream_GrAccessPattern);
70 GR_STATIC_ASSERT(SK_ARRAY_COUNT(drawUsages) == 1 + kLast_GrAccessPattern);
71 GR_STATIC_ASSERT(SK_ARRAY_COUNT(readUsages) == 1 + kLast_GrAccessPattern);
72
73 SkASSERT(accessPattern >= 0 && accessPattern <= kLast_GrAccessPattern);
74
75 switch (type) {
76 case kVertex_GrBufferType:
77 case kIndex_GrBufferType:
78 *target = nonXferTargets[type];
79 *usage = drawUsages[accessPattern];
80 break;
81 case kXferCpuToGpu_GrBufferType:
82 if (GrGLCaps::kChromium_TransferBufferType == caps.transferBufferTyp e()) {
83 *target = GR_GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM;
84 } else {
85 SkASSERT(GrGLCaps::kPBO_TransferBufferType == caps.transferBuffe rType());
86 *target = GR_GL_PIXEL_UNPACK_BUFFER;
87 }
88 *usage = drawUsages[accessPattern];
89 break;
90 case kXferGpuToCpu_GrBufferType:
91 if (GrGLCaps::kChromium_TransferBufferType == caps.transferBufferTyp e()) {
92 *target = GR_GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM;
93 } else {
94 SkASSERT(GrGLCaps::kPBO_TransferBufferType == caps.transferBuffe rType());
95 *target = GR_GL_PIXEL_PACK_BUFFER;
96 }
97 *usage = readUsages[accessPattern];
98 break;
99 default:
100 SkFAIL("Unexpected buffer type.");
101 break;
102 }
103 }
104
105 GrGLBuffer::GrGLBuffer(GrGLGpu* gpu, GrBufferType type, size_t size, GrAccessPat tern accessPattern,
106 bool cpuBacked)
107 : INHERITED(gpu, type, size, accessPattern, cpuBacked),
108 fCPUData(nullptr),
109 fTarget(0),
110 fBufferID(0),
111 fSizeInBytes(size),
112 fUsage(0),
113 fGLSizeInBytes(0) {
114 if (cpuBacked) {
115 if (gpu->caps()->mustClearUploadedBufferData()) {
116 fCPUData = sk_calloc_throw(fSizeInBytes);
117 } else {
118 fCPUData = sk_malloc_flags(fSizeInBytes, SK_MALLOC_THROW);
119 }
120 SkASSERT(kVertex_GrBufferType == type || kIndex_GrBufferType == type);
121 fTarget = kVertex_GrBufferType == type ? GR_GL_ARRAY_BUFFER : GR_GL_ELEM ENT_ARRAY_BUFFER;
122 } else {
123 GL_CALL(GenBuffers(1, &fBufferID));
124 fSizeInBytes = size;
125 get_target_and_usage(type, accessPattern, gpu->glCaps(), &fTarget, &fUsa ge);
126 if (fBufferID) {
127 gpu->bindBuffer(fBufferID, fTarget);
128 CLEAR_ERROR_BEFORE_ALLOC(gpu->glInterface());
129 // make sure driver can allocate memory for this buffer
130 GL_ALLOC_CALL(gpu->glInterface(), BufferData(fTarget,
131 (GrGLsizeiptr) fSizeInB ytes,
132 nullptr, // data ptr
133 fUsage));
134 if (CHECK_ALLOC_ERROR(gpu->glInterface()) != GR_GL_NO_ERROR) {
135 gpu->releaseBuffer(fBufferID, fTarget);
136 fBufferID = 0;
137 } else {
138 fGLSizeInBytes = fSizeInBytes;
139 }
140 }
141 }
142 VALIDATE();
143 this->registerWithCache();
144 }
145
146 inline GrGLGpu* GrGLBuffer::glGpu() const {
147 SkASSERT(!this->wasDestroyed());
148 return static_cast<GrGLGpu*>(this->getGpu());
149 }
150
151 inline const GrGLCaps& GrGLBuffer::glCaps() const {
152 return this->glGpu()->glCaps();
153 }
154
155 void GrGLBuffer::onRelease() {
156 if (!this->wasDestroyed()) {
157 VALIDATE();
158 // make sure we've not been abandoned or already released
159 if (fCPUData) {
160 SkASSERT(!fBufferID);
161 sk_free(fCPUData);
162 fCPUData = nullptr;
163 } else if (fBufferID) {
164 this->glGpu()->releaseBuffer(fBufferID, fTarget);
165 fBufferID = 0;
166 fGLSizeInBytes = 0;
167 }
168 fMapPtr = nullptr;
169 VALIDATE();
170 }
171
172 INHERITED::onRelease();
173 }
174
175 void GrGLBuffer::onAbandon() {
176 fBufferID = 0;
177 fGLSizeInBytes = 0;
178 fMapPtr = nullptr;
179 sk_free(fCPUData);
180 fCPUData = nullptr;
181 VALIDATE();
182 INHERITED::onAbandon();
183 }
184
185 void GrGLBuffer::onMap() {
186 if (this->wasDestroyed()) {
187 return;
188 }
189
190 VALIDATE();
191 SkASSERT(!this->isMapped());
192
193 if (0 == fBufferID) {
194 fMapPtr = fCPUData;
195 VALIDATE();
196 return;
197 }
198
199 bool readOnly = (kXferGpuToCpu_GrBufferType == this->type());
200
201 // Handling dirty context is done in the bindBuffer call
202 switch (this->glCaps().mapBufferType()) {
203 case GrGLCaps::kNone_MapBufferType:
204 break;
205 case GrGLCaps::kMapBuffer_MapBufferType:
206 this->glGpu()->bindBuffer(fBufferID, fTarget);
207 // Let driver know it can discard the old data
208 if (GR_GL_USE_BUFFER_DATA_NULL_HINT || fGLSizeInBytes != fSizeInByte s) {
209 GL_CALL(BufferData(fTarget, fSizeInBytes, nullptr, fUsage));
210 }
211 GL_CALL_RET(fMapPtr, MapBuffer(fTarget, readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY));
212 break;
213 case GrGLCaps::kMapBufferRange_MapBufferType: {
214 this->glGpu()->bindBuffer(fBufferID, fTarget);
215 // Make sure the GL buffer size agrees with fDesc before mapping.
216 if (fGLSizeInBytes != fSizeInBytes) {
217 GL_CALL(BufferData(fTarget, fSizeInBytes, nullptr, fUsage));
218 }
219 GrGLbitfield writeAccess = GR_GL_MAP_WRITE_BIT;
220 // TODO: allow the client to specify invalidation in the transfer bu ffer case.
221 if (kXferCpuToGpu_GrBufferType != this->type()) {
222 writeAccess |= GR_GL_MAP_INVALIDATE_BUFFER_BIT;
223 }
224 GL_CALL_RET(fMapPtr, MapBufferRange(fTarget, 0, fSizeInBytes,
225 readOnly ? GR_GL_MAP_READ_BIT : writeAccess));
226 break;
227 }
228 case GrGLCaps::kChromium_MapBufferType:
229 this->glGpu()->bindBuffer(fBufferID, fTarget);
230 // Make sure the GL buffer size agrees with fDesc before mapping.
231 if (fGLSizeInBytes != fSizeInBytes) {
232 GL_CALL(BufferData(fTarget, fSizeInBytes, nullptr, fUsage));
233 }
234 GL_CALL_RET(fMapPtr, MapBufferSubData(fTarget, 0, fSizeInBytes,
235 readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY));
236 break;
237 }
238 fGLSizeInBytes = fSizeInBytes;
239 VALIDATE();
240 }
241
242 void GrGLBuffer::onUnmap() {
243 if (this->wasDestroyed()) {
244 return;
245 }
246
247 VALIDATE();
248 SkASSERT(this->isMapped());
249 if (0 == fBufferID) {
250 fMapPtr = nullptr;
251 return;
252 }
253 // bind buffer handles the dirty context
254 switch (this->glCaps().mapBufferType()) {
255 case GrGLCaps::kNone_MapBufferType:
256 SkDEBUGFAIL("Shouldn't get here.");
257 return;
258 case GrGLCaps::kMapBuffer_MapBufferType: // fall through
259 case GrGLCaps::kMapBufferRange_MapBufferType:
260 this->glGpu()->bindBuffer(fBufferID, fTarget);
261 GL_CALL(UnmapBuffer(fTarget));
262 break;
263 case GrGLCaps::kChromium_MapBufferType:
264 this->glGpu()->bindBuffer(fBufferID, fTarget);
265 GL_CALL(UnmapBufferSubData(fMapPtr));
266 break;
267 }
268 fMapPtr = nullptr;
269 }
270
271 bool GrGLBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) {
272 if (this->wasDestroyed()) {
273 return false;
274 }
275
276 SkASSERT(!this->isMapped());
277 SkASSERT(GR_GL_ARRAY_BUFFER == fTarget || GR_GL_ELEMENT_ARRAY_BUFFER == fTar get);
278 VALIDATE();
279 if (srcSizeInBytes > fSizeInBytes) {
280 return false;
281 }
282 if (0 == fBufferID) {
283 memcpy(fCPUData, src, srcSizeInBytes);
284 return true;
285 }
286 SkASSERT(srcSizeInBytes <= fSizeInBytes);
287 // bindbuffer handles dirty context
288 this->glGpu()->bindBuffer(fBufferID, fTarget);
289
290 #if GR_GL_USE_BUFFER_DATA_NULL_HINT
291 if (fSizeInBytes == srcSizeInBytes) {
292 GL_CALL(BufferData(fTarget, (GrGLsizeiptr) srcSizeInBytes, src, fUsage)) ;
293 } else {
294 // Before we call glBufferSubData we give the driver a hint using
295 // glBufferData with nullptr. This makes the old buffer contents
296 // inaccessible to future draws. The GPU may still be processing
297 // draws that reference the old contents. With this hint it can
298 // assign a different allocation for the new contents to avoid
299 // flushing the gpu past draws consuming the old contents.
300 // TODO I think we actually want to try calling bufferData here
301 GL_CALL(BufferData(fTarget, fSizeInBytes, nullptr, fUsage));
302 GL_CALL(BufferSubData(fTarget, 0, (GrGLsizeiptr) srcSizeInBytes, src));
303 }
304 fGLSizeInBytes = fSizeInBytes;
305 #else
306 // Note that we're cheating on the size here. Currently no methods
307 // allow a partial update that preserves contents of non-updated
308 // portions of the buffer (map() does a glBufferData(..size, nullptr..))
309 GL_CALL(BufferData(fTarget, srcSizeInBytes, src, fUsage));
310 fGLSizeInBytes = srcSizeInBytes;
311 #endif
312 VALIDATE();
313 return true;
314 }
315
316 void GrGLBuffer::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
317 const SkString& dumpName) const {
318 SkString buffer_id;
319 buffer_id.appendU32(this->bufferID());
320 traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_buffer",
321 buffer_id.c_str());
322 }
323
324 #ifdef SK_DEBUG
325
326 void GrGLBuffer::validate() const {
327 SkASSERT(GR_GL_ARRAY_BUFFER == fTarget || GR_GL_ELEMENT_ARRAY_BUFFER == fTar get ||
328 GR_GL_PIXEL_PACK_BUFFER == fTarget || GR_GL_PIXEL_UNPACK_BUFFER == fTarget ||
329 GR_GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM == fTarget ||
330 GR_GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM == fTarget);
331 // The following assert isn't valid when the buffer has been abandoned:
332 // SkASSERT((0 == fDesc.fID) == (fCPUData));
333 SkASSERT(0 != fBufferID || 0 == fGLSizeInBytes);
334 SkASSERT(nullptr == fMapPtr || fCPUData || fGLSizeInBytes <= fSizeInBytes);
335 SkASSERT(nullptr == fCPUData || nullptr == fMapPtr || fCPUData == fMapPtr);
336 }
337
338 #endif
OLDNEW
« no previous file with comments | « src/gpu/gl/GrGLBuffer.h ('k') | src/gpu/gl/GrGLBufferImpl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698