gfx/gl/TextureImageEGL.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "TextureImageEGL.h"
michael@0 7 #include "GLLibraryEGL.h"
michael@0 8 #include "GLContext.h"
michael@0 9 #include "GLUploadHelpers.h"
michael@0 10 #include "gfxPlatform.h"
michael@0 11 #include "gfx2DGlue.h"
michael@0 12 #include "mozilla/gfx/Types.h"
michael@0 13
michael@0 14 namespace mozilla {
michael@0 15 namespace gl {
michael@0 16
michael@0 17 static GLenum
michael@0 18 GLFormatForImage(gfx::SurfaceFormat aFormat)
michael@0 19 {
michael@0 20 switch (aFormat) {
michael@0 21 case gfx::SurfaceFormat::B8G8R8A8:
michael@0 22 case gfx::SurfaceFormat::B8G8R8X8:
michael@0 23 return LOCAL_GL_RGBA;
michael@0 24 case gfx::SurfaceFormat::R5G6B5:
michael@0 25 return LOCAL_GL_RGB;
michael@0 26 case gfx::SurfaceFormat::A8:
michael@0 27 return LOCAL_GL_LUMINANCE;
michael@0 28 default:
michael@0 29 NS_WARNING("Unknown GL format for Surface format");
michael@0 30 }
michael@0 31 return 0;
michael@0 32 }
michael@0 33
michael@0 34 static GLenum
michael@0 35 GLTypeForImage(gfx::SurfaceFormat aFormat)
michael@0 36 {
michael@0 37 switch (aFormat) {
michael@0 38 case gfx::SurfaceFormat::B8G8R8A8:
michael@0 39 case gfx::SurfaceFormat::B8G8R8X8:
michael@0 40 case gfx::SurfaceFormat::A8:
michael@0 41 return LOCAL_GL_UNSIGNED_BYTE;
michael@0 42 case gfx::SurfaceFormat::R5G6B5:
michael@0 43 return LOCAL_GL_UNSIGNED_SHORT_5_6_5;
michael@0 44 default:
michael@0 45 NS_WARNING("Unknown GL format for Surface format");
michael@0 46 }
michael@0 47 return 0;
michael@0 48 }
michael@0 49
michael@0 50 TextureImageEGL::TextureImageEGL(GLuint aTexture,
michael@0 51 const nsIntSize& aSize,
michael@0 52 GLenum aWrapMode,
michael@0 53 ContentType aContentType,
michael@0 54 GLContext* aContext,
michael@0 55 Flags aFlags,
michael@0 56 TextureState aTextureState,
michael@0 57 TextureImage::ImageFormat aImageFormat)
michael@0 58 : TextureImage(aSize, aWrapMode, aContentType, aFlags)
michael@0 59 , mGLContext(aContext)
michael@0 60 , mUpdateFormat(gfx::ImageFormatToSurfaceFormat(aImageFormat))
michael@0 61 , mEGLImage(nullptr)
michael@0 62 , mTexture(aTexture)
michael@0 63 , mSurface(nullptr)
michael@0 64 , mConfig(nullptr)
michael@0 65 , mTextureState(aTextureState)
michael@0 66 , mBound(false)
michael@0 67 {
michael@0 68 if (mUpdateFormat == gfx::SurfaceFormat::UNKNOWN) {
michael@0 69 mUpdateFormat = gfx::ImageFormatToSurfaceFormat(
michael@0 70 gfxPlatform::GetPlatform()->OptimalFormatForContent(GetContentType()));
michael@0 71 }
michael@0 72
michael@0 73 if (mUpdateFormat == gfx::SurfaceFormat::R5G6B5) {
michael@0 74 mTextureFormat = gfx::SurfaceFormat::R8G8B8X8;
michael@0 75 } else if (mUpdateFormat == gfx::SurfaceFormat::B8G8R8X8) {
michael@0 76 mTextureFormat = gfx::SurfaceFormat::B8G8R8X8;
michael@0 77 } else {
michael@0 78 mTextureFormat = gfx::SurfaceFormat::B8G8R8A8;
michael@0 79 }
michael@0 80 }
michael@0 81
michael@0 82 TextureImageEGL::~TextureImageEGL()
michael@0 83 {
michael@0 84 if (mGLContext->IsDestroyed() || !mGLContext->IsOwningThreadCurrent()) {
michael@0 85 return;
michael@0 86 }
michael@0 87
michael@0 88 // If we have a context, then we need to delete the texture;
michael@0 89 // if we don't have a context (either real or shared),
michael@0 90 // then they went away when the contex was deleted, because it
michael@0 91 // was the only one that had access to it.
michael@0 92 mGLContext->MakeCurrent();
michael@0 93 mGLContext->fDeleteTextures(1, &mTexture);
michael@0 94 ReleaseTexImage();
michael@0 95 DestroyEGLSurface();
michael@0 96 }
michael@0 97
michael@0 98 void
michael@0 99 TextureImageEGL::GetUpdateRegion(nsIntRegion& aForRegion)
michael@0 100 {
michael@0 101 if (mTextureState != Valid) {
michael@0 102 // if the texture hasn't been initialized yet, force the
michael@0 103 // client to paint everything
michael@0 104 aForRegion = nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize));
michael@0 105 }
michael@0 106
michael@0 107 // We can only draw a rectangle, not subregions due to
michael@0 108 // the way that our texture upload functions work. If
michael@0 109 // needed, we /could/ do multiple texture uploads if we have
michael@0 110 // non-overlapping rects, but that's a tradeoff.
michael@0 111 aForRegion = nsIntRegion(aForRegion.GetBounds());
michael@0 112 }
michael@0 113
michael@0 114 gfx::DrawTarget*
michael@0 115 TextureImageEGL::BeginUpdate(nsIntRegion& aRegion)
michael@0 116 {
michael@0 117 NS_ASSERTION(!mUpdateDrawTarget, "BeginUpdate() without EndUpdate()?");
michael@0 118
michael@0 119 // determine the region the client will need to repaint
michael@0 120 GetUpdateRegion(aRegion);
michael@0 121 mUpdateRect = aRegion.GetBounds();
michael@0 122
michael@0 123 //printf_stderr("BeginUpdate with updateRect [%d %d %d %d]\n", mUpdateRect.x, mUpdateRect.y, mUpdateRect.width, mUpdateRect.height);
michael@0 124 if (!nsIntRect(nsIntPoint(0, 0), gfx::ThebesIntSize(mSize)).Contains(mUpdateRect)) {
michael@0 125 NS_ERROR("update outside of image");
michael@0 126 return nullptr;
michael@0 127 }
michael@0 128
michael@0 129 //printf_stderr("creating image surface %dx%d format %d\n", mUpdateRect.width, mUpdateRect.height, mUpdateFormat);
michael@0 130
michael@0 131 mUpdateDrawTarget = gfx::Factory::CreateDrawTarget(gfx::BackendType::CAIRO,
michael@0 132 gfx::IntSize(mUpdateRect.width, mUpdateRect.height),
michael@0 133 mUpdateFormat);
michael@0 134
michael@0 135 return mUpdateDrawTarget;
michael@0 136 }
michael@0 137
michael@0 138 void
michael@0 139 TextureImageEGL::EndUpdate()
michael@0 140 {
michael@0 141 NS_ASSERTION(!!mUpdateDrawTarget, "EndUpdate() without BeginUpdate()?");
michael@0 142
michael@0 143 //printf_stderr("EndUpdate: slow path");
michael@0 144
michael@0 145 // This is the slower path -- we didn't have any way to set up
michael@0 146 // a fast mapping between our cairo target surface and the GL
michael@0 147 // texture, so we have to upload data.
michael@0 148
michael@0 149 RefPtr<gfx::SourceSurface> updateSurface = nullptr;
michael@0 150 RefPtr<gfx::DataSourceSurface> uploadImage = nullptr;
michael@0 151 gfx::IntSize updateSize(mUpdateRect.width, mUpdateRect.height);
michael@0 152
michael@0 153 NS_ASSERTION(mUpdateDrawTarget->GetSize() == updateSize,
michael@0 154 "Upload image is the wrong size!");
michael@0 155
michael@0 156 updateSurface = mUpdateDrawTarget->Snapshot();
michael@0 157 uploadImage = updateSurface->GetDataSurface();
michael@0 158
michael@0 159 if (!uploadImage) {
michael@0 160 return;
michael@0 161 }
michael@0 162
michael@0 163 mGLContext->MakeCurrent();
michael@0 164 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
michael@0 165
michael@0 166 if (mTextureState != Valid) {
michael@0 167 NS_ASSERTION(mUpdateRect.x == 0 && mUpdateRect.y == 0 &&
michael@0 168 mUpdateRect.Size() == gfx::ThebesIntSize(mSize),
michael@0 169 "Bad initial update on non-created texture!");
michael@0 170
michael@0 171 mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
michael@0 172 0,
michael@0 173 GLFormatForImage(mUpdateFormat),
michael@0 174 mUpdateRect.width,
michael@0 175 mUpdateRect.height,
michael@0 176 0,
michael@0 177 GLFormatForImage(uploadImage->GetFormat()),
michael@0 178 GLTypeForImage(uploadImage->GetFormat()),
michael@0 179 uploadImage->GetData());
michael@0 180 } else {
michael@0 181 mGLContext->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
michael@0 182 0,
michael@0 183 mUpdateRect.x,
michael@0 184 mUpdateRect.y,
michael@0 185 mUpdateRect.width,
michael@0 186 mUpdateRect.height,
michael@0 187 GLFormatForImage(uploadImage->GetFormat()),
michael@0 188 GLTypeForImage(uploadImage->GetFormat()),
michael@0 189 uploadImage->GetData());
michael@0 190 }
michael@0 191
michael@0 192 mUpdateDrawTarget = nullptr;
michael@0 193 mTextureState = Valid;
michael@0 194 return; // mTexture is bound
michael@0 195 }
michael@0 196
michael@0 197 bool
michael@0 198 TextureImageEGL::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0,0) */)
michael@0 199 {
michael@0 200 nsIntRect bounds = aRegion.GetBounds();
michael@0 201
michael@0 202 nsIntRegion region;
michael@0 203 if (mTextureState != Valid) {
michael@0 204 bounds = nsIntRect(0, 0, mSize.width, mSize.height);
michael@0 205 region = nsIntRegion(bounds);
michael@0 206 } else {
michael@0 207 region = aRegion;
michael@0 208 }
michael@0 209
michael@0 210 mTextureFormat =
michael@0 211 UploadSurfaceToTexture(mGLContext,
michael@0 212 aSurf,
michael@0 213 region,
michael@0 214 mTexture,
michael@0 215 mTextureState == Created,
michael@0 216 bounds.TopLeft() + nsIntPoint(aFrom.x, aFrom.y),
michael@0 217 false);
michael@0 218
michael@0 219 mTextureState = Valid;
michael@0 220 return true;
michael@0 221 }
michael@0 222
michael@0 223 void
michael@0 224 TextureImageEGL::BindTexture(GLenum aTextureUnit)
michael@0 225 {
michael@0 226 // Ensure the texture is allocated before it is used.
michael@0 227 if (mTextureState == Created) {
michael@0 228 Resize(mSize);
michael@0 229 }
michael@0 230
michael@0 231 mGLContext->fActiveTexture(aTextureUnit);
michael@0 232 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
michael@0 233 mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
michael@0 234 }
michael@0 235
michael@0 236 void
michael@0 237 TextureImageEGL::Resize(const gfx::IntSize& aSize)
michael@0 238 {
michael@0 239 NS_ASSERTION(!mUpdateDrawTarget, "Resize() while in update?");
michael@0 240
michael@0 241 if (mSize == aSize && mTextureState != Created)
michael@0 242 return;
michael@0 243
michael@0 244 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
michael@0 245
michael@0 246 mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
michael@0 247 0,
michael@0 248 GLFormatForImage(mUpdateFormat),
michael@0 249 aSize.width,
michael@0 250 aSize.height,
michael@0 251 0,
michael@0 252 GLFormatForImage(mUpdateFormat),
michael@0 253 GLTypeForImage(mUpdateFormat),
michael@0 254 nullptr);
michael@0 255
michael@0 256 mTextureState = Allocated;
michael@0 257 mSize = aSize;
michael@0 258 }
michael@0 259
michael@0 260 bool
michael@0 261 TextureImageEGL::BindTexImage()
michael@0 262 {
michael@0 263 if (mBound && !ReleaseTexImage())
michael@0 264 return false;
michael@0 265
michael@0 266 EGLBoolean success =
michael@0 267 sEGLLibrary.fBindTexImage(EGL_DISPLAY(),
michael@0 268 (EGLSurface)mSurface,
michael@0 269 LOCAL_EGL_BACK_BUFFER);
michael@0 270
michael@0 271 if (success == LOCAL_EGL_FALSE)
michael@0 272 return false;
michael@0 273
michael@0 274 mBound = true;
michael@0 275 return true;
michael@0 276 }
michael@0 277
michael@0 278 bool
michael@0 279 TextureImageEGL::ReleaseTexImage()
michael@0 280 {
michael@0 281 if (!mBound)
michael@0 282 return true;
michael@0 283
michael@0 284 EGLBoolean success =
michael@0 285 sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(),
michael@0 286 (EGLSurface)mSurface,
michael@0 287 LOCAL_EGL_BACK_BUFFER);
michael@0 288
michael@0 289 if (success == LOCAL_EGL_FALSE)
michael@0 290 return false;
michael@0 291
michael@0 292 mBound = false;
michael@0 293 return true;
michael@0 294 }
michael@0 295
michael@0 296 void
michael@0 297 TextureImageEGL::DestroyEGLSurface(void)
michael@0 298 {
michael@0 299 if (!mSurface)
michael@0 300 return;
michael@0 301
michael@0 302 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
michael@0 303 mSurface = nullptr;
michael@0 304 }
michael@0 305
michael@0 306 already_AddRefed<TextureImage>
michael@0 307 CreateTextureImageEGL(GLContext *gl,
michael@0 308 const gfx::IntSize& aSize,
michael@0 309 TextureImage::ContentType aContentType,
michael@0 310 GLenum aWrapMode,
michael@0 311 TextureImage::Flags aFlags,
michael@0 312 TextureImage::ImageFormat aImageFormat)
michael@0 313 {
michael@0 314 nsRefPtr<TextureImage> t = new gl::TiledTextureImage(gl, aSize, aContentType, aFlags, aImageFormat);
michael@0 315 return t.forget();
michael@0 316 }
michael@0 317
michael@0 318 already_AddRefed<TextureImage>
michael@0 319 TileGenFuncEGL(GLContext *gl,
michael@0 320 const nsIntSize& aSize,
michael@0 321 TextureImage::ContentType aContentType,
michael@0 322 TextureImage::Flags aFlags,
michael@0 323 TextureImage::ImageFormat aImageFormat)
michael@0 324 {
michael@0 325 gl->MakeCurrent();
michael@0 326
michael@0 327 GLuint texture;
michael@0 328 gl->fGenTextures(1, &texture);
michael@0 329
michael@0 330 nsRefPtr<TextureImageEGL> teximage =
michael@0 331 new TextureImageEGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType,
michael@0 332 gl, aFlags, TextureImage::Created, aImageFormat);
michael@0 333
michael@0 334 teximage->BindTexture(LOCAL_GL_TEXTURE0);
michael@0 335
michael@0 336 GLint texfilter = aFlags & TextureImage::UseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
michael@0 337 gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
michael@0 338 gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
michael@0 339 gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
michael@0 340 gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
michael@0 341
michael@0 342 return teximage.forget();
michael@0 343 }
michael@0 344
michael@0 345 }
michael@0 346 }

mercurial