|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
2 // * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "GLContext.h" |
|
7 #include "gfx2DGlue.h" |
|
8 #include <ui/GraphicBuffer.h> |
|
9 #include "GrallocImages.h" // for GrallocImage |
|
10 #include "mozilla/layers/GrallocTextureHost.h" |
|
11 #include "mozilla/layers/CompositorOGL.h" |
|
12 #include "EGLImageHelpers.h" |
|
13 #include "GLReadTexImageHelper.h" |
|
14 |
|
15 namespace mozilla { |
|
16 namespace layers { |
|
17 |
|
18 using namespace android; |
|
19 |
|
20 static gfx::SurfaceFormat |
|
21 SurfaceFormatForAndroidPixelFormat(android::PixelFormat aFormat, |
|
22 bool swapRB = false) |
|
23 { |
|
24 switch (aFormat) { |
|
25 case android::PIXEL_FORMAT_BGRA_8888: |
|
26 return swapRB ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::B8G8R8A8; |
|
27 case android::PIXEL_FORMAT_RGBA_8888: |
|
28 return swapRB ? gfx::SurfaceFormat::B8G8R8A8 : gfx::SurfaceFormat::R8G8B8A8; |
|
29 case android::PIXEL_FORMAT_RGBX_8888: |
|
30 return swapRB ? gfx::SurfaceFormat::B8G8R8X8 : gfx::SurfaceFormat::R8G8B8X8; |
|
31 case android::PIXEL_FORMAT_RGB_565: |
|
32 return gfx::SurfaceFormat::R5G6B5; |
|
33 case HAL_PIXEL_FORMAT_YCbCr_422_SP: |
|
34 case HAL_PIXEL_FORMAT_YCrCb_420_SP: |
|
35 case HAL_PIXEL_FORMAT_YCbCr_422_I: |
|
36 case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: |
|
37 case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: |
|
38 case HAL_PIXEL_FORMAT_YV12: |
|
39 return gfx::SurfaceFormat::R8G8B8A8; // yup, use SurfaceFormat::R8G8B8A8 even though it's a YUV texture. This is an external texture. |
|
40 default: |
|
41 if (aFormat >= 0x100 && aFormat <= 0x1FF) { |
|
42 // Reserved range for HAL specific formats. |
|
43 return gfx::SurfaceFormat::R8G8B8A8; |
|
44 } else { |
|
45 // This is not super-unreachable, there's a bunch of hypothetical pixel |
|
46 // formats we don't deal with. |
|
47 // We only want to abort in debug builds here, since if we crash here |
|
48 // we'll take down the compositor process and thus the phone. This seems |
|
49 // like undesirable behaviour. We'd rather have a subtle artifact. |
|
50 printf_stderr(" xxxxx unknow android format %i\n", (int)aFormat); |
|
51 MOZ_ASSERT(false, "Unknown Android pixel format."); |
|
52 return gfx::SurfaceFormat::UNKNOWN; |
|
53 } |
|
54 } |
|
55 } |
|
56 |
|
57 static GLenum |
|
58 TextureTargetForAndroidPixelFormat(android::PixelFormat aFormat) |
|
59 { |
|
60 switch (aFormat) { |
|
61 case HAL_PIXEL_FORMAT_YCbCr_422_SP: |
|
62 case HAL_PIXEL_FORMAT_YCrCb_420_SP: |
|
63 case HAL_PIXEL_FORMAT_YCbCr_422_I: |
|
64 case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: |
|
65 case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: |
|
66 case HAL_PIXEL_FORMAT_YV12: |
|
67 return LOCAL_GL_TEXTURE_EXTERNAL; |
|
68 case android::PIXEL_FORMAT_BGRA_8888: |
|
69 case android::PIXEL_FORMAT_RGBA_8888: |
|
70 case android::PIXEL_FORMAT_RGBX_8888: |
|
71 case android::PIXEL_FORMAT_RGB_565: |
|
72 return LOCAL_GL_TEXTURE_2D; |
|
73 default: |
|
74 if (aFormat >= 0x100 && aFormat <= 0x1FF) { |
|
75 // Reserved range for HAL specific formats. |
|
76 return LOCAL_GL_TEXTURE_EXTERNAL; |
|
77 } else { |
|
78 // This is not super-unreachable, there's a bunch of hypothetical pixel |
|
79 // formats we don't deal with. |
|
80 // We only want to abort in debug builds here, since if we crash here |
|
81 // we'll take down the compositor process and thus the phone. This seems |
|
82 // like undesirable behaviour. We'd rather have a subtle artifact. |
|
83 MOZ_ASSERT(false, "Unknown Android pixel format."); |
|
84 return LOCAL_GL_TEXTURE_EXTERNAL; |
|
85 } |
|
86 } |
|
87 } |
|
88 |
|
89 GrallocTextureSourceOGL::GrallocTextureSourceOGL(CompositorOGL* aCompositor, |
|
90 android::GraphicBuffer* aGraphicBuffer, |
|
91 gfx::SurfaceFormat aFormat) |
|
92 : mCompositor(aCompositor) |
|
93 , mGraphicBuffer(aGraphicBuffer) |
|
94 , mEGLImage(0) |
|
95 , mFormat(aFormat) |
|
96 , mNeedsReset(true) |
|
97 { |
|
98 MOZ_ASSERT(mGraphicBuffer.get()); |
|
99 } |
|
100 |
|
101 GrallocTextureSourceOGL::~GrallocTextureSourceOGL() |
|
102 { |
|
103 DeallocateDeviceData(); |
|
104 mCompositor = nullptr; |
|
105 } |
|
106 |
|
107 void |
|
108 GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit, gfx::Filter aFilter) |
|
109 { |
|
110 /* |
|
111 * The job of this function is to ensure that the texture is tied to the |
|
112 * android::GraphicBuffer, so that texturing will source the GraphicBuffer. |
|
113 * |
|
114 * To this effect we create an EGLImage wrapping this GraphicBuffer, |
|
115 * using EGLImageCreateFromNativeBuffer, and then we tie this EGLImage to our |
|
116 * texture using fEGLImageTargetTexture2D. |
|
117 */ |
|
118 MOZ_ASSERT(gl()); |
|
119 if (!IsValid()) { |
|
120 return; |
|
121 } |
|
122 gl()->MakeCurrent(); |
|
123 |
|
124 GLuint tex = GetGLTexture(); |
|
125 GLuint textureTarget = GetTextureTarget(); |
|
126 |
|
127 gl()->fActiveTexture(aTextureUnit); |
|
128 gl()->fBindTexture(textureTarget, tex); |
|
129 |
|
130 if (mCompositableBackendData) { |
|
131 // There are two paths for locking/unlocking - if mCompositableBackendData is |
|
132 // set, we use the texture on there, otherwise we use |
|
133 // CompositorBackendSpecificData from the compositor and bind the EGLImage |
|
134 // only in Lock(). |
|
135 if (!mEGLImage) { |
|
136 mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer()); |
|
137 } |
|
138 gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage); |
|
139 } |
|
140 |
|
141 ApplyFilterToBoundTexture(gl(), aFilter, textureTarget); |
|
142 } |
|
143 |
|
144 void GrallocTextureSourceOGL::Lock() |
|
145 { |
|
146 if (mCompositableBackendData) return; |
|
147 |
|
148 MOZ_ASSERT(IsValid()); |
|
149 |
|
150 mTexture = mCompositor->GetTemporaryTexture(GetTextureTarget(), LOCAL_GL_TEXTURE0); |
|
151 |
|
152 GLuint textureTarget = GetTextureTarget(); |
|
153 |
|
154 gl()->MakeCurrent(); |
|
155 gl()->fActiveTexture(LOCAL_GL_TEXTURE0); |
|
156 gl()->fBindTexture(textureTarget, mTexture); |
|
157 if (!mEGLImage) { |
|
158 mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer()); |
|
159 } |
|
160 gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage); |
|
161 } |
|
162 |
|
163 bool |
|
164 GrallocTextureSourceOGL::IsValid() const |
|
165 { |
|
166 return !!gl() && !!mGraphicBuffer.get() && (!!mCompositor || !!mCompositableBackendData); |
|
167 } |
|
168 |
|
169 gl::GLContext* |
|
170 GrallocTextureSourceOGL::gl() const |
|
171 { |
|
172 return mCompositor ? mCompositor->gl() : nullptr; |
|
173 } |
|
174 |
|
175 void |
|
176 GrallocTextureSourceOGL::SetCompositor(Compositor* aCompositor) |
|
177 { |
|
178 if (mCompositor && !aCompositor) { |
|
179 DeallocateDeviceData(); |
|
180 } |
|
181 mCompositor = static_cast<CompositorOGL*>(aCompositor); |
|
182 } |
|
183 |
|
184 |
|
185 GLenum |
|
186 GrallocTextureSourceOGL::GetTextureTarget() const |
|
187 { |
|
188 MOZ_ASSERT(gl()); |
|
189 MOZ_ASSERT(mGraphicBuffer.get()); |
|
190 |
|
191 if (!gl() || !mGraphicBuffer.get()) { |
|
192 return LOCAL_GL_TEXTURE_EXTERNAL; |
|
193 } |
|
194 |
|
195 // SGX has a quirk that only TEXTURE_EXTERNAL works and any other value will |
|
196 // result in black pixels when trying to draw from bound textures. |
|
197 // Unfortunately, using TEXTURE_EXTERNAL on Adreno has a terrible effect on |
|
198 // performance. |
|
199 // See Bug 950050. |
|
200 if (gl()->Renderer() == gl::GLRenderer::SGX530 || |
|
201 gl()->Renderer() == gl::GLRenderer::SGX540) { |
|
202 return LOCAL_GL_TEXTURE_EXTERNAL; |
|
203 } |
|
204 |
|
205 return TextureTargetForAndroidPixelFormat(mGraphicBuffer->getPixelFormat()); |
|
206 } |
|
207 |
|
208 void |
|
209 GrallocTextureSourceOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData) |
|
210 { |
|
211 if (!aBackendData) { |
|
212 mCompositableBackendData = nullptr; |
|
213 DeallocateDeviceData(); |
|
214 return; |
|
215 } |
|
216 |
|
217 if (mCompositableBackendData != aBackendData) { |
|
218 mNeedsReset = true; |
|
219 } |
|
220 |
|
221 if (!mNeedsReset) { |
|
222 // Update binding to the EGLImage |
|
223 gl()->MakeCurrent(); |
|
224 GLuint tex = GetGLTexture(); |
|
225 GLuint textureTarget = GetTextureTarget(); |
|
226 gl()->fActiveTexture(LOCAL_GL_TEXTURE0); |
|
227 gl()->fBindTexture(textureTarget, tex); |
|
228 gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage); |
|
229 return; |
|
230 } |
|
231 |
|
232 mCompositableBackendData = aBackendData; |
|
233 |
|
234 if (!mCompositor) { |
|
235 return; |
|
236 } |
|
237 |
|
238 // delete old EGLImage |
|
239 DeallocateDeviceData(); |
|
240 |
|
241 gl()->MakeCurrent(); |
|
242 GLuint tex = GetGLTexture(); |
|
243 GLuint textureTarget = GetTextureTarget(); |
|
244 |
|
245 gl()->fActiveTexture(LOCAL_GL_TEXTURE0); |
|
246 gl()->fBindTexture(textureTarget, tex); |
|
247 // create new EGLImage |
|
248 mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer()); |
|
249 gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage); |
|
250 mNeedsReset = false; |
|
251 } |
|
252 |
|
253 gfx::IntSize |
|
254 GrallocTextureSourceOGL::GetSize() const |
|
255 { |
|
256 if (!IsValid()) { |
|
257 NS_WARNING("Trying to access the size of an invalid GrallocTextureSourceOGL"); |
|
258 return gfx::IntSize(0, 0); |
|
259 } |
|
260 return gfx::IntSize(mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight()); |
|
261 } |
|
262 |
|
263 void |
|
264 GrallocTextureSourceOGL::DeallocateDeviceData() |
|
265 { |
|
266 if (mEGLImage) { |
|
267 MOZ_ASSERT(gl()); |
|
268 gl()->MakeCurrent(); |
|
269 EGLImageDestroy(gl(), mEGLImage); |
|
270 mEGLImage = EGL_NO_IMAGE; |
|
271 } |
|
272 } |
|
273 |
|
274 GrallocTextureHostOGL::GrallocTextureHostOGL(TextureFlags aFlags, |
|
275 const NewSurfaceDescriptorGralloc& aDescriptor) |
|
276 : TextureHost(aFlags) |
|
277 { |
|
278 android::GraphicBuffer* graphicBuffer = nullptr; |
|
279 gfx::SurfaceFormat format = gfx::SurfaceFormat::UNKNOWN; |
|
280 |
|
281 mSize = aDescriptor.size(); |
|
282 mGrallocActor = |
|
283 static_cast<GrallocBufferActor*>(aDescriptor.bufferParent()); |
|
284 |
|
285 if (mGrallocActor) { |
|
286 mGrallocActor->AddTextureHost(this); |
|
287 graphicBuffer = mGrallocActor->GetGraphicBuffer(); |
|
288 } |
|
289 |
|
290 if (graphicBuffer) { |
|
291 format = |
|
292 SurfaceFormatForAndroidPixelFormat(graphicBuffer->getPixelFormat(), |
|
293 aFlags & TEXTURE_RB_SWAPPED); |
|
294 } |
|
295 mTextureSource = new GrallocTextureSourceOGL(nullptr, |
|
296 graphicBuffer, |
|
297 format); |
|
298 } |
|
299 |
|
300 GrallocTextureHostOGL::~GrallocTextureHostOGL() |
|
301 { |
|
302 mTextureSource = nullptr; |
|
303 if (mGrallocActor) { |
|
304 mGrallocActor->RemoveTextureHost(); |
|
305 mGrallocActor = nullptr; |
|
306 } |
|
307 } |
|
308 |
|
309 void |
|
310 GrallocTextureHostOGL::SetCompositor(Compositor* aCompositor) |
|
311 { |
|
312 mTextureSource->SetCompositor(static_cast<CompositorOGL*>(aCompositor)); |
|
313 } |
|
314 |
|
315 bool |
|
316 GrallocTextureHostOGL::Lock() |
|
317 { |
|
318 if (IsValid()) { |
|
319 mTextureSource->Lock(); |
|
320 return true; |
|
321 } |
|
322 return false; |
|
323 } |
|
324 |
|
325 void |
|
326 GrallocTextureHostOGL::Unlock() |
|
327 { |
|
328 // Unlock is done internally by binding the texture to another gralloc buffer |
|
329 } |
|
330 |
|
331 bool |
|
332 GrallocTextureHostOGL::IsValid() const |
|
333 { |
|
334 return mTextureSource->IsValid(); |
|
335 } |
|
336 |
|
337 gfx::SurfaceFormat |
|
338 GrallocTextureHostOGL::GetFormat() const |
|
339 { |
|
340 return mTextureSource->GetFormat(); |
|
341 } |
|
342 |
|
343 void |
|
344 GrallocTextureHostOGL::DeallocateSharedData() |
|
345 { |
|
346 if (mTextureSource) { |
|
347 mTextureSource->ForgetBuffer(); |
|
348 } |
|
349 if (mGrallocActor) { |
|
350 PGrallocBufferParent::Send__delete__(mGrallocActor); |
|
351 } |
|
352 } |
|
353 |
|
354 void |
|
355 GrallocTextureHostOGL::ForgetSharedData() |
|
356 { |
|
357 if (mTextureSource) { |
|
358 mTextureSource->ForgetBuffer(); |
|
359 } |
|
360 } |
|
361 |
|
362 void |
|
363 GrallocTextureHostOGL::DeallocateDeviceData() |
|
364 { |
|
365 mTextureSource->DeallocateDeviceData(); |
|
366 } |
|
367 |
|
368 LayerRenderState |
|
369 GrallocTextureHostOGL::GetRenderState() |
|
370 { |
|
371 if (IsValid()) { |
|
372 uint32_t flags = 0; |
|
373 if (mFlags & TEXTURE_NEEDS_Y_FLIP) { |
|
374 flags |= LAYER_RENDER_STATE_Y_FLIPPED; |
|
375 } |
|
376 if (mFlags & TEXTURE_RB_SWAPPED) { |
|
377 flags |= LAYER_RENDER_STATE_FORMAT_RB_SWAP; |
|
378 } |
|
379 return LayerRenderState(mTextureSource->mGraphicBuffer.get(), |
|
380 gfx::ThebesIntSize(mSize), |
|
381 flags, |
|
382 this); |
|
383 } |
|
384 |
|
385 return LayerRenderState(); |
|
386 } |
|
387 |
|
388 TemporaryRef<gfx::DataSourceSurface> |
|
389 GrallocTextureHostOGL::GetAsSurface() { |
|
390 return mTextureSource ? mTextureSource->GetAsSurface() |
|
391 : nullptr; |
|
392 } |
|
393 |
|
394 TemporaryRef<gfx::DataSourceSurface> |
|
395 GrallocTextureSourceOGL::GetAsSurface() { |
|
396 if (!IsValid()) { |
|
397 return nullptr; |
|
398 } |
|
399 gl()->MakeCurrent(); |
|
400 |
|
401 GLuint tex = GetGLTexture(); |
|
402 gl()->fActiveTexture(LOCAL_GL_TEXTURE0); |
|
403 gl()->fBindTexture(GetTextureTarget(), tex); |
|
404 if (!mEGLImage) { |
|
405 mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer()); |
|
406 } |
|
407 gl()->fEGLImageTargetTexture2D(GetTextureTarget(), mEGLImage); |
|
408 |
|
409 RefPtr<gfx::DataSourceSurface> surf = |
|
410 IsValid() ? ReadBackSurface(gl(), tex, false, GetFormat()) |
|
411 : nullptr; |
|
412 |
|
413 gl()->fActiveTexture(LOCAL_GL_TEXTURE0); |
|
414 return surf.forget(); |
|
415 } |
|
416 |
|
417 GLuint |
|
418 GrallocTextureSourceOGL::GetGLTexture() |
|
419 { |
|
420 if (mCompositableBackendData) { |
|
421 mCompositableBackendData->SetCompositor(mCompositor); |
|
422 return static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get())->GetTexture(); |
|
423 } |
|
424 |
|
425 return mTexture; |
|
426 } |
|
427 |
|
428 void |
|
429 GrallocTextureHostOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData) |
|
430 { |
|
431 mCompositableBackendData = aBackendData; |
|
432 if (mTextureSource) { |
|
433 mTextureSource->SetCompositableBackendSpecificData(aBackendData); |
|
434 } |
|
435 // Register this object to CompositableBackendSpecificData |
|
436 // as current TextureHost. |
|
437 if (aBackendData) { |
|
438 aBackendData->SetCurrentReleaseFenceTexture(this); |
|
439 } |
|
440 } |
|
441 |
|
442 } // namepsace layers |
|
443 } // namepsace mozilla |