summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorzmo <zmo@chromium.org>2015-03-10 13:50:34 -0700
committerCommit bot <commit-bot@chromium.org>2015-03-10 20:51:11 +0000
commita06b988d074e869eec0e910429549d6606e214e4 (patch)
treeb31c780fdfae8104159c817e39963dccb07a01da /gpu
parent89e07c277ad9986bc814fea1b61f835cebda730a (diff)
downloadchromium_src-a06b988d074e869eec0e910429549d6606e214e4.zip
chromium_src-a06b988d074e869eec0e910429549d6606e214e4.tar.gz
chromium_src-a06b988d074e869eec0e910429549d6606e214e4.tar.bz2
Add glMapBufferRange to GPU command buffer.
BUG=429053 TEST=gpu_unittests R=piman@chromium.org Review URL: https://codereview.chromium.org/960013002 Cr-Commit-Position: refs/heads/master@{#319966}
Diffstat (limited to 'gpu')
-rw-r--r--gpu/BUILD.gn1
-rw-r--r--gpu/GLES2/gl2chromium_autogen.h1
-rwxr-xr-xgpu/command_buffer/build_gles2_cmd_buffer.py24
-rw-r--r--gpu/command_buffer/client/gles2_c_lib_autogen.h10
-rw-r--r--gpu/command_buffer/client/gles2_cmd_helper_autogen.h15
-rw-r--r--gpu/command_buffer/client/gles2_implementation.cc162
-rw-r--r--gpu/command_buffer/client/gles2_implementation.h9
-rw-r--r--gpu/command_buffer/client/gles2_implementation_autogen.h5
-rw-r--r--gpu/command_buffer/client/gles2_implementation_unittest.cc114
-rw-r--r--gpu/command_buffer/client/gles2_implementation_unittest_autogen.h1
-rw-r--r--gpu/command_buffer/client/gles2_interface_autogen.h4
-rw-r--r--gpu/command_buffer/client/gles2_interface_stub_autogen.h4
-rw-r--r--gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h6
-rw-r--r--gpu/command_buffer/client/gles2_trace_implementation_autogen.h4
-rw-r--r--gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h8
-rw-r--r--gpu/command_buffer/cmd_buffer_functions.txt1
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format_autogen.h80
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format_test_autogen.h21
-rw-r--r--gpu/command_buffer/common/gles2_cmd_ids_autogen.h95
-rw-r--r--gpu/command_buffer/common/gles2_cmd_utils.cc25
-rw-r--r--gpu/command_buffer/common/gles2_cmd_utils.h2
-rw-r--r--gpu/command_buffer/common/gles2_cmd_utils_autogen.h1
-rw-r--r--gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h13
-rw-r--r--gpu/command_buffer/service/buffer_manager.cc27
-rw-r--r--gpu/command_buffer/service/buffer_manager.h16
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc65
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h2
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc311
-rw-r--r--gpu/command_buffer/service/gles2_cmd_validation_autogen.h1
-rw-r--r--gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h11
-rw-r--r--gpu/gpu.gyp1
31 files changed, 910 insertions, 130 deletions
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 6270d00..75aed69 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -186,6 +186,7 @@ test("gpu_unittests") {
"command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc",
"command_buffer/service/gles2_cmd_decoder_unittest_base.cc",
"command_buffer/service/gles2_cmd_decoder_unittest_base.h",
+ "command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc",
"command_buffer/service/gles2_cmd_decoder_unittest_context_state.cc",
"command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc",
"command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc",
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index 60404dc..0f3ebf3 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -256,6 +256,7 @@
#define glUnmapBufferCHROMIUM GLES2_GET_FUN(UnmapBufferCHROMIUM)
#define glMapBufferSubDataCHROMIUM GLES2_GET_FUN(MapBufferSubDataCHROMIUM)
#define glUnmapBufferSubDataCHROMIUM GLES2_GET_FUN(UnmapBufferSubDataCHROMIUM)
+#define glMapBufferRange GLES2_GET_FUN(MapBufferRange)
#define glMapTexSubImage2DCHROMIUM GLES2_GET_FUN(MapTexSubImage2DCHROMIUM)
#define glUnmapTexSubImage2DCHROMIUM GLES2_GET_FUN(UnmapTexSubImage2DCHROMIUM)
#define glResizeCHROMIUM GLES2_GET_FUN(ResizeCHROMIUM)
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index ab51fcd..4207305 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -607,6 +607,20 @@ _NAMED_TYPE_INFO = {
'GL_RENDERBUFFER',
],
},
+ 'MapBufferAccess': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_MAP_READ_BIT',
+ 'GL_MAP_WRITE_BIT',
+ 'GL_MAP_INVALIDATE_RANGE_BIT',
+ 'GL_MAP_INVALIDATE_BUFFER_BIT',
+ 'GL_MAP_FLUSH_EXPLICIT_BIT',
+ 'GL_MAP_UNSYNCHRONIZED_BIT',
+ ],
+ 'invalid': [
+ 'GL_SYNC_FLUSH_COMMANDS_BIT',
+ ],
+ },
'Bufferiv': {
'type': 'GLenum',
'valid': [
@@ -2503,6 +2517,16 @@ _FUNCTION_INFO = {
'client_test': False,
'pepper_interface': 'ChromiumMapSub',
},
+ 'MapBufferRange': {
+ 'type': 'Custom',
+ 'data_transfer_methods': ['shm'],
+ 'cmd_args': 'GLenumBufferTarget target, GLintptrNotNegative offset, '
+ 'GLsizeiptr size, GLbitfieldMapBufferAccess access, '
+ 'uint32_t data_shm_id, uint32_t data_shm_offset, '
+ 'uint32_t result_shm_id, uint32_t result_shm_offset',
+ 'unsafe': True,
+ 'result': ['uint32_t'],
+ },
'PauseTransformFeedback': {
'unsafe': True,
},
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index 7e0da4b..84a5708 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -1065,6 +1065,12 @@ void* GLES2MapBufferSubDataCHROMIUM(GLuint target,
void GLES2UnmapBufferSubDataCHROMIUM(const void* mem) {
gles2::GetGLContext()->UnmapBufferSubDataCHROMIUM(mem);
}
+void* GLES2MapBufferRange(GLenum target,
+ GLintptr offset,
+ GLsizeiptr size,
+ GLbitfield access) {
+ return gles2::GetGLContext()->MapBufferRange(target, offset, size, access);
+}
void* GLES2MapTexSubImage2DCHROMIUM(GLenum target,
GLint level,
GLint xoffset,
@@ -2293,6 +2299,10 @@ extern const NameToFunc g_gles2_function_table[] = {
reinterpret_cast<GLES2FunctionPointer>(glUnmapBufferSubDataCHROMIUM),
},
{
+ "glMapBufferRange",
+ reinterpret_cast<GLES2FunctionPointer>(glMapBufferRange),
+ },
+ {
"glMapTexSubImage2DCHROMIUM",
reinterpret_cast<GLES2FunctionPointer>(glMapTexSubImage2DCHROMIUM),
},
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index ad3eb58..e9abfc7 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -2226,6 +2226,21 @@ void EnableFeatureCHROMIUM(GLuint bucket_id,
}
}
+void MapBufferRange(GLenum target,
+ GLintptr offset,
+ GLsizeiptr size,
+ GLbitfield access,
+ uint32_t data_shm_id,
+ uint32_t data_shm_offset,
+ uint32_t result_shm_id,
+ uint32_t result_shm_offset) {
+ gles2::cmds::MapBufferRange* c = GetCmdSpace<gles2::cmds::MapBufferRange>();
+ if (c) {
+ c->Init(target, offset, size, access, data_shm_id, data_shm_offset,
+ result_shm_id, result_shm_offset);
+ }
+}
+
void ResizeCHROMIUM(GLuint width, GLuint height, GLfloat scale_factor) {
gles2::cmds::ResizeCHROMIUM* c = GetCmdSpace<gles2::cmds::ResizeCHROMIUM>();
if (c) {
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 5938524..74e79ef 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -222,6 +222,10 @@ GLES2Implementation::~GLES2Implementation() {
DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
}
+ // Release remaining BufferRange mem; This is when a MapBufferRange() is
+ // called but not the UnmapBuffer() pair.
+ ClearMappedBufferRangeMap();
+
// Release any per-context data in share group.
share_group_->FreeContext(this);
@@ -605,6 +609,11 @@ GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
}
bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
+ // TODO(zmo): For all the BINDING points, there is a possibility where
+ // resources are shared among multiple contexts, that the cached points
+ // are invalid. It is not a problem for now, but once we allow resource
+ // sharing in WebGL, we need to implement a mechanism to allow correct
+ // client side binding points tracking. crbug.com/465562.
switch (pname) {
case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
*params = capabilities_.max_combined_texture_image_units;
@@ -643,18 +652,12 @@ bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
*params = capabilities_.num_shader_binary_formats;
return true;
case GL_ARRAY_BUFFER_BINDING:
- if (share_group_->bind_generates_resource()) {
- *params = bound_array_buffer_id_;
- return true;
- }
- return false;
+ *params = bound_array_buffer_id_;
+ return true;
case GL_ELEMENT_ARRAY_BUFFER_BINDING:
- if (share_group_->bind_generates_resource()) {
- *params =
- vertex_array_object_manager_->bound_element_array_buffer();
- return true;
- }
- return false;
+ *params =
+ vertex_array_object_manager_->bound_element_array_buffer();
+ return true;
case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
*params = bound_pixel_pack_transfer_buffer_id_;
return true;
@@ -665,43 +668,27 @@ bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
*params = active_texture_unit_ + GL_TEXTURE0;
return true;
case GL_TEXTURE_BINDING_2D:
- if (share_group_->bind_generates_resource()) {
- *params = texture_units_[active_texture_unit_].bound_texture_2d;
- return true;
- }
- return false;
+ *params = texture_units_[active_texture_unit_].bound_texture_2d;
+ return true;
case GL_TEXTURE_BINDING_CUBE_MAP:
- if (share_group_->bind_generates_resource()) {
- *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
- return true;
- }
- return false;
+ *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
+ return true;
case GL_TEXTURE_BINDING_EXTERNAL_OES:
- if (share_group_->bind_generates_resource()) {
- *params =
- texture_units_[active_texture_unit_].bound_texture_external_oes;
- return true;
- }
- return false;
+ *params =
+ texture_units_[active_texture_unit_].bound_texture_external_oes;
+ return true;
case GL_FRAMEBUFFER_BINDING:
- if (share_group_->bind_generates_resource()) {
- *params = bound_framebuffer_;
- return true;
- }
- return false;
+ *params = bound_framebuffer_;
+ return true;
case GL_READ_FRAMEBUFFER_BINDING:
- if (IsChromiumFramebufferMultisampleAvailable() &&
- share_group_->bind_generates_resource()) {
+ if (IsChromiumFramebufferMultisampleAvailable()) {
*params = bound_read_framebuffer_;
return true;
}
return false;
case GL_RENDERBUFFER_BINDING:
- if (share_group_->bind_generates_resource()) {
- *params = bound_renderbuffer_;
- return true;
- }
- return false;
+ *params = bound_renderbuffer_;
+ return true;
case GL_MAX_UNIFORM_BUFFER_BINDINGS:
*params = capabilities_.max_uniform_buffer_bindings;
return true;
@@ -711,6 +698,7 @@ bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
*params = capabilities_.uniform_buffer_offset_alignment;
return true;
+ // TODO(zmo): Support ES3 pnames.
default:
return false;
}
@@ -1384,12 +1372,10 @@ void GLES2Implementation::BufferDataHelper(
return;
}
- if (size == 0) {
- return;
- }
+ RemoveMappedBufferRangeByTarget(target);
// If there is no data just send BufferData
- if (!data) {
+ if (size == 0 || !data) {
helper_->BufferData(target, size, 0, 0, usage);
return;
}
@@ -3291,6 +3277,8 @@ void GLES2Implementation::DeleteBuffersHelper(
if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
bound_pixel_unpack_transfer_buffer_id_ = 0;
}
+
+ RemoveMappedBufferRangeById(buffers[ii]);
}
}
@@ -3672,6 +3660,94 @@ void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
CheckGLError();
}
+GLuint GLES2Implementation::GetBoundBufferHelper(GLenum target) {
+ GLenum binding = GLES2Util::MapBufferTargetToBindingEnum(target);
+ GLint id = 0;
+ bool cached = GetHelper(binding, &id);
+ DCHECK(cached);
+ return static_cast<GLuint>(id);
+}
+
+void GLES2Implementation::RemoveMappedBufferRangeByTarget(GLenum target) {
+ GLuint buffer = GetBoundBufferHelper(target);
+ RemoveMappedBufferRangeById(buffer);
+}
+
+void GLES2Implementation::RemoveMappedBufferRangeById(GLuint buffer) {
+ if (buffer > 0) {
+ auto iter = mapped_buffer_range_map_.find(buffer);
+ if (iter != mapped_buffer_range_map_.end() && iter->second.shm_memory) {
+ mapped_memory_->FreePendingToken(
+ iter->second.shm_memory, helper_->InsertToken());
+ mapped_buffer_range_map_.erase(iter);
+ }
+ }
+}
+
+void GLES2Implementation::ClearMappedBufferRangeMap() {
+ for (auto& buffer_range : mapped_buffer_range_map_) {
+ if (buffer_range.second.shm_memory) {
+ mapped_memory_->FreePendingToken(
+ buffer_range.second.shm_memory, helper_->InsertToken());
+ }
+ }
+ mapped_buffer_range_map_.clear();
+}
+
+void* GLES2Implementation::MapBufferRange(
+ GLenum target, GLintptr offset, GLsizeiptr size, GLbitfield access) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferRange("
+ << GLES2Util::GetStringEnum(target) << ", " << offset << ", "
+ << size << ", " << access << ")");
+ if (!ValidateSize("glMapBufferRange", size) ||
+ !ValidateOffset("glMapBufferRange", offset)) {
+ return nullptr;
+ }
+
+ int32 shm_id;
+ unsigned int shm_offset;
+ void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
+ if (!mem) {
+ SetGLError(GL_OUT_OF_MEMORY, "glMapBufferRange", "out of memory");
+ return nullptr;
+ }
+
+ typedef cmds::MapBufferRange::Result Result;
+ Result* result = GetResultAs<Result*>();
+ *result = 0;
+ helper_->MapBufferRange(target, offset, size, access, shm_id, shm_offset,
+ GetResultShmId(), GetResultShmOffset());
+ // TODO(zmo): For write only mode with MAP_INVALID_*_BIT, we should
+ // consider an early return without WaitForCmd(). crbug.com/465804.
+ WaitForCmd();
+ if (*result) {
+ const GLbitfield kInvalidateBits =
+ GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
+ if ((access & kInvalidateBits) != 0) {
+ // We do not read back from the buffer, therefore, we set the client
+ // side memory to zero to avoid uninitialized data.
+ memset(mem, 0, size);
+ }
+ GLuint buffer = GetBoundBufferHelper(target);
+ DCHECK_NE(0u, buffer);
+ // glMapBufferRange fails on an already mapped buffer.
+ DCHECK(mapped_buffer_range_map_.find(buffer) ==
+ mapped_buffer_range_map_.end());
+ auto iter = mapped_buffer_range_map_.insert(std::make_pair(
+ buffer,
+ MappedBuffer(access, shm_id, mem, shm_offset, target, offset, size)));
+ DCHECK(iter.second);
+ } else {
+ mapped_memory_->Free(mem);
+ mem = nullptr;
+ }
+
+ GPU_CLIENT_LOG(" returned " << mem);
+ CheckGLError();
+ return mem;
+}
+
void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
GLenum target,
GLint level,
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index 1ffdf91..a9baf0b 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -560,6 +560,7 @@ class GLES2_IMPL_EXPORT GLES2Implementation
// Helpers for query functions.
bool GetHelper(GLenum pname, GLint* params);
+ GLuint GetBoundBufferHelper(GLenum target);
bool GetBooleanvHelper(GLenum pname, GLboolean* params);
bool GetBufferParameterivHelper(GLenum target, GLenum pname, GLint* params);
bool GetFloatvHelper(GLenum pname, GLfloat* params);
@@ -659,6 +660,10 @@ class GLES2_IMPL_EXPORT GLES2Implementation
void FailGLError(GLenum /* error */) { }
#endif
+ void RemoveMappedBufferRangeByTarget(GLenum target);
+ void RemoveMappedBufferRangeById(GLuint buffer);
+ void ClearMappedBufferRangeMap();
+
GLES2Util util_;
GLES2CmdHelper* helper_;
TransferBufferInterface* transfer_buffer_;
@@ -767,6 +772,10 @@ class GLES2_IMPL_EXPORT GLES2Implementation
typedef std::map<const void*, MappedBuffer> MappedBufferMap;
MappedBufferMap mapped_buffers_;
+ // TODO(zmo): Consolidate |mapped_buffers_| and |mapped_buffer_range_map_|.
+ typedef base::hash_map<GLuint, MappedBuffer> MappedBufferRangeMap;
+ MappedBufferRangeMap mapped_buffer_range_map_;
+
typedef std::map<const void*, MappedTexture> MappedTextureMap;
MappedTextureMap mapped_textures_;
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 8e032e4..5111a6a 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -800,6 +800,11 @@ void* MapBufferSubDataCHROMIUM(GLuint target,
void UnmapBufferSubDataCHROMIUM(const void* mem) override;
+void* MapBufferRange(GLenum target,
+ GLintptr offset,
+ GLsizeiptr size,
+ GLbitfield access) override;
+
void* MapTexSubImage2DCHROMIUM(GLenum target,
GLint level,
GLint xoffset,
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index 3af9413..16908ca 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -2858,37 +2858,6 @@ TEST_F(GLES2ImplementationTest, TexSubImage3D4Writes) {
reinterpret_cast<uint8*>(pixels.get()) + offset_to_last, mem2_2.ptr));
}
-// Binds can not be cached with bind_generates_resource = false because
-// our id might not be valid. More specifically if you bind on contextA then
-// delete on contextB the resource is still bound on contextA but GetInterger
-// won't return an id.
-TEST_F(GLES2ImplementationStrictSharedTest, BindsNotCached) {
- struct PNameValue {
- GLenum pname;
- GLint expected;
- };
- const PNameValue pairs[] = {{GL_TEXTURE_BINDING_2D, 1, },
- {GL_TEXTURE_BINDING_CUBE_MAP, 2, },
- {GL_TEXTURE_BINDING_EXTERNAL_OES, 3, },
- {GL_FRAMEBUFFER_BINDING, 4, },
- {GL_RENDERBUFFER_BINDING, 5, },
- {GL_ARRAY_BUFFER_BINDING, 6, },
- {GL_ELEMENT_ARRAY_BUFFER_BINDING, 7, }, };
- size_t num_pairs = sizeof(pairs) / sizeof(pairs[0]);
- for (size_t ii = 0; ii < num_pairs; ++ii) {
- const PNameValue& pv = pairs[ii];
- GLint v = -1;
- ExpectedMemoryInfo result1 =
- GetExpectedResultMemory(sizeof(cmds::GetIntegerv::Result));
- EXPECT_CALL(*command_buffer(), OnFlush())
- .WillOnce(SetMemory(result1.ptr,
- SizedResultHelper<GLuint>(pv.expected)))
- .RetiresOnSaturation();
- gl_->GetIntegerv(pv.pname, &v);
- EXPECT_EQ(pv.expected, v);
- }
-}
-
// glGen* Ids must not be reused until glDelete* commands have been
// flushed by glFlush.
TEST_F(GLES2ImplementationStrictSharedTest, FlushGenerationTestBuffers) {
@@ -3631,6 +3600,89 @@ TEST_F(GLES2ImplementationTest, WaitSync) {
EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
}
+TEST_F(GLES2ImplementationTest, MapBufferRangeWrite) {
+ ExpectedMemoryInfo result =
+ GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result));
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result.ptr, uint32_t(1)))
+ .RetiresOnSaturation();
+
+ const GLuint kBufferId = 123;
+ gl_->BindBuffer(GL_ARRAY_BUFFER, kBufferId);
+
+ void* mem = gl_->MapBufferRange(GL_ARRAY_BUFFER, 10, 64, GL_MAP_WRITE_BIT);
+ EXPECT_TRUE(mem != nullptr);
+}
+
+TEST_F(GLES2ImplementationTest, MapBufferRangeWriteWithInvalidateBit) {
+ ExpectedMemoryInfo result =
+ GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result));
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result.ptr, uint32_t(1)))
+ .RetiresOnSaturation();
+
+ const GLuint kBufferId = 123;
+ gl_->BindBuffer(GL_ARRAY_BUFFER, kBufferId);
+
+ GLsizeiptr kSize = 64;
+ void* mem = gl_->MapBufferRange(
+ GL_ARRAY_BUFFER, 10, kSize,
+ GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
+ EXPECT_TRUE(mem != nullptr);
+ std::vector<int8_t> zero(kSize);
+ memset(&zero[0], 0, kSize);
+ EXPECT_EQ(0, memcmp(mem, &zero[0], kSize));
+}
+
+TEST_F(GLES2ImplementationTest, MapBufferRangeWriteWithGLError) {
+ ExpectedMemoryInfo result =
+ GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result));
+
+ // Return a result of 0 to indicate an GL error.
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result.ptr, uint32_t(0)))
+ .RetiresOnSaturation();
+
+ const GLuint kBufferId = 123;
+ gl_->BindBuffer(GL_ARRAY_BUFFER, kBufferId);
+
+ void* mem = gl_->MapBufferRange(GL_ARRAY_BUFFER, 10, 64, GL_MAP_WRITE_BIT);
+ EXPECT_TRUE(mem == nullptr);
+}
+
+TEST_F(GLES2ImplementationTest, MapBufferRangeRead) {
+ ExpectedMemoryInfo result =
+ GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result));
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result.ptr, uint32_t(1)))
+ .RetiresOnSaturation();
+
+ const GLuint kBufferId = 123;
+ gl_->BindBuffer(GL_ARRAY_BUFFER, kBufferId);
+
+ void* mem = gl_->MapBufferRange(GL_ARRAY_BUFFER, 10, 64, GL_MAP_READ_BIT);
+ EXPECT_TRUE(mem != nullptr);
+}
+
+TEST_F(GLES2ImplementationTest, MapBufferRangeReadWithGLError) {
+ ExpectedMemoryInfo result =
+ GetExpectedResultMemory(sizeof(cmds::MapBufferRange::Result));
+
+ // Return a result of 0 to indicate an GL error.
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result.ptr, uint32_t(0)))
+ .RetiresOnSaturation();
+
+ const GLuint kBufferId = 123;
+ gl_->BindBuffer(GL_ARRAY_BUFFER, kBufferId);
+
+ void* mem = gl_->MapBufferRange(GL_ARRAY_BUFFER, 10, 64, GL_MAP_READ_BIT);
+ EXPECT_TRUE(mem == nullptr);
+}
+
TEST_F(GLES2ImplementationManualInitTest, LoseContextOnOOM) {
ContextInitOptions init_options;
init_options.lose_context_when_out_of_memory = true;
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
index 2d8480a..4785ff0 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -2718,6 +2718,7 @@ TEST_F(GLES2ImplementationTest, IsVertexArrayOES) {
EXPECT_TRUE(result);
}
// TODO(zmo): Implement unit test for EnableFeatureCHROMIUM
+// TODO(zmo): Implement unit test for MapBufferRange
TEST_F(GLES2ImplementationTest, ResizeCHROMIUM) {
struct Cmds {
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index f93ec07..a181c43 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -583,6 +583,10 @@ virtual void* MapBufferSubDataCHROMIUM(GLuint target,
GLsizeiptr size,
GLenum access) = 0;
virtual void UnmapBufferSubDataCHROMIUM(const void* mem) = 0;
+virtual void* MapBufferRange(GLenum target,
+ GLintptr offset,
+ GLsizeiptr size,
+ GLbitfield access) = 0;
virtual void* MapTexSubImage2DCHROMIUM(GLenum target,
GLint level,
GLint xoffset,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index 0381b323..48697d5 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -568,6 +568,10 @@ void* MapBufferSubDataCHROMIUM(GLuint target,
GLsizeiptr size,
GLenum access) override;
void UnmapBufferSubDataCHROMIUM(const void* mem) override;
+void* MapBufferRange(GLenum target,
+ GLintptr offset,
+ GLsizeiptr size,
+ GLbitfield access) override;
void* MapTexSubImage2DCHROMIUM(GLenum target,
GLint level,
GLint xoffset,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
index 0f2e5fd..dfbb319 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -987,6 +987,12 @@ void* GLES2InterfaceStub::MapBufferSubDataCHROMIUM(GLuint /* target */,
}
void GLES2InterfaceStub::UnmapBufferSubDataCHROMIUM(const void* /* mem */) {
}
+void* GLES2InterfaceStub::MapBufferRange(GLenum /* target */,
+ GLintptr /* offset */,
+ GLsizeiptr /* size */,
+ GLbitfield /* access */) {
+ return 0;
+}
void* GLES2InterfaceStub::MapTexSubImage2DCHROMIUM(GLenum /* target */,
GLint /* level */,
GLint /* xoffset */,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index 8a9be79..32ccdab 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -568,6 +568,10 @@ void* MapBufferSubDataCHROMIUM(GLuint target,
GLsizeiptr size,
GLenum access) override;
void UnmapBufferSubDataCHROMIUM(const void* mem) override;
+void* MapBufferRange(GLenum target,
+ GLintptr offset,
+ GLsizeiptr size,
+ GLbitfield access) override;
void* MapTexSubImage2DCHROMIUM(GLenum target,
GLint level,
GLint xoffset,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
index d1479b1..327becc 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -1683,6 +1683,14 @@ void GLES2TraceImplementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
gl_->UnmapBufferSubDataCHROMIUM(mem);
}
+void* GLES2TraceImplementation::MapBufferRange(GLenum target,
+ GLintptr offset,
+ GLsizeiptr size,
+ GLbitfield access) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::MapBufferRange");
+ return gl_->MapBufferRange(target, offset, size, access);
+}
+
void* GLES2TraceImplementation::MapTexSubImage2DCHROMIUM(GLenum target,
GLint level,
GLint xoffset,
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index 140db2c..153aca4 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -246,6 +246,7 @@ GL_APICALL void* GL_APIENTRY glMapBufferCHROMIUM (GLuint target, GLenum a
GL_APICALL GLboolean GL_APIENTRY glUnmapBufferCHROMIUM (GLuint target);
GL_APICALL void* GL_APIENTRY glMapBufferSubDataCHROMIUM (GLuint target, GLintptrNotNegative offset, GLsizeiptr size, GLenum access);
GL_APICALL void GL_APIENTRY glUnmapBufferSubDataCHROMIUM (const void* mem);
+GL_APICALL void* GL_APIENTRY glMapBufferRange (GLenumBufferTarget target, GLintptrNotNegative offset, GLsizeiptr size, GLbitfieldMapBufferAccess access);
GL_APICALL void* GL_APIENTRY glMapTexSubImage2DCHROMIUM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLenum access);
GL_APICALL void GL_APIENTRY glUnmapTexSubImage2DCHROMIUM (const void* mem);
GL_APICALL void GL_APIENTRY glResizeCHROMIUM (GLuint width, GLuint height, GLfloat scale_factor);
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index d3cb00a..251bfff 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -10939,6 +10939,86 @@ static_assert(offsetof(EnableFeatureCHROMIUM, result_shm_id) == 8,
static_assert(offsetof(EnableFeatureCHROMIUM, result_shm_offset) == 12,
"offset of EnableFeatureCHROMIUM result_shm_offset should be 12");
+struct MapBufferRange {
+ typedef MapBufferRange ValueType;
+ static const CommandId kCmdId = kMapBufferRange;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+ static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+ typedef uint32_t Result;
+
+ static uint32_t ComputeSize() {
+ return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() { header.SetCmd<ValueType>(); }
+
+ void Init(GLenum _target,
+ GLintptr _offset,
+ GLsizeiptr _size,
+ GLbitfield _access,
+ uint32_t _data_shm_id,
+ uint32_t _data_shm_offset,
+ uint32_t _result_shm_id,
+ uint32_t _result_shm_offset) {
+ SetHeader();
+ target = _target;
+ offset = _offset;
+ size = _size;
+ access = _access;
+ data_shm_id = _data_shm_id;
+ data_shm_offset = _data_shm_offset;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(void* cmd,
+ GLenum _target,
+ GLintptr _offset,
+ GLsizeiptr _size,
+ GLbitfield _access,
+ uint32_t _data_shm_id,
+ uint32_t _data_shm_offset,
+ uint32_t _result_shm_id,
+ uint32_t _result_shm_offset) {
+ static_cast<ValueType*>(cmd)->Init(_target, _offset, _size, _access,
+ _data_shm_id, _data_shm_offset,
+ _result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32_t target;
+ int32_t offset;
+ int32_t size;
+ uint32_t access;
+ uint32_t data_shm_id;
+ uint32_t data_shm_offset;
+ uint32_t result_shm_id;
+ uint32_t result_shm_offset;
+};
+
+static_assert(sizeof(MapBufferRange) == 36,
+ "size of MapBufferRange should be 36");
+static_assert(offsetof(MapBufferRange, header) == 0,
+ "offset of MapBufferRange header should be 0");
+static_assert(offsetof(MapBufferRange, target) == 4,
+ "offset of MapBufferRange target should be 4");
+static_assert(offsetof(MapBufferRange, offset) == 8,
+ "offset of MapBufferRange offset should be 8");
+static_assert(offsetof(MapBufferRange, size) == 12,
+ "offset of MapBufferRange size should be 12");
+static_assert(offsetof(MapBufferRange, access) == 16,
+ "offset of MapBufferRange access should be 16");
+static_assert(offsetof(MapBufferRange, data_shm_id) == 20,
+ "offset of MapBufferRange data_shm_id should be 20");
+static_assert(offsetof(MapBufferRange, data_shm_offset) == 24,
+ "offset of MapBufferRange data_shm_offset should be 24");
+static_assert(offsetof(MapBufferRange, result_shm_id) == 28,
+ "offset of MapBufferRange result_shm_id should be 28");
+static_assert(offsetof(MapBufferRange, result_shm_offset) == 32,
+ "offset of MapBufferRange result_shm_offset should be 32");
+
struct ResizeCHROMIUM {
typedef ResizeCHROMIUM ValueType;
static const CommandId kCmdId = kResizeCHROMIUM;
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
index 3162276..55485bf 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -3778,6 +3778,27 @@ TEST_F(GLES2FormatTest, EnableFeatureCHROMIUM) {
CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
}
+TEST_F(GLES2FormatTest, MapBufferRange) {
+ cmds::MapBufferRange& cmd = *GetBufferAs<cmds::MapBufferRange>();
+ void* next_cmd =
+ cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLintptr>(12),
+ static_cast<GLsizeiptr>(13), static_cast<GLbitfield>(14),
+ static_cast<uint32_t>(15), static_cast<uint32_t>(16),
+ static_cast<uint32_t>(17), static_cast<uint32_t>(18));
+ EXPECT_EQ(static_cast<uint32_t>(cmds::MapBufferRange::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLintptr>(12), cmd.offset);
+ EXPECT_EQ(static_cast<GLsizeiptr>(13), cmd.size);
+ EXPECT_EQ(static_cast<GLbitfield>(14), cmd.access);
+ EXPECT_EQ(static_cast<uint32_t>(15), cmd.data_shm_id);
+ EXPECT_EQ(static_cast<uint32_t>(16), cmd.data_shm_offset);
+ EXPECT_EQ(static_cast<uint32_t>(17), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32_t>(18), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
TEST_F(GLES2FormatTest, ResizeCHROMIUM) {
cmds::ResizeCHROMIUM& cmd = *GetBufferAs<cmds::ResizeCHROMIUM>();
void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11),
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index 1c739e8..997268c2 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -243,53 +243,54 @@
OP(SwapBuffers) /* 484 */ \
OP(GetMaxValueInBufferCHROMIUM) /* 485 */ \
OP(EnableFeatureCHROMIUM) /* 486 */ \
- OP(ResizeCHROMIUM) /* 487 */ \
- OP(GetRequestableExtensionsCHROMIUM) /* 488 */ \
- OP(RequestExtensionCHROMIUM) /* 489 */ \
- OP(GetProgramInfoCHROMIUM) /* 490 */ \
- OP(GetUniformBlocksCHROMIUM) /* 491 */ \
- OP(GetTransformFeedbackVaryingsCHROMIUM) /* 492 */ \
- OP(GetUniformsES3CHROMIUM) /* 493 */ \
- OP(GetTranslatedShaderSourceANGLE) /* 494 */ \
- OP(PostSubBufferCHROMIUM) /* 495 */ \
- OP(TexImageIOSurface2DCHROMIUM) /* 496 */ \
- OP(CopyTextureCHROMIUM) /* 497 */ \
- OP(CopySubTextureCHROMIUM) /* 498 */ \
- OP(DrawArraysInstancedANGLE) /* 499 */ \
- OP(DrawElementsInstancedANGLE) /* 500 */ \
- OP(VertexAttribDivisorANGLE) /* 501 */ \
- OP(GenMailboxCHROMIUM) /* 502 */ \
- OP(ProduceTextureCHROMIUMImmediate) /* 503 */ \
- OP(ProduceTextureDirectCHROMIUMImmediate) /* 504 */ \
- OP(ConsumeTextureCHROMIUMImmediate) /* 505 */ \
- OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 506 */ \
- OP(BindUniformLocationCHROMIUMBucket) /* 507 */ \
- OP(GenValuebuffersCHROMIUMImmediate) /* 508 */ \
- OP(DeleteValuebuffersCHROMIUMImmediate) /* 509 */ \
- OP(IsValuebufferCHROMIUM) /* 510 */ \
- OP(BindValuebufferCHROMIUM) /* 511 */ \
- OP(SubscribeValueCHROMIUM) /* 512 */ \
- OP(PopulateSubscribedValuesCHROMIUM) /* 513 */ \
- OP(UniformValuebufferCHROMIUM) /* 514 */ \
- OP(BindTexImage2DCHROMIUM) /* 515 */ \
- OP(ReleaseTexImage2DCHROMIUM) /* 516 */ \
- OP(TraceBeginCHROMIUM) /* 517 */ \
- OP(TraceEndCHROMIUM) /* 518 */ \
- OP(AsyncTexSubImage2DCHROMIUM) /* 519 */ \
- OP(AsyncTexImage2DCHROMIUM) /* 520 */ \
- OP(WaitAsyncTexImage2DCHROMIUM) /* 521 */ \
- OP(WaitAllAsyncTexImage2DCHROMIUM) /* 522 */ \
- OP(DiscardFramebufferEXTImmediate) /* 523 */ \
- OP(LoseContextCHROMIUM) /* 524 */ \
- OP(InsertSyncPointCHROMIUM) /* 525 */ \
- OP(WaitSyncPointCHROMIUM) /* 526 */ \
- OP(DrawBuffersEXTImmediate) /* 527 */ \
- OP(DiscardBackbufferCHROMIUM) /* 528 */ \
- OP(ScheduleOverlayPlaneCHROMIUM) /* 529 */ \
- OP(SwapInterval) /* 530 */ \
- OP(MatrixLoadfCHROMIUMImmediate) /* 531 */ \
- OP(MatrixLoadIdentityCHROMIUM) /* 532 */ \
- OP(BlendBarrierKHR) /* 533 */
+ OP(MapBufferRange) /* 487 */ \
+ OP(ResizeCHROMIUM) /* 488 */ \
+ OP(GetRequestableExtensionsCHROMIUM) /* 489 */ \
+ OP(RequestExtensionCHROMIUM) /* 490 */ \
+ OP(GetProgramInfoCHROMIUM) /* 491 */ \
+ OP(GetUniformBlocksCHROMIUM) /* 492 */ \
+ OP(GetTransformFeedbackVaryingsCHROMIUM) /* 493 */ \
+ OP(GetUniformsES3CHROMIUM) /* 494 */ \
+ OP(GetTranslatedShaderSourceANGLE) /* 495 */ \
+ OP(PostSubBufferCHROMIUM) /* 496 */ \
+ OP(TexImageIOSurface2DCHROMIUM) /* 497 */ \
+ OP(CopyTextureCHROMIUM) /* 498 */ \
+ OP(CopySubTextureCHROMIUM) /* 499 */ \
+ OP(DrawArraysInstancedANGLE) /* 500 */ \
+ OP(DrawElementsInstancedANGLE) /* 501 */ \
+ OP(VertexAttribDivisorANGLE) /* 502 */ \
+ OP(GenMailboxCHROMIUM) /* 503 */ \
+ OP(ProduceTextureCHROMIUMImmediate) /* 504 */ \
+ OP(ProduceTextureDirectCHROMIUMImmediate) /* 505 */ \
+ OP(ConsumeTextureCHROMIUMImmediate) /* 506 */ \
+ OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 507 */ \
+ OP(BindUniformLocationCHROMIUMBucket) /* 508 */ \
+ OP(GenValuebuffersCHROMIUMImmediate) /* 509 */ \
+ OP(DeleteValuebuffersCHROMIUMImmediate) /* 510 */ \
+ OP(IsValuebufferCHROMIUM) /* 511 */ \
+ OP(BindValuebufferCHROMIUM) /* 512 */ \
+ OP(SubscribeValueCHROMIUM) /* 513 */ \
+ OP(PopulateSubscribedValuesCHROMIUM) /* 514 */ \
+ OP(UniformValuebufferCHROMIUM) /* 515 */ \
+ OP(BindTexImage2DCHROMIUM) /* 516 */ \
+ OP(ReleaseTexImage2DCHROMIUM) /* 517 */ \
+ OP(TraceBeginCHROMIUM) /* 518 */ \
+ OP(TraceEndCHROMIUM) /* 519 */ \
+ OP(AsyncTexSubImage2DCHROMIUM) /* 520 */ \
+ OP(AsyncTexImage2DCHROMIUM) /* 521 */ \
+ OP(WaitAsyncTexImage2DCHROMIUM) /* 522 */ \
+ OP(WaitAllAsyncTexImage2DCHROMIUM) /* 523 */ \
+ OP(DiscardFramebufferEXTImmediate) /* 524 */ \
+ OP(LoseContextCHROMIUM) /* 525 */ \
+ OP(InsertSyncPointCHROMIUM) /* 526 */ \
+ OP(WaitSyncPointCHROMIUM) /* 527 */ \
+ OP(DrawBuffersEXTImmediate) /* 528 */ \
+ OP(DiscardBackbufferCHROMIUM) /* 529 */ \
+ OP(ScheduleOverlayPlaneCHROMIUM) /* 530 */ \
+ OP(SwapInterval) /* 531 */ \
+ OP(MatrixLoadfCHROMIUMImmediate) /* 532 */ \
+ OP(MatrixLoadIdentityCHROMIUM) /* 533 */ \
+ OP(BlendBarrierKHR) /* 534 */
enum CommandId {
kStartPoint = cmd::kLastCommonId, // All GLES2 commands start after this.
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc
index 0950b41..14d6a21 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.cc
+++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -870,6 +870,31 @@ uint64_t GLES2Util::MapTwoUint32ToUint64(uint32_t v32_0, uint32_t v32_1) {
return (v64 << 32) | v32_0;
}
+// static
+uint32_t GLES2Util::MapBufferTargetToBindingEnum(uint32_t target) {
+ switch (target) {
+ case GL_ARRAY_BUFFER:
+ return GL_ARRAY_BUFFER_BINDING;
+ case GL_COPY_READ_BUFFER:
+ return GL_COPY_READ_BUFFER_BINDING;
+ case GL_COPY_WRITE_BUFFER:
+ return GL_COPY_WRITE_BUFFER_BINDING;
+ case GL_ELEMENT_ARRAY_BUFFER:
+ return GL_ELEMENT_ARRAY_BUFFER_BINDING;
+ case GL_PIXEL_PACK_BUFFER:
+ return GL_PIXEL_PACK_BUFFER_BINDING;
+ case GL_PIXEL_UNPACK_BUFFER:
+ return GL_PIXEL_UNPACK_BUFFER_BINDING;
+ case GL_TRANSFORM_FEEDBACK_BUFFER:
+ return GL_TRANSFORM_FEEDBACK_BUFFER_BINDING;
+ case GL_UNIFORM_BUFFER:
+ return GL_UNIFORM_BUFFER_BINDING;
+ default:
+ return 0;
+ }
+}
+
+
namespace {
// WebGraphicsContext3DCommandBufferImpl configuration attributes. Those in
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h
index 9dd8f28..1661247 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -191,6 +191,8 @@ class GLES2_UTILS_EXPORT GLES2Util {
uint64_t v64, uint32_t* v32_0, uint32_t* v32_1);
static uint64_t MapTwoUint32ToUint64(uint32_t v32_0, uint32_t v32_1);
+ static uint32_t MapBufferTargetToBindingEnum(uint32_t target);
+
#include "../common/gles2_cmd_utils_autogen.h"
private:
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
index 76419ce..cd5002d 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
@@ -41,6 +41,7 @@ static std::string GetStringImageInternalFormat(uint32_t value);
static std::string GetStringImageUsage(uint32_t value);
static std::string GetStringIndexType(uint32_t value);
static std::string GetStringIndexedBufferTarget(uint32_t value);
+static std::string GetStringMapBufferAccess(uint32_t value);
static std::string GetStringMatrixMode(uint32_t value);
static std::string GetStringPixelStore(uint32_t value);
static std::string GetStringPixelType(uint32_t value);
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 403925e..52511ed 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -4845,6 +4845,19 @@ std::string GLES2Util::GetStringIndexedBufferTarget(uint32_t value) {
arraysize(string_table), value);
}
+std::string GLES2Util::GetStringMapBufferAccess(uint32_t value) {
+ static const EnumToString string_table[] = {
+ {GL_MAP_READ_BIT, "GL_MAP_READ_BIT"},
+ {GL_MAP_WRITE_BIT, "GL_MAP_WRITE_BIT"},
+ {GL_MAP_INVALIDATE_RANGE_BIT, "GL_MAP_INVALIDATE_RANGE_BIT"},
+ {GL_MAP_INVALIDATE_BUFFER_BIT, "GL_MAP_INVALIDATE_BUFFER_BIT"},
+ {GL_MAP_FLUSH_EXPLICIT_BIT, "GL_MAP_FLUSH_EXPLICIT_BIT"},
+ {GL_MAP_UNSYNCHRONIZED_BIT, "GL_MAP_UNSYNCHRONIZED_BIT"},
+ };
+ return GLES2Util::GetQualifiedEnumString(string_table,
+ arraysize(string_table), value);
+}
+
std::string GLES2Util::GetStringMatrixMode(uint32_t value) {
static const EnumToString string_table[] = {
{GL_PATH_PROJECTION_CHROMIUM, "GL_PATH_PROJECTION_CHROMIUM"},
diff --git a/gpu/command_buffer/service/buffer_manager.cc b/gpu/command_buffer/service/buffer_manager.cc
index 1f64fd5..d151a65 100644
--- a/gpu/command_buffer/service/buffer_manager.cc
+++ b/gpu/command_buffer/service/buffer_manager.cc
@@ -82,7 +82,8 @@ Buffer::Buffer(BufferManager* manager, GLuint service_id)
is_client_side_array_(false),
service_id_(service_id),
target_(0),
- usage_(GL_STATIC_DRAW) {
+ usage_(GL_STATIC_DRAW),
+ buffer_range_pointer_(nullptr) {
manager_->StartTracking(this);
}
@@ -119,6 +120,7 @@ void Buffer::SetInfo(
memset(shadow_.get(), 0, size);
}
}
+ buffer_range_pointer_ = nullptr;
}
bool Buffer::CheckRange(
@@ -397,12 +399,23 @@ bool BufferManager::SetTarget(Buffer* buffer, GLenum target) {
// Since one BufferManager can be shared by multiple decoders, ContextState is
// passed in each time and not just passed in during initialization.
Buffer* BufferManager::GetBufferInfoForTarget(
- ContextState* state, GLenum target) {
- DCHECK(target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER);
- if (target == GL_ARRAY_BUFFER) {
- return state->bound_array_buffer.get();
- } else {
- return state->vertex_attrib_manager->element_array_buffer();
+ ContextState* state, GLenum target) const {
+ switch (target) {
+ case GL_ARRAY_BUFFER:
+ return state->bound_array_buffer.get();
+ case GL_ELEMENT_ARRAY_BUFFER:
+ return state->vertex_attrib_manager->element_array_buffer();
+ case GL_COPY_READ_BUFFER:
+ case GL_COPY_WRITE_BUFFER:
+ case GL_PIXEL_PACK_BUFFER:
+ case GL_PIXEL_UNPACK_BUFFER:
+ case GL_TRANSFORM_FEEDBACK_BUFFER:
+ case GL_UNIFORM_BUFFER:
+ NOTIMPLEMENTED();
+ return nullptr;
+ default:
+ NOTREACHED();
+ return nullptr;
}
}
diff --git a/gpu/command_buffer/service/buffer_manager.h b/gpu/command_buffer/service/buffer_manager.h
index 22a6e42..fb6261d 100644
--- a/gpu/command_buffer/service/buffer_manager.h
+++ b/gpu/command_buffer/service/buffer_manager.h
@@ -67,6 +67,14 @@ class GPU_EXPORT Buffer : public base::RefCounted<Buffer> {
return is_client_side_array_;
}
+ void set_buffer_range_pointer(void* mem) {
+ buffer_range_pointer_ = mem;
+ }
+
+ void* buffer_range_pointer() const {
+ return buffer_range_pointer_;
+ }
+
private:
friend class BufferManager;
friend class BufferManagerTestBase;
@@ -163,6 +171,9 @@ class GPU_EXPORT Buffer : public base::RefCounted<Buffer> {
// Usage of buffer.
GLenum usage_;
+ // Returned value from last glMapBufferRange call.
+ void* buffer_range_pointer_;
+
// A map of ranges to the highest value in that range of a certain type.
typedef std::map<Range, GLuint, Range::Less> RangeToMaxValueMap;
RangeToMaxValueMap range_set_;
@@ -232,15 +243,16 @@ class GPU_EXPORT BufferManager {
// set to a non-zero size.
bool UseNonZeroSizeForClientSideArrayBuffer();
+ Buffer* GetBufferInfoForTarget(ContextState* state, GLenum target) const;
+
private:
friend class Buffer;
friend class TestHelper; // Needs access to DoBufferData.
friend class BufferManagerTestBase; // Needs access to DoBufferSubData.
+
void StartTracking(Buffer* buffer);
void StopTracking(Buffer* buffer);
- Buffer* GetBufferInfoForTarget(ContextState* state, GLenum target);
-
// Does a glBufferSubData and updates the approriate accounting.
// Assumes the values have already been validated.
void DoBufferSubData(
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 28c1e0f..3cf4dda 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -3113,6 +3113,7 @@ void GLES2DecoderImpl::DeleteBuffersHelper(
for (GLsizei ii = 0; ii < n; ++ii) {
Buffer* buffer = GetBuffer(client_ids[ii]);
if (buffer && !buffer->IsDeleted()) {
+ buffer->set_buffer_range_pointer(nullptr);
state_.vertex_attrib_manager->Unbind(buffer);
if (state_.bound_array_buffer.get() == buffer) {
state_.bound_array_buffer = NULL;
@@ -12288,6 +12289,70 @@ error::Error GLES2DecoderImpl::HandleWaitSync(
return error::kNoError;
}
+error::Error GLES2DecoderImpl::HandleMapBufferRange(
+ uint32_t immediate_data_size, const void* cmd_data) {
+ if (!unsafe_es3_apis_enabled()) {
+ return error::kUnknownCommand;
+ }
+ const gles2::cmds::MapBufferRange& c =
+ *static_cast<const gles2::cmds::MapBufferRange*>(cmd_data);
+ GLenum target = static_cast<GLenum>(c.target);
+ GLbitfield access = static_cast<GLbitfield>(c.access);
+ GLintptr offset = static_cast<GLintptr>(c.offset);
+ GLsizeiptr size = static_cast<GLsizeiptr>(c.size);
+
+ typedef cmds::MapBufferRange::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result));
+ if (!result) {
+ return error::kOutOfBounds;
+ }
+ if (*result != 0) {
+ *result = 0;
+ return error::kInvalidArguments;
+ }
+ int8_t* mem =
+ GetSharedMemoryAs<int8_t*>(c.data_shm_id, c.data_shm_offset, size);
+ if (!mem) {
+ return error::kOutOfBounds;
+ }
+
+ GLbitfield mask = GL_MAP_INVALIDATE_BUFFER_BIT;
+ if ((access & mask) == mask) {
+ // TODO(zmo): To be on the safe side, always map
+ // GL_MAP_INVALIDATE_BUFFER_BIT to GL_MAP_INVALIDATE_RANGE_BIT.
+ access = (access & ~GL_MAP_INVALIDATE_BUFFER_BIT);
+ access = (access | GL_MAP_INVALIDATE_RANGE_BIT);
+ }
+ // TODO(zmo): Always filter out GL_MAP_UNSYNCHRONIZED_BIT to get rid of
+ // undefined behaviors.
+ mask = GL_MAP_READ_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
+ if ((access & mask) == mask) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "MapBufferRange",
+ "incompatible access bits");
+ return error::kNoError;
+ }
+ access = (access & ~GL_MAP_UNSYNCHRONIZED_BIT);
+ if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT &&
+ (access & GL_MAP_INVALIDATE_RANGE_BIT) == 0) {
+ access = (access | GL_MAP_READ_BIT);
+ }
+ void* ptr = glMapBufferRange(target, offset, size, access);
+ if (ptr == nullptr) {
+ return error::kNoError;
+ }
+ Buffer* buffer = buffer_manager()->GetBufferInfoForTarget(&state_, target);
+ DCHECK(buffer);
+ if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT) {
+ buffer->set_buffer_range_pointer(ptr);
+ }
+ if ((access & GL_MAP_INVALIDATE_RANGE_BIT) == 0) {
+ memcpy(mem, ptr, size);
+ }
+ *result = 1;
+ return error::kNoError;
+}
+
void GLES2DecoderImpl::OnTextureRefDetachedFromFramebuffer(
TextureRef* texture_ref) {
Texture* texture = texture_ref->texture();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
index 29a55ba..fe5975e 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
@@ -218,6 +218,8 @@ TEST_P(GLES2DecoderTest3, PopGroupMarkerEXTValidArgs) {
// TODO(gman): GetMaxValueInBufferCHROMIUM
// TODO(gman): EnableFeatureCHROMIUM
+// TODO(gman): MapBufferRange
+
// TODO(gman): ResizeCHROMIUM
// TODO(gman): GetRequestableExtensionsCHROMIUM
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc
new file mode 100644
index 0000000..1c934dd
--- /dev/null
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc
@@ -0,0 +1,311 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest.h"
+
+using ::gfx::MockGLInterface;
+using ::testing::_;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+
+namespace gpu {
+namespace gles2 {
+
+using namespace cmds;
+
+namespace {
+
+} // namespace anonymous
+
+TEST_P(GLES2DecoderTest, MapBufferRangeReadSucceeds) {
+ const GLenum kTarget = GL_ARRAY_BUFFER;
+ const GLintptr kOffset = 10;
+ const GLsizeiptr kSize = 64;
+ const GLbitfield kAccess = GL_MAP_READ_BIT;
+
+ DoBindBuffer(kTarget, client_buffer_id_, kServiceBufferId);
+
+ std::vector<int8_t> data(kSize);
+ for (GLsizeiptr ii = 0; ii < kSize; ++ii) {
+ data[ii] = static_cast<int8_t>(ii % 255);
+ }
+ EXPECT_CALL(*gl_,
+ MapBufferRange(kTarget, kOffset, kSize, kAccess))
+ .WillOnce(Return(&data[0]))
+ .RetiresOnSaturation();
+
+ typedef MapBufferRange::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = 0;
+ uint32_t result_shm_id = kSharedMemoryId;
+ uint32_t result_shm_offset = kSharedMemoryOffset;
+ uint32_t data_shm_id = kSharedMemoryId;
+ uint32_t data_shm_offset = kSharedMemoryOffset + sizeof(*result);
+
+ MapBufferRange cmd;
+ cmd.Init(kTarget, kOffset, kSize, kAccess, data_shm_id, data_shm_offset,
+ result_shm_id, result_shm_offset);
+ decoder_->set_unsafe_es3_apis_enabled(true);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ int8_t* mem = reinterpret_cast<int8_t*>(&result[1]);
+ EXPECT_EQ(0, memcmp(&data[0], mem, kSize));
+ EXPECT_EQ(1u, *result);
+ decoder_->set_unsafe_es3_apis_enabled(false);
+ *result = 0;
+ EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, *result);
+}
+
+TEST_P(GLES2DecoderTest, MapBufferRangeWriteSucceeds) {
+ const GLenum kTarget = GL_ARRAY_BUFFER;
+ const GLintptr kOffset = 10;
+ const GLsizeiptr kSize = 64;
+ const GLbitfield kAccess = GL_MAP_WRITE_BIT;
+ const GLbitfield kMappedAccess = GL_MAP_WRITE_BIT | GL_MAP_READ_BIT;
+
+ DoBindBuffer(kTarget, client_buffer_id_, kServiceBufferId);
+
+ std::vector<int8_t> data(kSize);
+ for (GLsizeiptr ii = 0; ii < kSize; ++ii) {
+ data[ii] = static_cast<int8_t>(ii % 255);
+ }
+ EXPECT_CALL(*gl_,
+ MapBufferRange(kTarget, kOffset, kSize, kMappedAccess))
+ .WillOnce(Return(&data[0]))
+ .RetiresOnSaturation();
+
+ typedef MapBufferRange::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = 0;
+ uint32_t result_shm_id = kSharedMemoryId;
+ uint32_t result_shm_offset = kSharedMemoryOffset;
+ uint32_t data_shm_id = kSharedMemoryId;
+ uint32_t data_shm_offset = kSharedMemoryOffset + sizeof(*result);
+
+ MapBufferRange cmd;
+ cmd.Init(kTarget, kOffset, kSize, kAccess, data_shm_id, data_shm_offset,
+ result_shm_id, result_shm_offset);
+ decoder_->set_unsafe_es3_apis_enabled(true);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ int8_t* mem = reinterpret_cast<int8_t*>(&result[1]);
+ EXPECT_EQ(0, memcmp(&data[0], mem, kSize));
+ EXPECT_EQ(1u, *result);
+ decoder_->set_unsafe_es3_apis_enabled(false);
+ *result = 0;
+ EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, *result);
+}
+
+TEST_P(GLES2DecoderTest, MapBufferRangeNotInitFails) {
+ const GLenum kTarget = GL_ARRAY_BUFFER;
+ const GLintptr kOffset = 10;
+ const GLsizeiptr kSize = 64;
+ const GLbitfield kAccess = GL_MAP_READ_BIT;
+ std::vector<int8_t> data(kSize);
+
+ typedef MapBufferRange::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = 1; // Any value other than 0.
+ uint32_t result_shm_id = kSharedMemoryId;
+ uint32_t result_shm_offset = kSharedMemoryOffset;
+ uint32_t data_shm_id = kSharedMemoryId;
+ uint32_t data_shm_offset = kSharedMemoryOffset + sizeof(*result);
+
+ MapBufferRange cmd;
+ cmd.Init(kTarget, kOffset, kSize, kAccess, data_shm_id, data_shm_offset,
+ result_shm_id, result_shm_offset);
+ decoder_->set_unsafe_es3_apis_enabled(true);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest, MapBufferRangeWriteInvalidateRangeSucceeds) {
+ const GLenum kTarget = GL_ARRAY_BUFFER;
+ const GLintptr kOffset = 10;
+ const GLsizeiptr kSize = 64;
+ // With MAP_INVALIDATE_RANGE_BIT, no need to append MAP_READ_BIT.
+ const GLbitfield kAccess = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
+
+ DoBindBuffer(kTarget, client_buffer_id_, kServiceBufferId);
+
+ std::vector<int8_t> data(kSize);
+ for (GLsizeiptr ii = 0; ii < kSize; ++ii) {
+ data[ii] = static_cast<int8_t>(ii % 255);
+ }
+ EXPECT_CALL(*gl_,
+ MapBufferRange(kTarget, kOffset, kSize, kAccess))
+ .WillOnce(Return(&data[0]))
+ .RetiresOnSaturation();
+
+ typedef MapBufferRange::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = 0;
+ uint32_t result_shm_id = kSharedMemoryId;
+ uint32_t result_shm_offset = kSharedMemoryOffset;
+ uint32_t data_shm_id = kSharedMemoryId;
+ uint32_t data_shm_offset = kSharedMemoryOffset + sizeof(*result);
+
+ int8_t* mem = reinterpret_cast<int8_t*>(&result[1]);
+ memset(mem, 72, kSize); // Init to a random value other than 0.
+
+ MapBufferRange cmd;
+ cmd.Init(kTarget, kOffset, kSize, kAccess, data_shm_id, data_shm_offset,
+ result_shm_id, result_shm_offset);
+ decoder_->set_unsafe_es3_apis_enabled(true);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest, MapBufferRangeWriteInvalidateBufferSucceeds) {
+ // Test INVALIDATE_BUFFER_BIT is mapped to INVALIDATE_RANGE_BIT.
+ const GLenum kTarget = GL_ARRAY_BUFFER;
+ const GLintptr kOffset = 10;
+ const GLsizeiptr kSize = 64;
+ const GLbitfield kAccess = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT;
+ // With MAP_INVALIDATE_BUFFER_BIT, no need to append MAP_READ_BIT.
+ const GLbitfield kFilteredAccess =
+ GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
+
+ DoBindBuffer(kTarget, client_buffer_id_, kServiceBufferId);
+
+ std::vector<int8_t> data(kSize);
+ for (GLsizeiptr ii = 0; ii < kSize; ++ii) {
+ data[ii] = static_cast<int8_t>(ii % 255);
+ }
+ EXPECT_CALL(*gl_,
+ MapBufferRange(kTarget, kOffset, kSize, kFilteredAccess))
+ .WillOnce(Return(&data[0]))
+ .RetiresOnSaturation();
+
+ typedef MapBufferRange::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = 0;
+ uint32_t result_shm_id = kSharedMemoryId;
+ uint32_t result_shm_offset = kSharedMemoryOffset;
+ uint32_t data_shm_id = kSharedMemoryId;
+ uint32_t data_shm_offset = kSharedMemoryOffset + sizeof(*result);
+
+ int8_t* mem = reinterpret_cast<int8_t*>(&result[1]);
+ memset(mem, 72, kSize); // Init to a random value other than 0.
+
+ MapBufferRange cmd;
+ cmd.Init(kTarget, kOffset, kSize, kAccess, data_shm_id, data_shm_offset,
+ result_shm_id, result_shm_offset);
+ decoder_->set_unsafe_es3_apis_enabled(true);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest, MapBufferRangeWriteUnsynchronizedBit) {
+ // Test UNSYNCHRONIZED_BIT is filtered out.
+ const GLenum kTarget = GL_ARRAY_BUFFER;
+ const GLintptr kOffset = 10;
+ const GLsizeiptr kSize = 64;
+ const GLbitfield kAccess = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
+ const GLbitfield kFilteredAccess = GL_MAP_WRITE_BIT | GL_MAP_READ_BIT;
+
+ DoBindBuffer(kTarget, client_buffer_id_, kServiceBufferId);
+
+ std::vector<int8_t> data(kSize);
+ for (GLsizeiptr ii = 0; ii < kSize; ++ii) {
+ data[ii] = static_cast<int8_t>(ii % 255);
+ }
+ EXPECT_CALL(*gl_,
+ MapBufferRange(kTarget, kOffset, kSize, kFilteredAccess))
+ .WillOnce(Return(&data[0]))
+ .RetiresOnSaturation();
+
+ typedef MapBufferRange::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = 0;
+ uint32_t result_shm_id = kSharedMemoryId;
+ uint32_t result_shm_offset = kSharedMemoryOffset;
+ uint32_t data_shm_id = kSharedMemoryId;
+ uint32_t data_shm_offset = kSharedMemoryOffset + sizeof(*result);
+
+ int8_t* mem = reinterpret_cast<int8_t*>(&result[1]);
+ memset(mem, 72, kSize); // Init to a random value other than 0.
+
+ MapBufferRange cmd;
+ cmd.Init(kTarget, kOffset, kSize, kAccess, data_shm_id, data_shm_offset,
+ result_shm_id, result_shm_offset);
+ decoder_->set_unsafe_es3_apis_enabled(true);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0, memcmp(&data[0], mem, kSize));
+}
+
+TEST_P(GLES2DecoderTest, MapBufferRangeWithError) {
+ const GLenum kTarget = GL_ARRAY_BUFFER;
+ const GLintptr kOffset = 10;
+ const GLsizeiptr kSize = 64;
+ const GLbitfield kAccess = GL_MAP_READ_BIT;
+ std::vector<int8_t> data(kSize);
+ for (GLsizeiptr ii = 0; ii < kSize; ++ii) {
+ data[ii] = static_cast<int8_t>(ii % 255);
+ }
+ EXPECT_CALL(*gl_,
+ MapBufferRange(kTarget, kOffset, kSize, kAccess))
+ .WillOnce(Return(nullptr)) // Return nullptr to indicate a GL error.
+ .RetiresOnSaturation();
+
+ typedef MapBufferRange::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = 0;
+ uint32_t result_shm_id = kSharedMemoryId;
+ uint32_t result_shm_offset = kSharedMemoryOffset;
+ uint32_t data_shm_id = kSharedMemoryId;
+ uint32_t data_shm_offset = kSharedMemoryOffset + sizeof(*result);
+
+ int8_t* mem = reinterpret_cast<int8_t*>(&result[1]);
+ memset(mem, 72, kSize); // Init to a random value other than 0.
+
+ MapBufferRange cmd;
+ cmd.Init(kTarget, kOffset, kSize, kAccess, data_shm_id, data_shm_offset,
+ result_shm_id, result_shm_offset);
+ decoder_->set_unsafe_es3_apis_enabled(true);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ memset(&data[0], 72, kSize);
+ // Mem is untouched.
+ EXPECT_EQ(0, memcmp(&data[0], mem, kSize));
+ EXPECT_EQ(0u, *result);
+}
+
+TEST_P(GLES2DecoderTest, MapBufferRangeBadSharedMemoryFails) {
+ const GLenum kTarget = GL_ARRAY_BUFFER;
+ const GLintptr kOffset = 10;
+ const GLsizeiptr kSize = 64;
+ const GLbitfield kAccess = GL_MAP_READ_BIT;
+ std::vector<int8_t> data(kSize);
+ for (GLsizeiptr ii = 0; ii < kSize; ++ii) {
+ data[ii] = static_cast<int8_t>(ii % 255);
+ }
+
+ typedef MapBufferRange::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = 0;
+ uint32_t result_shm_id = kSharedMemoryId;
+ uint32_t result_shm_offset = kSharedMemoryOffset;
+ uint32_t data_shm_id = kSharedMemoryId;
+ uint32_t data_shm_offset = kSharedMemoryOffset + sizeof(*result);
+
+ decoder_->set_unsafe_es3_apis_enabled(true);
+ MapBufferRange cmd;
+ cmd.Init(kTarget, kOffset, kSize, kAccess,
+ kInvalidSharedMemoryId, data_shm_offset,
+ result_shm_id, result_shm_offset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(kTarget, kOffset, kSize, kAccess,
+ data_shm_id, data_shm_offset,
+ kInvalidSharedMemoryId, result_shm_offset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(kTarget, kOffset, kSize, kAccess,
+ data_shm_id, kInvalidSharedMemoryOffset,
+ result_shm_id, result_shm_offset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(kTarget, kOffset, kSize, kAccess,
+ data_shm_id, data_shm_offset,
+ result_shm_id, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
index 953c0f9..2a8684a 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
@@ -41,6 +41,7 @@ ValueValidator<GLenum> image_internal_format;
ValueValidator<GLenum> image_usage;
ValueValidator<GLenum> index_type;
ValueValidator<GLenum> indexed_buffer_target;
+ValueValidator<GLenum> map_buffer_access;
ValueValidator<GLenum> matrix_mode;
ValueValidator<GLenum> pixel_store;
ValueValidator<GLint> pixel_store_alignment;
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
index 11d8492..2f83240 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -289,6 +289,15 @@ static const GLenum valid_indexed_buffer_target_table[] = {
GL_UNIFORM_BUFFER,
};
+static const GLenum valid_map_buffer_access_table[] = {
+ GL_MAP_READ_BIT,
+ GL_MAP_WRITE_BIT,
+ GL_MAP_INVALIDATE_RANGE_BIT,
+ GL_MAP_INVALIDATE_BUFFER_BIT,
+ GL_MAP_FLUSH_EXPLICIT_BIT,
+ GL_MAP_UNSYNCHRONIZED_BIT,
+};
+
static const GLenum valid_matrix_mode_table[] = {
GL_PATH_PROJECTION_CHROMIUM,
GL_PATH_MODELVIEW_CHROMIUM,
@@ -670,6 +679,8 @@ Validators::Validators()
index_type(valid_index_type_table, arraysize(valid_index_type_table)),
indexed_buffer_target(valid_indexed_buffer_target_table,
arraysize(valid_indexed_buffer_target_table)),
+ map_buffer_access(valid_map_buffer_access_table,
+ arraysize(valid_map_buffer_access_table)),
matrix_mode(valid_matrix_mode_table, arraysize(valid_matrix_mode_table)),
pixel_store(valid_pixel_store_table, arraysize(valid_pixel_store_table)),
pixel_store_alignment(valid_pixel_store_alignment_table,
diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp
index 6021f56..29fb8b4 100644
--- a/gpu/gpu.gyp
+++ b/gpu/gpu.gyp
@@ -220,6 +220,7 @@
'command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc',
'command_buffer/service/gles2_cmd_decoder_unittest_base.cc',
'command_buffer/service/gles2_cmd_decoder_unittest_base.h',
+ 'command_buffer/service/gles2_cmd_decoder_unittest_buffers.cc',
'command_buffer/service/gles2_cmd_decoder_unittest_context_state.cc',
'command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc',
'command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc',