File: gpu_external_texture.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (210 lines) | stat: -rw-r--r-- 8,267 bytes parent folder | download | duplicates (5)
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_EXTERNAL_TEXTURE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_EXTERNAL_TEXTURE_H_

#include <atomic>

#include "base/task/single_thread_task_runner.h"
#include "media/base/video_frame.h"
#include "third_party/blink/renderer/modules/webgpu/dawn_object.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"

namespace media {
class PaintCanvasVideoRenderer;
}  // namespace media

namespace blink {

class ExceptionState;
class GPUExternalTexture;
class GPUExternalTextureDescriptor;
class WebGPUMailboxTexture;
class HTMLVideoElement;
class VideoFrame;

// GPUExternalTexture uses auto expiry mechanism
// (https://www.w3.org/TR/webgpu/#-automatic-expiry-task-source). The
// mechanism requires webgpu to expire GPUExternalTexture when current task
// scope finished by posting expiration task. The expired GPUExternalTexture
// is invalid to submit and needs to call importExternalTexture() to get the
// refreshed GPUExternalTexture object. In implementation side,
// importExternalTexture() also wraps GPUExternalTexture with underly video
// frames. It is possible that multiple importExternalTexture() call with the
// same source tries to wrap the same underly video frames. So a cache system
// has been integrated to avoid re-creating the GPUExternalTexture again and
// again with the same video frame. So importExternalTexture() tries to do:
// - Search cache to see any hit. if not, create a new GPUExternalTexture and
// insert it into cache.
// - Refresh the external texture to un-expire it.
// - Post a task to expire this external texture after finishing current task.
// More details refers to
// https://www.w3.org/TR/webgpu/#external-texture-creation
class ExternalTextureCache : public GarbageCollected<ExternalTextureCache> {
 public:
  explicit ExternalTextureCache(GPUDevice* device);
  ExternalTextureCache(const ExternalTextureCache&) = delete;
  ExternalTextureCache& operator=(const ExternalTextureCache&) = delete;

  // Implement importExternalTexture() auto expiry mechanism.
  GPUExternalTexture* Import(const GPUExternalTextureDescriptor* descriptor,
                             ExceptionState& exception_state);

  // Destroy all cached GPUExternalTexture and clear all lists.
  void Destroy();

  void Add(HTMLVideoElement* video, GPUExternalTexture* external_texture);
  void Remove(HTMLVideoElement* video);

  void Add(VideoFrame* frame, GPUExternalTexture* external_texture);
  void Remove(VideoFrame* frame);

  void ReferenceUntilGPUIsFinished(
      scoped_refptr<WebGPUMailboxTexture> mailbox_texture);

  void Trace(Visitor* visitor) const;
  GPUDevice* device() const;

 private:
  void ExpireAtEndOfTask(GPUExternalTexture* external_texture);
  void ExpireTask();

  // Keep a list of all active GPUExternalTexture. Eagerly destroy them
  // when the device is destroyed (via .destroy) to free the memory.
  HeapHashMap<WeakMember<HTMLVideoElement>, WeakMember<GPUExternalTexture>>
      from_html_video_element_;
  HeapHashMap<WeakMember<VideoFrame>, WeakMember<GPUExternalTexture>>
      from_video_frame_;

  bool expire_task_scheduled_ = false;
  HeapHashSet<Member<GPUExternalTexture>> expire_set_;

  Member<GPUDevice> device_;
};

class GPUExternalTexture : public DawnObject<wgpu::ExternalTexture> {
  DEFINE_WRAPPERTYPEINFO();

