Handle account removal correctly on all platforms.
[chromium-blink-merge.git] / gpu / command_buffer / service / vertex_attrib_manager.cc
blob8725c4f9533c5ce75b5205f92a7ef404184dd8b4
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 is_client_side_array_(false),
39 list_(NULL) {
42 VertexAttrib::~VertexAttrib() {
45 void VertexAttrib::SetInfo(
46 Buffer* buffer,
47 GLint size,
48 GLenum type,
49 GLboolean normalized,
50 GLsizei gl_stride,
51 GLsizei real_stride,
52 GLsizei offset) {
53 DCHECK_GT(real_stride, 0);
54 buffer_ = buffer;
55 size_ = size;
56 type_ = type;
57 normalized_ = normalized;
58 gl_stride_ = gl_stride;
59 real_stride_ = real_stride;
60 offset_ = offset;
63 void VertexAttrib::Unbind(Buffer* buffer) {
64 if (buffer_.get() == buffer) {
65 buffer_ = NULL;
69 bool VertexAttrib::CanAccess(GLuint index) const {
70 if (!enabled_) {
71 return true;
74 if (!buffer_.get() || buffer_->IsDeleted()) {
75 return false;
78 // The number of elements that can be accessed.
79 GLsizeiptr buffer_size = buffer_->size();
80 if (offset_ > buffer_size || real_stride_ == 0) {
81 return false;
84 uint32 usable_size = buffer_size - offset_;
85 GLuint num_elements = usable_size / real_stride_ +
86 ((usable_size % real_stride_) >=
87 (GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type_) * size_) ? 1 : 0);
88 return index < num_elements;
91 VertexAttribManager::VertexAttribManager()
92 : num_fixed_attribs_(0),
93 element_array_buffer_(NULL),
94 manager_(NULL),
95 deleted_(false),
96 service_id_(0) {
99 VertexAttribManager::VertexAttribManager(
100 VertexArrayManager* manager, GLuint service_id, uint32 num_vertex_attribs)
101 : num_fixed_attribs_(0),
102 element_array_buffer_(NULL),
103 manager_(manager),
104 deleted_(false),
105 service_id_(service_id) {
106 manager_->StartTracking(this);
107 Initialize(num_vertex_attribs, false);
110 VertexAttribManager::~VertexAttribManager() {
111 if (manager_) {
112 if (manager_->have_context_) {
113 if (service_id_ != 0) // 0 indicates an emulated VAO
114 glDeleteVertexArraysOES(1, &service_id_);
116 manager_->StopTracking(this);
117 manager_ = NULL;
121 void VertexAttribManager::Initialize(
122 uint32 max_vertex_attribs, bool init_attribs) {
123 vertex_attribs_.resize(max_vertex_attribs);
125 for (uint32 vv = 0; vv < vertex_attribs_.size(); ++vv) {
126 vertex_attribs_[vv].set_index(vv);
127 vertex_attribs_[vv].SetList(&disabled_vertex_attribs_);
129 if (init_attribs) {
130 glVertexAttrib4f(vv, 0.0f, 0.0f, 0.0f, 1.0f);
135 void VertexAttribManager::SetElementArrayBuffer(Buffer* buffer) {
136 element_array_buffer_ = buffer;
139 bool VertexAttribManager::Enable(GLuint index, bool enable) {
140 if (index >= vertex_attribs_.size()) {
141 return false;
143 VertexAttrib& info = vertex_attribs_[index];
144 if (info.enabled() != enable) {
145 info.set_enabled(enable);
146 info.SetList(enable ? &enabled_vertex_attribs_ : &disabled_vertex_attribs_);
148 return true;
151 void VertexAttribManager::Unbind(Buffer* buffer) {
152 if (element_array_buffer_.get() == buffer) {
153 element_array_buffer_ = NULL;
155 for (uint32 vv = 0; vv < vertex_attribs_.size(); ++vv) {
156 vertex_attribs_[vv].Unbind(buffer);
160 bool VertexAttribManager::ValidateBindings(
161 const char* function_name,
162 GLES2Decoder* decoder,
163 FeatureInfo* feature_info,
164 Program* current_program,
165 GLuint max_vertex_accessed,
166 bool instanced,
167 GLsizei primcount) {
168 DCHECK(primcount);
169 ErrorState* error_state = decoder->GetErrorState();
170 // true if any enabled, used divisor is zero
171 bool divisor0 = false;
172 bool have_enabled_active_attribs = 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 have_enabled_active_attribs = true;
189 GLuint count = attrib->MaxVertexAccessed(primcount, max_vertex_accessed);
190 // This attrib is used in the current program.
191 if (!attrib->CanAccess(count)) {
192 ERRORSTATE_SET_GL_ERROR(
193 error_state, GL_INVALID_OPERATION, function_name,
194 (std::string(
195 "attempt to access out of range vertices in attribute ") +
196 base::IntToString(attrib->index())).c_str());
197 return false;
199 if (use_client_side_arrays_for_stream_buffers) {
200 Buffer* buffer = attrib->buffer();
201 glEnableVertexAttribArray(attrib->index());
202 if (buffer->IsClientSideArray()) {
203 if (current_buffer_id != 0) {
204 current_buffer_id = 0;
205 glBindBuffer(GL_ARRAY_BUFFER, 0);
207 attrib->set_is_client_side_array(true);
208 const void* ptr = buffer->GetRange(attrib->offset(), 0);
209 DCHECK(ptr);
210 glVertexAttribPointer(
211 attrib->index(),
212 attrib->size(),
213 attrib->type(),
214 attrib->normalized(),
215 attrib->gl_stride(),
216 ptr);
217 } else if (attrib->is_client_side_array()) {
218 attrib->set_is_client_side_array(false);
219 GLuint new_buffer_id = buffer->service_id();
220 if (new_buffer_id != current_buffer_id) {
221 current_buffer_id = new_buffer_id;
222 glBindBuffer(GL_ARRAY_BUFFER, current_buffer_id);
224 const void* ptr = reinterpret_cast<const void*>(attrib->offset());
225 glVertexAttribPointer(
226 attrib->index(),
227 attrib->size(),
228 attrib->type(),
229 attrib->normalized(),
230 attrib->gl_stride(),
231 ptr);
234 } else {
235 // This attrib is not used in the current program.
236 if (!attrib->buffer()) {
237 ERRORSTATE_SET_GL_ERROR(
238 error_state, GL_INVALID_OPERATION, function_name,
239 (std::string(
240 "attempt to render with no buffer attached to "
241 "enabled attribute ") +
242 base::IntToString(attrib->index())).c_str());
243 return false;
244 } else if (use_client_side_arrays_for_stream_buffers) {
245 Buffer* buffer = attrib->buffer();
246 // Disable client side arrays for unused attributes else we'll
247 // read bad memory
248 if (buffer->IsClientSideArray()) {
249 // Don't disable attrib 0 since it's special.
250 if (attrib->index() > 0) {
251 glDisableVertexAttribArray(attrib->index());
258 // Instanced drawing needs at least one enabled attribute with divisor zero.
259 // Non-instanced drawing is fine with having no attributes at all, but if
260 // there are attributes, at least one should have divisor zero.
261 // (See ANGLE_instanced_arrays spec)
262 if (!divisor0 && (instanced || have_enabled_active_attribs)) {
263 ERRORSTATE_SET_GL_ERROR(
264 error_state, GL_INVALID_OPERATION, function_name,
265 "attempt to draw with all attributes having non-zero divisors");
266 return false;
269 if (current_buffer_id != kInitialBufferId) {
270 // Restore the buffer binding.
271 decoder->RestoreBufferBindings();
274 return true;
277 } // namespace gles2
278 } // namespace gpu