Elim cr-checkbox
[chromium-blink-merge.git] / gpu / command_buffer / service / vertex_attrib_manager.cc
blob7d2752fe00d05ec035793847bb347a1218c8c408
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.
5 #include "gpu/command_buffer/service/vertex_attrib_manager.h"
7 #include <list>
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "build/build_config.h"
13 #define GLES2_GPU_SERVICE 1
14 #include "gpu/command_buffer/common/gles2_cmd_format.h"
15 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
16 #include "gpu/command_buffer/service/buffer_manager.h"
17 #include "gpu/command_buffer/service/error_state.h"
18 #include "gpu/command_buffer/service/feature_info.h"
19 #include "gpu/command_buffer/service/gl_utils.h"
20 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
21 #include "gpu/command_buffer/service/gpu_switches.h"
22 #include "gpu/command_buffer/service/program_manager.h"
23 #include "gpu/command_buffer/service/vertex_array_manager.h"
25 namespace gpu {
26 namespace gles2 {
28 VertexAttrib::VertexAttrib()
29 : index_(0),
30 enabled_(false),
31 size_(4),
32 type_(GL_FLOAT),
33 offset_(0),
34 normalized_(GL_FALSE),
35 gl_stride_(0),
36 real_stride_(16),
37 divisor_(0),
38 integer_(GL_FALSE),
39 is_client_side_array_(false),
40 list_(NULL) {
43 VertexAttrib::~VertexAttrib() {
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 GLboolean integer) {
55 DCHECK_GT(real_stride, 0);
56 buffer_ = buffer;
57 size_ = size;
58 type_ = type;
59 normalized_ = normalized;
60 gl_stride_ = gl_stride;
61 real_stride_ = real_stride;
62 offset_ = offset;
63 integer_ = integer;
66 void VertexAttrib::Unbind(Buffer* buffer) {
67 if (buffer_.get() == buffer) {
68 buffer_ = NULL;
72 bool VertexAttrib::CanAccess(GLuint index) const {
73 if (!enabled_) {
74 return true;
77 if (!buffer_.get() || buffer_->IsDeleted()) {
78 return false;
81 // The number of elements that can be accessed.
82 GLsizeiptr buffer_size = buffer_->size();
83 if (offset_ > buffer_size || real_stride_ == 0) {
84 return false;
87 uint32 usable_size = buffer_size - offset_;
88 GLuint num_elements = usable_size / real_stride_ +
89 ((usable_size % real_stride_) >=
90 (GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type_) * size_) ? 1 : 0);
91 return index < num_elements;
94 VertexAttribManager::VertexAttribManager()
95 : num_fixed_attribs_(0),
96 element_array_buffer_(NULL),
97 manager_(NULL),
98 deleted_(false),
99 service_id_(0) {
102 VertexAttribManager::VertexAttribManager(
103 VertexArrayManager* manager, GLuint service_id, uint32 num_vertex_attribs)
104 : num_fixed_attribs_(0),
105 element_array_buffer_(NULL),
106 manager_(manager),
107 deleted_(false),
108 service_id_(service_id) {
109 manager_->StartTracking(this);
110 Initialize(num_vertex_attribs, false);
113 VertexAttribManager::~VertexAttribManager() {
114 if (manager_) {
115 if (manager_->have_context_) {
116 if (service_id_ != 0) // 0 indicates an emulated VAO
117 glDeleteVertexArraysOES(1, &service_id_);
119 manager_->StopTracking(this);
120 manager_ = NULL;
124 void VertexAttribManager::Initialize(
125 uint32 max_vertex_attribs, bool init_attribs) {
126 vertex_attribs_.resize(max_vertex_attribs);
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_);
132 if (init_attribs) {
133 glVertexAttrib4f(vv, 0.0f, 0.0f, 0.0f, 1.0f);
138 void VertexAttribManager::SetElementArrayBuffer(Buffer* buffer) {
139 element_array_buffer_ = buffer;
142 bool VertexAttribManager::Enable(GLuint index, bool enable) {
143 if (index >= vertex_attribs_.size()) {
144 return false;
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_);
151 return true;
154 void VertexAttribManager::Unbind(Buffer* buffer) {
155 if (element_array_buffer_.get() == buffer) {
156 element_array_buffer_ = NULL;
158 for (uint32 vv = 0; vv < vertex_attribs_.size(); ++vv) {
159 vertex_attribs_[vv].Unbind(buffer);
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 bool instanced,
170 GLsizei primcount) {
171 DCHECK(primcount);
172 ErrorState* error_state = decoder->GetErrorState();
173 // true if any enabled, used divisor is zero
174 bool divisor0 = false;
175 bool have_enabled_active_attribs = false;
176 const GLuint kInitialBufferId = 0xFFFFFFFFU;
177 GLuint current_buffer_id = kInitialBufferId;
178 bool use_client_side_arrays_for_stream_buffers = feature_info->workarounds(
179 ).use_client_side_arrays_for_stream_buffers;
180 // Validate all attribs currently enabled. If they are used by the current
181 // program then check that they have enough elements to handle the draw call.
182 // If they are not used by the current program check that they have a buffer
183 // assigned.
184 for (VertexAttribList::iterator it = enabled_vertex_attribs_.begin();
185 it != enabled_vertex_attribs_.end(); ++it) {
186 VertexAttrib* attrib = *it;
187 const Program::VertexAttrib* attrib_info =
188 current_program->GetAttribInfoByLocation(attrib->index());
189 if (attrib_info) {
190 divisor0 |= (attrib->divisor() == 0);
191 have_enabled_active_attribs = true;
192 GLuint count = attrib->MaxVertexAccessed(primcount, max_vertex_accessed);
193 // This attrib is used in the current program.
194 if (!attrib->CanAccess(count)) {
195 ERRORSTATE_SET_GL_ERROR(
196 error_state, GL_INVALID_OPERATION, function_name,
197 (std::string(
198 "attempt to access out of range vertices in attribute ") +
199 base::UintToString(attrib->index())).c_str());
200 return false;
202 if (use_client_side_arrays_for_stream_buffers) {
203 Buffer* buffer = attrib->buffer();
204 glEnableVertexAttribArray(attrib->index());
205 if (buffer->IsClientSideArray()) {
206 if (current_buffer_id != 0) {
207 current_buffer_id = 0;
208 glBindBuffer(GL_ARRAY_BUFFER, 0);
210 attrib->set_is_client_side_array(true);
211 const void* ptr = buffer->GetRange(attrib->offset(), 0);
212 DCHECK(ptr);
213 glVertexAttribPointer(
214 attrib->index(),
215 attrib->size(),
216 attrib->type(),
217 attrib->normalized(),
218 attrib->gl_stride(),
219 ptr);
220 } else if (attrib->is_client_side_array()) {
221 attrib->set_is_client_side_array(false);
222 GLuint new_buffer_id = buffer->service_id();
223 if (new_buffer_id != current_buffer_id) {
224 current_buffer_id = new_buffer_id;
225 glBindBuffer(GL_ARRAY_BUFFER, current_buffer_id);
227 const void* ptr = reinterpret_cast<const void*>(attrib->offset());
228 glVertexAttribPointer(
229 attrib->index(),
230 attrib->size(),
231 attrib->type(),
232 attrib->normalized(),
233 attrib->gl_stride(),
234 ptr);
237 } else {
238 // This attrib is not used in the current program.
239 if (!attrib->buffer()) {
240 ERRORSTATE_SET_GL_ERROR(
241 error_state, GL_INVALID_OPERATION, function_name,
242 (std::string(
243 "attempt to render with no buffer attached to "
244 "enabled attribute ") +
245 base::UintToString(attrib->index())).c_str());
246 return false;
247 } else if (use_client_side_arrays_for_stream_buffers) {
248 Buffer* buffer = attrib->buffer();
249 // Disable client side arrays for unused attributes else we'll
250 // read bad memory
251 if (buffer->IsClientSideArray()) {
252 // Don't disable attrib 0 since it's special.
253 if (attrib->index() > 0) {
254 glDisableVertexAttribArray(attrib->index());
261 // Instanced drawing needs at least one enabled attribute with divisor zero.
262 // Non-instanced drawing is fine with having no attributes at all, but if
263 // there are attributes, at least one should have divisor zero.
264 // (See ANGLE_instanced_arrays spec)
265 if (!divisor0 && (instanced || have_enabled_active_attribs)) {
266 ERRORSTATE_SET_GL_ERROR(
267 error_state, GL_INVALID_OPERATION, function_name,
268 "attempt to draw with all attributes having non-zero divisors");
269 return false;
272 if (current_buffer_id != kInitialBufferId) {
273 // Restore the buffer binding.
274 decoder->RestoreBufferBindings();
277 return true;
280 } // namespace gles2
281 } // namespace gpu