diff options
author | backer@chromium.org <backer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-09 23:12:03 +0000 |
---|---|---|
committer | backer@chromium.org <backer@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-09 23:12:03 +0000 |
commit | 2a7568a99f309fbd54bb33d9b3b35c88c63b8283 (patch) | |
tree | c7514b6b87e6a6323f0d983b2201885167b4d0cc /gpu/command_buffer/service | |
parent | 26385174eecea18029fcdf32eb1725924e75a5a8 (diff) | |
download | chromium_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')
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 */, |