 public:
  static GPUExternalTexture* CreateExpired(
      ExternalTextureCache* cache,
      const GPUExternalTextureDescriptor* webgpu_desc,
      ExceptionState& exception_state);
  static GPUExternalTexture* FromHTMLVideoElement(
      ExternalTextureCache* cache,
      HTMLVideoElement* video,
      const GPUExternalTextureDescriptor* webgpu_desc,
      ExceptionState& exception_state);
  static GPUExternalTexture* FromVideoFrame(
      ExternalTextureCache* cache,
      VideoFrame* frame,
      const GPUExternalTextureDescriptor* webgpu_desc,
      ExceptionState& exception_state);
  explicit GPUExternalTexture(
      ExternalTextureCache* cache,
      wgpu::ExternalTexture external_texture,
      scoped_refptr<WebGPUMailboxTexture> mailbox_texture,
      bool is_zero_copy,
      bool read_lock_fences_enabled,
      std::optional<media::VideoFrame::ID> media_video_frame_unique_id,
      const String& label);

  GPUExternalTexture(const GPUExternalTexture&) = delete;
  GPUExternalTexture& operator=(const GPUExternalTexture&) = delete;

  // gpu_external_texture.idl {{{
  bool isZeroCopy() const;
  // }}} End of WebIDL binding implementation.

  bool IsReadLockFenceEnabled() const;
  void Destroy();
  void Expire();
  void Refresh();

  void SetVideo(HTMLVideoElement* video);

  // Returns true iff the video frame is still available
  bool ListenToVideoFrame(VideoFrame* frame);

  // Check whether current VideoFrame is outdated from HTMLVideoElement. Pure
  // video playback might not trigger any script animation work. Check video
  // frame states in import to ensure cache refresh.
  bool NeedsToUpdate();

  // GPUExternalTexture from VideoFrame expires when VideoFrame is closed. Note
  // that all back resources destroyed needs to happen on the thread that
  // GPUExternalTexture is created.
  // In multithread situation, the callback should change the state of external
  // texture to State::Expired and post a task to issue the destroy.
  void OnVideoFrameClosed();

  void Trace(Visitor* visitor) const override;

 private:
  //                     [1]           [2]
  // Creation -> [Active] --> [Expired] --> [Destroyed]
  //                ^            |
  //                |-------------
  //                     [3]
  //
  // [1] Happens when the current task finishes: the GPUExternalTexture cannot
  // be used util it is refreshed [2] Happens when the source changes frames,
  // the texture can no longer be refreshed. [3] Happens when the texture is
  // refreshed by being re-imported.
  enum class Status { Active, Expired, Destroyed };
  static GPUExternalTexture* CreateImpl(
      ExternalTextureCache* cache,
      const GPUExternalTextureDescriptor* webgpu_desc,
      scoped_refptr<media::VideoFrame> media_video_frame,
      media::PaintCanvasVideoRenderer* video_renderer,
      std::optional<media::VideoFrame::ID> media_video_frame_unique_id,
      ExceptionState& exception_state);

  void SetLabelImpl(const String& value) override {
    std::string utf8_label = value.Utf8();
    GetHandle().SetLabel(utf8_label.c_str());
  }

  bool IsCurrentFrameFromHTMLVideoElementValid();

  // This is the function to push a task to destroy the external texture when
  // the imported video frame in GPUDevice cache is outdated. The function is
  // used as callback function and be registered to the imported
  // Blink::VideoFrame or HTMLVideoElement.
  void OnSourceInvalidated();

  // GPUDevice holds cache for GPUExternalTextures to handling import same
  // frame multiple time cases.
  void RemoveFromCache();

  bool IsActive() const;
  bool IsExpired() const;
  bool IsDestroyed() const;

  scoped_refptr<WebGPUMailboxTexture> mailbox_texture_;
  bool is_zero_copy_ = false;
  bool remove_from_cache_task_scheduled_ = false;

  // read_lock_fences_enabled_ comes from media::VideoFrame metadata.
  // VideoFrame set this metadata as a hint to ensure all previous gpu
  // execution complete before returning video frame to producer.
  bool read_lock_fences_enabled_ = false;

  std::optional<media::VideoFrame::ID> media_video_frame_unique_id_;
  WeakMember<HTMLVideoElement> video_;
  WeakMember<VideoFrame> frame_;
  WeakMember<ExternalTextureCache> cache_;
  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;

  std::atomic<Status> status_ = Status::Active;
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_EXTERNAL_TEXTURE_H_