// Copyright 2015 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 "cc/layers/content_layer_client.h" #include "cc/layers/picture_layer.h" #include "cc/output/copy_output_request.h" #include "cc/playback/display_item_list.h" #include "cc/playback/drawing_display_item.h" #include "cc/test/layer_tree_pixel_test.h" #include "cc/test/test_gpu_memory_buffer_manager.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPictureRecorder.h" #if !defined(OS_ANDROID) namespace cc { namespace { enum RasterMode { PARTIAL_ONE_COPY, FULL_ONE_COPY, GPU, BITMAP, }; class LayerTreeHostTilesPixelTest : public LayerTreePixelTest { protected: void InitializeSettings(LayerTreeSettings* settings) override { LayerTreePixelTest::InitializeSettings(settings); settings->use_display_lists = true; switch (raster_mode_) { case PARTIAL_ONE_COPY: settings->use_one_copy = true; settings->use_zero_copy = false; settings->use_persistent_map_for_gpu_memory_buffers = true; break; case FULL_ONE_COPY: settings->use_one_copy = true; settings->use_zero_copy = false; settings->use_persistent_map_for_gpu_memory_buffers = false; break; case BITMAP: // This is done via context creation. No settings to change here! break; case GPU: settings->gpu_rasterization_enabled = true; settings->gpu_rasterization_forced = true; break; } } void BeginTest() override { // Don't set up a readback target at the start of the test. PostSetNeedsCommitToMainThread(); } void DoReadback() { Layer* target = readback_target_ ? readback_target_ : layer_tree_host()->root_layer(); target->RequestCopyOfOutput(CreateCopyOutputRequest()); } void RunRasterPixelTest(bool threaded, RasterMode mode, scoped_refptr content_root, base::FilePath file_name) { raster_mode_ = mode; PixelTestType test_type = PIXEL_TEST_SOFTWARE; switch (mode) { case PARTIAL_ONE_COPY: case FULL_ONE_COPY: case GPU: test_type = PIXEL_TEST_GL; break; case BITMAP: test_type = PIXEL_TEST_SOFTWARE; } if (threaded) RunPixelTest(test_type, content_root, file_name); else RunSingleThreadedPixelTest(test_type, content_root, file_name); } base::FilePath ref_file_; scoped_ptr result_bitmap_; RasterMode raster_mode_; }; class BlueYellowClient : public ContentLayerClient { public: explicit BlueYellowClient(const gfx::Size& size) : size_(size), blue_top_(true) {} void PaintContents(SkCanvas* canvas, const gfx::Rect& clip, PaintingControlSetting painting_status) override {} scoped_refptr PaintContentsToDisplayList( const gfx::Rect& clip, PaintingControlSetting painting_status) override { bool use_cached_picture = false; scoped_refptr display_list = DisplayItemList::Create(clip, use_cached_picture); SkPictureRecorder recorder; skia::RefPtr canvas = skia::SharePtr( recorder.beginRecording(gfx::RectToSkRect(gfx::Rect(size_)))); gfx::Rect top(0, 0, size_.width(), size_.height() / 2); gfx::Rect bottom(0, size_.height() / 2, size_.width(), size_.height() / 2); gfx::Rect blue_rect = blue_top_ ? top : bottom; gfx::Rect yellow_rect = blue_top_ ? bottom : top; SkPaint paint; paint.setStyle(SkPaint::kFill_Style); paint.setColor(SK_ColorBLUE); canvas->drawRect(gfx::RectToSkRect(blue_rect), paint); paint.setColor(SK_ColorYELLOW); canvas->drawRect(gfx::RectToSkRect(yellow_rect), paint); skia::RefPtr picture = skia::AdoptRef(recorder.endRecordingAsPicture()); auto* item = display_list->CreateAndAppendItem(); item->SetNew(picture.Pass()); display_list->Finalize(); return display_list; } bool FillsBoundsCompletely() const override { return true; } void set_blue_top(bool b) { blue_top_ = b; } private: gfx::Size size_; bool blue_top_; }; class LayerTreeHostTilesTestPartialInvalidation : public LayerTreeHostTilesPixelTest { public: LayerTreeHostTilesTestPartialInvalidation() : client_(gfx::Size(200, 200)), picture_layer_(PictureLayer::Create(layer_settings(), &client_)) { picture_layer_->SetBounds(gfx::Size(200, 200)); picture_layer_->SetIsDrawable(true); } void DidCommitAndDrawFrame() override { switch (layer_tree_host()->source_frame_number()) { case 1: // We have done one frame, so the layer's content has been rastered. // Now we change the picture behind it to record something completely // different, but we give a smaller invalidation rect. The layer should // only re-raster the stuff in the rect. If it doesn't do partial raster // it would re-raster the whole thing instead. client_.set_blue_top(false); picture_layer_->SetNeedsDisplayRect(gfx::Rect(50, 50, 100, 100)); // Add a copy request to see what happened! DoReadback(); break; } } protected: BlueYellowClient client_; scoped_refptr picture_layer_; }; TEST_F(LayerTreeHostTilesTestPartialInvalidation, PartialRaster_SingleThread_OneCopy) { RunRasterPixelTest( false, PARTIAL_ONE_COPY, picture_layer_, base::FilePath(FILE_PATH_LITERAL("blue_yellow_partial_flipped.png"))); } TEST_F(LayerTreeHostTilesTestPartialInvalidation, FullRaster_SingleThread_OneCopy) { RunRasterPixelTest( false, FULL_ONE_COPY, picture_layer_, base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped.png"))); } TEST_F(LayerTreeHostTilesTestPartialInvalidation, FullRaster_MultiThread_OneCopy) { RunRasterPixelTest( true, FULL_ONE_COPY, picture_layer_, base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped.png"))); } TEST_F(LayerTreeHostTilesTestPartialInvalidation, PartialRaster_SingleThread_Software) { RunRasterPixelTest( false, BITMAP, picture_layer_, base::FilePath(FILE_PATH_LITERAL("blue_yellow_partial_flipped.png"))); } TEST_F(LayerTreeHostTilesTestPartialInvalidation, PartialRaster_SingleThread_GpuRaster) { RunRasterPixelTest( false, GPU, picture_layer_, base::FilePath(FILE_PATH_LITERAL("blue_yellow_partial_flipped.png"))); } } // namespace } // namespace cc #endif // !defined(OS_ANDROID)