| Index: gpu/command_buffer/client/gles2_implementation.cc
|
| diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
|
| index 59385241e5c89526420ceda1fd8c50d75fc050b1..fe59c2a0f099550a0dd144195e2c753e014910dd 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;
|
| }
|
| @@ -828,23 +816,44 @@ void GLES2Implementation::DrawElements(
|
| << count << ", "
|
| << GLES2Util::GetStringIndexType(type) << ", "
|
| << static_cast<const void*>(indices) << ")");
|
| - if (count < 0) {
|
| - SetGLError(GL_INVALID_VALUE, "glDrawElements", "count less than 0.");
|
| - return;
|
| - }
|
| - if (count == 0) {
|
| + DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
|
| +}
|
| +
|
| +void GLES2Implementation::DrawRangeElements(
|
| + GLenum mode, GLuint start, GLuint end,
|
| + GLsizei count, GLenum type, const void* indices) {
|
| + GPU_CLIENT_SINGLE_THREAD_CHECK();
|
| + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawRangeElements("
|
| + << GLES2Util::GetStringDrawMode(mode) << ", "
|
| + << start << ", " << end << ", " << count << ", "
|
| + << GLES2Util::GetStringIndexType(type) << ", "
|
| + << static_cast<const void*>(indices) << ")");
|
| + if (end < start) {
|
| + SetGLError(GL_INVALID_VALUE, "glDrawRangeElements", "end < start");
|
| return;
|
| }
|
| - if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
|
| - !ValidateOffset("glDrawElements", reinterpret_cast<GLintptr>(indices))) {
|
| + DrawElementsImpl(mode, count, type, indices, "glDrawRangeElements");
|
| +}
|
| +
|
| +void GLES2Implementation::DrawElementsImpl(
|
| + GLenum mode, GLsizei count, GLenum type, const void* indices,
|
| + const char* func_name) {
|
| + if (count < 0) {
|
| + SetGLError(GL_INVALID_VALUE, func_name, "count < 0");
|
| return;
|
| }
|
| - GLuint offset = 0;
|
| bool simulated = false;
|
| - if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
|
| - "glDrawElements", this, helper_, count, type, 0, indices,
|
| - &offset, &simulated)) {
|
| - return;
|
| + GLuint offset = ToGLuint(indices);
|
| + if (count > 0) {
|
| + if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
|
| + !ValidateOffset(func_name, reinterpret_cast<GLintptr>(indices))) {
|
| + return;
|
| + }
|
| + if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
|
| + func_name, this, helper_, count, type, 0, indices,
|
| + &offset, &simulated)) {
|
| + return;
|
| + }
|
| }
|
| helper_->DrawElements(mode, count, type, offset);
|
| RestoreElementAndArrayBuffers(simulated);
|
| @@ -1384,12 +1393,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 +3298,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 +3681,133 @@ 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;
|
| +}
|
| +
|
| +GLboolean GLES2Implementation::UnmapBuffer(GLenum target) {
|
| + GPU_CLIENT_SINGLE_THREAD_CHECK();
|
| + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapBuffer("
|
| + << GLES2Util::GetStringEnum(target) << ")");
|
| + switch (target) {
|
| + case GL_ARRAY_BUFFER:
|
| + case GL_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:
|
| + break;
|
| + default:
|
| + SetGLError(GL_INVALID_ENUM, "glUnmapBuffer", "invalid target");
|
| + return GL_FALSE;
|
| + }
|
| + GLuint buffer = GetBoundBufferHelper(target);
|
| + if (buffer == 0) {
|
| + SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "no buffer bound");
|
| + return GL_FALSE;
|
| + }
|
| + auto iter = mapped_buffer_range_map_.find(buffer);
|
| + if (iter == mapped_buffer_range_map_.end()) {
|
| + SetGLError(GL_INVALID_OPERATION, "glUnmapBuffer", "buffer is unmapped");
|
| + return GL_FALSE;
|
| + }
|
| +
|
| + helper_->UnmapBuffer(target);
|
| + RemoveMappedBufferRangeById(buffer);
|
| + // TODO(zmo): There is a rare situation that data might be corrupted and
|
| + // GL_FALSE should be returned. We lose context on that sitatuon, so we
|
| + // don't have to WaitForCmd().
|
| + GPU_CLIENT_LOG(" returned " << GL_TRUE);
|
| + CheckGLError();
|
| + return GL_TRUE;
|
| +}
|
| +
|
| void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
|
| GLenum target,
|
| GLint level,
|
|
|