| 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 b0b228d5c3e84c880a5e1d1a7694dcafe8f233c5..43b88a09f0fd78da586f001cf6166e380d9f7667 100644 | 
| --- a/gpu/command_buffer/client/gles2_implementation.cc | 
| +++ b/gpu/command_buffer/client/gles2_implementation.cc | 
| @@ -14,6 +14,7 @@ | 
| #include <stdio.h> | 
| #include <string.h> | 
| #include <GLES2/gl2ext.h> | 
| +#include "../client/buffer_tracker.h" | 
| #include "../client/mapped_memory.h" | 
| #include "../client/program_info_manager.h" | 
| #include "../client/query_tracker.h" | 
| @@ -439,6 +440,7 @@ GLES2Implementation::GLES2Implementation( | 
| bound_renderbuffer_(0), | 
| bound_array_buffer_id_(0), | 
| bound_element_array_buffer_id_(0), | 
| +      bound_pixel_unpack_transfer_buffer_id_(0), | 
| client_side_array_id_(0), | 
| client_side_element_array_id_(0), | 
| bound_vertex_array_id_(0), | 
| @@ -515,6 +517,7 @@ bool GLES2Implementation::Initialize( | 
| new TextureUnit[gl_state_.int_state.max_combined_texture_image_units]); | 
|  | 
| query_tracker_.reset(new QueryTracker(mapped_memory_.get())); | 
| +  buffer_tracker_.reset(new BufferTracker(mapped_memory_.get())); | 
|  | 
| #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) | 
| GetIdHandler(id_namespaces::kBuffers)->MakeIds( | 
| @@ -540,6 +543,8 @@ GLES2Implementation::~GLES2Implementation() { | 
| #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS) | 
| DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]); | 
| #endif | 
| +  buffer_tracker_.reset(); | 
| + | 
| // The share group needs to be able to use a command buffer to talk | 
| // to service if it's destroyed so set one for it then release the reference. | 
| // If it's destroyed it will use this GLES2Implemenation. | 
| @@ -960,6 +965,9 @@ bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) { | 
| return true; | 
| } | 
| return false; | 
| +    case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM: | 
| +      *params = bound_pixel_unpack_transfer_buffer_id_; | 
| +      return true; | 
| case GL_ACTIVE_TEXTURE: | 
| *params = active_texture_unit_ + GL_TEXTURE0; | 
| return true; | 
| @@ -1612,6 +1620,30 @@ void GLES2Implementation::BufferDataHelper( | 
| return; | 
| } | 
|  | 
| +  if (target == GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM) { | 
| +    GLuint buffer_id = bound_pixel_unpack_transfer_buffer_id_; | 
| +    if (!buffer_id) { | 
| +      SetGLError(GL_INVALID_VALUE, "glBufferData", "unknown buffer"); | 
| +      return; | 
| +    } | 
| + | 
| +    BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id); | 
| +    if (buffer) { | 
| +      // Free buffer memory, pending the passage of a token. | 
| +      buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken()); | 
| + | 
| +      // Remove old buffer. | 
| +      buffer_tracker_->RemoveBuffer(buffer_id); | 
| +    } | 
| + | 
| +    // Create new buffer. | 
| +    buffer = buffer_tracker_->CreateBuffer(buffer_id, size); | 
| +    GPU_DCHECK(buffer); | 
| +    if (data) | 
| +      memcpy(buffer->address(), data, size); | 
| +    return; | 
| +  } | 
| + | 
| // If there is no data just send BufferData | 
| if (!data) { | 
| helper_->BufferData(target, size, 0, 0, usage); | 
| @@ -1662,6 +1694,26 @@ void GLES2Implementation::BufferSubDataHelper( | 
| return; | 
| } | 
|  | 
| +  if (target == GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM) { | 
| +    BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer( | 
| +        bound_pixel_unpack_transfer_buffer_id_); | 
| +    if (!buffer) { | 
| +      SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer"); | 
| +      return; | 
| +    } | 
| + | 
| +    int32 end = 0; | 
| +    int32 buffer_size = buffer->size(); | 
| +    if (!SafeAddInt32(offset, size, &end) || end > buffer_size) { | 
| +      SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range"); | 
| +      return; | 
| +    } | 
| + | 
| +    if (data) | 
| +      memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size); | 
| +    return; | 
| +  } | 
| + | 
| ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_); | 
| BufferSubDataHelperImpl(target, offset, size, data, &buffer); | 
| } | 
| @@ -1700,6 +1752,27 @@ void GLES2Implementation::BufferSubData( | 
| BufferSubDataHelper(target, offset, size, data); | 
| } | 
|  | 
| +BufferTracker::Buffer* | 
| +GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid( | 
| +    const char* function_name, GLuint offset, GLsizei size) | 
| +{ | 
| +  BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer( | 
| +      bound_pixel_unpack_transfer_buffer_id_); | 
| +  if (!buffer) { | 
| +    SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer"); | 
| +    return NULL; | 
| +  } | 
| +  if (buffer->mapped()) { | 
| +    SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped"); | 
| +    return NULL; | 
| +  } | 
| +  if ((buffer->size() - offset) < static_cast<GLuint>(size)) { | 
| +    SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large"); | 
| +    return NULL; | 
| +  } | 
| +  return buffer; | 
| +} | 
| + | 
| void GLES2Implementation::CompressedTexImage2D( | 
| GLenum target, GLint level, GLenum internalformat, GLsizei width, | 
| GLsizei height, GLint border, GLsizei image_size, const void* data) { | 
| @@ -1718,6 +1791,18 @@ void GLES2Implementation::CompressedTexImage2D( | 
| if (height == 0 || width == 0) { | 
| return; | 
| } | 
| +  // If there's a pixel unpack buffer bound use it when issuing | 
| +  // CompressedTexImage2D. | 
| +  if (bound_pixel_unpack_transfer_buffer_id_) { | 
| +    GLuint offset = ToGLuint(data); | 
| +    BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid( | 
| +        "glCompressedTexImage2D", offset, image_size); | 
| +    if (buffer) | 
| +      helper_->CompressedTexImage2D( | 
| +          target, level, internalformat, width, height, border, image_size, | 
| +          buffer->shm_id(), buffer->shm_offset() + offset); | 
| +    return; | 
| +  } | 
| SetBucketContents(kResultBucketId, data, image_size); | 
| helper_->CompressedTexImage2DBucket( | 
| target, level, internalformat, width, height, border, kResultBucketId); | 
| @@ -1743,6 +1828,18 @@ void GLES2Implementation::CompressedTexSubImage2D( | 
| SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0"); | 
| return; | 
| } | 
| +  // If there's a pixel unpack buffer bound use it when issuing | 
| +  // CompressedTexSubImage2D. | 
| +  if (bound_pixel_unpack_transfer_buffer_id_) { | 
| +    GLuint offset = ToGLuint(data); | 
| +    BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid( | 
| +        "glCompressedTexSubImage2D", offset, image_size); | 
| +    if (buffer) | 
| +      helper_->CompressedTexSubImage2D( | 
| +          target, level, xoffset, yoffset, width, height, format, image_size, | 
| +          buffer->shm_id(), buffer->shm_offset() + offset); | 
| +    return; | 
| +  } | 
| SetBucketContents(kResultBucketId, data, image_size); | 
| helper_->CompressedTexSubImage2DBucket( | 
| target, level, xoffset, yoffset, width, height, format, kResultBucketId); | 
| @@ -1814,6 +1911,18 @@ void GLES2Implementation::TexImage2D( | 
| return; | 
| } | 
|  | 
| +  // If there's a pixel unpack buffer bound use it when issuing TexImage2D. | 
| +  if (bound_pixel_unpack_transfer_buffer_id_) { | 
| +    GLuint offset = ToGLuint(pixels); | 
| +    BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid( | 
| +        "glTexImage2D", offset, size); | 
| +    if (buffer) | 
| +      helper_->TexImage2D( | 
| +          target, level, internalformat, width, height, border, format, type, | 
| +          buffer->shm_id(), buffer->shm_offset() + offset); | 
| +    return; | 
| +  } | 
| + | 
| // If there's no data just issue TexImage2D | 
| if (!pixels) { | 
| helper_->TexImage2D( | 
| @@ -1901,6 +2010,18 @@ void GLES2Implementation::TexSubImage2D( | 
| return; | 
| } | 
|  | 
| +  // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D. | 
| +  if (bound_pixel_unpack_transfer_buffer_id_) { | 
| +    GLuint offset = ToGLuint(pixels); | 
| +    BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid( | 
| +        "glTexSubImage2D", offset, temp_size); | 
| +    if (buffer) | 
| +      helper_->TexSubImage2D( | 
| +          target, level, xoffset, yoffset, width, height, format, type, | 
| +          buffer->shm_id(), buffer->shm_offset() + offset, false); | 
| +    return; | 
| +  } | 
| + | 
| // compute the advance bytes per row for the src pixels | 
| uint32 src_padded_row_size; | 
| if (unpack_row_length_ > 0) { | 
| @@ -2417,6 +2538,9 @@ void GLES2Implementation::BindBufferHelper( | 
| case GL_ELEMENT_ARRAY_BUFFER: | 
| bound_element_array_buffer_id_ = buffer; | 
| break; | 
| +    case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM: | 
| +      bound_pixel_unpack_transfer_buffer_id_ = buffer; | 
| +      break; | 
| default: | 
| break; | 
| } | 
| @@ -2511,6 +2635,17 @@ void GLES2Implementation::DeleteBuffersHelper( | 
| if (buffers[ii] == bound_element_array_buffer_id_) { | 
| bound_element_array_buffer_id_ = 0; | 
| } | 
| +    if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) { | 
| +      bound_pixel_unpack_transfer_buffer_id_ = 0; | 
| +    } | 
| + | 
| +    BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]); | 
| +    if (buffer) { | 
| +      // Free buffer memory, pending the passage of a token. | 
| +      buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken()); | 
| +      // Remove buffer. | 
| +      buffer_tracker_->RemoveBuffer(buffers[ii]); | 
| +    } | 
| } | 
| } | 
|  | 
| @@ -3480,6 +3615,59 @@ void GLES2Implementation::TraceBeginCHROMIUM(const char* name) { | 
| helper_->SetBucketSize(kResultBucketId, 0); | 
| } | 
|  | 
| +void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) { | 
| +  GPU_CLIENT_SINGLE_THREAD_CHECK(); | 
| +  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM(" | 
| +      << target << ", " << GLES2Util::GetStringEnum(access) << ")"); | 
| +  if (target != GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM) { | 
| +    SetGLError( | 
| +        GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target"); | 
| +    return NULL; | 
| +  } | 
| +  if (access != GL_WRITE_ONLY) { | 
| +    SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode"); | 
| +    return NULL; | 
| +  } | 
| +  BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer( | 
| +        bound_pixel_unpack_transfer_buffer_id_); | 
| +  if (!buffer) { | 
| +    SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer"); | 
| +    return NULL; | 
| +  } | 
| +  if (buffer->mapped()) { | 
| +    SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped"); | 
| +    return NULL; | 
| +  } | 
| +  buffer->set_mapped(true); | 
| + | 
| +  GPU_DCHECK(buffer->address()); | 
| +  GPU_CLIENT_LOG("  returned " << buffer->address()); | 
| +  return buffer->address(); | 
| +} | 
| + | 
| +GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) { | 
| +  GPU_CLIENT_SINGLE_THREAD_CHECK(); | 
| +  GPU_CLIENT_LOG( | 
| +      "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")"); | 
| +  if (target != GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM) { | 
| +    SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target"); | 
| +    return false; | 
| +  } | 
| +  BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer( | 
| +      bound_pixel_unpack_transfer_buffer_id_); | 
| +  if (!buffer) { | 
| +    SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer"); | 
| +    return false; | 
| +  } | 
| +  if (!buffer->mapped()) { | 
| +    SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "not mapped"); | 
| +    return false; | 
| +  } | 
| +  buffer->set_mapped(false); | 
| + | 
| +  return true; | 
| +} | 
| + | 
| // Include the auto-generated part of this file. We split this because it means | 
| // we can easily edit the non-auto generated parts right here in this file | 
| // instead of having to edit some template or the code generator. | 
|  |