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/context_state.h"
6
7#include <cmath>
8
9#include "gpu/command_buffer/common/gles2_cmd_utils.h"
10#include "gpu/command_buffer/service/buffer_manager.h"
11#include "gpu/command_buffer/service/error_state.h"
12#include "gpu/command_buffer/service/framebuffer_manager.h"
13#include "gpu/command_buffer/service/program_manager.h"
14#include "gpu/command_buffer/service/renderbuffer_manager.h"
15#include "ui/gl/gl_bindings.h"
16#include "ui/gl/gl_implementation.h"
17
18namespace gpu {
19namespace gles2 {
20
21namespace {
22
23static void EnableDisable(GLenum pname, bool enable) {
24  if (enable) {
25    glEnable(pname);
26  } else {
27    glDisable(pname);
28  }
29}
30
31GLuint Get2dServiceId(const TextureUnit& unit) {
32  return unit.bound_texture_2d.get()
33      ? unit.bound_texture_2d->service_id() : 0;
34}
35
36GLuint GetCubeServiceId(const TextureUnit& unit) {
37  return unit.bound_texture_cube_map.get()
38      ? unit.bound_texture_cube_map->service_id() : 0;
39}
40
41GLuint GetOesServiceId(const TextureUnit& unit) {
42  return unit.bound_texture_external_oes.get()
43      ? unit.bound_texture_external_oes->service_id() : 0;
44}
45
46GLuint GetArbServiceId(const TextureUnit& unit) {
47  return unit.bound_texture_rectangle_arb.get()
48      ? unit.bound_texture_rectangle_arb->service_id() : 0;
49}
50
51GLuint GetServiceId(const TextureUnit& unit, GLuint target) {
52  switch (target) {
53    case GL_TEXTURE_2D:
54      return Get2dServiceId(unit);
55    case GL_TEXTURE_CUBE_MAP:
56      return GetCubeServiceId(unit);
57    case GL_TEXTURE_RECTANGLE_ARB:
58      return GetArbServiceId(unit);
59    case GL_TEXTURE_EXTERNAL_OES:
60      return GetOesServiceId(unit);
61    default:
62      NOTREACHED();
63      return 0;
64  }
65}
66
67bool TargetIsSupported(const FeatureInfo* feature_info, GLuint target) {
68  switch (target) {
69    case GL_TEXTURE_2D:
70      return true;
71    case GL_TEXTURE_CUBE_MAP:
72      return true;
73    case GL_TEXTURE_RECTANGLE_ARB:
74      return feature_info->feature_flags().arb_texture_rectangle;
75    case GL_TEXTURE_EXTERNAL_OES:
76      return feature_info->feature_flags().oes_egl_image_external;
77    default:
78      NOTREACHED();
79      return false;
80  }
81}
82
83}  // anonymous namespace.
84
85TextureUnit::TextureUnit()
86    : bind_target(GL_TEXTURE_2D) {
87}
88
89TextureUnit::~TextureUnit() {
90}
91
92ContextState::ContextState(FeatureInfo* feature_info,
93                           ErrorStateClient* error_state_client,
94                           Logger* logger)
95    : active_texture_unit(0),
96      bound_renderbuffer_valid(false),
97      pack_reverse_row_order(false),
98      ignore_cached_state(false),
99      fbo_binding_for_scissor_workaround_dirty_(false),
100      feature_info_(feature_info),
101      error_state_(ErrorState::Create(error_state_client, logger)) {
102  Initialize();
103}
104
105ContextState::~ContextState() {
106}
107
108void ContextState::RestoreTextureUnitBindings(
109    GLuint unit, const ContextState* prev_state) const {
110  DCHECK_LT(unit, texture_units.size());
111  const TextureUnit& texture_unit = texture_units[unit];
112  GLuint service_id_2d = Get2dServiceId(texture_unit);
113  GLuint service_id_cube = GetCubeServiceId(texture_unit);
114  GLuint service_id_oes = GetOesServiceId(texture_unit);
115  GLuint service_id_arb = GetArbServiceId(texture_unit);
116
117  bool bind_texture_2d = true;
118  bool bind_texture_cube = true;
119  bool bind_texture_oes = feature_info_->feature_flags().oes_egl_image_external;
120  bool bind_texture_arb = feature_info_->feature_flags().arb_texture_rectangle;
121
122  if (prev_state) {
123    const TextureUnit& prev_unit = prev_state->texture_units[unit];
124    bind_texture_2d = service_id_2d != Get2dServiceId(prev_unit);
125    bind_texture_cube = service_id_cube != GetCubeServiceId(prev_unit);
126    bind_texture_oes =
127        bind_texture_oes && service_id_oes != GetOesServiceId(prev_unit);
128    bind_texture_arb =
129        bind_texture_arb && service_id_arb != GetArbServiceId(prev_unit);
130  }
131
132  // Early-out if nothing has changed from the previous state.
133  if (!bind_texture_2d && !bind_texture_cube
134      && !bind_texture_oes && !bind_texture_arb) {
135    return;
136  }
137
138  glActiveTexture(GL_TEXTURE0 + unit);
139  if (bind_texture_2d) {
140    glBindTexture(GL_TEXTURE_2D, service_id_2d);
141  }
142  if (bind_texture_cube) {
143    glBindTexture(GL_TEXTURE_CUBE_MAP, service_id_cube);
144  }
145  if (bind_texture_oes) {
146    glBindTexture(GL_TEXTURE_EXTERNAL_OES, service_id_oes);
147  }
148  if (bind_texture_arb) {
149    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, service_id_arb);
150  }
151}
152
153void ContextState::RestoreBufferBindings() const {
154  if (vertex_attrib_manager.get()) {
155    Buffer* element_array_buffer =
156        vertex_attrib_manager->element_array_buffer();
157    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
158        element_array_buffer ? element_array_buffer->service_id() : 0);
159  }
160  glBindBuffer(GL_ARRAY_BUFFER,
161               bound_array_buffer.get() ? bound_array_buffer->service_id() : 0);
162}
163
164void ContextState::RestoreRenderbufferBindings() {
165  // Require Renderbuffer rebind.
166  bound_renderbuffer_valid = false;
167}
168
169void ContextState::RestoreProgramBindings() const {
170  glUseProgram(current_program.get() ? current_program->service_id() : 0);
171}
172
173void ContextState::RestoreActiveTexture() const {
174  glActiveTexture(GL_TEXTURE0 + active_texture_unit);
175}
176
177void ContextState::RestoreAllTextureUnitBindings(
178    const ContextState* prev_state) const {
179  // Restore Texture state.
180  for (size_t ii = 0; ii < texture_units.size(); ++ii) {
181    RestoreTextureUnitBindings(ii, prev_state);
182  }
183  RestoreActiveTexture();
184}
185
186void ContextState::RestoreActiveTextureUnitBinding(unsigned int target) const {
187  DCHECK_LT(active_texture_unit, texture_units.size());
188  const TextureUnit& texture_unit = texture_units[active_texture_unit];
189  if (TargetIsSupported(feature_info_, target))
190    glBindTexture(target, GetServiceId(texture_unit, target));
191}
192
193void ContextState::RestoreVertexAttribValues() const {
194  for (size_t attrib = 0; attrib < vertex_attrib_manager->num_attribs();
195       ++attrib) {
196    glVertexAttrib4fv(attrib, attrib_values[attrib].v);
197  }
198}
199
200void ContextState::RestoreVertexAttribArrays(
201    const scoped_refptr<VertexAttribManager> attrib_manager) const {
202  // This is expected to be called only for VAO with service_id 0,
203  // either to restore the default VAO or a virtual VAO with service_id 0.
204  GLuint vao_service_id = attrib_manager->service_id();
205  DCHECK(vao_service_id == 0);
206
207  // Bind VAO if supported.
208  if (feature_info_->feature_flags().native_vertex_array_object)
209    glBindVertexArrayOES(vao_service_id);
210
211  // Restore vertex attrib arrays.
212  for (size_t attrib_index = 0; attrib_index < attrib_manager->num_attribs();
213       ++attrib_index) {
214    const VertexAttrib* attrib = attrib_manager->GetVertexAttrib(attrib_index);
215
216    // Restore vertex array.
217    Buffer* buffer = attrib->buffer();
218    GLuint buffer_service_id = buffer ? buffer->service_id() : 0;
219    glBindBuffer(GL_ARRAY_BUFFER, buffer_service_id);
220    const void* ptr = reinterpret_cast<const void*>(attrib->offset());
221    glVertexAttribPointer(attrib_index,
222                          attrib->size(),
223                          attrib->type(),
224                          attrib->normalized(),
225                          attrib->gl_stride(),
226                          ptr);
227
228    // Restore attrib divisor if supported.
229    if (feature_info_->feature_flags().angle_instanced_arrays)
230      glVertexAttribDivisorANGLE(attrib_index, attrib->divisor());
231
232    // Never touch vertex attribute 0's state (in particular, never
233    // disable it) when running on desktop GL because it will never be
234    // re-enabled.
235    if (attrib_index != 0 ||
236        gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
237      if (attrib->enabled()) {
238        glEnableVertexAttribArray(attrib_index);
239      } else {
240        glDisableVertexAttribArray(attrib_index);
241      }
242    }
243  }
244}
245
246void ContextState::RestoreVertexAttribs() const {
247  // Restore Vertex Attrib Arrays
248  // TODO: This if should not be needed. RestoreState is getting called
249  // before GLES2Decoder::Initialize which is a bug.
250  if (vertex_attrib_manager.get()) {
251    // Restore VAOs.
252    if (feature_info_->feature_flags().native_vertex_array_object) {
253      // If default VAO is still using shared id 0 instead of unique ids
254      // per-context, default VAO state must be restored.
255      GLuint default_vao_service_id =
256          default_vertex_attrib_manager->service_id();
257      if (default_vao_service_id == 0)
258        RestoreVertexAttribArrays(default_vertex_attrib_manager);
259
260      // Restore the current VAO binding, unless it's the same as the
261      // default above.
262      GLuint curr_vao_service_id = vertex_attrib_manager->service_id();
263      if (curr_vao_service_id != 0)
264        glBindVertexArrayOES(curr_vao_service_id);
265    } else {
266      // If native VAO isn't supported, emulated VAOs are used.
267      // Restore to the currently bound VAO.
268      RestoreVertexAttribArrays(vertex_attrib_manager);
269    }
270  }
271
272  // glVertexAttrib4fv aren't part of VAO state and must be restored.
273  RestoreVertexAttribValues();
274}
275
276void ContextState::RestoreGlobalState(const ContextState* prev_state) const {
277  InitCapabilities(prev_state);
278  InitState(prev_state);
279}
280
281void ContextState::RestoreState(const ContextState* prev_state) {
282  RestoreAllTextureUnitBindings(prev_state);
283  RestoreVertexAttribs();
284  RestoreBufferBindings();
285  RestoreRenderbufferBindings();
286  RestoreProgramBindings();
287  RestoreGlobalState(prev_state);
288}
289
290ErrorState* ContextState::GetErrorState() {
291  return error_state_.get();
292}
293
294// Include the auto-generated part of this file. We split this because it means
295// we can easily edit the non-auto generated parts right here in this file
296// instead of having to edit some template or the code generator.
297#include "gpu/command_buffer/service/context_state_impl_autogen.h"
298
299}  // namespace gles2
300}  // namespace gpu
301
302
303