summaryrefslogtreecommitdiffstats
path: root/cc/output/gl_renderer.cc
diff options
context:
space:
mode:
authordanakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-18 18:24:24 +0000
committerdanakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-18 18:24:24 +0000
commit6389458704504692b4fdf2e5869ff4dbf1b66b5c (patch)
tree25b696fd0597fe55ad7fa2a1c1554007071761c9 /cc/output/gl_renderer.cc
parentcfa8f9d79c87ea20f0162af76acedc2a7e6cb5ab (diff)
downloadchromium_src-6389458704504692b4fdf2e5869ff4dbf1b66b5c.zip
chromium_src-6389458704504692b4fdf2e5869ff4dbf1b66b5c.tar.gz
chromium_src-6389458704504692b4fdf2e5869ff4dbf1b66b5c.tar.bz2
cc: Add ability to request copy of compositor output as a texture.
This adds the ability to request the compositor's output as a texture instead of requiring a readback to a SkBitmap on the cpu. This will allow the embedder to make a request for a texture and then scale or sample it without reading back the entire full-sized texture to the cpu. To readback successive frames will require constant commits at this time, but the mechanism could be extended to allow one main thread request to result in multiple copy result callbacks. This is tested by the LayerTreeHostPixelTestReadback tests. I've added a viewport offset, and surface expansion size, to all of the LayerTreeTest based pixel tests. This exposed a bug in the math for background filters when a viewport offset/surface expansion size is present, so this is fixed as well to make the tests pass (one line in GLRenderer::ApplyBackgroundFilters). Instead of having the CopyOutputRequest return a SkBitmap directly, or return a TextureMailbox directly (sometimes backed by a software bitmap), I've added a CopyOutputResult class to return with a reply from the compositor. This reply may be a texture (via a TextureMailbox) or a bitmap (via an SkBitmap). The embedder should be able to handle either one when it makes a request, unless its request forces a software-bitmap reply. The tests verify GLRenderer+general request, GLRenderer+forced software request, and SoftwareRenderer+general request. Adding the offset/expansion to the viewport/surface causes the offaxis background blur pixel test to become off-by-one in 5 pixels, requiring a rebaseline. R=enne, jamesr, piman BUG=242571 Review URL: https://chromiumcodereview.appspot.com/17018002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207037 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc/output/gl_renderer.cc')
-rw-r--r--cc/output/gl_renderer.cc177
1 files changed, 117 insertions, 60 deletions
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index fb5de4e..2a27ff7 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -21,6 +21,7 @@
#include "cc/output/compositor_frame_metadata.h"
#include "cc/output/context_provider.h"
#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
#include "cc/output/geometry_binding.h"
#include "cc/output/gl_frame_data.h"
#include "cc/output/output_surface.h"
@@ -136,7 +137,8 @@ GLRenderer::GLRenderer(RendererClient* client,
is_scissor_enabled_(false),
highp_threshold_min_(highp_threshold_min),
highp_threshold_cache_(0),
- on_demand_tile_raster_resource_id_(0) {
+ on_demand_tile_raster_resource_id_(0),
+ weak_factory_(this) {
DCHECK(context_);
}
@@ -599,19 +601,29 @@ scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters(
// FIXME: Do a single readback for both the surface and replica and cache the
// filtered results (once filter textures are not reused).
- gfx::Rect device_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
+ gfx::Rect window_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
contents_device_transform, SharedGeometryQuad().BoundingBox()));
int top, right, bottom, left;
filters.getOutsets(top, right, bottom, left);
- device_rect.Inset(-left, -top, -right, -bottom);
+ window_rect.Inset(-left, -top, -right, -bottom);
- device_rect.Intersect(frame->current_render_pass->output_rect);
+ window_rect.Intersect(
+ MoveFromDrawToWindowSpace(frame->current_render_pass->output_rect));
scoped_ptr<ScopedResource> device_background_texture =
ScopedResource::create(resource_provider_);
- if (!GetFramebufferTexture(device_background_texture.get(), device_rect))
+ if (!device_background_texture->Allocate(window_rect.size(),
+ GL_RGB,
+ ResourceProvider::TextureUsageAny)) {
return scoped_ptr<ScopedResource>();
+ } else {
+ ResourceProvider::ScopedWriteLockGL lock(resource_provider_,
+ device_background_texture->id());
+ GetFramebufferTexture(lock.texture_id(),
+ device_background_texture->format(),
+ window_rect);
+ }
SkBitmap filtered_device_background =
ApplyFilters(this, filters, device_background_texture.get());
@@ -658,7 +670,7 @@ scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters(
CopyTextureToFramebuffer(frame,
filtered_device_background_texture_id,
- device_rect,
+ window_rect,
device_to_framebuffer_transform,
flip_vertically);
}
@@ -2135,11 +2147,20 @@ void GLRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) {
pending_read.Pass());
// This is a syncronous call since the callback is null.
+ gfx::Rect window_rect = MoveFromDrawToWindowSpace(rect);
DoGetFramebufferPixels(static_cast<uint8*>(pixels),
- rect,
+ window_rect,
AsyncGetFramebufferPixelsCleanupCallback());
}
+void GLRenderer::DeleteTextureReleaseCallback(unsigned texture_id,
+ unsigned sync_point,
+ bool lost_resource) {
+ if (sync_point)
+ context_->waitSyncPoint(sync_point);
+ context_->deleteTexture(texture_id);
+}
+
void GLRenderer::GetFramebufferPixelsAsync(
gfx::Rect rect, scoped_ptr<CopyOutputRequest> request) {
DCHECK(!request->IsEmpty());
@@ -2148,8 +2169,56 @@ void GLRenderer::GetFramebufferPixelsAsync(
if (rect.IsEmpty())
return;
+ DCHECK(gfx::Rect(current_surface_size_).Contains(rect)) <<
+ "current_surface_size_: " << current_surface_size_.ToString() <<
+ " rect: " << rect.ToString();
+
+ gfx::Rect window_rect = MoveFromDrawToWindowSpace(rect);
+
+ if (!request->force_bitmap_result()) {
+ unsigned int texture_id = context_->createTexture();
+ GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+ GetFramebufferTexture(texture_id, GL_RGBA, window_rect);
+
+ gpu::Mailbox mailbox;
+ unsigned sync_point = 0;
+ GLC(context_, context_->genMailboxCHROMIUM(mailbox.name));
+ if (mailbox.IsZero()) {
+ context_->deleteTexture(texture_id);
+ request->SendResult(CopyOutputResult::CreateEmptyResult());
+ return;
+ }
+
+ GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id));
+ GLC(context_, context_->produceTextureCHROMIUM(
+ GL_TEXTURE_2D, mailbox.name));
+ GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0));
+ sync_point = context_->insertSyncPoint();
+ scoped_ptr<TextureMailbox> texture_mailbox = make_scoped_ptr(
+ new TextureMailbox(mailbox,
+ base::Bind(&GLRenderer::DeleteTextureReleaseCallback,
+ weak_factory_.GetWeakPtr(),
+ texture_id),
+ GL_TEXTURE_2D,
+ sync_point));
+ request->SendTextureResult(window_rect.size(), texture_mailbox.Pass());
+ return;
+ }
+
+ DCHECK(request->force_bitmap_result());
+
scoped_ptr<SkBitmap> bitmap(new SkBitmap);
- bitmap->setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height());
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config,
+ window_rect.width(),
+ window_rect.height());
bitmap->allocPixels();
scoped_ptr<SkAutoLockPixels> lock(new SkAutoLockPixels(*bitmap));
@@ -2169,14 +2238,15 @@ void GLRenderer::GetFramebufferPixelsAsync(
pending_read.Pass());
// This is an asyncronous call since the callback is not null.
- DoGetFramebufferPixels(pixels, rect, cleanup_callback);
+ DoGetFramebufferPixels(pixels, window_rect, cleanup_callback);
}
void GLRenderer::DoGetFramebufferPixels(
uint8* dest_pixels,
- gfx::Rect rect,
+ gfx::Rect window_rect,
const AsyncGetFramebufferPixelsCleanupCallback& cleanup_callback) {
- gfx::Rect window_rect = MoveFromDrawToWindowSpace(rect);
+ DCHECK_GE(window_rect.x(), 0);
+ DCHECK_GE(window_rect.y(), 0);
DCHECK_LE(window_rect.right(), current_surface_size_.width());
DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
@@ -2198,48 +2268,37 @@ void GLRenderer::DoGetFramebufferPixels(
temporary_texture = context_->createTexture();
GLC(context_, context_->bindTexture(GL_TEXTURE_2D, temporary_texture));
- GLC(context_,
- context_->texParameteri(
- GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
- GLC(context_,
- context_->texParameteri(
- GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
- GLC(context_,
- context_->texParameteri(
- GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
- GLC(context_,
- context_->texParameteri(
- GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+ GLC(context_, context_->texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
// Copy the contents of the current (IOSurface-backed) framebuffer into a
// temporary texture.
- GLC(context_,
- context_->copyTexImage2D(GL_TEXTURE_2D,
- 0,
- GL_RGBA,
- 0,
- 0,
- current_surface_size_.width(),
- current_surface_size_.height(),
- 0));
+ GetFramebufferTexture(temporary_texture,
+ GL_RGBA,
+ gfx::Rect(current_surface_size_));
temporary_fbo = context_->createFramebuffer();
// Attach this texture to an FBO, and perform the readback from that FBO.
GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, temporary_fbo));
- GLC(context_,
- context_->framebufferTexture2D(GL_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D,
- temporary_texture,
- 0));
+ GLC(context_, context_->framebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ temporary_texture,
+ 0));
- DCHECK(context_->checkFramebufferStatus(GL_FRAMEBUFFER) ==
- GL_FRAMEBUFFER_COMPLETE);
+ DCHECK_EQ(static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE),
+ context_->checkFramebufferStatus(GL_FRAMEBUFFER));
}
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(),
+ 4 * window_rect.size().GetArea(),
NULL,
GL_STREAM_READ));
@@ -2269,7 +2328,7 @@ void GLRenderer::DoGetFramebufferPixels(
cleanup_callback,
buffer,
dest_pixels,
- rect.size());
+ window_rect.size());
// Save the finished_callback so it can be cancelled.
pending_async_read_pixels_.front()->finished_read_pixels_callback.Reset(
finished_callback);
@@ -2348,35 +2407,33 @@ void GLRenderer::PassOnSkBitmap(
scoped_ptr<SkAutoLockPixels> lock,
scoped_ptr<CopyOutputRequest> request,
bool success) {
- DCHECK(request->HasBitmapRequest());
+ DCHECK(request->force_bitmap_result());
lock.reset();
if (success)
request->SendBitmapResult(bitmap.Pass());
}
-bool GLRenderer::GetFramebufferTexture(ScopedResource* texture,
- gfx::Rect device_rect) {
- DCHECK(!texture->id() || (texture->size() == device_rect.size() &&
- texture->format() == GL_RGB));
-
- if (!texture->id() && !texture->Allocate(device_rect.size(),
- GL_RGB,
- ResourceProvider::TextureUsageAny))
- return false;
+void GLRenderer::GetFramebufferTexture(unsigned texture_id,
+ unsigned texture_format,
+ gfx::Rect window_rect) {
+ DCHECK(texture_id);
+ DCHECK_GE(window_rect.x(), 0);
+ DCHECK_GE(window_rect.y(), 0);
+ DCHECK_LE(window_rect.right(), current_surface_size_.width());
+ DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
- ResourceProvider::ScopedWriteLockGL lock(resource_provider_, texture->id());
- GLC(context_, context_->bindTexture(GL_TEXTURE_2D, lock.texture_id()));
+ GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id));
GLC(context_,
context_->copyTexImage2D(GL_TEXTURE_2D,
0,
- texture->format(),
- device_rect.x(),
- device_rect.y(),
- device_rect.width(),
- device_rect.height(),
+ texture_format,
+ window_rect.x(),
+ window_rect.y(),
+ window_rect.width(),
+ window_rect.height(),
0));
- return true;
+ GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0));
}
bool GLRenderer::UseScopedTexture(DrawingFrame* frame,