| 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 1c9e4829825f79cd1f6b643171c455826ca4336d..fbeca2882b882284c56eae18fee65d65e207ac8e 100644
|
| --- a/gpu/command_buffer/client/gles2_implementation.cc
|
| +++ b/gpu/command_buffer/client/gles2_implementation.cc
|
| @@ -15,6 +15,7 @@
|
| #include <string>
|
| #include <GLES2/gl2ext.h>
|
| #include <GLES2/gl2extchromium.h>
|
| +#include "base/bind.h"
|
| #include "gpu/command_buffer/client/buffer_tracker.h"
|
| #include "gpu/command_buffer/client/gpu_memory_buffer_tracker.h"
|
| #include "gpu/command_buffer/client/program_info_manager.h"
|
| @@ -106,6 +107,10 @@ GLES2Implementation::GLES2Implementation(
|
| bound_array_buffer_id_(0),
|
| bound_pixel_pack_transfer_buffer_id_(0),
|
| bound_pixel_unpack_transfer_buffer_id_(0),
|
| + async_upload_token_(0),
|
| + async_upload_sync_(NULL),
|
| + async_upload_sync_shm_id_(0),
|
| + async_upload_sync_shm_offset_(0),
|
| error_bits_(0),
|
| debug_(false),
|
| use_count_(0),
|
| @@ -151,7 +156,15 @@ bool GLES2Implementation::Initialize(
|
| return false;
|
| }
|
|
|
| - mapped_memory_.reset(new MappedMemoryManager(helper_, mapped_memory_limit));
|
| + mapped_memory_.reset(
|
| + new MappedMemoryManager(
|
| + helper_,
|
| + base::Bind(&GLES2Implementation::PollAsyncUploads,
|
| + // The mapped memory manager is owned by |this| here, and
|
| + // since its destroyed before before we destroy ourselves
|
| + // we don't need extra safety measures for this closure.
|
| + base::Unretained(this)),
|
| + mapped_memory_limit));
|
|
|
| unsigned chunk_size = 2 * 1024 * 1024;
|
| if (mapped_memory_limit != kNoLimit) {
|
| @@ -278,6 +291,13 @@ GLES2Implementation::~GLES2Implementation() {
|
|
|
| buffer_tracker_.reset();
|
|
|
| + FreeAllAsyncUploadBuffers();
|
| +
|
| + if (async_upload_sync_) {
|
| + mapped_memory_->Free(async_upload_sync_);
|
| + async_upload_sync_ = NULL;
|
| + }
|
| +
|
| // Make sure the commands make it the service.
|
| WaitForCmd();
|
| }
|
| @@ -307,6 +327,7 @@ void GLES2Implementation::FreeUnusedSharedMemory() {
|
| }
|
|
|
| void GLES2Implementation::FreeEverything() {
|
| + FreeAllAsyncUploadBuffers();
|
| WaitForCmd();
|
| query_tracker_->Shrink();
|
| FreeUnusedSharedMemory();
|
| @@ -1364,13 +1385,8 @@ void GLES2Implementation::BufferDataHelper(
|
| }
|
|
|
| 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);
|
| - }
|
| + if (buffer)
|
| + RemoveTransferBuffer(buffer);
|
|
|
| // Create new buffer.
|
| buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
|
| @@ -1498,6 +1514,30 @@ void GLES2Implementation::BufferSubData(
|
| CheckGLError();
|
| }
|
|
|
| +void GLES2Implementation::RemoveTransferBuffer(BufferTracker::Buffer* buffer) {
|
| + int32 token = buffer->last_usage_token();
|
| + uint32 async_token = buffer->last_async_upload_token();
|
| +
|
| + if (async_token) {
|
| + if (HasAsyncUploadTokenPassed(async_token)) {
|
| + buffer_tracker_->Free(buffer);
|
| + } else {
|
| + detached_async_upload_memory_.push_back(
|
| + std::make_pair(buffer->address(), async_token));
|
| + buffer_tracker_->Unmanage(buffer);
|
| + }
|
| + } else if (token) {
|
| + if (helper_->HasTokenPassed(token))
|
| + buffer_tracker_->Free(buffer);
|
| + else
|
| + buffer_tracker_->FreePendingToken(buffer, token);
|
| + } else {
|
| + buffer_tracker_->Free(buffer);
|
| + }
|
| +
|
| + buffer_tracker_->RemoveBuffer(buffer->id());
|
| +}
|
| +
|
| bool GLES2Implementation::GetBoundPixelTransferBuffer(
|
| GLenum target,
|
| const char* function_name,
|
| @@ -1573,7 +1613,7 @@ void GLES2Implementation::CompressedTexImage2D(
|
| helper_->CompressedTexImage2D(
|
| target, level, internalformat, width, height, border, image_size,
|
| buffer->shm_id(), buffer->shm_offset() + offset);
|
| - buffer->set_transfer_ready_token(helper_->InsertToken());
|
| + buffer->set_last_usage_token(helper_->InsertToken());
|
| }
|
| return;
|
| }
|
| @@ -1614,7 +1654,7 @@ void GLES2Implementation::CompressedTexSubImage2D(
|
| helper_->CompressedTexSubImage2D(
|
| target, level, xoffset, yoffset, width, height, format, image_size,
|
| buffer->shm_id(), buffer->shm_offset() + offset);
|
| - buffer->set_transfer_ready_token(helper_->InsertToken());
|
| + buffer->set_last_usage_token(helper_->InsertToken());
|
| CheckGLError();
|
| }
|
| return;
|
| @@ -1701,7 +1741,7 @@ void GLES2Implementation::TexImage2D(
|
| helper_->TexImage2D(
|
| target, level, internalformat, width, height, border, format, type,
|
| buffer->shm_id(), buffer->shm_offset() + offset);
|
| - buffer->set_transfer_ready_token(helper_->InsertToken());
|
| + buffer->set_last_usage_token(helper_->InsertToken());
|
| CheckGLError();
|
| }
|
| return;
|
| @@ -1807,7 +1847,7 @@ void GLES2Implementation::TexSubImage2D(
|
| helper_->TexSubImage2D(
|
| target, level, xoffset, yoffset, width, height, format, type,
|
| buffer->shm_id(), buffer->shm_offset() + offset, false);
|
| - buffer->set_transfer_ready_token(helper_->InsertToken());
|
| + buffer->set_last_usage_token(helper_->InsertToken());
|
| CheckGLError();
|
| }
|
| return;
|
| @@ -2390,24 +2430,24 @@ void GLES2Implementation::GenQueriesEXTHelper(
|
| // deleted the resource.
|
|
|
| bool GLES2Implementation::BindBufferHelper(
|
| - GLenum target, GLuint buffer) {
|
| + GLenum target, GLuint buffer_id) {
|
| // TODO(gman): See note #1 above.
|
| bool changed = false;
|
| switch (target) {
|
| case GL_ARRAY_BUFFER:
|
| - if (bound_array_buffer_id_ != buffer) {
|
| - bound_array_buffer_id_ = buffer;
|
| + if (bound_array_buffer_id_ != buffer_id) {
|
| + bound_array_buffer_id_ = buffer_id;
|
| changed = true;
|
| }
|
| break;
|
| case GL_ELEMENT_ARRAY_BUFFER:
|
| - changed = vertex_array_object_manager_->BindElementArray(buffer);
|
| + changed = vertex_array_object_manager_->BindElementArray(buffer_id);
|
| break;
|
| case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
|
| - bound_pixel_pack_transfer_buffer_id_ = buffer;
|
| + bound_pixel_pack_transfer_buffer_id_ = buffer_id;
|
| break;
|
| case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
|
| - bound_pixel_unpack_transfer_buffer_id_ = buffer;
|
| + bound_pixel_unpack_transfer_buffer_id_ = buffer_id;
|
| break;
|
| default:
|
| changed = true;
|
| @@ -2415,7 +2455,7 @@ bool GLES2Implementation::BindBufferHelper(
|
| }
|
| // TODO(gman): There's a bug here. If the target is invalid the ID will not be
|
| // used even though it's marked it as used here.
|
| - GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(buffer);
|
| + GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(buffer_id);
|
| return changed;
|
| }
|
|
|
| @@ -2558,13 +2598,11 @@ void GLES2Implementation::DeleteBuffersHelper(
|
| bound_array_buffer_id_ = 0;
|
| }
|
| vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
|
| +
|
| 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]);
|
| - }
|
| + if (buffer)
|
| + RemoveTransferBuffer(buffer);
|
| +
|
| if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
|
| bound_pixel_unpack_transfer_buffer_id_ = 0;
|
| }
|
| @@ -3608,9 +3646,9 @@ void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
|
| // with this method of synchronization. Until this is fixed,
|
| // MapBufferCHROMIUM will not block even if the transfer is not ready
|
| // for these calls.
|
| - if (buffer->transfer_ready_token()) {
|
| - helper_->WaitForToken(buffer->transfer_ready_token());
|
| - buffer->set_transfer_ready_token(0);
|
| + if (buffer->last_usage_token()) {
|
| + helper_->WaitForToken(buffer->last_usage_token());
|
| + buffer->set_last_usage_token(0);
|
| }
|
| buffer->set_mapped(true);
|
|
|
| @@ -3644,6 +3682,71 @@ GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
|
| return true;
|
| }
|
|
|
| +bool GLES2Implementation::EnsureAsyncUploadSync() {
|
| + if (async_upload_sync_)
|
| + return true;
|
| +
|
| + int32 shm_id;
|
| + unsigned int shm_offset;
|
| + void* mem = mapped_memory_->Alloc(sizeof(AsyncUploadSync),
|
| + &shm_id,
|
| + &shm_offset);
|
| + if (!mem)
|
| + return false;
|
| +
|
| + async_upload_sync_shm_id_ = shm_id;
|
| + async_upload_sync_shm_offset_ = shm_offset;
|
| + async_upload_sync_ = static_cast<AsyncUploadSync*>(mem);
|
| + async_upload_sync_->Reset();
|
| +
|
| + return true;
|
| +}
|
| +
|
| +uint32 GLES2Implementation::NextAsyncUploadToken() {
|
| + async_upload_token_++;
|
| + if (async_upload_token_ == 0)
|
| + async_upload_token_++;
|
| + return async_upload_token_;
|
| +}
|
| +
|
| +void GLES2Implementation::PollAsyncUploads() {
|
| + if (!async_upload_sync_)
|
| + return;
|
| +
|
| + if (helper_->IsContextLost()) {
|
| + DetachedAsyncUploadMemoryList::iterator it =
|
| + detached_async_upload_memory_.begin();
|
| + while (it != detached_async_upload_memory_.end()) {
|
| + mapped_memory_->Free(it->first);
|
| + it = detached_async_upload_memory_.erase(it);
|
| + }
|
| + return;
|
| + }
|
| +
|
| + DetachedAsyncUploadMemoryList::iterator it =
|
| + detached_async_upload_memory_.begin();
|
| + while (it != detached_async_upload_memory_.end()) {
|
| + if (HasAsyncUploadTokenPassed(it->second)) {
|
| + mapped_memory_->Free(it->first);
|
| + it = detached_async_upload_memory_.erase(it);
|
| + } else {
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +void GLES2Implementation::FreeAllAsyncUploadBuffers() {
|
| + // Free all completed unmanaged async uploads buffers.
|
| + PollAsyncUploads();
|
| +
|
| + // Synchronously free rest of the unmanaged async upload buffers.
|
| + if (!detached_async_upload_memory_.empty()) {
|
| + WaitAllAsyncTexImage2DCHROMIUM();
|
| + WaitForCmd();
|
| + PollAsyncUploads();
|
| + }
|
| +}
|
| +
|
| void GLES2Implementation::AsyncTexImage2DCHROMIUM(
|
| GLenum target, GLint level, GLint internalformat, GLsizei width,
|
| GLsizei height, GLint border, GLenum format, GLenum type,
|
| @@ -3675,7 +3778,12 @@ void GLES2Implementation::AsyncTexImage2DCHROMIUM(
|
| if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
|
| helper_->AsyncTexImage2DCHROMIUM(
|
| target, level, internalformat, width, height, border, format, type,
|
| - 0, 0);
|
| + 0, 0, 0, 0, 0);
|
| + return;
|
| + }
|
| +
|
| + if (!EnsureAsyncUploadSync()) {
|
| + SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
|
| return;
|
| }
|
|
|
| @@ -3688,9 +3796,13 @@ void GLES2Implementation::AsyncTexImage2DCHROMIUM(
|
| bound_pixel_unpack_transfer_buffer_id_,
|
| "glAsyncTexImage2DCHROMIUM", offset, size);
|
| if (buffer && buffer->shm_id() != -1) {
|
| + uint32 async_token = NextAsyncUploadToken();
|
| + buffer->set_last_async_upload_token(async_token);
|
| helper_->AsyncTexImage2DCHROMIUM(
|
| target, level, internalformat, width, height, border, format, type,
|
| - buffer->shm_id(), buffer->shm_offset() + offset);
|
| + buffer->shm_id(), buffer->shm_offset() + offset,
|
| + async_token,
|
| + async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
|
| }
|
| }
|
|
|
| @@ -3723,6 +3835,11 @@ void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
|
| return;
|
| }
|
|
|
| + if (!EnsureAsyncUploadSync()) {
|
| + SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
|
| + return;
|
| + }
|
| +
|
| // Async uploads require a transfer buffer to be bound.
|
| // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
|
| // the buffer before the transfer is finished. (Currently such
|
| @@ -3732,9 +3849,13 @@ void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
|
| bound_pixel_unpack_transfer_buffer_id_,
|
| "glAsyncTexSubImage2DCHROMIUM", offset, size);
|
| if (buffer && buffer->shm_id() != -1) {
|
| + uint32 async_token = NextAsyncUploadToken();
|
| + buffer->set_last_async_upload_token(async_token);
|
| helper_->AsyncTexSubImage2DCHROMIUM(
|
| target, level, xoffset, yoffset, width, height, format, type,
|
| - buffer->shm_id(), buffer->shm_offset() + offset);
|
| + buffer->shm_id(), buffer->shm_offset() + offset,
|
| + async_token,
|
| + async_upload_sync_shm_id_, async_upload_sync_shm_offset_);
|
| }
|
| }
|
|
|
| @@ -3746,6 +3867,14 @@ void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
|
| CheckGLError();
|
| }
|
|
|
| +void GLES2Implementation::WaitAllAsyncTexImage2DCHROMIUM() {
|
| + GPU_CLIENT_SINGLE_THREAD_CHECK();
|
| + GPU_CLIENT_LOG("[" << GetLogPrefix()
|
| + << "] glWaitAllAsyncTexImage2DCHROMIUM()");
|
| + helper_->WaitAllAsyncTexImage2DCHROMIUM();
|
| + CheckGLError();
|
| +}
|
| +
|
| GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
|
| GPU_CLIENT_SINGLE_THREAD_CHECK();
|
| GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
|
|
|