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/. */
7 #include "RenderAndroidSurfaceTextureHost.h"
9 #include "GLReadTexImageHelper.h"
10 #include "mozilla/gfx/Logging.h"
11 #include "mozilla/webrender/RenderThread.h"
12 #include "GLContext.h"
17 RenderAndroidSurfaceTextureHost::RenderAndroidSurfaceTextureHost(
18 const java::GeckoSurfaceTexture::GlobalRef
& aSurfTex
, gfx::IntSize aSize
,
19 gfx::SurfaceFormat aFormat
, bool aContinuousUpdate
)
23 mContinuousUpdate(aContinuousUpdate
),
24 mPrepareStatus(STATUS_NONE
),
25 mAttachedToGLContext(false) {
26 MOZ_COUNT_CTOR_INHERITED(RenderAndroidSurfaceTextureHost
, RenderTextureHost
);
29 mSurfTex
->IncrementUse();
33 RenderAndroidSurfaceTextureHost::~RenderAndroidSurfaceTextureHost() {
34 MOZ_ASSERT(RenderThread::IsInRenderThread());
35 MOZ_COUNT_DTOR_INHERITED(RenderAndroidSurfaceTextureHost
, RenderTextureHost
);
36 // The SurfaceTexture gets destroyed when its use count reaches zero.
38 mSurfTex
->DecrementUse();
42 wr::WrExternalImage
RenderAndroidSurfaceTextureHost::Lock(
43 uint8_t aChannelIndex
, gl::GLContext
* aGL
, wr::ImageRendering aRendering
) {
44 MOZ_ASSERT(aChannelIndex
== 0);
45 MOZ_ASSERT((mPrepareStatus
== STATUS_PREPARED
) ||
46 (!mSurfTex
->IsSingleBuffer() &&
47 mPrepareStatus
== STATUS_UPDATE_TEX_IMAGE_NEEDED
));
49 if (mGL
.get() != aGL
) {
50 // This should not happen. On android, SingletonGL is used.
51 MOZ_ASSERT_UNREACHABLE("Unexpected GL context");
52 return InvalidToWrExternalImage();
55 if (!mSurfTex
|| !mGL
|| !mGL
->MakeCurrent()) {
56 return InvalidToWrExternalImage();
59 MOZ_ASSERT(mAttachedToGLContext
);
60 if (!mAttachedToGLContext
) {
61 return InvalidToWrExternalImage();
64 if (IsFilterUpdateNecessary(aRendering
)) {
65 // Cache new rendering filter.
66 mCachedRendering
= aRendering
;
67 ActivateBindAndTexParameteri(mGL
, LOCAL_GL_TEXTURE0
,
68 LOCAL_GL_TEXTURE_EXTERNAL_OES
,
69 mSurfTex
->GetTexName(), aRendering
);
72 if (mContinuousUpdate
) {
73 MOZ_ASSERT(!mSurfTex
->IsSingleBuffer());
74 mSurfTex
->UpdateTexImage();
75 } else if (mPrepareStatus
== STATUS_UPDATE_TEX_IMAGE_NEEDED
) {
76 MOZ_ASSERT(!mSurfTex
->IsSingleBuffer());
77 // When SurfaceTexture is not single buffer mode, call UpdateTexImage() once
78 // just before rendering. During playing video, one SurfaceTexture is used
79 // for all RenderAndroidSurfaceTextureHosts of video.
80 mSurfTex
->UpdateTexImage();
81 mPrepareStatus
= STATUS_PREPARED
;
84 return NativeTextureToWrExternalImage(mSurfTex
->GetTexName(), 0, 0,
85 mSize
.width
, mSize
.height
);
88 void RenderAndroidSurfaceTextureHost::Unlock() {}
90 bool RenderAndroidSurfaceTextureHost::EnsureAttachedToGLContext() {
91 // During handling WebRenderError, GeckoSurfaceTexture should not be attached
93 if (RenderThread::Get()->IsHandlingWebRenderError()) {
97 if (mAttachedToGLContext
) {
102 mGL
= RenderThread::Get()->SingletonGL();
105 if (!mSurfTex
|| !mGL
|| !mGL
->MakeCurrent()) {
109 if (!mSurfTex
->IsAttachedToGLContext((int64_t)mGL
.get())) {
111 mGL
->fGenTextures(1, &texName
);
112 ActivateBindAndTexParameteri(mGL
, LOCAL_GL_TEXTURE0
,
113 LOCAL_GL_TEXTURE_EXTERNAL_OES
, texName
,
116 if (NS_FAILED(mSurfTex
->AttachToGLContext((int64_t)mGL
.get(), texName
))) {
118 mGL
->fDeleteTextures(1, &texName
);
123 mAttachedToGLContext
= true;
127 void RenderAndroidSurfaceTextureHost::PrepareForUse() {
128 // When SurfaceTexture is single buffer mode, UpdateTexImage needs to be
129 // called only once for each publish. If UpdateTexImage is called more
130 // than once, it causes hang on puglish side. And UpdateTexImage needs to
131 // be called on render thread, since the SurfaceTexture is consumed on render
133 MOZ_ASSERT(RenderThread::IsInRenderThread());
134 MOZ_ASSERT(mPrepareStatus
== STATUS_NONE
);
136 if (mContinuousUpdate
|| !mSurfTex
) {
140 mPrepareStatus
= STATUS_MIGHT_BE_USED_BY_WR
;
142 if (mSurfTex
->IsSingleBuffer()) {
143 EnsureAttachedToGLContext();
144 // When SurfaceTexture is single buffer mode, it is OK to call
145 // UpdateTexImage() here.
146 mSurfTex
->UpdateTexImage();
147 mPrepareStatus
= STATUS_PREPARED
;
151 void RenderAndroidSurfaceTextureHost::NotifyForUse() {
152 MOZ_ASSERT(RenderThread::IsInRenderThread());
154 if (mPrepareStatus
== STATUS_MIGHT_BE_USED_BY_WR
) {
155 // This happens when SurfaceTexture of video is rendered on WebRender.
156 // There is a case that SurfaceTexture is not rendered on WebRender, instead
157 // it is rendered to WebGL and the SurfaceTexture should not be attached to
158 // gl context of WebRender. It is ugly. But it is same as Compositor
160 MOZ_ASSERT(!mSurfTex
->IsSingleBuffer());
161 if (!EnsureAttachedToGLContext()) {
164 mPrepareStatus
= STATUS_UPDATE_TEX_IMAGE_NEEDED
;
168 void RenderAndroidSurfaceTextureHost::NotifyNotUsed() {
169 MOZ_ASSERT(RenderThread::IsInRenderThread());
172 MOZ_ASSERT(mPrepareStatus
== STATUS_NONE
);
176 if (mSurfTex
->IsSingleBuffer()) {
177 MOZ_ASSERT(mPrepareStatus
== STATUS_PREPARED
);
178 MOZ_ASSERT(mAttachedToGLContext
);
179 // Release SurfaceTexture's buffer to client side.
181 mSurfTex
->ReleaseTexImage();
182 } else if (mPrepareStatus
== STATUS_UPDATE_TEX_IMAGE_NEEDED
) {
183 MOZ_ASSERT(mAttachedToGLContext
);
184 // This could happen when video frame was skipped. UpdateTexImage() neeeds
185 // to be called for adjusting SurfaceTexture's buffer status.
186 mSurfTex
->UpdateTexImage();
189 mPrepareStatus
= STATUS_NONE
;
192 gfx::SurfaceFormat
RenderAndroidSurfaceTextureHost::GetFormat() const {
193 MOZ_ASSERT(mFormat
== gfx::SurfaceFormat::R8G8B8A8
||
194 mFormat
== gfx::SurfaceFormat::R8G8B8X8
);
196 if (mFormat
== gfx::SurfaceFormat::R8G8B8A8
) {
197 return gfx::SurfaceFormat::B8G8R8A8
;
200 if (mFormat
== gfx::SurfaceFormat::R8G8B8X8
) {
201 return gfx::SurfaceFormat::B8G8R8X8
;
205 << "Unexpected color format of RenderAndroidSurfaceTextureHost";
207 return gfx::SurfaceFormat::UNKNOWN
;
210 already_AddRefed
<DataSourceSurface
>
211 RenderAndroidSurfaceTextureHost::ReadTexImage() {
213 mGL
= RenderThread::Get()->SingletonGL();
219 /* Allocate resulting image surface */
220 int32_t stride
= mSize
.width
* BytesPerPixel(GetFormat());
221 RefPtr
<DataSourceSurface
> surf
=
222 Factory::CreateDataSourceSurfaceWithStride(mSize
, GetFormat(), stride
);
227 layers::ShaderConfigOGL config
= layers::ShaderConfigFromTargetAndFormat(
228 LOCAL_GL_TEXTURE_EXTERNAL
, mFormat
);
229 int shaderConfig
= config
.mFeatures
;
231 bool ret
= mGL
->ReadTexImageHelper()->ReadTexImage(
232 surf
, mSurfTex
->GetTexName(), LOCAL_GL_TEXTURE_EXTERNAL
, mSize
,
233 shaderConfig
, /* aYInvert */ false);
238 return surf
.forget();
241 bool RenderAndroidSurfaceTextureHost::MapPlane(RenderCompositor
* aCompositor
,
242 uint8_t aChannelIndex
,
243 PlaneInfo
& aPlaneInfo
) {
244 RefPtr
<gfx::DataSourceSurface
> readback
= ReadTexImage();
249 DataSourceSurface::MappedSurface map
;
250 if (!readback
->Map(DataSourceSurface::MapType::READ
, &map
)) {
254 mReadback
= readback
;
255 aPlaneInfo
.mSize
= mSize
;
256 aPlaneInfo
.mStride
= map
.mStride
;
257 aPlaneInfo
.mData
= map
.mData
;
261 void RenderAndroidSurfaceTextureHost::UnmapPlanes() {
269 } // namespace mozilla