Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include "TexturePoolOGL.h"
6 : #include <stdlib.h> // for malloc
7 : #include "GLContext.h" // for GLContext
8 : #include "mozilla/Logging.h"
9 : #include "mozilla/Monitor.h" // for Monitor, MonitorAutoLock
10 : #include "mozilla/mozalloc.h" // for operator delete, etc
11 : #include "mozilla/layers/CompositorThread.h"
12 : #include "nsDebug.h" // for NS_ASSERTION, NS_ERROR, etc
13 : #include "nsDeque.h" // for nsDeque
14 : #include "nsThreadUtils.h"
15 :
16 : #ifdef MOZ_WIDGET_ANDROID
17 : #include "GeneratedJNINatives.h"
18 : #endif
19 :
20 : static const unsigned int TEXTURE_POOL_SIZE = 10;
21 : static const unsigned int TEXTURE_REFILL_THRESHOLD = TEXTURE_POOL_SIZE / 2;
22 :
23 : static mozilla::LazyLogModule gTexturePoolLog("TexturePoolOGL");
24 : #define LOG(arg, ...) MOZ_LOG(gTexturePoolLog, mozilla::LogLevel::Debug, ("TexturePoolOGL::%s: " arg, __func__, ##__VA_ARGS__))
25 :
26 : namespace mozilla {
27 : namespace gl {
28 :
29 : static GLContext* sActiveContext = nullptr;
30 :
31 : static Monitor* sMonitor = nullptr;
32 : static nsDeque* sTextures = nullptr;
33 :
34 : enum class PoolState : uint8_t {
35 : NOT_INITIALIZE,
36 : INITIALIZED,
37 : SHUTDOWN
38 : };
39 : static PoolState sPoolState = PoolState::NOT_INITIALIZE;
40 :
41 : static bool sHasPendingFillTask = false;
42 :
43 : #ifdef MOZ_WIDGET_ANDROID
44 :
45 : class GeckoSurfaceTextureSupport final
46 : : public java::GeckoSurfaceTexture::Natives<GeckoSurfaceTextureSupport>
47 : {
48 : public:
49 : static int32_t NativeAcquireTexture() {
50 : return TexturePoolOGL::AcquireTexture();
51 : }
52 : };
53 :
54 : #endif // MOZ_WIDGET_ANDROID
55 :
56 0 : void TexturePoolOGL::MaybeFillTextures()
57 : {
58 0 : if (sTextures->GetSize() < TEXTURE_REFILL_THRESHOLD &&
59 0 : !sHasPendingFillTask) {
60 0 : LOG("need to refill the texture pool.");
61 0 : sHasPendingFillTask = true;
62 0 : MessageLoop* loop = mozilla::layers::CompositorThreadHolder::Loop();
63 0 : MOZ_ASSERT(loop);
64 0 : loop->PostTask(
65 0 : NS_NewRunnableFunction(
66 : "TexturePoolOGL::MaybeFillTextures",
67 0 : [] () {
68 0 : TexturePoolOGL::Fill(sActiveContext);
69 0 : }));
70 : }
71 0 : }
72 :
73 0 : GLuint TexturePoolOGL::AcquireTexture()
74 : {
75 0 : MOZ_ASSERT(sPoolState != PoolState::NOT_INITIALIZE, "not initialized");
76 0 : MOZ_ASSERT(sPoolState != PoolState::SHUTDOWN, "should not be called after shutdown");
77 :
78 0 : MonitorAutoLock lock(*sMonitor);
79 :
80 0 : if (!sActiveContext) {
81 : // Wait for a context
82 0 : sMonitor->Wait();
83 :
84 0 : if (!sActiveContext)
85 0 : return 0;
86 : }
87 :
88 0 : GLuint texture = 0;
89 0 : if (sActiveContext->IsOwningThreadCurrent()) {
90 0 : sActiveContext->MakeCurrent();
91 :
92 0 : sActiveContext->fGenTextures(1, &texture);
93 : } else {
94 0 : while (sTextures->GetSize() == 0) {
95 0 : NS_WARNING("Waiting for texture");
96 0 : sMonitor->Wait();
97 : }
98 :
99 0 : GLuint* popped = (GLuint*) sTextures->Pop();
100 0 : if (!popped) {
101 0 : NS_ERROR("Failed to pop texture pool item");
102 0 : return 0;
103 : }
104 :
105 0 : texture = *popped;
106 : delete popped;
107 :
108 0 : NS_ASSERTION(texture, "Failed to retrieve texture from pool");
109 :
110 0 : MaybeFillTextures();
111 0 : LOG("remaining textures num = %zu", sTextures->GetSize());
112 : }
113 :
114 0 : return texture;
115 : }
116 :
117 0 : static void Clear()
118 : {
119 0 : const bool isCurrent = sActiveContext && sActiveContext->MakeCurrent();
120 :
121 : GLuint* item;
122 0 : while (sTextures->GetSize()) {
123 0 : item = (GLuint*)sTextures->Pop();
124 0 : if (isCurrent) {
125 0 : sActiveContext->fDeleteTextures(1, item);
126 : }
127 : delete item;
128 : }
129 0 : }
130 :
131 0 : void TexturePoolOGL::Fill(GLContext* aContext)
132 : {
133 0 : MOZ_ASSERT(aContext, "NULL GLContext");
134 0 : MOZ_ASSERT(sPoolState != PoolState::NOT_INITIALIZE, "not initialized");
135 0 : MOZ_ASSERT(sPoolState != PoolState::SHUTDOWN, "should not be called after shutdown");
136 :
137 0 : MonitorAutoLock lock(*sMonitor);
138 0 : sHasPendingFillTask = false;
139 :
140 0 : if (sActiveContext != aContext) {
141 0 : Clear();
142 0 : sActiveContext = aContext;
143 : }
144 :
145 0 : if (sTextures->GetSize() == TEXTURE_POOL_SIZE)
146 0 : return;
147 :
148 0 : DebugOnly<bool> ok = sActiveContext->MakeCurrent();
149 0 : MOZ_ASSERT(ok);
150 :
151 0 : GLuint* texture = nullptr;
152 0 : while (sTextures->GetSize() < TEXTURE_POOL_SIZE) {
153 0 : texture = (GLuint*)malloc(sizeof(GLuint));
154 0 : sActiveContext->fGenTextures(1, texture);
155 0 : sTextures->Push((void*) texture);
156 : }
157 :
158 0 : LOG("fill texture pool to %d", TEXTURE_POOL_SIZE);
159 0 : sMonitor->NotifyAll();
160 : }
161 :
162 0 : GLContext* TexturePoolOGL::GetGLContext()
163 : {
164 0 : return sActiveContext;
165 : }
166 :
167 0 : void TexturePoolOGL::Init()
168 : {
169 0 : MOZ_ASSERT(sPoolState != PoolState::INITIALIZED);
170 0 : sMonitor = new Monitor("TexturePoolOGL.sMonitor");
171 0 : sTextures = new nsDeque();
172 :
173 : #ifdef MOZ_WIDGET_ANDROID
174 : if (jni::IsAvailable()) {
175 : GeckoSurfaceTextureSupport::Init();
176 : }
177 : #endif
178 0 : sPoolState = PoolState::INITIALIZED;
179 0 : }
180 :
181 0 : void TexturePoolOGL::Shutdown()
182 : {
183 0 : MOZ_ASSERT(sPoolState == PoolState::INITIALIZED);
184 0 : sPoolState = PoolState::SHUTDOWN;
185 0 : delete sMonitor;
186 0 : delete sTextures;
187 0 : }
188 :
189 : } // namespace gl
190 : } // namespace mozilla
|