blob: 217bf3a2f7f62d6ccf7e23d3f7b9a51821eaef55 [file] [log] [blame]
// Copyright 2017 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 "components/viz/service/display_embedder/software_output_device_mac.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/skia_util.h"
namespace viz {
namespace {
TEST(SoftwareOutputDeviceMacTest, Basics) {
auto device = std::make_unique<SoftwareOutputDeviceMac>(
base::SequencedTaskRunnerHandle::Get());
gfx::Size pixel_size(512, 512);
float scale_factor = 1;
EXPECT_EQ(device->BufferQueueSizeForTesting(), 0u);
device->Resize(pixel_size, scale_factor);
// Frame 0.
gfx::Rect damage0(pixel_size);
device->BeginPaint(damage0);
IOSurfaceRef io_surface0 = device->CurrentPaintIOSurfaceForTesting();
device->EndPaint();
// Frame 1.
// We didn't set the IOSurface in use, so it should be re-used, and we should
// have no copy.
gfx::Rect damage1(10, 10, 10, 10);
device->BeginPaint(damage1);
IOSurfaceRef io_surface1 = device->CurrentPaintIOSurfaceForTesting();
device->EndPaint();
EXPECT_EQ(io_surface0, io_surface1);
EXPECT_EQ(device->BufferQueueSizeForTesting(), 1u);
EXPECT_TRUE(device->LastCopyRegionForTesting().isEmpty());
// Frame 2.
// The IOSurface is in use, so we should allocate a new one. We'll do a full
// copy because it's a new buffer.
IOSurfaceIncrementUseCount(io_surface1);
gfx::Rect damage2(20, 20, 10, 10);
device->BeginPaint(damage2);
IOSurfaceRef io_surface2 = device->CurrentPaintIOSurfaceForTesting();
device->EndPaint();
EXPECT_NE(io_surface1, io_surface2);
EXPECT_EQ(device->BufferQueueSizeForTesting(), 2u);
SkRegion copy_region2(gfx::RectToSkIRect(gfx::Rect(pixel_size)));
copy_region2.op(gfx::RectToSkIRect(damage2), SkRegion::kDifference_Op);
EXPECT_EQ(device->LastCopyRegionForTesting(), copy_region2);
// Frame 3.
// Both IOSurfaces are in use, so we'll allocate yet a new one and do another
// full copy.
IOSurfaceIncrementUseCount(io_surface2);
gfx::Rect damage3(30, 30, 10, 10);
device->BeginPaint(damage3);
IOSurfaceRef io_surface3 = device->CurrentPaintIOSurfaceForTesting();
device->EndPaint();
EXPECT_NE(io_surface1, io_surface3);
EXPECT_NE(io_surface2, io_surface3);
EXPECT_EQ(device->BufferQueueSizeForTesting(), 3u);
SkRegion copy_region3(gfx::RectToSkIRect(gfx::Rect(pixel_size)));
copy_region3.op(gfx::RectToSkIRect(damage3), SkRegion::kDifference_Op);
EXPECT_EQ(device->LastCopyRegionForTesting(), copy_region3);
// Frame 4.
// The IOSurface from frame1 is free, so we should re-use it. We should be
// copying the damage from frame2 and frame3.
IOSurfaceIncrementUseCount(io_surface3);
IOSurfaceDecrementUseCount(io_surface1);
gfx::Rect damage4(35, 35, 15, 15);
device->BeginPaint(damage4);
IOSurfaceRef io_surface4 = device->CurrentPaintIOSurfaceForTesting();
device->EndPaint();
EXPECT_EQ(io_surface1, io_surface4);
EXPECT_EQ(device->BufferQueueSizeForTesting(), 3u);
SkRegion copy_region4;
copy_region4.op(gfx::RectToSkIRect(damage2), SkRegion::kUnion_Op);
copy_region4.op(gfx::RectToSkIRect(damage3), SkRegion::kUnion_Op);
copy_region4.op(gfx::RectToSkIRect(damage4), SkRegion::kDifference_Op);
EXPECT_EQ(device->LastCopyRegionForTesting(), copy_region4);
// Frame 5.
// All IOSurfaces are allocated, allocate another.
IOSurfaceIncrementUseCount(io_surface4);
gfx::Rect damage5(50, 50, 10, 10);
device->BeginPaint(damage5);
IOSurfaceRef io_surface5 = device->CurrentPaintIOSurfaceForTesting();
EXPECT_NE(io_surface5, io_surface2);
EXPECT_NE(io_surface5, io_surface3);
EXPECT_NE(io_surface5, io_surface4);
device->EndPaint();
EXPECT_EQ(device->BufferQueueSizeForTesting(), 4u);
// Frame 6.
// All IOSurfaces are in use, allocate another, but free the one from frame2
// (add an extra retain and check to retain count to verify that it steps
// down).
IOSurfaceIncrementUseCount(io_surface5);
CFRetain(io_surface2);
EXPECT_EQ(CFGetRetainCount(io_surface2), 2u);
gfx::Rect damage6(60, 60, 10, 10);
device->BeginPaint(damage6);
IOSurfaceRef io_surface6 = device->CurrentPaintIOSurfaceForTesting();
device->EndPaint();
EXPECT_EQ(device->BufferQueueSizeForTesting(), 4u);
EXPECT_NE(io_surface6, io_surface2);
EXPECT_NE(io_surface6, io_surface3);
EXPECT_NE(io_surface6, io_surface4);
EXPECT_NE(io_surface6, io_surface5);
EXPECT_EQ(CFGetRetainCount(io_surface2), 1u);
CFRelease(io_surface2);
}
} // namespace
} // namespace viz