summaryrefslogtreecommitdiff
path: root/chromium/components/viz/service/display/gl_renderer_copier.h
blob: 7470b09cc91866e0df9e245737e2657336427d86 (plain)
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
// 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.

#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_COPIER_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_COPIER_H_

#include <stdint.h>

#include <array>
#include <memory>

#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/unguessable_token.h"
#include "components/viz/common/gl_helper.h"
#include "components/viz/service/viz_service_export.h"

namespace gfx {
class ColorSpace;
class Rect;
class Size;
}  // namespace gfx

namespace viz {

class ContextProvider;
class CopyOutputRequest;
class TextureDeleter;

// Helper class for GLRenderer that executes CopyOutputRequests using GL, and
// manages the caching of resources needed to ensure efficient video
// performance.
//
// GLRenderer calls CopyFromTextureOrFramebuffer() to execute a
// CopyOutputRequest. GLRendererCopier will examine the request and determine
// the minimal amount of work needed to satisfy all the requirements of the
// request.
//
// In many cases, interim GL objects (textures, framebuffers, etc.) must be
// created as part of a multi-step process. When considering video performance
// (i.e., a series of CopyOutputRequests from the same "source"), these interim
// objects must be cached to prevent a significant performance penalty on some
// GPU/drivers. GLRendererCopier manages such a cache and automatically frees
// the objects when it detects that a stream of CopyOutputRequests from a given
// "source" has ended.
class VIZ_SERVICE_EXPORT GLRendererCopier {
 public:
  // A callback that calls GLRenderer::MoveFromDrawToWindowSpace().
  using ComputeWindowRectCallback =
      base::RepeatingCallback<gfx::Rect(const gfx::Rect&)>;

  // |texture_deleter| must outlive this instance.
  GLRendererCopier(scoped_refptr<ContextProvider> context_provider,
                   TextureDeleter* texture_deleter,
                   ComputeWindowRectCallback window_rect_callback);

  ~GLRendererCopier();

  // Executes the |request|, copying from the currently-bound framebuffer of the
  // given |internal_format|. |output_rect| is the RenderPass's output Rect in
  // draw space, and is used to translate and clip the result selection Rect.
  // |framebuffer_texture| and |framebuffer_texture_size| are optional: When
  // non-zero, the texture might be used as the source, to avoid making an extra
  // copy of the framebuffer. |flipped_source| is true (common case) if the
  // framebuffer content is vertically flipped. |color_space| specifies the
  // color space of the pixels in the framebuffer.
  //
  // This implementation may change a wide variety of GL state, such as texture
  // and framebuffer bindings, shader programs, and related attributes; and so
  // the caller must not make any assumptions about the state of the GL context
  // after this call.
  void CopyFromTextureOrFramebuffer(std::unique_ptr<CopyOutputRequest> request,
                                    const gfx::Rect& output_rect,
                                    GLenum internal_format,
                                    GLuint framebuffer_texture,
                                    const gfx::Size& framebuffer_texture_size,
                                    bool flipped_source,
                                    const gfx::ColorSpace& color_space);

  // Checks whether cached resources should be freed because recent copy
  // activity is no longer using them. This should be called after a frame has
  // finished drawing (after all copy requests have been executed).
  void FreeUnusedCachedResources();

 private:
  friend class GLRendererCopierTest;

  // The collection of resources that might be cached over multiple copy
  // requests from the same source.
  //
  // TODO(crbug.com/781986): Post-impl clean-up to make this mechanism simpler.
  struct VIZ_SERVICE_EXPORT CacheEntry {
    uint32_t purge_count_at_last_use = 0;
    std::array<GLuint, 8> object_names;
    std::unique_ptr<GLHelper::ScalerInterface> scaler;
    std::unique_ptr<I420Converter> i420_converter;

    // Index in |object_names| of the various objects that might be cached.
    static constexpr int kFramebufferCopyTexture = 0;
    static constexpr int kResultTexture = 1;
    static constexpr int kYPlaneTexture = 2;
    static constexpr int kUPlaneTexture = 3;
    static constexpr int kVPlaneTexture = 4;
    static constexpr int kReadbackFramebuffer = 5;
    static constexpr int kReadbackFramebufferU = 6;
    static constexpr int kReadbackFramebufferV = 7;

    CacheEntry();
    CacheEntry(CacheEntry&&);
    CacheEntry& operator=(CacheEntry&&);
    ~CacheEntry();

   private:
    DISALLOW_COPY_AND_ASSIGN(CacheEntry);
  };

  // Creates a texture and renders a transformed copy of the currently-bound
  // framebuffer, according to the |request| parameters. This includes scaling.
  // The result texture's content is always Y-flipped. The caller owns the
  // returned texture.
  GLuint RenderResultTexture(const CopyOutputRequest& request,
                             const gfx::Rect& framebuffer_copy_rect,
                             GLenum internal_format,
                             GLuint framebuffer_texture,
                             const gfx::Size& framebuffer_texture_size,
                             bool flipped_source,
                             const gfx::Rect& result_rect);

