OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrGLBufferImpl.h" | 8 #include "GrGLBufferImpl.h" |
9 #include "GrGLGpu.h" | 9 #include "GrGLGpu.h" |
10 | 10 |
11 #define GL_CALL(GPU, X) GR_GL_CALL(GPU->glInterface(), X) | 11 #define GL_CALL(GPU, X) GR_GL_CALL(GPU->glInterface(), X) |
12 | 12 |
13 #ifdef SK_DEBUG | 13 #ifdef SK_DEBUG |
14 #define VALIDATE() this->validate() | 14 #define VALIDATE() this->validate() |
15 #else | 15 #else |
16 #define VALIDATE() do {} while(false) | 16 #define VALIDATE() do {} while(false) |
17 #endif | 17 #endif |
18 | 18 |
19 // GL_STREAM_DRAW triggers an optimization in Chromium's GPU process where a cli
ent's vertex buffer | 19 // GL_STREAM_DRAW triggers an optimization in Chromium's GPU process where a cli
ent's vertex buffer |
20 // objects are implemented as client-side-arrays on tile-deferred architectures. | 20 // objects are implemented as client-side-arrays on tile-deferred architectures. |
21 #define DYNAMIC_USAGE_PARAM GR_GL_STREAM_DRAW | 21 #define DYNAMIC_USAGE_PARAM GR_GL_STREAM_DRAW |
22 | 22 |
23 GrGLBufferImpl::GrGLBufferImpl(GrGLGpu* gpu, const Desc& desc, GrGLenum bufferTy
pe) | 23 GrGLBufferImpl::GrGLBufferImpl(GrGLGpu* gpu, const Desc& desc, GrGLenum bufferTy
pe) |
24 : fDesc(desc) | 24 : fDesc(desc) |
25 , fBufferType(bufferType) | 25 , fBufferType(bufferType) |
26 , fMapPtr(NULL) { | 26 , fMapPtr(nullptr) { |
27 if (0 == desc.fID) { | 27 if (0 == desc.fID) { |
28 if (gpu->caps()->mustClearUploadedBufferData()) { | 28 if (gpu->caps()->mustClearUploadedBufferData()) { |
29 fCPUData = sk_calloc_throw(desc.fSizeInBytes); | 29 fCPUData = sk_calloc_throw(desc.fSizeInBytes); |
30 } else { | 30 } else { |
31 fCPUData = sk_malloc_flags(desc.fSizeInBytes, SK_MALLOC_THROW); | 31 fCPUData = sk_malloc_flags(desc.fSizeInBytes, SK_MALLOC_THROW); |
32 } | 32 } |
33 fGLSizeInBytes = 0; | 33 fGLSizeInBytes = 0; |
34 } else { | 34 } else { |
35 fCPUData = NULL; | 35 fCPUData = nullptr; |
36 // We assume that the GL buffer was created at the desc's size initially
. | 36 // We assume that the GL buffer was created at the desc's size initially
. |
37 fGLSizeInBytes = fDesc.fSizeInBytes; | 37 fGLSizeInBytes = fDesc.fSizeInBytes; |
38 } | 38 } |
39 VALIDATE(); | 39 VALIDATE(); |
40 } | 40 } |
41 | 41 |
42 void GrGLBufferImpl::release(GrGLGpu* gpu) { | 42 void GrGLBufferImpl::release(GrGLGpu* gpu) { |
43 VALIDATE(); | 43 VALIDATE(); |
44 // make sure we've not been abandoned or already released | 44 // make sure we've not been abandoned or already released |
45 if (fCPUData) { | 45 if (fCPUData) { |
46 sk_free(fCPUData); | 46 sk_free(fCPUData); |
47 fCPUData = NULL; | 47 fCPUData = nullptr; |
48 } else if (fDesc.fID) { | 48 } else if (fDesc.fID) { |
49 GL_CALL(gpu, DeleteBuffers(1, &fDesc.fID)); | 49 GL_CALL(gpu, DeleteBuffers(1, &fDesc.fID)); |
50 if (GR_GL_ARRAY_BUFFER == fBufferType) { | 50 if (GR_GL_ARRAY_BUFFER == fBufferType) { |
51 gpu->notifyVertexBufferDelete(fDesc.fID); | 51 gpu->notifyVertexBufferDelete(fDesc.fID); |
52 } else { | 52 } else { |
53 SkASSERT(GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); | 53 SkASSERT(GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); |
54 gpu->notifyIndexBufferDelete(fDesc.fID); | 54 gpu->notifyIndexBufferDelete(fDesc.fID); |
55 } | 55 } |
56 fDesc.fID = 0; | 56 fDesc.fID = 0; |
57 fGLSizeInBytes = 0; | 57 fGLSizeInBytes = 0; |
58 } | 58 } |
59 fMapPtr = NULL; | 59 fMapPtr = nullptr; |
60 VALIDATE(); | 60 VALIDATE(); |
61 } | 61 } |
62 | 62 |
63 void GrGLBufferImpl::abandon() { | 63 void GrGLBufferImpl::abandon() { |
64 fDesc.fID = 0; | 64 fDesc.fID = 0; |
65 fGLSizeInBytes = 0; | 65 fGLSizeInBytes = 0; |
66 fMapPtr = NULL; | 66 fMapPtr = nullptr; |
67 sk_free(fCPUData); | 67 sk_free(fCPUData); |
68 fCPUData = NULL; | 68 fCPUData = nullptr; |
69 VALIDATE(); | 69 VALIDATE(); |
70 } | 70 } |
71 | 71 |
72 void GrGLBufferImpl::bind(GrGLGpu* gpu) const { | 72 void GrGLBufferImpl::bind(GrGLGpu* gpu) const { |
73 VALIDATE(); | 73 VALIDATE(); |
74 if (GR_GL_ARRAY_BUFFER == fBufferType) { | 74 if (GR_GL_ARRAY_BUFFER == fBufferType) { |
75 gpu->bindVertexBuffer(fDesc.fID); | 75 gpu->bindVertexBuffer(fDesc.fID); |
76 } else { | 76 } else { |
77 SkASSERT(GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); | 77 SkASSERT(GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); |
78 gpu->bindIndexBufferAndDefaultVertexArray(fDesc.fID); | 78 gpu->bindIndexBufferAndDefaultVertexArray(fDesc.fID); |
79 } | 79 } |
80 VALIDATE(); | 80 VALIDATE(); |
81 } | 81 } |
82 | 82 |
83 void* GrGLBufferImpl::map(GrGLGpu* gpu) { | 83 void* GrGLBufferImpl::map(GrGLGpu* gpu) { |
84 VALIDATE(); | 84 VALIDATE(); |
85 SkASSERT(!this->isMapped()); | 85 SkASSERT(!this->isMapped()); |
86 if (0 == fDesc.fID) { | 86 if (0 == fDesc.fID) { |
87 fMapPtr = fCPUData; | 87 fMapPtr = fCPUData; |
88 } else { | 88 } else { |
89 switch (gpu->glCaps().mapBufferType()) { | 89 switch (gpu->glCaps().mapBufferType()) { |
90 case GrGLCaps::kNone_MapBufferType: | 90 case GrGLCaps::kNone_MapBufferType: |
91 VALIDATE(); | 91 VALIDATE(); |
92 return NULL; | 92 return nullptr; |
93 case GrGLCaps::kMapBuffer_MapBufferType: | 93 case GrGLCaps::kMapBuffer_MapBufferType: |
94 this->bind(gpu); | 94 this->bind(gpu); |
95 // Let driver know it can discard the old data | 95 // Let driver know it can discard the old data |
96 if (GR_GL_USE_BUFFER_DATA_NULL_HINT || fDesc.fSizeInBytes != fGL
SizeInBytes) { | 96 if (GR_GL_USE_BUFFER_DATA_NULL_HINT || fDesc.fSizeInBytes != fGL
SizeInBytes) { |
97 fGLSizeInBytes = fDesc.fSizeInBytes; | 97 fGLSizeInBytes = fDesc.fSizeInBytes; |
98 GL_CALL(gpu, | 98 GL_CALL(gpu, |
99 BufferData(fBufferType, fGLSizeInBytes, NULL, | 99 BufferData(fBufferType, fGLSizeInBytes, nullptr, |
100 fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR
_GL_STATIC_DRAW)); | 100 fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR
_GL_STATIC_DRAW)); |
101 } | 101 } |
102 GR_GL_CALL_RET(gpu->glInterface(), fMapPtr, | 102 GR_GL_CALL_RET(gpu->glInterface(), fMapPtr, |
103 MapBuffer(fBufferType, GR_GL_WRITE_ONLY)); | 103 MapBuffer(fBufferType, GR_GL_WRITE_ONLY)); |
104 break; | 104 break; |
105 case GrGLCaps::kMapBufferRange_MapBufferType: { | 105 case GrGLCaps::kMapBufferRange_MapBufferType: { |
106 this->bind(gpu); | 106 this->bind(gpu); |
107 // Make sure the GL buffer size agrees with fDesc before mapping
. | 107 // Make sure the GL buffer size agrees with fDesc before mapping
. |
108 if (fDesc.fSizeInBytes != fGLSizeInBytes) { | 108 if (fDesc.fSizeInBytes != fGLSizeInBytes) { |
109 fGLSizeInBytes = fDesc.fSizeInBytes; | 109 fGLSizeInBytes = fDesc.fSizeInBytes; |
110 GL_CALL(gpu, | 110 GL_CALL(gpu, |
111 BufferData(fBufferType, fGLSizeInBytes, NULL, | 111 BufferData(fBufferType, fGLSizeInBytes, nullptr, |
112 fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR
_GL_STATIC_DRAW)); | 112 fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR
_GL_STATIC_DRAW)); |
113 } | 113 } |
114 static const GrGLbitfield kAccess = GR_GL_MAP_INVALIDATE_BUFFER_
BIT | | 114 static const GrGLbitfield kAccess = GR_GL_MAP_INVALIDATE_BUFFER_
BIT | |
115 GR_GL_MAP_WRITE_BIT; | 115 GR_GL_MAP_WRITE_BIT; |
116 GR_GL_CALL_RET(gpu->glInterface(), | 116 GR_GL_CALL_RET(gpu->glInterface(), |
117 fMapPtr, | 117 fMapPtr, |
118 MapBufferRange(fBufferType, 0, fGLSizeInBytes, kA
ccess)); | 118 MapBufferRange(fBufferType, 0, fGLSizeInBytes, kA
ccess)); |
119 break; | 119 break; |
120 } | 120 } |
121 case GrGLCaps::kChromium_MapBufferType: | 121 case GrGLCaps::kChromium_MapBufferType: |
122 this->bind(gpu); | 122 this->bind(gpu); |
123 // Make sure the GL buffer size agrees with fDesc before mapping
. | 123 // Make sure the GL buffer size agrees with fDesc before mapping
. |
124 if (fDesc.fSizeInBytes != fGLSizeInBytes) { | 124 if (fDesc.fSizeInBytes != fGLSizeInBytes) { |
125 fGLSizeInBytes = fDesc.fSizeInBytes; | 125 fGLSizeInBytes = fDesc.fSizeInBytes; |
126 GL_CALL(gpu, | 126 GL_CALL(gpu, |
127 BufferData(fBufferType, fGLSizeInBytes, NULL, | 127 BufferData(fBufferType, fGLSizeInBytes, nullptr, |
128 fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR
_GL_STATIC_DRAW)); | 128 fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR
_GL_STATIC_DRAW)); |
129 } | 129 } |
130 GR_GL_CALL_RET(gpu->glInterface(), | 130 GR_GL_CALL_RET(gpu->glInterface(), |
131 fMapPtr, | 131 fMapPtr, |
132 MapBufferSubData(fBufferType, 0, fGLSizeInBytes,
GR_GL_WRITE_ONLY)); | 132 MapBufferSubData(fBufferType, 0, fGLSizeInBytes,
GR_GL_WRITE_ONLY)); |
133 break; | 133 break; |
134 } | 134 } |
135 } | 135 } |
136 VALIDATE(); | 136 VALIDATE(); |
137 return fMapPtr; | 137 return fMapPtr; |
(...skipping 11 matching lines...) Expand all Loading... |
149 case GrGLCaps::kMapBufferRange_MapBufferType: | 149 case GrGLCaps::kMapBufferRange_MapBufferType: |
150 this->bind(gpu); | 150 this->bind(gpu); |
151 GL_CALL(gpu, UnmapBuffer(fBufferType)); | 151 GL_CALL(gpu, UnmapBuffer(fBufferType)); |
152 break; | 152 break; |
153 case GrGLCaps::kChromium_MapBufferType: | 153 case GrGLCaps::kChromium_MapBufferType: |
154 this->bind(gpu); | 154 this->bind(gpu); |
155 GR_GL_CALL(gpu->glInterface(), UnmapBufferSubData(fMapPtr)); | 155 GR_GL_CALL(gpu->glInterface(), UnmapBufferSubData(fMapPtr)); |
156 break; | 156 break; |
157 } | 157 } |
158 } | 158 } |
159 fMapPtr = NULL; | 159 fMapPtr = nullptr; |
160 } | 160 } |
161 | 161 |
162 bool GrGLBufferImpl::isMapped() const { | 162 bool GrGLBufferImpl::isMapped() const { |
163 VALIDATE(); | 163 VALIDATE(); |
164 return SkToBool(fMapPtr); | 164 return SkToBool(fMapPtr); |
165 } | 165 } |
166 | 166 |
167 bool GrGLBufferImpl::updateData(GrGLGpu* gpu, const void* src, size_t srcSizeInB
ytes) { | 167 bool GrGLBufferImpl::updateData(GrGLGpu* gpu, const void* src, size_t srcSizeInB
ytes) { |
168 SkASSERT(!this->isMapped()); | 168 SkASSERT(!this->isMapped()); |
169 VALIDATE(); | 169 VALIDATE(); |
170 if (srcSizeInBytes > fDesc.fSizeInBytes) { | 170 if (srcSizeInBytes > fDesc.fSizeInBytes) { |
171 return false; | 171 return false; |
172 } | 172 } |
173 if (0 == fDesc.fID) { | 173 if (0 == fDesc.fID) { |
174 memcpy(fCPUData, src, srcSizeInBytes); | 174 memcpy(fCPUData, src, srcSizeInBytes); |
175 return true; | 175 return true; |
176 } | 176 } |
177 this->bind(gpu); | 177 this->bind(gpu); |
178 GrGLenum usage = fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR_GL_STATIC_DRAW; | 178 GrGLenum usage = fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR_GL_STATIC_DRAW; |
179 | 179 |
180 #if GR_GL_USE_BUFFER_DATA_NULL_HINT | 180 #if GR_GL_USE_BUFFER_DATA_NULL_HINT |
181 if (fDesc.fSizeInBytes == srcSizeInBytes) { | 181 if (fDesc.fSizeInBytes == srcSizeInBytes) { |
182 GL_CALL(gpu, BufferData(fBufferType, (GrGLsizeiptr) srcSizeInBytes, src,
usage)); | 182 GL_CALL(gpu, BufferData(fBufferType, (GrGLsizeiptr) srcSizeInBytes, src,
usage)); |
183 } else { | 183 } else { |
184 // Before we call glBufferSubData we give the driver a hint using | 184 // Before we call glBufferSubData we give the driver a hint using |
185 // glBufferData with NULL. This makes the old buffer contents | 185 // glBufferData with nullptr. This makes the old buffer contents |
186 // inaccessible to future draws. The GPU may still be processing | 186 // inaccessible to future draws. The GPU may still be processing |
187 // draws that reference the old contents. With this hint it can | 187 // draws that reference the old contents. With this hint it can |
188 // assign a different allocation for the new contents to avoid | 188 // assign a different allocation for the new contents to avoid |
189 // flushing the gpu past draws consuming the old contents. | 189 // flushing the gpu past draws consuming the old contents. |
190 fGLSizeInBytes = fDesc.fSizeInBytes; | 190 fGLSizeInBytes = fDesc.fSizeInBytes; |
191 GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, NULL, usage)); | 191 GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, nullptr, usage)); |
192 GL_CALL(gpu, BufferSubData(fBufferType, 0, (GrGLsizeiptr) srcSizeInBytes
, src)); | 192 GL_CALL(gpu, BufferSubData(fBufferType, 0, (GrGLsizeiptr) srcSizeInBytes
, src)); |
193 } | 193 } |
194 #else | 194 #else |
195 // Note that we're cheating on the size here. Currently no methods | 195 // Note that we're cheating on the size here. Currently no methods |
196 // allow a partial update that preserves contents of non-updated | 196 // allow a partial update that preserves contents of non-updated |
197 // portions of the buffer (map() does a glBufferData(..size, NULL..)) | 197 // portions of the buffer (map() does a glBufferData(..size, nullptr..)) |
198 bool doSubData = false; | 198 bool doSubData = false; |
199 #if GR_GL_MAC_BUFFER_OBJECT_PERFOMANCE_WORKAROUND | 199 #if GR_GL_MAC_BUFFER_OBJECT_PERFOMANCE_WORKAROUND |
200 static int N = 0; | 200 static int N = 0; |
201 // 128 was chosen experimentally. At 256 a slight hitchiness was noticed | 201 // 128 was chosen experimentally. At 256 a slight hitchiness was noticed |
202 // when dragging a Chromium window around with a canvas tab backgrounded. | 202 // when dragging a Chromium window around with a canvas tab backgrounded. |
203 doSubData = 0 == (N % 128); | 203 doSubData = 0 == (N % 128); |
204 ++N; | 204 ++N; |
205 #endif | 205 #endif |
206 if (doSubData) { | 206 if (doSubData) { |
207 // The workaround is to do a glBufferData followed by glBufferSubData. | 207 // The workaround is to do a glBufferData followed by glBufferSubData. |
208 // Chromium's command buffer may turn a glBufferSubData where the size | 208 // Chromium's command buffer may turn a glBufferSubData where the size |
209 // exactly matches the buffer size into a glBufferData. So we tack 1 | 209 // exactly matches the buffer size into a glBufferData. So we tack 1 |
210 // extra byte onto the glBufferData. | 210 // extra byte onto the glBufferData. |
211 fGLSizeInBytes = srcSizeInBytes + 1; | 211 fGLSizeInBytes = srcSizeInBytes + 1; |
212 GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, NULL, usage)); | 212 GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, nullptr, usage)); |
213 GL_CALL(gpu, BufferSubData(fBufferType, 0, srcSizeInBytes, src)); | 213 GL_CALL(gpu, BufferSubData(fBufferType, 0, srcSizeInBytes, src)); |
214 } else { | 214 } else { |
215 fGLSizeInBytes = srcSizeInBytes; | 215 fGLSizeInBytes = srcSizeInBytes; |
216 GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, src, usage)); | 216 GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, src, usage)); |
217 } | 217 } |
218 #endif | 218 #endif |
219 return true; | 219 return true; |
220 } | 220 } |
221 | 221 |
222 void GrGLBufferImpl::validate() const { | 222 void GrGLBufferImpl::validate() const { |
223 SkASSERT(GR_GL_ARRAY_BUFFER == fBufferType || GR_GL_ELEMENT_ARRAY_BUFFER ==
fBufferType); | 223 SkASSERT(GR_GL_ARRAY_BUFFER == fBufferType || GR_GL_ELEMENT_ARRAY_BUFFER ==
fBufferType); |
224 // The following assert isn't valid when the buffer has been abandoned: | 224 // The following assert isn't valid when the buffer has been abandoned: |
225 // SkASSERT((0 == fDesc.fID) == (fCPUData)); | 225 // SkASSERT((0 == fDesc.fID) == (fCPUData)); |
226 SkASSERT(NULL == fCPUData || 0 == fGLSizeInBytes); | 226 SkASSERT(nullptr == fCPUData || 0 == fGLSizeInBytes); |
227 SkASSERT(NULL == fMapPtr || fCPUData || fGLSizeInBytes == fDesc.fSizeInBytes
); | 227 SkASSERT(nullptr == fMapPtr || fCPUData || fGLSizeInBytes == fDesc.fSizeInBy
tes); |
228 SkASSERT(NULL == fCPUData || NULL == fMapPtr || fCPUData == fMapPtr); | 228 SkASSERT(nullptr == fCPUData || nullptr == fMapPtr || fCPUData == fMapPtr); |
229 } | 229 } |
OLD | NEW |