summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorgman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-07 01:26:08 +0000
committergman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-07 01:26:08 +0000
commit17cfbe0ee496d4b63197415c9bf849c1f2d12694 (patch)
tree6dfe1c5fab337b20fca3586b655f710e1daabcf3 /gpu
parent5cd3af6cf38b7677b984b925327b8c6fa8548823 (diff)
downloadchromium_src-17cfbe0ee496d4b63197415c9bf849c1f2d12694.zip
chromium_src-17cfbe0ee496d4b63197415c9bf849c1f2d12694.tar.gz
chromium_src-17cfbe0ee496d4b63197415c9bf849c1f2d12694.tar.bz2
Revert "Revert 186416"
This reverts commit a8fb8f44bc56943c45bd06034fc004e22ef5da85 and fixes the bug related to the WebGL null object test. BUG=178093 TBR=apatrick@chromium.org Review URL: https://chromiumcodereview.appspot.com/12542009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@186573 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rwxr-xr-xgpu/command_buffer/build_gles2_cmd_buffer.py21
-rw-r--r--gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h14
-rw-r--r--gpu/command_buffer/service/buffer_manager.cc86
-rw-r--r--gpu/command_buffer/service/buffer_manager.h63
-rw-r--r--gpu/command_buffer/service/buffer_manager_unittest.cc295
-rw-r--r--gpu/command_buffer/service/context_group.cc3
-rw-r--r--gpu/command_buffer/service/feature_info.cc17
-rw-r--r--gpu/command_buffer/service/feature_info.h1
-rw-r--r--gpu/command_buffer/service/feature_info_unittest.cc31
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc135
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_autogen.h33
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc6
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h7
-rw-r--r--gpu/command_buffer/service/query_manager_unittest.cc6
-rw-r--r--gpu/command_buffer/service/test_helper.cc26
-rw-r--r--gpu/command_buffer/service/test_helper.h8
-rw-r--r--gpu/command_buffer/service/vertex_attrib_manager.cc114
-rw-r--r--gpu/command_buffer/service/vertex_attrib_manager.h22
-rw-r--r--gpu/command_buffer/service/vertex_attrib_manager_unittest.cc23
-rw-r--r--gpu/command_buffer/tests/gl_stream_draw_unittests.cc157
-rw-r--r--gpu/command_buffer/tests/gl_test_utils.cc18
-rw-r--r--gpu/command_buffer/tests/gl_test_utils.h5
-rw-r--r--gpu/gpu.gyp1
23 files changed, 844 insertions, 248 deletions
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index e826abd..a408db7 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -1176,6 +1176,7 @@ _PEPPER_INTERFACES = [
# when they can not be automatically determined.
# pepper_interface: The pepper interface that is used for this extension
# invalid_test: False if no invalid test needed.
+# shadowed: True = the value is shadowed so no glGetXXX call will be made.
_FUNCTION_INFO = {
'ActiveTexture': {
@@ -1563,7 +1564,13 @@ _FUNCTION_INFO = {
'decoder_func': 'DoGetBooleanv',
'gl_test_func': 'glGetBooleanv',
},
- 'GetBufferParameteriv': {'type': 'GETn', 'result': ['SizedResult<GLint>']},
+ 'GetBufferParameteriv': {
+ 'type': 'GETn',
+ 'result': ['SizedResult<GLint>'],
+ 'decoder_func': 'DoGetBufferParameteriv',
+ 'expectation': False,
+ 'shadowed': True,
+ },
'GetError': {
'type': 'Is',
'decoder_func': 'GetGLError',
@@ -4345,11 +4352,19 @@ class GETnHandler(TypeHandler):
if (result->size != 0) {
return error::kInvalidArguments;
}
- CopyRealGLErrorsToWrapper();
"""
+ shadowed = func.GetInfo('shadowed')
+ if not shadowed:
+ file.Write(" CopyRealGLErrorsToWrapper();\n");
file.Write(code)
func.WriteHandlerImplementation(file)
- code = """ GLenum error = glGetError();
+ if shadowed:
+ code = """ result->SetNumResults(num_values);
+ return error::kNoError;
+}
+"""
+ else:
+ code = """ GLenum error = glGetError();
if (error == GL_NO_ERROR) {
result->SetNumResults(num_values);
} else {
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
index 8ef9a14..9e4c660 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -22,6 +22,7 @@ static GLES2Util::EnumToString enum_to_string_table[] = {
{ 0, "GL_FALSE", },
{ 0x00400000, "GL_STENCIL_BUFFER_BIT6_QCOM", },
{ 0x82E6, "GL_SAMPLER", },
+ { 0x1E02, "GL_INCR", },
{ 0x9130, "GL_SGX_PROGRAM_BINARY_IMG", },
{ 0x9133, "GL_RENDERBUFFER_SAMPLES_IMG", },
{ 0x82E0, "GL_BUFFER", },
@@ -60,7 +61,7 @@ static GLES2Util::EnumToString enum_to_string_table[] = {
{ 0x8B54, "GL_INT_VEC3", },
{ 0x8DF4, "GL_MEDIUM_INT", },
{ 0x8DF5, "GL_HIGH_INT", },
- { 0x8B51, "GL_FLOAT_VEC3", },
+ { 0x8DF6, "GL_UNSIGNED_INT_10_10_10_2_OES", },
{ 0x8B50, "GL_FLOAT_VEC2", },
{ 0x806F, "GL_TEXTURE_3D_OES", },
{ 0x92E0, "GL_DEBUG_OUTPUT", },
@@ -88,6 +89,7 @@ static GLES2Util::EnumToString enum_to_string_table[] = {
{ 0x0C10, "GL_SCISSOR_BOX", },
{ 0x0C11, "GL_SCISSOR_TEST", },
{ 0x80000000, "GL_MULTISAMPLE_BUFFER_BIT7_QCOM", },
+ { 0x300E, "GL_CONTEXT_LOST", },
{ 0x02000000, "GL_MULTISAMPLE_BUFFER_BIT1_QCOM", },
{ 0x8C2F, "GL_ANY_SAMPLES_PASSED_EXT", },
{ 0x8BD2, "GL_TEXTURE_WIDTH_QCOM", },
@@ -283,7 +285,7 @@ static GLES2Util::EnumToString enum_to_string_table[] = {
{ 0x8FB1, "GL_CPU_OPTIMIZED_QCOM", },
{ 0x8B93, "GL_PALETTE4_RGBA4_OES", },
{ 0x8B92, "GL_PALETTE4_R5_G6_B5_OES", },
- { 0x1E02, "GL_INCR", },
+ { 0x8B91, "GL_PALETTE4_RGBA8_OES", },
{ 0x8B90, "GL_PALETTE4_RGB8_OES", },
{ 0x8B97, "GL_PALETTE8_R5_G6_B5_OES", },
{ 0x8B96, "GL_PALETTE8_RGBA8_OES", },
@@ -339,7 +341,7 @@ static GLES2Util::EnumToString enum_to_string_table[] = {
{ 0x82E1, "GL_SHADER", },
{ 0x8B52, "GL_FLOAT_VEC4", },
{ 0x9240, "GL_UNPACK_FLIP_Y_CHROMIUM", },
- { 0x8DF6, "GL_UNSIGNED_INT_10_10_10_2_OES", },
+ { 0x8B51, "GL_FLOAT_VEC3", },
{ 0x8230, "GL_RG32F_EXT", },
{ 0x8DF7, "GL_INT_10_10_10_2_OES", },
{ 0x812F, "GL_CLAMP_TO_EDGE", },
@@ -372,7 +374,6 @@ static GLES2Util::EnumToString enum_to_string_table[] = {
{ 0x881C, "GL_ALPHA16F_EXT", },
{ 0x8CD4, "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES", },
{ 0x8CD7, "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT", },
- { 0x08000000, "GL_MULTISAMPLE_BUFFER_BIT3_QCOM", },
{ 0x9112, "GL_OBJECT_TYPE_APPLE", },
{ 0x8038, "GL_POLYGON_OFFSET_FACTOR", },
{ 0x851A, "GL_TEXTURE_CUBE_MAP_NEGATIVE_Z", },
@@ -461,7 +462,7 @@ static GLES2Util::EnumToString enum_to_string_table[] = {
{ 0x84D4, "GL_TEXTURE20", },
{ 0x84D5, "GL_TEXTURE21", },
{ 0x84D2, "GL_TEXTURE18", },
- { 0x8B91, "GL_PALETTE4_RGBA8_OES", },
+ { 0x84D3, "GL_TEXTURE19", },
{ 0x84D0, "GL_TEXTURE16", },
{ 0x84D1, "GL_TEXTURE17", },
{ 0x1E03, "GL_DECR", },
@@ -487,7 +488,7 @@ static GLES2Util::EnumToString enum_to_string_table[] = {
{ 0x8865, "GL_CURRENT_QUERY_EXT", },
{ 0x8866, "GL_QUERY_RESULT_EXT", },
{ 0x8867, "GL_QUERY_RESULT_AVAILABLE_EXT", },
- { 0x300E, "GL_CONTEXT_LOST", },
+ { 0x08000000, "GL_MULTISAMPLE_BUFFER_BIT3_QCOM", },
{ 0x87FA, "GL_3DC_XY_AMD", },
{ 0x84C4, "GL_TEXTURE4", },
{ 0x85B5, "GL_VERTEX_ARRAY_BINDING_OES", },
@@ -597,7 +598,6 @@ static GLES2Util::EnumToString enum_to_string_table[] = {
{ 0x8893, "GL_ELEMENT_ARRAY_BUFFER", },
{ 0x8892, "GL_ARRAY_BUFFER", },
{ 0x8BD8, "GL_TEXTURE_IMAGE_VALID_QCOM", },
- { 0x84D3, "GL_TEXTURE19", },
{ 0x93BA, "GL_COMPRESSED_RGBA_ASTC_10x8_KHR", },
{ 0x93BB, "GL_COMPRESSED_RGBA_ASTC_10x10_KHR", },
{ 0x93BC, "GL_COMPRESSED_RGBA_ASTC_12x10_KHR", },
diff --git a/gpu/command_buffer/service/buffer_manager.cc b/gpu/command_buffer/service/buffer_manager.cc
index cb3062a..207ae3b 100644
--- a/gpu/command_buffer/service/buffer_manager.cc
+++ b/gpu/command_buffer/service/buffer_manager.cc
@@ -7,18 +7,26 @@
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "gpu/command_buffer/service/memory_tracking.h"
+#include "ui/gl/gl_bindings.h"
namespace gpu {
namespace gles2 {
-BufferManager::BufferManager(MemoryTracker* memory_tracker)
+BufferManager::BufferManager(
+ MemoryTracker* memory_tracker,
+ FeatureInfo* feature_info)
: memory_tracker_(
new MemoryTypeTracker(memory_tracker, MemoryTracker::kManaged)),
+ feature_info_(feature_info),
allow_buffers_on_multiple_targets_(false),
buffer_info_count_(0),
- have_context_(true) {
+ have_context_(true),
+ use_client_side_arrays_for_stream_buffers_(
+ feature_info ? feature_info->workarounds(
+ ).use_client_side_arrays_for_stream_buffers : 0) {
}
BufferManager::~BufferManager() {
@@ -70,7 +78,8 @@ Buffer::Buffer(BufferManager* manager, GLuint service_id)
target_(0),
size_(0),
usage_(GL_STATIC_DRAW),
- shadowed_(false) {
+ shadowed_(false),
+ is_client_side_array_(false) {
manager_->StartTracking(this);
}
@@ -86,14 +95,24 @@ Buffer::~Buffer() {
}
void Buffer::SetInfo(
- GLsizeiptr size, GLenum usage, bool shadow) {
+ GLsizeiptr size, GLenum usage, bool shadow, const GLvoid* data,
+ bool is_client_side_array) {
usage_ = usage;
+ is_client_side_array_ = is_client_side_array;
if (size != size_ || shadow != shadowed_) {
shadowed_ = shadow;
size_ = size;
ClearCache();
if (shadowed_) {
shadow_.reset(new int8[size]);
+ } else {
+ shadow_.reset();
+ }
+ }
+ if (shadowed_) {
+ if (data) {
+ memcpy(shadow_.get(), data, size);
+ } else {
memset(shadow_.get(), 0, size);
}
}
@@ -217,17 +236,66 @@ bool BufferManager::GetClientId(GLuint service_id, GLuint* client_id) const {
return false;
}
+bool BufferManager::IsUsageClientSideArray(GLenum usage) {
+ return usage == GL_STREAM_DRAW && use_client_side_arrays_for_stream_buffers_;
+}
+
void BufferManager::SetInfo(
- Buffer* info, GLsizeiptr size, GLenum usage) {
+ Buffer* info, GLsizeiptr size, GLenum usage, const GLvoid* data) {
DCHECK(info);
memory_tracker_->TrackMemFree(info->size());
- info->SetInfo(size,
- usage,
- info->target() == GL_ELEMENT_ARRAY_BUFFER ||
- allow_buffers_on_multiple_targets_);
+ bool is_client_side_array = IsUsageClientSideArray(usage);
+ bool shadow = info->target() == GL_ELEMENT_ARRAY_BUFFER ||
+ allow_buffers_on_multiple_targets_ ||
+ is_client_side_array;
+ info->SetInfo(size, usage, shadow, data, is_client_side_array);
memory_tracker_->TrackMemAlloc(info->size());
}
+void BufferManager::DoBufferData(
+ GLES2Decoder* decoder,
+ Buffer* buffer,
+ GLsizeiptr size,
+ GLenum usage,
+ const GLvoid* data) {
+ // Clear the buffer to 0 if no initial data was passed in.
+ scoped_array<int8> zero;
+ if (!data) {
+ zero.reset(new int8[size]);
+ memset(zero.get(), 0, size);
+ data = zero.get();
+ }
+
+ decoder->CopyRealGLErrorsToWrapper();
+ if (IsUsageClientSideArray(usage)) {
+ glBufferData(buffer->target(), 0, NULL, usage);
+ } else {
+ glBufferData(buffer->target(), size, data, usage);
+ }
+ GLenum error = decoder->PeekGLError();
+ if (error == GL_NO_ERROR) {
+ SetInfo(buffer, size, usage, data);
+ } else {
+ SetInfo(buffer, 0, usage, NULL);
+ }
+}
+
+void BufferManager::DoBufferSubData(
+ GLES2Decoder* decoder,
+ Buffer* buffer,
+ GLintptr offset,
+ GLsizeiptr size,
+ const GLvoid* data) {
+ if (!buffer->SetRange(offset, size, data)) {
+ decoder->SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
+ return;
+ }
+
+ if (!buffer->IsClientSideArray()) {
+ glBufferSubData(buffer->target(), offset, size, data);
+ }
+}
+
bool BufferManager::SetTarget(Buffer* info, GLenum target) {
// Check that we are not trying to bind it to a different target.
if (info->target() != 0 && info->target() != target &&
diff --git a/gpu/command_buffer/service/buffer_manager.h b/gpu/command_buffer/service/buffer_manager.h
index e9ea2f7..0d99e9b 100644
--- a/gpu/command_buffer/service/buffer_manager.h
+++ b/gpu/command_buffer/service/buffer_manager.h
@@ -19,6 +19,8 @@ namespace gpu {
namespace gles2 {
class BufferManager;
+class FeatureInfo;
+class GLES2Decoder;
// Info about Buffers currently in the system.
class GPU_EXPORT Buffer : public base::RefCounted<Buffer> {
@@ -29,6 +31,10 @@ class GPU_EXPORT Buffer : public base::RefCounted<Buffer> {
return service_id_;
}
+ GLenum target() const {
+ return target_;
+ }
+
GLsizeiptr size() const {
return size_;
}
@@ -37,11 +43,6 @@ class GPU_EXPORT Buffer : public base::RefCounted<Buffer> {
return usage_;
}
- // Sets a range of data for this buffer. Returns false if the offset or size
- // is out of range.
- bool SetRange(
- GLintptr offset, GLsizeiptr size, const GLvoid * data);
-
// Gets the maximum value in the buffer for the given range interpreted as
// the given type. Returns false if offset and count are out of range.
// offset is in bytes.
@@ -60,6 +61,10 @@ class GPU_EXPORT Buffer : public base::RefCounted<Buffer> {
return target() && !IsDeleted();
}
+ bool IsClientSideArray() const {
+ return is_client_side_array_;
+ }
+
private:
friend class BufferManager;
friend class BufferManagerTestBase;
@@ -95,10 +100,6 @@ class GPU_EXPORT Buffer : public base::RefCounted<Buffer> {
~Buffer();
- GLenum target() const {
- return target_;
- }
-
void set_target(GLenum target) {
DCHECK_EQ(target_, 0u); // you can only set this once.
target_ = target;
@@ -112,7 +113,16 @@ class GPU_EXPORT Buffer : public base::RefCounted<Buffer> {
deleted_ = true;
}
- void SetInfo(GLsizeiptr size, GLenum usage, bool shadow);
+ // Sets the size, usage and initial data of a buffer.
+ // If shadow is true then if data is NULL buffer will be initialized to 0.
+ void SetInfo(
+ GLsizeiptr size, GLenum usage, bool shadow, const GLvoid* data,
+ bool is_client_side_array);
+
+ // Sets a range of data for this buffer. Returns false if the offset or size
+ // is out of range.
+ bool SetRange(
+ GLintptr offset, GLsizeiptr size, const GLvoid * data);
// Clears any cache of index ranges.
void ClearCache();
@@ -143,6 +153,10 @@ class GPU_EXPORT Buffer : public base::RefCounted<Buffer> {
// Whether or not the data is shadowed.
bool shadowed_;
+ // Whether or not this Buffer is not uploaded to the GPU but just
+ // sitting in local memory.
+ bool is_client_side_array_;
+
// A copy of the data in the buffer. This data is only kept if the target
// is backed_ = true.
scoped_array<int8> shadow_;
@@ -159,7 +173,7 @@ class GPU_EXPORT Buffer : public base::RefCounted<Buffer> {
// shared by multiple GLES2Decoders.
class GPU_EXPORT BufferManager {
public:
- BufferManager(MemoryTracker* memory_tracker);
+ BufferManager(MemoryTracker* memory_tracker, FeatureInfo* feature_info);
~BufferManager();
// Must call before destruction.
@@ -177,8 +191,22 @@ class GPU_EXPORT BufferManager {
// Gets a client id for a given service id.
bool GetClientId(GLuint service_id, GLuint* client_id) const;
- // Sets the size and usage of a buffer.
- void SetInfo(Buffer* info, GLsizeiptr size, GLenum usage);
+ // Does a glBufferData and updates the approprate accounting. Currently
+ // assume the values have already been validated.
+ void DoBufferData(
+ GLES2Decoder* decoder,
+ Buffer* buffer,
+ GLsizeiptr size,
+ GLenum usage,
+ const GLvoid* data);
+
+ // Does a glBufferSubData and updates the approrate accounting.
+ void DoBufferSubData(
+ GLES2Decoder* decoder,
+ Buffer* buffer,
+ GLintptr offset,
+ GLsizeiptr size,
+ const GLvoid* data);
// Sets the target of a buffer. Returns false if the target can not be set.
bool SetTarget(Buffer* info, GLenum target);
@@ -191,12 +219,20 @@ class GPU_EXPORT BufferManager {
return memory_tracker_->GetMemRepresented();
}
+ // Tell's for a given usage if this would be a client side array.
+ bool IsUsageClientSideArray(GLenum usage);
+
private:
friend class Buffer;
void StartTracking(Buffer* info);
void StopTracking(Buffer* info);
+ // Sets the size, usage and initial data of a buffer.
+ // If data is NULL buffer will be initialized to 0 if shadowed.
+ void SetInfo(Buffer* info, GLsizeiptr size, GLenum usage, const GLvoid* data);
+
scoped_ptr<MemoryTypeTracker> memory_tracker_;
+ scoped_refptr<FeatureInfo> feature_info_;
// Info for each buffer in the system.
typedef base::hash_map<GLuint, scoped_refptr<Buffer> > BufferInfoMap;
@@ -210,6 +246,7 @@ class GPU_EXPORT BufferManager {
unsigned int buffer_info_count_;
bool have_context_;
+ bool use_client_side_arrays_for_stream_buffers_;
DISALLOW_COPY_AND_ASSIGN(BufferManager);
};
diff --git a/gpu/command_buffer/service/buffer_manager_unittest.cc b/gpu/command_buffer/service/buffer_manager_unittest.cc
index e782e7f..65dd7ed 100644
--- a/gpu/command_buffer/service/buffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/buffer_manager_unittest.cc
@@ -3,10 +3,15 @@
// found in the LICENSE file.
#include "gpu/command_buffer/service/buffer_manager.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/command_buffer/service/test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_mock.h"
+using ::testing::_;
+using ::testing::Return;
using ::testing::StrictMock;
namespace gpu {
@@ -14,32 +19,73 @@ namespace gles2 {
class BufferManagerTestBase : public testing::Test {
protected:
- void SetUpBase(MemoryTracker* memory_tracker) {
+ void SetUpBase(
+ MemoryTracker* memory_tracker,
+ FeatureInfo* feature_info,
+ const char* extensions,
+ const char* vendor,
+ const char* renderer) {
gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
::gfx::GLInterface::SetGLInterface(gl_.get());
- manager_.reset(new BufferManager(memory_tracker));
+ if (feature_info) {
+ TestHelper::SetupFeatureInfoInitExpectationsWithVendor(
+ gl_.get(), extensions, vendor, renderer);
+ feature_info->Initialize(NULL);
+ }
+ decoder_.reset(new MockGLES2Decoder());
+ manager_.reset(new BufferManager(memory_tracker, feature_info));
}
virtual void TearDown() {
manager_->Destroy(false);
manager_.reset();
::gfx::GLInterface::SetGLInterface(NULL);
+ decoder_.reset();
gl_.reset();
}
- GLenum GetTarget(const Buffer* info) const {
- return info->target();
+ GLenum GetTarget(const Buffer* buffer) const {
+ return buffer->target();
+ }
+
+ void DoBufferData(
+ Buffer* buffer, GLsizeiptr size, GLenum usage, const GLvoid* data,
+ GLenum error) {
+ TestHelper::DoBufferData(
+ gl_.get(), decoder_.get(), manager_.get(),
+ buffer, size, usage, data, error);
+ }
+
+ bool DoBufferSubData(
+ Buffer* buffer, GLintptr offset, GLsizeiptr size,
+ const GLvoid* data) {
+ bool success = true;
+ if (!buffer->CheckRange(offset, size)) {
+ EXPECT_CALL(*decoder_, SetGLError(GL_INVALID_VALUE, _, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ success = false;
+ } else if (!buffer->IsClientSideArray()) {
+ EXPECT_CALL(*gl_, BufferSubData(
+ buffer->target(), offset, size, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ manager_->DoBufferSubData(
+ decoder_.get(), buffer, offset, size, data);
+ return success;
}
// Use StrictMock to make 100% sure we know how GL will be called.
scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
scoped_ptr<BufferManager> manager_;
+ scoped_ptr<MockGLES2Decoder> decoder_;
};
class BufferManagerTest : public BufferManagerTestBase {
protected:
virtual void SetUp() {
- SetUpBase(NULL);
+ SetUpBase(NULL, NULL, "", "", "");
}
};
@@ -47,12 +93,22 @@ class BufferManagerMemoryTrackerTest : public BufferManagerTestBase {
protected:
virtual void SetUp() {
mock_memory_tracker_ = new StrictMock<MockMemoryTracker>();
- SetUpBase(mock_memory_tracker_.get());
+ SetUpBase(mock_memory_tracker_.get(), NULL, "", "", "");
}
scoped_refptr<MockMemoryTracker> mock_memory_tracker_;
};
+class BufferManagerClientSideArraysTest : public BufferManagerTestBase {
+ protected:
+ virtual void SetUp() {
+ feature_info_ = new FeatureInfo();
+ SetUpBase(NULL, feature_info_.get(), "", "Imagination Technologies", "");
+ }
+
+ scoped_refptr<FeatureInfo> feature_info_;
+};
+
#define EXPECT_MEMORY_ALLOCATION_CHANGE(old_size, new_size, pool) \
EXPECT_CALL(*mock_memory_tracker_, \
TrackMemoryAllocatedChange(old_size, new_size, pool)) \
@@ -67,22 +123,23 @@ TEST_F(BufferManagerTest, Basic) {
// Check we can create buffer.
manager_->CreateBuffer(kClientBuffer1Id, kServiceBuffer1Id);
// Check buffer got created.
- Buffer* info1 = manager_->GetBuffer(kClientBuffer1Id);
- ASSERT_TRUE(info1 != NULL);
- EXPECT_EQ(0u, GetTarget(info1));
- EXPECT_EQ(0, info1->size());
- EXPECT_EQ(static_cast<GLenum>(GL_STATIC_DRAW), info1->usage());
- EXPECT_FALSE(info1->IsDeleted());
- EXPECT_EQ(kServiceBuffer1Id, info1->service_id());
+ Buffer* buffer1 = manager_->GetBuffer(kClientBuffer1Id);
+ ASSERT_TRUE(buffer1 != NULL);
+ EXPECT_EQ(0u, GetTarget(buffer1));
+ EXPECT_EQ(0, buffer1->size());
+ EXPECT_EQ(static_cast<GLenum>(GL_STATIC_DRAW), buffer1->usage());
+ EXPECT_FALSE(buffer1->IsDeleted());
+ EXPECT_FALSE(buffer1->IsClientSideArray());
+ EXPECT_EQ(kServiceBuffer1Id, buffer1->service_id());
GLuint client_id = 0;
- EXPECT_TRUE(manager_->GetClientId(info1->service_id(), &client_id));
+ EXPECT_TRUE(manager_->GetClientId(buffer1->service_id(), &client_id));
EXPECT_EQ(kClientBuffer1Id, client_id);
- manager_->SetTarget(info1, GL_ELEMENT_ARRAY_BUFFER);
- EXPECT_EQ(static_cast<GLenum>(GL_ELEMENT_ARRAY_BUFFER), GetTarget(info1));
+ manager_->SetTarget(buffer1, GL_ELEMENT_ARRAY_BUFFER);
+ EXPECT_EQ(static_cast<GLenum>(GL_ELEMENT_ARRAY_BUFFER), GetTarget(buffer1));
// Check we and set its size.
- manager_->SetInfo(info1, kBuffer1Size, GL_DYNAMIC_DRAW);
- EXPECT_EQ(kBuffer1Size, info1->size());
- EXPECT_EQ(static_cast<GLenum>(GL_DYNAMIC_DRAW), info1->usage());
+ DoBufferData(buffer1, kBuffer1Size, GL_DYNAMIC_DRAW, NULL, GL_NO_ERROR);
+ EXPECT_EQ(kBuffer1Size, buffer1->size());
+ EXPECT_EQ(static_cast<GLenum>(GL_DYNAMIC_DRAW), buffer1->usage());
// Check we get nothing for a non-existent buffer.
EXPECT_TRUE(manager_->GetBuffer(kClientBuffer2Id) == NULL);
// Check trying to a remove non-existent buffers does not crash.
@@ -105,15 +162,15 @@ TEST_F(BufferManagerMemoryTrackerTest, Basic) {
EXPECT_MEMORY_ALLOCATION_CHANGE(0, 0, MemoryTracker::kManaged);
manager_->CreateBuffer(kClientBuffer1Id, kServiceBuffer1Id);
// Check buffer got created.
- Buffer* info1 = manager_->GetBuffer(kClientBuffer1Id);
- ASSERT_TRUE(info1 != NULL);
- manager_->SetTarget(info1, GL_ELEMENT_ARRAY_BUFFER);
+ Buffer* buffer1 = manager_->GetBuffer(kClientBuffer1Id);
+ ASSERT_TRUE(buffer1 != NULL);
+ manager_->SetTarget(buffer1, GL_ELEMENT_ARRAY_BUFFER);
// Check we and set its size.
EXPECT_MEMORY_ALLOCATION_CHANGE(0, kBuffer1Size1, MemoryTracker::kManaged);
- manager_->SetInfo(info1, kBuffer1Size1, GL_DYNAMIC_DRAW);
+ DoBufferData(buffer1, kBuffer1Size1, GL_DYNAMIC_DRAW, NULL, GL_NO_ERROR);
EXPECT_MEMORY_ALLOCATION_CHANGE(kBuffer1Size1, 0, MemoryTracker::kManaged);
EXPECT_MEMORY_ALLOCATION_CHANGE(0, kBuffer1Size2, MemoryTracker::kManaged);
- manager_->SetInfo(info1, kBuffer1Size2, GL_DYNAMIC_DRAW);
+ DoBufferData(buffer1, kBuffer1Size2, GL_DYNAMIC_DRAW, NULL, GL_NO_ERROR);
// On delete it will get freed.
EXPECT_MEMORY_ALLOCATION_CHANGE(kBuffer1Size2, 0, MemoryTracker::kManaged);
}
@@ -124,38 +181,37 @@ TEST_F(BufferManagerTest, Destroy) {
// Check we can create buffer.
manager_->CreateBuffer(kClient1Id, kService1Id);
// Check buffer got created.
- Buffer* info1 =
- manager_->GetBuffer(kClient1Id);
- ASSERT_TRUE(info1 != NULL);
+ Buffer* buffer1 = manager_->GetBuffer(kClient1Id);
+ ASSERT_TRUE(buffer1 != NULL);
EXPECT_CALL(*gl_, DeleteBuffersARB(1, ::testing::Pointee(kService1Id)))
.Times(1)
.RetiresOnSaturation();
manager_->Destroy(true);
// Check the resources were released.
- info1 = manager_->GetBuffer(kClient1Id);
- ASSERT_TRUE(info1 == NULL);
+ buffer1 = manager_->GetBuffer(kClient1Id);
+ ASSERT_TRUE(buffer1 == NULL);
}
-TEST_F(BufferManagerTest, SetRange) {
+TEST_F(BufferManagerTest, DoBufferSubData) {
const GLuint kClientBufferId = 1;
const GLuint kServiceBufferId = 11;
const uint8 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
manager_->CreateBuffer(kClientBufferId, kServiceBufferId);
- Buffer* info = manager_->GetBuffer(kClientBufferId);
- ASSERT_TRUE(info != NULL);
- manager_->SetTarget(info, GL_ELEMENT_ARRAY_BUFFER);
- manager_->SetInfo(info, sizeof(data), GL_STATIC_DRAW);
- EXPECT_TRUE(info->SetRange(0, sizeof(data), data));
- EXPECT_TRUE(info->SetRange(sizeof(data), 0, data));
- EXPECT_FALSE(info->SetRange(sizeof(data), 1, data));
- EXPECT_FALSE(info->SetRange(0, sizeof(data) + 1, data));
- EXPECT_FALSE(info->SetRange(-1, sizeof(data), data));
- EXPECT_FALSE(info->SetRange(0, -1, data));
- manager_->SetInfo(info, 1, GL_STATIC_DRAW);
+ Buffer* buffer = manager_->GetBuffer(kClientBufferId);
+ ASSERT_TRUE(buffer != NULL);
+ manager_->SetTarget(buffer, GL_ELEMENT_ARRAY_BUFFER);
+ DoBufferData(buffer, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR);
+ EXPECT_TRUE(DoBufferSubData(buffer, 0, sizeof(data), data));
+ EXPECT_TRUE(DoBufferSubData(buffer, sizeof(data), 0, data));
+ EXPECT_FALSE(DoBufferSubData(buffer, sizeof(data), 1, data));
+ EXPECT_FALSE(DoBufferSubData(buffer, 0, sizeof(data) + 1, data));
+ EXPECT_FALSE(DoBufferSubData(buffer, -1, sizeof(data), data));
+ EXPECT_FALSE(DoBufferSubData(buffer, 0, -1, data));
+ DoBufferData(buffer, 1, GL_STATIC_DRAW, NULL, GL_NO_ERROR);
const int size = 0x20000;
scoped_array<uint8> temp(new uint8[size]);
- EXPECT_FALSE(info->SetRange(0 - size, size, temp.get()));
- EXPECT_FALSE(info->SetRange(1, size / 2, temp.get()));
+ EXPECT_FALSE(DoBufferSubData(buffer, 0 - size, size, temp.get()));
+ EXPECT_FALSE(DoBufferSubData(buffer, 1, size / 2, temp.get()));
}
TEST_F(BufferManagerTest, GetRange) {
@@ -163,23 +219,24 @@ TEST_F(BufferManagerTest, GetRange) {
const GLuint kServiceBufferId = 11;
const uint8 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
manager_->CreateBuffer(kClientBufferId, kServiceBufferId);
- Buffer* info = manager_->GetBuffer(kClientBufferId);
- ASSERT_TRUE(info != NULL);
- manager_->SetTarget(info, GL_ELEMENT_ARRAY_BUFFER);
- manager_->SetInfo(info, sizeof(data), GL_STATIC_DRAW);
- const char* buf = static_cast<const char*>(info->GetRange(0, sizeof(data)));
+ Buffer* buffer = manager_->GetBuffer(kClientBufferId);
+ ASSERT_TRUE(buffer != NULL);
+ manager_->SetTarget(buffer, GL_ELEMENT_ARRAY_BUFFER);
+ DoBufferData(buffer, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR);
+ const char* buf =
+ static_cast<const char*>(buffer->GetRange(0, sizeof(data)));
ASSERT_TRUE(buf != NULL);
const char* buf1 =
- static_cast<const char*>(info->GetRange(1, sizeof(data) - 1));
+ static_cast<const char*>(buffer->GetRange(1, sizeof(data) - 1));
EXPECT_EQ(buf + 1, buf1);
- EXPECT_TRUE(info->GetRange(sizeof(data), 1) == NULL);
- EXPECT_TRUE(info->GetRange(0, sizeof(data) + 1) == NULL);
- EXPECT_TRUE(info->GetRange(-1, sizeof(data)) == NULL);
- EXPECT_TRUE(info->GetRange(-0, -1) == NULL);
+ EXPECT_TRUE(buffer->GetRange(sizeof(data), 1) == NULL);
+ EXPECT_TRUE(buffer->GetRange(0, sizeof(data) + 1) == NULL);
+ EXPECT_TRUE(buffer->GetRange(-1, sizeof(data)) == NULL);
+ EXPECT_TRUE(buffer->GetRange(-0, -1) == NULL);
const int size = 0x20000;
- manager_->SetInfo(info, size / 2, GL_STATIC_DRAW);
- EXPECT_TRUE(info->GetRange(0 - size, size) == NULL);
- EXPECT_TRUE(info->GetRange(1, size / 2) == NULL);
+ DoBufferData(buffer, size / 2, GL_STATIC_DRAW, NULL, GL_NO_ERROR);
+ EXPECT_TRUE(buffer->GetRange(0 - size, size) == NULL);
+ EXPECT_TRUE(buffer->GetRange(1, size / 2) == NULL);
}
TEST_F(BufferManagerTest, GetMaxValueForRangeUint8) {
@@ -188,28 +245,34 @@ TEST_F(BufferManagerTest, GetMaxValueForRangeUint8) {
const uint8 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
const uint8 new_data[] = {100, 120, 110};
manager_->CreateBuffer(kClientBufferId, kServiceBufferId);
- Buffer* info = manager_->GetBuffer(kClientBufferId);
- ASSERT_TRUE(info != NULL);
- manager_->SetTarget(info, GL_ELEMENT_ARRAY_BUFFER);
- manager_->SetInfo(info, sizeof(data), GL_STATIC_DRAW);
- EXPECT_TRUE(info->SetRange(0, sizeof(data), data));
+ Buffer* buffer = manager_->GetBuffer(kClientBufferId);
+ ASSERT_TRUE(buffer != NULL);
+ manager_->SetTarget(buffer, GL_ELEMENT_ARRAY_BUFFER);
+ DoBufferData(buffer, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR);
+ EXPECT_TRUE(DoBufferSubData(buffer, 0, sizeof(data), data));
GLuint max_value;
// Check entire range succeeds.
- EXPECT_TRUE(info->GetMaxValueForRange(0, 10, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 0, 10, GL_UNSIGNED_BYTE, &max_value));
EXPECT_EQ(10u, max_value);
// Check sub range succeeds.
- EXPECT_TRUE(info->GetMaxValueForRange(4, 3, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 4, 3, GL_UNSIGNED_BYTE, &max_value));
EXPECT_EQ(6u, max_value);
// Check changing sub range succeeds.
- EXPECT_TRUE(info->SetRange(4, sizeof(new_data), new_data));
- EXPECT_TRUE(info->GetMaxValueForRange(4, 3, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_TRUE(DoBufferSubData(buffer, 4, sizeof(new_data), new_data));
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 4, 3, GL_UNSIGNED_BYTE, &max_value));
EXPECT_EQ(120u, max_value);
max_value = 0;
- EXPECT_TRUE(info->GetMaxValueForRange(0, 10, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 0, 10, GL_UNSIGNED_BYTE, &max_value));
EXPECT_EQ(120u, max_value);
// Check out of range fails.
- EXPECT_FALSE(info->GetMaxValueForRange(0, 11, GL_UNSIGNED_BYTE, &max_value));
- EXPECT_FALSE(info->GetMaxValueForRange(10, 1, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_FALSE(buffer->GetMaxValueForRange(
+ 0, 11, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_FALSE(buffer->GetMaxValueForRange(
+ 10, 1, GL_UNSIGNED_BYTE, &max_value));
}
TEST_F(BufferManagerTest, GetMaxValueForRangeUint16) {
@@ -218,30 +281,37 @@ TEST_F(BufferManagerTest, GetMaxValueForRangeUint16) {
const uint16 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
const uint16 new_data[] = {100, 120, 110};
manager_->CreateBuffer(kClientBufferId, kServiceBufferId);
- Buffer* info = manager_->GetBuffer(kClientBufferId);
- ASSERT_TRUE(info != NULL);
- manager_->SetTarget(info, GL_ELEMENT_ARRAY_BUFFER);
- manager_->SetInfo(info, sizeof(data), GL_STATIC_DRAW);
- EXPECT_TRUE(info->SetRange(0, sizeof(data), data));
+ Buffer* buffer = manager_->GetBuffer(kClientBufferId);
+ ASSERT_TRUE(buffer != NULL);
+ manager_->SetTarget(buffer, GL_ELEMENT_ARRAY_BUFFER);
+ DoBufferData(buffer, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR);
+ EXPECT_TRUE(DoBufferSubData(buffer, 0, sizeof(data), data));
GLuint max_value;
// Check entire range succeeds.
- EXPECT_TRUE(info->GetMaxValueForRange(0, 10, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 0, 10, GL_UNSIGNED_SHORT, &max_value));
EXPECT_EQ(10u, max_value);
// Check odd offset fails for GL_UNSIGNED_SHORT.
- EXPECT_FALSE(info->GetMaxValueForRange(1, 10, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_FALSE(buffer->GetMaxValueForRange(
+ 1, 10, GL_UNSIGNED_SHORT, &max_value));
// Check sub range succeeds.
- EXPECT_TRUE(info->GetMaxValueForRange(8, 3, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 8, 3, GL_UNSIGNED_SHORT, &max_value));
EXPECT_EQ(6u, max_value);
// Check changing sub range succeeds.
- EXPECT_TRUE(info->SetRange(8, sizeof(new_data), new_data));
- EXPECT_TRUE(info->GetMaxValueForRange(8, 3, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_TRUE(DoBufferSubData(buffer, 8, sizeof(new_data), new_data));
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 8, 3, GL_UNSIGNED_SHORT, &max_value));
EXPECT_EQ(120u, max_value);
max_value = 0;
- EXPECT_TRUE(info->GetMaxValueForRange(0, 10, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 0, 10, GL_UNSIGNED_SHORT, &max_value));
EXPECT_EQ(120u, max_value);
// Check out of range fails.
- EXPECT_FALSE(info->GetMaxValueForRange(0, 11, GL_UNSIGNED_SHORT, &max_value));
- EXPECT_FALSE(info->GetMaxValueForRange(20, 1, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_FALSE(buffer->GetMaxValueForRange(
+ 0, 11, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_FALSE(buffer->GetMaxValueForRange(
+ 20, 1, GL_UNSIGNED_SHORT, &max_value));
}
TEST_F(BufferManagerTest, GetMaxValueForRangeUint32) {
@@ -250,32 +320,38 @@ TEST_F(BufferManagerTest, GetMaxValueForRangeUint32) {
const uint32 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
const uint32 new_data[] = {100, 120, 110};
manager_->CreateBuffer(kClientBufferId, kServiceBufferId);
- Buffer* info = manager_->GetBuffer(kClientBufferId);
- ASSERT_TRUE(info != NULL);
- manager_->SetTarget(info, GL_ELEMENT_ARRAY_BUFFER);
- manager_->SetInfo(info, sizeof(data), GL_STATIC_DRAW);
- EXPECT_TRUE(info->SetRange(0, sizeof(data), data));
+ Buffer* buffer = manager_->GetBuffer(kClientBufferId);
+ ASSERT_TRUE(buffer != NULL);
+ manager_->SetTarget(buffer, GL_ELEMENT_ARRAY_BUFFER);
+ DoBufferData(buffer, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR);
+ EXPECT_TRUE(DoBufferSubData(buffer, 0, sizeof(data), data));
GLuint max_value;
// Check entire range succeeds.
- EXPECT_TRUE(info->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, &max_value));
+ EXPECT_TRUE(
+ buffer->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, &max_value));
EXPECT_EQ(10u, max_value);
// Check non aligned offsets fails for GL_UNSIGNED_INT.
- EXPECT_FALSE(info->GetMaxValueForRange(1, 10, GL_UNSIGNED_INT, &max_value));
- EXPECT_FALSE(info->GetMaxValueForRange(2, 10, GL_UNSIGNED_INT, &max_value));
- EXPECT_FALSE(info->GetMaxValueForRange(3, 10, GL_UNSIGNED_INT, &max_value));
+ EXPECT_FALSE(
+ buffer->GetMaxValueForRange(1, 10, GL_UNSIGNED_INT, &max_value));
+ EXPECT_FALSE(
+ buffer->GetMaxValueForRange(2, 10, GL_UNSIGNED_INT, &max_value));
+ EXPECT_FALSE(
+ buffer->GetMaxValueForRange(3, 10, GL_UNSIGNED_INT, &max_value));
// Check sub range succeeds.
- EXPECT_TRUE(info->GetMaxValueForRange(16, 3, GL_UNSIGNED_INT, &max_value));
+ EXPECT_TRUE(buffer->GetMaxValueForRange(16, 3, GL_UNSIGNED_INT, &max_value));
EXPECT_EQ(6u, max_value);
// Check changing sub range succeeds.
- EXPECT_TRUE(info->SetRange(16, sizeof(new_data), new_data));
- EXPECT_TRUE(info->GetMaxValueForRange(16, 3, GL_UNSIGNED_INT, &max_value));
+ EXPECT_TRUE(DoBufferSubData(buffer, 16, sizeof(new_data), new_data));
+ EXPECT_TRUE(buffer->GetMaxValueForRange(16, 3, GL_UNSIGNED_INT, &max_value));
EXPECT_EQ(120u, max_value);
max_value = 0;
- EXPECT_TRUE(info->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, &max_value));
+ EXPECT_TRUE(buffer->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, &max_value));
EXPECT_EQ(120u, max_value);
// Check out of range fails.
- EXPECT_FALSE(info->GetMaxValueForRange(0, 11, GL_UNSIGNED_INT, &max_value));
- EXPECT_FALSE(info->GetMaxValueForRange(40, 1, GL_UNSIGNED_INT, &max_value));
+ EXPECT_FALSE(
+ buffer->GetMaxValueForRange(0, 11, GL_UNSIGNED_INT, &max_value));
+ EXPECT_FALSE(
+ buffer->GetMaxValueForRange(40, 1, GL_UNSIGNED_INT, &max_value));
}
TEST_F(BufferManagerTest, UseDeletedBuffer) {
@@ -283,19 +359,34 @@ TEST_F(BufferManagerTest, UseDeletedBuffer) {
const GLuint kServiceBufferId = 11;
const uint32 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
manager_->CreateBuffer(kClientBufferId, kServiceBufferId);
- scoped_refptr<Buffer> info =
- manager_->GetBuffer(kClientBufferId);
- ASSERT_TRUE(info != NULL);
- manager_->SetTarget(info, GL_ARRAY_BUFFER);
+ scoped_refptr<Buffer> buffer = manager_->GetBuffer(kClientBufferId);
+ ASSERT_TRUE(buffer != NULL);
+ manager_->SetTarget(buffer, GL_ARRAY_BUFFER);
// Remove buffer
manager_->RemoveBuffer(kClientBufferId);
// Use it after removing
- manager_->SetInfo(info, sizeof(data), GL_STATIC_DRAW);
+ DoBufferData(buffer, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR);
// Check that it gets deleted when the last reference is released.
EXPECT_CALL(*gl_, DeleteBuffersARB(1, ::testing::Pointee(kServiceBufferId)))
.Times(1)
.RetiresOnSaturation();
- info = NULL;
+ buffer = NULL;
+}
+
+// Test buffers get shadowed when they are supposed to be.
+TEST_F(BufferManagerClientSideArraysTest, StreamBuffersAreShadowed) {
+ const GLuint kClientBufferId = 1;
+ const GLuint kServiceBufferId = 11;
+ static const uint32 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ manager_->CreateBuffer(kClientBufferId, kServiceBufferId);
+ Buffer* buffer = manager_->GetBuffer(kClientBufferId);
+ ASSERT_TRUE(buffer != NULL);
+ manager_->SetTarget(buffer, GL_ARRAY_BUFFER);
+ DoBufferData(buffer, sizeof(data), GL_STREAM_DRAW, data, GL_NO_ERROR);
+ EXPECT_TRUE(buffer->IsClientSideArray());
+ EXPECT_EQ(0, memcmp(data, buffer->GetRange(0, sizeof(data)), sizeof(data)));
+ DoBufferData(buffer, sizeof(data), GL_DYNAMIC_DRAW, data, GL_NO_ERROR);
+ EXPECT_FALSE(buffer->IsClientSideArray());
}
} // namespace gles2
diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc
index abf262d..9f893e4 100644
--- a/gpu/command_buffer/service/context_group.cc
+++ b/gpu/command_buffer/service/context_group.cc
@@ -100,7 +100,8 @@ bool ContextGroup::Initialize(
glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
}
- buffer_manager_.reset(new BufferManager(memory_tracker_));
+ buffer_manager_.reset(new BufferManager(
+ memory_tracker_, feature_info_.get()));
framebuffer_manager_.reset(new FramebufferManager());
renderbuffer_manager_.reset(new RenderbufferManager(memory_tracker_,
max_renderbuffer_size,
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index bde9f3e..3a60942 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -94,6 +94,7 @@ FeatureInfo::Workarounds::Workarounds()
restore_scissor_on_fbo_change(false),
flush_on_context_switch(false),
delete_instead_of_resize_fbo(false),
+ use_client_side_arrays_for_stream_buffers(false),
max_texture_size(0),
max_cube_map_texture_size(0) {
}
@@ -168,6 +169,7 @@ void FeatureInfo::AddFeatures() {
bool is_mesa = false;
bool is_qualcomm = false;
bool is_imagination = false;
+ bool is_arm = false;
for (size_t ii = 0; ii < arraysize(string_ids); ++ii) {
const char* str = reinterpret_cast<const char*>(
glGetString(string_ids[ii]));
@@ -180,6 +182,7 @@ void FeatureInfo::AddFeatures() {
is_mesa |= string_set.Contains("mesa");
is_qualcomm |= string_set.Contains("qualcomm");
is_imagination |= string_set.Contains("imagination");
+ is_arm |= string_set.Contains("arm");
}
}
@@ -191,7 +194,6 @@ void FeatureInfo::AddFeatures() {
!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableShaderNameHashing);
-
bool npot_ok = false;
AddExtensionString("GL_ANGLE_translated_shader_source");
@@ -337,6 +339,19 @@ void FeatureInfo::AddFeatures() {
feature_flags_.native_vertex_array_object = true;
}
+ // If the driver doesn't like uploading lots of buffer data constantly
+ // work around it by using client side arrays.
+ if (is_arm || is_imagination) {
+ workarounds_.use_client_side_arrays_for_stream_buffers = true;
+ }
+
+ // If we're using client_side_arrays we have to emulate
+ // vertex array objects since vertex array objects do not work
+ // with client side arrays.
+ if (workarounds_.use_client_side_arrays_for_stream_buffers) {
+ feature_flags_.native_vertex_array_object = false;
+ }
+
if (extensions.Contains("GL_OES_element_index_uint") ||
gfx::HasDesktopGLFeatures()) {
AddExtensionString("GL_OES_element_index_uint");
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index 2eec536..88f0671 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -54,6 +54,7 @@ class GPU_EXPORT FeatureInfo : public base::RefCounted<FeatureInfo> {
bool restore_scissor_on_fbo_change;
bool flush_on_context_switch;
bool delete_instead_of_resize_fbo;
+ bool use_client_side_arrays_for_stream_buffers;
// Note: 0 here means use driver limit.
GLint max_texture_size;
diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc
index 0edaa78..bf716ff 100644
--- a/gpu/command_buffer/service/feature_info_unittest.cc
+++ b/gpu/command_buffer/service/feature_info_unittest.cc
@@ -95,6 +95,7 @@ TEST_F(FeatureInfoTest, Basic) {
EXPECT_FALSE(info_->workarounds().clear_alpha_in_readpixels);
EXPECT_EQ(0, info_->workarounds().max_texture_size);
EXPECT_EQ(0, info_->workarounds().max_cube_map_texture_size);
+ EXPECT_FALSE(info_->workarounds().use_client_side_arrays_for_stream_buffers);
// Test good types.
{
@@ -799,5 +800,35 @@ TEST_F(FeatureInfoTest, InitializeOES_element_index_uint) {
EXPECT_TRUE(info_->validators()->index_type.IsValid(GL_UNSIGNED_INT));
}
+TEST_F(FeatureInfoTest, InitializeARM) {
+ SetupInitExpectationsWithVendor("", "ARM", "MAli-T604");
+ info_->Initialize(NULL);
+ EXPECT_TRUE(info_->workarounds().use_client_side_arrays_for_stream_buffers);
+}
+
+TEST_F(FeatureInfoTest, InitializeImagination) {
+ SetupInitExpectationsWithVendor(
+ "", "Imagination Techologies", "PowerVR SGX 540");
+ info_->Initialize(NULL);
+ EXPECT_TRUE(info_->workarounds().use_client_side_arrays_for_stream_buffers);
+ EXPECT_FALSE(info_->feature_flags().native_vertex_array_object);
+}
+
+TEST_F(FeatureInfoTest, InitializeARMVAOs) {
+ SetupInitExpectationsWithVendor(
+ "GL_OES_vertex_array_object", "ARM", "MAli-T604");
+ info_->Initialize(NULL);
+ EXPECT_TRUE(info_->workarounds().use_client_side_arrays_for_stream_buffers);
+ EXPECT_FALSE(info_->feature_flags().native_vertex_array_object);
+}
+
+TEST_F(FeatureInfoTest, InitializeImaginationVAOs) {
+ SetupInitExpectationsWithVendor(
+ "GL_OES_vertex_array_object",
+ "Imagination Techologies", "PowerVR SGX 540");
+ info_->Initialize(NULL);
+ EXPECT_TRUE(info_->workarounds().use_client_side_arrays_for_stream_buffers);
+}
+
} // namespace gles2
} // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index ed17725..1fe3cfc 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1233,6 +1233,10 @@ class GLES2DecoderImpl : public GLES2Decoder {
GLuint DoGetMaxValueInBufferCHROMIUM(
GLuint buffer_id, GLsizei count, GLenum type, GLuint offset);
+ // Wrapper for glGetBufferParameteriv.
+ void DoGetBufferParameteriv(
+ GLenum target, GLenum pname, GLint* params);
+
// Wrapper for glGetProgramiv.
void DoGetProgramiv(
GLuint program_id, GLenum pname, GLint* params);
@@ -4313,6 +4317,27 @@ void GLES2DecoderImpl::DoGetProgramiv(
info->GetProgramiv(pname, params);
}
+void GLES2DecoderImpl::DoGetBufferParameteriv(
+ GLenum target, GLenum pname, GLint* params) {
+ Buffer* buffer = GetBufferInfoForTarget(target);
+ if (!buffer) {
+ SetGLError(
+ GL_INVALID_OPERATION, "glGetBufferParameteriv",
+ "no buffer bound for target");
+ return;
+ }
+ switch (pname) {
+ case GL_BUFFER_SIZE:
+ *params = buffer->size();
+ break;
+ case GL_BUFFER_USAGE:
+ *params = buffer->usage();
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
void GLES2DecoderImpl::DoBindAttribLocation(
GLuint program, GLuint index, const char* name) {
if (!StringIsValidForGLES(name)) {
@@ -5737,54 +5762,13 @@ bool GLES2DecoderImpl::IsDrawValid(
return false;
}
- // true if any enabled, used divisor is zero
- bool divisor0 = false;
- // Validate all attribs currently enabled. If they are used by the current
- // program then check that they have enough elements to handle the draw call.
- // If they are not used by the current program check that they have a buffer
- // assigned.
- const VertexAttribManager::VertexAttribInfoList& infos =
- state_.vertex_attrib_manager->GetEnabledVertexAttribInfos();
- for (VertexAttribManager::VertexAttribInfoList::const_iterator it =
- infos.begin(); it != infos.end(); ++it) {
- const VertexAttrib* info = *it;
- const Program::VertexAttrib* attrib_info =
- state_.current_program->GetAttribInfoByLocation(info->index());
- if (attrib_info) {
- divisor0 |= (info->divisor() == 0);
- GLuint count = info->MaxVertexAccessed(primcount, max_vertex_accessed);
- // This attrib is used in the current program.
- if (!info->CanAccess(count)) {
- SetGLError(
- GL_INVALID_OPERATION, function_name,
- (std::string(
- "attempt to access out of range vertices in attribute ") +
- base::IntToString(info->index())).c_str());
- return false;
- }
- } else {
- // This attrib is not used in the current program.
- if (!info->buffer()) {
- SetGLError(
- GL_INVALID_OPERATION, function_name,
- (std::string(
- "attempt to render with no buffer attached to "
- "enabled attribute ") +
- base::IntToString(info->index())).c_str());
- return false;
- }
- }
- }
-
- if (primcount && !divisor0) {
- SetGLError(
- GL_INVALID_OPERATION, function_name,
- "attempt instanced render with all attributes having "
- "non-zero divisors");
- return false;
- }
-
- return true;
+ return state_.vertex_attrib_manager->ValidateBindings(
+ function_name,
+ this,
+ feature_info_.get(),
+ state_.current_program,
+ max_vertex_accessed,
+ primcount);
}
bool GLES2DecoderImpl::SimulateAttrib0(
@@ -6145,8 +6129,11 @@ error::Error GLES2DecoderImpl::DoDrawElements(
}
GLuint max_vertex_accessed;
- if (!state_.vertex_attrib_manager->element_array_buffer()->
- GetMaxValueForRange(offset, count, type, &max_vertex_accessed)) {
+ Buffer* element_array_buffer =
+ state_.vertex_attrib_manager->element_array_buffer();
+
+ if (!element_array_buffer->GetMaxValueForRange(
+ offset, count, type, &max_vertex_accessed)) {
SetGLError(GL_INVALID_OPERATION,
function_name, "range out of bounds for buffer");
return error::kNoError;
@@ -6168,12 +6155,27 @@ error::Error GLES2DecoderImpl::DoDrawElements(
primcount)) {
bool textures_set = SetBlackTextureForNonRenderableTextures();
ApplyDirtyState();
+ // TODO(gman): Refactor to hide these details in BufferManager or
+ // VertexAttribManager.
const GLvoid* indices = reinterpret_cast<const GLvoid*>(offset);
+ bool used_client_side_array = false;
+ if (element_array_buffer->IsClientSideArray()) {
+ used_client_side_array = true;
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ indices = element_array_buffer->GetRange(offset, 0);
+ }
+
if (!instanced) {
glDrawElements(mode, count, type, indices);
} else {
glDrawElementsInstancedANGLE(mode, count, type, indices, primcount);
}
+
+ if (used_client_side_array) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
+ element_array_buffer->service_id());
+ }
+
ProcessPendingQueries();
if (textures_set) {
RestoreStateForNonRenderableTextures();
@@ -7191,8 +7193,8 @@ void GLES2DecoderImpl::DoBufferData(
SetGLError(GL_INVALID_VALUE, "glBufferData", "size < 0");
return;
}
- Buffer* info = GetBufferInfoForTarget(target);
- if (!info) {
+ Buffer* buffer = GetBufferInfoForTarget(target);
+ if (!buffer) {
SetGLError(GL_INVALID_VALUE, "glBufferData", "unknown buffer");
return;
}
@@ -7202,23 +7204,7 @@ void GLES2DecoderImpl::DoBufferData(
return;
}
- // Clear the buffer to 0 if no initial data was passed in.
- scoped_array<int8> zero;
- if (!data) {
- zero.reset(new int8[size]);
- memset(zero.get(), 0, size);
- data = zero.get();
- }
-
- CopyRealGLErrorsToWrapper();
- glBufferData(target, size, data, usage);
- GLenum error = PeekGLError();
- if (error == GL_NO_ERROR) {
- buffer_manager()->SetInfo(info, size, usage);
- info->SetRange(0, size, data);
- } else {
- buffer_manager()->SetInfo(info, 0, usage);
- }
+ buffer_manager()->DoBufferData(this, buffer, size, usage, data);
}
error::Error GLES2DecoderImpl::HandleBufferData(
@@ -7255,16 +7241,13 @@ error::Error GLES2DecoderImpl::HandleBufferDataImmediate(
void GLES2DecoderImpl::DoBufferSubData(
GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data) {
- Buffer* info = GetBufferInfoForTarget(target);
- if (!info) {
+ Buffer* buffer = GetBufferInfoForTarget(target);
+ if (!buffer) {
SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
return;
}
- if (!info->SetRange(offset, size, data)) {
- SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
- return;
- }
- glBufferSubData(target, offset, size, data);
+
+ buffer_manager()->DoBufferSubData(this, buffer, offset, size, data);
}
bool GLES2DecoderImpl::ClearLevel(
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 2263a7f..d06d652 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -975,11 +975,11 @@ error::Error GLES2DecoderImpl::HandleGetBooleanv(
if (params == NULL) {
return error::kOutOfBounds;
}
+ CopyRealGLErrorsToWrapper();
// Check that the client initialized the result.
if (result->size != 0) {
return error::kInvalidArguments;
}
- CopyRealGLErrorsToWrapper();
DoGetBooleanv(pname, params);
GLenum error = glGetError();
if (error == GL_NO_ERROR) {
@@ -1015,17 +1015,10 @@ error::Error GLES2DecoderImpl::HandleGetBufferParameteriv(
if (result->size != 0) {
return error::kInvalidArguments;
}
- CopyRealGLErrorsToWrapper();
- glGetBufferParameteriv(target, pname, params);
- GLenum error = glGetError();
- if (error == GL_NO_ERROR) {
- result->SetNumResults(num_values);
- } else {
- SetGLError(error, "", "");
- }
+ DoGetBufferParameteriv(target, pname, params);
+ result->SetNumResults(num_values);
return error::kNoError;
}
-
error::Error GLES2DecoderImpl::HandleGetError(
uint32 immediate_data_size, const gles2::cmds::GetError& c) {
typedef cmds::GetError::Result Result;
@@ -1054,11 +1047,11 @@ error::Error GLES2DecoderImpl::HandleGetFloatv(
if (params == NULL) {
return error::kOutOfBounds;
}
+ CopyRealGLErrorsToWrapper();
// Check that the client initialized the result.
if (result->size != 0) {
return error::kInvalidArguments;
}
- CopyRealGLErrorsToWrapper();
DoGetFloatv(pname, params);
GLenum error = glGetError();
if (error == GL_NO_ERROR) {
@@ -1099,11 +1092,11 @@ error::Error GLES2DecoderImpl::HandleGetFramebufferAttachmentParameteriv(
if (params == NULL) {
return error::kOutOfBounds;
}
+ CopyRealGLErrorsToWrapper();
// Check that the client initialized the result.
if (result->size != 0) {
return error::kInvalidArguments;
}
- CopyRealGLErrorsToWrapper();
DoGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
GLenum error = glGetError();
if (error == GL_NO_ERROR) {
@@ -1130,11 +1123,11 @@ error::Error GLES2DecoderImpl::HandleGetIntegerv(
if (params == NULL) {
return error::kOutOfBounds;
}
+ CopyRealGLErrorsToWrapper();
// Check that the client initialized the result.
if (result->size != 0) {
return error::kInvalidArguments;
}
- CopyRealGLErrorsToWrapper();
DoGetIntegerv(pname, params);
GLenum error = glGetError();
if (error == GL_NO_ERROR) {
@@ -1162,11 +1155,11 @@ error::Error GLES2DecoderImpl::HandleGetProgramiv(
if (params == NULL) {
return error::kOutOfBounds;
}
+ CopyRealGLErrorsToWrapper();
// Check that the client initialized the result.
if (result->size != 0) {
return error::kInvalidArguments;
}
- CopyRealGLErrorsToWrapper();
DoGetProgramiv(program, pname, params);
GLenum error = glGetError();
if (error == GL_NO_ERROR) {
@@ -1199,11 +1192,11 @@ error::Error GLES2DecoderImpl::HandleGetRenderbufferParameteriv(
if (params == NULL) {
return error::kOutOfBounds;
}
+ CopyRealGLErrorsToWrapper();
// Check that the client initialized the result.
if (result->size != 0) {
return error::kInvalidArguments;
}
- CopyRealGLErrorsToWrapper();
DoGetRenderbufferParameteriv(target, pname, params);
GLenum error = glGetError();
if (error == GL_NO_ERROR) {
@@ -1231,11 +1224,11 @@ error::Error GLES2DecoderImpl::HandleGetShaderiv(
if (params == NULL) {
return error::kOutOfBounds;
}
+ CopyRealGLErrorsToWrapper();
// Check that the client initialized the result.
if (result->size != 0) {
return error::kInvalidArguments;
}
- CopyRealGLErrorsToWrapper();
DoGetShaderiv(shader, pname, params);
GLenum error = glGetError();
if (error == GL_NO_ERROR) {
@@ -1267,11 +1260,11 @@ error::Error GLES2DecoderImpl::HandleGetTexParameterfv(
if (params == NULL) {
return error::kOutOfBounds;
}
+ CopyRealGLErrorsToWrapper();
// Check that the client initialized the result.
if (result->size != 0) {
return error::kInvalidArguments;
}
- CopyRealGLErrorsToWrapper();
glGetTexParameterfv(target, pname, params);
GLenum error = glGetError();
if (error == GL_NO_ERROR) {
@@ -1303,11 +1296,11 @@ error::Error GLES2DecoderImpl::HandleGetTexParameteriv(
if (params == NULL) {
return error::kOutOfBounds;
}
+ CopyRealGLErrorsToWrapper();
// Check that the client initialized the result.
if (result->size != 0) {
return error::kInvalidArguments;
}
- CopyRealGLErrorsToWrapper();
glGetTexParameteriv(target, pname, params);
GLenum error = glGetError();
if (error == GL_NO_ERROR) {
@@ -1335,11 +1328,11 @@ error::Error GLES2DecoderImpl::HandleGetVertexAttribfv(
if (params == NULL) {
return error::kOutOfBounds;
}
+ CopyRealGLErrorsToWrapper();
// Check that the client initialized the result.
if (result->size != 0) {
return error::kInvalidArguments;
}
- CopyRealGLErrorsToWrapper();
DoGetVertexAttribfv(index, pname, params);
GLenum error = glGetError();
if (error == GL_NO_ERROR) {
@@ -1367,11 +1360,11 @@ error::Error GLES2DecoderImpl::HandleGetVertexAttribiv(
if (params == NULL) {
return error::kOutOfBounds;
}
+ CopyRealGLErrorsToWrapper();
// Check that the client initialized the result.
if (result->size != 0) {
return error::kInvalidArguments;
}
- CopyRealGLErrorsToWrapper();
DoGetVertexAttribiv(index, pname, params);
GLenum error = glGetError();
if (error == GL_NO_ERROR) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
index 497faf1a..f018338 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
@@ -149,6 +149,12 @@ void GLES2DecoderTestBase::SpecializedSetup<cmds::FramebufferTexture2D, 0>(
template <>
void GLES2DecoderTestBase::SpecializedSetup<
+ cmds::GetBufferParameteriv, 0>(bool /* valid */) {
+ DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<
cmds::GetFramebufferAttachmentParameteriv, 0>(bool /* valid */) {
DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
kServiceFramebufferId);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
index fc77e17..bb4b8c8 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
@@ -1172,16 +1172,9 @@ TEST_F(GLES2DecoderTest1, GetBooleanvInvalidArgs1_1) {
}
TEST_F(GLES2DecoderTest1, GetBufferParameterivValidArgs) {
- EXPECT_CALL(*gl_, GetError())
- .WillOnce(Return(GL_NO_ERROR))
- .WillOnce(Return(GL_NO_ERROR))
- .RetiresOnSaturation();
SpecializedSetup<cmds::GetBufferParameteriv, 0>(true);
typedef cmds::GetBufferParameteriv::Result Result;
Result* result = static_cast<Result*>(shared_memory_address_);
- EXPECT_CALL(
- *gl_, GetBufferParameteriv(
- GL_ARRAY_BUFFER, GL_BUFFER_SIZE, result->GetData()));
result->size = 0;
cmds::GetBufferParameteriv cmd;
cmd.Init(
diff --git a/gpu/command_buffer/service/query_manager_unittest.cc b/gpu/command_buffer/service/query_manager_unittest.cc
index 5d273fa..28e6e08 100644
--- a/gpu/command_buffer/service/query_manager_unittest.cc
+++ b/gpu/command_buffer/service/query_manager_unittest.cc
@@ -98,7 +98,7 @@ class QueryManagerTest : public testing::Test {
virtual ~MockCommandBufferEngine() {
}
- virtual Buffer GetSharedMemoryBuffer(int32 shm_id) OVERRIDE {
+ virtual gpu::Buffer GetSharedMemoryBuffer(int32 shm_id) OVERRIDE {
return shm_id == kSharedMemoryId ? valid_buffer_ : invalid_buffer_;
}
@@ -129,8 +129,8 @@ class QueryManagerTest : public testing::Test {
private:
scoped_array<int8> data_;
- Buffer valid_buffer_;
- Buffer invalid_buffer_;
+ gpu::Buffer valid_buffer_;
+ gpu::Buffer invalid_buffer_;
};
scoped_ptr<MockCommandBufferEngine> engine_;
diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc
index 13cc469..2cbef21 100644
--- a/gpu/command_buffer/service/test_helper.cc
+++ b/gpu/command_buffer/service/test_helper.cc
@@ -10,7 +10,9 @@
#include "base/string_number_conversions.h"
#include "base/strings/string_tokenizer.h"
#include "gpu/command_buffer/common/types.h"
+#include "gpu/command_buffer/service/buffer_manager.h"
#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
#include "gpu/command_buffer/service/program_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_mock.h"
@@ -491,6 +493,30 @@ void TestHelper::SetupShader(
gl, attribs, num_attribs, uniforms, num_uniforms, service_id);
}
+void TestHelper::DoBufferData(
+ ::gfx::MockGLInterface* gl, MockGLES2Decoder* decoder,
+ BufferManager* manager, Buffer* buffer, GLsizeiptr size, GLenum usage,
+ const GLvoid* data, GLenum error) {
+ EXPECT_CALL(*decoder, CopyRealGLErrorsToWrapper())
+ .Times(1)
+ .RetiresOnSaturation();
+ if (manager->IsUsageClientSideArray(usage)) {
+ EXPECT_CALL(*gl, BufferData(
+ buffer->target(), 0, _, usage))
+ .Times(1)
+ .RetiresOnSaturation();
+ } else {
+ EXPECT_CALL(*gl, BufferData(
+ buffer->target(), size, _, usage))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ EXPECT_CALL(*decoder, PeekGLError())
+ .WillOnce(Return(error))
+ .RetiresOnSaturation();
+ manager->DoBufferData(decoder, buffer, size, usage, data);
+}
+
} // namespace gles2
} // namespace gpu
diff --git a/gpu/command_buffer/service/test_helper.h b/gpu/command_buffer/service/test_helper.h
index 86354c6..a97cf74 100644
--- a/gpu/command_buffer/service/test_helper.h
+++ b/gpu/command_buffer/service/test_helper.h
@@ -11,6 +11,9 @@ namespace gpu {
namespace gles2 {
struct DisallowedFeatures;
+class Buffer;
+class BufferManager;
+class MockGLES2Decoder;
class TestHelper {
public:
@@ -86,6 +89,11 @@ class TestHelper {
UniformInfo* uniforms, size_t num_uniforms,
GLuint service_id);
+ static void DoBufferData(
+ ::gfx::MockGLInterface* gl, MockGLES2Decoder* decoder,
+ BufferManager* manager, Buffer* buffer, GLsizeiptr size, GLenum usage,
+ const GLvoid* data, GLenum error);
+
private:
static void SetupTextureInitializationExpectations(
::gfx::MockGLInterface* gl, GLenum target);
diff --git a/gpu/command_buffer/service/vertex_attrib_manager.cc b/gpu/command_buffer/service/vertex_attrib_manager.cc
index 50c2dec..fe346ab 100644
--- a/gpu/command_buffer/service/vertex_attrib_manager.cc
+++ b/gpu/command_buffer/service/vertex_attrib_manager.cc
@@ -9,13 +9,17 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/string_number_conversions.h"
#include "build/build_config.h"
#define GLES2_GPU_SERVICE 1
#include "gpu/command_buffer/common/gles2_cmd_format.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "gpu/command_buffer/service/buffer_manager.h"
+#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/command_buffer/service/program_manager.h"
#include "gpu/command_buffer/service/vertex_array_manager.h"
namespace gpu {
@@ -31,6 +35,7 @@ VertexAttrib::VertexAttrib()
gl_stride_(0),
real_stride_(16),
divisor_(0),
+ is_client_side_array_(false),
list_(NULL) {
}
@@ -154,5 +159,114 @@ void VertexAttribManager::Unbind(Buffer* buffer) {
}
}
+bool VertexAttribManager::ValidateBindings(
+ const char* function_name,
+ GLES2Decoder* decoder,
+ FeatureInfo* feature_info,
+ Program* current_program,
+ GLuint max_vertex_accessed,
+ GLsizei primcount) {
+ // true if any enabled, used divisor is zero
+ bool divisor0 = false;
+ const GLuint kInitialBufferId = 0xFFFFFFFFU;
+ GLuint current_buffer_id = kInitialBufferId;
+ bool use_client_side_arrays_for_stream_buffers = feature_info->workarounds(
+ ).use_client_side_arrays_for_stream_buffers;
+ // Validate all attribs currently enabled. If they are used by the current
+ // program then check that they have enough elements to handle the draw call.
+ // If they are not used by the current program check that they have a buffer
+ // assigned.
+ for (VertexAttribInfoList::iterator it = enabled_vertex_attribs_.begin();
+ it != enabled_vertex_attribs_.end(); ++it) {
+ VertexAttrib* attrib = *it;
+ const Program::VertexAttrib* attrib_info =
+ current_program->GetAttribInfoByLocation(attrib->index());
+ if (attrib_info) {
+ divisor0 |= (attrib->divisor() == 0);
+ GLuint count = attrib->MaxVertexAccessed(primcount, max_vertex_accessed);
+ // This attrib is used in the current program.
+ if (!attrib->CanAccess(count)) {
+ decoder->SetGLError(
+ GL_INVALID_OPERATION, function_name,
+ (std::string(
+ "attempt to access out of range vertices in attribute ") +
+ base::IntToString(attrib->index())).c_str());
+ return false;
+ }
+ if (use_client_side_arrays_for_stream_buffers) {
+ Buffer* buffer = attrib->buffer();
+ glEnableVertexAttribArray(attrib->index());
+ if (buffer->IsClientSideArray()) {
+ if (current_buffer_id != 0) {
+ current_buffer_id = 0;
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+ attrib->set_is_client_side_array(true);
+ const void* ptr = buffer->GetRange(attrib->offset(), 0);
+ DCHECK(ptr);
+ glVertexAttribPointer(
+ attrib->index(),
+ attrib->size(),
+ attrib->type(),
+ attrib->normalized(),
+ attrib->gl_stride(),
+ ptr);
+ } else if (attrib->is_client_side_array()) {
+ attrib->set_is_client_side_array(false);
+ GLuint new_buffer_id = buffer->service_id();
+ if (new_buffer_id != current_buffer_id) {
+ current_buffer_id = new_buffer_id;
+ glBindBuffer(GL_ARRAY_BUFFER, current_buffer_id);
+ }
+ const void* ptr = reinterpret_cast<const void*>(attrib->offset());
+ glVertexAttribPointer(
+ attrib->index(),
+ attrib->size(),
+ attrib->type(),
+ attrib->normalized(),
+ attrib->gl_stride(),
+ ptr);
+ }
+ }
+ } else {
+ // This attrib is not used in the current program.
+ if (!attrib->buffer()) {
+ decoder->SetGLError(
+ GL_INVALID_OPERATION, function_name,
+ (std::string(
+ "attempt to render with no buffer attached to "
+ "enabled attribute ") +
+ base::IntToString(attrib->index())).c_str());
+ return false;
+ } else if (use_client_side_arrays_for_stream_buffers) {
+ Buffer* buffer = attrib->buffer();
+ // Disable client side arrays for unused attributes else we'll
+ // read bad memory
+ if (buffer->IsClientSideArray()) {
+ // Don't disable attrib 0 since it's special.
+ if (attrib->index() > 0) {
+ glDisableVertexAttribArray(attrib->index());
+ }
+ }
+ }
+ }
+ }
+
+ if (primcount && !divisor0) {
+ decoder->SetGLError(
+ GL_INVALID_OPERATION, function_name,
+ "attempt instanced render with all attributes having "
+ "non-zero divisors");
+ return false;
+ }
+
+ if (current_buffer_id != kInitialBufferId) {
+ // Restore the buffer binding.
+ decoder->RestoreBufferBindings();
+ }
+
+ return true;
+}
+
} // namespace gles2
} // namespace gpu
diff --git a/gpu/command_buffer/service/vertex_attrib_manager.h b/gpu/command_buffer/service/vertex_attrib_manager.h
index 76c75c8..ddd29be 100644
--- a/gpu/command_buffer/service/vertex_attrib_manager.h
+++ b/gpu/command_buffer/service/vertex_attrib_manager.h
@@ -17,6 +17,9 @@
namespace gpu {
namespace gles2 {
+class FeatureInfo;
+class GLES2Decoder;
+class Program;
class VertexArrayManager;
// Info about a Vertex Attribute. This is used to track what the user currently
@@ -75,6 +78,14 @@ class GPU_EXPORT VertexAttrib {
max_vertex_accessed;
}
+ bool is_client_side_array() const {
+ return is_client_side_array_;
+ }
+
+ void set_is_client_side_array(bool value) {
+ is_client_side_array_ = value;
+ }
+
private:
friend class VertexAttribManager;
@@ -139,6 +150,9 @@ class GPU_EXPORT VertexAttrib {
GLsizei divisor_;
+ // Will be true if this was assigned to a client side array.
+ bool is_client_side_array_;
+
// The buffer bound to this attribute.
scoped_refptr<Buffer> buffer_;
@@ -231,6 +245,14 @@ class GPU_EXPORT VertexAttribManager :
return vertex_attrib_infos_.size();
}
+ bool ValidateBindings(
+ const char* function_name,
+ GLES2Decoder* decoder,
+ FeatureInfo* feature_info,
+ Program* current_program,
+ GLuint max_vertex_accessed,
+ GLsizei primcount);
+
private:
friend class VertexArrayManager;
friend class VertexArrayManagerTest;
diff --git a/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc b/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc
index 3ce938c..71a694c 100644
--- a/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc
+++ b/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc
@@ -7,6 +7,7 @@
#include "base/memory/scoped_ptr.h"
#include "gpu/command_buffer/service/buffer_manager.h"
#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
#include "gpu/command_buffer/service/test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_mock.h"
@@ -109,7 +110,7 @@ TEST_F(VertexAttribManagerTest, Enable) {
}
TEST_F(VertexAttribManagerTest, SetAttribInfo) {
- BufferManager buffer_manager(NULL);
+ BufferManager buffer_manager(NULL, NULL);
buffer_manager.CreateBuffer(1, 2);
Buffer* buffer = buffer_manager.GetBuffer(1);
ASSERT_TRUE(buffer != NULL);
@@ -145,7 +146,8 @@ TEST_F(VertexAttribManagerTest, HaveFixedAttribs) {
}
TEST_F(VertexAttribManagerTest, CanAccess) {
- BufferManager buffer_manager(NULL);
+ MockGLES2Decoder decoder;
+ BufferManager buffer_manager(NULL, NULL);
buffer_manager.CreateBuffer(1, 2);
Buffer* buffer = buffer_manager.GetBuffer(1);
ASSERT_TRUE(buffer != NULL);
@@ -161,17 +163,23 @@ TEST_F(VertexAttribManagerTest, CanAccess) {
EXPECT_FALSE(info->CanAccess(0));
EXPECT_TRUE(buffer_manager.SetTarget(buffer, GL_ARRAY_BUFFER));
- buffer_manager.SetInfo(buffer, 15, GL_STATIC_DRAW);
+ TestHelper::DoBufferData(
+ gl_.get(), &decoder, &buffer_manager, buffer, 15, GL_STATIC_DRAW, NULL,
+ GL_NO_ERROR);
EXPECT_FALSE(info->CanAccess(0));
- buffer_manager.SetInfo(buffer, 16, GL_STATIC_DRAW);
+ TestHelper::DoBufferData(
+ gl_.get(), &decoder, &buffer_manager, buffer, 16, GL_STATIC_DRAW, NULL,
+ GL_NO_ERROR);
EXPECT_TRUE(info->CanAccess(0));
EXPECT_FALSE(info->CanAccess(1));
manager_->SetAttribInfo(1, buffer, 4, GL_FLOAT, GL_FALSE, 0, 16, 1);
EXPECT_FALSE(info->CanAccess(0));
- buffer_manager.SetInfo(buffer, 32, GL_STATIC_DRAW);
+ TestHelper::DoBufferData(
+ gl_.get(), &decoder, &buffer_manager, buffer, 32, GL_STATIC_DRAW, NULL,
+ GL_NO_ERROR);
EXPECT_TRUE(info->CanAccess(0));
EXPECT_FALSE(info->CanAccess(1));
manager_->SetAttribInfo(1, buffer, 4, GL_FLOAT, GL_FALSE, 0, 16, 0);
@@ -187,7 +195,7 @@ TEST_F(VertexAttribManagerTest, CanAccess) {
}
TEST_F(VertexAttribManagerTest, Unbind) {
- BufferManager buffer_manager(NULL);
+ BufferManager buffer_manager(NULL, NULL);
buffer_manager.CreateBuffer(1, 2);
buffer_manager.CreateBuffer(3, 4);
Buffer* buffer1 = buffer_manager.GetBuffer(1);
@@ -223,6 +231,9 @@ TEST_F(VertexAttribManagerTest, Unbind) {
buffer_manager.Destroy(false);
}
+// TODO(gman): Test ValidateBindings
+// TODO(gman): Test ValidateBindings with client side arrays.
+
} // namespace gles2
} // namespace gpu
diff --git a/gpu/command_buffer/tests/gl_stream_draw_unittests.cc b/gpu/command_buffer/tests/gl_stream_draw_unittests.cc
new file mode 100644
index 0000000..3997016
--- /dev/null
+++ b/gpu/command_buffer/tests/gl_stream_draw_unittests.cc
@@ -0,0 +1,157 @@
+// Copyright (c) 2013 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 <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include "gpu/command_buffer/tests/gl_manager.h"
+#include "gpu/command_buffer/tests/gl_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+
+#define SHADER(Src) #Src
+
+namespace gpu {
+
+class GLStreamDrawTest : public testing::Test {
+ protected:
+ static const int kSize = 4;
+
+ virtual void SetUp() {
+ GLManager::Options options;
+ options.size = gfx::Size(kSize, kSize);
+ gl_.Initialize(options);
+ }
+
+ virtual void TearDown() {
+ gl_.Destroy();
+ }
+
+ GLManager gl_;
+};
+
+namespace {
+
+GLuint SetupProgram() {
+ static const char* v_shader_str = SHADER(
+ attribute vec4 a_position;
+ attribute vec4 a_color;
+ varying vec4 v_color;
+ void main()
+ {
+ gl_Position = a_position;
+ v_color = a_color;
+ }
+ );
+
+ static const char* f_shader_str = SHADER(
+ precision mediump float;
+ varying vec4 v_color;
+ void main()
+ {
+ gl_FragColor = v_color;
+ }
+ );
+
+ GLuint program = GLTestHelper::LoadProgram(v_shader_str, f_shader_str);
+ glUseProgram(program);
+ return program;
+}
+
+} // anonymous namespace.
+
+TEST_F(GLStreamDrawTest, Basic) {
+ static GLfloat float_red[4] = { 1.0f, 0.0f, 0.0f, 1.0f, };
+ static GLfloat float_green[4] = { 0.0f, 1.0f, 0.0f, 1.0f, };
+ static uint8 expected_red[4] = {255, 0, 0, 255, };
+ static uint8 expected_green[4] = {0, 255, 0, 255, };
+
+ GLuint program = SetupProgram();
+ GLuint position_loc = glGetAttribLocation(program, "a_position");
+ GLuint color_loc = glGetAttribLocation(program, "a_color");
+ GLTestHelper::SetupUnitQuad(position_loc);
+ GLTestHelper::SetupColorsForUnitQuad(color_loc, float_red, GL_STREAM_DRAW);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, kSize, kSize, 0, expected_red));
+ GLTestHelper::SetupColorsForUnitQuad(color_loc, float_green, GL_STATIC_DRAW);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, kSize, kSize, 0, expected_green));
+
+ GLTestHelper::CheckGLError("no errors", __LINE__);
+}
+
+TEST_F(GLStreamDrawTest, DrawElements) {
+ static GLfloat float_red[4] = { 1.0f, 0.0f, 0.0f, 1.0f, };
+ static GLfloat float_green[4] = { 0.0f, 1.0f, 0.0f, 1.0f, };
+ static uint8 expected_red[4] = {255, 0, 0, 255, };
+ static uint8 expected_green[4] = {0, 255, 0, 255, };
+
+ GLuint program = SetupProgram();
+ GLuint position_loc = glGetAttribLocation(program, "a_position");
+ GLuint color_loc = glGetAttribLocation(program, "a_color");
+ GLTestHelper::SetupUnitQuad(position_loc);
+ GLTestHelper::SetupColorsForUnitQuad(color_loc, float_red, GL_STREAM_DRAW);
+
+ GLuint index_buffer = 0;
+ glGenBuffers(1, &index_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
+ static GLubyte indices[] = { 0, 1, 2, 3, 4, 5, };
+ glBufferData(
+ GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STREAM_DRAW);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, NULL);
+ EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, kSize, kSize, 0, expected_red));
+ GLTestHelper::SetupColorsForUnitQuad(color_loc, float_green, GL_STATIC_DRAW);
+
+ glBufferData(
+ GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, NULL);
+ EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, kSize, kSize, 0, expected_green));
+
+ GLTestHelper::CheckGLError("no errors", __LINE__);
+}
+
+TEST_F(GLStreamDrawTest, VertexArrayObjects) {
+ if (!GLTestHelper::HasExtension("GL_OES_vertex_array_object")) {
+ return;
+ }
+
+ static GLfloat float_red[4] = { 1.0f, 0.0f, 0.0f, 1.0f, };
+ static GLfloat float_green[4] = { 0.0f, 1.0f, 0.0f, 1.0f, };
+ static uint8 expected_red[4] = {255, 0, 0, 255, };
+ static uint8 expected_green[4] = {0, 255, 0, 255, };
+
+ GLuint program = SetupProgram();
+ GLuint position_loc = glGetAttribLocation(program, "a_position");
+ GLuint color_loc = glGetAttribLocation(program, "a_color");
+
+ GLuint vaos[2];
+ glGenVertexArraysOES(2, vaos);
+
+ glBindVertexArrayOES(vaos[0]);
+ GLuint position_buffer = GLTestHelper::SetupUnitQuad(position_loc);
+ GLTestHelper::SetupColorsForUnitQuad(color_loc, float_red, GL_STREAM_DRAW);
+
+ glBindVertexArrayOES(vaos[1]);
+ glBindBuffer(GL_ARRAY_BUFFER, position_buffer);
+ glEnableVertexAttribArray(position_loc);
+ glVertexAttribPointer(position_loc, 2, GL_FLOAT, GL_FALSE, 0, 0);
+ GLTestHelper::SetupColorsForUnitQuad(color_loc, float_green, GL_STATIC_DRAW);
+
+ for (int ii = 0; ii < 2; ++ii) {
+ glBindVertexArrayOES(vaos[0]);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, kSize, kSize, 0, expected_red));
+
+ glBindVertexArrayOES(vaos[1]);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ EXPECT_TRUE(
+ GLTestHelper::CheckPixels(0, 0, kSize, kSize, 0, expected_green));
+ }
+
+ GLTestHelper::CheckGLError("no errors", __LINE__);
+}
+
+} // namespace gpu
+
diff --git a/gpu/command_buffer/tests/gl_test_utils.cc b/gpu/command_buffer/tests/gl_test_utils.cc
index 1a3e7c2..4b87f1e 100644
--- a/gpu/command_buffer/tests/gl_test_utils.cc
+++ b/gpu/command_buffer/tests/gl_test_utils.cc
@@ -108,6 +108,24 @@ GLuint GLTestHelper::SetupUnitQuad(GLint position_location) {
return vbo;
}
+GLuint GLTestHelper::SetupColorsForUnitQuad(
+ GLint location, const GLfloat color[4], GLenum usage) {
+ GLuint vbo = 0;
+ glGenBuffers(1, &vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, vbo);
+ GLfloat vertices[6 * 4];
+ for (int ii = 0; ii < 6; ++ii) {
+ for (int jj = 0; jj < 4; ++jj) {
+ vertices[ii * 4 + jj] = color[jj];
+ }
+ }
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, usage);
+ glEnableVertexAttribArray(location);
+ glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, 0, 0);
+
+ return vbo;
+}
+
bool GLTestHelper::CheckPixels(
GLint x, GLint y, GLsizei width, GLsizei height, GLint tolerance,
const uint8* color) {
diff --git a/gpu/command_buffer/tests/gl_test_utils.h b/gpu/command_buffer/tests/gl_test_utils.h
index 31de7cd..972ea0a 100644
--- a/gpu/command_buffer/tests/gl_test_utils.h
+++ b/gpu/command_buffer/tests/gl_test_utils.h
@@ -35,6 +35,11 @@ class GLTestHelper {
// Returns the created buffer.
static GLuint SetupUnitQuad(GLint position_location);
+ // Make a 6 vertex colors.
+ // Returns the created buffer.
+ static GLuint SetupColorsForUnitQuad(
+ GLint location, const GLfloat color[4], GLenum usage);
+
// Checks an area of pixels for a color.
static bool CheckPixels(
GLint x, GLint y, GLsizei width, GLsizei height, GLint tolerance,
diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp
index e6e9868..005573d 100644
--- a/gpu/gpu.gyp
+++ b/gpu/gpu.gyp
@@ -261,6 +261,7 @@
'command_buffer/tests/gl_texture_storage_unittests.cc',
'command_buffer/tests/gl_unittests.cc',
'command_buffer/tests/gl_virtual_contexts_unittests.cc',
+ 'command_buffer/tests/gl_stream_draw_unittests.cc',
'command_buffer/tests/occlusion_query_unittests.cc',
],
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.