#include "ash/fast_ink/fast_ink_host_frame_utils.h"
#include <memory>
#include <tuple>
#include <utility>
#include <vector>
#include "ash/frame_sink/ui_resource.h"
#include "ash/frame_sink/ui_resource_manager.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/ash_test_helper.h"
#include "base/memory/raw_ptr.h"
#include "cc/base/math_util.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/resources/resource_id.h"
#include "components/viz/common/resources/shared_image_format_utils.h"
#include "gpu/command_buffer/client/client_shared_image.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/shared_image_capabilities.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/display/display_switches.h"
#include "ui/display/screen.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/transform.h"
namespace ash {
namespace {
constexpr auto kTestContentRectInDIP = gfx::Rect(0, 0, 200, 100);
constexpr auto kTestTotalDamageRectInDIP = gfx::Rect(0, 0, 50, 25);
class FastInkHostCreateFrameUtilTest : public AshTestBase {
public:
FastInkHostCreateFrameUtilTest() = default;
FastInkHostCreateFrameUtilTest(const FastInkHostCreateFrameUtilTest&) =
delete;
FastInkHostCreateFrameUtilTest& operator=(
const FastInkHostCreateFrameUtilTest&) = delete;
~FastInkHostCreateFrameUtilTest() override = default;
void SetUp() override {
AshTestBase::SetUp();
UpdateDisplay("1000x500*2");
auto* root_window = ash_test_helper()->GetHost()->window();
gfx::Rect screen_bounds = root_window->GetBoundsInScreen();
auto host_window =
CreateTestWindow(screen_bounds, aura::client::WINDOW_TYPE_NORMAL,
kShellWindowId_OverlayContainer);
host_window_ = host_window.release();
gfx::Size buffer_size = BufferSizeForHostWindow(host_window_.get());
gpu::SharedImageUsageSet usage =
gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
gpu::SHARED_IMAGE_USAGE_CONCURRENT_READ_WRITE;
if (shared_image_interface()
->GetCapabilities()
.supports_scanout_shared_images) {
usage |= gpu::SHARED_IMAGE_USAGE_SCANOUT;
}
shared_image_ = fast_ink_internal::CreateMappableSharedImage(
buffer_size, usage, gfx::BufferUsage::SCANOUT_CPU_READ_WRITE);
ASSERT_TRUE(shared_image_);
}
void TearDown() override {
shared_image_.reset();
resource_manager_.ClearAvailableResources();
resource_manager_.LostExportedResources();
AshTestBase::TearDown();
}
protected:
const gfx::Size BufferSizeForHostWindow(aura::Window* host_window) {
const gfx::Transform& window_to_buffer_transform =
host_window->GetHost()->GetRootTransform();
gfx::Rect bounds(host_window->GetBoundsInScreen().size());
return cc::MathUtil::MapEnclosingClippedRect(window_to_buffer_transform,
bounds)
.size();
}
gpu::SharedImageInterface* shared_image_interface() {
return fast_ink_internal::GetContextProvider()->SharedImageInterface();
}
UiResourceManager resource_manager_;
raw_ptr<aura::Window, DanglingUntriaged> host_window_;
scoped_refptr<gpu::ClientSharedImage> shared_image_;
};
TEST_F(FastInkHostCreateFrameUtilTest, HasValidSourceId) {
auto frame = fast_ink_internal::CreateCompositorFrame(
viz::BeginFrameAck::CreateManualAckWithDamage(), kTestContentRectInDIP,
kTestTotalDamageRectInDIP, true, *host_window_,
&resource_manager_, shared_image_, gpu::SyncToken());
ASSERT_EQ(frame->resource_list.size(), 1u);
viz::ResourceId resource_id = frame->resource_list.back().id;
EXPECT_NE(resource_manager_.PeekExportedResource(resource_id)->ui_source_id,
kInvalidUiSourceId);
}
TEST_F(FastInkHostCreateFrameUtilTest, ResourceUsesMailbox) {
auto frame = fast_ink_internal::CreateCompositorFrame(
viz::BeginFrameAck::CreateManualAckWithDamage(), kTestContentRectInDIP,
kTestTotalDamageRectInDIP, true, *host_window_,
&resource_manager_, shared_image_, gpu::SyncToken());
ASSERT_EQ(frame->resource_list.size(), 1u);
viz::ResourceId resource_id = frame->resource_list.back().id;
auto* resource = resource_manager_.PeekExportedResource(resource_id);
EXPECT_NE(resource->ui_source_id, kInvalidUiSourceId);
EXPECT_EQ(resource->client_shared_image(), shared_image_);
}
TEST_F(FastInkHostCreateFrameUtilTest, CompositorFrameHasCorrectStructure) {
auto frame = fast_ink_internal::CreateCompositorFrame(
viz::BeginFrameAck::CreateManualAckWithDamage(), kTestContentRectInDIP,
kTestTotalDamageRectInDIP, true, *host_window_,
&resource_manager_, shared_image_, gpu::SyncToken());
auto primary_display = display::Screen::Get()->GetPrimaryDisplay();
ASSERT_EQ(frame->render_pass_list.size(), 1u);
EXPECT_EQ(frame->size_in_pixels(), gfx::Size(1000, 404));
EXPECT_EQ(frame->resource_list.size(), 1u);
EXPECT_EQ(resource_manager_.exported_resources_count(), 1u);
auto& render_pass = frame->render_pass_list.front();
EXPECT_EQ(render_pass->quad_list.size(), 1u);
EXPECT_EQ(render_pass->shared_quad_state_list.size(), 1u);
EXPECT_EQ(frame->device_scale_factor(),
primary_display.device_scale_factor());
}
TEST_F(FastInkHostCreateFrameUtilTest, FrameDamage_AutoModeOff) {
auto frame = fast_ink_internal::CreateCompositorFrame(
viz::BeginFrameAck::CreateManualAckWithDamage(), kTestContentRectInDIP,
kTestTotalDamageRectInDIP, false, *host_window_,
&resource_manager_, shared_image_, gpu::SyncToken());
EXPECT_EQ(frame->render_pass_list.front()->damage_rect,
gfx::Rect(0, 0, 100, 50));
frame = fast_ink_internal::CreateCompositorFrame(
viz::BeginFrameAck::CreateManualAckWithDamage(), kTestContentRectInDIP,
gfx::Rect(0, 0, 501, 100), false, *host_window_,
&resource_manager_, shared_image_, gpu::SyncToken());
EXPECT_EQ(frame->render_pass_list.front()->damage_rect,
gfx::Rect(0, 0, 1000, 200));
}
TEST_F(FastInkHostCreateFrameUtilTest, FrameDamage_AutoModeOn) {
auto frame = fast_ink_internal::CreateCompositorFrame(
viz::BeginFrameAck::CreateManualAckWithDamage(), kTestContentRectInDIP,
kTestTotalDamageRectInDIP, true, *host_window_,
&resource_manager_, shared_image_, gpu::SyncToken());
EXPECT_EQ(frame->render_pass_list.front()->damage_rect,
gfx::Rect(frame->size_in_pixels()));
}
TEST_F(FastInkHostCreateFrameUtilTest, OnlyCreateNewResourcesWhenNecessary) {
for (int i = 0; i < 2; i++) {
resource_manager_.OfferResourceForTesting(
fast_ink_internal::CreateUiResource(
fast_ink_internal::kFastInkUiSourceId,
false, shared_image_, gpu::SyncToken()));
}
constexpr gfx::Size kResourceSizes[2] = {{250, 150}, {50, 25}};
for (const auto& size : kResourceSizes) {
auto shared_image = fast_ink_internal::CreateMappableSharedImage(
size, shared_image_->usage(), gfx::BufferUsage::SCANOUT_CPU_READ_WRITE);
resource_manager_.OfferResourceForTesting(
fast_ink_internal::CreateUiResource(
fast_ink_internal::kFastInkUiSourceId,
false, shared_image, gpu::SyncToken()));
}
EXPECT_EQ(resource_manager_.available_resources_count(), 4u);
auto frame = fast_ink_internal::CreateCompositorFrame(
viz::BeginFrameAck::CreateManualAckWithDamage(), kTestContentRectInDIP,
kTestTotalDamageRectInDIP, true, *host_window_,
&resource_manager_, shared_image_, gpu::SyncToken());
EXPECT_EQ(resource_manager_.available_resources_count(), 3u);
EXPECT_EQ(resource_manager_.exported_resources_count(), 1u);
frame = fast_ink_internal::CreateCompositorFrame(
viz::BeginFrameAck::CreateManualAckWithDamage(), kTestContentRectInDIP,
kTestTotalDamageRectInDIP, true, *host_window_,
&resource_manager_, shared_image_, gpu::SyncToken());
EXPECT_EQ(resource_manager_.available_resources_count(), 2u);
EXPECT_EQ(resource_manager_.exported_resources_count(), 2u);
frame = fast_ink_internal::CreateCompositorFrame(
viz::BeginFrameAck::CreateManualAckWithDamage(), kTestContentRectInDIP,
kTestTotalDamageRectInDIP, true, *host_window_,
&resource_manager_, shared_image_, gpu::SyncToken());
EXPECT_EQ(resource_manager_.available_resources_count(), 2u);
EXPECT_EQ(resource_manager_.exported_resources_count(), 3u);
}
}
}