Commit c4875316 authored by yunchao.he's avatar yunchao.he Committed by Commit bot

WebGL 2: make sure VertexAttrib type match the corresponding attrib type in shader.

Fix bugs in attrib-type-match.html

BUG=628459
TEST=conformance2/rendering/attrib-type-match.html
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel

Review-Url: https://codereview.chromium.org/2148723004
Cr-Commit-Position: refs/heads/master@{#407168}
parent bbbbf65c
......@@ -434,6 +434,7 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder,
max_varying_vectors_,
max_draw_buffers_,
max_dual_source_draw_buffers_,
max_vertex_attribs_,
gpu_preferences_,
feature_info_.get()));
......
......@@ -224,6 +224,10 @@ ContextState::ContextState(FeatureInfo* feature_info,
framebuffer_srgb_(false),
feature_info_(feature_info),
error_state_(ErrorState::Create(error_state_client, logger)) {
max_vertex_attribs_ = 0;
generic_attrib_base_type_mask_.resize(1);
generic_attrib_base_type_mask_[0] = 0xFFFFFFFF;
Initialize();
}
......
......@@ -243,6 +243,31 @@ struct GPU_EXPORT ContextState {
void SetBoundBuffer(GLenum target, Buffer* buffer);
void RemoveBoundBuffer(Buffer* buffer);
void InitGenericAttribBaseType(GLuint max_vertex_attribs) {
max_vertex_attribs_ = max_vertex_attribs;
uint32_t packed_size = max_vertex_attribs_ / 16;
packed_size += (max_vertex_attribs_ % 16 == 0) ? 0 : 1;
generic_attrib_base_type_mask_.resize(packed_size);
for (uint32_t i = 0; i < packed_size; ++i) {
generic_attrib_base_type_mask_[i] = 0xFFFFFFFF;
}
}
void SetGenericVertexAttribBaseType(GLuint index, GLenum base_type) {
DCHECK(index < max_vertex_attribs_);
int shift_bits = (index % 16) * 2;
generic_attrib_base_type_mask_[index / 16] &= ~(0x3 << shift_bits);
generic_attrib_base_type_mask_[index / 16] |= (base_type << shift_bits);
}
// Return 16 attributes' base types, in which the generic attribute
// specified by argument 'index' located.
uint32_t GetGenericVertexAttribBaseTypeMask(GLuint index) {
DCHECK(index < max_vertex_attribs_);
return generic_attrib_base_type_mask_[index / 16];
}
void UnbindTexture(TextureRef* texture);
void UnbindSampler(Sampler* sampler);
......@@ -320,6 +345,12 @@ struct GPU_EXPORT ContextState {
bool framebuffer_srgb_;
uint32_t max_vertex_attribs_;
// Generic vertex attrib base types: FLOAT, INT, or UINT.
// Each base type is encoded into 2 bits, the lowest 2 bits for location 0,
// the highest 2 bits for location (max_vertex_attribs_ - 1).
std::vector<uint32_t> generic_attrib_base_type_mask_;
FeatureInfo* feature_info_;
std::unique_ptr<ErrorState> error_state_;
};
......
......@@ -1424,6 +1424,21 @@ bool FeatureInfo::IsWebGLContext() const {
return false;
}
bool FeatureInfo::IsWebGL2OrES3Context() const {
// Switch statement to cause a compile-time error if we miss a case.
switch (context_type_) {
case CONTEXT_TYPE_WEBGL2:
case CONTEXT_TYPE_OPENGLES3:
return true;
case CONTEXT_TYPE_WEBGL1:
case CONTEXT_TYPE_OPENGLES2:
return false;
default:
NOTREACHED();
return false;
}
}
void FeatureInfo::AddExtensionString(const char* s) {
std::string str(s);
size_t pos = extensions_.find(str);
......
......@@ -150,6 +150,7 @@ class GPU_EXPORT FeatureInfo : public base::RefCounted<FeatureInfo> {
bool disable_shader_translator() const { return disable_shader_translator_; }
bool IsWebGLContext() const;
bool IsWebGL2OrES3Context() const;
void EnableCHROMIUMColorBufferFloatRGBA();
void EnableCHROMIUMColorBufferFloatRGB();
......
......@@ -1795,6 +1795,10 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient {
// false if pname is unknown.
bool GetNumValuesReturnedForGLGet(GLenum pname, GLsizei* num_values);
// Checks if every attribute's type set by vertexAttrib API match
// the type of corresponding attribute in vertex shader.
bool AttribsTypeMatch();
// Checks if the current program and vertex attributes are valid for drawing.
bool IsDrawValid(
const char* function_name, GLuint max_vertex_accessed, bool instanced,
......@@ -3066,6 +3070,7 @@ bool GLES2DecoderImpl::Initialize(
state_.indexed_uniform_buffer_bindings = new IndexedBufferBindingHost(
group_->max_uniform_buffer_bindings(), needs_emulation);
state_.InitGenericAttribBaseType(group_->max_vertex_attribs());
state_.attrib_values.resize(group_->max_vertex_attribs());
vertex_array_manager_.reset(new VertexArrayManager());
......@@ -9114,6 +9119,28 @@ void GLES2DecoderImpl::RestoreStateForSimulatedFixedAttribs() {
: 0);
}
bool GLES2DecoderImpl::AttribsTypeMatch() {
for (uint32_t index = 0; index < group_->max_vertex_attribs(); index += 16) {
uint32_t shader_attrib_written_mask =
state_.current_program->vertex_input_type_written_mask(index);
uint32_t vao_attrib_written_mask =
state_.vertex_attrib_manager->attrib_type_written_mask(index);
uint32_t vertex_attrib_base_type_mask =
(~vao_attrib_written_mask &
state_.GetGenericVertexAttribBaseTypeMask(index)) |
(vao_attrib_written_mask &
state_.vertex_attrib_manager->attrib_base_type_mask(index));
if ((state_.current_program->vertex_input_base_type_mask(index)
& shader_attrib_written_mask) !=
(vertex_attrib_base_type_mask & shader_attrib_written_mask)) {
return false;
}
}
return true;
}
error::Error GLES2DecoderImpl::DoDrawArrays(
const char* function_name,
bool instanced,
......@@ -9160,6 +9187,12 @@ error::Error GLES2DecoderImpl::DoDrawArrays(
return error::kNoError;
}
if (feature_info_->IsWebGL2OrES3Context() && !AttribsTypeMatch()) {
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
"vertexAttrib function must match shader attrib type");
return error::kNoError;
}
GLuint max_vertex_accessed = first + count - 1;
if (IsDrawValid(function_name, max_vertex_accessed, instanced, primcount)) {
if (!ClearUnclearedTextures()) {
......@@ -9286,6 +9319,12 @@ error::Error GLES2DecoderImpl::DoDrawElements(const char* function_name,
return error::kNoError;
}
if (feature_info_->IsWebGL2OrES3Context() && !AttribsTypeMatch()) {
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
"vertexAttrib function must match shader attrib type");
return error::kNoError;
}
GLuint max_vertex_accessed;
Buffer* element_array_buffer =
state_.vertex_attrib_manager->element_array_buffer();
......@@ -9885,6 +9924,8 @@ bool GLES2DecoderImpl::SetVertexAttribValue(
void GLES2DecoderImpl::DoVertexAttrib1f(GLuint index, GLfloat v0) {
GLfloat v[4] = { v0, 0.0f, 0.0f, 1.0f, };
if (SetVertexAttribValue("glVertexAttrib1f", index, v)) {
state_.SetGenericVertexAttribBaseType(
index, SHADER_VARIABLE_FLOAT);
glVertexAttrib1f(index, v0);
}
}
......@@ -9892,6 +9933,8 @@ void GLES2DecoderImpl::DoVertexAttrib1f(GLuint index, GLfloat v0) {
void GLES2DecoderImpl::DoVertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1) {
GLfloat v[4] = { v0, v1, 0.0f, 1.0f, };
if (SetVertexAttribValue("glVertexAttrib2f", index, v)) {
state_.SetGenericVertexAttribBaseType(
index, SHADER_VARIABLE_FLOAT);
glVertexAttrib2f(index, v0, v1);
}
}
......@@ -9900,6 +9943,8 @@ void GLES2DecoderImpl::DoVertexAttrib3f(
GLuint index, GLfloat v0, GLfloat v1, GLfloat v2) {
GLfloat v[4] = { v0, v1, v2, 1.0f, };
if (SetVertexAttribValue("glVertexAttrib3f", index, v)) {
state_.SetGenericVertexAttribBaseType(
index, SHADER_VARIABLE_FLOAT);
glVertexAttrib3f(index, v0, v1, v2);
}
}
......@@ -9908,6 +9953,8 @@ void GLES2DecoderImpl::DoVertexAttrib4f(
GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {
GLfloat v[4] = { v0, v1, v2, v3, };
if (SetVertexAttribValue("glVertexAttrib4f", index, v)) {
state_.SetGenericVertexAttribBaseType(
index, SHADER_VARIABLE_FLOAT);
glVertexAttrib4f(index, v0, v1, v2, v3);
}
}
......@@ -9915,6 +9962,8 @@ void GLES2DecoderImpl::DoVertexAttrib4f(
void GLES2DecoderImpl::DoVertexAttrib1fv(GLuint index, const GLfloat* v) {
GLfloat t[4] = { v[0], 0.0f, 0.0f, 1.0f, };
if (SetVertexAttribValue("glVertexAttrib1fv", index, t)) {
state_.SetGenericVertexAttribBaseType(
index, SHADER_VARIABLE_FLOAT);
glVertexAttrib1fv(index, v);
}
}
......@@ -9922,6 +9971,8 @@ void GLES2DecoderImpl::DoVertexAttrib1fv(GLuint index, const GLfloat* v) {
void GLES2DecoderImpl::DoVertexAttrib2fv(GLuint index, const GLfloat* v) {
GLfloat t[4] = { v[0], v[1], 0.0f, 1.0f, };
if (SetVertexAttribValue("glVertexAttrib2fv", index, t)) {
state_.SetGenericVertexAttribBaseType(
index, SHADER_VARIABLE_FLOAT);
glVertexAttrib2fv(index, v);
}
}
......@@ -9929,12 +9980,16 @@ void GLES2DecoderImpl::DoVertexAttrib2fv(GLuint index, const GLfloat* v) {
void GLES2DecoderImpl::DoVertexAttrib3fv(GLuint index, const GLfloat* v) {
GLfloat t[4] = { v[0], v[1], v[2], 1.0f, };
if (SetVertexAttribValue("glVertexAttrib3fv", index, t)) {
state_.SetGenericVertexAttribBaseType(
index, SHADER_VARIABLE_FLOAT);
glVertexAttrib3fv(index, v);
}
}
void GLES2DecoderImpl::DoVertexAttrib4fv(GLuint index, const GLfloat* v) {
if (SetVertexAttribValue("glVertexAttrib4fv", index, v)) {
state_.SetGenericVertexAttribBaseType(
index, SHADER_VARIABLE_FLOAT);
glVertexAttrib4fv(index, v);
}
}
......@@ -9943,12 +9998,16 @@ void GLES2DecoderImpl::DoVertexAttribI4i(
GLuint index, GLint v0, GLint v1, GLint v2, GLint v3) {
GLint v[4] = { v0, v1, v2, v3 };
if (SetVertexAttribValue("glVertexAttribI4i", index, v)) {
state_.SetGenericVertexAttribBaseType(
index, SHADER_VARIABLE_INT);
glVertexAttribI4i(index, v0, v1, v2, v3);
}
}
void GLES2DecoderImpl::DoVertexAttribI4iv(GLuint index, const GLint* v) {
if (SetVertexAttribValue("glVertexAttribI4iv", index, v)) {
state_.SetGenericVertexAttribBaseType(
index, SHADER_VARIABLE_INT);
glVertexAttribI4iv(index, v);
}
}
......@@ -9957,12 +10016,16 @@ void GLES2DecoderImpl::DoVertexAttribI4ui(
GLuint index, GLuint v0, GLuint v1, GLuint v2, GLuint v3) {
GLuint v[4] = { v0, v1, v2, v3 };
if (SetVertexAttribValue("glVertexAttribI4ui", index, v)) {
state_.SetGenericVertexAttribBaseType(
index, SHADER_VARIABLE_UINT);
glVertexAttribI4ui(index, v0, v1, v2, v3);
}
}
void GLES2DecoderImpl::DoVertexAttribI4uiv(GLuint index, const GLuint* v) {
if (SetVertexAttribValue("glVertexAttribI4uiv", index, v)) {
state_.SetGenericVertexAttribBaseType(
index, SHADER_VARIABLE_UINT);
glVertexAttribI4uiv(index, v);
}
}
......@@ -10041,6 +10104,11 @@ error::Error GLES2DecoderImpl::HandleVertexAttribIPointer(
"glVertexAttribIPointer", "stride not valid for type");
return error::kNoError;
}
GLenum base_type = (type == GL_BYTE || type == GL_SHORT || type == GL_INT) ?
SHADER_VARIABLE_INT : SHADER_VARIABLE_UINT;
state_.vertex_attrib_manager->UpdateAttribBaseTypeAndMask(indx, base_type);
GLsizei group_size = GLES2Util::GetGroupSizeForBufferType(size, type);
state_.vertex_attrib_manager
->SetAttribInfo(indx,
......@@ -10135,6 +10203,10 @@ error::Error GLES2DecoderImpl::HandleVertexAttribPointer(
"glVertexAttribPointer", "stride not valid for type");
return error::kNoError;
}
state_.vertex_attrib_manager->UpdateAttribBaseTypeAndMask(
indx, SHADER_VARIABLE_FLOAT);
GLsizei group_size = GLES2Util::GetGroupSizeForBufferType(size, type);
state_.vertex_attrib_manager
->SetAttribInfo(indx,
......
......@@ -117,7 +117,7 @@ uint32_t ComputeOffset(const void* start, const void* position) {
static_cast<const uint8_t*>(start);
}
ShaderVariableBaseType FragmentOutputTypeToBaseType(GLenum type) {
ShaderVariableBaseType InputOutputTypeToBaseType(bool is_input, GLenum type) {
switch (type) {
case GL_INT:
case GL_INT_VEC2:
......@@ -134,6 +134,17 @@ ShaderVariableBaseType FragmentOutputTypeToBaseType(GLenum type) {
case GL_FLOAT_VEC3:
case GL_FLOAT_VEC4:
return SHADER_VARIABLE_FLOAT;
case GL_FLOAT_MAT2:
case GL_FLOAT_MAT3:
case GL_FLOAT_MAT4:
case GL_FLOAT_MAT2x3:
case GL_FLOAT_MAT3x2:
case GL_FLOAT_MAT2x4:
case GL_FLOAT_MAT4x2:
case GL_FLOAT_MAT3x4:
case GL_FLOAT_MAT4x3:
DCHECK(is_input);
return SHADER_VARIABLE_FLOAT;
default:
NOTREACHED();
return SHADER_VARIABLE_UNDEFINED_TYPE;
......@@ -316,6 +327,8 @@ void Program::Reset() {
attrib_location_to_index_map_.clear();
fragment_output_type_mask_ = 0u;
fragment_output_written_mask_ = 0u;
vertex_input_base_type_mask_.clear();
vertex_input_type_written_mask_.clear();
}
void Program::UpdateFragmentOutputBaseTypes() {
......@@ -351,8 +364,33 @@ void Program::UpdateFragmentOutputBaseTypes() {
int shift_bits = ii * 2;
fragment_output_written_mask_ |= 0x3 << shift_bits;
fragment_output_type_mask_ |=
FragmentOutputTypeToBaseType(output.type) << shift_bits;
InputOutputTypeToBaseType(false, output.type) << shift_bits;
}
}
}
void Program::UpdateVertexInputBaseTypes() {
max_vertex_attribs_ = manager_->max_vertex_attribs();
uint32_t packed_size = max_vertex_attribs_ / 16;
packed_size += (max_vertex_attribs_ % 16 == 0) ? 0 : 1;
vertex_input_base_type_mask_.resize(packed_size);
vertex_input_type_written_mask_.resize(packed_size);
for (uint32_t ii = 0; ii < packed_size; ++ii) {
vertex_input_type_written_mask_[ii] = 0u;
vertex_input_base_type_mask_[ii] = 0u;
}
for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
DCHECK(ii < max_vertex_attribs_);
const VertexAttrib& input = attrib_infos_[ii];
if (ProgramManager::HasBuiltInPrefix(input.name)) {
continue;
}
int shift_bits = (input.location % 16) * 2;
vertex_input_type_written_mask_[ii / 16] |= 0x3 << shift_bits;
vertex_input_base_type_mask_[ii / 16] |=
InputOutputTypeToBaseType(true, input.type) << shift_bits;
}
}
......@@ -623,6 +661,7 @@ void Program::Update() {
UpdateFragmentInputs();
UpdateProgramOutputs();
UpdateFragmentOutputBaseTypes();
UpdateVertexInputBaseTypes();
UpdateUniformBlockSizeInfo();
valid_ = true;
......@@ -2376,6 +2415,7 @@ ProgramManager::ProgramManager(
uint32_t max_varying_vectors,
uint32_t max_draw_buffers,
uint32_t max_dual_source_draw_buffers,
uint32_t max_vertex_attribs,
const GpuPreferences& gpu_preferences,
FeatureInfo* feature_info)
: program_count_(0),
......@@ -2384,6 +2424,7 @@ ProgramManager::ProgramManager(
max_varying_vectors_(max_varying_vectors),
max_draw_buffers_(max_draw_buffers),
max_dual_source_draw_buffers_(max_dual_source_draw_buffers),
max_vertex_attribs_(max_vertex_attribs),
gpu_preferences_(gpu_preferences),
feature_info_(feature_info) {}
......
......@@ -403,6 +403,20 @@ class GPU_EXPORT Program : public base::RefCounted<Program> {
return fragment_output_written_mask_;
}
// The data are only valid after a successful link.
// Return 16 attributes' base types, in which the attribute
// specified by argument 'loc' located.
uint32_t vertex_input_base_type_mask(GLuint loc) const {
DCHECK(loc < max_vertex_attribs_);
return vertex_input_base_type_mask_[loc / 16];
}
// Return 16 attributes' type written masks, in which the
// attribute specified by argument 'loc' located.
uint32_t vertex_input_type_written_mask(GLuint loc) const {
DCHECK(loc < max_vertex_attribs_);
return vertex_input_type_written_mask_[loc / 16];
}
// Update uniform block binding after a successful glUniformBlockBinding().
void SetUniformBlockBinding(GLuint index, GLuint binding);
......@@ -447,6 +461,7 @@ class GPU_EXPORT Program : public base::RefCounted<Program> {
void UpdateFragmentInputs();
void UpdateProgramOutputs();
void UpdateFragmentOutputBaseTypes();
void UpdateVertexInputBaseTypes();
void UpdateUniformBlockSizeInfo();
// Process the program log, replacing the hashed names with original names.
......@@ -565,6 +580,15 @@ class GPU_EXPORT Program : public base::RefCounted<Program> {
// Same layout as above, 2 bits per location, 0x03 if a location is occupied
// by an output variable, 0x00 if not.
uint32_t fragment_output_written_mask_;
uint32_t max_vertex_attribs_;
// Vertex input attrib base types: FLOAT, INT, or UINT.
// Each base type is encoded into 2 bits, the lowest 2 bits for location 0,
// the highest 2 bits for location (max_vertex_attribs_ - 1).
std::vector<uint32_t> vertex_input_base_type_mask_;
// Same layout as above, 2 bits per location, 0x03 if a location is set
// by vertexAttrib API, 0x00 if not.
std::vector<uint32_t> vertex_input_type_written_mask_;
};
// Tracks the Programs.
......@@ -577,6 +601,7 @@ class GPU_EXPORT ProgramManager {
uint32_t max_varying_vectors,
uint32_t max_draw_buffers,
uint32_t max_dual_source_draw_buffers,
uint32_t max_vertex_attribs,
const GpuPreferences& gpu_preferences,
FeatureInfo* feature_info);
~ProgramManager();
......@@ -625,6 +650,8 @@ class GPU_EXPORT ProgramManager {
return max_dual_source_draw_buffers_;
}
uint32_t max_vertex_attribs() const { return max_vertex_attribs_; }
private:
friend class Program;
......@@ -653,6 +680,7 @@ class GPU_EXPORT ProgramManager {
uint32_t max_varying_vectors_;
uint32_t max_draw_buffers_;
uint32_t max_dual_source_draw_buffers_;
uint32_t max_vertex_attribs_;
const GpuPreferences& gpu_preferences_;
scoped_refptr<FeatureInfo> feature_info_;
......
......@@ -45,6 +45,7 @@ namespace {
const uint32_t kMaxVaryingVectors = 8;
const uint32_t kMaxDrawBuffers = 8;
const uint32_t kMaxDualSourceDrawBuffers = 8;
const uint32_t kMaxVertexAttribs = 8;
void ShaderCacheCb(const std::string& key, const std::string& shader) {}
......@@ -61,6 +62,7 @@ class ProgramManagerTestBase : public GpuServiceTest {
manager_.reset(new ProgramManager(nullptr, kMaxVaryingVectors,
kMaxDrawBuffers,
kMaxDualSourceDrawBuffers,
kMaxVertexAttribs,
gpu_preferences_,
feature_info_.get()));
}
......@@ -2072,6 +2074,7 @@ class ProgramManagerWithCacheTest : public ProgramManagerTestBase {
manager_.reset(new ProgramManager(cache_.get(), kMaxVaryingVectors,
kMaxDrawBuffers,
kMaxDualSourceDrawBuffers,
kMaxVertexAttribs,
gpu_preferences_,
feature_info_.get()));
}
......
......@@ -127,6 +127,16 @@ VertexAttribManager::~VertexAttribManager() {
void VertexAttribManager::Initialize(uint32_t max_vertex_attribs,
bool init_attribs) {
vertex_attribs_.resize(max_vertex_attribs);
max_vertex_attribs_ = max_vertex_attribs;
uint32_t packed_size = max_vertex_attribs_ / 16;
packed_size += (max_vertex_attribs_ % 16 == 0) ? 0 : 1;
attrib_base_type_mask_.resize(packed_size);
attrib_type_written_mask_.resize(packed_size);
for (uint32_t ii = 0; ii < packed_size; ++ii) {
attrib_type_written_mask_[ii] = 0u;
attrib_base_type_mask_[ii] = 0u;
}
for (uint32_t vv = 0; vv < vertex_attribs_.size(); ++vv) {
vertex_attribs_[vv].set_index(vv);
......@@ -146,6 +156,15 @@ bool VertexAttribManager::Enable(GLuint index, bool enable) {
if (index >= vertex_attribs_.size()) {
return false;
}
DCHECK(index < max_vertex_attribs_);
GLuint shift_bits = (index % 16) * 2;
if (enable) {
attrib_type_written_mask_[index / 16] |= (0x3 << shift_bits);
} else {
attrib_type_written_mask_[index / 16] &= ~(0x3 << shift_bits);
}
VertexAttrib& info = vertex_attribs_[index];
if (info.enabled() != enable) {
info.set_enabled(enable);
......
......@@ -200,6 +200,28 @@ class GPU_EXPORT VertexAttribManager :
return NULL;
}
void UpdateAttribBaseTypeAndMask(GLuint loc, GLenum base_type) {
DCHECK(loc < max_vertex_attribs_);
int shift_bits = (loc % 16) * 2;
attrib_type_written_mask_[loc / 16] |= (0x3 << shift_bits);
attrib_base_type_mask_[loc / 16] &= ~(0x3 << shift_bits);
attrib_base_type_mask_[loc / 16] |= base_type << shift_bits;
}
// Return 16 attributes' base types, in which the attribute
// specified by argument 'loc' located.
uint32_t attrib_base_type_mask(GLuint loc) const {
DCHECK(loc < max_vertex_attribs_);
return attrib_base_type_mask_[loc / 16];
}
// Return 16 attributes' type written masks, in which the
// attribute specified by argument 'loc' located.
uint32_t attrib_type_written_mask(GLuint loc) const {
DCHECK(loc < max_vertex_attribs_);
return attrib_type_written_mask_[loc / 16];
}
void SetAttribInfo(
GLuint index,
Buffer* buffer,
......@@ -284,6 +306,15 @@ class GPU_EXPORT VertexAttribManager :
// if it is safe to draw.
std::vector<VertexAttrib> vertex_attribs_;
uint32_t max_vertex_attribs_;
// Vertex attrib base types: FLOAT, INT, or UINT.
// Each base type is encoded into 2 bits, the lowest 2 bits for location 0,
// the highest 2 bits for location (max_vertex_attribs_ - 1).
std::vector<uint32_t> attrib_base_type_mask_;
// Same layout as above, 2 bits per location, 0x03 if a location is set
// by vertexAttrib API, 0x00 if not.
std::vector<uint32_t> attrib_type_written_mask_;
// The currently bound element array buffer. If this is 0 it is illegal
// to call glDrawElements.
scoped_refptr<Buffer> element_array_buffer_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment