Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(177)

Unified Diff: ui/gl/async_pixel_transfer_delegate_android.cc

Issue 11428140: gpu: Add async pixel transfer interface, stub and tests. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/gl/async_pixel_transfer_delegate_android.cc
diff --git a/ui/gl/async_pixel_transfer_delegate_android.cc b/ui/gl/async_pixel_transfer_delegate_android.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0be2d51d3f217f6c5ab21f05a564ee3d3395c0c0
--- /dev/null
+++ b/ui/gl/async_pixel_transfer_delegate_android.cc
@@ -0,0 +1,292 @@
+// 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_android.h"
+
+#include "base/bind.h"
+#include "base/cancelable_callback.h"
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread.h"
+#include "build/build_config.h"
+#include "third_party/angle/include/EGL/egl.h"
+#include "third_party/angle/include/EGL/eglext.h"
+#include "ui/gfx/point.h"
+#include "ui/gfx/size.h"
+#include "ui/gl/async_pixel_transfer_delegate.h"
+#include "ui/gl/egl_util.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_surface_egl.h"
+
+namespace gfx {
+
+
apatrick 2012/12/03 21:23:59 nit: delete blank line.
epennerAtGoogle 2012/12/04 19:56:48 Done.
+bool check_errors(const char* file, int line) {
apatrick 2012/12/03 21:23:59 nit: CheckErrors
epennerAtGoogle 2012/12/04 19:56:48 Done.
+ EGLint eglerror;
+ GLenum glerror;
+ bool success = true;
+ while ((eglerror = eglGetError()) != EGL_SUCCESS) {
+ LOG(ERROR) << "ESP eglerror " << file << ":" << line << " " << eglerror;
+ success = false;
+ }
+ while ((glerror = glGetError()) != GL_NO_ERROR) {
+ LOG(ERROR) << "ESP openglerror " << file << ":" << line << " " << glerror;
+ success = false;
+ }
+ return success;
+}
+#define CHK() check_errors(__FILE__, __LINE__)
+
+
+class AsyncTransferStateAndroid : public AsyncPixelTransferState {
+ public:
+ AsyncTransferStateAndroid(GLuint texture_id)
+ : texture_id_(texture_id)
+ , egl_image_(0) {}
apatrick 2012/12/03 21:23:59 nit: comma to line above.
epennerAtGoogle 2012/12/04 19:56:48 Done.
+ virtual ~AsyncTransferStateAndroid() {
+ if (egl_image_) {
+ EGLDisplay display = eglGetCurrentDisplay();
+ eglDestroyImageKHR(display, egl_image_);
+ }
+ }
+ void no_op() {}
apatrick 2012/12/03 21:23:59 I think you sent with the free function in the ano
epennerAtGoogle 2012/12/03 22:48:45 I use this one too, solely such that a reply holds
greggman 2012/12/05 02:23:42 nit: functions are CamelCase
epenner 2012/12/08 03:15:03 Done.
+ GLuint texture_id_;
+ EGLImageKHR egl_image_;
+};
+
+
+// Class which handles async pixel transfers on Android (using
+// EGLImageKHR and another upload thread)
+class AsyncPixelTransferDelegateAndroid : public AsyncPixelTransferDelegate {
+ public:
+ AsyncPixelTransferDelegateAndroid();
+ virtual ~AsyncPixelTransferDelegateAndroid();
+
+ // implement AsyncPixelTransferDelegate:
+ virtual scoped_refptr<AsyncPixelTransferState>
+ CreatePixelTransferState(GLuint);
+ virtual void AsyncNotifyCompletion(
+ const base::Closure& task);
+ virtual void AsyncTexSubImage2D(
+ AsyncPixelTransferState*,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ const void* data);
+
+ private:
+ void Initialize();
+ void Shutdown();
+ void PerformInitialize();
+ void PerformShutdown();
+
+ void PerformAsyncTexSubImage2D(
+ EGLImageKHR egl_image,
+ gfx::Point offset,
+ gfx::Size size,
+ GLenum format,
+ GLenum type,
+ const void * data);
+
+ scoped_ptr<base::Thread> thread_;
+ scoped_refptr<gfx::GLContext> thread_context_;
+ scoped_refptr<gfx::GLSurface> thread_surface_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateAndroid);
+};
+
+// Lazy instance creation.
+base::LazyInstance<AsyncPixelTransferDelegateAndroid>
+ g_async_pixel_transfer_delegate_ = LAZY_INSTANCE_INITIALIZER;
+
+AsyncPixelTransferDelegate* AsyncPixelTransferDelegate::Get() {
+ return g_async_pixel_transfer_delegate_.Pointer();
+}
+
+scoped_refptr<AsyncPixelTransferState>
+ AsyncPixelTransferDelegateAndroid::
+ CreatePixelTransferState(GLuint texture_id) {
+ return make_scoped_refptr((AsyncPixelTransferState*)
apatrick 2012/12/03 21:23:59 nit: no c-style casts.
epennerAtGoogle 2012/12/04 19:56:48 Done.
+ new AsyncTransferStateAndroid(texture_id));
+}
+
+AsyncPixelTransferDelegateAndroid::AsyncPixelTransferDelegateAndroid()
+ : thread_(new base::Thread("GPUAsyncTransferThread"))
+{
greggman 2012/12/05 02:23:42 nit: { wants to be on previous line
epenner 2012/12/08 03:15:03 Done.
+ Initialize();
+}
+
+AsyncPixelTransferDelegateAndroid::~AsyncPixelTransferDelegateAndroid()
+{
greggman 2012/12/05 02:23:42 nit: { wants to be on previous line
epenner 2012/12/08 03:15:03 Done.
+ Shutdown();
+}
+
+void AsyncPixelTransferDelegateAndroid::Initialize() {
+ // Start the thread and initialize on the thread.
+ thread_->Start();
+ thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
+ &AsyncPixelTransferDelegateAndroid::PerformInitialize,
+ base::Unretained(this)));
+}
+
+void AsyncPixelTransferDelegateAndroid::Shutdown() {
+ // Shutdown and wait for the thread to finish.
+ thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
+ &AsyncPixelTransferDelegateAndroid::PerformShutdown,
+ base::Unretained(this)));
+ thread_->Stop();
+}
+
+namespace {
+ void no_op() {}
apatrick 2012/12/03 21:23:59 nit: no indentation. NoOp.
epennerAtGoogle 2012/12/04 19:56:48 Done.
+}
+
+void AsyncPixelTransferDelegateAndroid::AsyncNotifyCompletion(
+ const base::Closure& task) {
+ // Post a no-op task to the upload thread followed
+ // by a reply to the callback. The reply will occur after
+ // all async transfers are complete.
+ thread_->message_loop_proxy()->PostTaskAndReply(FROM_HERE,
+ base::Bind(&no_op), task);
+}
+
+
+void AsyncPixelTransferDelegateAndroid::AsyncTexSubImage2D(
+ AsyncPixelTransferState* transfer_state,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ const void* data) {
+ TRACE_EVENT2("gpu", "AsyncTexSubImage2D",
+ "width", width,
+ "height", height);
+ AsyncTransferStateAndroid* state =(AsyncTransferStateAndroid*)transfer_state;
apatrick 2012/12/03 21:23:59 nit: no c-style casts.
epennerAtGoogle 2012/12/04 19:56:48 Done.
+ DCHECK(state);
+ DCHECK(state->texture_id_);
+
+ // TODO: Implement other targets/levels if needed.
+ DCHECK(target == GL_TEXTURE_2D);
+ DCHECK(level == 0);
+
+ // Create the EGLImage if it hasn't already been created.
+ if (!state->egl_image_) {
+ EGLDisplay egl_display = eglGetCurrentDisplay();
+ EGLContext egl_context = eglGetCurrentContext();
+ EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR;
+ EGLClientBuffer egl_buffer = (EGLClientBuffer) state->texture_id_;
apatrick 2012/12/03 21:23:59 nit: c-style casts.
epennerAtGoogle 2012/12/04 19:56:48 Done.
+ EGLint egl_attrib_list[] = {
+ EGL_GL_TEXTURE_LEVEL_KHR, level, // mip-map level to reference.
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, // preserve the data in the texture.
+ EGL_NONE
+ };
+ state->egl_image_ = eglCreateImageKHR(
+ egl_display,
+ egl_context,
+ egl_target,
+ egl_buffer,
+ egl_attrib_list);
+ }
+
+ // Post the upload task. The reply is a no-op but keeps
+ // the texture state referenced, so the EGLImage is not destroyed
+ // before it is used on the upload thead.
+ thread_->message_loop_proxy()->PostTaskAndReply(FROM_HERE,
+ base::Bind(
+ &AsyncPixelTransferDelegateAndroid::PerformAsyncTexSubImage2D,
+ base::Unretained(this),
+ state->egl_image_,
+ gfx::Point(xoffset, yoffset),
+ gfx::Size(width, height),
+ format, type, data),
+ base::Bind(
+ &AsyncTransferStateAndroid::no_op,
+ state));
+ CHK();
+}
+
+
+void AsyncPixelTransferDelegateAndroid::PerformInitialize() {
+ DCHECK(!thread_surface_);
+ DCHECK(!thread_context_);
+ GLShareGroup* share_group = NULL;
+ bool software = false;
+ thread_surface_ = new gfx::PbufferGLSurfaceEGL(software, gfx::Size(1,1));
apatrick 2012/12/03 21:23:59 Neither GLSurface or GLContext implementations are
epennerAtGoogle 2012/12/03 22:48:45 I see! I think since this is self-contained and p
epennerAtGoogle 2012/12/04 00:47:14 Actually after looking at this it appears some of
+ thread_surface_->Initialize();
+ thread_context_ = gfx::GLContext::CreateGLContext(share_group,
+ thread_surface_,
+ gfx::PreferDiscreteGpu);
+ bool is_current = thread_context_->MakeCurrent(thread_surface_);
apatrick 2012/12/03 21:23:59 This will modify the current context pointer, shar
epennerAtGoogle 2012/12/03 22:48:45 Very good to know, thanks!
+ DCHECK(thread_surface_);
+ DCHECK(thread_context_);
+ DCHECK(is_current);
+}
+
+void AsyncPixelTransferDelegateAndroid::PerformShutdown() {
+ DCHECK(thread_surface_);
+ DCHECK(thread_context_);
+ thread_surface_ = NULL;
+ thread_context_->ReleaseCurrent(thread_surface_);
+ thread_context_ = NULL;
+}
+
+void AsyncPixelTransferDelegateAndroid::PerformAsyncTexSubImage2D(
+ EGLImageKHR egl_image,
+ gfx::Point offset,
+ gfx::Size size,
+ GLenum format,
+ GLenum type,
+ const void* data) {
+ // For a texSubImage, the texture must already have been
+ // created on the main thread, along with EGLImageKHR.
+ DCHECK(egl_image);
+ TRACE_EVENT2("gpu", "performAsyncTexSubImage2D",
+ "width", size.width(),
+ "height", size.height());
+
+ // Create a texture from the image and upload to it.
+ GLuint texture = 0;
+ glGenTextures(1, &texture);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image);
+ {
+ TRACE_EVENT0("gpu", "performAsyncTexSubImage2D glTexSubImage2D");
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ offset.x(), offset.y(),
+ size.width(), size.height(),
+ format, type, data);
+ }
+
+ // Uploads usually finish on the GPU, but just in case add a fence
+ // and guarantee the upload has completed.
+ // EGLSyncKHR fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, NULL);
+ // EGLint flags = EGL_SYNC_FLUSH_COMMANDS_BIT_KHR;
+ // EGLTimeKHR time = EGL_FOREVER_KHR;
+ // eglClientWaitSyncKHR(display, fence, flags, time);
+
+ // TODO: Fix bindings (link errors) to enable the above instead of glFinish.
+ glFinish();
+
+ // We can delete this thread's texture as the real texture
+ // now contains the data.
+ glDeleteTextures(1, &texture);
+ CHK();
+}
+
+
+
+} // namespace gfx

Powered by Google App Engine
This is Rietveld 408576698