• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "gpu/command_buffer/client/vertex_array_object_manager.h"
6 
7 #include "base/logging.h"
8 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
9 #include "gpu/command_buffer/client/gles2_implementation.h"
10 
11 #if defined(__native_client__) && !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
12 #define GLES2_SUPPORT_CLIENT_SIDE_ARRAYS
13 #endif
14 
15 namespace gpu {
16 namespace gles2 {
17 
18 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
19 
RoundUpToMultipleOf4(GLsizei size)20 static GLsizei RoundUpToMultipleOf4(GLsizei size) {
21   return (size + 3) & ~3;
22 }
23 
24 #endif  // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
25 
26 // A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
ToGLuint(const void * ptr)27 static GLuint ToGLuint(const void* ptr) {
28   return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
29 }
30 
31 // This class tracks VertexAttribPointers and helps emulate client side buffers.
32 //
33 // The way client side buffers work is we shadow all the Vertex Attribs so we
34 // know which ones are pointing to client side buffers.
35 //
36 // At Draw time, for any attribs pointing to client side buffers we copy them
37 // to a special VBO and reset the actual vertex attrib pointers to point to this
38 // VBO.
39 //
40 // This also means we have to catch calls to query those values so that when
41 // an attrib is a client side buffer we pass the info back the user expects.
42 
43 class GLES2_IMPL_EXPORT VertexArrayObject {
44  public:
45   // Info about Vertex Attributes. This is used to track what the user currently
46   // has bound on each Vertex Attribute so we can simulate client side buffers
47   // at glDrawXXX time.
48   class VertexAttrib {
49    public:
VertexAttrib()50     VertexAttrib()
51         : enabled_(false),
52           buffer_id_(0),
53           size_(4),
54           type_(GL_FLOAT),
55           normalized_(GL_FALSE),
56           pointer_(NULL),
57           gl_stride_(0),
58           divisor_(0) {
59     }
60 
enabled() const61     bool enabled() const {
62       return enabled_;
63     }
64 
set_enabled(bool enabled)65     void set_enabled(bool enabled) {
66       enabled_ = enabled;
67     }
68 
buffer_id() const69     GLuint buffer_id() const {
70       return buffer_id_;
71     }
72 
set_buffer_id(GLuint id)73     void set_buffer_id(GLuint id) {
74       buffer_id_ = id;
75     }
76 
type() const77     GLenum type() const {
78       return type_;
79     }
80 
size() const81     GLint size() const {
82       return size_;
83     }
84 
stride() const85     GLsizei stride() const {
86       return gl_stride_;
87     }
88 
normalized() const89     GLboolean normalized() const {
90       return normalized_;
91     }
92 
pointer() const93     const GLvoid* pointer() const {
94       return pointer_;
95     }
96 
IsClientSide() const97     bool IsClientSide() const {
98       return buffer_id_ == 0;
99     }
100 
divisor() const101     GLuint divisor() const {
102       return divisor_;
103     }
104 
SetInfo(GLuint buffer_id,GLint size,GLenum type,GLboolean normalized,GLsizei gl_stride,const GLvoid * pointer)105     void SetInfo(
106         GLuint buffer_id,
107         GLint size,
108         GLenum type,
109         GLboolean normalized,
110         GLsizei gl_stride,
111         const GLvoid* pointer) {
112       buffer_id_ = buffer_id;
113       size_ = size;
114       type_ = type;
115       normalized_ = normalized;
116       gl_stride_ = gl_stride;
117       pointer_ = pointer;
118     }
119 
SetDivisor(GLuint divisor)120     void SetDivisor(GLuint divisor) {
121       divisor_ = divisor;
122     }
123 
124    private:
125     // Whether or not this attribute is enabled.
126     bool enabled_;
127 
128     // The id of the buffer. 0 = client side buffer.
129     GLuint buffer_id_;
130 
131     // Number of components (1, 2, 3, 4).
132     GLint size_;
133 
134     // GL_BYTE, GL_FLOAT, etc. See glVertexAttribPointer.
135     GLenum type_;
136 
137     // GL_TRUE or GL_FALSE
138     GLboolean normalized_;
139 
140     // The pointer/offset into the buffer.
141     const GLvoid* pointer_;
142 
143     // The stride that will be used to access the buffer. This is the bogus GL
144     // stride where 0 = compute the stride based on size and type.
145     GLsizei gl_stride_;
146 
147     // Divisor, for geometry instancing.
148     GLuint divisor_;
149   };
150 
151   typedef std::vector<VertexAttrib> VertexAttribs;
152 
153   explicit VertexArrayObject(GLuint max_vertex_attribs);
154 
155   void UnbindBuffer(GLuint id);
156 
157   bool BindElementArray(GLuint id);
158 
159   bool HaveEnabledClientSideBuffers() const;
160 
161   void SetAttribEnable(GLuint index, bool enabled);
162 
163   void SetAttribPointer(
164     GLuint buffer_id,
165     GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
166     const void* ptr);
167 
168   bool GetVertexAttrib(
169       GLuint index, GLenum pname, uint32* param) const;
170 
171   void SetAttribDivisor(GLuint index, GLuint divisor);
172 
173   bool GetAttribPointer(GLuint index, GLenum pname, void** ptr) const;
174 
vertex_attribs() const175   const VertexAttribs& vertex_attribs() const {
176     return vertex_attribs_;
177   }
178 
bound_element_array_buffer() const179   GLuint bound_element_array_buffer() const {
180     return bound_element_array_buffer_id_;
181   }
182 
183  private:
184   const VertexAttrib* GetAttrib(GLuint index) const;
185 
186   int num_client_side_pointers_enabled_;
187 
188   // The currently bound element array buffer.
189   GLuint bound_element_array_buffer_id_;
190 
191   VertexAttribs vertex_attribs_;
192 
193   DISALLOW_COPY_AND_ASSIGN(VertexArrayObject);
194 };
195 
VertexArrayObject(GLuint max_vertex_attribs)196 VertexArrayObject::VertexArrayObject(GLuint max_vertex_attribs)
197     : num_client_side_pointers_enabled_(0),
198       bound_element_array_buffer_id_(0) {
199   vertex_attribs_.resize(max_vertex_attribs);
200 }
201 
UnbindBuffer(GLuint id)202 void VertexArrayObject::UnbindBuffer(GLuint id) {
203   if (id == 0) {
204     return;
205   }
206   for (size_t ii = 0; ii < vertex_attribs_.size(); ++ii) {
207     VertexAttrib& attrib = vertex_attribs_[ii];
208     if (attrib.buffer_id() == id) {
209       attrib.set_buffer_id(0);
210       if (attrib.enabled()) {
211         ++num_client_side_pointers_enabled_;
212       }
213     }
214   }
215   if (bound_element_array_buffer_id_ == id) {
216     bound_element_array_buffer_id_ = 0;
217   }
218 }
219 
BindElementArray(GLuint id)220 bool VertexArrayObject::BindElementArray(GLuint id) {
221   if (id == bound_element_array_buffer_id_) {
222     return false;
223   }
224   bound_element_array_buffer_id_ = id;
225   return true;
226 }
HaveEnabledClientSideBuffers() const227 bool VertexArrayObject::HaveEnabledClientSideBuffers() const {
228   return num_client_side_pointers_enabled_ > 0;
229 }
230 
SetAttribEnable(GLuint index,bool enabled)231 void VertexArrayObject::SetAttribEnable(GLuint index, bool enabled) {
232   if (index < vertex_attribs_.size()) {
233     VertexAttrib& attrib = vertex_attribs_[index];
234     if (attrib.enabled() != enabled) {
235       if (attrib.IsClientSide()) {
236         num_client_side_pointers_enabled_ += enabled ? 1 : -1;
237         DCHECK_GE(num_client_side_pointers_enabled_, 0);
238       }
239       attrib.set_enabled(enabled);
240     }
241   }
242 }
243 
SetAttribPointer(GLuint buffer_id,GLuint index,GLint size,GLenum type,GLboolean normalized,GLsizei stride,const void * ptr)244 void VertexArrayObject::SetAttribPointer(
245     GLuint buffer_id,
246     GLuint index,
247     GLint size,
248     GLenum type,
249     GLboolean normalized,
250     GLsizei stride,
251     const void* ptr) {
252   if (index < vertex_attribs_.size()) {
253     VertexAttrib& attrib = vertex_attribs_[index];
254     if (attrib.IsClientSide() && attrib.enabled()) {
255       --num_client_side_pointers_enabled_;
256       DCHECK_GE(num_client_side_pointers_enabled_, 0);
257     }
258 
259     attrib.SetInfo(buffer_id, size, type, normalized, stride, ptr);
260 
261     if (attrib.IsClientSide() && attrib.enabled()) {
262       ++num_client_side_pointers_enabled_;
263     }
264   }
265 }
266 
GetVertexAttrib(GLuint index,GLenum pname,uint32 * param) const267 bool VertexArrayObject::GetVertexAttrib(
268     GLuint index, GLenum pname, uint32* param) const {
269   const VertexAttrib* attrib = GetAttrib(index);
270   if (!attrib) {
271     return false;
272   }
273 
274   switch (pname) {
275     case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
276       *param = attrib->buffer_id();
277       break;
278     case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
279       *param = attrib->enabled();
280       break;
281     case GL_VERTEX_ATTRIB_ARRAY_SIZE:
282       *param = attrib->size();
283       break;
284     case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
285       *param = attrib->stride();
286       break;
287     case GL_VERTEX_ATTRIB_ARRAY_TYPE:
288       *param = attrib->type();
289       break;
290     case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
291       *param = attrib->normalized();
292       break;
293     default:
294       return false;  // pass through to service side.
295       break;
296   }
297   return true;
298 }
299 
SetAttribDivisor(GLuint index,GLuint divisor)300 void VertexArrayObject::SetAttribDivisor(GLuint index, GLuint divisor) {
301   if (index < vertex_attribs_.size()) {
302     VertexAttrib& attrib = vertex_attribs_[index];
303     attrib.SetDivisor(divisor);
304   }
305 }
306 
307 // Gets the Attrib pointer for an attrib but only if it's a client side
308 // pointer. Returns true if it got the pointer.
GetAttribPointer(GLuint index,GLenum pname,void ** ptr) const309 bool VertexArrayObject::GetAttribPointer(
310     GLuint index, GLenum pname, void** ptr) const {
311   const VertexAttrib* attrib = GetAttrib(index);
312   if (attrib && pname == GL_VERTEX_ATTRIB_ARRAY_POINTER) {
313     *ptr = const_cast<void*>(attrib->pointer());
314     return true;
315   }
316   return false;
317 }
318 
319 // Gets an attrib if it's in range and it's client side.
GetAttrib(GLuint index) const320 const VertexArrayObject::VertexAttrib* VertexArrayObject::GetAttrib(
321     GLuint index) const {
322   if (index < vertex_attribs_.size()) {
323     const VertexAttrib* attrib = &vertex_attribs_[index];
324     return attrib;
325   }
326   return NULL;
327 }
328 
VertexArrayObjectManager(GLuint max_vertex_attribs,GLuint array_buffer_id,GLuint element_array_buffer_id)329 VertexArrayObjectManager::VertexArrayObjectManager(
330     GLuint max_vertex_attribs,
331     GLuint array_buffer_id,
332     GLuint element_array_buffer_id)
333     : max_vertex_attribs_(max_vertex_attribs),
334       array_buffer_id_(array_buffer_id),
335       array_buffer_size_(0),
336       array_buffer_offset_(0),
337       element_array_buffer_id_(element_array_buffer_id),
338       element_array_buffer_size_(0),
339       collection_buffer_size_(0),
340       default_vertex_array_object_(new VertexArrayObject(max_vertex_attribs)),
341       bound_vertex_array_object_(default_vertex_array_object_) {
342 }
343 
~VertexArrayObjectManager()344 VertexArrayObjectManager::~VertexArrayObjectManager() {
345   for (VertexArrayObjectMap::iterator it = vertex_array_objects_.begin();
346        it != vertex_array_objects_.end(); ++it) {
347     delete it->second;
348   }
349   delete default_vertex_array_object_;
350 }
351 
IsReservedId(GLuint id) const352 bool VertexArrayObjectManager::IsReservedId(GLuint id) const {
353   return (id != 0 &&
354           (id == array_buffer_id_ || id == element_array_buffer_id_));
355 }
356 
bound_element_array_buffer() const357 GLuint VertexArrayObjectManager::bound_element_array_buffer() const {
358   return bound_vertex_array_object_->bound_element_array_buffer();
359 }
360 
UnbindBuffer(GLuint id)361 void VertexArrayObjectManager::UnbindBuffer(GLuint id) {
362   bound_vertex_array_object_->UnbindBuffer(id);
363 }
364 
BindElementArray(GLuint id)365 bool VertexArrayObjectManager::BindElementArray(GLuint id) {
366   return  bound_vertex_array_object_->BindElementArray(id);
367 }
368 
GenVertexArrays(GLsizei n,const GLuint * arrays)369 void VertexArrayObjectManager::GenVertexArrays(
370     GLsizei n, const GLuint* arrays) {
371   DCHECK_GE(n, 0);
372   for (GLsizei i = 0; i < n; ++i) {
373     std::pair<VertexArrayObjectMap::iterator, bool> result =
374         vertex_array_objects_.insert(std::make_pair(
375             arrays[i], new VertexArrayObject(max_vertex_attribs_)));
376     DCHECK(result.second);
377   }
378 }
379 
DeleteVertexArrays(GLsizei n,const GLuint * arrays)380 void VertexArrayObjectManager::DeleteVertexArrays(
381     GLsizei n, const GLuint* arrays) {
382   DCHECK_GE(n, 0);
383   for (GLsizei i = 0; i < n; ++i) {
384     GLuint id = arrays[i];
385     if (id) {
386       VertexArrayObjectMap::iterator it = vertex_array_objects_.find(id);
387       if (it != vertex_array_objects_.end()) {
388         if (bound_vertex_array_object_ == it->second) {
389           bound_vertex_array_object_ = default_vertex_array_object_;
390         }
391         delete it->second;
392         vertex_array_objects_.erase(it);
393       }
394     }
395   }
396 }
397 
BindVertexArray(GLuint array,bool * changed)398 bool VertexArrayObjectManager::BindVertexArray(GLuint array, bool* changed) {
399   *changed = false;
400   VertexArrayObject* vertex_array_object = default_vertex_array_object_;
401   if (array != 0) {
402     VertexArrayObjectMap::iterator it = vertex_array_objects_.find(array);
403     if (it == vertex_array_objects_.end()) {
404       return false;
405     }
406     vertex_array_object = it->second;
407   }
408   *changed = vertex_array_object != bound_vertex_array_object_;
409   bound_vertex_array_object_ = vertex_array_object;
410   return true;
411 }
412 
HaveEnabledClientSideBuffers() const413 bool VertexArrayObjectManager::HaveEnabledClientSideBuffers() const {
414   return bound_vertex_array_object_->HaveEnabledClientSideBuffers();
415 }
416 
SetAttribEnable(GLuint index,bool enabled)417 void VertexArrayObjectManager::SetAttribEnable(GLuint index, bool enabled) {
418   bound_vertex_array_object_->SetAttribEnable(index, enabled);
419 }
420 
GetVertexAttrib(GLuint index,GLenum pname,uint32 * param)421 bool VertexArrayObjectManager::GetVertexAttrib(
422     GLuint index, GLenum pname, uint32* param) {
423   return bound_vertex_array_object_->GetVertexAttrib(index, pname, param);
424 }
425 
GetAttribPointer(GLuint index,GLenum pname,void ** ptr) const426 bool VertexArrayObjectManager::GetAttribPointer(
427     GLuint index, GLenum pname, void** ptr) const {
428   return bound_vertex_array_object_->GetAttribPointer(index, pname, ptr);
429 }
430 
SetAttribPointer(GLuint buffer_id,GLuint index,GLint size,GLenum type,GLboolean normalized,GLsizei stride,const void * ptr)431 bool VertexArrayObjectManager::SetAttribPointer(
432     GLuint buffer_id,
433     GLuint index,
434     GLint size,
435     GLenum type,
436     GLboolean normalized,
437     GLsizei stride,
438     const void* ptr) {
439   // Client side arrays are not allowed in vaos.
440   if (buffer_id == 0 && !IsDefaultVAOBound()) {
441     return false;
442   }
443   bound_vertex_array_object_->SetAttribPointer(
444       buffer_id, index, size, type, normalized, stride, ptr);
445   return true;
446 }
447 
SetAttribDivisor(GLuint index,GLuint divisor)448 void VertexArrayObjectManager::SetAttribDivisor(GLuint index, GLuint divisor) {
449   bound_vertex_array_object_->SetAttribDivisor(index, divisor);
450 }
451 
452 // Collects the data into the collection buffer and returns the number of
453 // bytes collected.
CollectData(const void * data,GLsizei bytes_per_element,GLsizei real_stride,GLsizei num_elements)454 GLsizei VertexArrayObjectManager::CollectData(
455     const void* data,
456     GLsizei bytes_per_element,
457     GLsizei real_stride,
458     GLsizei num_elements) {
459   GLsizei bytes_needed = bytes_per_element * num_elements;
460   if (collection_buffer_size_ < bytes_needed) {
461     collection_buffer_.reset(new int8[bytes_needed]);
462     collection_buffer_size_ = bytes_needed;
463   }
464   const int8* src = static_cast<const int8*>(data);
465   int8* dst = collection_buffer_.get();
466   int8* end = dst + bytes_per_element * num_elements;
467   for (; dst < end; src += real_stride, dst += bytes_per_element) {
468     memcpy(dst, src, bytes_per_element);
469   }
470   return bytes_needed;
471 }
472 
IsDefaultVAOBound() const473 bool VertexArrayObjectManager::IsDefaultVAOBound() const {
474   return bound_vertex_array_object_ == default_vertex_array_object_;
475 }
476 
477 // Returns true if buffers were setup.
SetupSimulatedClientSideBuffers(const char * function_name,GLES2Implementation * gl,GLES2CmdHelper * gl_helper,GLsizei num_elements,GLsizei primcount,bool * simulated)478 bool VertexArrayObjectManager::SetupSimulatedClientSideBuffers(
479     const char* function_name,
480     GLES2Implementation* gl,
481     GLES2CmdHelper* gl_helper,
482     GLsizei num_elements,
483     GLsizei primcount,
484     bool* simulated) {
485   *simulated = false;
486 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
487   if (!bound_vertex_array_object_->HaveEnabledClientSideBuffers()) {
488     return true;
489   }
490   if (!IsDefaultVAOBound()) {
491     gl->SetGLError(
492         GL_INVALID_OPERATION, function_name,
493         "client side arrays not allowed with vertex array object");
494     return false;
495   }
496   *simulated = true;
497   GLsizei total_size = 0;
498   // Compute the size of the buffer we need.
499   const VertexArrayObject::VertexAttribs& vertex_attribs =
500       bound_vertex_array_object_->vertex_attribs();
501   for (GLuint ii = 0; ii < vertex_attribs.size(); ++ii) {
502     const VertexArrayObject::VertexAttrib& attrib = vertex_attribs[ii];
503     if (attrib.IsClientSide() && attrib.enabled()) {
504       size_t bytes_per_element =
505           GLES2Util::GetGLTypeSizeForTexturesAndBuffers(attrib.type()) *
506           attrib.size();
507       GLsizei elements = (primcount && attrib.divisor() > 0) ?
508           ((primcount - 1) / attrib.divisor() + 1) : num_elements;
509       total_size += RoundUpToMultipleOf4(bytes_per_element * elements);
510     }
511   }
512   gl_helper->BindBuffer(GL_ARRAY_BUFFER, array_buffer_id_);
513   array_buffer_offset_ = 0;
514   if (total_size > array_buffer_size_) {
515     gl->BufferDataHelper(GL_ARRAY_BUFFER, total_size, NULL, GL_DYNAMIC_DRAW);
516     array_buffer_size_ = total_size;
517   }
518   for (GLuint ii = 0; ii < vertex_attribs.size(); ++ii) {
519     const VertexArrayObject::VertexAttrib& attrib = vertex_attribs[ii];
520     if (attrib.IsClientSide() && attrib.enabled()) {
521       size_t bytes_per_element =
522           GLES2Util::GetGLTypeSizeForTexturesAndBuffers(attrib.type()) *
523           attrib.size();
524       GLsizei real_stride = attrib.stride() ?
525           attrib.stride() : static_cast<GLsizei>(bytes_per_element);
526       GLsizei elements = (primcount && attrib.divisor() > 0) ?
527           ((primcount - 1) / attrib.divisor() + 1) : num_elements;
528       GLsizei bytes_collected = CollectData(
529           attrib.pointer(), bytes_per_element, real_stride, elements);
530       gl->BufferSubDataHelper(
531           GL_ARRAY_BUFFER, array_buffer_offset_, bytes_collected,
532           collection_buffer_.get());
533       gl_helper->VertexAttribPointer(
534           ii, attrib.size(), attrib.type(), attrib.normalized(), 0,
535           array_buffer_offset_);
536       array_buffer_offset_ += RoundUpToMultipleOf4(bytes_collected);
537       DCHECK_LE(array_buffer_offset_, array_buffer_size_);
538     }
539   }
540 #endif  // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
541   return true;
542 }
543 
544 // Copies in indices to the service and returns the highest index accessed + 1
SetupSimulatedIndexAndClientSideBuffers(const char * function_name,GLES2Implementation * gl,GLES2CmdHelper * gl_helper,GLsizei count,GLenum type,GLsizei primcount,const void * indices,GLuint * offset,bool * simulated)545 bool VertexArrayObjectManager::SetupSimulatedIndexAndClientSideBuffers(
546     const char* function_name,
547     GLES2Implementation* gl,
548     GLES2CmdHelper* gl_helper,
549     GLsizei count,
550     GLenum type,
551     GLsizei primcount,
552     const void* indices,
553     GLuint* offset,
554     bool* simulated) {
555   *simulated = false;
556   *offset = ToGLuint(indices);
557 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
558   GLsizei num_elements = 0;
559   if (bound_vertex_array_object_->bound_element_array_buffer() == 0) {
560     *simulated = true;
561     *offset = 0;
562     GLsizei max_index = -1;
563     switch (type) {
564       case GL_UNSIGNED_BYTE: {
565         const uint8* src = static_cast<const uint8*>(indices);
566         for (GLsizei ii = 0; ii < count; ++ii) {
567           if (src[ii] > max_index) {
568             max_index = src[ii];
569           }
570         }
571         break;
572       }
573       case GL_UNSIGNED_SHORT: {
574         const uint16* src = static_cast<const uint16*>(indices);
575         for (GLsizei ii = 0; ii < count; ++ii) {
576           if (src[ii] > max_index) {
577             max_index = src[ii];
578           }
579         }
580         break;
581       }
582       case GL_UNSIGNED_INT: {
583         uint32 max_glsizei = static_cast<uint32>(
584             std::numeric_limits<GLsizei>::max());
585         const uint32* src = static_cast<const uint32*>(indices);
586         for (GLsizei ii = 0; ii < count; ++ii) {
587           // Other parts of the API use GLsizei (signed) to store limits.
588           // As such, if we encounter a index that cannot be represented with
589           // an unsigned int we need to flag it as an error here.
590           if(src[ii] > max_glsizei) {
591             gl->SetGLError(
592                 GL_INVALID_OPERATION, function_name, "index too large.");
593             return false;
594           }
595           GLsizei signed_index = static_cast<GLsizei>(src[ii]);
596           if (signed_index > max_index) {
597             max_index = signed_index;
598           }
599         }
600         break;
601       }
602       default:
603         break;
604     }
605     gl_helper->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_array_buffer_id_);
606     GLsizei bytes_per_element =
607         GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type);
608     GLsizei bytes_needed = bytes_per_element * count;
609     if (bytes_needed > element_array_buffer_size_) {
610       element_array_buffer_size_ = bytes_needed;
611       gl->BufferDataHelper(
612           GL_ELEMENT_ARRAY_BUFFER, bytes_needed, NULL, GL_DYNAMIC_DRAW);
613     }
614     gl->BufferSubDataHelper(
615         GL_ELEMENT_ARRAY_BUFFER, 0, bytes_needed, indices);
616 
617     num_elements = max_index + 1;
618   } else if (bound_vertex_array_object_->HaveEnabledClientSideBuffers()) {
619     // Index buffer is GL buffer. Ask the service for the highest vertex
620     // that will be accessed. Note: It doesn't matter if another context
621     // changes the contents of any of the buffers. The service will still
622     // validate the indices. We just need to know how much to copy across.
623     num_elements = gl->GetMaxValueInBufferCHROMIUMHelper(
624         bound_vertex_array_object_->bound_element_array_buffer(),
625         count, type, ToGLuint(indices)) + 1;
626   }
627 
628   bool simulated_client_side_buffers = false;
629   SetupSimulatedClientSideBuffers(
630       function_name, gl, gl_helper, num_elements, primcount,
631       &simulated_client_side_buffers);
632   *simulated = *simulated || simulated_client_side_buffers;
633 #endif  // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
634   return true;
635 }
636 
637 }  // namespace gles2
638 }  // namespace gpu
639 
640 
641