#include "ash/fast_ink/fast_ink_host_frame_utils.h"
#include "ash/frame_sink/frame_sink_host.h"
#include "ash/frame_sink/ui_resource.h"
#include "base/check.h"
#include "base/logging.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 "gpu/command_buffer/client/client_shared_image.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "ui/aura/env.h"
#include "ui/aura/window_tree_host.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/transform.h"
namespace ash {
namespace fast_ink_internal {
namespace {
std::unique_ptr<UiResource> AcquireUiResource(
bool is_overlay_candidate,
UiResourceManager* resource_manager,
const scoped_refptr<gpu::ClientSharedImage>& shared_image,
gpu::SyncToken sync_token) {
CHECK(shared_image);
std::unique_ptr<UiResource> resource = resource_manager->GetResourceToReuse(
shared_image->size(), kFastInkSharedImageFormat, kFastInkUiSourceId);
if (resource) {
CHECK(shared_image == resource->client_shared_image());
} else {
resource = CreateUiResource(kFastInkUiSourceId, is_overlay_candidate,
shared_image, sync_token);
}
return resource;
}
void AppendQuad(const viz::TransferableResource& resource,
const gfx::Rect& output_rect,
const gfx::Rect& quad_rect,
const gfx::Size& buffer_size,
const gfx::Transform& buffer_to_target_transform,
viz::CompositorRenderPass& render_pass_out) {
viz::SharedQuadState* quad_state =
render_pass_out.CreateAndAppendSharedQuadState();
quad_state->SetAll(buffer_to_target_transform,
output_rect,
output_rect,
gfx::MaskFilterInfo(),
std::nullopt, false,
1.f,
SkBlendMode::kSrcOver,
0,
0u, false);
viz::TextureDrawQuad* texture_quad =
render_pass_out.CreateAndAppendDrawQuad<viz::TextureDrawQuad>();
gfx::RectF uv_crop(quad_rect);
uv_crop.Scale(1.f / buffer_size.width(), 1.f / buffer_size.height());
texture_quad->SetNew(quad_state, quad_rect, quad_rect,
true, resource.id, uv_crop.origin(),
uv_crop.bottom_right(), SkColors::kTransparent,
false,
false,
gfx::ProtectedVideoType::kClear);
}
}
gfx::Rect BufferRectFromWindowRect(
const gfx::Transform& window_to_buffer_transform,
const gfx::Size& buffer_size,
const gfx::Rect& window_rect) {
gfx::Rect buffer_rect = cc::MathUtil::MapEnclosingClippedRect(
window_to_buffer_transform, window_rect);
buffer_rect.Intersect(gfx::Rect(buffer_size));
return buffer_rect;
}
scoped_refptr<gpu::ClientSharedImage> CreateMappableSharedImage(
const gfx::Size& size,
gpu::SharedImageUsageSet shared_image_usage,
gfx::BufferUsage buffer_usage) {
return GetContextProvider()->SharedImageInterface()->CreateSharedImage(
{kFastInkSharedImageFormat, size, gfx::ColorSpace(), shared_image_usage,
"FastInkHostUIResource"},
gpu::kNullSurfaceHandle, buffer_usage);
}
std::unique_ptr<UiResource> CreateUiResource(
UiSourceId ui_source_id,
bool is_overlay_candidate,
const scoped_refptr<gpu::ClientSharedImage>& shared_image,
gpu::SyncToken sync_token) {
DCHECK(ui_source_id > 0);
CHECK(shared_image);
auto context_provider = GetContextProvider();
if (!context_provider) {
LOG(ERROR) << "Failed to acquire a context provider";
return nullptr;
}
auto resource = std::make_unique<UiResource>(
context_provider->SharedImageInterface(), shared_image);
resource->sync_token = sync_token;
resource->damaged = true;
resource->is_overlay_candidate = is_overlay_candidate;
resource->ui_source_id = ui_source_id;
return resource;
}
std::unique_ptr<viz::CompositorFrame> CreateCompositorFrame(
const viz::BeginFrameAck& begin_frame_ack,
const gfx::Rect& content_rect,
const gfx::Rect& total_damage_rect,
bool auto_update,
const aura::Window& host_window,
UiResourceManager* resource_manager,
const scoped_refptr<gpu::ClientSharedImage>& shared_image,
gpu::SyncToken sync_token) {
float device_scale_factor = host_window.layer()->device_scale_factor();
const gfx::Transform& window_to_buffer_transform =
host_window.GetHost()->GetRootTransform();
gfx::Size window_size_in_dip = host_window.GetBoundsInScreen().size();
const gfx::Size window_size_in_pixel =
gfx::ScaleToEnclosingRectIgnoringError(gfx::Rect{window_size_in_dip},
device_scale_factor)
.size();
CHECK(shared_image);
auto resource = AcquireUiResource(auto_update, resource_manager, shared_image,
sync_token);
if (!resource) {
return nullptr;
}
if (resource->damaged) {
resource->shared_image_interface->UpdateSharedImage(
resource->sync_token, resource->client_shared_image()->mailbox());
resource->sync_token =
resource->shared_image_interface->GenVerifiedSyncToken();
resource->damaged = false;
}
viz::TransferableResource transferable_resource =
resource_manager->OfferAndPrepareResourceForExport(std::move(resource));
gfx::Transform target_to_buffer_transform(window_to_buffer_transform);
target_to_buffer_transform.Scale(1.f / device_scale_factor,
1.f / device_scale_factor);
gfx::Transform buffer_to_target_transform =
target_to_buffer_transform.GetCheckedInverse();
const gfx::Rect output_rect(window_size_in_pixel);
gfx::Rect quad_rect;
gfx::Rect damage_rect;
const gfx::Size buffer_size = shared_image->size();
if (auto_update) {
quad_rect = gfx::Rect(buffer_size);
damage_rect = gfx::Rect(output_rect);
} else {
quad_rect = BufferRectFromWindowRect(window_to_buffer_transform,
buffer_size, content_rect);
damage_rect = gfx::ToEnclosingRect(
gfx::ConvertRectToPixels(total_damage_rect, device_scale_factor));
damage_rect.Intersect(output_rect);
}
auto frame = std::make_unique<viz::CompositorFrame>();
frame->metadata.begin_frame_ack = begin_frame_ack;
frame->metadata.begin_frame_ack.has_damage = true;
frame->metadata.device_scale_factor = device_scale_factor;
auto render_pass = viz::CompositorRenderPass::Create(
1, 1);
render_pass->SetNew(viz::CompositorRenderPassId{1}, output_rect, damage_rect,
buffer_to_target_transform);
AppendQuad(transferable_resource, output_rect, quad_rect, buffer_size,
buffer_to_target_transform, *render_pass);
frame->resource_list.push_back(std::move(transferable_resource));
frame->render_pass_list.push_back(std::move(render_pass));
return frame;
}
scoped_refptr<viz::RasterContextProvider> GetContextProvider() {
return aura::Env::GetInstance()
->context_factory()
->SharedMainThreadRasterContextProvider();
}
}
}