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

Unified Diff: cc/output/gl_renderer.cc

Issue 14273026: cc: Make async readback path use async glRreadPixels. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: forlanding Created 7 years, 8 months 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
« no previous file with comments | « cc/output/gl_renderer.h ('k') | cc/output/software_renderer.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cc/output/gl_renderer.cc
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index adfcf473665d0b7e0e317910b8d247a6258906f5..38ce6a6d1ca5343c5d18c6ac0b73e4d55402af7e 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -30,6 +30,7 @@
#include "cc/resources/layer_quad.h"
#include "cc/resources/priority_calculator.h"
#include "cc/resources/scoped_resource.h"
+#include "cc/resources/sync_point_helper.h"
#include "cc/trees/damage_tracker.h"
#include "cc/trees/proxy.h"
#include "cc/trees/single_thread_proxy.h"
@@ -87,6 +88,17 @@ const float kAntiAliasingEpsilon = 1.0f / 1024.0f;
} // anonymous namespace
+struct GLRenderer::PendingAsyncReadPixels {
+ PendingAsyncReadPixels() : buffer(0) {}
+
+ CopyRenderPassCallback copy_callback;
+ base::CancelableClosure finished_read_pixels_callback;
+ unsigned buffer;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PendingAsyncReadPixels);
+};
+
scoped_ptr<GLRenderer> GLRenderer::Create(RendererClient* client,
OutputSurface* output_surface,
ResourceProvider* resource_provider,
@@ -192,6 +204,13 @@ bool GLRenderer::Initialize() {
}
GLRenderer::~GLRenderer() {
+ while (!pending_async_read_pixels_.empty()) {
+ pending_async_read_pixels_.back()->finished_read_pixels_callback.Cancel();
+ pending_async_read_pixels_.back()->copy_callback.Run(
+ scoped_ptr<SkBitmap>());
+ pending_async_read_pixels_.pop_back();
+ }
+
context_->setMemoryAllocationChangedCallbackCHROMIUM(NULL);
CleanupSharedObjects();
}
@@ -1777,17 +1796,10 @@ void GLRenderer::EnsureScissorTestDisabled() {
is_scissor_enabled_ = false;
}
-void GLRenderer::CopyCurrentRenderPassToBitmap(DrawingFrame* frame,
- SkBitmap* bitmap) {
- gfx::Size render_pass_size = frame->current_render_pass->output_rect.size();
- bitmap->setConfig(SkBitmap::kARGB_8888_Config,
- render_pass_size.width(),
- render_pass_size.height());
- if (bitmap->allocPixels()) {
- bitmap->lockPixels();
- GetFramebufferPixels(bitmap->getPixels(), gfx::Rect(render_pass_size));
- bitmap->unlockPixels();
- }
+void GLRenderer::CopyCurrentRenderPassToBitmap(
+ DrawingFrame* frame,
+ const CopyRenderPassCallback& callback) {
+ GetFramebufferPixelsAsync(frame->current_render_pass->output_rect, callback);
}
void GLRenderer::ToGLMatrix(float* gl_matrix, const gfx::Transform& transform) {
@@ -1989,18 +2001,68 @@ void GLRenderer::EnsureBackbuffer() {
}
void GLRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) {
+ if (!pixels || rect.IsEmpty())
+ return;
+
+ scoped_ptr<PendingAsyncReadPixels> pending_read(new PendingAsyncReadPixels);
+ pending_async_read_pixels_.insert(pending_async_read_pixels_.begin(),
+ pending_read.Pass());
+
+ // This is a syncronous call since the callback is null.
+ DoGetFramebufferPixels(static_cast<uint8*>(pixels),
+ rect,
+ AsyncGetFramebufferPixelsCleanupCallback());
+}
+
+void GLRenderer::GetFramebufferPixelsAsync(gfx::Rect rect,
+ CopyRenderPassCallback callback) {
+ if (callback.is_null())
+ return;
+ if (rect.IsEmpty()) {
+ callback.Run(scoped_ptr<SkBitmap>());
+ return;
+ }
+
+ scoped_ptr<SkBitmap> bitmap(new SkBitmap);
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height());
+ bitmap->allocPixels();
+
+ scoped_ptr<SkAutoLockPixels> lock(new SkAutoLockPixels(*bitmap));
+
+ // Save a pointer to the pixels, the bitmap is owned by the cleanup_callback.
+ uint8* pixels = static_cast<uint8*>(bitmap->getPixels());
+
+ AsyncGetFramebufferPixelsCleanupCallback cleanup_callback = base::Bind(
+ &GLRenderer::PassOnSkBitmap,
+ base::Unretained(this),
+ base::Passed(&bitmap),
+ base::Passed(&lock),
+ callback);
+
+ scoped_ptr<PendingAsyncReadPixels> pending_read(new PendingAsyncReadPixels);
+ pending_read->copy_callback = callback;
+ pending_async_read_pixels_.insert(pending_async_read_pixels_.begin(),
+ pending_read.Pass());
+
+ // This is an asyncronous call since the callback is not null.
+ DoGetFramebufferPixels(pixels, rect, cleanup_callback);
+}
+
+void GLRenderer::DoGetFramebufferPixels(
+ uint8* dest_pixels,
+ gfx::Rect rect,
+ const AsyncGetFramebufferPixelsCleanupCallback& cleanup_callback) {
DCHECK(rect.right() <= ViewportWidth());
DCHECK(rect.bottom() <= ViewportHeight());
- if (!pixels)
- return;
+ bool is_async = !cleanup_callback.is_null();
MakeContextCurrent();
bool do_workaround = NeedsIOSurfaceReadbackWorkaround();
- GLuint temporary_texture = 0;
- GLuint temporary_fbo = 0;
+ unsigned temporary_texture = 0;
+ unsigned temporary_fbo = 0;
if (do_workaround) {
// On Mac OS X, calling glReadPixels() against an FBO whose color attachment
@@ -2048,8 +2110,14 @@ void GLRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) {
GL_FRAMEBUFFER_COMPLETE);
}
- scoped_ptr<uint8_t[]> src_pixels(
- new uint8_t[rect.width() * rect.height() * 4]);
+ unsigned buffer = context_->createBuffer();
+ GLC(context_, context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
+ buffer));
+ GLC(context_, context_->bufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
+ 4 * rect.size().GetArea(),
+ NULL,
+ GL_STREAM_READ));
+
GLC(context_,
context_->readPixels(rect.x(),
ViewportSize().height() - rect.bottom(),
@@ -2057,23 +2125,10 @@ void GLRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) {
rect.height(),
GL_RGBA,
GL_UNSIGNED_BYTE,
- src_pixels.get()));
-
- uint8_t* dest_pixels = static_cast<uint8_t*>(pixels);
- size_t row_bytes = rect.width() * 4;
- int num_rows = rect.height();
- size_t total_bytes = num_rows * row_bytes;
- for (size_t dest_y = 0; dest_y < total_bytes; dest_y += row_bytes) {
- // Flip Y axis.
- size_t src_y = total_bytes - dest_y - row_bytes;
- // Swizzle BGRA -> RGBA.
- for (size_t x = 0; x < row_bytes; x += 4) {
- dest_pixels[dest_y + (x + 0)] = src_pixels.get()[src_y + (x + 2)];
- dest_pixels[dest_y + (x + 1)] = src_pixels.get()[src_y + (x + 1)];
- dest_pixels[dest_y + (x + 2)] = src_pixels.get()[src_y + (x + 0)];
- dest_pixels[dest_y + (x + 3)] = src_pixels.get()[src_y + (x + 3)];
- }
- }
+ NULL));
+
+ GLC(context_, context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
+ 0));
if (do_workaround) {
// Clean up.
@@ -2083,9 +2138,97 @@ void GLRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) {
GLC(context_, context_->deleteTexture(temporary_texture));
}
+ base::Closure finished_callback =
+ base::Bind(&GLRenderer::FinishedReadback,
+ base::Unretained(this),
+ cleanup_callback,
+ buffer,
+ dest_pixels,
+ rect.size());
+ // Save the finished_callback so it can be cancelled.
+ pending_async_read_pixels_.front()->finished_read_pixels_callback.Reset(
+ finished_callback);
+
+ // Save the buffer to verify the callbacks happen in the expected order.
+ pending_async_read_pixels_.front()->buffer = buffer;
+
+ if (is_async) {
+ unsigned sync_point = context_->insertSyncPoint();
+ SyncPointHelper::SignalSyncPoint(
+ context_,
+ sync_point,
+ finished_callback);
+ } else {
+ resource_provider_->Finish();
+ finished_callback.Run();
+ }
+
EnforceMemoryPolicy();
}
+void GLRenderer::FinishedReadback(
+ const AsyncGetFramebufferPixelsCleanupCallback& cleanup_callback,
+ unsigned source_buffer,
+ uint8* dest_pixels,
+ gfx::Size size) {
+ DCHECK(!pending_async_read_pixels_.empty());
+ DCHECK_EQ(source_buffer, pending_async_read_pixels_.back()->buffer);
+
+ uint8* src_pixels = NULL;
+
+ if (source_buffer != 0) {
+ GLC(context_, context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
+ source_buffer));
+ src_pixels = static_cast<uint8*>(
+ context_->mapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
+ GL_READ_ONLY));
+
+ if (src_pixels) {
+ size_t row_bytes = size.width() * 4;
+ int num_rows = size.height();
+ size_t total_bytes = num_rows * row_bytes;
+ for (size_t dest_y = 0; dest_y < total_bytes; dest_y += row_bytes) {
+ // Flip Y axis.
+ size_t src_y = total_bytes - dest_y - row_bytes;
+ // Swizzle BGRA -> RGBA.
+ for (size_t x = 0; x < row_bytes; x += 4) {
+ dest_pixels[dest_y + (x + 0)] = src_pixels[src_y + (x + 2)];
+ dest_pixels[dest_y + (x + 1)] = src_pixels[src_y + (x + 1)];
+ dest_pixels[dest_y + (x + 2)] = src_pixels[src_y + (x + 0)];
+ dest_pixels[dest_y + (x + 3)] = src_pixels[src_y + (x + 3)];
+ }
+ }
+
+ GLC(context_, context_->unmapBufferCHROMIUM(
+ GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM));
+ }
+ GLC(context_, context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
+ 0));
+ GLC(context_, context_->deleteBuffer(source_buffer));
+ }
+
+ // TODO(danakj): This can go away when synchronous readback is no more and its
+ // contents can just move here.
+ if (!cleanup_callback.is_null())
+ cleanup_callback.Run(src_pixels != NULL);
+
+ pending_async_read_pixels_.pop_back();
+}
+
+void GLRenderer::PassOnSkBitmap(
+ scoped_ptr<SkBitmap> bitmap,
+ scoped_ptr<SkAutoLockPixels> lock,
+ const CopyRenderPassCallback& callback,
+ bool success) {
+ DCHECK(callback.Equals(pending_async_read_pixels_.back()->copy_callback));
+
+ lock.reset();
+ if (success)
+ callback.Run(bitmap.Pass());
+ else
+ callback.Run(scoped_ptr<SkBitmap>());
+}
+
bool GLRenderer::GetFramebufferTexture(ScopedResource* texture,
gfx::Rect device_rect) {
DCHECK(!texture->id() || (texture->size() == device_rect.size() &&
« no previous file with comments | « cc/output/gl_renderer.h ('k') | cc/output/software_renderer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698