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 | |
20 // objects are implemented as client-side-arrays on tile-deferred architectures. | |
21 #define DYNAMIC_USAGE_PARAM GR_GL_STREAM_DRAW | |
22 | |
23 GrGLBufferImpl::GrGLBufferImpl(GrGLGpu* gpu, const Desc& desc, GrGLenum bufferTy
pe) | 19 GrGLBufferImpl::GrGLBufferImpl(GrGLGpu* gpu, const Desc& desc, GrGLenum bufferTy
pe) |
24 : fDesc(desc) | 20 : fDesc(desc) |
25 , fBufferType(bufferType) | 21 , fBufferType(bufferType) |
26 , fMapPtr(nullptr) { | 22 , fMapPtr(nullptr) { |
27 if (0 == desc.fID) { | 23 if (0 == desc.fID) { |
28 if (gpu->caps()->mustClearUploadedBufferData()) { | 24 if (gpu->caps()->mustClearUploadedBufferData()) { |
29 fCPUData = sk_calloc_throw(desc.fSizeInBytes); | 25 fCPUData = sk_calloc_throw(desc.fSizeInBytes); |
30 } else { | 26 } else { |
31 fCPUData = sk_malloc_flags(desc.fSizeInBytes, SK_MALLOC_THROW); | 27 fCPUData = sk_malloc_flags(desc.fSizeInBytes, SK_MALLOC_THROW); |
32 } | 28 } |
33 fGLSizeInBytes = 0; | 29 fGLSizeInBytes = 0; |
34 } else { | 30 } else { |
35 fCPUData = nullptr; | 31 fCPUData = nullptr; |
36 // We assume that the GL buffer was created at the desc's size initially
. | 32 // We assume that the GL buffer was created at the desc's size initially
. |
37 fGLSizeInBytes = fDesc.fSizeInBytes; | 33 fGLSizeInBytes = fDesc.fSizeInBytes; |
38 } | 34 } |
39 VALIDATE(); | 35 VALIDATE(); |
40 } | 36 } |
41 | 37 |
42 void GrGLBufferImpl::release(GrGLGpu* gpu) { | 38 void GrGLBufferImpl::release(GrGLGpu* gpu) { |
43 VALIDATE(); | 39 VALIDATE(); |
44 // make sure we've not been abandoned or already released | 40 // make sure we've not been abandoned or already released |
45 if (fCPUData) { | 41 if (fCPUData) { |
46 sk_free(fCPUData); | 42 sk_free(fCPUData); |
47 fCPUData = nullptr; | 43 fCPUData = nullptr; |
48 } else if (fDesc.fID) { | 44 } else if (fDesc.fID) { |
49 GL_CALL(gpu, DeleteBuffers(1, &fDesc.fID)); | 45 gpu->releaseBuffer(fDesc.fID, fBufferType); |
50 if (GR_GL_ARRAY_BUFFER == fBufferType) { | |
51 gpu->notifyVertexBufferDelete(fDesc.fID); | |
52 } else { | |
53 SkASSERT(GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); | |
54 gpu->notifyIndexBufferDelete(fDesc.fID); | |
55 } | |
56 fDesc.fID = 0; | 46 fDesc.fID = 0; |
57 fGLSizeInBytes = 0; | 47 fGLSizeInBytes = 0; |
58 } | 48 } |
59 fMapPtr = nullptr; | 49 fMapPtr = nullptr; |
60 VALIDATE(); | 50 VALIDATE(); |
61 } | 51 } |
62 | 52 |
63 void GrGLBufferImpl::abandon() { | 53 void GrGLBufferImpl::abandon() { |
64 fDesc.fID = 0; | 54 fDesc.fID = 0; |
65 fGLSizeInBytes = 0; | 55 fGLSizeInBytes = 0; |
66 fMapPtr = nullptr; | 56 fMapPtr = nullptr; |
67 sk_free(fCPUData); | 57 sk_free(fCPUData); |
68 fCPUData = nullptr; | 58 fCPUData = nullptr; |
69 VALIDATE(); | 59 VALIDATE(); |
70 } | 60 } |
71 | 61 |
72 void GrGLBufferImpl::bind(GrGLGpu* gpu) const { | |
73 VALIDATE(); | |
74 if (GR_GL_ARRAY_BUFFER == fBufferType) { | |
75 gpu->bindVertexBuffer(fDesc.fID); | |
76 } else { | |
77 SkASSERT(GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType); | |
78 gpu->bindIndexBufferAndDefaultVertexArray(fDesc.fID); | |
79 } | |
80 VALIDATE(); | |
81 } | |
82 | |
83 void* GrGLBufferImpl::map(GrGLGpu* gpu) { | 62 void* GrGLBufferImpl::map(GrGLGpu* gpu) { |
84 VALIDATE(); | 63 VALIDATE(); |
85 SkASSERT(!this->isMapped()); | 64 SkASSERT(!this->isMapped()); |
86 if (0 == fDesc.fID) { | 65 if (0 == fDesc.fID) { |
87 fMapPtr = fCPUData; | 66 fMapPtr = fCPUData; |
88 } else { | 67 } else { |
89 switch (gpu->glCaps().mapBufferType()) { | 68 fMapPtr = gpu->mapBuffer(fDesc.fID, fBufferType, fDesc.fDynamic, fGLSize
InBytes, |
90 case GrGLCaps::kNone_MapBufferType: | 69 fDesc.fSizeInBytes); |
91 VALIDATE(); | 70 fGLSizeInBytes = fDesc.fSizeInBytes; |
92 return nullptr; | |
93 case GrGLCaps::kMapBuffer_MapBufferType: | |
94 this->bind(gpu); | |
95 // Let driver know it can discard the old data | |
96 if (GR_GL_USE_BUFFER_DATA_NULL_HINT || fDesc.fSizeInBytes != fGL
SizeInBytes) { | |
97 fGLSizeInBytes = fDesc.fSizeInBytes; | |
98 GL_CALL(gpu, | |
99 BufferData(fBufferType, fGLSizeInBytes, nullptr, | |
100 fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR
_GL_STATIC_DRAW)); | |
101 } | |
102 GR_GL_CALL_RET(gpu->glInterface(), fMapPtr, | |
103 MapBuffer(fBufferType, GR_GL_WRITE_ONLY)); | |
104 break; | |
105 case GrGLCaps::kMapBufferRange_MapBufferType: { | |
106 this->bind(gpu); | |
107 // Make sure the GL buffer size agrees with fDesc before mapping
. | |
108 if (fDesc.fSizeInBytes != fGLSizeInBytes) { | |
109 fGLSizeInBytes = fDesc.fSizeInBytes; | |
110 GL_CALL(gpu, | |
111 BufferData(fBufferType, fGLSizeInBytes, nullptr, | |
112 fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR
_GL_STATIC_DRAW)); | |
113 } | |
114 static const GrGLbitfield kAccess = GR_GL_MAP_INVALIDATE_BUFFER_
BIT | | |
115 GR_GL_MAP_WRITE_BIT; | |
116 GR_GL_CALL_RET(gpu->glInterface(), | |
117 fMapPtr, | |
118 MapBufferRange(fBufferType, 0, fGLSizeInBytes, kA
ccess)); | |
119 break; | |
120 } | |
121 case GrGLCaps::kChromium_MapBufferType: | |
122 this->bind(gpu); | |
123 // Make sure the GL buffer size agrees with fDesc before mapping
. | |
124 if (fDesc.fSizeInBytes != fGLSizeInBytes) { | |
125 fGLSizeInBytes = fDesc.fSizeInBytes; | |
126 GL_CALL(gpu, | |
127 BufferData(fBufferType, fGLSizeInBytes, nullptr, | |
128 fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR
_GL_STATIC_DRAW)); | |
129 } | |
130 GR_GL_CALL_RET(gpu->glInterface(), | |
131 fMapPtr, | |
132 MapBufferSubData(fBufferType, 0, fGLSizeInBytes,
GR_GL_WRITE_ONLY)); | |
133 break; | |
134 } | |
135 } | 71 } |
136 VALIDATE(); | 72 VALIDATE(); |
137 return fMapPtr; | 73 return fMapPtr; |
138 } | 74 } |
139 | 75 |
140 void GrGLBufferImpl::unmap(GrGLGpu* gpu) { | 76 void GrGLBufferImpl::unmap(GrGLGpu* gpu) { |
141 VALIDATE(); | 77 VALIDATE(); |
142 SkASSERT(this->isMapped()); | 78 SkASSERT(this->isMapped()); |
143 if (0 != fDesc.fID) { | 79 if (0 != fDesc.fID) { |
144 switch (gpu->glCaps().mapBufferType()) { | 80 gpu->unmapBuffer(fDesc.fID, fBufferType, fMapPtr); |
145 case GrGLCaps::kNone_MapBufferType: | |
146 SkDEBUGFAIL("Shouldn't get here."); | |
147 return; | |
148 case GrGLCaps::kMapBuffer_MapBufferType: // fall through | |
149 case GrGLCaps::kMapBufferRange_MapBufferType: | |
150 this->bind(gpu); | |
151 GL_CALL(gpu, UnmapBuffer(fBufferType)); | |
152 break; | |
153 case GrGLCaps::kChromium_MapBufferType: | |
154 this->bind(gpu); | |
155 GR_GL_CALL(gpu->glInterface(), UnmapBufferSubData(fMapPtr)); | |
156 break; | |
157 } | |
158 } | 81 } |
159 fMapPtr = nullptr; | 82 fMapPtr = nullptr; |
160 } | 83 } |
161 | 84 |
162 bool GrGLBufferImpl::isMapped() const { | 85 bool GrGLBufferImpl::isMapped() const { |
163 VALIDATE(); | 86 VALIDATE(); |
164 return SkToBool(fMapPtr); | 87 return SkToBool(fMapPtr); |
165 } | 88 } |
166 | 89 |
167 bool GrGLBufferImpl::updateData(GrGLGpu* gpu, const void* src, size_t srcSizeInB
ytes) { | 90 bool GrGLBufferImpl::updateData(GrGLGpu* gpu, const void* src, size_t srcSizeInB
ytes) { |
168 SkASSERT(!this->isMapped()); | 91 SkASSERT(!this->isMapped()); |
169 VALIDATE(); | 92 VALIDATE(); |
170 if (srcSizeInBytes > fDesc.fSizeInBytes) { | 93 if (srcSizeInBytes > fDesc.fSizeInBytes) { |
171 return false; | 94 return false; |
172 } | 95 } |
173 if (0 == fDesc.fID) { | 96 if (0 == fDesc.fID) { |
174 memcpy(fCPUData, src, srcSizeInBytes); | 97 memcpy(fCPUData, src, srcSizeInBytes); |
175 return true; | 98 return true; |
176 } | 99 } |
177 this->bind(gpu); | 100 gpu->bufferData(fDesc.fID, fBufferType, fDesc.fDynamic, fDesc.fSizeInBytes,
src, |
178 GrGLenum usage = fDesc.fDynamic ? DYNAMIC_USAGE_PARAM : GR_GL_STATIC_DRAW; | 101 srcSizeInBytes); |
179 | |
180 #if GR_GL_USE_BUFFER_DATA_NULL_HINT | 102 #if GR_GL_USE_BUFFER_DATA_NULL_HINT |
181 if (fDesc.fSizeInBytes == srcSizeInBytes) { | 103 fGLSizeInBytes = fDesc.fSizeInBytes; |
182 GL_CALL(gpu, BufferData(fBufferType, (GrGLsizeiptr) srcSizeInBytes, src,
usage)); | |
183 } else { | |
184 // Before we call glBufferSubData we give the driver a hint using | |
185 // glBufferData with nullptr. This makes the old buffer contents | |
186 // inaccessible to future draws. The GPU may still be processing | |
187 // draws that reference the old contents. With this hint it can | |
188 // assign a different allocation for the new contents to avoid | |
189 // flushing the gpu past draws consuming the old contents. | |
190 fGLSizeInBytes = fDesc.fSizeInBytes; | |
191 GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, nullptr, usage)); | |
192 GL_CALL(gpu, BufferSubData(fBufferType, 0, (GrGLsizeiptr) srcSizeInBytes
, src)); | |
193 } | |
194 #else | 104 #else |
195 // Note that we're cheating on the size here. Currently no methods | |
196 // allow a partial update that preserves contents of non-updated | |
197 // portions of the buffer (map() does a glBufferData(..size, nullptr..)) | |
198 fGLSizeInBytes = srcSizeInBytes; | 105 fGLSizeInBytes = srcSizeInBytes; |
199 GL_CALL(gpu, BufferData(fBufferType, fGLSizeInBytes, src, usage)); | |
200 #endif | 106 #endif |
| 107 VALIDATE(); |
201 return true; | 108 return true; |
202 } | 109 } |
203 | 110 |
204 void GrGLBufferImpl::validate() const { | 111 void GrGLBufferImpl::validate() const { |
205 SkASSERT(GR_GL_ARRAY_BUFFER == fBufferType || GR_GL_ELEMENT_ARRAY_BUFFER ==
fBufferType); | 112 SkASSERT(GR_GL_ARRAY_BUFFER == fBufferType || GR_GL_ELEMENT_ARRAY_BUFFER ==
fBufferType); |
206 // The following assert isn't valid when the buffer has been abandoned: | 113 // The following assert isn't valid when the buffer has been abandoned: |
207 // SkASSERT((0 == fDesc.fID) == (fCPUData)); | 114 // SkASSERT((0 == fDesc.fID) == (fCPUData)); |
208 SkASSERT(nullptr == fCPUData || 0 == fGLSizeInBytes); | 115 SkASSERT(nullptr == fCPUData || 0 == fGLSizeInBytes); |
209 SkASSERT(nullptr == fMapPtr || fCPUData || fGLSizeInBytes == fDesc.fSizeInBy
tes); | 116 SkASSERT(nullptr == fMapPtr || fCPUData || fGLSizeInBytes <= fDesc.fSizeInBy
tes); |
210 SkASSERT(nullptr == fCPUData || nullptr == fMapPtr || fCPUData == fMapPtr); | 117 SkASSERT(nullptr == fCPUData || nullptr == fMapPtr || fCPUData == fMapPtr); |
211 } | 118 } |
OLD | NEW |