summaryrefslogtreecommitdiffstats
path: root/gpu/command_buffer/service
diff options
context:
space:
mode:
authorbacker@chromium.org <backer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-09 23:12:03 +0000
committerbacker@chromium.org <backer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-09 23:12:03 +0000
commit2a7568a99f309fbd54bb33d9b3b35c88c63b8283 (patch)
treec7514b6b87e6a6323f0d983b2201885167b4d0cc /gpu/command_buffer/service
parent26385174eecea18029fcdf32eb1725924e75a5a8 (diff)
downloadchromium_src-2a7568a99f309fbd54bb33d9b3b35c88c63b8283.zip
chromium_src-2a7568a99f309fbd54bb33d9b3b35c88c63b8283.tar.gz
chromium_src-2a7568a99f309fbd54bb33d9b3b35c88c63b8283.tar.bz2
GPU: Move some GPU process specific code from ui/gl to gpu/command_buffer/service
No functional change. ui/gl/async_pixel_transfer_delegate* ---> gpu/command_buffer/service ui/gl/safe_shared_memory_pool* --> gpu/command_buffer/service BUG=235229 TEST=bots stay green Review URL: https://chromiumcodereview.appspot.com/14864015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@199297 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu/command_buffer/service')
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate.cc17
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate.h127
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_android.cc43
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_egl.cc808
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_egl.h90
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_idle.cc313
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_idle.h86
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_linux.cc30
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_mac.cc30
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_mock.cc4
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h25
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_stub.cc77
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_stub.h47
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_sync.cc135
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_sync.h51
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_win.cc30
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc24
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.h6
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_mock.h4
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc20
-rw-r--r--gpu/command_buffer/service/query_manager.cc6
-rw-r--r--gpu/command_buffer/service/safe_shared_memory_pool.cc150
-rw-r--r--gpu/command_buffer/service/safe_shared_memory_pool.h86
-rw-r--r--gpu/command_buffer/service/texture_manager.h10
24 files changed, 2169 insertions, 50 deletions
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate.cc
new file mode 100644
index 0000000..16f0f19
--- /dev/null
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+
+namespace gpu {
+
+AsyncPixelTransferState::AsyncPixelTransferState() {}
+
+AsyncPixelTransferState::~AsyncPixelTransferState() {}
+
+AsyncPixelTransferDelegate::AsyncPixelTransferDelegate() {}
+
+AsyncPixelTransferDelegate::~AsyncPixelTransferDelegate() {}
+
+} // namespace gpu
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate.h b/gpu/command_buffer/service/async_pixel_transfer_delegate.h
new file mode 100644
index 0000000..0a32683
--- /dev/null
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time.h"
+#include "gpu/gpu_export.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace base {
+class SharedMemory;
+}
+
+namespace gpu {
+
+struct AsyncTexImage2DParams {
+ GLenum target;
+ GLint level;
+ GLenum internal_format;
+ GLsizei width;
+ GLsizei height;
+ GLint border;
+ GLenum format;
+ GLenum type;
+};
+
+struct AsyncTexSubImage2DParams {
+ GLenum target;
+ GLint level;
+ GLint xoffset;
+ GLint yoffset;
+ GLsizei width;
+ GLsizei height;
+ GLenum format;
+ GLenum type;
+};
+
+struct AsyncMemoryParams {
+ base::SharedMemory* shared_memory;
+ uint32 shm_size;
+ uint32 shm_data_offset;
+ uint32 shm_data_size;
+};
+
+// AsyncPixelTransferState holds the resources required to do async
+// transfers on one texture. It should stay alive for the lifetime
+// of the texture to allow multiple transfers.
+class GPU_EXPORT AsyncPixelTransferState :
+ public base::SupportsWeakPtr<AsyncPixelTransferState> {
+ public:
+ virtual ~AsyncPixelTransferState();
+
+ // Returns true if there is a transfer in progress.
+ virtual bool TransferIsInProgress() = 0;
+
+ protected:
+ friend class base::RefCounted<AsyncPixelTransferState>;
+ AsyncPixelTransferState();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferState);
+};
+
+class GPU_EXPORT AsyncPixelTransferDelegate {
+ public:
+ typedef base::Callback<void(const AsyncMemoryParams&)> CompletionCallback;
+
+ static AsyncPixelTransferDelegate* Create(gfx::GLContext* context);
+
+ virtual ~AsyncPixelTransferDelegate();
+
+ virtual AsyncPixelTransferState* CreatePixelTransferState(
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) = 0;
+
+ virtual void BindCompletedAsyncTransfers() = 0;
+
+ // There's no guarantee that callback will run on the caller thread.
+ virtual void AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ const CompletionCallback& callback) = 0;
+
+ // The callback occurs on the caller thread, once the texture is
+ // safe/ready to be used.
+ virtual void AsyncTexImage2D(
+ AsyncPixelTransferState* state,
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) = 0;
+
+ virtual void AsyncTexSubImage2D(
+ AsyncPixelTransferState* state,
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) = 0;
+
+ // Block until the specified transfer completes.
+ virtual void WaitForTransferCompletion(
+ AsyncPixelTransferState* state) = 0;
+
+ virtual uint32 GetTextureUploadCount() = 0;
+ virtual base::TimeDelta GetTotalTextureUploadTime() = 0;
+
+ // ProcessMorePendingTransfers() will be called at a good time
+ // to process a small amount of pending transfer work while
+ // NeedsProcessMorePendingTransfers() returns true. Implementations
+ // that can't dispatch work to separate threads should use
+ // this to avoid blocking the caller thread inappropriately.
+ virtual void ProcessMorePendingTransfers() = 0;
+ virtual bool NeedsProcessMorePendingTransfers() = 0;
+
+ protected:
+ AsyncPixelTransferDelegate();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegate);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_H_
+
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_android.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate_android.cc
new file mode 100644
index 0000000..2d834c9
--- /dev/null
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_android.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+
+#include "base/debug/trace_event.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate_egl.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate_stub.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate_sync.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace gpu {
+
+// We only used threaded uploads when we can:
+// - Create EGLImages out of OpenGL textures (EGL_KHR_gl_texture_2D_image)
+// - Bind EGLImages to OpenGL textures (GL_OES_EGL_image)
+// - Use fences (to test for upload completion).
+AsyncPixelTransferDelegate* AsyncPixelTransferDelegate::Create(
+ gfx::GLContext* context) {
+ TRACE_EVENT0("gpu", "AsyncPixelTransferDelegate::Create");
+ switch (gfx::GetGLImplementation()) {
+ case gfx::kGLImplementationEGLGLES2:
+ DCHECK(context);
+ if (context->HasExtension("EGL_KHR_fence_sync") &&
+ context->HasExtension("EGL_KHR_image") &&
+ context->HasExtension("EGL_KHR_image_base") &&
+ context->HasExtension("EGL_KHR_gl_texture_2D_image") &&
+ context->HasExtension("GL_OES_EGL_image")) {
+ return new AsyncPixelTransferDelegateEGL;
+ }
+ LOG(INFO) << "Async pixel transfers not supported";
+ return new AsyncPixelTransferDelegateSync;
+ case gfx::kGLImplementationMockGL:
+ return new AsyncPixelTransferDelegateStub;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+} // namespace gpu
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_egl.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate_egl.cc
new file mode 100644
index 0000000..a630881
--- /dev/null
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_egl.cc
@@ -0,0 +1,808 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate_egl.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "gpu/command_buffer/service/safe_shared_memory_pool.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/scoped_binders.h"
+
+#if defined(OS_ANDROID)
+// TODO(epenner): Move thread priorities to base. (crbug.com/170549)
+#include <sys/resource.h>
+#endif
+
+using base::SharedMemory;
+using base::SharedMemoryHandle;
+
+namespace gpu {
+
+namespace {
+
+bool CheckErrors(const char* file, int line) {
+ EGLint eglerror;
+ GLenum glerror;
+ bool success = true;
+ while ((eglerror = eglGetError()) != EGL_SUCCESS) {
+ LOG(ERROR) << "Async transfer EGL error at "
+ << file << ":" << line << " " << eglerror;
+ success = false;
+ }
+ while ((glerror = glGetError()) != GL_NO_ERROR) {
+ LOG(ERROR) << "Async transfer OpenGL error at "
+ << file << ":" << line << " " << glerror;
+ success = false;
+ }
+ return success;
+}
+#define CHECK_GL() CheckErrors(__FILE__, __LINE__)
+
+const char kAsyncTransferThreadName[] = "AsyncTransferThread";
+
+// Regular glTexImage2D call.
+void DoTexImage2D(const AsyncTexImage2DParams& tex_params, void* data) {
+ glTexImage2D(
+ GL_TEXTURE_2D, tex_params.level, tex_params.internal_format,
+ tex_params.width, tex_params.height,
+ tex_params.border, tex_params.format, tex_params.type, data);
+}
+
+// Regular glTexSubImage2D call.
+void DoTexSubImage2D(const AsyncTexSubImage2DParams& tex_params, void* data) {
+ glTexSubImage2D(
+ GL_TEXTURE_2D, tex_params.level,
+ tex_params.xoffset, tex_params.yoffset,
+ tex_params.width, tex_params.height,
+ tex_params.format, tex_params.type, data);
+}
+
+// Full glTexSubImage2D call, from glTexImage2D params.
+void DoFullTexSubImage2D(const AsyncTexImage2DParams& tex_params, void* data) {
+ glTexSubImage2D(
+ GL_TEXTURE_2D, tex_params.level,
+ 0, 0, tex_params.width, tex_params.height,
+ tex_params.format, tex_params.type, data);
+}
+
+// Gets the address of the data from shared memory.
+void* GetAddress(SharedMemory* shared_memory, uint32 shm_data_offset) {
+ // Memory bounds have already been validated, so there
+ // are just DCHECKS here.
+ CHECK(shared_memory);
+ CHECK(shared_memory->memory());
+ return static_cast<int8*>(shared_memory->memory()) + shm_data_offset;
+}
+
+class TransferThread : public base::Thread {
+ public:
+ TransferThread() : base::Thread(kAsyncTransferThreadName) {
+ Start();
+ }
+ virtual ~TransferThread() {
+ Stop();
+ }
+
+ virtual void Init() OVERRIDE {
+ gfx::GLShareGroup* share_group = NULL;
+ bool software = false;
+ surface_ = new gfx::PbufferGLSurfaceEGL(software, gfx::Size(1,1));
+ surface_->Initialize();
+ context_ = gfx::GLContext::CreateGLContext(share_group,
+ surface_,
+ gfx::PreferDiscreteGpu);
+ bool is_current = context_->MakeCurrent(surface_);
+ DCHECK(is_current);
+
+#if defined(OS_ANDROID)
+ // TODO(epenner): Move thread priorities to base. (crbug.com/170549)
+ int nice_value = 10; // Idle priority.
+ setpriority(PRIO_PROCESS, base::PlatformThread::CurrentId(), nice_value);
+#endif
+
+ }
+
+ virtual void CleanUp() OVERRIDE {
+ surface_ = NULL;
+ context_->ReleaseCurrent(surface_);
+ context_ = NULL;
+ }
+
+ SafeSharedMemoryPool* safe_shared_memory_pool() {
+ return &safe_shared_memory_pool_;
+ }
+
+ private:
+ scoped_refptr<gfx::GLContext> context_;
+ scoped_refptr<gfx::GLSurface> surface_;
+
+ SafeSharedMemoryPool safe_shared_memory_pool_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransferThread);
+};
+
+base::LazyInstance<TransferThread>
+ g_transfer_thread = LAZY_INSTANCE_INITIALIZER;
+
+base::MessageLoopProxy* transfer_message_loop_proxy() {
+ return g_transfer_thread.Pointer()->message_loop_proxy();
+}
+
+SafeSharedMemoryPool* safe_shared_memory_pool() {
+ return g_transfer_thread.Pointer()->safe_shared_memory_pool();
+}
+
+} // namespace
+
+// Class which holds async pixel transfers state (EGLImage).
+// The EGLImage is accessed by either thread, but everything
+// else accessed only on the main thread.
+class TransferStateInternal
+ : public base::RefCountedThreadSafe<TransferStateInternal> {
+ public:
+ TransferStateInternal(GLuint texture_id,
+ const AsyncTexImage2DParams& define_params,
+ bool wait_for_uploads,
+ bool wait_for_creation,
+ bool use_image_preserved)
+ : texture_id_(texture_id),
+ thread_texture_id_(0),
+ transfer_completion_(true, true),
+ egl_image_(EGL_NO_IMAGE_KHR),
+ wait_for_uploads_(wait_for_uploads),
+ wait_for_creation_(wait_for_creation),
+ use_image_preserved_(use_image_preserved) {
+ define_params_ = define_params;
+ }
+
+ bool TransferIsInProgress() {
+ return !transfer_completion_.IsSignaled();
+ }
+
+ void BindTransfer() {
+ TRACE_EVENT2("gpu", "BindAsyncTransfer glEGLImageTargetTexture2DOES",
+ "width", define_params_.width,
+ "height", define_params_.height);
+ DCHECK(texture_id_);
+ DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_);
+
+ ui::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id_);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_);
+ bind_callback_.Run();
+
+ DCHECK(CHECK_GL());
+ }
+
+ void CreateEglImage(GLuint texture_id) {
+ TRACE_EVENT0("gpu", "eglCreateImageKHR");
+ DCHECK(texture_id);
+ DCHECK_EQ(egl_image_, EGL_NO_IMAGE_KHR);
+
+ EGLDisplay egl_display = eglGetCurrentDisplay();
+ EGLContext egl_context = eglGetCurrentContext();
+ EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR;
+ EGLClientBuffer egl_buffer =
+ reinterpret_cast<EGLClientBuffer>(texture_id);
+
+ EGLint image_preserved = use_image_preserved_ ? EGL_TRUE : EGL_FALSE;
+ EGLint egl_attrib_list[] = {
+ EGL_GL_TEXTURE_LEVEL_KHR, 0, // mip-level.
+ EGL_IMAGE_PRESERVED_KHR, image_preserved,
+ EGL_NONE
+ };
+ egl_image_ = eglCreateImageKHR(
+ egl_display,
+ egl_context,
+ egl_target,
+ egl_buffer,
+ egl_attrib_list);
+
+ DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_);
+ }
+
+ void CreateEglImageOnUploadThread() {
+ CreateEglImage(thread_texture_id_);
+ }
+
+ void CreateEglImageOnMainThreadIfNeeded() {
+ if (egl_image_ == EGL_NO_IMAGE_KHR) {
+ CreateEglImage(texture_id_);
+ if (wait_for_creation_) {
+ TRACE_EVENT0("gpu", "glFinish creation");
+ glFinish();
+ }
+ }
+ }
+
+ void WaitForLastUpload() {
+ // This glFinish is just a safe-guard for if uploads have some
+ // GPU action that needs to occur. We could use fences and try
+ // to do this less often. However, on older drivers fences are
+ // not always reliable (eg. Mali-400 just blocks forever).
+ if (wait_for_uploads_) {
+ TRACE_EVENT0("gpu", "glFinish");
+ glFinish();
+ }
+ }
+
+ void MarkAsTransferIsInProgress() {
+ transfer_completion_.Reset();
+ }
+
+ void MarkAsCompleted() {
+ transfer_completion_.Signal();
+ }
+
+ void WaitForTransferCompletion() {
+ transfer_completion_.Wait();
+ }
+
+ protected:
+ friend class base::RefCountedThreadSafe<TransferStateInternal>;
+ friend class AsyncPixelTransferDelegateEGL;
+
+ static void DeleteTexture(GLuint id) {
+ glDeleteTextures(1, &id);
+ }
+
+ virtual ~TransferStateInternal() {
+ if (egl_image_ != EGL_NO_IMAGE_KHR) {
+ EGLDisplay display = eglGetCurrentDisplay();
+ eglDestroyImageKHR(display, egl_image_);
+ }
+ if (thread_texture_id_) {
+ transfer_message_loop_proxy()->PostTask(FROM_HERE,
+ base::Bind(&DeleteTexture, thread_texture_id_));
+ }
+ }
+
+ // The 'real' texture.
+ GLuint texture_id_;
+
+ // The EGLImage sibling on the upload thread.
+ GLuint thread_texture_id_;
+
+ // Definition params for texture that needs binding.
+ AsyncTexImage2DParams define_params_;
+
+ // Indicates that an async transfer is in progress.
+ base::WaitableEvent transfer_completion_;
+
+ // It would be nice if we could just create a new EGLImage for
+ // every upload, but I found that didn't work, so this stores
+ // one for the lifetime of the texture.
+ EGLImageKHR egl_image_;
+
+ // Callback to invoke when AsyncTexImage2D is complete
+ // and the client can safely use the texture. This occurs
+ // during BindCompletedAsyncTransfers().
+ base::Closure bind_callback_;
+
+ // Customize when we block on fences (these are work-arounds).
+ bool wait_for_uploads_;
+ bool wait_for_creation_;
+ bool use_image_preserved_;
+};
+
+class TextureUploadStats
+ : public base::RefCountedThreadSafe<TextureUploadStats> {
+ public:
+ TextureUploadStats() : texture_upload_count_(0) {}
+
+ void AddUpload(base::TimeDelta transfer_time) {
+ base::AutoLock scoped_lock(lock_);
+ texture_upload_count_++;
+ total_texture_upload_time_ += transfer_time;
+ }
+
+ int GetStats(base::TimeDelta* total_texture_upload_time) {
+ base::AutoLock scoped_lock(lock_);
+ if (total_texture_upload_time)
+ *total_texture_upload_time = total_texture_upload_time_;
+ return texture_upload_count_;
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<TextureUploadStats>;
+
+ ~TextureUploadStats() {}
+
+ int texture_upload_count_;
+ base::TimeDelta total_texture_upload_time_;
+ base::Lock lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextureUploadStats);
+};
+
+namespace {
+
+// EGL needs thread-safe ref-counting, so this just wraps
+// an internal thread-safe ref-counted state object.
+class AsyncTransferStateImpl : public AsyncPixelTransferState {
+ public:
+ AsyncTransferStateImpl(GLuint texture_id,
+ const AsyncTexImage2DParams& define_params,
+ bool wait_for_uploads,
+ bool wait_for_creation,
+ bool use_image_preserved)
+ : internal_(new TransferStateInternal(texture_id,
+ define_params,
+ wait_for_uploads,
+ wait_for_creation,
+ use_image_preserved)) {
+ }
+ virtual ~AsyncTransferStateImpl() {}
+
+ virtual bool TransferIsInProgress() OVERRIDE {
+ return internal_->TransferIsInProgress();
+ }
+
+ void BindTransfer() {
+ internal_->BindTransfer();
+ }
+
+ scoped_refptr<TransferStateInternal> internal_;
+};
+
+} // namespace
+
+AsyncPixelTransferDelegateEGL::AsyncPixelTransferDelegateEGL() {
+ std::string vendor;
+ vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
+ is_imagination_ = vendor.find("Imagination") != std::string::npos;
+ is_qualcomm_ = vendor.find("Qualcomm") != std::string::npos;
+ // TODO(reveman): Skip this if --enable-gpu-benchmarking is not present.
+ texture_upload_stats_ = make_scoped_refptr(new TextureUploadStats);
+}
+
+AsyncPixelTransferDelegateEGL::~AsyncPixelTransferDelegateEGL() {}
+
+AsyncPixelTransferState* AsyncPixelTransferDelegateEGL::
+ CreatePixelTransferState(GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) {
+ // We can't wait on uploads on imagination (it can take 200ms+).
+ // In practice, they are complete when the CPU glTexSubImage2D completes.
+ bool wait_for_uploads = !is_imagination_;
+
+ // Qualcomm runs into texture corruption problems if the same texture is
+ // uploaded to with both async and normal uploads. Synchronize after EGLImage
+ // creation on the main thread as a work-around.
+ bool wait_for_creation = is_qualcomm_;
+
+ // Qualcomm has a race when using image_preserved=FALSE,
+ // which can result in black textures even after the first upload.
+ // Since using FALSE is mainly for performance (to avoid layout changes),
+ // but Qualcomm itself doesn't seem to get any performance benefit,
+ // we just using image_preservedd=TRUE on Qualcomm as a work-around.
+ bool use_image_preserved = is_qualcomm_ || is_imagination_;
+
+ return new AsyncTransferStateImpl(texture_id,
+ define_params,
+ wait_for_uploads,
+ wait_for_creation,
+ use_image_preserved);
+}
+
+void AsyncPixelTransferDelegateEGL::BindCompletedAsyncTransfers() {
+ while(!pending_allocations_.empty()) {
+ if (!pending_allocations_.front().get()) {
+ pending_allocations_.pop_front();
+ continue;
+ }
+ scoped_refptr<TransferStateInternal> state =
+ static_cast<AsyncTransferStateImpl*>
+ (pending_allocations_.front().get())->internal_.get();
+ // Terminate early, as all transfers finish in order, currently.
+ if (state->TransferIsInProgress())
+ break;
+ // If the transfer is finished, bind it to the texture
+ // and remove it from pending list.
+ state->BindTransfer();
+ pending_allocations_.pop_front();
+ }
+}
+
+void AsyncPixelTransferDelegateEGL::AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ const CompletionCallback& callback) {
+ DCHECK(mem_params.shared_memory);
+ DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
+ mem_params.shm_size);
+ // Post a PerformNotifyCompletion task to the upload thread. This task
+ // will run after all async transfers are complete.
+ transfer_message_loop_proxy()->PostTask(
+ FROM_HERE,
+ base::Bind(&AsyncPixelTransferDelegateEGL::PerformNotifyCompletion,
+ mem_params,
+ base::Owned(
+ new ScopedSafeSharedMemory(safe_shared_memory_pool(),
+ mem_params.shared_memory,
+ mem_params.shm_size)),
+ callback));
+}
+
+void AsyncPixelTransferDelegateEGL::WaitForTransferCompletion(
+ AsyncPixelTransferState* transfer_state) {
+ TRACE_EVENT0("gpu", "WaitForTransferCompletion");
+ scoped_refptr<TransferStateInternal> state =
+ static_cast<AsyncTransferStateImpl*>(transfer_state)->internal_.get();
+ DCHECK(state);
+ DCHECK(state->texture_id_);
+
+ if (state->TransferIsInProgress()) {
+#if defined(OS_ANDROID)
+ // TODO(epenner): Move thread priorities to base. (crbug.com/170549)
+ int default_nice_value = 0; // Default priority.
+ int idle_nice_value = 10; // Idle priority.
+ setpriority(PRIO_PROCESS,
+ g_transfer_thread.Pointer()->thread_id(),
+ default_nice_value);
+#endif
+
+ state->WaitForTransferCompletion();
+ DCHECK(!state->TransferIsInProgress());
+
+#if defined(OS_ANDROID)
+ // TODO(epenner): Move thread priorities to base. (crbug.com/170549)
+ setpriority(PRIO_PROCESS,
+ g_transfer_thread.Pointer()->thread_id(),
+ idle_nice_value);
+#endif
+ }
+}
+
+void AsyncPixelTransferDelegateEGL::AsyncTexImage2D(
+ AsyncPixelTransferState* transfer_state,
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) {
+ if (WorkAroundAsyncTexImage2D(transfer_state, tex_params,
+ mem_params, bind_callback))
+ return;
+
+ scoped_refptr<TransferStateInternal> state =
+ static_cast<AsyncTransferStateImpl*>(transfer_state)->internal_.get();
+ DCHECK(mem_params.shared_memory);
+ DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
+ mem_params.shm_size);
+ DCHECK(state);
+ DCHECK(state->texture_id_);
+ DCHECK(!state->TransferIsInProgress());
+ DCHECK_EQ(state->egl_image_, EGL_NO_IMAGE_KHR);
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
+ DCHECK_EQ(tex_params.level, 0);
+
+ // Mark the transfer in progress and save the late bind
+ // callback, so we can notify the client when it is bound.
+ pending_allocations_.push_back(transfer_state->AsWeakPtr());
+ state->bind_callback_ = bind_callback;
+
+ // Mark the transfer in progress.
+ state->MarkAsTransferIsInProgress();
+
+ // Duplicate the shared memory so there is no way we can get
+ // a use-after-free of the raw pixels.
+ transfer_message_loop_proxy()->PostTask(FROM_HERE,
+ base::Bind(
+ &AsyncPixelTransferDelegateEGL::PerformAsyncTexImage2D,
+ state,
+ tex_params,
+ mem_params,
+ base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
+ mem_params.shared_memory,
+ mem_params.shm_size))));
+
+
+ DCHECK(CHECK_GL());
+}
+
+void AsyncPixelTransferDelegateEGL::AsyncTexSubImage2D(
+ AsyncPixelTransferState* transfer_state,
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) {
+ TRACE_EVENT2("gpu", "AsyncTexSubImage2D",
+ "width", tex_params.width,
+ "height", tex_params.height);
+ if (WorkAroundAsyncTexSubImage2D(transfer_state, tex_params, mem_params))
+ return;
+ scoped_refptr<TransferStateInternal> state =
+ static_cast<AsyncTransferStateImpl*>(transfer_state)->internal_.get();
+
+ DCHECK(state->texture_id_);
+ DCHECK(!state->TransferIsInProgress());
+ DCHECK(mem_params.shared_memory);
+ DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
+ mem_params.shm_size);
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
+ DCHECK_EQ(tex_params.level, 0);
+
+ // Mark the transfer in progress.
+ state->MarkAsTransferIsInProgress();
+
+ // If this wasn't async allocated, we don't have an EGLImage yet.
+ // Create the EGLImage if it hasn't already been created.
+ state->CreateEglImageOnMainThreadIfNeeded();
+
+ // Duplicate the shared memory so there are no way we can get
+ // a use-after-free of the raw pixels.
+ transfer_message_loop_proxy()->PostTask(FROM_HERE,
+ base::Bind(
+ &AsyncPixelTransferDelegateEGL::PerformAsyncTexSubImage2D,
+ state,
+ tex_params,
+ mem_params,
+ base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
+ mem_params.shared_memory,
+ mem_params.shm_size)),
+ texture_upload_stats_));
+
+ DCHECK(CHECK_GL());
+}
+
+uint32 AsyncPixelTransferDelegateEGL::GetTextureUploadCount() {
+ CHECK(texture_upload_stats_);
+ return texture_upload_stats_->GetStats(NULL);
+}
+
+base::TimeDelta AsyncPixelTransferDelegateEGL::GetTotalTextureUploadTime() {
+ CHECK(texture_upload_stats_);
+ base::TimeDelta total_texture_upload_time;
+ texture_upload_stats_->GetStats(&total_texture_upload_time);
+ return total_texture_upload_time;
+}
+
+void AsyncPixelTransferDelegateEGL::ProcessMorePendingTransfers() {
+}
+
+bool AsyncPixelTransferDelegateEGL::NeedsProcessMorePendingTransfers() {
+ return false;
+}
+
+namespace {
+void SetGlParametersForEglImageTexture() {
+ // These params are needed for EGLImage creation to succeed on several
+ // Android devices. I couldn't find this requirement in the EGLImage
+ // extension spec, but several devices fail without it.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+}
+} // namespace
+
+void AsyncPixelTransferDelegateEGL::PerformNotifyCompletion(
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ const CompletionCallback& callback) {
+ TRACE_EVENT0("gpu", "PerformNotifyCompletion");
+ AsyncMemoryParams safe_mem_params = mem_params;
+ safe_mem_params.shared_memory = safe_shared_memory->shared_memory();
+ callback.Run(safe_mem_params);
+}
+
+void AsyncPixelTransferDelegateEGL::PerformAsyncTexImage2D(
+ TransferStateInternal* state,
+ AsyncTexImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory) {
+ TRACE_EVENT2("gpu", "PerformAsyncTexImage",
+ "width", tex_params.width,
+ "height", tex_params.height);
+ DCHECK(state);
+ DCHECK(!state->thread_texture_id_);
+ DCHECK_EQ(0, tex_params.level);
+ DCHECK_EQ(EGL_NO_IMAGE_KHR, state->egl_image_);
+
+ void* data = GetAddress(safe_shared_memory->shared_memory(),
+ mem_params.shm_data_offset);
+ {
+ TRACE_EVENT0("gpu", "glTexImage2D no data");
+ glGenTextures(1, &state->thread_texture_id_);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, state->thread_texture_id_);
+
+ SetGlParametersForEglImageTexture();
+
+ // If we need to use image_preserved, we pass the data with
+ // the allocation. Otherwise we use a NULL allocation to
+ // try to avoid any costs associated with creating the EGLImage.
+ if (state->use_image_preserved_)
+ DoTexImage2D(tex_params, data);
+ else
+ DoTexImage2D(tex_params, NULL);
+ }
+
+ state->CreateEglImageOnUploadThread();
+
+ {
+ TRACE_EVENT0("gpu", "glTexSubImage2D with data");
+
+ // If we didn't use image_preserved, we haven't uploaded
+ // the data yet, so we do this with a full texSubImage.
+ if (!state->use_image_preserved_)
+ DoFullTexSubImage2D(tex_params, data);
+ }
+
+ state->WaitForLastUpload();
+ state->MarkAsCompleted();
+
+ DCHECK(CHECK_GL());
+}
+
+void AsyncPixelTransferDelegateEGL::PerformAsyncTexSubImage2D(
+ TransferStateInternal* state,
+ AsyncTexSubImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ scoped_refptr<TextureUploadStats> texture_upload_stats) {
+ TRACE_EVENT2("gpu", "PerformAsyncTexSubImage2D",
+ "width", tex_params.width,
+ "height", tex_params.height);
+
+ DCHECK(state);
+ DCHECK_NE(EGL_NO_IMAGE_KHR, state->egl_image_);
+ DCHECK_EQ(0, tex_params.level);
+
+ void* data = GetAddress(safe_shared_memory->shared_memory(),
+ mem_params.shm_data_offset);
+
+ base::TimeTicks begin_time;
+ if (texture_upload_stats)
+ begin_time = base::TimeTicks::HighResNow();
+
+ if (!state->thread_texture_id_) {
+ TRACE_EVENT0("gpu", "glEGLImageTargetTexture2DOES");
+ glGenTextures(1, &state->thread_texture_id_);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, state->thread_texture_id_);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, state->egl_image_);
+ } else {
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, state->thread_texture_id_);
+ }
+ {
+ TRACE_EVENT0("gpu", "glTexSubImage2D");
+ DoTexSubImage2D(tex_params, data);
+ }
+ state->WaitForLastUpload();
+ state->MarkAsCompleted();
+
+ DCHECK(CHECK_GL());
+ if (texture_upload_stats) {
+ texture_upload_stats->AddUpload(
+ base::TimeTicks::HighResNow() - begin_time);
+ }
+}
+
+namespace {
+bool IsPowerOfTwo (unsigned int x) {
+ return ((x != 0) && !(x & (x - 1)));
+}
+
+bool IsMultipleOfEight(unsigned int x) {
+ return (x & 7) == 0;
+}
+
+bool DimensionsSupportImgFastPath(int width, int height) {
+ // Multiple of eight, but not a power of two.
+ return IsMultipleOfEight(width) &&
+ IsMultipleOfEight(height) &&
+ !(IsPowerOfTwo(width) &&
+ IsPowerOfTwo(height));
+}
+} // namespace
+
+// It is very difficult to stream uploads on Imagination GPUs:
+// - glTexImage2D defers a swizzle/stall until draw-time
+// - glTexSubImage2D will sleep for 16ms on a good day, and 100ms
+// or longer if OpenGL is in heavy use by another thread.
+// The one combination that avoids these problems requires:
+// a.) Allocations/Uploads must occur on different threads/contexts.
+// b.) Texture size must be non-power-of-two.
+// When using a+b, uploads will be incorrect/corrupt unless:
+// c.) Texture size must be a multiple-of-eight.
+//
+// To achieve a.) we allocate synchronously on the main thread followed
+// by uploading on the upload thread. When b/c are not true we fall back
+// on purely synchronous allocation/upload on the main thread.
+
+bool AsyncPixelTransferDelegateEGL::WorkAroundAsyncTexImage2D(
+ AsyncPixelTransferState* transfer_state,
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) {
+ if (!is_imagination_)
+ return false;
+ scoped_refptr<TransferStateInternal> state =
+ static_cast<AsyncTransferStateImpl*>(transfer_state)->internal_.get();
+
+ // On imagination we allocate synchronously all the time, even
+ // if the dimensions support fast uploads. This is for part a.)
+ // above, so allocations occur on a different thread/context as uploads.
+ void* data = GetAddress(mem_params.shared_memory,
+ mem_params.shm_data_offset);
+ SetGlParametersForEglImageTexture();
+
+ {
+ TRACE_EVENT0("gpu", "glTexImage2D with data");
+ DoTexImage2D(tex_params, data);
+ }
+
+ // The allocation has already occured, so mark it as finished
+ // and ready for binding.
+ CHECK(!state->TransferIsInProgress());
+
+ // If the dimensions support fast async uploads, create the
+ // EGLImage for future uploads. The late bind should not
+ // be needed since the EGLImage was created from the main thread
+ // texture, but this is required to prevent an imagination driver crash.
+ if (DimensionsSupportImgFastPath(tex_params.width, tex_params.height)) {
+ state->CreateEglImageOnMainThreadIfNeeded();
+ pending_allocations_.push_back(transfer_state->AsWeakPtr());
+ state->bind_callback_ = bind_callback;
+ }
+
+ DCHECK(CHECK_GL());
+ return true;
+}
+
+bool AsyncPixelTransferDelegateEGL::WorkAroundAsyncTexSubImage2D(
+ AsyncPixelTransferState* transfer_state,
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) {
+ if (!is_imagination_)
+ return false;
+
+ // If the dimensions support fast async uploads, we can use the
+ // normal async upload path for uploads.
+ if (DimensionsSupportImgFastPath(tex_params.width, tex_params.height))
+ return false;
+
+ scoped_refptr<TransferStateInternal> state =
+ static_cast<AsyncTransferStateImpl*>(transfer_state)->internal_.get();
+
+ // Fall back on a synchronous stub as we don't have a known fast path.
+ // Also, older ICS drivers crash when we do any glTexSubImage2D on the
+ // same thread. To work around this we do glTexImage2D instead. Since
+ // we didn't create an EGLImage for this texture (see above), this is
+ // okay, but it limits this API to full updates for now.
+ DCHECK(!state->egl_image_);
+ DCHECK_EQ(tex_params.xoffset, 0);
+ DCHECK_EQ(tex_params.yoffset, 0);
+ DCHECK_EQ(state->define_params_.width, tex_params.width);
+ DCHECK_EQ(state->define_params_.height, tex_params.height);
+ DCHECK_EQ(state->define_params_.level, tex_params.level);
+ DCHECK_EQ(state->define_params_.format, tex_params.format);
+ DCHECK_EQ(state->define_params_.type, tex_params.type);
+
+ void* data = GetAddress(mem_params.shared_memory,
+ mem_params.shm_data_offset);
+ base::TimeTicks begin_time;
+ if (texture_upload_stats_)
+ begin_time = base::TimeTicks::HighResNow();
+ {
+ TRACE_EVENT0("gpu", "glTexSubImage2D");
+ // Note we use define_params_ instead of tex_params.
+ // The DCHECKs above verify this is always the same.
+ DoTexImage2D(state->define_params_, data);
+ }
+ if (texture_upload_stats_) {
+ texture_upload_stats_->AddUpload(
+ base::TimeTicks::HighResNow() - begin_time);
+ }
+
+ DCHECK(CHECK_GL());
+ return true;
+}
+
+} // namespace gpu
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_egl.h b/gpu/command_buffer/service/async_pixel_transfer_delegate_egl.h
new file mode 100644
index 0000000..39a63cd
--- /dev/null
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_egl.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_EGL_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_EGL_H_
+
+#include <list>
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+
+namespace gpu {
+class ScopedSafeSharedMemory;
+class TextureUploadStats;
+class TransferStateInternal;
+
+// Class which handles async pixel transfers using EGLImageKHR and another
+// upload thread
+class AsyncPixelTransferDelegateEGL
+ : public AsyncPixelTransferDelegate,
+ public base::SupportsWeakPtr<AsyncPixelTransferDelegateEGL> {
+ public:
+ AsyncPixelTransferDelegateEGL();
+ virtual ~AsyncPixelTransferDelegateEGL();
+
+ // Implement AsyncPixelTransferDelegate:
+ virtual AsyncPixelTransferState* CreatePixelTransferState(
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) OVERRIDE;
+ virtual void BindCompletedAsyncTransfers() OVERRIDE;
+ virtual void AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ const CompletionCallback& callback) OVERRIDE;
+ virtual void AsyncTexImage2D(
+ AsyncPixelTransferState* state,
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) OVERRIDE;
+ virtual void AsyncTexSubImage2D(
+ AsyncPixelTransferState* state,
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) OVERRIDE;
+ virtual void WaitForTransferCompletion(
+ AsyncPixelTransferState* state) OVERRIDE;
+ virtual uint32 GetTextureUploadCount() OVERRIDE;
+ virtual base::TimeDelta GetTotalTextureUploadTime() OVERRIDE;
+ virtual void ProcessMorePendingTransfers() OVERRIDE;
+ virtual bool NeedsProcessMorePendingTransfers() OVERRIDE;
+
+ private:
+ static void PerformNotifyCompletion(
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ const CompletionCallback& callback);
+ static void PerformAsyncTexImage2D(
+ TransferStateInternal* state,
+ AsyncTexImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory);
+ static void PerformAsyncTexSubImage2D(
+ TransferStateInternal* state,
+ AsyncTexSubImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ scoped_refptr<TextureUploadStats> texture_upload_stats);
+
+ // Returns true if a work-around was used.
+ bool WorkAroundAsyncTexImage2D(
+ AsyncPixelTransferState* state,
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback);
+ bool WorkAroundAsyncTexSubImage2D(
+ AsyncPixelTransferState* state,
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params);
+
+ typedef std::list<base::WeakPtr<AsyncPixelTransferState> > TransferQueue;
+ TransferQueue pending_allocations_;
+
+ scoped_refptr<TextureUploadStats> texture_upload_stats_;
+ bool is_imagination_;
+ bool is_qualcomm_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateEGL);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_EGL_H_
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_idle.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate_idle.cc
new file mode 100644
index 0000000..17b3fd2
--- /dev/null
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_idle.cc
@@ -0,0 +1,313 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate_idle.h"
+
+#include "base/bind.h"
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
+#include "base/memory/shared_memory.h"
+#include "gpu/command_buffer/service/safe_shared_memory_pool.h"
+#include "ui/gl/scoped_binders.h"
+
+using base::SharedMemory;
+using base::SharedMemoryHandle;
+
+namespace gpu {
+
+namespace {
+
+// Gets the address of the data from shared memory.
+void* GetAddress(SharedMemory* shared_memory, uint32 shm_data_offset) {
+ // Memory bounds have already been validated, so there
+ // are just DCHECKS here.
+ DCHECK(shared_memory);
+ DCHECK(shared_memory->memory());
+ return static_cast<int8*>(shared_memory->memory()) + shm_data_offset;
+}
+
+base::LazyInstance<SafeSharedMemoryPool> g_safe_shared_memory_pool =
+ LAZY_INSTANCE_INITIALIZER;
+
+SafeSharedMemoryPool* safe_shared_memory_pool() {
+ return g_safe_shared_memory_pool.Pointer();
+}
+
+static uint64 g_next_pixel_transfer_state_id = 1;
+
+class AsyncPixelTransferStateImpl : public AsyncPixelTransferState {
+ public:
+ typedef base::Callback<void(GLuint)> TransferCallback;
+
+ explicit AsyncPixelTransferStateImpl(GLuint texture_id)
+ : id_(g_next_pixel_transfer_state_id++),
+ texture_id_(texture_id),
+ transfer_in_progress_(false) {
+ }
+ virtual ~AsyncPixelTransferStateImpl() {}
+
+ // Implement AsyncPixelTransferState:
+ virtual bool TransferIsInProgress() OVERRIDE {
+ return transfer_in_progress_;
+ }
+
+ uint64 id() const { return id_; }
+
+ void set_transfer_in_progress(bool transfer_in_progress) {
+ transfer_in_progress_ = transfer_in_progress;
+ }
+
+ void PerformTransfer(const TransferCallback& callback) {
+ DCHECK(texture_id_);
+ DCHECK(transfer_in_progress_);
+ callback.Run(texture_id_);
+ transfer_in_progress_ = false;
+ }
+
+ private:
+ uint64 id_;
+ GLuint texture_id_;
+ bool transfer_in_progress_;
+};
+
+} // namespace
+
+AsyncPixelTransferDelegateIdle::Task::Task(
+ uint64 transfer_id, const base::Closure& task)
+ : transfer_id(transfer_id),
+ task(task) {
+}
+
+AsyncPixelTransferDelegateIdle::Task::~Task() {}
+
+AsyncPixelTransferDelegateIdle::AsyncPixelTransferDelegateIdle()
+ : texture_upload_count_(0) {
+}
+
+AsyncPixelTransferDelegateIdle::~AsyncPixelTransferDelegateIdle() {}
+
+AsyncPixelTransferState* AsyncPixelTransferDelegateIdle::
+ CreatePixelTransferState(GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) {
+ return new AsyncPixelTransferStateImpl(texture_id);
+}
+
+void AsyncPixelTransferDelegateIdle::BindCompletedAsyncTransfers() {
+ // Everything is already bound.
+}
+
+void AsyncPixelTransferDelegateIdle::AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ const CompletionCallback& callback) {
+ if (tasks_.empty()) {
+ callback.Run(mem_params);
+ return;
+ }
+
+ tasks_.push_back(
+ Task(0, // 0 transfer_id for notification tasks.
+ base::Bind(
+ &AsyncPixelTransferDelegateIdle::PerformNotifyCompletion,
+ AsWeakPtr(),
+ mem_params,
+ base::Owned(new ScopedSafeSharedMemory(
+ safe_shared_memory_pool(),
+ mem_params.shared_memory,
+ mem_params.shm_size)),
+ callback)));
+}
+
+void AsyncPixelTransferDelegateIdle::AsyncTexImage2D(
+ AsyncPixelTransferState* transfer_state,
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) {
+ AsyncPixelTransferStateImpl* state =
+ static_cast<AsyncPixelTransferStateImpl*>(transfer_state);
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
+ DCHECK(mem_params.shared_memory);
+ DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
+ mem_params.shm_size);
+ DCHECK(state);
+
+ tasks_.push_back(
+ Task(state->id(),
+ base::Bind(
+ &AsyncPixelTransferStateImpl::PerformTransfer,
+ base::AsWeakPtr(state),
+ base::Bind(
+ &AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D,
+ AsWeakPtr(),
+ tex_params,
+ mem_params,
+ bind_callback,
+ base::Owned(new ScopedSafeSharedMemory(
+ safe_shared_memory_pool(),
+ mem_params.shared_memory,
+ mem_params.shm_size))))));
+
+ state->set_transfer_in_progress(true);
+}
+
+void AsyncPixelTransferDelegateIdle::AsyncTexSubImage2D(
+ AsyncPixelTransferState* transfer_state,
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) {
+ AsyncPixelTransferStateImpl* state =
+ static_cast<AsyncPixelTransferStateImpl*>(transfer_state);
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
+ DCHECK(mem_params.shared_memory);
+ DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
+ mem_params.shm_size);
+ DCHECK(state);
+
+ tasks_.push_back(
+ Task(state->id(),
+ base::Bind(
+ &AsyncPixelTransferStateImpl::PerformTransfer,
+ base::AsWeakPtr(state),
+ base::Bind(
+ &AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D,
+ AsWeakPtr(),
+ tex_params,
+ mem_params,
+ base::Owned(new ScopedSafeSharedMemory(
+ safe_shared_memory_pool(),
+ mem_params.shared_memory,
+ mem_params.shm_size))))));
+
+ state->set_transfer_in_progress(true);
+}
+
+void AsyncPixelTransferDelegateIdle::WaitForTransferCompletion(
+ AsyncPixelTransferState* transfer_state) {
+ AsyncPixelTransferStateImpl* state =
+ static_cast<AsyncPixelTransferStateImpl*>(transfer_state);
+ DCHECK(state);
+
+ for (std::list<Task>::iterator iter = tasks_.begin();
+ iter != tasks_.end(); ++iter) {
+ if (iter->transfer_id != state->id())
+ continue;
+
+ (*iter).task.Run();
+ tasks_.erase(iter);
+ break;
+ }
+
+ ProcessNotificationTasks();
+}
+
+uint32 AsyncPixelTransferDelegateIdle::GetTextureUploadCount() {
+ return texture_upload_count_;
+}
+
+base::TimeDelta AsyncPixelTransferDelegateIdle::GetTotalTextureUploadTime() {
+ return total_texture_upload_time_;
+}
+
+void AsyncPixelTransferDelegateIdle::ProcessMorePendingTransfers() {
+ if (tasks_.empty())
+ return;
+
+ // First task should always be a pixel transfer task.
+ DCHECK(tasks_.front().transfer_id);
+ tasks_.front().task.Run();
+ tasks_.pop_front();
+
+ ProcessNotificationTasks();
+}
+
+bool AsyncPixelTransferDelegateIdle::NeedsProcessMorePendingTransfers() {
+ return !tasks_.empty();
+}
+
+void AsyncPixelTransferDelegateIdle::ProcessNotificationTasks() {
+ while (!tasks_.empty()) {
+ // Stop when we reach a pixel transfer task.
+ if (tasks_.front().transfer_id)
+ return;
+
+ tasks_.front().task.Run();
+ tasks_.pop_front();
+ }
+}
+
+void AsyncPixelTransferDelegateIdle::PerformNotifyCompletion(
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ const CompletionCallback& callback) {
+ TRACE_EVENT0("gpu", "PerformNotifyCompletion");
+ AsyncMemoryParams safe_mem_params = mem_params;
+ safe_mem_params.shared_memory = safe_shared_memory->shared_memory();
+ callback.Run(safe_mem_params);
+}
+
+void AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D(
+ AsyncTexImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ const base::Closure& bind_callback,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ GLuint texture_id) {
+ TRACE_EVENT2("gpu", "PerformAsyncTexImage2D",
+ "width", tex_params.width,
+ "height", tex_params.height);
+
+ void* data = GetAddress(safe_shared_memory->shared_memory(),
+ mem_params.shm_data_offset);
+
+ ui::ScopedTextureBinder texture_binder(tex_params.target, texture_id);
+
+ {
+ TRACE_EVENT0("gpu", "glTexImage2D");
+ glTexImage2D(
+ tex_params.target,
+ tex_params.level,
+ tex_params.internal_format,
+ tex_params.width,
+ tex_params.height,
+ tex_params.border,
+ tex_params.format,
+ tex_params.type,
+ data);
+ }
+
+ // The texture is already fully bound so just call it now.
+ bind_callback.Run();
+}
+
+void AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D(
+ AsyncTexSubImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ GLuint texture_id) {
+ TRACE_EVENT2("gpu", "PerformAsyncTexSubImage2D",
+ "width", tex_params.width,
+ "height", tex_params.height);
+
+ void* data = GetAddress(safe_shared_memory->shared_memory(),
+ mem_params.shm_data_offset);
+
+ base::TimeTicks begin_time(base::TimeTicks::HighResNow());
+ ui::ScopedTextureBinder texture_binder(tex_params.target, texture_id);
+
+ {
+ TRACE_EVENT0("gpu", "glTexSubImage2D");
+ glTexSubImage2D(
+ tex_params.target,
+ tex_params.level,
+ tex_params.xoffset,
+ tex_params.yoffset,
+ tex_params.width,
+ tex_params.height,
+ tex_params.format,
+ tex_params.type,
+ data);
+ }
+
+ texture_upload_count_++;
+ total_texture_upload_time_ += base::TimeTicks::HighResNow() - begin_time;
+}
+
+} // namespace gpu
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_idle.h b/gpu/command_buffer/service/async_pixel_transfer_delegate_idle.h
new file mode 100644
index 0000000..4e62cde
--- /dev/null
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_idle.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_IDLE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_IDLE_H_
+
+#include <list>
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+
+namespace gpu {
+class ScopedSafeSharedMemory;
+
+// Class which handles async pixel transfers in a platform
+// independent way.
+class AsyncPixelTransferDelegateIdle : public AsyncPixelTransferDelegate,
+ public base::SupportsWeakPtr<AsyncPixelTransferDelegateIdle> {
+ public:
+ AsyncPixelTransferDelegateIdle();
+ virtual ~AsyncPixelTransferDelegateIdle();
+
+ // implement AsyncPixelTransferDelegate:
+ virtual AsyncPixelTransferState* CreatePixelTransferState(
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) OVERRIDE;
+ virtual void BindCompletedAsyncTransfers() OVERRIDE;
+ virtual void AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ const CompletionCallback& callback) OVERRIDE;
+ virtual void AsyncTexImage2D(
+ AsyncPixelTransferState* transfer_state,
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) OVERRIDE;
+ virtual void AsyncTexSubImage2D(
+ AsyncPixelTransferState* transfer_state,
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) OVERRIDE;
+ virtual void WaitForTransferCompletion(
+ AsyncPixelTransferState* transfer_state) OVERRIDE;
+ virtual uint32 GetTextureUploadCount() OVERRIDE;
+ virtual base::TimeDelta GetTotalTextureUploadTime() OVERRIDE;
+ virtual void ProcessMorePendingTransfers() OVERRIDE;
+ virtual bool NeedsProcessMorePendingTransfers() OVERRIDE;
+
+ private:
+ struct Task {
+ Task(uint64 transfer_id, const base::Closure& task);
+ ~Task();
+
+ // This is non-zero if pixel transfer task.
+ uint64 transfer_id;
+
+ base::Closure task;
+ };
+
+ void ProcessNotificationTasks();
+
+ void PerformNotifyCompletion(
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ const CompletionCallback& callback);
+ void PerformAsyncTexImage2D(
+ AsyncTexImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ const base::Closure& bind_callback,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ GLuint texture_id);
+ void PerformAsyncTexSubImage2D(
+ AsyncTexSubImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ GLuint texture_id);
+
+ int texture_upload_count_;
+ base::TimeDelta total_texture_upload_time_;
+
+ std::list<Task> tasks_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateIdle);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_IDLE_H_
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_linux.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate_linux.cc
new file mode 100644
index 0000000..76a3e4b
--- /dev/null
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_linux.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+
+#include "base/debug/trace_event.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate_idle.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate_stub.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace gpu {
+
+AsyncPixelTransferDelegate* AsyncPixelTransferDelegate::Create(
+ gfx::GLContext* context) {
+ TRACE_EVENT0("gpu", "AsyncPixelTransferDelegate::Create");
+ switch (gfx::GetGLImplementation()) {
+ case gfx::kGLImplementationOSMesaGL:
+ case gfx::kGLImplementationDesktopGL:
+ case gfx::kGLImplementationEGLGLES2:
+ return new AsyncPixelTransferDelegateIdle;
+ case gfx::kGLImplementationMockGL:
+ return new AsyncPixelTransferDelegateStub;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+} // namespace gpu
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_mac.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate_mac.cc
new file mode 100644
index 0000000..496359c
--- /dev/null
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_mac.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+
+#include "base/debug/trace_event.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate_idle.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate_stub.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace gpu {
+
+AsyncPixelTransferDelegate* AsyncPixelTransferDelegate::Create(
+ gfx::GLContext* context) {
+ TRACE_EVENT0("gpu", "AsyncPixelTransferDelegate::Create");
+ switch (gfx::GetGLImplementation()) {
+ case gfx::kGLImplementationOSMesaGL:
+ case gfx::kGLImplementationDesktopGL:
+ case gfx::kGLImplementationAppleGL:
+ return new AsyncPixelTransferDelegateIdle;
+ case gfx::kGLImplementationMockGL:
+ return new AsyncPixelTransferDelegateStub;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+} // namespace gpu
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.cc
index 1937842..2affd24 100644
--- a/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.cc
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.cc
@@ -4,7 +4,7 @@
#include "gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h"
-namespace gfx {
+namespace gpu {
MockAsyncPixelTransferState::MockAsyncPixelTransferState() {
}
@@ -18,5 +18,5 @@ MockAsyncPixelTransferDelegate::MockAsyncPixelTransferDelegate() {
MockAsyncPixelTransferDelegate::~MockAsyncPixelTransferDelegate() {
}
-} // namespace gfx
+} // namespace gpu
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h b/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h
index 8b135da..146eaa4 100644
--- a/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GL_ASYNC_TASK_DELEGATE_MOCK_H_
-#define UI_GL_ASYNC_TASK_DELEGATE_MOCK_H_
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_MOCK
+#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_MOCK
#include "base/basictypes.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
#include "testing/gmock/include/gmock/gmock.h"
-#include "ui/gl/async_pixel_transfer_delegate.h"
-namespace gfx {
+namespace gpu {
-class MockAsyncPixelTransferState : public gfx::AsyncPixelTransferState {
+class MockAsyncPixelTransferState : public AsyncPixelTransferState {
public:
MockAsyncPixelTransferState();
@@ -24,29 +24,29 @@ class MockAsyncPixelTransferState : public gfx::AsyncPixelTransferState {
DISALLOW_COPY_AND_ASSIGN(MockAsyncPixelTransferState);
};
-class MockAsyncPixelTransferDelegate : public gfx::AsyncPixelTransferDelegate {
+class MockAsyncPixelTransferDelegate : public AsyncPixelTransferDelegate {
public:
MockAsyncPixelTransferDelegate();
virtual ~MockAsyncPixelTransferDelegate();
// Implement AsyncPixelTransferDelegate.
MOCK_METHOD2(CreatePixelTransferState,
- gfx::AsyncPixelTransferState*(
+ AsyncPixelTransferState*(
GLuint service_id, const AsyncTexImage2DParams& define_params));
MOCK_METHOD0(BindCompletedAsyncTransfers, void());
MOCK_METHOD2(AsyncNotifyCompletion,
void(const AsyncMemoryParams& mem_params,
const CompletionCallback& callback));
MOCK_METHOD4(AsyncTexImage2D,
- void(gfx::AsyncPixelTransferState*,
+ void(AsyncPixelTransferState*,
const AsyncTexImage2DParams& tex_params,
const AsyncMemoryParams& mem_params,
const base::Closure& bind_callback));
MOCK_METHOD3(AsyncTexSubImage2D,
- void(gfx::AsyncPixelTransferState*,
+ void(AsyncPixelTransferState*,
const AsyncTexSubImage2DParams& tex_params,
const AsyncMemoryParams& mem_params));
- MOCK_METHOD1(WaitForTransferCompletion, void(gfx::AsyncPixelTransferState*));
+ MOCK_METHOD1(WaitForTransferCompletion, void(AsyncPixelTransferState*));
MOCK_METHOD0(GetTextureUploadCount, uint32());
MOCK_METHOD0(GetTotalTextureUploadTime, base::TimeDelta());
MOCK_METHOD0(ProcessMorePendingTransfers, void());
@@ -56,7 +56,6 @@ class MockAsyncPixelTransferDelegate : public gfx::AsyncPixelTransferDelegate {
DISALLOW_COPY_AND_ASSIGN(MockAsyncPixelTransferDelegate);
};
-} // namespace gfx
-
-#endif // UI_GL_ASYNC_TASK_DELEGATE_MOCK_H_
+} // namespace gpu
+#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_MOCK
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_stub.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate_stub.cc
new file mode 100644
index 0000000..474e245
--- /dev/null
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_stub.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate_stub.h"
+
+namespace gpu {
+
+namespace {
+
+class AsyncPixelTransferStateImpl : public AsyncPixelTransferState {
+ public:
+ AsyncPixelTransferStateImpl() {}
+ virtual ~AsyncPixelTransferStateImpl() {}
+
+ // Implement AsyncPixelTransferState:
+ virtual bool TransferIsInProgress() OVERRIDE {
+ return false;
+ }
+};
+
+} // namespace
+
+AsyncPixelTransferDelegateStub::AsyncPixelTransferDelegateStub() {}
+
+AsyncPixelTransferDelegateStub::~AsyncPixelTransferDelegateStub() {}
+
+AsyncPixelTransferState* AsyncPixelTransferDelegateStub::
+ CreatePixelTransferState(GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) {
+ return new AsyncPixelTransferStateImpl;
+}
+
+void AsyncPixelTransferDelegateStub::BindCompletedAsyncTransfers() {
+}
+
+void AsyncPixelTransferDelegateStub::AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ const CompletionCallback& callback) {
+ callback.Run(mem_params);
+}
+
+void AsyncPixelTransferDelegateStub::AsyncTexImage2D(
+ AsyncPixelTransferState* transfer_state,
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) {
+ bind_callback.Run();
+}
+
+void AsyncPixelTransferDelegateStub::AsyncTexSubImage2D(
+ AsyncPixelTransferState* transfer_state,
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) {
+}
+
+void AsyncPixelTransferDelegateStub::WaitForTransferCompletion(
+ AsyncPixelTransferState* state) {
+}
+
+uint32 AsyncPixelTransferDelegateStub::GetTextureUploadCount() {
+ return 0;
+}
+
+base::TimeDelta AsyncPixelTransferDelegateStub::GetTotalTextureUploadTime() {
+ return base::TimeDelta();
+}
+
+void AsyncPixelTransferDelegateStub::ProcessMorePendingTransfers() {
+}
+
+bool AsyncPixelTransferDelegateStub::NeedsProcessMorePendingTransfers() {
+ return false;
+}
+
+} // namespace gpu
+
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_stub.h b/gpu/command_buffer/service/async_pixel_transfer_delegate_stub.h
new file mode 100644
index 0000000..f2381990
--- /dev/null
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_stub.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_STUB_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_STUB_H_
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+
+namespace gpu {
+
+class AsyncPixelTransferDelegateStub : public AsyncPixelTransferDelegate {
+ public:
+ AsyncPixelTransferDelegateStub();
+ virtual ~AsyncPixelTransferDelegateStub();
+
+ // Implement AsyncPixelTransferDelegate:
+ virtual AsyncPixelTransferState* CreatePixelTransferState(
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) OVERRIDE;
+ virtual void BindCompletedAsyncTransfers() OVERRIDE;
+ virtual void AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ const CompletionCallback& callback) OVERRIDE;
+ virtual void AsyncTexImage2D(
+ AsyncPixelTransferState* state,
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) OVERRIDE;
+ virtual void AsyncTexSubImage2D(
+ AsyncPixelTransferState* transfer_state,
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) OVERRIDE;
+ virtual void WaitForTransferCompletion(
+ AsyncPixelTransferState* state) OVERRIDE;
+ virtual uint32 GetTextureUploadCount() OVERRIDE;
+ virtual base::TimeDelta GetTotalTextureUploadTime() OVERRIDE;
+ virtual void ProcessMorePendingTransfers() OVERRIDE;
+ virtual bool NeedsProcessMorePendingTransfers() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateStub);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_STUB_H_
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_sync.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate_sync.cc
new file mode 100644
index 0000000..ef67f46
--- /dev/null
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_sync.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2012 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/async_pixel_transfer_delegate_sync.h"
+
+#include "base/memory/shared_memory.h"
+
+using base::SharedMemory;
+using base::SharedMemoryHandle;
+
+namespace gpu {
+
+namespace {
+
+// Gets the address of the data from shared memory.
+void* GetAddress(SharedMemory* shared_memory,
+ uint32 shm_size,
+ uint32 shm_data_offset,
+ uint32 shm_data_size) {
+ // Memory bounds have already been validated, so there
+ // are just DCHECKS here.
+ DCHECK(shared_memory);
+ DCHECK(shared_memory->memory());
+ DCHECK_LE(shm_data_offset + shm_data_size, shm_size);
+ return static_cast<int8*>(shared_memory->memory()) + shm_data_offset;
+}
+
+class AsyncPixelTransferStateImpl : public AsyncPixelTransferState {
+ public:
+ AsyncPixelTransferStateImpl() {}
+ virtual ~AsyncPixelTransferStateImpl() {}
+
+ // Implement AsyncPixelTransferState:
+ virtual bool TransferIsInProgress() OVERRIDE {
+ return false;
+ }
+};
+
+} // namespace
+
+AsyncPixelTransferDelegateSync::AsyncPixelTransferDelegateSync()
+ : texture_upload_count_(0) {
+}
+
+AsyncPixelTransferDelegateSync::~AsyncPixelTransferDelegateSync() {}
+
+AsyncPixelTransferState* AsyncPixelTransferDelegateSync::
+ CreatePixelTransferState(GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) {
+ return new AsyncPixelTransferStateImpl;
+}
+
+void AsyncPixelTransferDelegateSync::BindCompletedAsyncTransfers() {
+ // Everything is already bound.
+}
+
+void AsyncPixelTransferDelegateSync::AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ const CompletionCallback& callback) {
+ callback.Run(mem_params);
+}
+
+void AsyncPixelTransferDelegateSync::AsyncTexImage2D(
+ AsyncPixelTransferState* transfer_state,
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) {
+ // Save the define params to return later during deferred
+ // binding of the transfer texture.
+ DCHECK(transfer_state);
+ void* data = GetAddress(mem_params.shared_memory,
+ mem_params.shm_size,
+ mem_params.shm_data_offset,
+ mem_params.shm_data_size);
+ glTexImage2D(
+ tex_params.target,
+ tex_params.level,
+ tex_params.internal_format,
+ tex_params.width,
+ tex_params.height,
+ tex_params.border,
+ tex_params.format,
+ tex_params.type,
+ data);
+ // The texture is already fully bound so just call it now.
+ bind_callback.Run();
+}
+
+void AsyncPixelTransferDelegateSync::AsyncTexSubImage2D(
+ AsyncPixelTransferState* transfer_state,
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) {
+ void* data = GetAddress(mem_params.shared_memory,
+ mem_params.shm_size,
+ mem_params.shm_data_offset,
+ mem_params.shm_data_size);
+ DCHECK(transfer_state);
+ base::TimeTicks begin_time(base::TimeTicks::HighResNow());
+ glTexSubImage2D(
+ tex_params.target,
+ tex_params.level,
+ tex_params.xoffset,
+ tex_params.yoffset,
+ tex_params.width,
+ tex_params.height,
+ tex_params.format,
+ tex_params.type,
+ data);
+ texture_upload_count_++;
+ total_texture_upload_time_ += base::TimeTicks::HighResNow() - begin_time;
+}
+
+void AsyncPixelTransferDelegateSync::WaitForTransferCompletion(
+ AsyncPixelTransferState* state) {
+ // Already done.
+}
+
+uint32 AsyncPixelTransferDelegateSync::GetTextureUploadCount() {
+ return texture_upload_count_;
+}
+
+base::TimeDelta AsyncPixelTransferDelegateSync::GetTotalTextureUploadTime() {
+ return total_texture_upload_time_;
+}
+
+void AsyncPixelTransferDelegateSync::ProcessMorePendingTransfers() {
+}
+
+bool AsyncPixelTransferDelegateSync::NeedsProcessMorePendingTransfers() {
+ return false;
+}
+
+} // namespace gpu
+
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_sync.h b/gpu/command_buffer/service/async_pixel_transfer_delegate_sync.h
new file mode 100644
index 0000000..5927094
--- /dev/null
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_sync.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_SYNC_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_SYNC_H_
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+
+namespace gpu {
+
+// Class which handles async pixel transfers synchronously.
+class AsyncPixelTransferDelegateSync : public AsyncPixelTransferDelegate {
+ public:
+ AsyncPixelTransferDelegateSync();
+ virtual ~AsyncPixelTransferDelegateSync();
+
+ // Implement AsyncPixelTransferDelegate:
+ virtual AsyncPixelTransferState* CreatePixelTransferState(
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) OVERRIDE;
+ virtual void BindCompletedAsyncTransfers() OVERRIDE;
+ virtual void AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ const CompletionCallback& callback) OVERRIDE;
+ virtual void AsyncTexImage2D(
+ AsyncPixelTransferState* state,
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) OVERRIDE;
+ virtual void AsyncTexSubImage2D(
+ AsyncPixelTransferState* transfer_state,
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) OVERRIDE;
+ virtual void WaitForTransferCompletion(
+ AsyncPixelTransferState* state) OVERRIDE;
+ virtual uint32 GetTextureUploadCount() OVERRIDE;
+ virtual base::TimeDelta GetTotalTextureUploadTime() OVERRIDE;
+ virtual void ProcessMorePendingTransfers() OVERRIDE;
+ virtual bool NeedsProcessMorePendingTransfers() OVERRIDE;
+
+ private:
+ int texture_upload_count_;
+ base::TimeDelta total_texture_upload_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateSync);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_SYNC_H_
diff --git a/gpu/command_buffer/service/async_pixel_transfer_delegate_win.cc b/gpu/command_buffer/service/async_pixel_transfer_delegate_win.cc
new file mode 100644
index 0000000..76a3e4b
--- /dev/null
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_win.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+
+#include "base/debug/trace_event.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate_idle.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate_stub.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace gpu {
+
+AsyncPixelTransferDelegate* AsyncPixelTransferDelegate::Create(
+ gfx::GLContext* context) {
+ TRACE_EVENT0("gpu", "AsyncPixelTransferDelegate::Create");
+ switch (gfx::GetGLImplementation()) {
+ case gfx::kGLImplementationOSMesaGL:
+ case gfx::kGLImplementationDesktopGL:
+ case gfx::kGLImplementationEGLGLES2:
+ return new AsyncPixelTransferDelegateIdle;
+ case gfx::kGLImplementationMockGL:
+ return new AsyncPixelTransferDelegateStub;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+} // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 2fefb5f..e3d308f 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -56,7 +56,7 @@
#include "gpu/command_buffer/service/texture_manager.h"
#include "gpu/command_buffer/service/vertex_attrib_manager.h"
#include "gpu/command_buffer/service/vertex_array_manager.h"
-#include "ui/gl/async_pixel_transfer_delegate.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_image.h"
#include "ui/gl/gl_implementation.h"
@@ -648,10 +648,10 @@ class GLES2DecoderImpl : public GLES2Decoder {
virtual void SetStreamTextureManager(StreamTextureManager* manager) OVERRIDE;
- virtual gfx::AsyncPixelTransferDelegate*
+ virtual AsyncPixelTransferDelegate*
GetAsyncPixelTransferDelegate() OVERRIDE;
virtual void SetAsyncPixelTransferDelegate(
- gfx::AsyncPixelTransferDelegate* delegate) OVERRIDE;
+ AsyncPixelTransferDelegate* delegate) OVERRIDE;
void ProcessFinishedAsyncTransfers();
virtual bool GetServiceTextureId(uint32 client_texture_id,
@@ -1705,7 +1705,7 @@ class GLES2DecoderImpl : public GLES2Decoder {
ShaderCacheCallback shader_cache_callback_;
StreamTextureManager* stream_texture_manager_;
- scoped_ptr<gfx::AsyncPixelTransferDelegate> async_pixel_transfer_delegate_;
+ scoped_ptr<AsyncPixelTransferDelegate> async_pixel_transfer_delegate_;
// The format of the back buffer_
GLenum back_buffer_color_format_;
@@ -2545,7 +2545,7 @@ bool GLES2DecoderImpl::Initialize(
// Create a delegate to perform async pixel transfers.
async_pixel_transfer_delegate_.reset(
- gfx::AsyncPixelTransferDelegate::Create(context.get()));
+ AsyncPixelTransferDelegate::Create(context.get()));
return true;
}
@@ -3113,13 +3113,13 @@ void GLES2DecoderImpl::SetStreamTextureManager(StreamTextureManager* manager) {
stream_texture_manager_ = manager;
}
-gfx::AsyncPixelTransferDelegate*
+AsyncPixelTransferDelegate*
GLES2DecoderImpl::GetAsyncPixelTransferDelegate() {
return async_pixel_transfer_delegate_.get();
}
void GLES2DecoderImpl::SetAsyncPixelTransferDelegate(
- gfx::AsyncPixelTransferDelegate* delegate) {
+ AsyncPixelTransferDelegate* delegate) {
async_pixel_transfer_delegate_ = make_scoped_ptr(delegate);
}
@@ -10272,9 +10272,9 @@ error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM(
// Setup the parameters.
GLenum gl_internal_format =
GetTexInternalFormat(internal_format, format, type);
- gfx::AsyncTexImage2DParams tex_params = {target, level, gl_internal_format,
+ AsyncTexImage2DParams tex_params = {target, level, gl_internal_format,
width, height, border, format, type};
- gfx::AsyncMemoryParams mem_params = {shared_memory, shm_size,
+ AsyncMemoryParams mem_params = {shared_memory, shm_size,
shm_data_offset, shm_data_size};
// Set up the async state if needed, and make the texture
@@ -10362,15 +10362,15 @@ error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM(
uint32 shm_data_size = data_size;
// Setup the parameters.
- gfx::AsyncTexSubImage2DParams tex_params = {target, level, xoffset, yoffset,
+ AsyncTexSubImage2DParams tex_params = {target, level, xoffset, yoffset,
width, height, format, type};
- gfx::AsyncMemoryParams mem_params = {shared_memory, shm_size,
+ AsyncMemoryParams mem_params = {shared_memory, shm_size,
shm_data_offset, shm_data_size};
if (!texture->GetAsyncTransferState()) {
// TODO(epenner): We may want to enforce exclusive use
// of async APIs in which case this should become an error,
// (the texture should have been async defined).
- gfx::AsyncTexImage2DParams define_params = {target, level,
+ AsyncTexImage2DParams define_params = {target, level,
0, 0, 0, 0, 0, 0};
texture->GetLevelSize(target, level, &define_params.width,
&define_params.height);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index 818ace9..e342da3 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -21,11 +21,11 @@
namespace gfx {
class GLContext;
class GLSurface;
-class AsyncPixelTransferDelegate;
}
namespace gpu {
+class AsyncPixelTransferDelegate;
class StreamTextureManager;
namespace gles2 {
@@ -177,9 +177,9 @@ class GPU_EXPORT GLES2Decoder : public base::SupportsWeakPtr<GLES2Decoder>,
virtual void SetStreamTextureManager(StreamTextureManager* manager) = 0;
// Interface to performing async pixel transfers.
- virtual gfx::AsyncPixelTransferDelegate* GetAsyncPixelTransferDelegate() = 0;
+ virtual AsyncPixelTransferDelegate* GetAsyncPixelTransferDelegate() = 0;
virtual void SetAsyncPixelTransferDelegate(
- gfx::AsyncPixelTransferDelegate* delegate) = 0;
+ AsyncPixelTransferDelegate* delegate) = 0;
// Get the service texture ID corresponding to a client texture ID.
// If no such record is found then return false.
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
index 624b6f9..eeecf17 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -70,9 +70,9 @@ class MockGLES2Decoder : public GLES2Decoder {
MOCK_METHOD1(SetResizeCallback, void(const base::Callback<void(gfx::Size)>&));
MOCK_METHOD1(SetStreamTextureManager, void(StreamTextureManager*));
MOCK_METHOD0(GetAsyncPixelTransferDelegate,
- gfx::AsyncPixelTransferDelegate*());
+ AsyncPixelTransferDelegate*());
MOCK_METHOD1(SetAsyncPixelTransferDelegate,
- void(gfx::AsyncPixelTransferDelegate*));
+ void(AsyncPixelTransferDelegate*));
MOCK_METHOD3(DoCommand, error::Error(unsigned int command,
unsigned int arg_count,
const void* cmd_data));
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index b6e1f00..2292b8b 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -8134,10 +8134,10 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
Texture* texture = GetTexture(client_texture_id_);
// Set a mock Async delegate
- StrictMock<gfx::MockAsyncPixelTransferDelegate>* delegate =
- new StrictMock<gfx::MockAsyncPixelTransferDelegate>;
+ StrictMock<gpu::MockAsyncPixelTransferDelegate>* delegate =
+ new StrictMock<gpu::MockAsyncPixelTransferDelegate>;
decoder_->SetAsyncPixelTransferDelegate(delegate);
- StrictMock<gfx::MockAsyncPixelTransferState>* state = NULL;
+ StrictMock<gpu::MockAsyncPixelTransferState>* state = NULL;
// Tex(Sub)Image2D upload commands.
AsyncTexImage2DCHROMIUM teximage_cmd;
@@ -8159,7 +8159,7 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
// Create transfer state since it doesn't exist.
EXPECT_CALL(*delegate, CreatePixelTransferState(kServiceTextureId, _))
.WillOnce(Return(
- state = new StrictMock<gfx::MockAsyncPixelTransferState>))
+ state = new StrictMock<gpu::MockAsyncPixelTransferState>))
.RetiresOnSaturation();
EXPECT_CALL(*delegate, AsyncTexImage2D(state, _, _, _))
.WillOnce(SaveArg<3>(&bind_callback))
@@ -8203,13 +8203,13 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
}
// AsyncTexSubImage2D
- texture->SetAsyncTransferState(scoped_ptr<gfx::AsyncPixelTransferState>());
+ texture->SetAsyncTransferState(scoped_ptr<AsyncPixelTransferState>());
texture->SetImmutable(false);
{
// Create transfer state since it doesn't exist.
EXPECT_CALL(*delegate, CreatePixelTransferState(kServiceTextureId, _))
.WillOnce(Return(
- state = new StrictMock<gfx::MockAsyncPixelTransferState>))
+ state = new StrictMock<gpu::MockAsyncPixelTransferState>))
.RetiresOnSaturation();
EXPECT_CALL(*delegate, AsyncTexSubImage2D(state, _, _))
.RetiresOnSaturation();
@@ -8254,16 +8254,16 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
// asynchronously and AsyncTexSubImage2D does not involved binding.
EXPECT_CALL(*gl_, GenTextures(1, _))
.WillOnce(SetArgumentPointee<1>(kServiceTextureId));
- texture->SetAsyncTransferState(scoped_ptr<gfx::AsyncPixelTransferState>());
+ texture->SetAsyncTransferState(scoped_ptr<AsyncPixelTransferState>());
DoDeleteTexture(client_texture_id_, kServiceTextureId);
DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
texture = GetTexture(client_texture_id_);
- texture->SetAsyncTransferState(scoped_ptr<gfx::AsyncPixelTransferState>());
+ texture->SetAsyncTransferState(scoped_ptr<AsyncPixelTransferState>());
texture->SetImmutable(false);
// Create transfer state since it doesn't exist.
EXPECT_CALL(*delegate, CreatePixelTransferState(kServiceTextureId, _))
.WillOnce(Return(
- state = new StrictMock<gfx::MockAsyncPixelTransferState>))
+ state = new StrictMock<gpu::MockAsyncPixelTransferState>))
.RetiresOnSaturation();
EXPECT_CALL(*delegate, AsyncTexImage2D(state, _, _, _))
.RetiresOnSaturation();
@@ -8280,7 +8280,7 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
}
decoder_->SetAsyncPixelTransferDelegate(NULL);
- texture->SetAsyncTransferState(scoped_ptr<gfx::AsyncPixelTransferState>());
+ texture->SetAsyncTransferState(scoped_ptr<AsyncPixelTransferState>());
}
namespace {
diff --git a/gpu/command_buffer/service/query_manager.cc b/gpu/command_buffer/service/query_manager.cc
index 7b41232..a6efd47 100644
--- a/gpu/command_buffer/service/query_manager.cc
+++ b/gpu/command_buffer/service/query_manager.cc
@@ -10,10 +10,10 @@
#include "base/shared_memory.h"
#include "base/time.h"
#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
#include "gpu/command_buffer/service/error_state.h"
#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
-#include "ui/gl/async_pixel_transfer_delegate.h"
namespace gpu {
namespace gles2 {
@@ -183,7 +183,7 @@ class AsyncPixelTransfersCompletedQuery
virtual ~AsyncPixelTransfersCompletedQuery();
static void MarkAsCompletedThreadSafe(
- uint32 submit_count, const gfx::AsyncMemoryParams& mem_params) {
+ uint32 submit_count, const AsyncMemoryParams& mem_params) {
DCHECK(mem_params.shared_memory);
DCHECK(mem_params.shared_memory->memory());
void *data = static_cast<int8*>(mem_params.shared_memory->memory()) +
@@ -207,7 +207,7 @@ bool AsyncPixelTransfersCompletedQuery::Begin() {
}
bool AsyncPixelTransfersCompletedQuery::End(uint32 submit_count) {
- gfx::AsyncMemoryParams mem_params;
+ AsyncMemoryParams mem_params;
// Get the real shared memory since it might need to be duped to prevent
// use-after-free of the memory.
Buffer buffer = manager()->decoder()->GetSharedMemoryBuffer(shm_id());
diff --git a/gpu/command_buffer/service/safe_shared_memory_pool.cc b/gpu/command_buffer/service/safe_shared_memory_pool.cc
new file mode 100644
index 0000000..05fce77
--- /dev/null
+++ b/gpu/command_buffer/service/safe_shared_memory_pool.cc
@@ -0,0 +1,150 @@
+// Copyright (c) 2012 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/safe_shared_memory_pool.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/process_util.h"
+#include "build/build_config.h"
+
+using base::SharedMemory;
+using base::SharedMemoryHandle;
+
+namespace gpu {
+
+ScopedSafeSharedMemory::ScopedSafeSharedMemory(SafeSharedMemoryPool* pool,
+ base::SharedMemory* memory,
+ size_t shm_size) {
+ DCHECK(pool);
+ DCHECK(memory);
+ DCHECK(memory->memory());
+ pool_ = pool;
+ original_handle_ = memory->handle();
+ safe_shared_memory_ = pool->AcquireSafeSharedMemory(memory, shm_size);
+ CHECK(safe_shared_memory_);
+}
+
+ScopedSafeSharedMemory::~ScopedSafeSharedMemory() {
+ // Release the handle. The pool will delete the SharedMemory
+ // object when it is no longer referenced.
+ pool_->ReleaseSafeSharedMemory(original_handle_);
+}
+
+base::SharedMemory* ScopedSafeSharedMemory::shared_memory() {
+ return safe_shared_memory_;
+}
+
+
+SafeSharedMemoryPool::SafeSharedMemoryPool()
+ : handles_acquired_(0),
+ handles_consumed_(0),
+ address_space_consumed_(0),
+ max_handles_acquired_(0),
+ max_handles_consumed_(0),
+ max_address_space_consumed_(0) {
+}
+
+SafeSharedMemoryPool::~SafeSharedMemoryPool() {
+}
+
+base::SharedMemory* SafeSharedMemoryPool::
+ AcquireSafeSharedMemory(base::SharedMemory* shared_memory,
+ size_t shm_size) {
+ DCHECK(shared_memory);
+ DCHECK(shared_memory->memory());
+ base::AutoLock scoped_lock(lock_);
+
+ // Adjust stats.
+ handles_acquired_++;
+ max_handles_acquired_ = std::max(max_handles_acquired_,
+ handles_acquired_);
+
+ MemoryMap::iterator it = memory_.find(shared_memory->handle());
+ // If we don't already have it, duplicated it.
+ if (it == memory_.end()) {
+ // Duplicate a new shared memory and track it.
+ TrackedMemory tracker;
+ tracker.safe_shared_memory = DuplicateSharedMemory(shared_memory, shm_size);
+ tracker.reference_count = 1;
+ tracker.shm_size = shm_size;
+ memory_[shared_memory->handle()] = tracker;
+
+ // Adjust stats.
+ handles_consumed_++;
+ address_space_consumed_ += shm_size;
+ max_handles_consumed_ = std::max(max_handles_consumed_,
+ handles_consumed_);
+ max_address_space_consumed_ = std::max(max_address_space_consumed_,
+ address_space_consumed_);
+ return tracker.safe_shared_memory;
+ }
+
+ // Otherwise, add a reference and return the existing one.
+ DCHECK(it->second.reference_count);
+ DCHECK(it->second.safe_shared_memory);
+ DCHECK(it->second.safe_shared_memory->memory());
+ it->second.reference_count++;
+ return it->second.safe_shared_memory;
+}
+
+void SafeSharedMemoryPool::
+ ReleaseSafeSharedMemory(const base::SharedMemoryHandle& handle) {
+ base::AutoLock scoped_lock(lock_);
+
+ // Adjust stats.
+ handles_acquired_--;
+ DCHECK(handles_acquired_ >= 0);
+
+ MemoryMap::iterator it = memory_.find(handle);
+ CHECK(it != memory_.end());
+ CHECK(it->second.reference_count);
+ CHECK(it->second.safe_shared_memory);
+ if (--it->second.reference_count == 0) {
+ // Adjust stats.
+ handles_consumed_--;
+ address_space_consumed_ -= it->second.shm_size;
+ DCHECK(handles_consumed_ >= 0);
+ DCHECK(address_space_consumed_ >= 0);
+ // Delete the safe memory and remove it.
+ delete it->second.safe_shared_memory;
+ memory_.erase(it);
+ }
+}
+
+SharedMemory* SafeSharedMemoryPool::DuplicateSharedMemory(
+ SharedMemory* shared_memory, size_t size) {
+ // Duplicate the handle.
+ SharedMemoryHandle duped_shared_memory_handle;
+ if (!shared_memory->ShareToProcess(
+ base::GetCurrentProcessHandle(),
+ &duped_shared_memory_handle)) {
+ LOG(ERROR) << "Failed SharedMemory::ShareToProcess";
+ LOG(ERROR) << "Total handles acquired " << handles_acquired_;
+ LOG(ERROR) << "Total handles open " << handles_consumed_;
+ LOG(ERROR) << "Total address space " << address_space_consumed_;
+ LOG(ERROR) << "Max handles acquired " << max_handles_acquired_;
+ LOG(ERROR) << "Max handles open " << max_handles_consumed_;
+ LOG(ERROR) << "Max address space " << max_address_space_consumed_;
+ CHECK(false); // Diagnosing a crash.
+ return NULL;
+ }
+ scoped_ptr<SharedMemory> duped_shared_memory(
+ new SharedMemory(duped_shared_memory_handle, false));
+ // Map the shared memory into this process. This validates the size.
+ if (!duped_shared_memory->Map(size)) {
+ LOG(ERROR) << "Failed SharedMemory::Map";
+ LOG(ERROR) << "Total handles acquired " << handles_acquired_;
+ LOG(ERROR) << "Total handles open " << handles_consumed_;
+ LOG(ERROR) << "Total address space " << address_space_consumed_;
+ LOG(ERROR) << "Max handles acquired " << max_handles_acquired_;
+ LOG(ERROR) << "Max handles open " << max_handles_consumed_;
+ LOG(ERROR) << "Max address space " << max_address_space_consumed_;
+ CHECK(false); // Diagnosing a crash.
+ return NULL;
+ }
+ return duped_shared_memory.release();
+}
+
+} // namespace gfx
diff --git a/gpu/command_buffer/service/safe_shared_memory_pool.h b/gpu/command_buffer/service/safe_shared_memory_pool.h
new file mode 100644
index 0000000..24da1a5
--- /dev/null
+++ b/gpu/command_buffer/service/safe_shared_memory_pool.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2011 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.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_SAFE_SHARED_MEMORY_POOL_H_
+#define GPU_COMMAND_BUFFER_SERVICE_SAFE_SHARED_MEMORY_POOL_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/memory/shared_memory.h"
+#include "base/synchronization/lock.h"
+#include "build/build_config.h"
+
+namespace base {
+class SharedMemory;
+}
+
+namespace gpu {
+class SafeSharedMemoryPool;
+
+// These classes exist to help protect against deletion of shared
+// memory that is being used on a worker thread. It's mainly a
+// security measure to prevent use-after-free in the browser, due
+// to a misbehaving client. That said, this should be removed
+// in favor of higher-level reference counting of an appropriate
+// opaque 'memory blob' data-structure.
+
+class ScopedSafeSharedMemory {
+ public:
+ base::SharedMemory* shared_memory();
+ ScopedSafeSharedMemory(SafeSharedMemoryPool* pool,
+ base::SharedMemory* memory,
+ size_t shm_size);
+ ~ScopedSafeSharedMemory();
+ private:
+ base::SharedMemory* safe_shared_memory_;
+ base::SharedMemoryHandle original_handle_;
+ SafeSharedMemoryPool* pool_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedSafeSharedMemory);
+};
+
+class SafeSharedMemoryPool {
+ public:
+ SafeSharedMemoryPool();
+ virtual ~SafeSharedMemoryPool();
+
+ private:
+ friend class ScopedSafeSharedMemory;
+
+ // Acquires and release shared memory. The acquired shared memory
+ // is guaranteed to live until it is released.
+ base::SharedMemory* AcquireSafeSharedMemory(base::SharedMemory*, size_t size);
+ void ReleaseSafeSharedMemory(const base::SharedMemoryHandle&);
+
+ // Utility function to duplicate shared memory.
+ base::SharedMemory* DuplicateSharedMemory(base::SharedMemory*, size_t size);
+
+ // Track all SharedMemory's that we have already duplicated.
+ struct TrackedMemory {
+ base::SharedMemory* safe_shared_memory;
+ size_t shm_size;
+ int reference_count;
+ };
+
+ typedef std::map<base::SharedMemoryHandle, TrackedMemory> MemoryMap;
+ MemoryMap memory_;
+
+ // Track usage to diagnose crashes.
+ int handles_acquired_;
+ int handles_consumed_;
+ size_t address_space_consumed_;
+ int max_handles_acquired_;
+ int max_handles_consumed_;
+ size_t max_address_space_consumed_;
+
+ base::Lock lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(SafeSharedMemoryPool);
+};
+
+} // namespace gfx
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_SAFE_SHARED_MEMORY_POOL_H_
+
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h
index 51c9ba4..7293f27 100644
--- a/gpu/command_buffer/service/texture_manager.h
+++ b/gpu/command_buffer/service/texture_manager.h
@@ -12,10 +12,10 @@
#include "base/hash_tables.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
#include "gpu/command_buffer/service/gl_utils.h"
#include "gpu/command_buffer/service/memory_tracking.h"
#include "gpu/gpu_export.h"
-#include "ui/gl/async_pixel_transfer_delegate.h"
#include "ui/gl/gl_image.h"
namespace gpu {
@@ -147,10 +147,10 @@ class GPU_EXPORT Texture : public base::RefCounted<Texture> {
return stream_texture_;
}
- gfx::AsyncPixelTransferState* GetAsyncTransferState() const {
+ gpu::AsyncPixelTransferState* GetAsyncTransferState() const {
return async_transfer_state_.get();
}
- void SetAsyncTransferState(scoped_ptr<gfx::AsyncPixelTransferState> state) {
+ void SetAsyncTransferState(scoped_ptr<gpu::AsyncPixelTransferState> state) {
async_transfer_state_ = state.Pass();
}
bool AsyncTransferIsInProgress() {
@@ -346,7 +346,7 @@ class GPU_EXPORT Texture : public base::RefCounted<Texture> {
bool stream_texture_;
// State to facilitate async transfers on this texture.
- scoped_ptr<gfx::AsyncPixelTransferState> async_transfer_state_;
+ scoped_ptr<gpu::AsyncPixelTransferState> async_transfer_state_;
// Whether the texture is immutable and no further changes to the format
// or dimensions of the texture object can be made.
@@ -452,7 +452,7 @@ class GPU_EXPORT TextureManager {
// Adapter to call above function.
void SetLevelInfoFromParams(Texture* texture,
- const gfx::AsyncTexImage2DParams& params) {
+ const gpu::AsyncTexImage2DParams& params) {
SetLevelInfo(
texture, params.target, params.level, params.internal_format,
params.width, params.height, 1 /* depth */,