• 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/service/vertex_attrib_manager.h"
6 
7 #include <list>
8 
9 #include "base/command_line.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "build/build_config.h"
14 #define GLES2_GPU_SERVICE 1
15 #include "gpu/command_buffer/common/gles2_cmd_format.h"
16 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
17 #include "gpu/command_buffer/service/buffer_manager.h"
18 #include "gpu/command_buffer/service/error_state.h"
19 #include "gpu/command_buffer/service/feature_info.h"
20 #include "gpu/command_buffer/service/gl_utils.h"
21 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
22 #include "gpu/command_buffer/service/gpu_switches.h"
23 #include "gpu/command_buffer/service/program_manager.h"
24 #include "gpu/command_buffer/service/vertex_array_manager.h"
25 
26 namespace gpu {
27 namespace gles2 {
28 
VertexAttrib()29 VertexAttrib::VertexAttrib()
30     : index_(0),
31       enabled_(false),
32       size_(4),
33       type_(GL_FLOAT),
34       offset_(0),
35       normalized_(GL_FALSE),
36       gl_stride_(0),
37       real_stride_(16),
38       divisor_(0),
39       is_client_side_array_(false),
40       list_(NULL) {
41 }
42 
~VertexAttrib()43 VertexAttrib::~VertexAttrib() {
44 }
45 
SetInfo(Buffer * buffer,GLint size,GLenum type,GLboolean normalized,GLsizei gl_stride,GLsizei real_stride,GLsizei offset)46 void VertexAttrib::SetInfo(
47     Buffer* buffer,
48     GLint size,
49     GLenum type,
50     GLboolean normalized,
51     GLsizei gl_stride,
52     GLsizei real_stride,
53     GLsizei offset) {
54   DCHECK_GT(real_stride, 0);
55   buffer_ = buffer;
56   size_ = size;
57   type_ = type;
58   normalized_ = normalized;
59   gl_stride_ = gl_stride;
60   real_stride_ = real_stride;
61   offset_ = offset;
62 }
63 
Unbind(Buffer * buffer)64 void VertexAttrib::Unbind(Buffer* buffer) {
65   if (buffer_.get() == buffer) {
66     buffer_ = NULL;
67   }
68 }
69 
CanAccess(GLuint index) const70 bool VertexAttrib::CanAccess(GLuint index) const {
71   if (!enabled_) {
72     return true;
73   }
74 
75   if (!buffer_.get() || buffer_->IsDeleted()) {
76     return false;
77   }
78 
79   // The number of elements that can be accessed.
80   GLsizeiptr buffer_size = buffer_->size();
81   if (offset_ > buffer_size || real_stride_ == 0) {
82     return false;
83   }
84 
85   uint32 usable_size = buffer_size - offset_;
86   GLuint num_elements = usable_size / real_stride_ +
87       ((usable_size % real_stride_) >=
88        (GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type_) * size_) ? 1 : 0);
89   return index < num_elements;
90 }
91 
VertexAttribManager()92 VertexAttribManager::VertexAttribManager()
93     : num_fixed_attribs_(0),
94       element_array_buffer_(NULL),
95       manager_(NULL),
96       deleted_(false),
97       service_id_(0) {
98 }
99 
VertexAttribManager(VertexArrayManager * manager,GLuint service_id,uint32 num_vertex_attribs)100 VertexAttribManager::VertexAttribManager(
101     VertexArrayManager* manager, GLuint service_id, uint32 num_vertex_attribs)
102     : num_fixed_attribs_(0),
103       element_array_buffer_(NULL),
104       manager_(manager),
105       deleted_(false),
106       service_id_(service_id) {
107   manager_->StartTracking(this);
108   Initialize(num_vertex_attribs, false);
109 }
110 
~VertexAttribManager()111 VertexAttribManager::~VertexAttribManager() {
112   if (manager_) {
113     if (manager_->have_context_) {
114       if (service_id_ != 0)  // 0 indicates an emulated VAO
115         glDeleteVertexArraysOES(1, &service_id_);
116     }
117     manager_->StopTracking(this);
118     manager_ = NULL;
119   }
120 }
121 
Initialize(uint32 max_vertex_attribs,bool init_attribs)122 void VertexAttribManager::Initialize(
123     uint32 max_vertex_attribs, bool init_attribs) {
124   vertex_attribs_.resize(max_vertex_attribs);
125   bool disable_workarounds = CommandLine::ForCurrentProcess()->HasSwitch(
126       switches::kDisableGpuDriverBugWorkarounds);
127 
128   for (uint32 vv = 0; vv < vertex_attribs_.size(); ++vv) {
129     vertex_attribs_[vv].set_index(vv);
130     vertex_attribs_[vv].SetList(&disabled_vertex_attribs_);
131 
132     if (!disable_workarounds && init_attribs) {
133       glVertexAttrib4f(vv, 0.0f, 0.0f, 0.0f, 1.0f);
134     }
135   }
136 }
137 
SetElementArrayBuffer(Buffer * buffer)138 void VertexAttribManager::SetElementArrayBuffer(Buffer* buffer) {
139   element_array_buffer_ = buffer;
140 }
141 
Enable(GLuint index,bool enable)142 bool VertexAttribManager::Enable(GLuint index, bool enable) {
143   if (index >= vertex_attribs_.size()) {
144     return false;
145   }
146   VertexAttrib& info = vertex_attribs_[index];
147   if (info.enabled() != enable) {
148     info.set_enabled(enable);
149     info.SetList(enable ? &enabled_vertex_attribs_ : &disabled_vertex_attribs_);
150   }
151   return true;
152 }
153 
Unbind(Buffer * buffer)154 void VertexAttribManager::Unbind(Buffer* buffer) {
155   if (element_array_buffer_.get() == buffer) {
156     element_array_buffer_ = NULL;
157   }
158   for (uint32 vv = 0; vv < vertex_attribs_.size(); ++vv) {
159     vertex_attribs_[vv].Unbind(buffer);
160   }
161 }
162 
ValidateBindings(const char * function_name,GLES2Decoder * decoder,FeatureInfo * feature_info,Program * current_program,GLuint max_vertex_accessed,GLsizei primcount)163 bool VertexAttribManager::ValidateBindings(
164     const char* function_name,
165     GLES2Decoder* decoder,
166     FeatureInfo* feature_info,
167     Program* current_program,
168     GLuint max_vertex_accessed,
169     GLsizei primcount) {
170   ErrorState* error_state = decoder->GetErrorState();
171   // true if any enabled, used divisor is zero
172   bool divisor0 = false;
173   const GLuint kInitialBufferId = 0xFFFFFFFFU;
174   GLuint current_buffer_id = kInitialBufferId;
175   bool use_client_side_arrays_for_stream_buffers = feature_info->workarounds(
176       ).use_client_side_arrays_for_stream_buffers;
177   // Validate all attribs currently enabled. If they are used by the current
178   // program then check that they have enough elements to handle the draw call.
179   // If they are not used by the current program check that they have a buffer
180   // assigned.
181   for (VertexAttribList::iterator it = enabled_vertex_attribs_.begin();
182        it != enabled_vertex_attribs_.end(); ++it) {
183     VertexAttrib* attrib = *it;
184     const Program::VertexAttrib* attrib_info =
185         current_program->GetAttribInfoByLocation(attrib->index());
186     if (attrib_info) {
187       divisor0 |= (attrib->divisor() == 0);
188       GLuint count = attrib->MaxVertexAccessed(primcount, max_vertex_accessed);
189       // This attrib is used in the current program.
190       if (!attrib->CanAccess(count)) {
191         ERRORSTATE_SET_GL_ERROR(
192             error_state, GL_INVALID_OPERATION, function_name,
193             (std::string(
194                  "attempt to access out of range vertices in attribute ") +
195              base::IntToString(attrib->index())).c_str());
196         return false;
197       }
198       if (use_client_side_arrays_for_stream_buffers) {
199         Buffer* buffer = attrib->buffer();
200         glEnableVertexAttribArray(attrib->index());
201         if (buffer->IsClientSideArray()) {
202           if (current_buffer_id != 0) {
203             current_buffer_id = 0;
204             glBindBuffer(GL_ARRAY_BUFFER, 0);
205           }
206           attrib->set_is_client_side_array(true);
207           const void* ptr = buffer->GetRange(attrib->offset(), 0);
208           DCHECK(ptr);
209           glVertexAttribPointer(
210               attrib->index(),
211               attrib->size(),
212               attrib->type(),
213               attrib->normalized(),
214               attrib->gl_stride(),
215               ptr);
216         } else if (attrib->is_client_side_array()) {
217           attrib->set_is_client_side_array(false);
218           GLuint new_buffer_id = buffer->service_id();
219           if (new_buffer_id != current_buffer_id) {
220             current_buffer_id = new_buffer_id;
221             glBindBuffer(GL_ARRAY_BUFFER, current_buffer_id);
222           }
223           const void* ptr = reinterpret_cast<const void*>(attrib->offset());
224           glVertexAttribPointer(
225               attrib->index(),
226               attrib->size(),
227               attrib->type(),
228               attrib->normalized(),
229               attrib->gl_stride(),
230               ptr);
231         }
232       }
233     } else {
234       // This attrib is not used in the current program.
235       if (!attrib->buffer()) {
236         ERRORSTATE_SET_GL_ERROR(
237             error_state, GL_INVALID_OPERATION, function_name,
238             (std::string(
239                  "attempt to render with no buffer attached to "
240                  "enabled attribute ") +
241                  base::IntToString(attrib->index())).c_str());
242         return false;
243       } else if (use_client_side_arrays_for_stream_buffers) {
244         Buffer* buffer = attrib->buffer();
245         // Disable client side arrays for unused attributes else we'll
246         // read bad memory
247         if (buffer->IsClientSideArray()) {
248           // Don't disable attrib 0 since it's special.
249           if (attrib->index() > 0) {
250             glDisableVertexAttribArray(attrib->index());
251           }
252         }
253       }
254     }
255   }
256 
257   if (primcount && !divisor0) {
258     ERRORSTATE_SET_GL_ERROR(
259         error_state, GL_INVALID_OPERATION, function_name,
260         "attempt instanced render with all attributes having "
261         "non-zero divisors");
262     return false;
263   }
264 
265   if (current_buffer_id != kInitialBufferId) {
266     // Restore the buffer binding.
267     decoder->RestoreBufferBindings();
268   }
269 
270   return true;
271 }
272 
273 }  // namespace gles2
274 }  // namespace gpu
275