summaryrefslogtreecommitdiff
path: root/gfx/layers/AsyncCanvasRenderer.h
blob: 404695de4afcbecb8f3e91eb6f64f3a7efb5a7e8 (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
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_
#define MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_

#include "LayersTypes.h"
#include "mozilla/gfx/Point.h"          // for IntSize
#include "mozilla/Mutex.h"
#include "nsCOMPtr.h"                   // for nsCOMPtr

class nsICanvasRenderingContextInternal;
class nsIInputStream;
class nsIThread;

namespace mozilla {

namespace gfx {
class DataSourceSurface;
}

namespace gl {
class GLContext;
}

namespace dom {
class HTMLCanvasElement;
}

namespace layers {

class CanvasClient;
class TextureClient;

/**
 * Since HTMLCanvasElement and OffscreenCanvas are not thread-safe, we create
 * AsyncCanvasRenderer which is thread-safe wrapper object for communicating
 * among main, worker and ImageBridgeChild threads.
 *
 * Each HTMLCanvasElement object is responsible for creating
 * AsyncCanvasRenderer object. Once Canvas is transfered to worker,
 * OffscreenCanvas will keep reference pointer of this object.
 *
 * Sometimes main thread needs AsyncCanvasRenderer's result, such as layers
 * fallback to BasicLayerManager or calling toDataURL in Javascript. Simply call
 * GetSurface() in main thread will readback the result to mSurface.
 *
 * If layers backend is LAYERS_CLIENT, this object will pass to ImageBridgeChild
 * for submitting frames to Compositor.
 */
class AsyncCanvasRenderer final
{
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncCanvasRenderer)

public:
  AsyncCanvasRenderer();

  void NotifyElementAboutAttributesChanged();
  void NotifyElementAboutInvalidation();

  void SetCanvasClient(CanvasClient* aClient);

  void SetWidth(uint32_t aWidth)
  {
    mWidth = aWidth;
  }

  void SetHeight(uint32_t aHeight)
  {
    mHeight = aHeight;
  }

  void SetIsAlphaPremultiplied(bool aIsAlphaPremultiplied)
  {
    mIsAlphaPremultiplied = aIsAlphaPremultiplied;
  }

  // Active thread means the thread which spawns GLContext.
  void SetActiveThread();
  void ResetActiveThread();

  // This will readback surface and return the surface
  // in the DataSourceSurface.
  // Can be called in main thread only.
  already_AddRefed<gfx::DataSourceSurface> GetSurface();

  // For SharedSurface_Basic case, before the frame sending to the compositor,
  // we readback it to a texture client because SharedSurface_Basic cannot shared.
  // We don't want to readback it again here, so just copy the content of that
  // texture client here to avoid readback again.
  void CopyFromTextureClient(TextureClient *aClient);

  // Readback current WebGL's content and convert it to InputStream. This
  // function called GetSurface implicitly and GetSurface handles only get
  // called in the main thread. So this function can be called in main thread.
  nsresult
  GetInputStream(const char *aMimeType,
                 const char16_t *aEncoderOptions,
                 nsIInputStream **aStream);

  gfx::IntSize GetSize() const
  {
    return gfx::IntSize(mWidth, mHeight);
  }

  uint64_t GetCanvasClientAsyncID() const
  {
    return mCanvasClientAsyncID;
  }

  CanvasClient* GetCanvasClient() const
  {
    return mCanvasClient;
  }

  already_AddRefed<nsIThread> GetActiveThread();

  // The lifetime is controllered by HTMLCanvasElement.
  // Only accessed in main thread.
  dom::HTMLCanvasElement* mHTMLCanvasElement;

  // Only accessed in active thread.
  nsICanvasRenderingContextInternal* mContext;

  // We need to keep a reference to the context around here, otherwise the
  // canvas' surface texture destructor will deref and destroy it too early
  // Only accessed in active thread.
  RefPtr<gl::GLContext> mGLContext;
private:

  virtual ~AsyncCanvasRenderer();

  // Readback current WebGL's content and return it as DataSourceSurface.
  already_AddRefed<gfx::DataSourceSurface> UpdateTarget();

  bool mIsAlphaPremultiplied;

  uint32_t mWidth;
  uint32_t mHeight;
  uint64_t mCanvasClientAsyncID;

  // The lifetime of this pointer is controlled by OffscreenCanvas
  // Can be accessed in active thread and ImageBridge thread.
  // But we never accessed it at the same time on both thread. So no
  // need to protect this member.
  CanvasClient* mCanvasClient;

  // When backend is LAYER_BASIC and SharedSurface type is Basic.
  // CanvasClient will readback the GLContext to a TextureClient
  // in order to send frame to compositor. To avoid readback again,
  // we copy from this TextureClient to this mSurfaceForBasic directly
  // by calling CopyFromTextureClient().
  RefPtr<gfx::DataSourceSurface> mSurfaceForBasic;

  // Protect non thread-safe objects.
  Mutex mMutex;

  // Can be accessed in any thread, need protect by mutex.
  nsCOMPtr<nsIThread> mActiveThread;
};

} // namespace layers
} // namespace mozilla

#endif // MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_