blob: 7501a1ec0be635c2e3888dc8e7e0928780466fac [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/service/context_state.h"
#include <stddef.h>
#include <cmath>
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "gpu/command_buffer/service/buffer_manager.h"
#include "gpu/command_buffer/service/error_state.h"
#include "gpu/command_buffer/service/framebuffer_manager.h"
#include "gpu/command_buffer/service/program_manager.h"
#include "gpu/command_buffer/service/renderbuffer_manager.h"
#include "gpu/command_buffer/service/transform_feedback_manager.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_version_info.h"
namespace gpu {
namespace gles2 {
namespace {
GLuint Get2dServiceId(const TextureUnit& unit) {
return unit.bound_texture_2d.get() ? unit.bound_texture_2d->service_id() : 0;
}
GLuint Get2dArrayServiceId(const TextureUnit& unit) {
return unit.bound_texture_2d_array.get()
? unit.bound_texture_2d_array->service_id()
: 0;
}
GLuint Get3dServiceId(const TextureUnit& unit) {
return unit.bound_texture_3d.get() ? unit.bound_texture_3d->service_id() : 0;
}
GLuint GetCubeServiceId(const TextureUnit& unit) {
return unit.bound_texture_cube_map.get()
? unit.bound_texture_cube_map->service_id()
: 0;
}
GLuint GetOesServiceId(const TextureUnit& unit) {
return unit.bound_texture_external_oes.get()
? unit.bound_texture_external_oes->service_id()
: 0;
}
GLuint GetArbServiceId(const TextureUnit& unit) {
return unit.bound_texture_rectangle_arb.get()
? unit.bound_texture_rectangle_arb->service_id()
: 0;
}
GLuint GetServiceId(const TextureUnit& unit, GLuint target) {
switch (target) {
case GL_TEXTURE_2D:
return Get2dServiceId(unit);
case GL_TEXTURE_CUBE_MAP:
return GetCubeServiceId(unit);
case GL_TEXTURE_RECTANGLE_ARB:
return GetArbServiceId(unit);
case GL_TEXTURE_EXTERNAL_OES:
return GetOesServiceId(unit);
default:
NOTREACHED();
return 0;
}
}
bool TargetIsSupported(const FeatureInfo* feature_info, GLuint target) {
switch (target) {
case GL_TEXTURE_2D:
return true;
case GL_TEXTURE_CUBE_MAP:
return true;
case GL_TEXTURE_RECTANGLE_ARB:
return feature_info->feature_flags().arb_texture_rectangle;
case GL_TEXTURE_EXTERNAL_OES:
return feature_info->feature_flags().oes_egl_image_external ||
feature_info->feature_flags().nv_egl_stream_consumer_external;
default:
NOTREACHED();
return false;
}
}
GLuint GetBufferId(const Buffer* buffer) {
if (buffer)
return buffer->service_id();
return 0;
}
} // anonymous namespace.
TextureUnit::TextureUnit() : bind_target(GL_TEXTURE_2D) {}
TextureUnit::TextureUnit(const TextureUnit& other) = default;
TextureUnit::~TextureUnit() = default;
bool Vec4::Equal(const Vec4& other) const {
if (type_ != other.type_)
return false;
switch (type_) {
case SHADER_VARIABLE_FLOAT:
for (size_t ii = 0; ii < 4; ++ii) {
if (v_[ii].float_value != other.v_[ii].float_value)
return false;
}
break;
case SHADER_VARIABLE_INT:
for (size_t ii = 0; ii < 4; ++ii) {
if (v_[ii].int_value != other.v_[ii].int_value)
return false;
}
break;
case SHADER_VARIABLE_UINT:
for (size_t ii = 0; ii < 4; ++ii) {
if (v_[ii].uint_value != other.v_[ii].uint_value)
return false;
}
break;
default:
NOTREACHED();
break;
}
return true;
}
template <>
void Vec4::GetValues<GLfloat>(GLfloat* values) const {
DCHECK(values);
switch (type_) {
case SHADER_VARIABLE_FLOAT:
for (size_t ii = 0; ii < 4; ++ii)
values[ii] = v_[ii].float_value;
break;
case SHADER_VARIABLE_INT:
for (size_t ii = 0; ii < 4; ++ii)
values[ii] = static_cast<GLfloat>(v_[ii].int_value);
break;
case SHADER_VARIABLE_UINT:
for (size_t ii = 0; ii < 4; ++ii)
values[ii] = static_cast<GLfloat>(v_[ii].uint_value);
break;
default:
NOTREACHED();
break;
}
}
template <>
void Vec4::GetValues<GLint>(GLint* values) const {
DCHECK(values);
switch (type_) {
case SHADER_VARIABLE_FLOAT:
for (size_t ii = 0; ii < 4; ++ii)
values[ii] = static_cast<GLint>(v_[ii].float_value);
break;
case SHADER_VARIABLE_INT:
for (size_t ii = 0; ii < 4; ++ii)
values[ii] = v_[ii].int_value;
break;
case SHADER_VARIABLE_UINT:
for (size_t ii = 0; ii < 4; ++ii)
values[ii] = static_cast<GLint>(v_[ii].uint_value);
break;
default:
NOTREACHED();
break;
}
}
template <>
void Vec4::GetValues<GLuint>(GLuint* values) const {
DCHECK(values);
switch (type_) {
case SHADER_VARIABLE_FLOAT:
for (size_t ii = 0; ii < 4; ++ii)
values[ii] = static_cast<GLuint>(v_[ii].float_value);
break;
case SHADER_VARIABLE_INT:
for (size_t ii = 0; ii < 4; ++ii)
values[ii] = static_cast<GLuint>(v_[ii].int_value);
break;
case SHADER_VARIABLE_UINT:
for (size_t ii = 0; ii < 4; ++ii)
values[ii] = v_[ii].uint_value;
break;
default:
NOTREACHED();
break;
}
}
template <>
void Vec4::SetValues<GLfloat>(const GLfloat* values) {
DCHECK(values);
for (size_t ii = 0; ii < 4; ++ii)
v_[ii].float_value = values[ii];
type_ = SHADER_VARIABLE_FLOAT;
}
template <>
void Vec4::SetValues<GLint>(const GLint* values) {
DCHECK(values);
for (size_t ii = 0; ii < 4; ++ii)
v_[ii].int_value = values[ii];
type_ = SHADER_VARIABLE_INT;
}
template <>
void Vec4::SetValues<GLuint>(const GLuint* values) {
DCHECK(values);
for (size_t ii = 0; ii < 4; ++ii)
v_[ii].uint_value = values[ii];
type_ = SHADER_VARIABLE_UINT;
}
ContextState::ContextState(FeatureInfo* feature_info,
ErrorStateClient* error_state_client,
Logger* logger,
bool track_texture_and_sampler_units)
: track_texture_and_sampler_units(track_texture_and_sampler_units),
feature_info_(feature_info),
error_state_(ErrorState::Create(error_state_client, logger)) {
Initialize();
}
ContextState::~ContextState() = default;
void ContextState::SetLineWidthBounds(GLfloat min, GLfloat max) {
line_width_min_ = min;
line_width_max_ = max;
}
void ContextState::RestoreTextureUnitBindings(
GLuint unit,
const ContextState* prev_state) const {
DCHECK(unit < texture_units.size() ||
(unit == 0 && !track_texture_and_sampler_units));
GLuint service_id_2d = 0u;
GLuint service_id_2d_array = 0u;
GLuint service_id_3d = 0u;
GLuint service_id_cube = 0u;
GLuint service_id_oes = 0u;
GLuint service_id_arb = 0u;
if (track_texture_and_sampler_units) {
const TextureUnit& texture_unit = texture_units[unit];
service_id_2d = Get2dServiceId(texture_unit);
service_id_2d_array = Get2dArrayServiceId(texture_unit);
service_id_3d = Get3dServiceId(texture_unit);
service_id_cube = GetCubeServiceId(texture_unit);
service_id_oes = GetOesServiceId(texture_unit);
service_id_arb = GetArbServiceId(texture_unit);
}
bool bind_texture_2d = true;
bool bind_texture_cube = true;
bool bind_texture_oes =
feature_info_->feature_flags().oes_egl_image_external ||
feature_info_->feature_flags().nv_egl_stream_consumer_external;
bool bind_texture_arb = feature_info_->feature_flags().arb_texture_rectangle;
// TEXTURE_2D_ARRAY and TEXTURE_3D are only applicable from ES3 version.
// So set it to FALSE by default.
bool bind_texture_2d_array = false;
bool bind_texture_3d = false;
// set the variables to true only if the application is ES3 or newer
if (feature_info_->IsES3Capable()) {
bind_texture_2d_array = true;
bind_texture_3d = true;
}
if (prev_state) {
if (prev_state->track_texture_and_sampler_units) {
const TextureUnit& prev_unit = prev_state->texture_units[unit];
bind_texture_2d = service_id_2d != Get2dServiceId(prev_unit);
bind_texture_2d_array =
bind_texture_2d_array &&
service_id_2d_array != Get2dArrayServiceId(prev_unit);
bind_texture_3d =
bind_texture_3d && service_id_3d != Get3dServiceId(prev_unit);
bind_texture_cube = service_id_cube != GetCubeServiceId(prev_unit);
bind_texture_oes =
bind_texture_oes && service_id_oes != GetOesServiceId(prev_unit);
bind_texture_arb =
bind_texture_arb && service_id_arb != GetArbServiceId(prev_unit);
} else if (prev_state->texture_units_in_ground_state) {
bind_texture_2d = service_id_2d;
bind_texture_2d_array = bind_texture_2d_array && service_id_2d_array;
bind_texture_3d = bind_texture_3d && service_id_3d;
bind_texture_cube = service_id_cube;
bind_texture_oes = bind_texture_oes && service_id_oes;
bind_texture_arb = bind_texture_arb && service_id_arb;
} else {
// We need bind all restore target binding, if texture units is not in
// ground state.
}
}
// Early-out if nothing has changed from the previous state.
if (!bind_texture_2d && !bind_texture_2d_array && !bind_texture_3d &&
!bind_texture_cube && !bind_texture_oes && !bind_texture_arb) {
return;
}
api()->glActiveTextureFn(GL_TEXTURE0 + unit);
if (bind_texture_2d) {
api()->glBindTextureFn(GL_TEXTURE_2D, service_id_2d);
}
if (bind_texture_cube) {
api()->glBindTextureFn(GL_TEXTURE_CUBE_MAP, service_id_cube);
}
if (bind_texture_oes) {
api()->glBindTextureFn(GL_TEXTURE_EXTERNAL_OES, service_id_oes);
}
if (bind_texture_arb) {
api()->glBindTextureFn(GL_TEXTURE_RECTANGLE_ARB, service_id_arb);
}
if (bind_texture_2d_array) {
api()->glBindTextureFn(GL_TEXTURE_2D_ARRAY, service_id_2d_array);
}
if (bind_texture_3d) {
api()->glBindTextureFn(GL_TEXTURE_3D, service_id_3d);
}
} // namespace gles2
void ContextState::RestoreSamplerBinding(GLuint unit,
const ContextState* prev_state) const {
if (!feature_info_->IsES3Capable())
return;
const scoped_refptr<Sampler>& cur_sampler = sampler_units[unit];
GLuint cur_id = cur_sampler ? cur_sampler->service_id() : 0;
GLuint prev_id = 0;
if (prev_state && prev_state->track_texture_and_sampler_units) {
const scoped_refptr<Sampler>& prev_sampler =
prev_state->sampler_units[unit];
prev_id = prev_sampler ? prev_sampler->service_id() : 0;
}
if (!prev_state || !prev_state->sampler_units_in_ground_state ||
cur_id != prev_id) {
api()->glBindSamplerFn(unit, cur_id);
}
}
void ContextState::PushTextureUnpackState() const {
api()->glPixelStoreiFn(GL_UNPACK_ALIGNMENT, 1);
if (bound_pixel_unpack_buffer.get()) {
api()->glBindBufferFn(GL_PIXEL_UNPACK_BUFFER, 0);
api()->glPixelStoreiFn(GL_UNPACK_ROW_LENGTH, 0);
api()->glPixelStoreiFn(GL_UNPACK_IMAGE_HEIGHT, 0);
DCHECK_EQ(0, unpack_skip_pixels);
DCHECK_EQ(0, unpack_skip_rows);
DCHECK_EQ(0, unpack_skip_images);
}
}
void ContextState::RestoreUnpackState() const {
api()->glPixelStoreiFn(GL_UNPACK_ALIGNMENT, unpack_alignment);
if (bound_pixel_unpack_buffer.get()) {
api()->glBindBufferFn(GL_PIXEL_UNPACK_BUFFER,
GetBufferId(bound_pixel_unpack_buffer.get()));
api()->glPixelStoreiFn(GL_UNPACK_ROW_LENGTH, unpack_row_length);
api()->glPixelStoreiFn(GL_UNPACK_IMAGE_HEIGHT, unpack_image_height);
}
}
void ContextState::DoLineWidth(GLfloat width) const {
api()->glLineWidthFn(
std::min(std::max(width, line_width_min_), line_width_max_));
}
void ContextState::RestoreBufferBindings() const {
if (vertex_attrib_manager.get()) {
Buffer* element_array_buffer =
vertex_attrib_manager->element_array_buffer();
api()->glBindBufferFn(GL_ELEMENT_ARRAY_BUFFER,
GetBufferId(element_array_buffer));
}
api()->glBindBufferFn(GL_ARRAY_BUFFER, GetBufferId(bound_array_buffer.get()));
if (feature_info_->IsES3Capable()) {
api()->glBindBufferFn(GL_COPY_READ_BUFFER,
GetBufferId(bound_copy_read_buffer.get()));
api()->glBindBufferFn(GL_COPY_WRITE_BUFFER,
GetBufferId(bound_copy_write_buffer.get()));
api()->glBindBufferFn(GL_PIXEL_PACK_BUFFER,
GetBufferId(bound_pixel_pack_buffer.get()));
UpdatePackParameters();
api()->glBindBufferFn(GL_PIXEL_UNPACK_BUFFER,
GetBufferId(bound_pixel_unpack_buffer.get()));
UpdateUnpackParameters();
api()->glBindBufferFn(GL_TRANSFORM_FEEDBACK_BUFFER,
GetBufferId(bound_transform_feedback_buffer.get()));
api()->glBindBufferFn(GL_UNIFORM_BUFFER,
GetBufferId(bound_uniform_buffer.get()));
}
}
void ContextState::RestoreRenderbufferBindings() {
// Require Renderbuffer rebind.
bound_renderbuffer_valid = false;
}
void ContextState::RestoreProgramSettings(
const ContextState* prev_state,
bool restore_transform_feedback_bindings) const {
bool flag =
(restore_transform_feedback_bindings && feature_info_->IsES3Capable());
if (flag && prev_state) {
if (prev_state->bound_transform_feedback.get() &&
prev_state->bound_transform_feedback->active() &&
!prev_state->bound_transform_feedback->paused()) {
api()->glPauseTransformFeedbackFn();
}
}
api()->glUseProgramFn(current_program.get() ? current_program->service_id()
: 0);
if (flag) {
if (bound_transform_feedback.get()) {
bound_transform_feedback->DoBindTransformFeedback(
GL_TRANSFORM_FEEDBACK, bound_transform_feedback.get(),
bound_transform_feedback_buffer.get());
} else {
api()->glBindTransformFeedbackFn(GL_TRANSFORM_FEEDBACK, 0);
}
}
}
void ContextState::RestoreIndexedUniformBufferBindings(
const ContextState* prev_state) {
if (!feature_info_->IsES3Capable())
return;
indexed_uniform_buffer_bindings->RestoreBindings(
prev_state ? prev_state->indexed_uniform_buffer_bindings.get() : nullptr);
}
void ContextState::RestoreActiveTexture() const {
api()->glActiveTextureFn(GL_TEXTURE0 + active_texture_unit);
}
void ContextState::RestoreAllTextureUnitAndSamplerBindings(
const ContextState* prev_state) const {
if (!track_texture_and_sampler_units) {
if (prev_state) {
if (!prev_state->track_texture_and_sampler_units) {
texture_units_in_ground_state =
prev_state->texture_units_in_ground_state;
sampler_units_in_ground_state =
prev_state->sampler_units_in_ground_state;
return;
}
texture_units_in_ground_state = true;
for (size_t i = 1; i < prev_state->texture_units.size(); ++i) {
if (prev_state->texture_units[i].AnyTargetBound()) {
texture_units_in_ground_state = false;
break;
}
}
// If the current gl texture units are not in ground state, then we do
// need reset texture unit 0.
if (texture_units_in_ground_state)
RestoreTextureUnitBindings(0, prev_state);
sampler_units_in_ground_state = true;
for (auto& sampler : prev_state->sampler_units) {
if (sampler) {
sampler_units_in_ground_state = false;
break;
}
}
} else {
texture_units_in_ground_state = false;
sampler_units_in_ground_state = false;
}
} else {
// Restore Texture state.
for (size_t i = 0; i < texture_units.size(); ++i) {
RestoreTextureUnitBindings(i, prev_state);
RestoreSamplerBinding(i, prev_state);
}
RestoreActiveTexture();
}
}
void ContextState::RestoreActiveTextureUnitBinding(unsigned int target) const {
DCHECK(active_texture_unit < texture_units.size() ||
(active_texture_unit == 0 && !track_texture_and_sampler_units));
GLuint service_id = 0;
if (track_texture_and_sampler_units) {
const TextureUnit& texture_unit = texture_units[active_texture_unit];
service_id = GetServiceId(texture_unit, target);
}
if (TargetIsSupported(feature_info_, target))
api()->glBindTextureFn(target, service_id);
}
void ContextState::RestoreVertexAttribValues() const {
for (size_t attrib = 0; attrib < vertex_attrib_manager->num_attribs();
++attrib) {
switch (attrib_values[attrib].type()) {
case SHADER_VARIABLE_FLOAT: {
GLfloat v[4];
attrib_values[attrib].GetValues(v);
api()->glVertexAttrib4fvFn(attrib, v);
} break;
case SHADER_VARIABLE_INT: {
GLint v[4];
attrib_values[attrib].GetValues(v);
api()->glVertexAttribI4ivFn(attrib, v);
} break;
case SHADER_VARIABLE_UINT: {
GLuint v[4];
attrib_values[attrib].GetValues(v);
api()->glVertexAttribI4uivFn(attrib, v);
} break;
default:
NOTREACHED();
break;
}
}
}
void ContextState::RestoreVertexAttribArrays(
const scoped_refptr<VertexAttribManager> attrib_manager) const {
// This is expected to be called only for VAO with service_id 0,
// either to restore the default VAO or a virtual VAO with service_id 0.
GLuint vao_service_id = attrib_manager->service_id();
DCHECK(vao_service_id == 0);
// Bind VAO if supported.
if (feature_info_->feature_flags().native_vertex_array_object)
api()->glBindVertexArrayOESFn(vao_service_id);
// Restore vertex attrib arrays.
for (size_t attrib_index = 0; attrib_index < attrib_manager->num_attribs();
++attrib_index) {
const VertexAttrib* attrib = attrib_manager->GetVertexAttrib(attrib_index);
// Restore vertex array.
Buffer* buffer = attrib->buffer();
GLuint buffer_service_id = buffer ? buffer->service_id() : 0;
api()->glBindBufferFn(GL_ARRAY_BUFFER, buffer_service_id);
const void* ptr = reinterpret_cast<const void*>(attrib->offset());
api()->glVertexAttribPointerFn(attrib_index, attrib->size(), attrib->type(),
attrib->normalized(), attrib->gl_stride(),
ptr);
// Restore attrib divisor if supported.
if (feature_info_->feature_flags().angle_instanced_arrays)
api()->glVertexAttribDivisorANGLEFn(attrib_index, attrib->divisor());
if (attrib->enabled_in_driver()) {
api()->glEnableVertexAttribArrayFn(attrib_index);
} else {
api()->glDisableVertexAttribArrayFn(attrib_index);
}
}
}
void ContextState::RestoreVertexAttribs(const ContextState* prev_state) const {
// Restore Vertex Attrib Arrays
DCHECK(vertex_attrib_manager.get());
// Restore VAOs.
if (feature_info_->feature_flags().native_vertex_array_object) {
// If default VAO is still using shared id 0 instead of unique ids
// per-context, default VAO state must be restored.
GLuint default_vao_service_id = default_vertex_attrib_manager->service_id();
if (default_vao_service_id == 0)
RestoreVertexAttribArrays(default_vertex_attrib_manager);
// Restore the current VAO binding, unless it's the same as the
// default above.
GLuint curr_vao_service_id = vertex_attrib_manager->service_id();
if (curr_vao_service_id != 0)
api()->glBindVertexArrayOESFn(curr_vao_service_id);
} else {
if (prev_state &&
prev_state->feature_info_->feature_flags().native_vertex_array_object &&
feature_info_->workarounds()
.use_client_side_arrays_for_stream_buffers) {
// In order to use client side arrays, the driver's default VAO has to be
// bound.
api()->glBindVertexArrayOESFn(0);
}
// If native VAO isn't supported, emulated VAOs are used.
// Restore to the currently bound VAO.
RestoreVertexAttribArrays(vertex_attrib_manager);
}
// glVertexAttrib4fv aren't part of VAO state and must be restored.
RestoreVertexAttribValues();
}
void ContextState::RestoreGlobalState(const ContextState* prev_state) const {
InitCapabilities(prev_state);
InitState(prev_state);
}
void ContextState::RestoreState(const ContextState* prev_state) {
RestoreAllTextureUnitAndSamplerBindings(prev_state);
// For RasterDecoder, |vertex_attrib_manager| will be nullptr, and we don't
// need restore vertex attribs for them.
if (vertex_attrib_manager)
RestoreVertexAttribs(prev_state);
// RestoreIndexedUniformBufferBindings must be called before
// RestoreBufferBindings. This is because setting the indexed uniform buffer
// bindings via glBindBuffer{Base,Range} also sets the general uniform buffer
// bindings (glBindBuffer), but not vice versa.
// For RasterDecoder, |indexed_uniform_buffer_bindings| will be nullptr, and
// we don't need restore indexed uniform buffer for them.
if (indexed_uniform_buffer_bindings)
RestoreIndexedUniformBufferBindings(prev_state);
RestoreBufferBindings();
RestoreRenderbufferBindings();
RestoreProgramSettings(prev_state, true);
RestoreGlobalState(prev_state);
// FRAMEBUFFER_SRGB will be restored lazily at render time.
framebuffer_srgb_valid_ = false;
}
ErrorState* ContextState::GetErrorState() {
return error_state_.get();
}
void ContextState::EnableDisable(GLenum pname, bool enable) const {
if (pname == GL_PRIMITIVE_RESTART_FIXED_INDEX &&
feature_info_->feature_flags().emulate_primitive_restart_fixed_index) {
// GLES2DecoderImpl::DoDrawElements can handle this situation
return;
}
if (enable) {
api()->glEnableFn(pname);
} else {
api()->glDisableFn(pname);
}
}
void ContextState::UpdatePackParameters() const {
if (!feature_info_->IsES3Capable())
return;
if (bound_pixel_pack_buffer.get()) {
api()->glPixelStoreiFn(GL_PACK_ROW_LENGTH, pack_row_length);
} else {
api()->glPixelStoreiFn(GL_PACK_ROW_LENGTH, 0);
}
}
void ContextState::SetMaxWindowRectangles(size_t max) {
window_rectangles_ = std::vector<GLint>(max * 4, 0);
}
size_t ContextState::GetMaxWindowRectangles() const {
size_t size = window_rectangles_.size();
DCHECK_EQ(0ull, size % 4);
return size / 4;
}
void ContextState::SetWindowRectangles(GLenum mode,
size_t count,
const volatile GLint* box) {
window_rectangles_mode = mode;
num_window_rectangles = count;
DCHECK_LE(count, GetMaxWindowRectangles());
if (count) {
std::copy(box, &box[count * 4], window_rectangles_.begin());
}
}
void ContextState::UpdateWindowRectangles() const {
if (!feature_info_->feature_flags().ext_window_rectangles) {
return;
}
if (current_draw_framebuffer_client_id == 0) {
// Window rectangles must not take effect for client_id 0 (backbuffer).
api()->glWindowRectanglesEXTFn(GL_EXCLUSIVE_EXT, 0, nullptr);
} else {
DCHECK_LE(static_cast<size_t>(num_window_rectangles),
GetMaxWindowRectangles());
const GLint* data =
num_window_rectangles ? window_rectangles_.data() : nullptr;
api()->glWindowRectanglesEXTFn(window_rectangles_mode,
num_window_rectangles, data);
}
}
void ContextState::UpdateWindowRectanglesForBoundDrawFramebufferClientID(
GLuint client_id) {
bool old_id_nonzero = current_draw_framebuffer_client_id != 0;
bool new_id_nonzero = client_id != 0;
current_draw_framebuffer_client_id = client_id;
// If switching from FBO to backbuffer, or vice versa, update driver state.
if (old_id_nonzero ^ new_id_nonzero) {
UpdateWindowRectangles();
}
}
void ContextState::UpdateUnpackParameters() const {
if (!feature_info_->IsES3Capable())
return;
if (bound_pixel_unpack_buffer.get()) {
api()->glPixelStoreiFn(GL_UNPACK_ROW_LENGTH, unpack_row_length);
api()->glPixelStoreiFn(GL_UNPACK_IMAGE_HEIGHT, unpack_image_height);
} else {
api()->glPixelStoreiFn(GL_UNPACK_ROW_LENGTH, 0);
api()->glPixelStoreiFn(GL_UNPACK_IMAGE_HEIGHT, 0);
}
}
void ContextState::SetBoundBuffer(GLenum target, Buffer* buffer) {
bool do_refcounting = feature_info_->IsWebGL2OrES3Context();
switch (target) {
case GL_ARRAY_BUFFER:
if (do_refcounting && bound_array_buffer)
bound_array_buffer->OnUnbind(target, false);
bound_array_buffer = buffer;
if (do_refcounting && buffer)
buffer->OnBind(target, false);
break;
case GL_ELEMENT_ARRAY_BUFFER:
vertex_attrib_manager->SetElementArrayBuffer(buffer);
break;
case GL_COPY_READ_BUFFER:
if (do_refcounting && bound_copy_read_buffer)
bound_copy_read_buffer->OnUnbind(target, false);
bound_copy_read_buffer = buffer;
if (do_refcounting && buffer)
buffer->OnBind(target, false);
break;
case GL_COPY_WRITE_BUFFER:
if (do_refcounting && bound_copy_write_buffer)
bound_copy_write_buffer->OnUnbind(target, false);
bound_copy_write_buffer = buffer;
if (do_refcounting && buffer)
buffer->OnBind(target, false);
break;
case GL_PIXEL_PACK_BUFFER:
if (do_refcounting && bound_pixel_pack_buffer)
bound_pixel_pack_buffer->OnUnbind(target, false);
bound_pixel_pack_buffer = buffer;
if (do_refcounting && buffer)
buffer->OnBind(target, false);
UpdatePackParameters();
break;
case GL_PIXEL_UNPACK_BUFFER:
if (do_refcounting && bound_pixel_unpack_buffer)
bound_pixel_unpack_buffer->OnUnbind(target, false);
bound_pixel_unpack_buffer = buffer;
if (do_refcounting && buffer)
buffer->OnBind(target, false);
UpdateUnpackParameters();
break;
case GL_TRANSFORM_FEEDBACK_BUFFER:
if (do_refcounting && bound_transform_feedback_buffer)
bound_transform_feedback_buffer->OnUnbind(target, false);
bound_transform_feedback_buffer = buffer;
if (do_refcounting && buffer)
buffer->OnBind(target, false);
break;
case GL_UNIFORM_BUFFER:
if (do_refcounting && bound_uniform_buffer)
bound_uniform_buffer->OnUnbind(target, false);
bound_uniform_buffer = buffer;
if (do_refcounting && buffer)
buffer->OnBind(target, false);
break;
default:
NOTREACHED();
break;
}
}
void ContextState::RemoveBoundBuffer(Buffer* buffer) {
DCHECK(buffer);
bool do_refcounting = feature_info_->IsWebGL2OrES3Context();
if (bound_array_buffer.get() == buffer) {
bound_array_buffer = nullptr;
if (do_refcounting)
buffer->OnUnbind(GL_ARRAY_BUFFER, false);
if (!context_lost_)
api()->glBindBufferFn(GL_ARRAY_BUFFER, 0);
}
// Needs to be called after bound_array_buffer handled.
vertex_attrib_manager->Unbind(buffer, bound_array_buffer.get());
if (bound_copy_read_buffer.get() == buffer) {
bound_copy_read_buffer = nullptr;
if (do_refcounting)
buffer->OnUnbind(GL_COPY_READ_BUFFER, false);
if (!context_lost_)
api()->glBindBufferFn(GL_COPY_READ_BUFFER, 0);
}
if (bound_copy_write_buffer.get() == buffer) {
bound_copy_write_buffer = nullptr;
if (do_refcounting)
buffer->OnUnbind(GL_COPY_WRITE_BUFFER, false);
if (!context_lost_)
api()->glBindBufferFn(GL_COPY_WRITE_BUFFER, 0);
}
if (bound_pixel_pack_buffer.get() == buffer) {
bound_pixel_pack_buffer = nullptr;
if (do_refcounting)
buffer->OnUnbind(GL_PIXEL_PACK_BUFFER, false);
if (!context_lost_)
api()->glBindBufferFn(GL_PIXEL_PACK_BUFFER, 0);
UpdatePackParameters();
}
if (bound_pixel_unpack_buffer.get() == buffer) {
bound_pixel_unpack_buffer = nullptr;
if (do_refcounting)
buffer->OnUnbind(GL_PIXEL_UNPACK_BUFFER, false);
if (!context_lost_)
api()->glBindBufferFn(GL_PIXEL_UNPACK_BUFFER, 0);
UpdateUnpackParameters();
}
if (bound_transform_feedback_buffer.get() == buffer) {
bound_transform_feedback_buffer = nullptr;
if (do_refcounting)
buffer->OnUnbind(GL_TRANSFORM_FEEDBACK_BUFFER, false);
if (!context_lost_)
api()->glBindBufferFn(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
}
// Needs to be called after bound_transform_feedback_buffer handled.
if (bound_transform_feedback.get()) {
bound_transform_feedback->RemoveBoundBuffer(
GL_TRANSFORM_FEEDBACK_BUFFER, buffer,
bound_transform_feedback_buffer.get(), !context_lost_);
}
if (bound_uniform_buffer.get() == buffer) {
bound_uniform_buffer = nullptr;
if (do_refcounting)
buffer->OnUnbind(GL_UNIFORM_BUFFER, false);
if (!context_lost_)
api()->glBindBufferFn(GL_UNIFORM_BUFFER, 0);
}
// Needs to be called after bound_uniform_buffer handled.
if (indexed_uniform_buffer_bindings) {
indexed_uniform_buffer_bindings->RemoveBoundBuffer(
GL_UNIFORM_BUFFER, buffer, bound_uniform_buffer.get(), !context_lost_);
}
}
void ContextState::UnbindTexture(TextureRef* texture) {
GLuint active_unit = active_texture_unit;
for (size_t jj = 0; jj < texture_units.size(); ++jj) {
TextureUnit& unit = texture_units[jj];
if (unit.bound_texture_2d.get() == texture) {
unit.bound_texture_2d = nullptr;
if (active_unit != jj) {
api()->glActiveTextureFn(GL_TEXTURE0 + jj);
active_unit = jj;
}
api()->glBindTextureFn(GL_TEXTURE_2D, 0);
} else if (unit.bound_texture_cube_map.get() == texture) {
unit.bound_texture_cube_map = nullptr;
if (active_unit != jj) {
api()->glActiveTextureFn(GL_TEXTURE0 + jj);
active_unit = jj;
}
api()->glBindTextureFn(GL_TEXTURE_CUBE_MAP, 0);
} else if (unit.bound_texture_external_oes.get() == texture) {
unit.bound_texture_external_oes = nullptr;
if (active_unit != jj) {
api()->glActiveTextureFn(GL_TEXTURE0 + jj);
active_unit = jj;
}
api()->glBindTextureFn(GL_TEXTURE_EXTERNAL_OES, 0);
} else if (unit.bound_texture_rectangle_arb.get() == texture) {
unit.bound_texture_rectangle_arb = nullptr;
if (active_unit != jj) {
api()->glActiveTextureFn(GL_TEXTURE0 + jj);
active_unit = jj;
}
api()->glBindTextureFn(GL_TEXTURE_RECTANGLE_ARB, 0);
} else if (unit.bound_texture_3d.get() == texture) {
unit.bound_texture_3d = nullptr;
if (active_unit != jj) {
api()->glActiveTextureFn(GL_TEXTURE0 + jj);
active_unit = jj;
}
api()->glBindTextureFn(GL_TEXTURE_3D, 0);
} else if (unit.bound_texture_2d_array.get() == texture) {
unit.bound_texture_2d_array = nullptr;
if (active_unit != jj) {
api()->glActiveTextureFn(GL_TEXTURE0 + jj);
active_unit = jj;
}
api()->glBindTextureFn(GL_TEXTURE_2D_ARRAY, 0);
}
}
if (active_unit != active_texture_unit) {
api()->glActiveTextureFn(GL_TEXTURE0 + active_texture_unit);
}
}
void ContextState::UnbindSampler(Sampler* sampler) {
for (size_t jj = 0; jj < sampler_units.size(); ++jj) {
if (sampler_units[jj].get() == sampler) {
sampler_units[jj] = nullptr;
api()->glBindSamplerFn(jj, 0);
}
}
}
PixelStoreParams ContextState::GetPackParams() {
DCHECK_EQ(0, pack_skip_pixels);
DCHECK_EQ(0, pack_skip_rows);
PixelStoreParams params;
params.alignment = pack_alignment;
params.row_length = pack_row_length;
return params;
}
PixelStoreParams ContextState::GetUnpackParams(Dimension dimension) {
DCHECK_EQ(0, unpack_skip_pixels);
DCHECK_EQ(0, unpack_skip_rows);
DCHECK_EQ(0, unpack_skip_images);
PixelStoreParams params;
params.alignment = unpack_alignment;
params.row_length = unpack_row_length;
if (dimension == k3D) {
params.image_height = unpack_image_height;
}
return params;
}
void ContextState::EnableDisableFramebufferSRGB(bool enable) {
if (framebuffer_srgb_valid_ && framebuffer_srgb_ == enable)
return;
EnableDisable(GL_FRAMEBUFFER_SRGB, enable);
framebuffer_srgb_ = enable;
framebuffer_srgb_valid_ = true;
}
void ContextState::InitStateManual(const ContextState*) const {
// Here we always reset the states whether it's different from previous ones.
// We have very limited states here; also, once we switch to MANGLE, MANGLE
// will opmitize this.
UpdatePackParameters();
UpdateUnpackParameters();
UpdateWindowRectangles();
}
// Include the auto-generated part of this file. We split this because it means
// we can easily edit the non-auto generated parts right here in this file
// instead of having to edit some template or the code generator.
#include "gpu/command_buffer/service/context_state_impl_autogen.h"
} // namespace gles2
} // namespace gpu