summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h2
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc18
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc7
-rw-r--r--ui/gl/async_pixel_transfer_delegate.cc17
-rw-r--r--ui/gl/async_pixel_transfer_delegate.h37
-rw-r--r--ui/gl/async_pixel_transfer_delegate_android.cc913
-rw-r--r--ui/gl/async_pixel_transfer_delegate_android.h11
-rw-r--r--ui/gl/async_pixel_transfer_delegate_egl.cc813
-rw-r--r--ui/gl/async_pixel_transfer_delegate_egl.h90
-rw-r--r--ui/gl/async_pixel_transfer_delegate_idle.cc61
-rw-r--r--ui/gl/async_pixel_transfer_delegate_idle.h23
-rw-r--r--ui/gl/async_pixel_transfer_delegate_linux.cc30
-rw-r--r--ui/gl/async_pixel_transfer_delegate_mac.cc30
-rw-r--r--ui/gl/async_pixel_transfer_delegate_stub.cc106
-rw-r--r--ui/gl/async_pixel_transfer_delegate_stub.h41
-rw-r--r--ui/gl/async_pixel_transfer_delegate_sync.cc137
-rw-r--r--ui/gl/async_pixel_transfer_delegate_sync.h51
-rw-r--r--ui/gl/async_pixel_transfer_delegate_win.cc30
-rw-r--r--ui/gl/gl.gyp11
19 files changed, 1314 insertions, 1114 deletions
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 e75cf1b..202c398 100644
--- a/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h
+++ b/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h
@@ -30,7 +30,7 @@ class MockAsyncPixelTransferDelegate : public gfx::AsyncPixelTransferDelegate {
virtual ~MockAsyncPixelTransferDelegate();
// Implement AsyncPixelTransferDelegate.
- MOCK_METHOD2(CreateRawPixelTransferState,
+ MOCK_METHOD2(CreatePixelTransferState,
gfx::AsyncPixelTransferState*(
GLuint service_id, const AsyncTexImage2DParams& define_params));
MOCK_METHOD0(BindCompletedAsyncTransfers, bool());
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index b50437a..10fec42 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -2546,8 +2546,8 @@ bool GLES2DecoderImpl::Initialize(
context_->SetSafeToForceGpuSwitch();
// Create a delegate to perform async pixel transfers.
- async_pixel_transfer_delegate_ =
- gfx::AsyncPixelTransferDelegate::Create(context.get());
+ async_pixel_transfer_delegate_.reset(
+ gfx::AsyncPixelTransferDelegate::Create(context.get()));
return true;
}
@@ -10278,9 +10278,10 @@ error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM(
// is set up lazily when the transfer completes.
DCHECK(!texture->GetAsyncTransferState());
texture->SetAsyncTransferState(
- async_pixel_transfer_delegate_->
- CreatePixelTransferState(texture->service_id(),
- tex_params));
+ make_scoped_ptr(
+ async_pixel_transfer_delegate_->CreatePixelTransferState(
+ texture->service_id(),
+ tex_params)));
texture->SetImmutable(true);
async_pixel_transfer_delegate_->AsyncTexImage2D(
@@ -10374,9 +10375,10 @@ error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM(
// Set up the async state if needed, and make the texture
// immutable so the async state stays valid.
texture->SetAsyncTransferState(
- async_pixel_transfer_delegate_->
- CreatePixelTransferState(texture->service_id(),
- define_params));
+ make_scoped_ptr(
+ async_pixel_transfer_delegate_->CreatePixelTransferState(
+ texture->service_id(),
+ define_params)));
texture->SetImmutable(true);
}
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index 2c0b782..2b11977 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -8134,7 +8134,6 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
Texture* texture = GetTexture(client_texture_id_);
// Set a mock Async delegate
- // Async state is returned as a scoped_ptr, but we keep a raw copy.
StrictMock<gfx::MockAsyncPixelTransferDelegate>* delegate =
new StrictMock<gfx::MockAsyncPixelTransferDelegate>;
decoder_->SetAsyncPixelTransferDelegate(delegate);
@@ -8158,7 +8157,7 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
// AsyncTexImage2D
{
// Create transfer state since it doesn't exist.
- EXPECT_CALL(*delegate, CreateRawPixelTransferState(kServiceTextureId, _))
+ EXPECT_CALL(*delegate, CreatePixelTransferState(kServiceTextureId, _))
.WillOnce(Return(
state = new StrictMock<gfx::MockAsyncPixelTransferState>))
.RetiresOnSaturation();
@@ -8208,7 +8207,7 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
texture->SetImmutable(false);
{
// Create transfer state since it doesn't exist.
- EXPECT_CALL(*delegate, CreateRawPixelTransferState(kServiceTextureId, _))
+ EXPECT_CALL(*delegate, CreatePixelTransferState(kServiceTextureId, _))
.WillOnce(Return(
state = new StrictMock<gfx::MockAsyncPixelTransferState>))
.RetiresOnSaturation();
@@ -8262,7 +8261,7 @@ TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
texture->SetAsyncTransferState(scoped_ptr<gfx::AsyncPixelTransferState>());
texture->SetImmutable(false);
// Create transfer state since it doesn't exist.
- EXPECT_CALL(*delegate, CreateRawPixelTransferState(kServiceTextureId, _))
+ EXPECT_CALL(*delegate, CreatePixelTransferState(kServiceTextureId, _))
.WillOnce(Return(
state = new StrictMock<gfx::MockAsyncPixelTransferState>))
.RetiresOnSaturation();
diff --git a/ui/gl/async_pixel_transfer_delegate.cc b/ui/gl/async_pixel_transfer_delegate.cc
new file mode 100644
index 0000000..9d4c4a2
--- /dev/null
+++ b/ui/gl/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 "ui/gl/async_pixel_transfer_delegate.h"
+
+namespace gfx {
+
+AsyncPixelTransferState::AsyncPixelTransferState() {}
+
+AsyncPixelTransferState::~AsyncPixelTransferState() {}
+
+AsyncPixelTransferDelegate::AsyncPixelTransferDelegate() {}
+
+AsyncPixelTransferDelegate::~AsyncPixelTransferDelegate() {}
+
+} // namespace gfx
diff --git a/ui/gl/async_pixel_transfer_delegate.h b/ui/gl/async_pixel_transfer_delegate.h
index 3f9f434..e5a0e2e 100644
--- a/ui/gl/async_pixel_transfer_delegate.h
+++ b/ui/gl/async_pixel_transfer_delegate.h
@@ -1,16 +1,15 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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 UI_GL_ASYNC_TASK_DELEGATE_H_
-#define UI_GL_ASYNC_TASK_DELEGATE_H_
+#ifndef UI_GL_ASYNC_PIXEL_TRANSFER_DELEGATE_H_
+#define UI_GL_ASYNC_PIXEL_TRANSFER_DELEGATE_H_
#include "base/basictypes.h"
-#include "base/bind.h"
+#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time.h"
-#include "build/build_config.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_export.h"
@@ -55,14 +54,14 @@ struct AsyncMemoryParams {
class GL_EXPORT AsyncPixelTransferState :
public base::SupportsWeakPtr<AsyncPixelTransferState> {
public:
- virtual ~AsyncPixelTransferState() {}
+ virtual ~AsyncPixelTransferState();
// Returns true if there is a transfer in progress.
virtual bool TransferIsInProgress() = 0;
protected:
friend class base::RefCounted<AsyncPixelTransferState>;
- AsyncPixelTransferState() {}
+ AsyncPixelTransferState();
private:
DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferState);
@@ -72,17 +71,13 @@ class GL_EXPORT AsyncPixelTransferDelegate {
public:
typedef base::Callback<void(const AsyncMemoryParams&)> CompletionCallback;
- static scoped_ptr<AsyncPixelTransferDelegate>
- Create(gfx::GLContext* context);
- virtual ~AsyncPixelTransferDelegate() {}
+ static AsyncPixelTransferDelegate* Create(gfx::GLContext* context);
- // This wouldn't work with MOCK_METHOD, so it routes through
- // a virtual protected version which returns a raw pointer.
- scoped_ptr<AsyncPixelTransferState>
- CreatePixelTransferState(GLuint tex_id,
- const AsyncTexImage2DParams& define_params) {
- return make_scoped_ptr(CreateRawPixelTransferState(tex_id, define_params));
- }
+ virtual ~AsyncPixelTransferDelegate();
+
+ virtual AsyncPixelTransferState* CreatePixelTransferState(
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) = 0;
// Returns true iff a texture was bound to texture-unit zero.
virtual bool BindCompletedAsyncTransfers() = 0;
@@ -123,11 +118,7 @@ class GL_EXPORT AsyncPixelTransferDelegate {
virtual bool NeedsProcessMorePendingTransfers() = 0;
protected:
- AsyncPixelTransferDelegate() {}
- // For testing, as returning scoped_ptr wouldn't work with MOCK_METHOD.
- virtual AsyncPixelTransferState*
- CreateRawPixelTransferState(GLuint tex_id,
- const AsyncTexImage2DParams& define_params) = 0;
+ AsyncPixelTransferDelegate();
private:
DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegate);
@@ -135,5 +126,5 @@ class GL_EXPORT AsyncPixelTransferDelegate {
} // namespace gfx
-#endif // UI_GL_ASYNC_TASK_DELEGATE_H_
+#endif // UI_GL_ASYNC_PIXEL_TRANSFER_DELEGATE_H_
diff --git a/ui/gl/async_pixel_transfer_delegate_android.cc b/ui/gl/async_pixel_transfer_delegate_android.cc
index 2414472..f29fdf6 100644
--- a/ui/gl/async_pixel_transfer_delegate_android.cc
+++ b/ui/gl/async_pixel_transfer_delegate_android.cc
@@ -1,906 +1,43 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 "ui/gl/async_pixel_transfer_delegate_android.h"
-
-#include <list>
-#include <string>
+#include "ui/gl/async_pixel_transfer_delegate.h"
-#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/process_util.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread.h"
-#include "build/build_config.h"
-#include "ui/gl/async_pixel_transfer_delegate.h"
+#include "ui/gl/async_pixel_transfer_delegate_egl.h"
#include "ui/gl/async_pixel_transfer_delegate_stub.h"
-#include "ui/gl/egl_util.h"
-#include "ui/gl/gl_bindings.h"
+#include "ui/gl/async_pixel_transfer_delegate_sync.h"
#include "ui/gl/gl_context.h"
-#include "ui/gl/gl_surface_egl.h"
-#include "ui/gl/safe_shared_memory_pool.h"
-
-// TODO(epenner): Move thread priorities to base. (crbug.com/170549)
-#include <sys/resource.h>
-
-using base::SharedMemory;
-using base::SharedMemoryHandle;
+#include "ui/gl/gl_implementation.h"
namespace gfx {
-namespace {
-
-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 RefCountedThreadSafe<TextureUploadStats>;
-
- ~TextureUploadStats() {}
-
- int texture_upload_count_;
- base::TimeDelta total_texture_upload_time_;
- base::Lock lock_;
-
- DISALLOW_COPY_AND_ASSIGN(TextureUploadStats);
-};
-
-const char kAsyncTransferThreadName[] = "AsyncTransferThread";
-
-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__)
-
-// 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 {
- 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);
-
- // TODO(epenner): Move thread priorities to base. (crbug.com/170549)
- int nice_value = 10; // Idle priority.
- setpriority(PRIO_PROCESS, base::PlatformThread::CurrentId(), nice_value);
- }
-
- 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:
- explicit 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;
- }
-
- // Implement AsyncPixelTransferState:
- 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_);
-
- // We can only change the active texture and unit 0,
- // as that is all that will be restored.
- glBindTexture(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 AsyncPixelTransferDelegateAndroid;
-
- 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_;
-};
-
-// Android needs thread-safe ref-counting, so this just wraps
-// an internal thread-safe ref-counted state object.
-class AsyncTransferStateAndroid : public AsyncPixelTransferState {
- public:
- explicit AsyncTransferStateAndroid(
- 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 ~AsyncTransferStateAndroid() {}
- virtual bool TransferIsInProgress() OVERRIDE {
- return internal_->TransferIsInProgress();
- }
- void BindTransfer() {
- internal_->BindTransfer();
- }
- scoped_refptr<TransferStateInternal> internal_;
-};
-
-// Class which handles async pixel transfers on Android (using
-// EGLImageKHR and another upload thread)
-class AsyncPixelTransferDelegateAndroid
- : public AsyncPixelTransferDelegate,
- public base::SupportsWeakPtr<AsyncPixelTransferDelegateAndroid> {
- public:
- AsyncPixelTransferDelegateAndroid();
- virtual ~AsyncPixelTransferDelegateAndroid();
-
- // implement AsyncPixelTransferDelegate:
- virtual bool 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 bool ProcessMorePendingTransfers() OVERRIDE;
- virtual bool NeedsProcessMorePendingTransfers() OVERRIDE;
-
- private:
- // implement AsyncPixelTransferDelegate:
- virtual AsyncPixelTransferState*
- CreateRawPixelTransferState(GLuint texture_id,
- const AsyncTexImage2DParams& define_params) OVERRIDE;
-
- 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(AsyncPixelTransferDelegateAndroid);
-};
-
// 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).
-scoped_ptr<AsyncPixelTransferDelegate>
- AsyncPixelTransferDelegate::Create(gfx::GLContext* context) {
- 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 make_scoped_ptr(
- static_cast<AsyncPixelTransferDelegate*>(
- new AsyncPixelTransferDelegateAndroid()));
- } else {
- LOG(INFO) << "Async pixel transfers not supported";
- return make_scoped_ptr(
- static_cast<AsyncPixelTransferDelegate*>(
- new AsyncPixelTransferDelegateStub()));
- }
-}
-
-AsyncPixelTransferDelegateAndroid::AsyncPixelTransferDelegateAndroid() {
- 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);
-}
-
-AsyncPixelTransferDelegateAndroid::~AsyncPixelTransferDelegateAndroid() {
-}
-
-AsyncPixelTransferState*
- AsyncPixelTransferDelegateAndroid::
- CreateRawPixelTransferState(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 AsyncTransferStateAndroid(texture_id,
- define_params,
- wait_for_uploads,
- wait_for_creation,
- use_image_preserved);
-}
-
-bool AsyncPixelTransferDelegateAndroid::BindCompletedAsyncTransfers() {
- bool texture_dirty = false;
- while(!pending_allocations_.empty()) {
- if (!pending_allocations_.front().get()) {
- pending_allocations_.pop_front();
- continue;
- }
- scoped_refptr<TransferStateInternal> state =
- static_cast<AsyncTransferStateAndroid*>
- (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.
- texture_dirty = true;
- state->BindTransfer();
- pending_allocations_.pop_front();
- }
- return texture_dirty;
-}
-
-void AsyncPixelTransferDelegateAndroid::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(&AsyncPixelTransferDelegateAndroid::PerformNotifyCompletion,
- mem_params,
- base::Owned(
- new ScopedSafeSharedMemory(safe_shared_memory_pool(),
- mem_params.shared_memory,
- mem_params.shm_size)),
- callback));
-}
-
-void AsyncPixelTransferDelegateAndroid::WaitForTransferCompletion(
- AsyncPixelTransferState* transfer_state) {
- TRACE_EVENT0("gpu", "WaitForTransferCompletion");
- scoped_refptr<TransferStateInternal> state =
- static_cast<AsyncTransferStateAndroid*>(transfer_state)->internal_.get();
- DCHECK(state);
- DCHECK(state->texture_id_);
-
- if (state->TransferIsInProgress()) {
- // 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);
-
- state->WaitForTransferCompletion();
- DCHECK(!state->TransferIsInProgress());
-
- // TODO(epenner): Move thread priorities to base. (crbug.com/170549)
- setpriority(PRIO_PROCESS,
- g_transfer_thread.Pointer()->thread_id(),
- idle_nice_value);
- }
-}
-
-void AsyncPixelTransferDelegateAndroid::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<AsyncTransferStateAndroid*>(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(
- &AsyncPixelTransferDelegateAndroid::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 AsyncPixelTransferDelegateAndroid::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<AsyncTransferStateAndroid*>(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(
- &AsyncPixelTransferDelegateAndroid::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 AsyncPixelTransferDelegateAndroid::GetTextureUploadCount() {
- CHECK(texture_upload_stats_);
- return texture_upload_stats_->GetStats(NULL);
-}
-
-base::TimeDelta AsyncPixelTransferDelegateAndroid::GetTotalTextureUploadTime() {
- CHECK(texture_upload_stats_);
- base::TimeDelta total_texture_upload_time;
- texture_upload_stats_->GetStats(&total_texture_upload_time);
- return total_texture_upload_time;
-}
-
-bool AsyncPixelTransferDelegateAndroid::ProcessMorePendingTransfers() {
- return false;
-}
-
-bool AsyncPixelTransferDelegateAndroid::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 AsyncPixelTransferDelegateAndroid::PerformNotifyCompletion(
- AsyncMemoryParams mem_params,
- ScopedSafeSharedMemory* safe_shared_memory,
- const CompletionCallback& callback) {
- TRACE_EVENT0("gpu", "PerformNotifyCompletion");
- gfx::AsyncMemoryParams safe_mem_params = mem_params;
- safe_mem_params.shared_memory = safe_shared_memory->shared_memory();
- callback.Run(safe_mem_params);
-}
-
-void AsyncPixelTransferDelegateAndroid::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 AsyncPixelTransferDelegateAndroid::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 AsyncPixelTransferDelegateAndroid::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<AsyncTransferStateAndroid*>(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 AsyncPixelTransferDelegateAndroid::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<AsyncTransferStateAndroid*>(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);
+AsyncPixelTransferDelegate* AsyncPixelTransferDelegate::Create(
+ gfx::GLContext* context) {
+ TRACE_EVENT0("gpu", "AsyncPixelTransferDelegate::Create");
+ switch (GetGLImplementation()) {
+ case 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 kGLImplementationMockGL:
+ return new AsyncPixelTransferDelegateStub;
+ default:
+ NOTREACHED();
+ return NULL;
}
-
- DCHECK(CHECK_GL());
- return true;
}
} // namespace gfx
diff --git a/ui/gl/async_pixel_transfer_delegate_android.h b/ui/gl/async_pixel_transfer_delegate_android.h
deleted file mode 100644
index 4534b40..0000000
--- a/ui/gl/async_pixel_transfer_delegate_android.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// 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.
-
-#ifndef UI_GL_ASYNC_TASK_DELEGATE_ANDROID_H_
-#define UI_GL_ASYNC_TASK_DELEGATE_ANDROID_H_
-
-namespace gfx {
-} // namespace gfx
-
-#endif // UI_GL_ASYNC_TASK_DELEGATE_ANDROID_H_
diff --git a/ui/gl/async_pixel_transfer_delegate_egl.cc b/ui/gl/async_pixel_transfer_delegate_egl.cc
new file mode 100644
index 0000000..d2878a2
--- /dev/null
+++ b/ui/gl/async_pixel_transfer_delegate_egl.cc
@@ -0,0 +1,813 @@
+// 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 "ui/gl/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 "ui/gl/gl_context.h"
+#include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/safe_shared_memory_pool.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 gfx {
+
+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 {
+ 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_);
+
+ // We can only change the active texture and unit 0,
+ // as that is all that will be restored.
+ glBindTexture(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);
+}
+
+bool AsyncPixelTransferDelegateEGL::BindCompletedAsyncTransfers() {
+ bool texture_dirty = false;
+ 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.
+ texture_dirty = true;
+ state->BindTransfer();
+ pending_allocations_.pop_front();
+ }
+ return texture_dirty;
+}
+
+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;
+}
+
+bool AsyncPixelTransferDelegateEGL::ProcessMorePendingTransfers() {
+ return false;
+}
+
+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");
+ gfx::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 gfx
diff --git a/ui/gl/async_pixel_transfer_delegate_egl.h b/ui/gl/async_pixel_transfer_delegate_egl.h
new file mode 100644
index 0000000..f9b3d10
--- /dev/null
+++ b/ui/gl/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 UI_GL_ASYNC_PIXEL_TRANSFER_DELEGATE_EGL_H_
+#define UI_GL_ASYNC_PIXEL_TRANSFER_DELEGATE_EGL_H_
+
+#include <list>
+
+#include "ui/gl/async_pixel_transfer_delegate.h"
+
+namespace gfx {
+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 bool 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 bool 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 gfx
+
+#endif // UI_GL_ASYNC_PIXEL_TRANSFER_DELEGATE_EGL_H_
diff --git a/ui/gl/async_pixel_transfer_delegate_idle.cc b/ui/gl/async_pixel_transfer_delegate_idle.cc
index a47da8f..9b95ac6 100644
--- a/ui/gl/async_pixel_transfer_delegate_idle.cc
+++ b/ui/gl/async_pixel_transfer_delegate_idle.cc
@@ -8,14 +8,7 @@
#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/memory/shared_memory.h"
-#include "base/message_loop.h"
-#include "base/process_util.h"
-#include "build/build_config.h"
-#include "ui/gl/gl_bindings.h"
-#include "ui/gl/gl_context.h"
-#include "ui/gl/gl_surface.h"
#include "ui/gl/safe_shared_memory_pool.h"
-#include "ui/gl/scoped_make_current.h"
using base::SharedMemory;
using base::SharedMemoryHandle;
@@ -42,34 +35,18 @@ SafeSharedMemoryPool* safe_shared_memory_pool() {
static uint64 g_next_pixel_transfer_state_id = 1;
-} // namespace
-
-#if !defined(OS_ANDROID)
-scoped_ptr<AsyncPixelTransferDelegate>
- AsyncPixelTransferDelegate::Create(gfx::GLContext* context) {
- return AsyncPixelTransferDelegateIdle::Create(context);
-}
-#endif
-
-scoped_ptr<AsyncPixelTransferDelegate>
- AsyncPixelTransferDelegateIdle::Create(gfx::GLContext* context) {
- return make_scoped_ptr(
- static_cast<AsyncPixelTransferDelegate*>(
- new AsyncPixelTransferDelegateIdle()));
-}
-
-class AsyncPixelTransferStateIdle : public AsyncPixelTransferState {
+class AsyncPixelTransferStateImpl : public AsyncPixelTransferState {
public:
typedef base::Callback<void(GLuint)> TransferCallback;
- explicit AsyncPixelTransferStateIdle(GLuint texture_id)
+ explicit AsyncPixelTransferStateImpl(GLuint texture_id)
: id_(g_next_pixel_transfer_state_id++),
texture_id_(texture_id),
transfer_in_progress_(false) {
}
- virtual ~AsyncPixelTransferStateIdle() {}
+ virtual ~AsyncPixelTransferStateImpl() {}
- // Overridden from gfx::AsyncPixelTransferState:
+ // Implement AsyncPixelTransferState:
virtual bool TransferIsInProgress() OVERRIDE {
return transfer_in_progress_;
}
@@ -93,6 +70,8 @@ class AsyncPixelTransferStateIdle : public AsyncPixelTransferState {
bool transfer_in_progress_;
};
+} // namespace
+
AsyncPixelTransferDelegateIdle::Task::Task(
uint64 transfer_id, const base::Closure& task)
: transfer_id(transfer_id),
@@ -105,14 +84,12 @@ AsyncPixelTransferDelegateIdle::AsyncPixelTransferDelegateIdle()
: texture_upload_count_(0) {
}
-AsyncPixelTransferDelegateIdle::~AsyncPixelTransferDelegateIdle() {
-}
+AsyncPixelTransferDelegateIdle::~AsyncPixelTransferDelegateIdle() {}
-AsyncPixelTransferState*
- AsyncPixelTransferDelegateIdle::CreateRawPixelTransferState(
- GLuint texture_id,
- const AsyncTexImage2DParams& define_params) {
- return new AsyncPixelTransferStateIdle(texture_id);
+AsyncPixelTransferState* AsyncPixelTransferDelegateIdle::
+ CreatePixelTransferState(GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) {
+ return new AsyncPixelTransferStateImpl(texture_id);
}
bool AsyncPixelTransferDelegateIdle::BindCompletedAsyncTransfers() {
@@ -146,8 +123,8 @@ void AsyncPixelTransferDelegateIdle::AsyncTexImage2D(
const AsyncTexImage2DParams& tex_params,
const AsyncMemoryParams& mem_params,
const base::Closure& bind_callback) {
- AsyncPixelTransferStateIdle* state =
- static_cast<AsyncPixelTransferStateIdle*>(transfer_state);
+ 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,
@@ -157,7 +134,7 @@ void AsyncPixelTransferDelegateIdle::AsyncTexImage2D(
tasks_.push_back(
Task(state->id(),
base::Bind(
- &AsyncPixelTransferStateIdle::PerformTransfer,
+ &AsyncPixelTransferStateImpl::PerformTransfer,
base::AsWeakPtr(state),
base::Bind(
&AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D,
@@ -177,8 +154,8 @@ void AsyncPixelTransferDelegateIdle::AsyncTexSubImage2D(
AsyncPixelTransferState* transfer_state,
const AsyncTexSubImage2DParams& tex_params,
const AsyncMemoryParams& mem_params) {
- AsyncPixelTransferStateIdle* state =
- static_cast<AsyncPixelTransferStateIdle*>(transfer_state);
+ 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,
@@ -188,7 +165,7 @@ void AsyncPixelTransferDelegateIdle::AsyncTexSubImage2D(
tasks_.push_back(
Task(state->id(),
base::Bind(
- &AsyncPixelTransferStateIdle::PerformTransfer,
+ &AsyncPixelTransferStateImpl::PerformTransfer,
base::AsWeakPtr(state),
base::Bind(
&AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D,
@@ -205,8 +182,8 @@ void AsyncPixelTransferDelegateIdle::AsyncTexSubImage2D(
void AsyncPixelTransferDelegateIdle::WaitForTransferCompletion(
AsyncPixelTransferState* transfer_state) {
- AsyncPixelTransferStateIdle* state =
- static_cast<AsyncPixelTransferStateIdle*>(transfer_state);
+ AsyncPixelTransferStateImpl* state =
+ static_cast<AsyncPixelTransferStateImpl*>(transfer_state);
DCHECK(state);
for (std::list<Task>::iterator iter = tasks_.begin();
diff --git a/ui/gl/async_pixel_transfer_delegate_idle.h b/ui/gl/async_pixel_transfer_delegate_idle.h
index f0a8fc8..96c2363 100644
--- a/ui/gl/async_pixel_transfer_delegate_idle.h
+++ b/ui/gl/async_pixel_transfer_delegate_idle.h
@@ -2,18 +2,14 @@
// 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_IDLE_H_
-#define UI_GL_ASYNC_TASK_DELEGATE_IDLE_H_
+#ifndef UI_GL_ASYNC_PIXEL_TRANSFER_DELEGATE_IDLE_H_
+#define UI_GL_ASYNC_PIXEL_TRANSFER_DELEGATE_IDLE_H_
#include <list>
-#include <queue>
-#include "base/callback.h"
#include "ui/gl/async_pixel_transfer_delegate.h"
namespace gfx {
-class GLSurface;
-class TransferStateInternalIdle;
class ScopedSafeSharedMemory;
// Class which handles async pixel transfers in a platform
@@ -21,13 +17,13 @@ class ScopedSafeSharedMemory;
class AsyncPixelTransferDelegateIdle : public AsyncPixelTransferDelegate,
public base::SupportsWeakPtr<AsyncPixelTransferDelegateIdle> {
public:
- static scoped_ptr<AsyncPixelTransferDelegate>
- Create(gfx::GLContext* context);
-
AsyncPixelTransferDelegateIdle();
virtual ~AsyncPixelTransferDelegateIdle();
// implement AsyncPixelTransferDelegate:
+ virtual AsyncPixelTransferState* CreatePixelTransferState(
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) OVERRIDE;
virtual bool BindCompletedAsyncTransfers() OVERRIDE;
virtual void AsyncNotifyCompletion(
const AsyncMemoryParams& mem_params,
@@ -61,12 +57,6 @@ class AsyncPixelTransferDelegateIdle : public AsyncPixelTransferDelegate,
void ProcessNotificationTasks();
- // implement AsyncPixelTransferDelegate:
- virtual AsyncPixelTransferState*
- CreateRawPixelTransferState(
- GLuint texture_id,
- const AsyncTexImage2DParams& define_params) OVERRIDE;
-
void PerformNotifyCompletion(
AsyncMemoryParams mem_params,
ScopedSafeSharedMemory* safe_shared_memory,
@@ -93,5 +83,4 @@ class AsyncPixelTransferDelegateIdle : public AsyncPixelTransferDelegate,
} // namespace gfx
-#endif // UI_GL_ASYNC_TASK_DELEGATE_IDLE_H_
-
+#endif // UI_GL_ASYNC_PIXEL_TRANSFER_DELEGATE_IDLE_H_
diff --git a/ui/gl/async_pixel_transfer_delegate_linux.cc b/ui/gl/async_pixel_transfer_delegate_linux.cc
new file mode 100644
index 0000000..6eb8021
--- /dev/null
+++ b/ui/gl/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 "ui/gl/async_pixel_transfer_delegate.h"
+
+#include "base/debug/trace_event.h"
+#include "ui/gl/async_pixel_transfer_delegate_idle.h"
+#include "ui/gl/async_pixel_transfer_delegate_stub.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace gfx {
+
+AsyncPixelTransferDelegate* AsyncPixelTransferDelegate::Create(
+ gfx::GLContext* context) {
+ TRACE_EVENT0("gpu", "AsyncPixelTransferDelegate::Create");
+ switch (GetGLImplementation()) {
+ case kGLImplementationOSMesaGL:
+ case kGLImplementationDesktopGL:
+ case kGLImplementationEGLGLES2:
+ return new AsyncPixelTransferDelegateIdle;
+ case kGLImplementationMockGL:
+ return new AsyncPixelTransferDelegateStub;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+} // namespace gfx
diff --git a/ui/gl/async_pixel_transfer_delegate_mac.cc b/ui/gl/async_pixel_transfer_delegate_mac.cc
new file mode 100644
index 0000000..779c517
--- /dev/null
+++ b/ui/gl/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 "ui/gl/async_pixel_transfer_delegate.h"
+
+#include "base/debug/trace_event.h"
+#include "ui/gl/async_pixel_transfer_delegate_idle.h"
+#include "ui/gl/async_pixel_transfer_delegate_stub.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace gfx {
+
+AsyncPixelTransferDelegate* AsyncPixelTransferDelegate::Create(
+ gfx::GLContext* context) {
+ TRACE_EVENT0("gpu", "AsyncPixelTransferDelegate::Create");
+ switch (GetGLImplementation()) {
+ case kGLImplementationOSMesaGL:
+ case kGLImplementationDesktopGL:
+ case kGLImplementationAppleGL:
+ return new AsyncPixelTransferDelegateIdle;
+ case kGLImplementationMockGL:
+ return new AsyncPixelTransferDelegateStub;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+} // namespace gfx
diff --git a/ui/gl/async_pixel_transfer_delegate_stub.cc b/ui/gl/async_pixel_transfer_delegate_stub.cc
index b085b1e..79b697c 100644
--- a/ui/gl/async_pixel_transfer_delegate_stub.cc
+++ b/ui/gl/async_pixel_transfer_delegate_stub.cc
@@ -1,66 +1,37 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 "ui/gl/async_pixel_transfer_delegate_stub.h"
-#include "base/memory/shared_memory.h"
-#include "build/build_config.h"
-#include "ui/gl/gl_bindings.h"
-
-using base::SharedMemory;
-using base::SharedMemoryHandle;
+namespace gfx {
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;
-}
-} // namespace
-namespace gfx {
+class AsyncPixelTransferStateImpl : public AsyncPixelTransferState {
+ public:
+ AsyncPixelTransferStateImpl() {}
+ virtual ~AsyncPixelTransferStateImpl() {}
-scoped_ptr<AsyncPixelTransferDelegate>
- AsyncPixelTransferDelegateStub::Create(gfx::GLContext* context) {
- return make_scoped_ptr(
- static_cast<AsyncPixelTransferDelegate*>(
- new AsyncPixelTransferDelegateStub()));
-}
+ // Implement AsyncPixelTransferState:
+ virtual bool TransferIsInProgress() OVERRIDE {
+ return false;
+ }
+};
-AsyncTransferStateStub::AsyncTransferStateStub(GLuint texture_id) {
-}
+} // namespace
-AsyncTransferStateStub::~AsyncTransferStateStub() {
-}
+AsyncPixelTransferDelegateStub::AsyncPixelTransferDelegateStub() {}
-bool AsyncTransferStateStub::TransferIsInProgress() {
- return false;
-}
-
-AsyncPixelTransferDelegateStub::AsyncPixelTransferDelegateStub()
- : texture_upload_count_(0) {
-}
-
-AsyncPixelTransferDelegateStub::~AsyncPixelTransferDelegateStub() {
-}
+AsyncPixelTransferDelegateStub::~AsyncPixelTransferDelegateStub() {}
-AsyncPixelTransferState*
- AsyncPixelTransferDelegateStub::CreateRawPixelTransferState(
- GLuint texture_id,
- const AsyncTexImage2DParams& define_params) {
- return new AsyncTransferStateStub(texture_id);
+AsyncPixelTransferState* AsyncPixelTransferDelegateStub::
+ CreatePixelTransferState(GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) {
+ return new AsyncPixelTransferStateImpl;
}
bool AsyncPixelTransferDelegateStub::BindCompletedAsyncTransfers() {
- // Everything is already bound.
return false;
}
@@ -75,24 +46,6 @@ void AsyncPixelTransferDelegateStub::AsyncTexImage2D(
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();
}
@@ -100,37 +53,18 @@ void AsyncPixelTransferDelegateStub::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 AsyncPixelTransferDelegateStub::WaitForTransferCompletion(
AsyncPixelTransferState* state) {
- // Already done.
}
uint32 AsyncPixelTransferDelegateStub::GetTextureUploadCount() {
- return texture_upload_count_;
+ return 0;
}
base::TimeDelta AsyncPixelTransferDelegateStub::GetTotalTextureUploadTime() {
- return total_texture_upload_time_;
+ return base::TimeDelta();
}
bool AsyncPixelTransferDelegateStub::ProcessMorePendingTransfers() {
diff --git a/ui/gl/async_pixel_transfer_delegate_stub.h b/ui/gl/async_pixel_transfer_delegate_stub.h
index 40548b1..2a73d2d 100644
--- a/ui/gl/async_pixel_transfer_delegate_stub.h
+++ b/ui/gl/async_pixel_transfer_delegate_stub.h
@@ -1,38 +1,23 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 UI_GL_ASYNC_TASK_DELEGATE_STUB_H_
-#define UI_GL_ASYNC_TASK_DELEGATE_STUB_H_
+#ifndef UI_GL_ASYNC_PIXEL_TRANSFER_DELEGATE_STUB_H_
+#define UI_GL_ASYNC_PIXEL_TRANSFER_DELEGATE_STUB_H_
#include "ui/gl/async_pixel_transfer_delegate.h"
namespace gfx {
-class AsyncTransferStateStub : public AsyncPixelTransferState {
- public:
- // implement AsyncPixelTransferState:
- virtual bool TransferIsInProgress() OVERRIDE;
-
- private:
- friend class AsyncPixelTransferDelegateStub;
-
- explicit AsyncTransferStateStub(GLuint texture_id);
- virtual ~AsyncTransferStateStub();
- DISALLOW_COPY_AND_ASSIGN(AsyncTransferStateStub);
-};
-
-// Class which handles async pixel transfers (as a fallback).
-// This class just does the uploads synchronously.
class AsyncPixelTransferDelegateStub : public AsyncPixelTransferDelegate {
public:
- static scoped_ptr<AsyncPixelTransferDelegate>
- Create(gfx::GLContext* context);
-
AsyncPixelTransferDelegateStub();
virtual ~AsyncPixelTransferDelegateStub();
- // implement AsyncPixelTransferDelegate:
+ // Implement AsyncPixelTransferDelegate:
+ virtual AsyncPixelTransferState* CreatePixelTransferState(
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params) OVERRIDE;
virtual bool BindCompletedAsyncTransfers() OVERRIDE;
virtual void AsyncNotifyCompletion(
const AsyncMemoryParams& mem_params,
@@ -52,19 +37,11 @@ class AsyncPixelTransferDelegateStub : public AsyncPixelTransferDelegate {
virtual base::TimeDelta GetTotalTextureUploadTime() OVERRIDE;
virtual bool ProcessMorePendingTransfers() OVERRIDE;
virtual bool NeedsProcessMorePendingTransfers() OVERRIDE;
- private:
- // implement AsyncPixelTransferDelegate:
- virtual AsyncPixelTransferState*
- CreateRawPixelTransferState(GLuint texture_id,
- const AsyncTexImage2DParams& define_params) OVERRIDE;
-
- int texture_upload_count_;
- base::TimeDelta total_texture_upload_time_;
+ private:
DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateStub);
};
} // namespace gfx
-#endif // UI_GL_ASYNC_TASK_DELEGATE_ANDROID_H_
-
+#endif // UI_GL_ASYNC_PIXEL_TRANSFER_DELEGATE_STUB_H_
diff --git a/ui/gl/async_pixel_transfer_delegate_sync.cc b/ui/gl/async_pixel_transfer_delegate_sync.cc
new file mode 100644
index 0000000..e948957
--- /dev/null
+++ b/ui/gl/async_pixel_transfer_delegate_sync.cc
@@ -0,0 +1,137 @@
+// 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 "ui/gl/async_pixel_transfer_delegate_sync.h"
+
+#include "base/memory/shared_memory.h"
+
+using base::SharedMemory;
+using base::SharedMemoryHandle;
+
+namespace gfx {
+
+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;
+}
+
+bool AsyncPixelTransferDelegateSync::BindCompletedAsyncTransfers() {
+ // Everything is already bound.
+ return false;
+}
+
+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_;
+}
+
+bool AsyncPixelTransferDelegateSync::ProcessMorePendingTransfers() {
+ return false;
+}
+
+bool AsyncPixelTransferDelegateSync::NeedsProcessMorePendingTransfers() {
+ return false;
+}
+
+} // namespace gfx
+
diff --git a/ui/gl/async_pixel_transfer_delegate_sync.h b/ui/gl/async_pixel_transfer_delegate_sync.h
new file mode 100644
index 0000000..ba60042
--- /dev/null
+++ b/ui/gl/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 UI_GL_ASYNC_PIXEL_TRANSFER_DELEGATE_SYNC_H_
+#define UI_GL_ASYNC_PIXEL_TRANSFER_DELEGATE_SYNC_H_
+
+#include "ui/gl/async_pixel_transfer_delegate.h"
+
+namespace gfx {
+
+// 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 bool 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 bool ProcessMorePendingTransfers() OVERRIDE;
+ virtual bool NeedsProcessMorePendingTransfers() OVERRIDE;
+
+ private:
+ int texture_upload_count_;
+ base::TimeDelta total_texture_upload_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateSync);
+};
+
+} // namespace gfx
+
+#endif // UI_GL_ASYNC_PIXEL_TRANSFER_DELEGATE_SYNC_H_
diff --git a/ui/gl/async_pixel_transfer_delegate_win.cc b/ui/gl/async_pixel_transfer_delegate_win.cc
new file mode 100644
index 0000000..6eb8021
--- /dev/null
+++ b/ui/gl/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 "ui/gl/async_pixel_transfer_delegate.h"
+
+#include "base/debug/trace_event.h"
+#include "ui/gl/async_pixel_transfer_delegate_idle.h"
+#include "ui/gl/async_pixel_transfer_delegate_stub.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace gfx {
+
+AsyncPixelTransferDelegate* AsyncPixelTransferDelegate::Create(
+ gfx::GLContext* context) {
+ TRACE_EVENT0("gpu", "AsyncPixelTransferDelegate::Create");
+ switch (GetGLImplementation()) {
+ case kGLImplementationOSMesaGL:
+ case kGLImplementationDesktopGL:
+ case kGLImplementationEGLGLES2:
+ return new AsyncPixelTransferDelegateIdle;
+ case kGLImplementationMockGL:
+ return new AsyncPixelTransferDelegateStub;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+} // namespace gfx
diff --git a/ui/gl/gl.gyp b/ui/gl/gl.gyp
index a6bf398..b1527cb 100644
--- a/ui/gl/gl.gyp
+++ b/ui/gl/gl.gyp
@@ -48,11 +48,18 @@
'android/surface_texture_bridge.h',
'android/surface_texture_listener.cc',
'android/surface_texture_listener.h',
+ 'async_pixel_transfer_delegate.cc',
'async_pixel_transfer_delegate.h',
+ 'async_pixel_transfer_delegate_android.cc',
'async_pixel_transfer_delegate_idle.cc',
'async_pixel_transfer_delegate_idle.h',
+ 'async_pixel_transfer_delegate_linux.cc',
+ 'async_pixel_transfer_delegate_mac.cc',
'async_pixel_transfer_delegate_stub.cc',
'async_pixel_transfer_delegate_stub.h',
+ 'async_pixel_transfer_delegate_sync.cc',
+ 'async_pixel_transfer_delegate_sync.h',
+ 'async_pixel_transfer_delegate_win.cc',
'gl_bindings.h',
'gl_bindings_skia_in_process.cc',
'gl_bindings_skia_in_process.h',
@@ -183,6 +190,8 @@
'conditions': [
['OS != "mac"', {
'sources': [
+ 'async_pixel_transfer_delegate_egl.cc',
+ 'async_pixel_transfer_delegate_egl.h',
'egl_util.cc',
'egl_util.h',
'gl_context_egl.cc',
@@ -265,8 +274,6 @@
'gl_jni_headers',
],
'sources': [
- 'async_pixel_transfer_delegate_android.cc',
- 'async_pixel_transfer_delegate_android.h',
'gl_image_egl.cc',
'gl_image_egl.h',
],