diff options
author | danakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-18 18:24:24 +0000 |
---|---|---|
committer | danakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-18 18:24:24 +0000 |
commit | 6389458704504692b4fdf2e5869ff4dbf1b66b5c (patch) | |
tree | 25b696fd0597fe55ad7fa2a1c1554007071761c9 /cc/test/layer_tree_pixel_test.cc | |
parent | cfa8f9d79c87ea20f0162af76acedc2a7e6cb5ab (diff) | |
download | chromium_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/test/layer_tree_pixel_test.cc')
-rw-r--r-- | cc/test/layer_tree_pixel_test.cc | 152 |
1 files changed, 128 insertions, 24 deletions
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc index 3c67e54..3d757ca 100644 --- a/cc/test/layer_tree_pixel_test.cc +++ b/cc/test/layer_tree_pixel_test.cc @@ -6,8 +6,12 @@ #include "base/path_service.h" #include "cc/output/copy_output_request.h" +#include "cc/output/copy_output_result.h" +#include "cc/resources/texture_mailbox.h" #include "cc/test/paths.h" #include "cc/test/pixel_comparator.h" +#include "cc/test/pixel_test_output_surface.h" +#include "cc/test/pixel_test_software_output_device.h" #include "cc/test/pixel_test_utils.h" #include "cc/trees/layer_tree_impl.h" #include "ui/gl/gl_implementation.h" @@ -17,19 +21,37 @@ namespace cc { LayerTreePixelTest::LayerTreePixelTest() - : pixel_comparator_(new ExactPixelComparator(true)) {} + : pixel_comparator_(new ExactPixelComparator(true)), use_gl_(true) {} LayerTreePixelTest::~LayerTreePixelTest() {} scoped_ptr<OutputSurface> LayerTreePixelTest::CreateOutputSurface() { - CHECK(gfx::InitializeGLBindings(gfx::kGLImplementationOSMesaGL)); - - using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl; - scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d( - WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext( - WebKit::WebGraphicsContext3D::Attributes())); - return make_scoped_ptr( - new OutputSurface(context3d.PassAs<WebKit::WebGraphicsContext3D>())); + gfx::Vector2d viewport_offset(20, 10); + gfx::Size surface_expansion_size(40, 60); + scoped_ptr<PixelTestOutputSurface> output_surface; + + if (!use_gl_) { + scoped_ptr<PixelTestSoftwareOutputDevice> software_output_device( + new PixelTestSoftwareOutputDevice); + software_output_device->set_surface_expansion_size(surface_expansion_size); + output_surface = make_scoped_ptr( + new PixelTestOutputSurface( + software_output_device.PassAs<SoftwareOutputDevice>())); + } else { + CHECK(gfx::InitializeGLBindings(gfx::kGLImplementationOSMesaGL)); + + using WebKit::WebGraphicsContext3D; + using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl; + scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d( + WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext( + WebGraphicsContext3D::Attributes())); + output_surface = make_scoped_ptr( + new PixelTestOutputSurface(context3d.PassAs<WebGraphicsContext3D>())); + } + + output_surface->set_viewport_offset(viewport_offset); + output_surface->set_surface_expansion_size(surface_expansion_size); + return output_surface.PassAs<OutputSurface>(); } scoped_refptr<cc::ContextProvider> @@ -48,31 +70,36 @@ LayerTreePixelTest::OffscreenContextProviderForCompositorThread() { return provider; } -void LayerTreePixelTest::ReadbackResult(scoped_ptr<SkBitmap> bitmap) { - ASSERT_TRUE(bitmap); - - base::FilePath test_data_dir; - EXPECT_TRUE(PathService::Get(cc::DIR_TEST_DATA, &test_data_dir)); - - // To rebaseline: - // EXPECT_TRUE(WritePNGFile(*bitmap, test_data_dir.Append(ref_file_), true)); +scoped_ptr<CopyOutputRequest> LayerTreePixelTest::CreateCopyOutputRequest() { + return CopyOutputRequest::CreateBitmapRequest( + base::Bind(&LayerTreePixelTest::ReadbackResult, base::Unretained(this))); +} - EXPECT_TRUE(MatchesPNGFile(*bitmap, - test_data_dir.Append(ref_file_), - *pixel_comparator_)); +void LayerTreePixelTest::ReadbackResult(scoped_ptr<CopyOutputResult> result) { + ASSERT_TRUE(result->HasBitmap()); + result_bitmap_ = result->TakeBitmap().Pass(); EndTest(); } void LayerTreePixelTest::BeginTest() { Layer* target = readback_target_ ? readback_target_ : layer_tree_host()->root_layer(); - target->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( - base::Bind(&LayerTreePixelTest::ReadbackResult, - base::Unretained(this)))); + target->RequestCopyOfOutput(CreateCopyOutputRequest().Pass()); PostSetNeedsCommitToMainThread(); } -void LayerTreePixelTest::AfterTest() {} +void LayerTreePixelTest::AfterTest() { + base::FilePath test_data_dir; + EXPECT_TRUE(PathService::Get(cc::DIR_TEST_DATA, &test_data_dir)); + base::FilePath ref_file_path = test_data_dir.Append(ref_file_); + + // To rebaseline: + // EXPECT_TRUE(WritePNGFile(*result_bitmap_, ref_file_path, true)); + + EXPECT_TRUE(MatchesPNGFile(*result_bitmap_, + ref_file_path, + *pixel_comparator_)); +} scoped_refptr<SolidColorLayer> LayerTreePixelTest::CreateSolidColorLayer( gfx::Rect rect, SkColor color) { @@ -140,4 +167,81 @@ void LayerTreePixelTest::SetupTree() { LayerTreeTest::SetupTree(); } +scoped_ptr<SkBitmap> LayerTreePixelTest::CopyTextureMailboxToBitmap( + gfx::Size size, + const TextureMailbox& texture_mailbox) { + DCHECK(texture_mailbox.IsTexture()); + if (!texture_mailbox.IsTexture()) + return scoped_ptr<SkBitmap>(); + + using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl; + scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d( + WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext( + WebKit::WebGraphicsContext3D::Attributes())); + + EXPECT_TRUE(context3d->makeContextCurrent()); + + if (texture_mailbox.sync_point()) + context3d->waitSyncPoint(texture_mailbox.sync_point()); + + unsigned texture_id = context3d->createTexture(); + context3d->bindTexture(GL_TEXTURE_2D, texture_id); + context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + context3d->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + context3d->texParameteri( + GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + context3d->texParameteri( + GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + context3d->consumeTextureCHROMIUM(texture_mailbox.target(), + texture_mailbox.data()); + context3d->bindTexture(GL_TEXTURE_2D, 0); + + unsigned fbo = context3d->createFramebuffer(); + context3d->bindFramebuffer(GL_FRAMEBUFFER, fbo); + context3d->framebufferTexture2D(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + texture_id, + 0); + EXPECT_EQ(static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE), + context3d->checkFramebufferStatus(GL_FRAMEBUFFER)); + + scoped_ptr<uint8[]> pixels(new uint8[size.GetArea() * 4]); + context3d->readPixels(0, + 0, + size.width(), + size.height(), + GL_RGBA, + GL_UNSIGNED_BYTE, + pixels.get()); + + context3d->deleteFramebuffer(fbo); + context3d->deleteTexture(texture_id); + + scoped_ptr<SkBitmap> bitmap(new SkBitmap); + bitmap->setConfig(SkBitmap::kARGB_8888_Config, + size.width(), + size.height()); + bitmap->allocPixels(); + + scoped_ptr<SkAutoLockPixels> lock(new SkAutoLockPixels(*bitmap)); + uint8* out_pixels = static_cast<uint8*>(bitmap->getPixels()); + + size_t row_bytes = size.width() * 4; + size_t total_bytes = size.height() * 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 OpenGL -> Skia byte order. + for (size_t x = 0; x < row_bytes; x += 4) { + out_pixels[dest_y + x + SK_R32_SHIFT/8] = pixels.get()[src_y + x + 0]; + out_pixels[dest_y + x + SK_G32_SHIFT/8] = pixels.get()[src_y + x + 1]; + out_pixels[dest_y + x + SK_B32_SHIFT/8] = pixels.get()[src_y + x + 2]; + out_pixels[dest_y + x + SK_A32_SHIFT/8] = pixels.get()[src_y + x + 3]; + } + } + + return bitmap.Pass(); +} + } // namespace cc |