Bumping manifests a=b2g-bump
[gecko.git] / gfx / gl / TextureImageEGL.cpp
blobfa18f67de2177ce903dd32b3639789dce63adb5d
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"
8 #include "GLContext.h"
9 #include "GLUploadHelpers.h"
10 #include "gfxPlatform.h"
11 #include "gfx2DGlue.h"
12 #include "mozilla/gfx/Types.h"
14 namespace mozilla {
15 namespace gl {
17 static GLenum
18 GLFormatForImage(gfx::SurfaceFormat aFormat)
20 switch (aFormat) {
21 case gfx::SurfaceFormat::B8G8R8A8:
22 case gfx::SurfaceFormat::B8G8R8X8:
23 return LOCAL_GL_RGBA;
24 case gfx::SurfaceFormat::R5G6B5:
25 return LOCAL_GL_RGB;
26 case gfx::SurfaceFormat::A8:
27 return LOCAL_GL_LUMINANCE;
28 default:
29 NS_WARNING("Unknown GL format for Surface format");
31 return 0;
34 static GLenum
35 GLTypeForImage(gfx::SurfaceFormat aFormat)
37 switch (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;
44 default:
45 NS_WARNING("Unknown GL format for Surface format");
47 return 0;
50 TextureImageEGL::TextureImageEGL(GLuint aTexture,
51 const nsIntSize& aSize,
52 GLenum aWrapMode,
53 ContentType aContentType,
54 GLContext* aContext,
55 Flags aFlags,
56 TextureState aTextureState,
57 TextureImage::ImageFormat aImageFormat)
58 : TextureImage(aSize, aWrapMode, aContentType, aFlags)
59 , mGLContext(aContext)
60 , mUpdateFormat(gfx::ImageFormatToSurfaceFormat(aImageFormat))
61 , mEGLImage(nullptr)
62 , mTexture(aTexture)
63 , mSurface(nullptr)
64 , mConfig(nullptr)
65 , mTextureState(aTextureState)
66 , mBound(false)
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;
77 } else {
78 mTextureFormat = gfx::SurfaceFormat::B8G8R8A8;
82 TextureImageEGL::~TextureImageEGL()
84 if (mGLContext->IsDestroyed() || !mGLContext->IsOwningThreadCurrent()) {
85 return;
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);
95 ReleaseTexImage();
96 DestroyEGLSurface();
99 void
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());
115 gfx::DrawTarget*
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");
127 return nullptr;
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),
134 mUpdateFormat);
136 return mUpdateDrawTarget;
139 void
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();
160 if (!uploadImage) {
161 return;
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),
175 mUpdateRect.width,
176 mUpdateRect.height,
178 GLFormatForImage(uploadImage->GetFormat()),
179 GLTypeForImage(uploadImage->GetFormat()),
180 uploadImage->GetData());
181 } else {
182 mGLContext->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
184 mUpdateRect.x,
185 mUpdateRect.y,
186 mUpdateRect.width,
187 mUpdateRect.height,
188 GLFormatForImage(uploadImage->GetFormat()),
189 GLTypeForImage(uploadImage->GetFormat()),
190 uploadImage->GetData());
193 mUpdateDrawTarget = nullptr;
194 mTextureState = Valid;
195 return; // mTexture is bound
198 bool
199 TextureImageEGL::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0,0) */)
201 nsIntRect bounds = aRegion.GetBounds();
203 nsIntRegion region;
204 if (mTextureState != Valid) {
205 bounds = nsIntRect(0, 0, mSize.width, mSize.height);
206 region = nsIntRegion(bounds);
207 } else {
208 region = aRegion;
211 mTextureFormat =
212 UploadSurfaceToTexture(mGLContext,
213 aSurf,
214 region,
215 mTexture,
216 mTextureState == Created,
217 bounds.TopLeft() + nsIntPoint(aFrom.x, aFrom.y),
218 false);
220 mTextureState = Valid;
221 return true;
224 void
225 TextureImageEGL::BindTexture(GLenum aTextureUnit)
227 // Ensure the texture is allocated before it is used.
228 if (mTextureState == Created) {
229 Resize(mSize);
232 mGLContext->fActiveTexture(aTextureUnit);
233 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
234 mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
237 void
238 TextureImageEGL::Resize(const gfx::IntSize& aSize)
240 NS_ASSERTION(!mUpdateDrawTarget, "Resize() while in update?");
242 if (mSize == aSize && mTextureState != Created)
243 return;
245 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
247 mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
249 GLFormatForImage(mUpdateFormat),
250 aSize.width,
251 aSize.height,
253 GLFormatForImage(mUpdateFormat),
254 GLTypeForImage(mUpdateFormat),
255 nullptr);
257 mTextureState = Allocated;
258 mSize = aSize;
261 bool
262 TextureImageEGL::BindTexImage()
264 if (mBound && !ReleaseTexImage())
265 return false;
267 EGLBoolean success =
268 sEGLLibrary.fBindTexImage(EGL_DISPLAY(),
269 (EGLSurface)mSurface,
270 LOCAL_EGL_BACK_BUFFER);
272 if (success == LOCAL_EGL_FALSE)
273 return false;
275 mBound = true;
276 return true;
279 bool
280 TextureImageEGL::ReleaseTexImage()
282 if (!mBound)
283 return true;
285 EGLBoolean success =
286 sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(),
287 (EGLSurface)mSurface,
288 LOCAL_EGL_BACK_BUFFER);
290 if (success == LOCAL_EGL_FALSE)
291 return false;
293 mBound = false;
294 return true;
297 void
298 TextureImageEGL::DestroyEGLSurface(void)
300 if (!mSurface)
301 return;
303 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
304 mSurface = nullptr;
307 already_AddRefed<TextureImage>
308 CreateTextureImageEGL(GLContext *gl,
309 const gfx::IntSize& aSize,
310 TextureImage::ContentType aContentType,
311 GLenum aWrapMode,
312 TextureImage::Flags aFlags,
313 TextureImage::ImageFormat aImageFormat)
315 nsRefPtr<TextureImage> t = new gl::TiledTextureImage(gl, aSize, aContentType, aFlags, aImageFormat);
316 return t.forget();
319 already_AddRefed<TextureImage>
320 TileGenFuncEGL(GLContext *gl,
321 const nsIntSize& aSize,
322 TextureImage::ContentType aContentType,
323 TextureImage::Flags aFlags,
324 TextureImage::ImageFormat aImageFormat)
326 gl->MakeCurrent();
328 GLuint texture;
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();