summaryrefslogtreecommitdiffstats
path: root/components/exo
diff options
context:
space:
mode:
authorreveman <reveman@chromium.org>2016-02-24 17:50:03 -0800
committerCommit bot <commit-bot@chromium.org>2016-02-25 01:51:19 +0000
commitae3b7c85a92790c252c470f6fe0c772e5c5959ca (patch)
treee10a47f61e07b708c096301396300fa318b2e484 /components/exo
parent5477c3e6bf9fbe689f23afc431646c4007c61a25 (diff)
downloadchromium_src-ae3b7c85a92790c252c470f6fe0c772e5c5959ca.zip
chromium_src-ae3b7c85a92790c252c470f6fe0c772e5c5959ca.tar.gz
chromium_src-ae3b7c85a92790c252c470f6fe0c772e5c5959ca.tar.bz2
exo: Wait for release query result after 500ms.
Wait for release queries to complete after some amount of time has passed. This avoids having the client UI completely freeze when a driver is buggy and makes it easier to detect this type driver bugs. BUG=b/27317178 TEST=exo_unittests Review URL: https://codereview.chromium.org/1732013003 Cr-Commit-Position: refs/heads/master@{#377461}
Diffstat (limited to 'components/exo')
-rw-r--r--components/exo/buffer.cc96
1 files changed, 88 insertions, 8 deletions
diff --git a/components/exo/buffer.cc b/components/exo/buffer.cc
index cf25844..de74136 100644
--- a/components/exo/buffer.cc
+++ b/components/exo/buffer.cc
@@ -11,8 +11,12 @@
#include <algorithm>
#include <utility>
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_argument.h"
#include "cc/output/context_provider.h"
@@ -27,6 +31,10 @@
namespace exo {
namespace {
+// The amount of time before we wait for release queries using
+// GetQueryObjectuivEXT(GL_QUERY_RESULT_EXT).
+const int kWaitForReleaseDelayMs = 500;
+
GLenum GLInternalFormat(gfx::BufferFormat format) {
const GLenum kGLInternalFormats[] = {
GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD, // ATC
@@ -119,6 +127,11 @@ class Buffer::Texture {
gpu::Mailbox mailbox() const { return mailbox_; }
private:
+ void ReleaseWhenQueryResultIsAvailable(const base::Closure& callback);
+ void Released();
+ void ScheduleWaitForRelease(base::TimeDelta delay);
+ void WaitForRelease();
+
scoped_refptr<cc::ContextProvider> context_provider_;
const unsigned texture_target_;
const unsigned query_type_;
@@ -127,6 +140,10 @@ class Buffer::Texture {
unsigned query_id_;
unsigned texture_id_;
gpu::Mailbox mailbox_;
+ base::Closure release_callback_;
+ base::TimeTicks wait_for_release_time_;
+ bool wait_for_release_pending_;
+ base::WeakPtrFactory<Texture> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(Texture);
};
@@ -138,7 +155,9 @@ Buffer::Texture::Texture(cc::ContextProvider* context_provider)
internalformat_(GL_RGBA),
image_id_(0),
query_id_(0),
- texture_id_(0) {
+ texture_id_(0),
+ wait_for_release_pending_(false),
+ weak_ptr_factory_(this) {
gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
texture_id_ = CreateGLTexture(gles2, texture_target_);
// Generate a crypto-secure random mailbox name.
@@ -155,7 +174,9 @@ Buffer::Texture::Texture(cc::ContextProvider* context_provider,
internalformat_(GLInternalFormat(gpu_memory_buffer->GetFormat())),
image_id_(0),
query_id_(0),
- texture_id_(0) {
+ texture_id_(0),
+ wait_for_release_pending_(false),
+ weak_ptr_factory_(this) {
gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
gfx::Size size = gpu_memory_buffer->GetSize();
image_id_ =
@@ -222,11 +243,11 @@ void Buffer::Texture::ReleaseTexImage(const base::Closure& callback,
gles2->BeginQueryEXT(query_type_, query_id_);
gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
gles2->EndQueryEXT(query_type_);
- // Run callback when query has signaled and ReleaseTexImage has been handled
- // if sync token has data and buffer has been used. If buffer was never used
- // then run the callback immediately.
+ // Run callback when query result is available and ReleaseTexImage has been
+ // handled if sync token has data and buffer has been used. If buffer was
+ // never used then run the callback immediately.
if (sync_token.HasData()) {
- context_provider_->ContextSupport()->SignalQuery(query_id_, callback);
+ ReleaseWhenQueryResultIsAvailable(callback);
} else {
callback.Run();
}
@@ -246,8 +267,9 @@ gpu::SyncToken Buffer::Texture::CopyTexImage(Texture* destination,
gles2->BeginQueryEXT(query_type_, query_id_);
gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
gles2->EndQueryEXT(query_type_);
- // Run callback when query has signaled and ReleaseTexImage has been handled.
- context_provider_->ContextSupport()->SignalQuery(query_id_, callback);
+ // Run callback when query result is available and ReleaseTexImage has been
+ // handled.
+ ReleaseWhenQueryResultIsAvailable(callback);
// Create and return a sync token that can be used to ensure that the
// CopyTextureCHROMIUM call is processed before issuing any commands
// that will read from the target texture on a different context.
@@ -258,6 +280,64 @@ gpu::SyncToken Buffer::Texture::CopyTexImage(Texture* destination,
return sync_token;
}
+void Buffer::Texture::ReleaseWhenQueryResultIsAvailable(
+ const base::Closure& callback) {
+ DCHECK(release_callback_.is_null());
+ release_callback_ = callback;
+ base::TimeDelta wait_for_release_delay =
+ base::TimeDelta::FromMilliseconds(kWaitForReleaseDelayMs);
+ wait_for_release_time_ = base::TimeTicks::Now() + wait_for_release_delay;
+ ScheduleWaitForRelease(wait_for_release_delay);
+ context_provider_->ContextSupport()->SignalQuery(
+ query_id_,
+ base::Bind(&Buffer::Texture::Released, weak_ptr_factory_.GetWeakPtr()));
+}
+
+void Buffer::Texture::Released() {
+ if (!release_callback_.is_null())
+ base::ResetAndReturn(&release_callback_).Run();
+}
+
+void Buffer::Texture::ScheduleWaitForRelease(base::TimeDelta delay) {
+ if (wait_for_release_pending_)
+ return;
+
+ wait_for_release_pending_ = true;
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::Bind(&Buffer::Texture::WaitForRelease,
+ weak_ptr_factory_.GetWeakPtr()),
+ delay);
+}
+
+void Buffer::Texture::WaitForRelease() {
+ DCHECK(wait_for_release_pending_);
+ wait_for_release_pending_ = false;
+
+ if (release_callback_.is_null())
+ return;
+
+ base::TimeTicks current_time = base::TimeTicks::Now();
+ if (current_time < wait_for_release_time_) {
+ ScheduleWaitForRelease(wait_for_release_time_ - current_time);
+ return;
+ }
+
+ base::Closure callback = base::ResetAndReturn(&release_callback_);
+
+ {
+ TRACE_EVENT0("exo", "Buffer::Texture::WaitForQueryResult");
+
+ // We need to wait for the result to be available. Getting the result of
+ // the query implies waiting for it to become available. The actual result
+ // is unimportant and also not well defined.
+ unsigned result = 0;
+ gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
+ gles2->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
+ }
+
+ callback.Run();
+}
+
////////////////////////////////////////////////////////////////////////////////
// Buffer, public: