Index: gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc |
diff --git a/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc b/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc |
deleted file mode 100644 |
index 6e1c3e7c61ec232926659cf6ae6434215a3f04c4..0000000000000000000000000000000000000000 |
--- a/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc |
+++ /dev/null |
@@ -1,733 +0,0 @@ |
-// Copyright 2013 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "gpu/command_buffer/service/async_pixel_transfer_manager_egl.h" |
- |
-#include <list> |
-#include <string> |
- |
-#include "base/bind.h" |
-#include "base/lazy_instance.h" |
-#include "base/location.h" |
-#include "base/logging.h" |
-#include "base/memory/ref_counted.h" |
-#include "base/single_thread_task_runner.h" |
-#include "base/synchronization/waitable_event.h" |
-#include "base/threading/thread.h" |
-#include "base/trace_event/trace_event.h" |
-#include "base/trace_event/trace_event_synthetic_delay.h" |
-#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h" |
-#include "ui/gl/gl_context.h" |
-#include "ui/gl/gl_surface_egl.h" |
-#include "ui/gl/scoped_binders.h" |
- |
-namespace gpu { |
- |
-namespace { |
- |
-bool CheckErrors(const char* file, int line) { |
- EGLint eglerror; |
- GLenum glerror; |
- bool success = true; |
- while ((eglerror = eglGetError()) != EGL_SUCCESS) { |
- LOG(ERROR) << "Async transfer EGL error at " |
- << file << ":" << line << " " << eglerror; |
- success = false; |
- } |
- while ((glerror = glGetError()) != GL_NO_ERROR) { |
- LOG(ERROR) << "Async transfer OpenGL error at " |
- << file << ":" << line << " " << glerror; |
- success = false; |
- } |
- return success; |
-} |
-#define CHECK_GL() CheckErrors(__FILE__, __LINE__) |
- |
-const char kAsyncTransferThreadName[] = "AsyncTransferThread"; |
- |
-// Regular glTexImage2D call. |
-void DoTexImage2D(const AsyncTexImage2DParams& tex_params, void* data) { |
- glTexImage2D( |
- GL_TEXTURE_2D, tex_params.level, tex_params.internal_format, |
- tex_params.width, tex_params.height, |
- tex_params.border, tex_params.format, tex_params.type, data); |
-} |
- |
-// Regular glTexSubImage2D call. |
-void DoTexSubImage2D(const AsyncTexSubImage2DParams& tex_params, void* data) { |
- glTexSubImage2D( |
- GL_TEXTURE_2D, tex_params.level, |
- tex_params.xoffset, tex_params.yoffset, |
- tex_params.width, tex_params.height, |
- tex_params.format, tex_params.type, data); |
-} |
- |
-// Full glTexSubImage2D call, from glTexImage2D params. |
-void DoFullTexSubImage2D(const AsyncTexImage2DParams& tex_params, void* data) { |
- glTexSubImage2D( |
- GL_TEXTURE_2D, tex_params.level, |
- 0, 0, tex_params.width, tex_params.height, |
- tex_params.format, tex_params.type, data); |
-} |
- |
-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); |
-} |
- |
-void PerformNotifyCompletion( |
- AsyncMemoryParams mem_params, |
- scoped_refptr<AsyncPixelTransferCompletionObserver> observer) { |
- TRACE_EVENT0("gpu", "PerformNotifyCompletion"); |
- observer->DidComplete(mem_params); |
-} |
- |
-class TransferThread : public base::Thread { |
- public: |
- TransferThread() : base::Thread(kAsyncTransferThreadName) { |
- base::Thread::Options options; |
-#if defined(OS_ANDROID) |
- options.priority = base::ThreadPriority::BACKGROUND; |
-#endif |
- StartWithOptions(options); |
- } |
- ~TransferThread() override { Stop(); } |
- |
- void Init() override { |
- gfx::GLShareGroup* share_group = NULL; |
- surface_ = new gfx::PbufferGLSurfaceEGL(gfx::Size(1, 1)); |
- surface_->Initialize(); |
- context_ = gfx::GLContext::CreateGLContext( |
- share_group, surface_.get(), gfx::PreferDiscreteGpu); |
- bool is_current = context_->MakeCurrent(surface_.get()); |
- DCHECK(is_current); |
- } |
- |
- void CleanUp() override { |
- surface_ = NULL; |
- context_->ReleaseCurrent(surface_.get()); |
- context_ = NULL; |
- } |
- |
- private: |
- scoped_refptr<gfx::GLContext> context_; |
- scoped_refptr<gfx::GLSurface> surface_; |
- |
- DISALLOW_COPY_AND_ASSIGN(TransferThread); |
-}; |
- |
-base::LazyInstance<TransferThread> |
- g_transfer_thread = LAZY_INSTANCE_INITIALIZER; |
- |
-base::SingleThreadTaskRunner* transfer_task_runner() { |
- return g_transfer_thread.Pointer()->task_runner().get(); |
-} |
- |
-// 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_); |
- if (EGL_NO_IMAGE_KHR == egl_image_) |
- return; |
- |
- 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); |
- |
- DLOG_IF(ERROR, EGL_NO_IMAGE_KHR == egl_image_) |
- << "eglCreateImageKHR failed"; |
- } |
- |
- 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() { |
- TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("gpu.AsyncTexImage"); |
- transfer_completion_.Reset(); |
- } |
- |
- void MarkAsCompleted() { |
- TRACE_EVENT_SYNTHETIC_DELAY_END("gpu.AsyncTexImage"); |
- transfer_completion_.Signal(); |
- } |
- |
- void WaitForTransferCompletion() { |
- TRACE_EVENT0("gpu", "WaitForTransferCompletion"); |
- // TODO(backer): Deschedule the channel rather than blocking the main GPU |
- // thread (crbug.com/240265). |
- transfer_completion_.Wait(); |
- } |
- |
- void PerformAsyncTexImage2D( |
- AsyncTexImage2DParams tex_params, |
- AsyncMemoryParams mem_params, |
- scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) { |
- TRACE_EVENT2("gpu", |
- "PerformAsyncTexImage", |
- "width", |
- tex_params.width, |
- "height", |
- tex_params.height); |
- DCHECK(!thread_texture_id_); |
- DCHECK_EQ(0, tex_params.level); |
- if (EGL_NO_IMAGE_KHR != egl_image_) { |
- MarkAsCompleted(); |
- return; |
- } |
- |
- void* data = mem_params.GetDataAddress(); |
- |
- base::TimeTicks begin_time; |
- if (texture_upload_stats.get()) |
- begin_time = base::TimeTicks::Now(); |
- |
- { |
- TRACE_EVENT0("gpu", "glTexImage2D no data"); |
- glGenTextures(1, &thread_texture_id_); |
- glActiveTexture(GL_TEXTURE0); |
- glBindTexture(GL_TEXTURE_2D, 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 (use_image_preserved_) |
- DoTexImage2D(tex_params, data); |
- else |
- DoTexImage2D(tex_params, NULL); |
- } |
- |
- 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 (!use_image_preserved_) |
- DoFullTexSubImage2D(tex_params, data); |
- } |
- |
- WaitForLastUpload(); |
- MarkAsCompleted(); |
- |
- DCHECK(CHECK_GL()); |
- if (texture_upload_stats.get()) { |
- texture_upload_stats->AddUpload(base::TimeTicks::Now() - begin_time); |
- } |
- } |
- |
- void PerformAsyncTexSubImage2D( |
- AsyncTexSubImage2DParams tex_params, |
- AsyncMemoryParams mem_params, |
- scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) { |
- TRACE_EVENT2("gpu", |
- "PerformAsyncTexSubImage2D", |
- "width", |
- tex_params.width, |
- "height", |
- tex_params.height); |
- |
- DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_); |
- DCHECK_EQ(0, tex_params.level); |
- |
- void* data = mem_params.GetDataAddress(); |
- |
- base::TimeTicks begin_time; |
- if (texture_upload_stats.get()) |
- begin_time = base::TimeTicks::Now(); |
- |
- if (!thread_texture_id_) { |
- TRACE_EVENT0("gpu", "glEGLImageTargetTexture2DOES"); |
- glGenTextures(1, &thread_texture_id_); |
- glActiveTexture(GL_TEXTURE0); |
- glBindTexture(GL_TEXTURE_2D, thread_texture_id_); |
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_); |
- } else { |
- glActiveTexture(GL_TEXTURE0); |
- glBindTexture(GL_TEXTURE_2D, thread_texture_id_); |
- } |
- { |
- TRACE_EVENT0("gpu", "glTexSubImage2D"); |
- DoTexSubImage2D(tex_params, data); |
- } |
- WaitForLastUpload(); |
- MarkAsCompleted(); |
- |
- DCHECK(CHECK_GL()); |
- if (texture_upload_stats.get()) { |
- texture_upload_stats->AddUpload(base::TimeTicks::Now() - begin_time); |
- } |
- } |
- |
- protected: |
- friend class base::RefCountedThreadSafe<TransferStateInternal>; |
- friend class gpu::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_task_runner()->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_; |
-}; |
- |
-} // namespace |
- |
-// Class which handles async pixel transfers using EGLImageKHR and another |
-// upload thread |
-class AsyncPixelTransferDelegateEGL |
- : public AsyncPixelTransferDelegate, |
- public base::SupportsWeakPtr<AsyncPixelTransferDelegateEGL> { |
- public: |
- AsyncPixelTransferDelegateEGL( |
- AsyncPixelTransferManagerEGL::SharedState* shared_state, |
- GLuint texture_id, |
- const AsyncTexImage2DParams& define_params); |
- ~AsyncPixelTransferDelegateEGL() override; |
- |
- void BindTransfer() { state_->BindTransfer(); } |
- |
- // Implement AsyncPixelTransferDelegate: |
- void AsyncTexImage2D(const AsyncTexImage2DParams& tex_params, |
- const AsyncMemoryParams& mem_params, |
- const base::Closure& bind_callback) override; |
- void AsyncTexSubImage2D(const AsyncTexSubImage2DParams& tex_params, |
- const AsyncMemoryParams& mem_params) override; |
- bool TransferIsInProgress() override; |
- void WaitForTransferCompletion() override; |
- |
- private: |
- // Returns true if a work-around was used. |
- bool WorkAroundAsyncTexImage2D( |
- const AsyncTexImage2DParams& tex_params, |
- const AsyncMemoryParams& mem_params, |
- const base::Closure& bind_callback); |
- bool WorkAroundAsyncTexSubImage2D( |
- const AsyncTexSubImage2DParams& tex_params, |
- const AsyncMemoryParams& mem_params); |
- |
- // A raw pointer is safe because the SharedState is owned by the Manager, |
- // which owns this Delegate. |
- AsyncPixelTransferManagerEGL::SharedState* shared_state_; |
- scoped_refptr<TransferStateInternal> state_; |
- |
- DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateEGL); |
-}; |
- |
-AsyncPixelTransferDelegateEGL::AsyncPixelTransferDelegateEGL( |
- AsyncPixelTransferManagerEGL::SharedState* shared_state, |
- GLuint texture_id, |
- const AsyncTexImage2DParams& define_params) |
- : shared_state_(shared_state) { |
- // 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 = !shared_state_->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 = shared_state_->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 = |
- shared_state_->is_qualcomm || shared_state_->is_imagination; |
- |
- state_ = new TransferStateInternal(texture_id, |
- define_params, |
- wait_for_uploads, |
- wait_for_creation, |
- use_image_preserved); |
-} |
- |
-AsyncPixelTransferDelegateEGL::~AsyncPixelTransferDelegateEGL() {} |
- |
-bool AsyncPixelTransferDelegateEGL::TransferIsInProgress() { |
- return state_->TransferIsInProgress(); |
-} |
- |
-void AsyncPixelTransferDelegateEGL::WaitForTransferCompletion() { |
- if (state_->TransferIsInProgress()) { |
- state_->WaitForTransferCompletion(); |
- DCHECK(!state_->TransferIsInProgress()); |
- } |
-} |
- |
-void AsyncPixelTransferDelegateEGL::AsyncTexImage2D( |
- const AsyncTexImage2DParams& tex_params, |
- const AsyncMemoryParams& mem_params, |
- const base::Closure& bind_callback) { |
- if (WorkAroundAsyncTexImage2D(tex_params, mem_params, bind_callback)) |
- return; |
- |
- 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. |
- shared_state_->pending_allocations.push_back(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_task_runner()->PostTask( |
- FROM_HERE, |
- base::Bind(&TransferStateInternal::PerformAsyncTexImage2D, state_, |
- tex_params, mem_params, shared_state_->texture_upload_stats)); |
- |
- DCHECK(CHECK_GL()); |
-} |
- |
-void AsyncPixelTransferDelegateEGL::AsyncTexSubImage2D( |
- const AsyncTexSubImage2DParams& tex_params, |
- const AsyncMemoryParams& mem_params) { |
- TRACE_EVENT2("gpu", "AsyncTexSubImage2D", |
- "width", tex_params.width, |
- "height", tex_params.height); |
- if (WorkAroundAsyncTexSubImage2D(tex_params, mem_params)) |
- return; |
- DCHECK(!state_->TransferIsInProgress()); |
- 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_task_runner()->PostTask( |
- FROM_HERE, |
- base::Bind(&TransferStateInternal::PerformAsyncTexSubImage2D, state_, |
- tex_params, mem_params, shared_state_->texture_upload_stats)); |
- |
- DCHECK(CHECK_GL()); |
-} |
- |
-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( |
- const AsyncTexImage2DParams& tex_params, |
- const AsyncMemoryParams& mem_params, |
- const base::Closure& bind_callback) { |
- if (!shared_state_->is_imagination) |
- return false; |
- |
- // 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 = mem_params.GetDataAddress(); |
- 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(); |
- shared_state_->pending_allocations.push_back(AsWeakPtr()); |
- state_->bind_callback_ = bind_callback; |
- } |
- |
- DCHECK(CHECK_GL()); |
- return true; |
-} |
- |
-bool AsyncPixelTransferDelegateEGL::WorkAroundAsyncTexSubImage2D( |
- const AsyncTexSubImage2DParams& tex_params, |
- const AsyncMemoryParams& mem_params) { |
- if (!shared_state_->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; |
- |
- // 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 = mem_params.GetDataAddress(); |
- base::TimeTicks begin_time; |
- if (shared_state_->texture_upload_stats.get()) |
- begin_time = base::TimeTicks::Now(); |
- { |
- 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 (shared_state_->texture_upload_stats.get()) { |
- shared_state_->texture_upload_stats |
- ->AddUpload(base::TimeTicks::Now() - begin_time); |
- } |
- |
- DCHECK(CHECK_GL()); |
- return true; |
-} |
- |
-AsyncPixelTransferManagerEGL::SharedState::SharedState() |
- // TODO(reveman): Skip this if --enable-gpu-benchmarking is not present. |
- : texture_upload_stats(new AsyncPixelTransferUploadStats) { |
- const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR)); |
- if (vendor) { |
- is_imagination = |
- std::string(vendor).find("Imagination") != std::string::npos; |
- is_qualcomm = std::string(vendor).find("Qualcomm") != std::string::npos; |
- } |
-} |
- |
-AsyncPixelTransferManagerEGL::SharedState::~SharedState() {} |
- |
-AsyncPixelTransferManagerEGL::AsyncPixelTransferManagerEGL() {} |
- |
-AsyncPixelTransferManagerEGL::~AsyncPixelTransferManagerEGL() {} |
- |
-void AsyncPixelTransferManagerEGL::BindCompletedAsyncTransfers() { |
- scoped_ptr<gfx::ScopedTextureBinder> texture_binder; |
- |
- while(!shared_state_.pending_allocations.empty()) { |
- if (!shared_state_.pending_allocations.front().get()) { |
- shared_state_.pending_allocations.pop_front(); |
- continue; |
- } |
- AsyncPixelTransferDelegateEGL* delegate = |
- shared_state_.pending_allocations.front().get(); |
- // Terminate early, as all transfers finish in order, currently. |
- if (delegate->TransferIsInProgress()) |
- break; |
- |
- if (!texture_binder) |
- texture_binder.reset(new gfx::ScopedTextureBinder(GL_TEXTURE_2D, 0)); |
- |
- // If the transfer is finished, bind it to the texture |
- // and remove it from pending list. |
- delegate->BindTransfer(); |
- shared_state_.pending_allocations.pop_front(); |
- } |
-} |
- |
-void AsyncPixelTransferManagerEGL::AsyncNotifyCompletion( |
- const AsyncMemoryParams& mem_params, |
- AsyncPixelTransferCompletionObserver* observer) { |
- // Post a PerformNotifyCompletion task to the upload thread. This task |
- // will run after all async transfers are complete. |
- transfer_task_runner()->PostTask( |
- FROM_HERE, base::Bind(&PerformNotifyCompletion, mem_params, |
- make_scoped_refptr(observer))); |
-} |
- |
-uint32 AsyncPixelTransferManagerEGL::GetTextureUploadCount() { |
- return shared_state_.texture_upload_stats->GetStats(NULL); |
-} |
- |
-base::TimeDelta AsyncPixelTransferManagerEGL::GetTotalTextureUploadTime() { |
- base::TimeDelta total_texture_upload_time; |
- shared_state_.texture_upload_stats->GetStats(&total_texture_upload_time); |
- return total_texture_upload_time; |
-} |
- |
-void AsyncPixelTransferManagerEGL::ProcessMorePendingTransfers() { |
-} |
- |
-bool AsyncPixelTransferManagerEGL::NeedsProcessMorePendingTransfers() { |
- return false; |
-} |
- |
-void AsyncPixelTransferManagerEGL::WaitAllAsyncTexImage2D() { |
- if (shared_state_.pending_allocations.empty()) |
- return; |
- |
- AsyncPixelTransferDelegateEGL* delegate = |
- shared_state_.pending_allocations.back().get(); |
- if (delegate) |
- delegate->WaitForTransferCompletion(); |
-} |
- |
-AsyncPixelTransferDelegate* |
-AsyncPixelTransferManagerEGL::CreatePixelTransferDelegateImpl( |
- gles2::TextureRef* ref, |
- const AsyncTexImage2DParams& define_params) { |
- return new AsyncPixelTransferDelegateEGL( |
- &shared_state_, ref->service_id(), define_params); |
-} |
- |
-} // namespace gpu |