  // Processes the next phase of the copy request by starting readback of the
  // |copy_rect| from the given |source_texture| into a pixel transfer buffer.
  // The source texture is assumed to be Y-flipped. This method does NOT take
  // ownership of the |source_texture|.
  void StartReadbackFromTexture(std::unique_ptr<CopyOutputRequest> request,
                                GLuint source_texture,
                                const gfx::Rect& copy_rect,
                                const gfx::Rect& result_rect,
                                const gfx::ColorSpace& color_space);

  // Processes the next phase of the copy request by starting readback of the
  // |copy_rect| from the currently-bound framebuffer into a pixel transfer
  // buffer. The framebuffer content is assumed to be Y-flipped. This method
  // kicks-off an asynchronous glReadPixels() workflow.
  void StartReadbackFromFramebuffer(std::unique_ptr<CopyOutputRequest> request,
                                    const gfx::Rect& copy_rect,
                                    const gfx::Rect& result_rect,
                                    const gfx::ColorSpace& color_space);

  // Completes a copy request by packaging-up and sending the given
  // |result_texture| in a mailbox. This method takes ownership of
  // |result_texture|.
  void SendTextureResult(std::unique_ptr<CopyOutputRequest> request,
                         GLuint result_texture,
                         const gfx::Rect& result_rect,
                         const gfx::ColorSpace& color_space);

  // Processes the next phase of an I420_PLANES copy request by using the
  // I420Converter to planarize the given |source_texture| and then starting
  // readback of the planes via a pixel transfer buffer. The source texture is
  // assumed to be Y-flipped. This method does NOT take ownership of the
  // |source_texture|.
  void StartI420ReadbackFromTexture(std::unique_ptr<CopyOutputRequest> request,
                                    GLuint source_texture,
                                    const gfx::Size& source_texture_size,
                                    const gfx::Rect& copy_rect,
                                    const gfx::Rect& result_rect,
                                    const gfx::ColorSpace& color_space);

  // Returns the GL object names found in the cache, or creates new ones
  // on-demand. The caller takes ownership of the objects.
  void TakeCachedObjectsOrCreate(const base::UnguessableToken& for_source,
                                 int first,
                                 int count,
                                 GLuint* names);

  // Stashes GL object names into the cache, or deletes the objects if they
  // should not be cached.
  void CacheObjectsOrDelete(const base::UnguessableToken& for_source,
                            int first,
                            int count,
                            const GLuint* names);

  // Returns a cached scaler for the given request, or creates one on-demand.
  std::unique_ptr<GLHelper::ScalerInterface> TakeCachedScalerOrCreate(
      const CopyOutputRequest& for_request,
      bool flipped_source);

  // Stashes a scaler into the cache, or deletes it if it should not be cached.
  void CacheScalerOrDelete(const base::UnguessableToken& for_source,
                           std::unique_ptr<GLHelper::ScalerInterface> scaler);

  // Returns a cached I420 converter for the given source, or creates one
  // on-demand.
  std::unique_ptr<I420Converter> TakeCachedI420ConverterOrCreate(
      const base::UnguessableToken& for_source);

  // Stashes an I420 converter into the cache, or deletes it if it should not be
  // cached.
  void CacheI420ConverterOrDelete(
      const base::UnguessableToken& for_source,
      std::unique_ptr<I420Converter> i420_converter);

  // Frees any objects currently stashed in the given CacheEntry.
  void FreeCachedResources(CacheEntry* entry);

  // Queries the GL implementation to determine which is the more performance-
  // optimal supported readback format: GL_RGBA or GL_BGRA_EXT, and memoizes the
  // result for all future calls.
  //
  // Precondition: The GL context has a complete, bound framebuffer ready for
  // readback.
  GLenum GetOptimalReadbackFormat();

  // Injected dependencies.
  const scoped_refptr<ContextProvider> context_provider_;
  TextureDeleter* const texture_deleter_;
  const ComputeWindowRectCallback window_rect_callback_;

  // Provides comprehensive, quality and efficient scaling and other utilities.
  GLHelper helper_;

  // This increments by one for every call to FreeUnusedCachedResources(). It
  // is meant to determine when cached resources should be freed because they
  // are unlikely to see further use.
  uint32_t purge_counter_ = 0;

  // A cache of resources recently used in the execution of a stream of copy
  // requests from the same source. Since this reflects the number of active
  // video captures, it is expected to almost always be zero or one entry in
  // size.
  base::flat_map<base::UnguessableToken, CacheEntry> cache_;

  // This specifies whether the GPU+driver combination executes readback more
  // efficiently using GL_RGBA or GL_BGRA_EXT format. This starts out as
  // GL_NONE, which means "unknown," and will be determined at the time the
  // first readback request is made.
  GLenum optimal_readback_format_ = static_cast<GLenum>(GL_NONE);

  // Purge cache entries that have not been used after this many calls to
  // FreeUnusedCachedResources(). The choice of 60 is arbitrary, but on most
  // platforms means that a somewhat-to-fully active compositor will cause
  // things to be auto-purged after approx. 1-2 seconds of not being used.
  static constexpr int kKeepalivePeriod = 60;

  DISALLOW_COPY_AND_ASSIGN(GLRendererCopier);
};

}  // namespace viz

#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_COPIER_H_