1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/gl/TextureImageEGL.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,346 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "TextureImageEGL.h" 1.10 +#include "GLLibraryEGL.h" 1.11 +#include "GLContext.h" 1.12 +#include "GLUploadHelpers.h" 1.13 +#include "gfxPlatform.h" 1.14 +#include "gfx2DGlue.h" 1.15 +#include "mozilla/gfx/Types.h" 1.16 + 1.17 +namespace mozilla { 1.18 +namespace gl { 1.19 + 1.20 +static GLenum 1.21 +GLFormatForImage(gfx::SurfaceFormat aFormat) 1.22 +{ 1.23 + switch (aFormat) { 1.24 + case gfx::SurfaceFormat::B8G8R8A8: 1.25 + case gfx::SurfaceFormat::B8G8R8X8: 1.26 + return LOCAL_GL_RGBA; 1.27 + case gfx::SurfaceFormat::R5G6B5: 1.28 + return LOCAL_GL_RGB; 1.29 + case gfx::SurfaceFormat::A8: 1.30 + return LOCAL_GL_LUMINANCE; 1.31 + default: 1.32 + NS_WARNING("Unknown GL format for Surface format"); 1.33 + } 1.34 + return 0; 1.35 +} 1.36 + 1.37 +static GLenum 1.38 +GLTypeForImage(gfx::SurfaceFormat aFormat) 1.39 +{ 1.40 + switch (aFormat) { 1.41 + case gfx::SurfaceFormat::B8G8R8A8: 1.42 + case gfx::SurfaceFormat::B8G8R8X8: 1.43 + case gfx::SurfaceFormat::A8: 1.44 + return LOCAL_GL_UNSIGNED_BYTE; 1.45 + case gfx::SurfaceFormat::R5G6B5: 1.46 + return LOCAL_GL_UNSIGNED_SHORT_5_6_5; 1.47 + default: 1.48 + NS_WARNING("Unknown GL format for Surface format"); 1.49 + } 1.50 + return 0; 1.51 +} 1.52 + 1.53 +TextureImageEGL::TextureImageEGL(GLuint aTexture, 1.54 + const nsIntSize& aSize, 1.55 + GLenum aWrapMode, 1.56 + ContentType aContentType, 1.57 + GLContext* aContext, 1.58 + Flags aFlags, 1.59 + TextureState aTextureState, 1.60 + TextureImage::ImageFormat aImageFormat) 1.61 + : TextureImage(aSize, aWrapMode, aContentType, aFlags) 1.62 + , mGLContext(aContext) 1.63 + , mUpdateFormat(gfx::ImageFormatToSurfaceFormat(aImageFormat)) 1.64 + , mEGLImage(nullptr) 1.65 + , mTexture(aTexture) 1.66 + , mSurface(nullptr) 1.67 + , mConfig(nullptr) 1.68 + , mTextureState(aTextureState) 1.69 + , mBound(false) 1.70 +{ 1.71 + if (mUpdateFormat == gfx::SurfaceFormat::UNKNOWN) { 1.72 + mUpdateFormat = gfx::ImageFormatToSurfaceFormat( 1.73 + gfxPlatform::GetPlatform()->OptimalFormatForContent(GetContentType())); 1.74 + } 1.75 + 1.76 + if (mUpdateFormat == gfx::SurfaceFormat::R5G6B5) { 1.77 + mTextureFormat = gfx::SurfaceFormat::R8G8B8X8; 1.78 + } else if (mUpdateFormat == gfx::SurfaceFormat::B8G8R8X8) { 1.79 + mTextureFormat = gfx::SurfaceFormat::B8G8R8X8; 1.80 + } else { 1.81 + mTextureFormat = gfx::SurfaceFormat::B8G8R8A8; 1.82 + } 1.83 +} 1.84 + 1.85 +TextureImageEGL::~TextureImageEGL() 1.86 +{ 1.87 + if (mGLContext->IsDestroyed() || !mGLContext->IsOwningThreadCurrent()) { 1.88 + return; 1.89 + } 1.90 + 1.91 + // If we have a context, then we need to delete the texture; 1.92 + // if we don't have a context (either real or shared), 1.93 + // then they went away when the contex was deleted, because it 1.94 + // was the only one that had access to it. 1.95 + mGLContext->MakeCurrent(); 1.96 + mGLContext->fDeleteTextures(1, &mTexture); 1.97 + ReleaseTexImage(); 1.98 + DestroyEGLSurface(); 1.99 +} 1.100 + 1.101 +void 1.102 +TextureImageEGL::GetUpdateRegion(nsIntRegion& aForRegion) 1.103 +{ 1.104 + if (mTextureState != Valid) { 1.105 + // if the texture hasn't been initialized yet, force the 1.106 + // client to paint everything 1.107 + aForRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize)); 1.108 + } 1.109 + 1.110 + // We can only draw a rectangle, not subregions due to 1.111 + // the way that our texture upload functions work. If 1.112 + // needed, we /could/ do multiple texture uploads if we have 1.113 + // non-overlapping rects, but that's a tradeoff. 1.114 + aForRegion = nsIntRegion(aForRegion.GetBounds()); 1.115 +} 1.116 + 1.117 +gfx::DrawTarget* 1.118 +TextureImageEGL::BeginUpdate(nsIntRegion& aRegion) 1.119 +{ 1.120 + NS_ASSERTION(!mUpdateDrawTarget, "BeginUpdate() without EndUpdate()?"); 1.121 + 1.122 + // determine the region the client will need to repaint 1.123 + GetUpdateRegion(aRegion); 1.124 + mUpdateRect = aRegion.GetBounds(); 1.125 + 1.126 + //printf_stderr("BeginUpdate with updateRect [%d %d %d %d]\n", mUpdateRect.x, mUpdateRect.y, mUpdateRect.width, mUpdateRect.height); 1.127 + if (!nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize)).Contains(mUpdateRect)) { 1.128 + NS_ERROR("update outside of image"); 1.129 + return nullptr; 1.130 + } 1.131 + 1.132 + //printf_stderr("creating image surface %dx%d format %d\n", mUpdateRect.width, mUpdateRect.height, mUpdateFormat); 1.133 + 1.134 + mUpdateDrawTarget = gfx::Factory::CreateDrawTarget(gfx::BackendType::CAIRO, 1.135 + gfx::IntSize(mUpdateRect.width, mUpdateRect.height), 1.136 + mUpdateFormat); 1.137 + 1.138 + return mUpdateDrawTarget; 1.139 +} 1.140 + 1.141 +void 1.142 +TextureImageEGL::EndUpdate() 1.143 +{ 1.144 + NS_ASSERTION(!!mUpdateDrawTarget, "EndUpdate() without BeginUpdate()?"); 1.145 + 1.146 + //printf_stderr("EndUpdate: slow path"); 1.147 + 1.148 + // This is the slower path -- we didn't have any way to set up 1.149 + // a fast mapping between our cairo target surface and the GL 1.150 + // texture, so we have to upload data. 1.151 + 1.152 + RefPtr<gfx::SourceSurface> updateSurface = nullptr; 1.153 + RefPtr<gfx::DataSourceSurface> uploadImage = nullptr; 1.154 + gfx::IntSize updateSize(mUpdateRect.width, mUpdateRect.height); 1.155 + 1.156 + NS_ASSERTION(mUpdateDrawTarget->GetSize() == updateSize, 1.157 + "Upload image is the wrong size!"); 1.158 + 1.159 + updateSurface = mUpdateDrawTarget->Snapshot(); 1.160 + uploadImage = updateSurface->GetDataSurface(); 1.161 + 1.162 + if (!uploadImage) { 1.163 + return; 1.164 + } 1.165 + 1.166 + mGLContext->MakeCurrent(); 1.167 + mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); 1.168 + 1.169 + if (mTextureState != Valid) { 1.170 + NS_ASSERTION(mUpdateRect.x == 0 && mUpdateRect.y == 0 && 1.171 + mUpdateRect.Size() == gfx::ThebesIntSize(mSize), 1.172 + "Bad initial update on non-created texture!"); 1.173 + 1.174 + mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 1.175 + 0, 1.176 + GLFormatForImage(mUpdateFormat), 1.177 + mUpdateRect.width, 1.178 + mUpdateRect.height, 1.179 + 0, 1.180 + GLFormatForImage(uploadImage->GetFormat()), 1.181 + GLTypeForImage(uploadImage->GetFormat()), 1.182 + uploadImage->GetData()); 1.183 + } else { 1.184 + mGLContext->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 1.185 + 0, 1.186 + mUpdateRect.x, 1.187 + mUpdateRect.y, 1.188 + mUpdateRect.width, 1.189 + mUpdateRect.height, 1.190 + GLFormatForImage(uploadImage->GetFormat()), 1.191 + GLTypeForImage(uploadImage->GetFormat()), 1.192 + uploadImage->GetData()); 1.193 + } 1.194 + 1.195 + mUpdateDrawTarget = nullptr; 1.196 + mTextureState = Valid; 1.197 + return; // mTexture is bound 1.198 +} 1.199 + 1.200 +bool 1.201 +TextureImageEGL::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0,0) */) 1.202 +{ 1.203 + nsIntRect bounds = aRegion.GetBounds(); 1.204 + 1.205 + nsIntRegion region; 1.206 + if (mTextureState != Valid) { 1.207 + bounds = nsIntRect(0, 0, mSize.width, mSize.height); 1.208 + region = nsIntRegion(bounds); 1.209 + } else { 1.210 + region = aRegion; 1.211 + } 1.212 + 1.213 + mTextureFormat = 1.214 + UploadSurfaceToTexture(mGLContext, 1.215 + aSurf, 1.216 + region, 1.217 + mTexture, 1.218 + mTextureState == Created, 1.219 + bounds.TopLeft() + nsIntPoint(aFrom.x, aFrom.y), 1.220 + false); 1.221 + 1.222 + mTextureState = Valid; 1.223 + return true; 1.224 +} 1.225 + 1.226 +void 1.227 +TextureImageEGL::BindTexture(GLenum aTextureUnit) 1.228 +{ 1.229 + // Ensure the texture is allocated before it is used. 1.230 + if (mTextureState == Created) { 1.231 + Resize(mSize); 1.232 + } 1.233 + 1.234 + mGLContext->fActiveTexture(aTextureUnit); 1.235 + mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); 1.236 + mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); 1.237 +} 1.238 + 1.239 +void 1.240 +TextureImageEGL::Resize(const gfx::IntSize& aSize) 1.241 +{ 1.242 + NS_ASSERTION(!mUpdateDrawTarget, "Resize() while in update?"); 1.243 + 1.244 + if (mSize == aSize && mTextureState != Created) 1.245 + return; 1.246 + 1.247 + mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); 1.248 + 1.249 + mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 1.250 + 0, 1.251 + GLFormatForImage(mUpdateFormat), 1.252 + aSize.width, 1.253 + aSize.height, 1.254 + 0, 1.255 + GLFormatForImage(mUpdateFormat), 1.256 + GLTypeForImage(mUpdateFormat), 1.257 + nullptr); 1.258 + 1.259 + mTextureState = Allocated; 1.260 + mSize = aSize; 1.261 +} 1.262 + 1.263 +bool 1.264 +TextureImageEGL::BindTexImage() 1.265 +{ 1.266 + if (mBound && !ReleaseTexImage()) 1.267 + return false; 1.268 + 1.269 + EGLBoolean success = 1.270 + sEGLLibrary.fBindTexImage(EGL_DISPLAY(), 1.271 + (EGLSurface)mSurface, 1.272 + LOCAL_EGL_BACK_BUFFER); 1.273 + 1.274 + if (success == LOCAL_EGL_FALSE) 1.275 + return false; 1.276 + 1.277 + mBound = true; 1.278 + return true; 1.279 +} 1.280 + 1.281 +bool 1.282 +TextureImageEGL::ReleaseTexImage() 1.283 +{ 1.284 + if (!mBound) 1.285 + return true; 1.286 + 1.287 + EGLBoolean success = 1.288 + sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(), 1.289 + (EGLSurface)mSurface, 1.290 + LOCAL_EGL_BACK_BUFFER); 1.291 + 1.292 + if (success == LOCAL_EGL_FALSE) 1.293 + return false; 1.294 + 1.295 + mBound = false; 1.296 + return true; 1.297 +} 1.298 + 1.299 +void 1.300 +TextureImageEGL::DestroyEGLSurface(void) 1.301 +{ 1.302 + if (!mSurface) 1.303 + return; 1.304 + 1.305 + sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface); 1.306 + mSurface = nullptr; 1.307 +} 1.308 + 1.309 +already_AddRefed<TextureImage> 1.310 +CreateTextureImageEGL(GLContext *gl, 1.311 + const gfx::IntSize& aSize, 1.312 + TextureImage::ContentType aContentType, 1.313 + GLenum aWrapMode, 1.314 + TextureImage::Flags aFlags, 1.315 + TextureImage::ImageFormat aImageFormat) 1.316 +{ 1.317 + nsRefPtr<TextureImage> t = new gl::TiledTextureImage(gl, aSize, aContentType, aFlags, aImageFormat); 1.318 + return t.forget(); 1.319 +} 1.320 + 1.321 +already_AddRefed<TextureImage> 1.322 +TileGenFuncEGL(GLContext *gl, 1.323 + const nsIntSize& aSize, 1.324 + TextureImage::ContentType aContentType, 1.325 + TextureImage::Flags aFlags, 1.326 + TextureImage::ImageFormat aImageFormat) 1.327 +{ 1.328 + gl->MakeCurrent(); 1.329 + 1.330 + GLuint texture; 1.331 + gl->fGenTextures(1, &texture); 1.332 + 1.333 + nsRefPtr<TextureImageEGL> teximage = 1.334 + new TextureImageEGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, 1.335 + gl, aFlags, TextureImage::Created, aImageFormat); 1.336 + 1.337 + teximage->BindTexture(LOCAL_GL_TEXTURE0); 1.338 + 1.339 + GLint texfilter = aFlags & TextureImage::UseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR; 1.340 + gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter); 1.341 + gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter); 1.342 + gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); 1.343 + gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); 1.344 + 1.345 + return teximage.forget(); 1.346 +} 1.347 + 1.348 +} 1.349 +}