1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/. */
6 #include "TextureImageEGL.h"
7 #include "GLLibraryEGL.h"
9 #include "GLUploadHelpers.h"
10 #include "gfxPlatform.h"
11 #include "gfx2DGlue.h"
12 #include "mozilla/gfx/Types.h"
18 GLFormatForImage(gfx::SurfaceFormat aFormat
)
21 case gfx::SurfaceFormat::B8G8R8A8
:
22 case gfx::SurfaceFormat::B8G8R8X8
:
24 case gfx::SurfaceFormat::R5G6B5
:
26 case gfx::SurfaceFormat::A8
:
27 return LOCAL_GL_LUMINANCE
;
29 NS_WARNING("Unknown GL format for Surface format");
35 GLTypeForImage(gfx::SurfaceFormat aFormat
)
38 case gfx::SurfaceFormat::B8G8R8A8
:
39 case gfx::SurfaceFormat::B8G8R8X8
:
40 case gfx::SurfaceFormat::A8
:
41 return LOCAL_GL_UNSIGNED_BYTE
;
42 case gfx::SurfaceFormat::R5G6B5
:
43 return LOCAL_GL_UNSIGNED_SHORT_5_6_5
;
45 NS_WARNING("Unknown GL format for Surface format");
50 TextureImageEGL::TextureImageEGL(GLuint aTexture
,
51 const nsIntSize
& aSize
,
53 ContentType aContentType
,
56 TextureState aTextureState
,
57 TextureImage::ImageFormat aImageFormat
)
58 : TextureImage(aSize
, aWrapMode
, aContentType
, aFlags
)
59 , mGLContext(aContext
)
60 , mUpdateFormat(gfx::ImageFormatToSurfaceFormat(aImageFormat
))
65 , mTextureState(aTextureState
)
68 if (mUpdateFormat
== gfx::SurfaceFormat::UNKNOWN
) {
69 mUpdateFormat
= gfx::ImageFormatToSurfaceFormat(
70 gfxPlatform::GetPlatform()->OptimalFormatForContent(GetContentType()));
73 if (mUpdateFormat
== gfx::SurfaceFormat::R5G6B5
) {
74 mTextureFormat
= gfx::SurfaceFormat::R8G8B8X8
;
75 } else if (mUpdateFormat
== gfx::SurfaceFormat::B8G8R8X8
) {
76 mTextureFormat
= gfx::SurfaceFormat::B8G8R8X8
;
78 mTextureFormat
= gfx::SurfaceFormat::B8G8R8A8
;
82 TextureImageEGL::~TextureImageEGL()
84 if (mGLContext
->IsDestroyed() || !mGLContext
->IsOwningThreadCurrent()) {
88 // If we have a context, then we need to delete the texture;
89 // if we don't have a context (either real or shared),
90 // then they went away when the contex was deleted, because it
91 // was the only one that had access to it.
92 if (mGLContext
->MakeCurrent()) {
93 mGLContext
->fDeleteTextures(1, &mTexture
);
100 TextureImageEGL::GetUpdateRegion(nsIntRegion
& aForRegion
)
102 if (mTextureState
!= Valid
) {
103 // if the texture hasn't been initialized yet, force the
104 // client to paint everything
105 aForRegion
= nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize
));
108 // We can only draw a rectangle, not subregions due to
109 // the way that our texture upload functions work. If
110 // needed, we /could/ do multiple texture uploads if we have
111 // non-overlapping rects, but that's a tradeoff.
112 aForRegion
= nsIntRegion(aForRegion
.GetBounds());
116 TextureImageEGL::BeginUpdate(nsIntRegion
& aRegion
)
118 NS_ASSERTION(!mUpdateDrawTarget
, "BeginUpdate() without EndUpdate()?");
120 // determine the region the client will need to repaint
121 GetUpdateRegion(aRegion
);
122 mUpdateRect
= aRegion
.GetBounds();
124 //printf_stderr("BeginUpdate with updateRect [%d %d %d %d]\n", mUpdateRect.x, mUpdateRect.y, mUpdateRect.width, mUpdateRect.height);
125 if (!nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize
)).Contains(mUpdateRect
)) {
126 NS_ERROR("update outside of image");
130 //printf_stderr("creating image surface %dx%d format %d\n", mUpdateRect.width, mUpdateRect.height, mUpdateFormat);
132 mUpdateDrawTarget
= gfx::Factory::CreateDrawTarget(gfx::BackendType::CAIRO
,
133 gfx::IntSize(mUpdateRect
.width
, mUpdateRect
.height
),
136 return mUpdateDrawTarget
;
140 TextureImageEGL::EndUpdate()
142 NS_ASSERTION(!!mUpdateDrawTarget
, "EndUpdate() without BeginUpdate()?");
144 //printf_stderr("EndUpdate: slow path");
146 // This is the slower path -- we didn't have any way to set up
147 // a fast mapping between our cairo target surface and the GL
148 // texture, so we have to upload data.
150 RefPtr
<gfx::SourceSurface
> updateSurface
= nullptr;
151 RefPtr
<gfx::DataSourceSurface
> uploadImage
= nullptr;
152 gfx::IntSize
updateSize(mUpdateRect
.width
, mUpdateRect
.height
);
154 NS_ASSERTION(mUpdateDrawTarget
->GetSize() == updateSize
,
155 "Upload image is the wrong size!");
157 updateSurface
= mUpdateDrawTarget
->Snapshot();
158 uploadImage
= updateSurface
->GetDataSurface();
164 mGLContext
->MakeCurrent();
165 mGLContext
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mTexture
);
167 if (mTextureState
!= Valid
) {
168 NS_ASSERTION(mUpdateRect
.x
== 0 && mUpdateRect
.y
== 0 &&
169 mUpdateRect
.Size() == gfx::ThebesIntSize(mSize
),
170 "Bad initial update on non-created texture!");
172 mGLContext
->fTexImage2D(LOCAL_GL_TEXTURE_2D
,
174 GLFormatForImage(mUpdateFormat
),
178 GLFormatForImage(uploadImage
->GetFormat()),
179 GLTypeForImage(uploadImage
->GetFormat()),
180 uploadImage
->GetData());
182 mGLContext
->fTexSubImage2D(LOCAL_GL_TEXTURE_2D
,
188 GLFormatForImage(uploadImage
->GetFormat()),
189 GLTypeForImage(uploadImage
->GetFormat()),
190 uploadImage
->GetData());
193 mUpdateDrawTarget
= nullptr;
194 mTextureState
= Valid
;
195 return; // mTexture is bound
199 TextureImageEGL::DirectUpdate(gfx::DataSourceSurface
* aSurf
, const nsIntRegion
& aRegion
, const gfx::IntPoint
& aFrom
/* = gfx::IntPoint(0,0) */)
201 nsIntRect bounds
= aRegion
.GetBounds();
204 if (mTextureState
!= Valid
) {
205 bounds
= nsIntRect(0, 0, mSize
.width
, mSize
.height
);
206 region
= nsIntRegion(bounds
);
212 UploadSurfaceToTexture(mGLContext
,
216 mTextureState
== Created
,
217 bounds
.TopLeft() + nsIntPoint(aFrom
.x
, aFrom
.y
),
220 mTextureState
= Valid
;
225 TextureImageEGL::BindTexture(GLenum aTextureUnit
)
227 // Ensure the texture is allocated before it is used.
228 if (mTextureState
== Created
) {
232 mGLContext
->fActiveTexture(aTextureUnit
);
233 mGLContext
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mTexture
);
234 mGLContext
->fActiveTexture(LOCAL_GL_TEXTURE0
);
238 TextureImageEGL::Resize(const gfx::IntSize
& aSize
)
240 NS_ASSERTION(!mUpdateDrawTarget
, "Resize() while in update?");
242 if (mSize
== aSize
&& mTextureState
!= Created
)
245 mGLContext
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mTexture
);
247 mGLContext
->fTexImage2D(LOCAL_GL_TEXTURE_2D
,
249 GLFormatForImage(mUpdateFormat
),
253 GLFormatForImage(mUpdateFormat
),
254 GLTypeForImage(mUpdateFormat
),
257 mTextureState
= Allocated
;
262 TextureImageEGL::BindTexImage()
264 if (mBound
&& !ReleaseTexImage())
268 sEGLLibrary
.fBindTexImage(EGL_DISPLAY(),
269 (EGLSurface
)mSurface
,
270 LOCAL_EGL_BACK_BUFFER
);
272 if (success
== LOCAL_EGL_FALSE
)
280 TextureImageEGL::ReleaseTexImage()
286 sEGLLibrary
.fReleaseTexImage(EGL_DISPLAY(),
287 (EGLSurface
)mSurface
,
288 LOCAL_EGL_BACK_BUFFER
);
290 if (success
== LOCAL_EGL_FALSE
)
298 TextureImageEGL::DestroyEGLSurface(void)
303 sEGLLibrary
.fDestroySurface(EGL_DISPLAY(), mSurface
);
307 already_AddRefed
<TextureImage
>
308 CreateTextureImageEGL(GLContext
*gl
,
309 const gfx::IntSize
& aSize
,
310 TextureImage::ContentType aContentType
,
312 TextureImage::Flags aFlags
,
313 TextureImage::ImageFormat aImageFormat
)
315 nsRefPtr
<TextureImage
> t
= new gl::TiledTextureImage(gl
, aSize
, aContentType
, aFlags
, aImageFormat
);
319 already_AddRefed
<TextureImage
>
320 TileGenFuncEGL(GLContext
*gl
,
321 const nsIntSize
& aSize
,
322 TextureImage::ContentType aContentType
,
323 TextureImage::Flags aFlags
,
324 TextureImage::ImageFormat aImageFormat
)
329 gl
->fGenTextures(1, &texture
);
331 nsRefPtr
<TextureImageEGL
> teximage
=
332 new TextureImageEGL(texture
, aSize
, LOCAL_GL_CLAMP_TO_EDGE
, aContentType
,
333 gl
, aFlags
, TextureImage::Created
, aImageFormat
);
335 teximage
->BindTexture(LOCAL_GL_TEXTURE0
);
337 GLint texfilter
= aFlags
& TextureImage::UseNearestFilter
? LOCAL_GL_NEAREST
: LOCAL_GL_LINEAR
;
338 gl
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_MIN_FILTER
, texfilter
);
339 gl
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_MAG_FILTER
, texfilter
);
340 gl
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_WRAP_S
, LOCAL_GL_CLAMP_TO_EDGE
);
341 gl
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_WRAP_T
, LOCAL_GL_CLAMP_TO_EDGE
);
343 return teximage
.forget();