/src/mozilla-central/gfx/layers/opengl/TextureHostOGL.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "TextureHostOGL.h" |
8 | | |
9 | | #include "EGLUtils.h" |
10 | | #include "GLContext.h" // for GLContext, etc |
11 | | #include "GLLibraryEGL.h" // for GLLibraryEGL |
12 | | #include "GLUploadHelpers.h" |
13 | | #include "GLReadTexImageHelper.h" |
14 | | #include "gfx2DGlue.h" // for ContentForFormat, etc |
15 | | #include "mozilla/gfx/2D.h" // for DataSourceSurface |
16 | | #include "mozilla/gfx/BaseSize.h" // for BaseSize |
17 | | #include "mozilla/gfx/Logging.h" // for gfxCriticalError |
18 | | #include "mozilla/layers/ISurfaceAllocator.h" |
19 | | #include "nsRegion.h" // for nsIntRegion |
20 | | #include "AndroidSurfaceTexture.h" |
21 | | #include "GfxTexturesReporter.h" // for GfxTexturesReporter |
22 | | #include "GLBlitTextureImageHelper.h" |
23 | | #include "GeckoProfiler.h" |
24 | | |
25 | | #ifdef XP_MACOSX |
26 | | #include "mozilla/layers/MacIOSurfaceTextureHostOGL.h" |
27 | | #endif |
28 | | |
29 | | using namespace mozilla::gl; |
30 | | using namespace mozilla::gfx; |
31 | | |
32 | | namespace mozilla { |
33 | | namespace layers { |
34 | | |
35 | | class Compositor; |
36 | | |
37 | | already_AddRefed<TextureHost> |
38 | | CreateTextureHostOGL(const SurfaceDescriptor& aDesc, |
39 | | ISurfaceAllocator* aDeallocator, |
40 | | LayersBackend aBackend, |
41 | | TextureFlags aFlags) |
42 | 0 | { |
43 | 0 | RefPtr<TextureHost> result; |
44 | 0 | switch (aDesc.type()) { |
45 | | #ifdef MOZ_WIDGET_ANDROID |
46 | | case SurfaceDescriptor::TSurfaceTextureDescriptor: { |
47 | | const SurfaceTextureDescriptor& desc = aDesc.get_SurfaceTextureDescriptor(); |
48 | | java::GeckoSurfaceTexture::LocalRef surfaceTexture = java::GeckoSurfaceTexture::Lookup(desc.handle()); |
49 | | |
50 | | result = new SurfaceTextureHost(aFlags, |
51 | | surfaceTexture, |
52 | | desc.size(), |
53 | | desc.format(), |
54 | | desc.continuous(), |
55 | | desc.ignoreTransform()); |
56 | | break; |
57 | | } |
58 | | #endif |
59 | |
|
60 | 0 | case SurfaceDescriptor::TEGLImageDescriptor: { |
61 | 0 | const EGLImageDescriptor& desc = aDesc.get_EGLImageDescriptor(); |
62 | 0 | result = new EGLImageTextureHost(aFlags, |
63 | 0 | (EGLImage)desc.image(), |
64 | 0 | (EGLSync)desc.fence(), |
65 | 0 | desc.size(), |
66 | 0 | desc.hasAlpha()); |
67 | 0 | break; |
68 | 0 | } |
69 | 0 |
|
70 | | #ifdef XP_MACOSX |
71 | | case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: { |
72 | | const SurfaceDescriptorMacIOSurface& desc = |
73 | | aDesc.get_SurfaceDescriptorMacIOSurface(); |
74 | | result = new MacIOSurfaceTextureHostOGL(aFlags, desc); |
75 | | break; |
76 | | } |
77 | | #endif |
78 | |
|
79 | 0 | case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture: { |
80 | 0 | const auto& desc = aDesc.get_SurfaceDescriptorSharedGLTexture(); |
81 | 0 | result = new GLTextureHost(aFlags, desc.texture(), |
82 | 0 | desc.target(), |
83 | 0 | (GLsync)desc.fence(), |
84 | 0 | desc.size(), |
85 | 0 | desc.hasAlpha()); |
86 | 0 | break; |
87 | 0 | } |
88 | 0 | default: { |
89 | 0 | MOZ_ASSERT_UNREACHABLE("Unsupported SurfaceDescriptor type"); |
90 | 0 | break; |
91 | 0 | } |
92 | 0 | } |
93 | 0 | return result.forget(); |
94 | 0 | } |
95 | | |
96 | | static gl::TextureImage::Flags |
97 | | FlagsToGLFlags(TextureFlags aFlags) |
98 | 0 | { |
99 | 0 | uint32_t result = TextureImage::NoFlags; |
100 | 0 |
|
101 | 0 | if (aFlags & TextureFlags::USE_NEAREST_FILTER) |
102 | 0 | result |= TextureImage::UseNearestFilter; |
103 | 0 | if (aFlags & TextureFlags::ORIGIN_BOTTOM_LEFT) |
104 | 0 | result |= TextureImage::OriginBottomLeft; |
105 | 0 | if (aFlags & TextureFlags::DISALLOW_BIGIMAGE) |
106 | 0 | result |= TextureImage::DisallowBigImage; |
107 | 0 |
|
108 | 0 | return static_cast<gl::TextureImage::Flags>(result); |
109 | 0 | } |
110 | | |
111 | | bool |
112 | | TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface, |
113 | | nsIntRegion* aDestRegion, |
114 | | gfx::IntPoint* aSrcOffset) |
115 | 0 | { |
116 | 0 | GLContext *gl = mGL; |
117 | 0 | MOZ_ASSERT(gl); |
118 | 0 | if (!gl || !gl->MakeCurrent()) { |
119 | 0 | NS_WARNING("trying to update TextureImageTextureSourceOGL without a GLContext"); |
120 | 0 | return false; |
121 | 0 | } |
122 | 0 | if (!aSurface) { |
123 | 0 | gfxCriticalError() << "Invalid surface for OGL update"; |
124 | 0 | return false; |
125 | 0 | } |
126 | 0 | MOZ_ASSERT(aSurface); |
127 | 0 |
|
128 | 0 | IntSize size = aSurface->GetSize(); |
129 | 0 | if (!mTexImage || |
130 | 0 | (mTexImage->GetSize() != size && !aSrcOffset) || |
131 | 0 | mTexImage->GetContentType() != gfx::ContentForFormat(aSurface->GetFormat())) { |
132 | 0 | if (mFlags & TextureFlags::DISALLOW_BIGIMAGE) { |
133 | 0 | GLint maxTextureSize; |
134 | 0 | gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTextureSize); |
135 | 0 | if (size.width > maxTextureSize || size.height > maxTextureSize) { |
136 | 0 | NS_WARNING("Texture exceeds maximum texture size, refusing upload"); |
137 | 0 | return false; |
138 | 0 | } |
139 | 0 | // Explicitly use CreateBasicTextureImage instead of CreateTextureImage, |
140 | 0 | // because CreateTextureImage might still choose to create a tiled |
141 | 0 | // texture image. |
142 | 0 | mTexImage = CreateBasicTextureImage(gl, size, |
143 | 0 | gfx::ContentForFormat(aSurface->GetFormat()), |
144 | 0 | LOCAL_GL_CLAMP_TO_EDGE, |
145 | 0 | FlagsToGLFlags(mFlags)); |
146 | 0 | } else { |
147 | 0 | // XXX - clarify which size we want to use. IncrementalContentHost will |
148 | 0 | // require the size of the destination surface to be different from |
149 | 0 | // the size of aSurface. |
150 | 0 | // See bug 893300 (tracks the implementation of ContentHost for new textures). |
151 | 0 | mTexImage = CreateTextureImage(gl, |
152 | 0 | size, |
153 | 0 | gfx::ContentForFormat(aSurface->GetFormat()), |
154 | 0 | LOCAL_GL_CLAMP_TO_EDGE, |
155 | 0 | FlagsToGLFlags(mFlags), |
156 | 0 | SurfaceFormatToImageFormat(aSurface->GetFormat())); |
157 | 0 | } |
158 | 0 | ClearCachedFilter(); |
159 | 0 |
|
160 | 0 | if (aDestRegion && |
161 | 0 | !aSrcOffset && |
162 | 0 | !aDestRegion->IsEqual(gfx::IntRect(0, 0, size.width, size.height))) { |
163 | 0 | // UpdateFromDataSource will ignore our specified aDestRegion since the texture |
164 | 0 | // hasn't been allocated with glTexImage2D yet. Call Resize() to force the |
165 | 0 | // allocation (full size, but no upload), and then we'll only upload the pixels |
166 | 0 | // we care about below. |
167 | 0 | mTexImage->Resize(size); |
168 | 0 | } |
169 | 0 | } |
170 | 0 |
|
171 | 0 | return mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset); |
172 | 0 | } |
173 | | |
174 | | void |
175 | | TextureImageTextureSourceOGL::EnsureBuffer(const IntSize& aSize, |
176 | | gfxContentType aContentType) |
177 | 0 | { |
178 | 0 | if (!mTexImage || |
179 | 0 | mTexImage->GetSize() != aSize || |
180 | 0 | mTexImage->GetContentType() != aContentType) { |
181 | 0 | mTexImage = CreateTextureImage(mGL, |
182 | 0 | aSize, |
183 | 0 | aContentType, |
184 | 0 | LOCAL_GL_CLAMP_TO_EDGE, |
185 | 0 | FlagsToGLFlags(mFlags)); |
186 | 0 | } |
187 | 0 | mTexImage->Resize(aSize); |
188 | 0 | } |
189 | | |
190 | | void |
191 | | TextureImageTextureSourceOGL::SetTextureSourceProvider(TextureSourceProvider* aProvider) |
192 | 0 | { |
193 | 0 | GLContext* newGL = aProvider ? aProvider->GetGLContext() : nullptr; |
194 | 0 | if (!newGL || mGL != newGL) { |
195 | 0 | DeallocateDeviceData(); |
196 | 0 | } |
197 | 0 | mGL = newGL; |
198 | 0 | } |
199 | | |
200 | | gfx::IntSize |
201 | | TextureImageTextureSourceOGL::GetSize() const |
202 | 0 | { |
203 | 0 | if (mTexImage) { |
204 | 0 | if (mIterating) { |
205 | 0 | return mTexImage->GetTileRect().Size(); |
206 | 0 | } |
207 | 0 | return mTexImage->GetSize(); |
208 | 0 | } |
209 | 0 | NS_WARNING("Trying to query the size of an empty TextureSource."); |
210 | 0 | return gfx::IntSize(0, 0); |
211 | 0 | } |
212 | | |
213 | | gfx::SurfaceFormat |
214 | | TextureImageTextureSourceOGL::GetFormat() const |
215 | 0 | { |
216 | 0 | if (mTexImage) { |
217 | 0 | return mTexImage->GetTextureFormat(); |
218 | 0 | } |
219 | 0 | NS_WARNING("Trying to query the format of an empty TextureSource."); |
220 | 0 | return gfx::SurfaceFormat::UNKNOWN; |
221 | 0 | } |
222 | | |
223 | | gfx::IntRect TextureImageTextureSourceOGL::GetTileRect() |
224 | 0 | { |
225 | 0 | return mTexImage->GetTileRect(); |
226 | 0 | } |
227 | | |
228 | | void |
229 | | TextureImageTextureSourceOGL::BindTexture(GLenum aTextureUnit, |
230 | | gfx::SamplingFilter aSamplingFilter) |
231 | 0 | { |
232 | 0 | MOZ_ASSERT(mTexImage, |
233 | 0 | "Trying to bind a TextureSource that does not have an underlying GL texture."); |
234 | 0 | mTexImage->BindTexture(aTextureUnit); |
235 | 0 | SetSamplingFilter(mGL, aSamplingFilter); |
236 | 0 | } |
237 | | |
238 | | //////////////////////////////////////////////////////////////////////// |
239 | | // GLTextureSource |
240 | | |
241 | | GLTextureSource::GLTextureSource(TextureSourceProvider* aProvider, |
242 | | GLuint aTextureHandle, |
243 | | GLenum aTarget, |
244 | | gfx::IntSize aSize, |
245 | | gfx::SurfaceFormat aFormat) |
246 | | : mGL(aProvider->GetGLContext()) |
247 | | , mTextureHandle(aTextureHandle) |
248 | | , mTextureTarget(aTarget) |
249 | | , mSize(aSize) |
250 | | , mFormat(aFormat) |
251 | 0 | { |
252 | 0 | MOZ_COUNT_CTOR(GLTextureSource); |
253 | 0 | } |
254 | | |
255 | | GLTextureSource::~GLTextureSource() |
256 | 0 | { |
257 | 0 | MOZ_COUNT_DTOR(GLTextureSource); |
258 | 0 | DeleteTextureHandle(); |
259 | 0 | } |
260 | | |
261 | | void |
262 | | GLTextureSource::DeallocateDeviceData() |
263 | 0 | { |
264 | 0 | DeleteTextureHandle(); |
265 | 0 | } |
266 | | |
267 | | void |
268 | | GLTextureSource::DeleteTextureHandle() |
269 | 0 | { |
270 | 0 | GLContext* gl = this->gl(); |
271 | 0 | if (mTextureHandle != 0 && gl && gl->MakeCurrent()) { |
272 | 0 | gl->fDeleteTextures(1, &mTextureHandle); |
273 | 0 | } |
274 | 0 | mTextureHandle = 0; |
275 | 0 | } |
276 | | |
277 | | void |
278 | | GLTextureSource::BindTexture(GLenum aTextureUnit, |
279 | | gfx::SamplingFilter aSamplingFilter) |
280 | 0 | { |
281 | 0 | MOZ_ASSERT(mTextureHandle != 0); |
282 | 0 | GLContext* gl = this->gl(); |
283 | 0 | if (!gl || !gl->MakeCurrent()) { |
284 | 0 | return; |
285 | 0 | } |
286 | 0 | gl->fActiveTexture(aTextureUnit); |
287 | 0 | gl->fBindTexture(mTextureTarget, mTextureHandle); |
288 | 0 | ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget); |
289 | 0 | } |
290 | | |
291 | | void |
292 | | GLTextureSource::SetTextureSourceProvider(TextureSourceProvider* aProvider) |
293 | 0 | { |
294 | 0 | GLContext* newGL = aProvider ? aProvider->GetGLContext() : nullptr; |
295 | 0 | if (!newGL) { |
296 | 0 | mGL = newGL; |
297 | 0 | } else if (mGL != newGL) { |
298 | 0 | gfxCriticalError() << "GLTextureSource does not support changing compositors"; |
299 | 0 | } |
300 | 0 |
|
301 | 0 | if (mNextSibling) { |
302 | 0 | mNextSibling->SetTextureSourceProvider(aProvider); |
303 | 0 | } |
304 | 0 | } |
305 | | |
306 | | bool |
307 | | GLTextureSource::IsValid() const |
308 | 0 | { |
309 | 0 | return !!gl() && mTextureHandle != 0; |
310 | 0 | } |
311 | | |
312 | | //////////////////////////////////////////////////////////////////////// |
313 | | // DirectMapTextureSource |
314 | | |
315 | | DirectMapTextureSource::DirectMapTextureSource(TextureSourceProvider* aProvider, |
316 | | gfx::DataSourceSurface* aSurface) |
317 | | : GLTextureSource(aProvider, |
318 | | 0, |
319 | | LOCAL_GL_TEXTURE_RECTANGLE_ARB, |
320 | | aSurface->GetSize(), |
321 | | aSurface->GetFormat()) |
322 | 0 | { |
323 | 0 | MOZ_ASSERT(aSurface); |
324 | 0 |
|
325 | 0 | UpdateInternal(aSurface, nullptr, nullptr, true); |
326 | 0 | } |
327 | | |
328 | | bool |
329 | | DirectMapTextureSource::Update(gfx::DataSourceSurface* aSurface, |
330 | | nsIntRegion* aDestRegion, |
331 | | gfx::IntPoint* aSrcOffset) |
332 | 0 | { |
333 | 0 | if (!aSurface) { |
334 | 0 | return false; |
335 | 0 | } |
336 | 0 | |
337 | 0 | return UpdateInternal(aSurface, aDestRegion, aSrcOffset, false); |
338 | 0 | } |
339 | | |
340 | | bool |
341 | | DirectMapTextureSource::Sync(bool aBlocking) |
342 | 0 | { |
343 | 0 | if (!gl() || !gl()->MakeCurrent()) { |
344 | 0 | // We use this function to decide whether we can unlock the texture |
345 | 0 | // and clean it up. If we return false here and for whatever reason |
346 | 0 | // the context is absent or invalid, the compositor will keep a |
347 | 0 | // reference to this texture forever. |
348 | 0 | return true; |
349 | 0 | } |
350 | 0 | |
351 | 0 | if (!gl()->IsDestroyed()) { |
352 | 0 | if (aBlocking) { |
353 | 0 | gl()->fFinishObjectAPPLE(LOCAL_GL_TEXTURE, mTextureHandle); |
354 | 0 | } else { |
355 | 0 | return gl()->fTestObjectAPPLE(LOCAL_GL_TEXTURE, mTextureHandle); |
356 | 0 | } |
357 | 0 | } |
358 | 0 | return true; |
359 | 0 | } |
360 | | |
361 | | bool |
362 | | DirectMapTextureSource::UpdateInternal(gfx::DataSourceSurface* aSurface, |
363 | | nsIntRegion* aDestRegion, |
364 | | gfx::IntPoint* aSrcOffset, |
365 | | bool aInit) |
366 | 0 | { |
367 | 0 | if (!gl() || !gl()->MakeCurrent()) { |
368 | 0 | return false; |
369 | 0 | } |
370 | 0 | |
371 | 0 | if (aInit) { |
372 | 0 | gl()->fGenTextures(1, &mTextureHandle); |
373 | 0 | gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, mTextureHandle); |
374 | 0 |
|
375 | 0 | gl()->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, |
376 | 0 | LOCAL_GL_TEXTURE_STORAGE_HINT_APPLE, |
377 | 0 | LOCAL_GL_STORAGE_CACHED_APPLE); |
378 | 0 | gl()->fTextureRangeAPPLE(LOCAL_GL_TEXTURE_RECTANGLE_ARB, |
379 | 0 | aSurface->Stride() * aSurface->GetSize().height, |
380 | 0 | aSurface->GetData()); |
381 | 0 |
|
382 | 0 | gl()->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, |
383 | 0 | LOCAL_GL_TEXTURE_WRAP_S, |
384 | 0 | LOCAL_GL_CLAMP_TO_EDGE); |
385 | 0 | gl()->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, |
386 | 0 | LOCAL_GL_TEXTURE_WRAP_T, |
387 | 0 | LOCAL_GL_CLAMP_TO_EDGE); |
388 | 0 | } |
389 | 0 |
|
390 | 0 | MOZ_ASSERT(mTextureHandle); |
391 | 0 |
|
392 | 0 | // APPLE_client_storage |
393 | 0 | gl()->fPixelStorei(LOCAL_GL_UNPACK_CLIENT_STORAGE_APPLE, LOCAL_GL_TRUE); |
394 | 0 |
|
395 | 0 | nsIntRegion destRegion = aDestRegion ? *aDestRegion |
396 | 0 | : IntRect(0, 0, |
397 | 0 | aSurface->GetSize().width, |
398 | 0 | aSurface->GetSize().height); |
399 | 0 | gfx::IntPoint srcPoint = aSrcOffset ? *aSrcOffset |
400 | 0 | : gfx::IntPoint(0, 0); |
401 | 0 | mFormat = gl::UploadSurfaceToTexture(gl(), |
402 | 0 | aSurface, |
403 | 0 | destRegion, |
404 | 0 | mTextureHandle, |
405 | 0 | aSurface->GetSize(), |
406 | 0 | nullptr, |
407 | 0 | aInit, |
408 | 0 | srcPoint, |
409 | 0 | LOCAL_GL_TEXTURE0, |
410 | 0 | LOCAL_GL_TEXTURE_RECTANGLE_ARB); |
411 | 0 |
|
412 | 0 | gl()->fPixelStorei(LOCAL_GL_UNPACK_CLIENT_STORAGE_APPLE, LOCAL_GL_FALSE); |
413 | 0 | return true; |
414 | 0 | } |
415 | | |
416 | | //////////////////////////////////////////////////////////////////////// |
417 | | //////////////////////////////////////////////////////////////////////// |
418 | | // SurfaceTextureHost |
419 | | |
420 | | #ifdef MOZ_WIDGET_ANDROID |
421 | | |
422 | | SurfaceTextureSource::SurfaceTextureSource(TextureSourceProvider* aProvider, |
423 | | mozilla::java::GeckoSurfaceTexture::Ref& aSurfTex, |
424 | | gfx::SurfaceFormat aFormat, |
425 | | GLenum aTarget, |
426 | | GLenum aWrapMode, |
427 | | gfx::IntSize aSize, |
428 | | bool aIgnoreTransform) |
429 | | : mGL(aProvider->GetGLContext()) |
430 | | , mSurfTex(aSurfTex) |
431 | | , mFormat(aFormat) |
432 | | , mTextureTarget(aTarget) |
433 | | , mWrapMode(aWrapMode) |
434 | | , mSize(aSize) |
435 | | , mIgnoreTransform(aIgnoreTransform) |
436 | | { |
437 | | } |
438 | | |
439 | | void |
440 | | SurfaceTextureSource::BindTexture(GLenum aTextureUnit, |
441 | | gfx::SamplingFilter aSamplingFilter) |
442 | | { |
443 | | MOZ_ASSERT(mSurfTex); |
444 | | GLContext* gl = this->gl(); |
445 | | if (!gl || !gl->MakeCurrent()) { |
446 | | NS_WARNING("Trying to bind a texture without a GLContext"); |
447 | | return; |
448 | | } |
449 | | |
450 | | gl->fActiveTexture(aTextureUnit); |
451 | | gl->fBindTexture(mTextureTarget, mSurfTex->GetTexName()); |
452 | | |
453 | | ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget); |
454 | | } |
455 | | |
456 | | void |
457 | | SurfaceTextureSource::SetTextureSourceProvider(TextureSourceProvider* aProvider) |
458 | | { |
459 | | GLContext* newGL = aProvider->GetGLContext(); |
460 | | if (!newGL || mGL != newGL) { |
461 | | DeallocateDeviceData(); |
462 | | return; |
463 | | } |
464 | | |
465 | | mGL = newGL; |
466 | | } |
467 | | |
468 | | bool |
469 | | SurfaceTextureSource::IsValid() const |
470 | | { |
471 | | return !!gl(); |
472 | | } |
473 | | |
474 | | gfx::Matrix4x4 |
475 | | SurfaceTextureSource::GetTextureTransform() |
476 | | { |
477 | | MOZ_ASSERT(mSurfTex); |
478 | | |
479 | | gfx::Matrix4x4 ret; |
480 | | |
481 | | // GetTransformMatrix() returns the transform set by the producer side of |
482 | | // the SurfaceTexture. We should ignore this if we know the transform should |
483 | | // be identity but the producer couldn't set it correctly, like is the |
484 | | // case for AndroidNativeWindowTextureData. |
485 | | if (!mIgnoreTransform) { |
486 | | const auto& surf = java::sdk::SurfaceTexture::LocalRef(java::sdk::SurfaceTexture::Ref::From(mSurfTex)); |
487 | | AndroidSurfaceTexture::GetTransformMatrix(surf, &ret); |
488 | | } |
489 | | |
490 | | return ret; |
491 | | } |
492 | | |
493 | | void |
494 | | SurfaceTextureSource::DeallocateDeviceData() |
495 | | { |
496 | | mSurfTex = nullptr; |
497 | | } |
498 | | |
499 | | //////////////////////////////////////////////////////////////////////// |
500 | | |
501 | | SurfaceTextureHost::SurfaceTextureHost(TextureFlags aFlags, |
502 | | mozilla::java::GeckoSurfaceTexture::Ref& aSurfTex, |
503 | | gfx::IntSize aSize, |
504 | | gfx::SurfaceFormat aFormat, |
505 | | bool aContinuousUpdate, |
506 | | bool aIgnoreTransform) |
507 | | : TextureHost(aFlags) |
508 | | , mSurfTex(aSurfTex) |
509 | | , mSize(aSize) |
510 | | , mFormat(aFormat) |
511 | | , mContinuousUpdate(aContinuousUpdate) |
512 | | , mIgnoreTransform(aIgnoreTransform) |
513 | | { |
514 | | if (!mSurfTex) { |
515 | | return; |
516 | | } |
517 | | |
518 | | // Continuous update makes no sense with single buffer mode |
519 | | MOZ_ASSERT(!mSurfTex->IsSingleBuffer() || !mContinuousUpdate); |
520 | | |
521 | | mSurfTex->IncrementUse(); |
522 | | } |
523 | | |
524 | | SurfaceTextureHost::~SurfaceTextureHost() |
525 | | { |
526 | | if (mSurfTex) { |
527 | | mSurfTex->DecrementUse(); |
528 | | mSurfTex = nullptr; |
529 | | } |
530 | | } |
531 | | |
532 | | void |
533 | | SurfaceTextureHost::PrepareTextureSource(CompositableTextureSourceRef& aTexture) |
534 | | { |
535 | | if (!mContinuousUpdate && mSurfTex) { |
536 | | if (!EnsureAttached()) { |
537 | | return; |
538 | | } |
539 | | |
540 | | // UpdateTexImage() advances the internal buffer queue, so we only want to call this |
541 | | // once per transactionwhen we are not in continuous mode (as we are here). Otherwise, |
542 | | // the SurfaceTexture content will be de-synced from the rest of the page in subsequent |
543 | | // compositor passes. |
544 | | mSurfTex->UpdateTexImage(); |
545 | | } |
546 | | } |
547 | | |
548 | | gl::GLContext* |
549 | | SurfaceTextureHost::gl() const |
550 | | { |
551 | | return mProvider ? mProvider->GetGLContext() : nullptr; |
552 | | } |
553 | | |
554 | | bool |
555 | | SurfaceTextureHost::EnsureAttached() |
556 | | { |
557 | | GLContext* gl = this->gl(); |
558 | | if (!gl || !gl->MakeCurrent()) { |
559 | | return false; |
560 | | } |
561 | | |
562 | | if (!mSurfTex) { |
563 | | return false; |
564 | | } |
565 | | |
566 | | if (!mSurfTex->IsAttachedToGLContext((int64_t)gl)) { |
567 | | GLuint texName; |
568 | | gl->fGenTextures(1, &texName); |
569 | | if (NS_FAILED(mSurfTex->AttachToGLContext((int64_t)gl, texName))) { |
570 | | return false; |
571 | | } |
572 | | } |
573 | | |
574 | | return true; |
575 | | } |
576 | | |
577 | | bool |
578 | | SurfaceTextureHost::Lock() |
579 | | { |
580 | | if (!EnsureAttached()) { |
581 | | return false; |
582 | | } |
583 | | |
584 | | if (mContinuousUpdate) { |
585 | | mSurfTex->UpdateTexImage(); |
586 | | } |
587 | | |
588 | | if (!mTextureSource) { |
589 | | GLenum target = LOCAL_GL_TEXTURE_EXTERNAL; // This is required by SurfaceTexture |
590 | | GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE; |
591 | | mTextureSource = new SurfaceTextureSource(mProvider, |
592 | | mSurfTex, |
593 | | mFormat, |
594 | | target, |
595 | | wrapMode, |
596 | | mSize, |
597 | | mIgnoreTransform); |
598 | | } |
599 | | |
600 | | return true; |
601 | | } |
602 | | |
603 | | void |
604 | | SurfaceTextureHost::SetTextureSourceProvider(TextureSourceProvider* aProvider) |
605 | | { |
606 | | if (mProvider != aProvider) { |
607 | | if (!aProvider || !aProvider->GetGLContext()) { |
608 | | DeallocateDeviceData(); |
609 | | return; |
610 | | } |
611 | | mProvider = aProvider; |
612 | | } |
613 | | |
614 | | if (mTextureSource) { |
615 | | mTextureSource->SetTextureSourceProvider(aProvider); |
616 | | } |
617 | | } |
618 | | |
619 | | void |
620 | | SurfaceTextureHost::NotifyNotUsed() |
621 | | { |
622 | | if (mSurfTex && mSurfTex->IsSingleBuffer()) { |
623 | | mSurfTex->ReleaseTexImage(); |
624 | | } |
625 | | |
626 | | TextureHost::NotifyNotUsed(); |
627 | | } |
628 | | |
629 | | gfx::SurfaceFormat |
630 | | SurfaceTextureHost::GetFormat() const |
631 | | { |
632 | | return mFormat; |
633 | | } |
634 | | |
635 | | void |
636 | | SurfaceTextureHost::DeallocateDeviceData() |
637 | | { |
638 | | if (mTextureSource) { |
639 | | mTextureSource->DeallocateDeviceData(); |
640 | | } |
641 | | |
642 | | if (mSurfTex) { |
643 | | mSurfTex->DecrementUse(); |
644 | | mSurfTex = nullptr; |
645 | | } |
646 | | } |
647 | | |
648 | | #endif // MOZ_WIDGET_ANDROID |
649 | | |
650 | | //////////////////////////////////////////////////////////////////////// |
651 | | //////////////////////////////////////////////////////////////////////// |
652 | | // EGLImage |
653 | | |
654 | | EGLImageTextureSource::EGLImageTextureSource(TextureSourceProvider* aProvider, |
655 | | EGLImage aImage, |
656 | | gfx::SurfaceFormat aFormat, |
657 | | GLenum aTarget, |
658 | | GLenum aWrapMode, |
659 | | gfx::IntSize aSize) |
660 | | : mImage(aImage) |
661 | | , mFormat(aFormat) |
662 | | , mTextureTarget(aTarget) |
663 | | , mWrapMode(aWrapMode) |
664 | | , mSize(aSize) |
665 | 0 | { |
666 | 0 | MOZ_ASSERT(mTextureTarget == LOCAL_GL_TEXTURE_2D || |
667 | 0 | mTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL); |
668 | 0 | SetTextureSourceProvider(aProvider); |
669 | 0 | } |
670 | | |
671 | | void |
672 | | EGLImageTextureSource::BindTexture(GLenum aTextureUnit, |
673 | | gfx::SamplingFilter aSamplingFilter) |
674 | 0 | { |
675 | 0 | GLContext* gl = this->gl(); |
676 | 0 | if (!gl || !gl->MakeCurrent()) { |
677 | 0 | NS_WARNING("Trying to bind a texture without a GLContext"); |
678 | 0 | return; |
679 | 0 | } |
680 | 0 |
|
681 | 0 | MOZ_ASSERT(DoesEGLContextSupportSharingWithEGLImage(gl), |
682 | 0 | "EGLImage not supported or disabled in runtime"); |
683 | 0 |
|
684 | 0 | GLuint tex = mCompositor->GetTemporaryTexture(mTextureTarget, aTextureUnit); |
685 | 0 |
|
686 | 0 | gl->fActiveTexture(aTextureUnit); |
687 | 0 | gl->fBindTexture(mTextureTarget, tex); |
688 | 0 |
|
689 | 0 | gl->fEGLImageTargetTexture2D(mTextureTarget, mImage); |
690 | 0 |
|
691 | 0 | ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget); |
692 | 0 | } |
693 | | |
694 | | void |
695 | | EGLImageTextureSource::SetTextureSourceProvider(TextureSourceProvider* aProvider) |
696 | 0 | { |
697 | 0 | if (mCompositor == aProvider) { |
698 | 0 | return; |
699 | 0 | } |
700 | 0 | |
701 | 0 | if (!aProvider) { |
702 | 0 | mGL = nullptr; |
703 | 0 | mCompositor = nullptr; |
704 | 0 | return; |
705 | 0 | } |
706 | 0 | |
707 | 0 | mGL = aProvider->GetGLContext(); |
708 | 0 | if (Compositor* compositor = aProvider->AsCompositor()) { |
709 | 0 | mCompositor = compositor->AsCompositorOGL(); |
710 | 0 | } |
711 | 0 | } |
712 | | |
713 | | bool |
714 | | EGLImageTextureSource::IsValid() const |
715 | 0 | { |
716 | 0 | return !!gl(); |
717 | 0 | } |
718 | | |
719 | | gfx::Matrix4x4 |
720 | | EGLImageTextureSource::GetTextureTransform() |
721 | 0 | { |
722 | 0 | gfx::Matrix4x4 ret; |
723 | 0 | return ret; |
724 | 0 | } |
725 | | |
726 | | //////////////////////////////////////////////////////////////////////// |
727 | | |
728 | | EGLImageTextureHost::EGLImageTextureHost(TextureFlags aFlags, |
729 | | EGLImage aImage, |
730 | | EGLSync aSync, |
731 | | gfx::IntSize aSize, |
732 | | bool hasAlpha) |
733 | | : TextureHost(aFlags) |
734 | | , mImage(aImage) |
735 | | , mSync(aSync) |
736 | | , mSize(aSize) |
737 | | , mHasAlpha(hasAlpha) |
738 | 0 | {} |
739 | | |
740 | | EGLImageTextureHost::~EGLImageTextureHost() |
741 | 0 | {} |
742 | | |
743 | | gl::GLContext* |
744 | | EGLImageTextureHost::gl() const |
745 | 0 | { |
746 | 0 | return mProvider ? mProvider ->GetGLContext() : nullptr; |
747 | 0 | } |
748 | | |
749 | | bool |
750 | | EGLImageTextureHost::Lock() |
751 | 0 | { |
752 | 0 | GLContext* gl = this->gl(); |
753 | 0 | if (!gl || !gl->MakeCurrent()) { |
754 | 0 | return false; |
755 | 0 | } |
756 | 0 | |
757 | 0 | auto* egl = gl::GLLibraryEGL::Get(); |
758 | 0 | EGLint status = LOCAL_EGL_CONDITION_SATISFIED; |
759 | 0 |
|
760 | 0 | if (mSync) { |
761 | 0 | MOZ_ASSERT(egl->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync)); |
762 | 0 | status = egl->fClientWaitSync(EGL_DISPLAY(), mSync, 0, LOCAL_EGL_FOREVER); |
763 | 0 | } |
764 | 0 |
|
765 | 0 | if (status != LOCAL_EGL_CONDITION_SATISFIED) { |
766 | 0 | MOZ_ASSERT(status != 0, |
767 | 0 | "ClientWaitSync generated an error. Has mSync already been destroyed?"); |
768 | 0 | return false; |
769 | 0 | } |
770 | 0 |
|
771 | 0 | if (!mTextureSource) { |
772 | 0 | gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8 |
773 | 0 | : gfx::SurfaceFormat::R8G8B8X8; |
774 | 0 | GLenum target = gl->GetPreferredEGLImageTextureTarget(); |
775 | 0 | GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE; |
776 | 0 | mTextureSource = new EGLImageTextureSource(mProvider, |
777 | 0 | mImage, |
778 | 0 | format, |
779 | 0 | target, |
780 | 0 | wrapMode, |
781 | 0 | mSize); |
782 | 0 | } |
783 | 0 |
|
784 | 0 | return true; |
785 | 0 | } |
786 | | |
787 | | void |
788 | | EGLImageTextureHost::Unlock() |
789 | 0 | { |
790 | 0 | } |
791 | | |
792 | | void |
793 | | EGLImageTextureHost::SetTextureSourceProvider(TextureSourceProvider* aProvider) |
794 | 0 | { |
795 | 0 | if (mProvider != aProvider) { |
796 | 0 | if (!aProvider || !aProvider->GetGLContext()) { |
797 | 0 | mProvider = nullptr; |
798 | 0 | mTextureSource = nullptr; |
799 | 0 | return; |
800 | 0 | } |
801 | 0 | mProvider = aProvider; |
802 | 0 | } |
803 | 0 |
|
804 | 0 | if (mTextureSource) { |
805 | 0 | mTextureSource->SetTextureSourceProvider(aProvider); |
806 | 0 | } |
807 | 0 | } |
808 | | |
809 | | gfx::SurfaceFormat |
810 | | EGLImageTextureHost::GetFormat() const |
811 | 0 | { |
812 | 0 | MOZ_ASSERT(mTextureSource); |
813 | 0 | return mTextureSource ? mTextureSource->GetFormat() : gfx::SurfaceFormat::UNKNOWN; |
814 | 0 | } |
815 | | |
816 | | // |
817 | | |
818 | | GLTextureHost::GLTextureHost(TextureFlags aFlags, |
819 | | GLuint aTextureHandle, |
820 | | GLenum aTarget, |
821 | | GLsync aSync, |
822 | | gfx::IntSize aSize, |
823 | | bool aHasAlpha) |
824 | | : TextureHost(aFlags) |
825 | | , mTexture(aTextureHandle) |
826 | | , mTarget(aTarget) |
827 | | , mSync(aSync) |
828 | | , mSize(aSize) |
829 | | , mHasAlpha(aHasAlpha) |
830 | 0 | {} |
831 | | |
832 | | GLTextureHost::~GLTextureHost() |
833 | 0 | {} |
834 | | |
835 | | gl::GLContext* |
836 | | GLTextureHost::gl() const |
837 | 0 | { |
838 | 0 | return mProvider ? mProvider->GetGLContext() : nullptr; |
839 | 0 | } |
840 | | |
841 | | bool |
842 | | GLTextureHost::Lock() |
843 | 0 | { |
844 | 0 | GLContext* gl = this->gl(); |
845 | 0 | if (!gl || !gl->MakeCurrent()) { |
846 | 0 | return false; |
847 | 0 | } |
848 | 0 | |
849 | 0 | if (mSync) { |
850 | 0 | if (!gl->MakeCurrent()) { |
851 | 0 | return false; |
852 | 0 | } |
853 | 0 | gl->fWaitSync(mSync, 0, LOCAL_GL_TIMEOUT_IGNORED); |
854 | 0 | gl->fDeleteSync(mSync); |
855 | 0 | mSync = 0; |
856 | 0 | } |
857 | 0 |
|
858 | 0 | if (!mTextureSource) { |
859 | 0 | gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8 |
860 | 0 | : gfx::SurfaceFormat::R8G8B8X8; |
861 | 0 | mTextureSource = new GLTextureSource(mProvider, |
862 | 0 | mTexture, |
863 | 0 | mTarget, |
864 | 0 | mSize, |
865 | 0 | format); |
866 | 0 | } |
867 | 0 |
|
868 | 0 | return true; |
869 | 0 | } |
870 | | |
871 | | void |
872 | | GLTextureHost::SetTextureSourceProvider(TextureSourceProvider* aProvider) |
873 | 0 | { |
874 | 0 | if (mProvider != aProvider) { |
875 | 0 | if (!aProvider || !aProvider->GetGLContext()) { |
876 | 0 | mProvider = nullptr; |
877 | 0 | mTextureSource = nullptr; |
878 | 0 | return; |
879 | 0 | } |
880 | 0 | mProvider = aProvider; |
881 | 0 | } |
882 | 0 |
|
883 | 0 | if (mTextureSource) { |
884 | 0 | mTextureSource->SetTextureSourceProvider(aProvider); |
885 | 0 | } |
886 | 0 | } |
887 | | |
888 | | gfx::SurfaceFormat |
889 | | GLTextureHost::GetFormat() const |
890 | 0 | { |
891 | 0 | MOZ_ASSERT(mTextureSource); |
892 | 0 | return mTextureSource ? mTextureSource->GetFormat() : gfx::SurfaceFormat::UNKNOWN; |
893 | 0 | } |
894 | | |
895 | | } // namespace layers |
896 | | } // namespace mozilla |