1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GL_DELEGATED_INK_POINT_RENDERER_GPU_H_
#define UI_GL_DELEGATED_INK_POINT_RENDERER_GPU_H_
#include <dcomp.h>
#include <wrl/client.h>
#include <optional>
#include <vector>
#include "base/check_is_test.h"
#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "ui/gfx/delegated_ink_metadata.h"
#include "ui/gfx/delegated_ink_point.h"
#include "ui/gfx/geometry/transform_util.h"
#include "ui/gfx/mojom/delegated_ink_point_renderer.mojom.h"
#include "ui/gl/dc_layer_overlay_params.h"
#include "ui/gl/gl_export.h"
namespace gl {
// On construction, this class will create a new visual for the visual tree with
// an IDCompositionDelegatedInk object as the contents. This will be added as
// a child of the root surface visual in the tree, and the trail will be drawn
// to it. It is a child of the root surface visual because this visual contains
// the swapchain, and there will be no transforms applied to the delegated ink
// visual this way.
// For more information about the design of this class and using the OS APIs,
// view the design doc here: https://aka.ms/GPUBackedDesignDoc
class GL_EXPORT DelegatedInkPointRendererGpu
: public gfx::mojom::DelegatedInkPointRenderer {
public:
DelegatedInkPointRendererGpu();
~DelegatedInkPointRendererGpu() override;
struct DelegatedInkPointCompare {
bool operator()(const gfx::DelegatedInkPoint& lhs,
const gfx::DelegatedInkPoint& rhs) const {
return lhs.timestamp() < rhs.timestamp();
}
};
using DelegatedInkPointTokenMap = base::flat_map<gfx::DelegatedInkPoint,
std::optional<unsigned int>,
DelegatedInkPointCompare>;
void InitMessagePipeline(
mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer>
pending_receiver);
bool DelegatedInkIsSupported(
const Microsoft::WRL::ComPtr<IDCompositionDevice2>& dcomp_device) const;
void SetDelegatedInkTrailStartPoint(
std::unique_ptr<gfx::DelegatedInkMetadata> metadata);
void StoreDelegatedInkPoint(const gfx::DelegatedInkPoint& point) override;
void ResetPrediction() override;
gfx::DelegatedInkMetadata* MetadataForTesting() const {
CHECK_IS_TEST();
return metadata_.get();
}
// Creates an overlay for the current frame's Delegated Ink Metadata.
// If the Delegated Ink Renderer can not be initialized, it returns a
// nullptr. The ink trail will synchronize its updates with |root_swap_chain|
// if present, otherwise it will synchronize with DComp commit.
std::optional<DCLayerOverlayParams> MakeDelegatedInkOverlay(
IDCompositionDevice2* dcomp_device2,
IDXGISwapChain1* root_swap_chain,
std::unique_ptr<gfx::DelegatedInkMetadata> metadata);
uint64_t InkTrailTokenCountForTesting() const;
uint64_t DelegatedInkPointPointerIdCountForTesting() const {
CHECK_IS_TEST();
return delegated_ink_points_.size();
}
bool CheckForPointerIdForTesting(int32_t pointer_id) const;
const DelegatedInkPointTokenMap& DelegatedInkPointsForTesting(
int32_t pointer_id) {
CHECK_IS_TEST();
DCHECK(delegated_ink_points_.find(pointer_id) !=
delegated_ink_points_.end());
return delegated_ink_points_[pointer_id];
}
bool WaitForNewTrailToDrawForTesting() const {
CHECK_IS_TEST();
return wait_for_new_trail_to_draw_;
}
std::vector<gfx::DelegatedInkPoint> PointstoBeDrawnForTesting() const {
CHECK_IS_TEST();
return points_to_be_drawn_;
}
uint64_t GetMaximumNumberOfPointerIdsForTesting() const;
void InitializeForTesting(IDCompositionDevice2* dcomp_device2);
// This function is called after Delegated Ink's points are submitted to be
// drawn on screen, and fires a histogram with the time between points' event
// creation and the points' draw submission to the OS.
void ReportPointsDrawn();
private:
bool Initialize(IDCompositionDevice2* dcomp_device2,
IDXGISwapChain1* root_swap_chain);
void EraseExcessPointerIds();
std::optional<int32_t> GetPointerIdForMetadata();
void DrawSavedTrailPoints();
bool DrawDelegatedInkPoint(const gfx::DelegatedInkPoint& point);
// The delegated ink trail object that the ink trail is drawn on. This is the
// content of the ink visual.
Microsoft::WRL::ComPtr<IDCompositionDelegatedInkTrail> delegated_ink_trail_;
// The swap chain whose updates |delegated_ink_trail_| is synchronized with.
// If null, |delegated_ink_trail_| is synchronized with DComp commit.
raw_ptr<IDXGISwapChain1> swap_chain_ = nullptr;
Microsoft::WRL::ComPtr<IDCompositionInkTrailDevice> ink_trail_device_;
// The most recent metadata received. The metadata marks the last point of
// the app rendered stroke, which corresponds to the first point of the
// delegated ink trail that will be drawn.
std::unique_ptr<gfx::DelegatedInkMetadata> metadata_;
// A base::flat_map of all the points that have arrived in
// StoreDelegatedInkPoint() with a timestamp greater than or equal to that of
// |metadata_|, where the key is the DelegatedInkPoint that was received, and
// the value is an optional token. The value will be null until the
// DelegatedInkPoint is added to the trail, at which point the value is the
// token that was returned by AddTrailPoints. The elements of the flat_map are
// sorted by the timestamp of the DelegatedInkPoint. All points are stored in
// here until we receive a |metadata_|, then any DelegatedInkPoints that have
// a timestamp earlier than |metadata_|'s are removed, and any new
// DelegatedInkPoints that may arrive with an earlier timestamp are ignored.
// Then as each new |metadata| arrives in SetDelegatedInkTrailStartPoint(),
// we remove any old elements with earlier timestamps, up to and including the
// element that matches the DelegatedInkMetadata.
base::flat_map<int32_t, DelegatedInkPointTokenMap> delegated_ink_points_;
// Cached pointer id of the most recently drawn trail.
std::optional<int32_t> pointer_id_;
// Flag to know if new DelegatedInkPoints that arrive should be drawn
// immediately or if they should wait for a new trail to be started. Set to
// true when ResetPrediction is called, as this tells us that something about
// the pointerevents in the browser process changed. When that happens, we
// should continue to remove points for any metadata that arrive with
// timestamps that match DelegatedInkPoints that arrived before the
// ResetPrediction call. However, once a metadata arrives with a timestamp
// after the ResetPrediction, then we know that inking should continue, so a
// new trail is started and we try to draw everything in
// |delegated_ink_points_|.
bool wait_for_new_trail_to_draw_ = true;
// Set to true when DelegatedInkPointRendererGPU has been (re)initialized.
// This can happen due to the first metadata being received, or change in
// root surface swap chain or DirectCompositionDevice.
bool force_new_ink_trail_ = false;
mojo::Receiver<gfx::mojom::DelegatedInkPointRenderer> receiver_{this};
// Holds the timestamp of points added to the Delegated Ink's Trail to measure
// the time between point creation and draw operation called.
std::vector<gfx::DelegatedInkPoint> points_to_be_drawn_;
// The timestamp in which a Delegated Ink point that matches the metadata was
// first painted.
std::optional<base::TimeTicks> metadata_paint_time_;
};
} // namespace gl
#endif // UI_GL_DELEGATED_INK_POINT_RENDERER_GPU_H_
|