Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
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 "CompositorOGL.h" |
michael@0 | 7 | #include <stddef.h> // for size_t |
michael@0 | 8 | #include <stdint.h> // for uint32_t, uint8_t |
michael@0 | 9 | #include <stdlib.h> // for free, malloc |
michael@0 | 10 | #include "GLContextProvider.h" // for GLContextProvider |
michael@0 | 11 | #include "GLContext.h" // for GLContext |
michael@0 | 12 | #include "GLUploadHelpers.h" |
michael@0 | 13 | #include "Layers.h" // for WriteSnapshotToDumpFile |
michael@0 | 14 | #include "LayerScope.h" // for LayerScope |
michael@0 | 15 | #include "gfx2DGlue.h" // for ThebesFilter |
michael@0 | 16 | #include "gfx3DMatrix.h" // for gfx3DMatrix |
michael@0 | 17 | #include "gfxCrashReporterUtils.h" // for ScopedGfxFeatureReporter |
michael@0 | 18 | #include "gfxImageSurface.h" // for gfxImageSurface |
michael@0 | 19 | #include "gfxMatrix.h" // for gfxMatrix |
michael@0 | 20 | #include "GraphicsFilter.h" // for GraphicsFilter |
michael@0 | 21 | #include "gfxPlatform.h" // for gfxPlatform |
michael@0 | 22 | #include "gfxPrefs.h" // for gfxPrefs |
michael@0 | 23 | #include "gfxRect.h" // for gfxRect |
michael@0 | 24 | #include "gfxUtils.h" // for NextPowerOfTwo, gfxUtils, etc |
michael@0 | 25 | #include "mozilla/ArrayUtils.h" // for ArrayLength |
michael@0 | 26 | #include "mozilla/Preferences.h" // for Preferences |
michael@0 | 27 | #include "mozilla/gfx/BasePoint.h" // for BasePoint |
michael@0 | 28 | #include "mozilla/gfx/Matrix.h" // for Matrix4x4, Matrix |
michael@0 | 29 | #include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite, etc |
michael@0 | 30 | #include "mozilla/layers/CompositingRenderTargetOGL.h" |
michael@0 | 31 | #include "mozilla/layers/Effects.h" // for EffectChain, TexturedEffect, etc |
michael@0 | 32 | #include "mozilla/layers/TextureHost.h" // for TextureSource, etc |
michael@0 | 33 | #include "mozilla/layers/TextureHostOGL.h" // for TextureSourceOGL, etc |
michael@0 | 34 | #include "mozilla/mozalloc.h" // for operator delete, etc |
michael@0 | 35 | #include "nsAString.h" |
michael@0 | 36 | #include "nsIConsoleService.h" // for nsIConsoleService, etc |
michael@0 | 37 | #include "nsIWidget.h" // for nsIWidget |
michael@0 | 38 | #include "nsLiteralString.h" // for NS_LITERAL_STRING |
michael@0 | 39 | #include "nsMathUtils.h" // for NS_roundf |
michael@0 | 40 | #include "nsRect.h" // for nsIntRect |
michael@0 | 41 | #include "nsServiceManagerUtils.h" // for do_GetService |
michael@0 | 42 | #include "nsString.h" // for nsString, nsAutoCString, etc |
michael@0 | 43 | #include "DecomposeIntoNoRepeatTriangles.h" |
michael@0 | 44 | #include "ScopedGLHelpers.h" |
michael@0 | 45 | #include "GLReadTexImageHelper.h" |
michael@0 | 46 | #include "TiledLayerBuffer.h" // for TiledLayerComposer |
michael@0 | 47 | |
michael@0 | 48 | #if MOZ_ANDROID_OMTC |
michael@0 | 49 | #include "TexturePoolOGL.h" |
michael@0 | 50 | #endif |
michael@0 | 51 | |
michael@0 | 52 | #ifdef XP_MACOSX |
michael@0 | 53 | #include "nsCocoaFeatures.h" |
michael@0 | 54 | #endif |
michael@0 | 55 | |
michael@0 | 56 | #include "GeckoProfiler.h" |
michael@0 | 57 | |
michael@0 | 58 | #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 |
michael@0 | 59 | #include "libdisplay/GonkDisplay.h" // for GonkDisplay |
michael@0 | 60 | #include <ui/Fence.h> |
michael@0 | 61 | #endif |
michael@0 | 62 | |
michael@0 | 63 | #define BUFFER_OFFSET(i) ((char *)nullptr + (i)) |
michael@0 | 64 | |
michael@0 | 65 | namespace mozilla { |
michael@0 | 66 | |
michael@0 | 67 | using namespace std; |
michael@0 | 68 | using namespace gfx; |
michael@0 | 69 | |
michael@0 | 70 | namespace layers { |
michael@0 | 71 | |
michael@0 | 72 | using namespace mozilla::gl; |
michael@0 | 73 | |
michael@0 | 74 | static inline IntSize ns2gfxSize(const nsIntSize& s) { |
michael@0 | 75 | return IntSize(s.width, s.height); |
michael@0 | 76 | } |
michael@0 | 77 | |
michael@0 | 78 | static void |
michael@0 | 79 | BindMaskForProgram(ShaderProgramOGL* aProgram, TextureSourceOGL* aSourceMask, |
michael@0 | 80 | GLenum aTexUnit, const gfx::Matrix4x4& aTransform) |
michael@0 | 81 | { |
michael@0 | 82 | MOZ_ASSERT(LOCAL_GL_TEXTURE0 <= aTexUnit && aTexUnit <= LOCAL_GL_TEXTURE31); |
michael@0 | 83 | aSourceMask->BindTexture(aTexUnit, gfx::Filter::LINEAR); |
michael@0 | 84 | aProgram->SetMaskTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0); |
michael@0 | 85 | aProgram->SetMaskLayerTransform(aTransform); |
michael@0 | 86 | } |
michael@0 | 87 | |
michael@0 | 88 | // Draw the given quads with the already selected shader. Texture coordinates |
michael@0 | 89 | // are supplied if the shader requires them. |
michael@0 | 90 | static void |
michael@0 | 91 | DrawQuads(GLContext *aGLContext, |
michael@0 | 92 | VBOArena &aVBOs, |
michael@0 | 93 | ShaderProgramOGL *aProg, |
michael@0 | 94 | GLenum aMode, |
michael@0 | 95 | RectTriangles &aRects) |
michael@0 | 96 | { |
michael@0 | 97 | NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized"); |
michael@0 | 98 | GLuint vertAttribIndex = |
michael@0 | 99 | aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib); |
michael@0 | 100 | GLuint texCoordAttribIndex = |
michael@0 | 101 | aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib); |
michael@0 | 102 | bool texCoords = (texCoordAttribIndex != GLuint(-1)); |
michael@0 | 103 | |
michael@0 | 104 | GLsizei bytes = aRects.elements() * 2 * sizeof(GLfloat); |
michael@0 | 105 | |
michael@0 | 106 | GLsizei total = bytes; |
michael@0 | 107 | if (texCoords) { |
michael@0 | 108 | total *= 2; |
michael@0 | 109 | } |
michael@0 | 110 | |
michael@0 | 111 | aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, |
michael@0 | 112 | aVBOs.Allocate(aGLContext)); |
michael@0 | 113 | aGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, |
michael@0 | 114 | total, |
michael@0 | 115 | nullptr, |
michael@0 | 116 | LOCAL_GL_STREAM_DRAW); |
michael@0 | 117 | |
michael@0 | 118 | aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER, |
michael@0 | 119 | 0, |
michael@0 | 120 | bytes, |
michael@0 | 121 | aRects.vertCoords().Elements()); |
michael@0 | 122 | aGLContext->fEnableVertexAttribArray(vertAttribIndex); |
michael@0 | 123 | aGLContext->fVertexAttribPointer(vertAttribIndex, |
michael@0 | 124 | 2, LOCAL_GL_FLOAT, |
michael@0 | 125 | LOCAL_GL_FALSE, |
michael@0 | 126 | 0, BUFFER_OFFSET(0)); |
michael@0 | 127 | |
michael@0 | 128 | if (texCoords) { |
michael@0 | 129 | aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER, |
michael@0 | 130 | bytes, |
michael@0 | 131 | bytes, |
michael@0 | 132 | aRects.texCoords().Elements()); |
michael@0 | 133 | aGLContext->fEnableVertexAttribArray(texCoordAttribIndex); |
michael@0 | 134 | aGLContext->fVertexAttribPointer(texCoordAttribIndex, |
michael@0 | 135 | 2, LOCAL_GL_FLOAT, |
michael@0 | 136 | LOCAL_GL_FALSE, |
michael@0 | 137 | 0, BUFFER_OFFSET(bytes)); |
michael@0 | 138 | } else { |
michael@0 | 139 | aGLContext->fDisableVertexAttribArray(texCoordAttribIndex); |
michael@0 | 140 | } |
michael@0 | 141 | |
michael@0 | 142 | aGLContext->fDrawArrays(aMode, 0, aRects.elements()); |
michael@0 | 143 | |
michael@0 | 144 | aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); |
michael@0 | 145 | } |
michael@0 | 146 | |
michael@0 | 147 | CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth, |
michael@0 | 148 | int aSurfaceHeight, bool aUseExternalSurfaceSize) |
michael@0 | 149 | : mWidget(aWidget) |
michael@0 | 150 | , mWidgetSize(-1, -1) |
michael@0 | 151 | , mSurfaceSize(aSurfaceWidth, aSurfaceHeight) |
michael@0 | 152 | , mHasBGRA(0) |
michael@0 | 153 | , mUseExternalSurfaceSize(aUseExternalSurfaceSize) |
michael@0 | 154 | , mFrameInProgress(false) |
michael@0 | 155 | , mDestroyed(false) |
michael@0 | 156 | , mHeight(0) |
michael@0 | 157 | { |
michael@0 | 158 | MOZ_COUNT_CTOR(CompositorOGL); |
michael@0 | 159 | SetBackend(LayersBackend::LAYERS_OPENGL); |
michael@0 | 160 | } |
michael@0 | 161 | |
michael@0 | 162 | CompositorOGL::~CompositorOGL() |
michael@0 | 163 | { |
michael@0 | 164 | MOZ_COUNT_DTOR(CompositorOGL); |
michael@0 | 165 | Destroy(); |
michael@0 | 166 | } |
michael@0 | 167 | |
michael@0 | 168 | already_AddRefed<mozilla::gl::GLContext> |
michael@0 | 169 | CompositorOGL::CreateContext() |
michael@0 | 170 | { |
michael@0 | 171 | nsRefPtr<GLContext> context; |
michael@0 | 172 | |
michael@0 | 173 | #ifdef XP_WIN |
michael@0 | 174 | if (PR_GetEnv("MOZ_LAYERS_PREFER_EGL")) { |
michael@0 | 175 | printf_stderr("Trying GL layers...\n"); |
michael@0 | 176 | context = gl::GLContextProviderEGL::CreateForWindow(mWidget); |
michael@0 | 177 | } |
michael@0 | 178 | #endif |
michael@0 | 179 | |
michael@0 | 180 | if (!context) |
michael@0 | 181 | context = gl::GLContextProvider::CreateForWindow(mWidget); |
michael@0 | 182 | |
michael@0 | 183 | if (!context) { |
michael@0 | 184 | NS_WARNING("Failed to create CompositorOGL context"); |
michael@0 | 185 | } |
michael@0 | 186 | |
michael@0 | 187 | return context.forget(); |
michael@0 | 188 | } |
michael@0 | 189 | |
michael@0 | 190 | void |
michael@0 | 191 | CompositorOGL::Destroy() |
michael@0 | 192 | { |
michael@0 | 193 | if (gl() && gl()->MakeCurrent()) { |
michael@0 | 194 | mVBOs.Flush(gl()); |
michael@0 | 195 | } |
michael@0 | 196 | |
michael@0 | 197 | if (mTexturePool) { |
michael@0 | 198 | mTexturePool->Clear(); |
michael@0 | 199 | mTexturePool = nullptr; |
michael@0 | 200 | } |
michael@0 | 201 | |
michael@0 | 202 | if (!mDestroyed) { |
michael@0 | 203 | mDestroyed = true; |
michael@0 | 204 | CleanupResources(); |
michael@0 | 205 | } |
michael@0 | 206 | } |
michael@0 | 207 | |
michael@0 | 208 | void |
michael@0 | 209 | CompositorOGL::CleanupResources() |
michael@0 | 210 | { |
michael@0 | 211 | if (!mGLContext) |
michael@0 | 212 | return; |
michael@0 | 213 | |
michael@0 | 214 | nsRefPtr<GLContext> ctx = mGLContext->GetSharedContext(); |
michael@0 | 215 | if (!ctx) { |
michael@0 | 216 | ctx = mGLContext; |
michael@0 | 217 | } |
michael@0 | 218 | |
michael@0 | 219 | for (std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.begin(); |
michael@0 | 220 | iter != mPrograms.end(); |
michael@0 | 221 | iter++) { |
michael@0 | 222 | delete iter->second; |
michael@0 | 223 | } |
michael@0 | 224 | mPrograms.clear(); |
michael@0 | 225 | |
michael@0 | 226 | if (!ctx->MakeCurrent()) { |
michael@0 | 227 | mQuadVBO = 0; |
michael@0 | 228 | mGLContext = nullptr; |
michael@0 | 229 | return; |
michael@0 | 230 | } |
michael@0 | 231 | |
michael@0 | 232 | ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); |
michael@0 | 233 | |
michael@0 | 234 | if (mQuadVBO) { |
michael@0 | 235 | ctx->fDeleteBuffers(1, &mQuadVBO); |
michael@0 | 236 | mQuadVBO = 0; |
michael@0 | 237 | } |
michael@0 | 238 | |
michael@0 | 239 | mGLContext = nullptr; |
michael@0 | 240 | } |
michael@0 | 241 | |
michael@0 | 242 | bool |
michael@0 | 243 | CompositorOGL::Initialize() |
michael@0 | 244 | { |
michael@0 | 245 | ScopedGfxFeatureReporter reporter("GL Layers", true); |
michael@0 | 246 | |
michael@0 | 247 | // Do not allow double initialization |
michael@0 | 248 | NS_ABORT_IF_FALSE(mGLContext == nullptr, "Don't reinitialize CompositorOGL"); |
michael@0 | 249 | |
michael@0 | 250 | mGLContext = CreateContext(); |
michael@0 | 251 | |
michael@0 | 252 | #ifdef MOZ_WIDGET_ANDROID |
michael@0 | 253 | if (!mGLContext) |
michael@0 | 254 | NS_RUNTIMEABORT("We need a context on Android"); |
michael@0 | 255 | #endif |
michael@0 | 256 | |
michael@0 | 257 | if (!mGLContext) |
michael@0 | 258 | return false; |
michael@0 | 259 | |
michael@0 | 260 | MakeCurrent(); |
michael@0 | 261 | |
michael@0 | 262 | mHasBGRA = |
michael@0 | 263 | mGLContext->IsExtensionSupported(gl::GLContext::EXT_texture_format_BGRA8888) || |
michael@0 | 264 | mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra); |
michael@0 | 265 | |
michael@0 | 266 | mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, |
michael@0 | 267 | LOCAL_GL_ONE, LOCAL_GL_ONE); |
michael@0 | 268 | mGLContext->fEnable(LOCAL_GL_BLEND); |
michael@0 | 269 | |
michael@0 | 270 | // initialise a common shader to check that we can actually compile a shader |
michael@0 | 271 | RefPtr<EffectSolidColor> effect = new EffectSolidColor(Color(0, 0, 0, 0)); |
michael@0 | 272 | ShaderConfigOGL config = GetShaderConfigFor(effect); |
michael@0 | 273 | if (!GetShaderProgramFor(config)) { |
michael@0 | 274 | return false; |
michael@0 | 275 | } |
michael@0 | 276 | |
michael@0 | 277 | if (mGLContext->WorkAroundDriverBugs()) { |
michael@0 | 278 | /** |
michael@0 | 279 | * We'll test the ability here to bind NPOT textures to a framebuffer, if |
michael@0 | 280 | * this fails we'll try ARB_texture_rectangle. |
michael@0 | 281 | */ |
michael@0 | 282 | |
michael@0 | 283 | GLenum textureTargets[] = { |
michael@0 | 284 | LOCAL_GL_TEXTURE_2D, |
michael@0 | 285 | LOCAL_GL_NONE |
michael@0 | 286 | }; |
michael@0 | 287 | |
michael@0 | 288 | if (!mGLContext->IsGLES()) { |
michael@0 | 289 | // No TEXTURE_RECTANGLE_ARB available on ES2 |
michael@0 | 290 | textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB; |
michael@0 | 291 | } |
michael@0 | 292 | |
michael@0 | 293 | mFBOTextureTarget = LOCAL_GL_NONE; |
michael@0 | 294 | |
michael@0 | 295 | GLuint testFBO = 0; |
michael@0 | 296 | mGLContext->fGenFramebuffers(1, &testFBO); |
michael@0 | 297 | GLuint testTexture = 0; |
michael@0 | 298 | |
michael@0 | 299 | for (uint32_t i = 0; i < ArrayLength(textureTargets); i++) { |
michael@0 | 300 | GLenum target = textureTargets[i]; |
michael@0 | 301 | if (!target) |
michael@0 | 302 | continue; |
michael@0 | 303 | |
michael@0 | 304 | mGLContext->fGenTextures(1, &testTexture); |
michael@0 | 305 | mGLContext->fBindTexture(target, testTexture); |
michael@0 | 306 | mGLContext->fTexParameteri(target, |
michael@0 | 307 | LOCAL_GL_TEXTURE_MIN_FILTER, |
michael@0 | 308 | LOCAL_GL_NEAREST); |
michael@0 | 309 | mGLContext->fTexParameteri(target, |
michael@0 | 310 | LOCAL_GL_TEXTURE_MAG_FILTER, |
michael@0 | 311 | LOCAL_GL_NEAREST); |
michael@0 | 312 | mGLContext->fTexImage2D(target, |
michael@0 | 313 | 0, |
michael@0 | 314 | LOCAL_GL_RGBA, |
michael@0 | 315 | 5, 3, /* sufficiently NPOT */ |
michael@0 | 316 | 0, |
michael@0 | 317 | LOCAL_GL_RGBA, |
michael@0 | 318 | LOCAL_GL_UNSIGNED_BYTE, |
michael@0 | 319 | nullptr); |
michael@0 | 320 | |
michael@0 | 321 | // unbind this texture, in preparation for binding it to the FBO |
michael@0 | 322 | mGLContext->fBindTexture(target, 0); |
michael@0 | 323 | |
michael@0 | 324 | mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, testFBO); |
michael@0 | 325 | mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, |
michael@0 | 326 | LOCAL_GL_COLOR_ATTACHMENT0, |
michael@0 | 327 | target, |
michael@0 | 328 | testTexture, |
michael@0 | 329 | 0); |
michael@0 | 330 | |
michael@0 | 331 | if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) == |
michael@0 | 332 | LOCAL_GL_FRAMEBUFFER_COMPLETE) |
michael@0 | 333 | { |
michael@0 | 334 | mFBOTextureTarget = target; |
michael@0 | 335 | mGLContext->fDeleteTextures(1, &testTexture); |
michael@0 | 336 | break; |
michael@0 | 337 | } |
michael@0 | 338 | |
michael@0 | 339 | mGLContext->fDeleteTextures(1, &testTexture); |
michael@0 | 340 | } |
michael@0 | 341 | |
michael@0 | 342 | if (testFBO) { |
michael@0 | 343 | mGLContext->fDeleteFramebuffers(1, &testFBO); |
michael@0 | 344 | } |
michael@0 | 345 | |
michael@0 | 346 | if (mFBOTextureTarget == LOCAL_GL_NONE) { |
michael@0 | 347 | /* Unable to find a texture target that works with FBOs and NPOT textures */ |
michael@0 | 348 | return false; |
michael@0 | 349 | } |
michael@0 | 350 | } else { |
michael@0 | 351 | // not trying to work around driver bugs, so TEXTURE_2D should just work |
michael@0 | 352 | mFBOTextureTarget = LOCAL_GL_TEXTURE_2D; |
michael@0 | 353 | } |
michael@0 | 354 | |
michael@0 | 355 | // back to default framebuffer, to avoid confusion |
michael@0 | 356 | mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); |
michael@0 | 357 | |
michael@0 | 358 | if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) { |
michael@0 | 359 | /* If we're using TEXTURE_RECTANGLE, then we must have the ARB |
michael@0 | 360 | * extension -- the EXT variant does not provide support for |
michael@0 | 361 | * texture rectangle access inside GLSL (sampler2DRect, |
michael@0 | 362 | * texture2DRect). |
michael@0 | 363 | */ |
michael@0 | 364 | if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle)) |
michael@0 | 365 | return false; |
michael@0 | 366 | } |
michael@0 | 367 | |
michael@0 | 368 | /* Create a simple quad VBO */ |
michael@0 | 369 | |
michael@0 | 370 | mGLContext->fGenBuffers(1, &mQuadVBO); |
michael@0 | 371 | mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO); |
michael@0 | 372 | |
michael@0 | 373 | GLfloat vertices[] = { |
michael@0 | 374 | /* First quad vertices */ |
michael@0 | 375 | 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, |
michael@0 | 376 | /* Then quad texcoords */ |
michael@0 | 377 | 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, |
michael@0 | 378 | }; |
michael@0 | 379 | mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW); |
michael@0 | 380 | mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); |
michael@0 | 381 | |
michael@0 | 382 | nsCOMPtr<nsIConsoleService> |
michael@0 | 383 | console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); |
michael@0 | 384 | |
michael@0 | 385 | if (console) { |
michael@0 | 386 | nsString msg; |
michael@0 | 387 | msg += |
michael@0 | 388 | NS_LITERAL_STRING("OpenGL compositor Initialized Succesfully.\nVersion: "); |
michael@0 | 389 | msg += NS_ConvertUTF8toUTF16( |
michael@0 | 390 | nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VERSION))); |
michael@0 | 391 | msg += NS_LITERAL_STRING("\nVendor: "); |
michael@0 | 392 | msg += NS_ConvertUTF8toUTF16( |
michael@0 | 393 | nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VENDOR))); |
michael@0 | 394 | msg += NS_LITERAL_STRING("\nRenderer: "); |
michael@0 | 395 | msg += NS_ConvertUTF8toUTF16( |
michael@0 | 396 | nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_RENDERER))); |
michael@0 | 397 | msg += NS_LITERAL_STRING("\nFBO Texture Target: "); |
michael@0 | 398 | if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D) |
michael@0 | 399 | msg += NS_LITERAL_STRING("TEXTURE_2D"); |
michael@0 | 400 | else |
michael@0 | 401 | msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE"); |
michael@0 | 402 | console->LogStringMessage(msg.get()); |
michael@0 | 403 | } |
michael@0 | 404 | |
michael@0 | 405 | reporter.SetSuccessful(); |
michael@0 | 406 | return true; |
michael@0 | 407 | } |
michael@0 | 408 | |
michael@0 | 409 | // |aTextureTransform| is the texture transform that will be set on |
michael@0 | 410 | // aProg, possibly multiplied with another texture transform of our |
michael@0 | 411 | // own. |
michael@0 | 412 | // |aTexCoordRect| is the rectangle from the texture that we want to |
michael@0 | 413 | // draw using the given program. The program already has a necessary |
michael@0 | 414 | // offset and scale, so the geometry that needs to be drawn is a unit |
michael@0 | 415 | // square from 0,0 to 1,1. |
michael@0 | 416 | // |
michael@0 | 417 | // |aTexture| is the texture we are drawing. Its actual size can be |
michael@0 | 418 | // larger than the rectangle given by |aTexCoordRect|. |
michael@0 | 419 | void |
michael@0 | 420 | CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg, |
michael@0 | 421 | const gfx3DMatrix& aTextureTransform, |
michael@0 | 422 | const Rect& aTexCoordRect, |
michael@0 | 423 | TextureSource *aTexture) |
michael@0 | 424 | { |
michael@0 | 425 | // Given what we know about these textures and coordinates, we can |
michael@0 | 426 | // compute fmod(t, 1.0f) to get the same texture coordinate out. If |
michael@0 | 427 | // the texCoordRect dimension is < 0 or > width/height, then we have |
michael@0 | 428 | // wraparound that we need to deal with by drawing multiple quads, |
michael@0 | 429 | // because we can't rely on full non-power-of-two texture support |
michael@0 | 430 | // (which is required for the REPEAT wrap mode). |
michael@0 | 431 | |
michael@0 | 432 | RectTriangles rects; |
michael@0 | 433 | |
michael@0 | 434 | GLenum wrapMode = aTexture->AsSourceOGL()->GetWrapMode(); |
michael@0 | 435 | |
michael@0 | 436 | IntSize realTexSize = aTexture->GetSize(); |
michael@0 | 437 | if (!CanUploadNonPowerOfTwo(mGLContext)) { |
michael@0 | 438 | realTexSize = IntSize(NextPowerOfTwo(realTexSize.width), |
michael@0 | 439 | NextPowerOfTwo(realTexSize.height)); |
michael@0 | 440 | } |
michael@0 | 441 | |
michael@0 | 442 | // We need to convert back to actual texels here to get proper behaviour with |
michael@0 | 443 | // our GL helper functions. Should fix this sometime. |
michael@0 | 444 | // I want to vomit. |
michael@0 | 445 | IntRect texCoordRect = IntRect(NS_roundf(aTexCoordRect.x * aTexture->GetSize().width), |
michael@0 | 446 | NS_roundf(aTexCoordRect.y * aTexture->GetSize().height), |
michael@0 | 447 | NS_roundf(aTexCoordRect.width * aTexture->GetSize().width), |
michael@0 | 448 | NS_roundf(aTexCoordRect.height * aTexture->GetSize().height)); |
michael@0 | 449 | |
michael@0 | 450 | // This is fairly disgusting - if the texture should be flipped it will have a |
michael@0 | 451 | // negative height, in which case we un-invert the texture coords and pass the |
michael@0 | 452 | // flipped 'flag' to the functions below. We can't just use the inverted coords |
michael@0 | 453 | // because our GL funtions use an explicit flag. |
michael@0 | 454 | bool flipped = false; |
michael@0 | 455 | if (texCoordRect.height < 0) { |
michael@0 | 456 | flipped = true; |
michael@0 | 457 | texCoordRect.y = texCoordRect.YMost(); |
michael@0 | 458 | texCoordRect.height = -texCoordRect.height; |
michael@0 | 459 | } |
michael@0 | 460 | |
michael@0 | 461 | if (wrapMode == LOCAL_GL_REPEAT) { |
michael@0 | 462 | rects.addRect(/* dest rectangle */ |
michael@0 | 463 | 0.0f, 0.0f, 1.0f, 1.0f, |
michael@0 | 464 | /* tex coords */ |
michael@0 | 465 | texCoordRect.x / GLfloat(realTexSize.width), |
michael@0 | 466 | texCoordRect.y / GLfloat(realTexSize.height), |
michael@0 | 467 | texCoordRect.XMost() / GLfloat(realTexSize.width), |
michael@0 | 468 | texCoordRect.YMost() / GLfloat(realTexSize.height), |
michael@0 | 469 | flipped); |
michael@0 | 470 | } else { |
michael@0 | 471 | nsIntRect tcRect(texCoordRect.x, texCoordRect.y, |
michael@0 | 472 | texCoordRect.width, texCoordRect.height); |
michael@0 | 473 | DecomposeIntoNoRepeatTriangles(tcRect, |
michael@0 | 474 | nsIntSize(realTexSize.width, realTexSize.height), |
michael@0 | 475 | rects, flipped); |
michael@0 | 476 | } |
michael@0 | 477 | |
michael@0 | 478 | gfx3DMatrix textureTransform; |
michael@0 | 479 | if (rects.isSimpleQuad(textureTransform)) { |
michael@0 | 480 | Matrix4x4 transform; |
michael@0 | 481 | ToMatrix4x4(aTextureTransform * textureTransform, transform); |
michael@0 | 482 | aProg->SetTextureTransform(transform); |
michael@0 | 483 | BindAndDrawQuad(aProg); |
michael@0 | 484 | } else { |
michael@0 | 485 | Matrix4x4 transform; |
michael@0 | 486 | ToMatrix4x4(aTextureTransform, transform); |
michael@0 | 487 | aProg->SetTextureTransform(transform); |
michael@0 | 488 | DrawQuads(mGLContext, mVBOs, aProg, LOCAL_GL_TRIANGLES, rects); |
michael@0 | 489 | } |
michael@0 | 490 | } |
michael@0 | 491 | |
michael@0 | 492 | void |
michael@0 | 493 | CompositorOGL::PrepareViewport(const gfx::IntSize& aSize, |
michael@0 | 494 | const Matrix& aWorldTransform) |
michael@0 | 495 | { |
michael@0 | 496 | // Set the viewport correctly. |
michael@0 | 497 | mGLContext->fViewport(0, 0, aSize.width, aSize.height); |
michael@0 | 498 | |
michael@0 | 499 | mHeight = aSize.height; |
michael@0 | 500 | |
michael@0 | 501 | // We flip the view matrix around so that everything is right-side up; we're |
michael@0 | 502 | // drawing directly into the window's back buffer, so this keeps things |
michael@0 | 503 | // looking correct. |
michael@0 | 504 | // XXX: We keep track of whether the window size changed, so we could skip |
michael@0 | 505 | // this update if it hadn't changed since the last call. We will need to |
michael@0 | 506 | // track changes to aTransformPolicy and aWorldTransform for this to work |
michael@0 | 507 | // though. |
michael@0 | 508 | |
michael@0 | 509 | // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0, |
michael@0 | 510 | // 2, 2) and flip the contents. |
michael@0 | 511 | Matrix viewMatrix; |
michael@0 | 512 | viewMatrix.Translate(-1.0, 1.0); |
michael@0 | 513 | viewMatrix.Scale(2.0f / float(aSize.width), 2.0f / float(aSize.height)); |
michael@0 | 514 | viewMatrix.Scale(1.0f, -1.0f); |
michael@0 | 515 | if (!mTarget) { |
michael@0 | 516 | viewMatrix.Translate(mRenderOffset.x, mRenderOffset.y); |
michael@0 | 517 | } |
michael@0 | 518 | |
michael@0 | 519 | viewMatrix = aWorldTransform * viewMatrix; |
michael@0 | 520 | |
michael@0 | 521 | Matrix4x4 matrix3d = Matrix4x4::From2D(viewMatrix); |
michael@0 | 522 | matrix3d._33 = 0.0f; |
michael@0 | 523 | |
michael@0 | 524 | mProjMatrix = matrix3d; |
michael@0 | 525 | } |
michael@0 | 526 | |
michael@0 | 527 | TemporaryRef<CompositingRenderTarget> |
michael@0 | 528 | CompositorOGL::CreateRenderTarget(const IntRect &aRect, SurfaceInitMode aInit) |
michael@0 | 529 | { |
michael@0 | 530 | GLuint tex = 0; |
michael@0 | 531 | GLuint fbo = 0; |
michael@0 | 532 | CreateFBOWithTexture(aRect, false, 0, &fbo, &tex); |
michael@0 | 533 | RefPtr<CompositingRenderTargetOGL> surface |
michael@0 | 534 | = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo); |
michael@0 | 535 | surface->Initialize(aRect.Size(), mFBOTextureTarget, aInit); |
michael@0 | 536 | return surface.forget(); |
michael@0 | 537 | } |
michael@0 | 538 | |
michael@0 | 539 | TemporaryRef<CompositingRenderTarget> |
michael@0 | 540 | CompositorOGL::CreateRenderTargetFromSource(const IntRect &aRect, |
michael@0 | 541 | const CompositingRenderTarget *aSource, |
michael@0 | 542 | const IntPoint &aSourcePoint) |
michael@0 | 543 | { |
michael@0 | 544 | GLuint tex = 0; |
michael@0 | 545 | GLuint fbo = 0; |
michael@0 | 546 | const CompositingRenderTargetOGL* sourceSurface |
michael@0 | 547 | = static_cast<const CompositingRenderTargetOGL*>(aSource); |
michael@0 | 548 | IntRect sourceRect(aSourcePoint, aRect.Size()); |
michael@0 | 549 | if (aSource) { |
michael@0 | 550 | CreateFBOWithTexture(sourceRect, true, sourceSurface->GetFBO(), |
michael@0 | 551 | &fbo, &tex); |
michael@0 | 552 | } else { |
michael@0 | 553 | CreateFBOWithTexture(sourceRect, true, 0, |
michael@0 | 554 | &fbo, &tex); |
michael@0 | 555 | } |
michael@0 | 556 | |
michael@0 | 557 | RefPtr<CompositingRenderTargetOGL> surface |
michael@0 | 558 | = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo); |
michael@0 | 559 | surface->Initialize(aRect.Size(), |
michael@0 | 560 | mFBOTextureTarget, |
michael@0 | 561 | INIT_MODE_NONE); |
michael@0 | 562 | return surface.forget(); |
michael@0 | 563 | } |
michael@0 | 564 | |
michael@0 | 565 | void |
michael@0 | 566 | CompositorOGL::SetRenderTarget(CompositingRenderTarget *aSurface) |
michael@0 | 567 | { |
michael@0 | 568 | MOZ_ASSERT(aSurface); |
michael@0 | 569 | CompositingRenderTargetOGL* surface |
michael@0 | 570 | = static_cast<CompositingRenderTargetOGL*>(aSurface); |
michael@0 | 571 | if (mCurrentRenderTarget != surface) { |
michael@0 | 572 | surface->BindRenderTarget(); |
michael@0 | 573 | mCurrentRenderTarget = surface; |
michael@0 | 574 | } |
michael@0 | 575 | } |
michael@0 | 576 | |
michael@0 | 577 | CompositingRenderTarget* |
michael@0 | 578 | CompositorOGL::GetCurrentRenderTarget() const |
michael@0 | 579 | { |
michael@0 | 580 | return mCurrentRenderTarget; |
michael@0 | 581 | } |
michael@0 | 582 | |
michael@0 | 583 | static GLenum |
michael@0 | 584 | GetFrameBufferInternalFormat(GLContext* gl, |
michael@0 | 585 | GLuint aFrameBuffer, |
michael@0 | 586 | nsIWidget* aWidget) |
michael@0 | 587 | { |
michael@0 | 588 | if (aFrameBuffer == 0) { // default framebuffer |
michael@0 | 589 | return aWidget->GetGLFrameBufferFormat(); |
michael@0 | 590 | } |
michael@0 | 591 | return LOCAL_GL_RGBA; |
michael@0 | 592 | } |
michael@0 | 593 | |
michael@0 | 594 | /* |
michael@0 | 595 | * Returns a size that is larger than and closest to aSize where both |
michael@0 | 596 | * width and height are powers of two. |
michael@0 | 597 | * If the OpenGL setup is capable of using non-POT textures, then it |
michael@0 | 598 | * will just return aSize. |
michael@0 | 599 | */ |
michael@0 | 600 | static IntSize |
michael@0 | 601 | CalculatePOTSize(const IntSize& aSize, GLContext* gl) |
michael@0 | 602 | { |
michael@0 | 603 | if (CanUploadNonPowerOfTwo(gl)) |
michael@0 | 604 | return aSize; |
michael@0 | 605 | |
michael@0 | 606 | return IntSize(NextPowerOfTwo(aSize.width), NextPowerOfTwo(aSize.height)); |
michael@0 | 607 | } |
michael@0 | 608 | |
michael@0 | 609 | void |
michael@0 | 610 | CompositorOGL::ClearRect(const gfx::Rect& aRect) |
michael@0 | 611 | { |
michael@0 | 612 | // Map aRect to OGL coordinates, origin:bottom-left |
michael@0 | 613 | GLint y = mHeight - (aRect.y + aRect.height); |
michael@0 | 614 | |
michael@0 | 615 | ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true); |
michael@0 | 616 | ScopedScissorRect autoScissorRect(mGLContext, aRect.x, y, aRect.width, aRect.height); |
michael@0 | 617 | mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0); |
michael@0 | 618 | mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); |
michael@0 | 619 | } |
michael@0 | 620 | |
michael@0 | 621 | void |
michael@0 | 622 | CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion, |
michael@0 | 623 | const Rect *aClipRectIn, |
michael@0 | 624 | const gfx::Matrix& aTransform, |
michael@0 | 625 | const Rect& aRenderBounds, |
michael@0 | 626 | Rect *aClipRectOut, |
michael@0 | 627 | Rect *aRenderBoundsOut) |
michael@0 | 628 | { |
michael@0 | 629 | PROFILER_LABEL("CompositorOGL", "BeginFrame"); |
michael@0 | 630 | MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame"); |
michael@0 | 631 | |
michael@0 | 632 | LayerScope::BeginFrame(mGLContext, PR_Now()); |
michael@0 | 633 | |
michael@0 | 634 | mVBOs.Reset(); |
michael@0 | 635 | |
michael@0 | 636 | mFrameInProgress = true; |
michael@0 | 637 | gfx::Rect rect; |
michael@0 | 638 | if (mUseExternalSurfaceSize) { |
michael@0 | 639 | rect = gfx::Rect(0, 0, mSurfaceSize.width, mSurfaceSize.height); |
michael@0 | 640 | } else { |
michael@0 | 641 | rect = gfx::Rect(aRenderBounds.x, aRenderBounds.y, aRenderBounds.width, aRenderBounds.height); |
michael@0 | 642 | // If render bounds is not updated explicitly, try to infer it from widget |
michael@0 | 643 | if (rect.width == 0 || rect.height == 0) { |
michael@0 | 644 | // FIXME/bug XXXXXX this races with rotation changes on the main |
michael@0 | 645 | // thread, and undoes all the care we take with layers txns being |
michael@0 | 646 | // sent atomically with rotation changes |
michael@0 | 647 | nsIntRect intRect; |
michael@0 | 648 | mWidget->GetClientBounds(intRect); |
michael@0 | 649 | rect = gfx::Rect(0, 0, intRect.width, intRect.height); |
michael@0 | 650 | } |
michael@0 | 651 | } |
michael@0 | 652 | |
michael@0 | 653 | rect = aTransform.TransformBounds(rect); |
michael@0 | 654 | if (aRenderBoundsOut) { |
michael@0 | 655 | *aRenderBoundsOut = rect; |
michael@0 | 656 | } |
michael@0 | 657 | |
michael@0 | 658 | GLint width = rect.width; |
michael@0 | 659 | GLint height = rect.height; |
michael@0 | 660 | |
michael@0 | 661 | // We can't draw anything to something with no area |
michael@0 | 662 | // so just return |
michael@0 | 663 | if (width == 0 || height == 0) |
michael@0 | 664 | return; |
michael@0 | 665 | |
michael@0 | 666 | // If the widget size changed, we have to force a MakeCurrent |
michael@0 | 667 | // to make sure that GL sees the updated widget size. |
michael@0 | 668 | if (mWidgetSize.width != width || |
michael@0 | 669 | mWidgetSize.height != height) |
michael@0 | 670 | { |
michael@0 | 671 | MakeCurrent(ForceMakeCurrent); |
michael@0 | 672 | |
michael@0 | 673 | mWidgetSize.width = width; |
michael@0 | 674 | mWidgetSize.height = height; |
michael@0 | 675 | } else { |
michael@0 | 676 | MakeCurrent(); |
michael@0 | 677 | } |
michael@0 | 678 | |
michael@0 | 679 | mPixelsPerFrame = width * height; |
michael@0 | 680 | mPixelsFilled = 0; |
michael@0 | 681 | |
michael@0 | 682 | #if MOZ_ANDROID_OMTC |
michael@0 | 683 | TexturePoolOGL::Fill(gl()); |
michael@0 | 684 | #endif |
michael@0 | 685 | |
michael@0 | 686 | mCurrentRenderTarget = CompositingRenderTargetOGL::RenderTargetForWindow(this, |
michael@0 | 687 | IntSize(width, height), |
michael@0 | 688 | aTransform); |
michael@0 | 689 | mCurrentRenderTarget->BindRenderTarget(); |
michael@0 | 690 | #ifdef DEBUG |
michael@0 | 691 | mWindowRenderTarget = mCurrentRenderTarget; |
michael@0 | 692 | #endif |
michael@0 | 693 | |
michael@0 | 694 | // Default blend function implements "OVER" |
michael@0 | 695 | mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, |
michael@0 | 696 | LOCAL_GL_ONE, LOCAL_GL_ONE); |
michael@0 | 697 | mGLContext->fEnable(LOCAL_GL_BLEND); |
michael@0 | 698 | |
michael@0 | 699 | mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST); |
michael@0 | 700 | |
michael@0 | 701 | if (aClipRectOut && !aClipRectIn) { |
michael@0 | 702 | aClipRectOut->SetRect(0, 0, width, height); |
michael@0 | 703 | } |
michael@0 | 704 | |
michael@0 | 705 | // If the Android compositor is being used, this clear will be done in |
michael@0 | 706 | // DrawWindowUnderlay. Make sure the bits used here match up with those used |
michael@0 | 707 | // in mobile/android/base/gfx/LayerRenderer.java |
michael@0 | 708 | #ifndef MOZ_ANDROID_OMTC |
michael@0 | 709 | mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0); |
michael@0 | 710 | mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); |
michael@0 | 711 | #endif |
michael@0 | 712 | } |
michael@0 | 713 | |
michael@0 | 714 | void |
michael@0 | 715 | CompositorOGL::CreateFBOWithTexture(const IntRect& aRect, bool aCopyFromSource, |
michael@0 | 716 | GLuint aSourceFrameBuffer, |
michael@0 | 717 | GLuint *aFBO, GLuint *aTexture) |
michael@0 | 718 | { |
michael@0 | 719 | GLuint tex, fbo; |
michael@0 | 720 | |
michael@0 | 721 | mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); |
michael@0 | 722 | mGLContext->fGenTextures(1, &tex); |
michael@0 | 723 | mGLContext->fBindTexture(mFBOTextureTarget, tex); |
michael@0 | 724 | |
michael@0 | 725 | if (aCopyFromSource) { |
michael@0 | 726 | GLuint curFBO = mCurrentRenderTarget->GetFBO(); |
michael@0 | 727 | if (curFBO != aSourceFrameBuffer) { |
michael@0 | 728 | mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aSourceFrameBuffer); |
michael@0 | 729 | } |
michael@0 | 730 | |
michael@0 | 731 | // We're going to create an RGBA temporary fbo. But to |
michael@0 | 732 | // CopyTexImage() from the current framebuffer, the framebuffer's |
michael@0 | 733 | // format has to be compatible with the new texture's. So we |
michael@0 | 734 | // check the format of the framebuffer here and take a slow path |
michael@0 | 735 | // if it's incompatible. |
michael@0 | 736 | GLenum format = |
michael@0 | 737 | GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget); |
michael@0 | 738 | |
michael@0 | 739 | bool isFormatCompatibleWithRGBA |
michael@0 | 740 | = gl()->IsGLES() ? (format == LOCAL_GL_RGBA) |
michael@0 | 741 | : true; |
michael@0 | 742 | |
michael@0 | 743 | if (isFormatCompatibleWithRGBA) { |
michael@0 | 744 | mGLContext->fCopyTexImage2D(mFBOTextureTarget, |
michael@0 | 745 | 0, |
michael@0 | 746 | LOCAL_GL_RGBA, |
michael@0 | 747 | aRect.x, FlipY(aRect.y + aRect.height), |
michael@0 | 748 | aRect.width, aRect.height, |
michael@0 | 749 | 0); |
michael@0 | 750 | } else { |
michael@0 | 751 | // Curses, incompatible formats. Take a slow path. |
michael@0 | 752 | |
michael@0 | 753 | // RGBA |
michael@0 | 754 | size_t bufferSize = aRect.width * aRect.height * 4; |
michael@0 | 755 | nsAutoArrayPtr<uint8_t> buf(new uint8_t[bufferSize]); |
michael@0 | 756 | |
michael@0 | 757 | mGLContext->fReadPixels(aRect.x, aRect.y, |
michael@0 | 758 | aRect.width, aRect.height, |
michael@0 | 759 | LOCAL_GL_RGBA, |
michael@0 | 760 | LOCAL_GL_UNSIGNED_BYTE, |
michael@0 | 761 | buf); |
michael@0 | 762 | mGLContext->fTexImage2D(mFBOTextureTarget, |
michael@0 | 763 | 0, |
michael@0 | 764 | LOCAL_GL_RGBA, |
michael@0 | 765 | aRect.width, aRect.height, |
michael@0 | 766 | 0, |
michael@0 | 767 | LOCAL_GL_RGBA, |
michael@0 | 768 | LOCAL_GL_UNSIGNED_BYTE, |
michael@0 | 769 | buf); |
michael@0 | 770 | } |
michael@0 | 771 | GLenum error = mGLContext->GetAndClearError(); |
michael@0 | 772 | if (error != LOCAL_GL_NO_ERROR) { |
michael@0 | 773 | nsAutoCString msg; |
michael@0 | 774 | msg.AppendPrintf("Texture initialization failed! -- error 0x%x, Source %d, Source format %d, RGBA Compat %d", |
michael@0 | 775 | error, aSourceFrameBuffer, format, isFormatCompatibleWithRGBA); |
michael@0 | 776 | NS_ERROR(msg.get()); |
michael@0 | 777 | } |
michael@0 | 778 | } else { |
michael@0 | 779 | mGLContext->fTexImage2D(mFBOTextureTarget, |
michael@0 | 780 | 0, |
michael@0 | 781 | LOCAL_GL_RGBA, |
michael@0 | 782 | aRect.width, aRect.height, |
michael@0 | 783 | 0, |
michael@0 | 784 | LOCAL_GL_RGBA, |
michael@0 | 785 | LOCAL_GL_UNSIGNED_BYTE, |
michael@0 | 786 | nullptr); |
michael@0 | 787 | } |
michael@0 | 788 | mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER, |
michael@0 | 789 | LOCAL_GL_LINEAR); |
michael@0 | 790 | mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER, |
michael@0 | 791 | LOCAL_GL_LINEAR); |
michael@0 | 792 | mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_S, |
michael@0 | 793 | LOCAL_GL_CLAMP_TO_EDGE); |
michael@0 | 794 | mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_T, |
michael@0 | 795 | LOCAL_GL_CLAMP_TO_EDGE); |
michael@0 | 796 | mGLContext->fBindTexture(mFBOTextureTarget, 0); |
michael@0 | 797 | |
michael@0 | 798 | mGLContext->fGenFramebuffers(1, &fbo); |
michael@0 | 799 | |
michael@0 | 800 | *aFBO = fbo; |
michael@0 | 801 | *aTexture = tex; |
michael@0 | 802 | } |
michael@0 | 803 | |
michael@0 | 804 | ShaderConfigOGL |
michael@0 | 805 | CompositorOGL::GetShaderConfigFor(Effect *aEffect, MaskType aMask) const |
michael@0 | 806 | { |
michael@0 | 807 | ShaderConfigOGL config; |
michael@0 | 808 | |
michael@0 | 809 | switch(aEffect->mType) { |
michael@0 | 810 | case EFFECT_SOLID_COLOR: |
michael@0 | 811 | config.SetRenderColor(true); |
michael@0 | 812 | break; |
michael@0 | 813 | case EFFECT_YCBCR: |
michael@0 | 814 | config.SetYCbCr(true); |
michael@0 | 815 | break; |
michael@0 | 816 | case EFFECT_COMPONENT_ALPHA: |
michael@0 | 817 | { |
michael@0 | 818 | config.SetComponentAlpha(true); |
michael@0 | 819 | EffectComponentAlpha* effectComponentAlpha = |
michael@0 | 820 | static_cast<EffectComponentAlpha*>(aEffect); |
michael@0 | 821 | gfx::SurfaceFormat format = effectComponentAlpha->mOnWhite->GetFormat(); |
michael@0 | 822 | config.SetRBSwap(format == gfx::SurfaceFormat::B8G8R8A8 || |
michael@0 | 823 | format == gfx::SurfaceFormat::B8G8R8X8); |
michael@0 | 824 | break; |
michael@0 | 825 | } |
michael@0 | 826 | case EFFECT_RENDER_TARGET: |
michael@0 | 827 | config.SetTextureTarget(mFBOTextureTarget); |
michael@0 | 828 | break; |
michael@0 | 829 | default: |
michael@0 | 830 | { |
michael@0 | 831 | MOZ_ASSERT(aEffect->mType == EFFECT_RGB); |
michael@0 | 832 | TexturedEffect* texturedEffect = |
michael@0 | 833 | static_cast<TexturedEffect*>(aEffect); |
michael@0 | 834 | TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL(); |
michael@0 | 835 | MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_EXTERNAL, |
michael@0 | 836 | source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8); |
michael@0 | 837 | MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB, |
michael@0 | 838 | source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 || |
michael@0 | 839 | source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 || |
michael@0 | 840 | source->GetFormat() == gfx::SurfaceFormat::R5G6B5); |
michael@0 | 841 | config = ShaderConfigFromTargetAndFormat(source->GetTextureTarget(), |
michael@0 | 842 | source->GetFormat()); |
michael@0 | 843 | break; |
michael@0 | 844 | } |
michael@0 | 845 | } |
michael@0 | 846 | config.SetMask2D(aMask == Mask2d); |
michael@0 | 847 | config.SetMask3D(aMask == Mask3d); |
michael@0 | 848 | return config; |
michael@0 | 849 | } |
michael@0 | 850 | |
michael@0 | 851 | ShaderProgramOGL* |
michael@0 | 852 | CompositorOGL::GetShaderProgramFor(const ShaderConfigOGL &aConfig) |
michael@0 | 853 | { |
michael@0 | 854 | std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.find(aConfig); |
michael@0 | 855 | if (iter != mPrograms.end()) |
michael@0 | 856 | return iter->second; |
michael@0 | 857 | |
michael@0 | 858 | ProgramProfileOGL profile = ProgramProfileOGL::GetProfileFor(aConfig); |
michael@0 | 859 | ShaderProgramOGL *shader = new ShaderProgramOGL(gl(), profile); |
michael@0 | 860 | if (!shader->Initialize()) { |
michael@0 | 861 | delete shader; |
michael@0 | 862 | return nullptr; |
michael@0 | 863 | } |
michael@0 | 864 | |
michael@0 | 865 | mPrograms[aConfig] = shader; |
michael@0 | 866 | return shader; |
michael@0 | 867 | } |
michael@0 | 868 | |
michael@0 | 869 | void |
michael@0 | 870 | CompositorOGL::DrawLines(const std::vector<gfx::Point>& aLines, const gfx::Rect& aClipRect, |
michael@0 | 871 | const gfx::Color& aColor, |
michael@0 | 872 | gfx::Float aOpacity, const gfx::Matrix4x4 &aTransform) |
michael@0 | 873 | { |
michael@0 | 874 | mGLContext->fLineWidth(2.0); |
michael@0 | 875 | |
michael@0 | 876 | EffectChain effects; |
michael@0 | 877 | effects.mPrimaryEffect = new EffectSolidColor(aColor); |
michael@0 | 878 | |
michael@0 | 879 | for (int32_t i = 0; i < (int32_t)aLines.size() - 1; i++) { |
michael@0 | 880 | const gfx::Point& p1 = aLines[i]; |
michael@0 | 881 | const gfx::Point& p2 = aLines[i+1]; |
michael@0 | 882 | DrawQuadInternal(Rect(p1.x, p2.y, p2.x - p1.x, p1.y - p2.y), |
michael@0 | 883 | aClipRect, effects, aOpacity, aTransform, |
michael@0 | 884 | LOCAL_GL_LINE_STRIP); |
michael@0 | 885 | } |
michael@0 | 886 | } |
michael@0 | 887 | |
michael@0 | 888 | void |
michael@0 | 889 | CompositorOGL::DrawQuadInternal(const Rect& aRect, |
michael@0 | 890 | const Rect& aClipRect, |
michael@0 | 891 | const EffectChain &aEffectChain, |
michael@0 | 892 | Float aOpacity, |
michael@0 | 893 | const gfx::Matrix4x4 &aTransform, |
michael@0 | 894 | GLuint aDrawMode) |
michael@0 | 895 | { |
michael@0 | 896 | PROFILER_LABEL("CompositorOGL", "DrawQuad"); |
michael@0 | 897 | MOZ_ASSERT(mFrameInProgress, "frame not started"); |
michael@0 | 898 | |
michael@0 | 899 | Rect clipRect = aClipRect; |
michael@0 | 900 | if (!mTarget) { |
michael@0 | 901 | clipRect.MoveBy(mRenderOffset.x, mRenderOffset.y); |
michael@0 | 902 | } |
michael@0 | 903 | IntRect intClipRect; |
michael@0 | 904 | clipRect.ToIntRect(&intClipRect); |
michael@0 | 905 | |
michael@0 | 906 | gl()->fScissor(intClipRect.x, FlipY(intClipRect.y + intClipRect.height), |
michael@0 | 907 | intClipRect.width, intClipRect.height); |
michael@0 | 908 | |
michael@0 | 909 | LayerScope::SendEffectChain(mGLContext, aEffectChain, |
michael@0 | 910 | aRect.width, aRect.height); |
michael@0 | 911 | |
michael@0 | 912 | MaskType maskType; |
michael@0 | 913 | EffectMask* effectMask; |
michael@0 | 914 | TextureSourceOGL* sourceMask = nullptr; |
michael@0 | 915 | gfx::Matrix4x4 maskQuadTransform; |
michael@0 | 916 | if (aEffectChain.mSecondaryEffects[EFFECT_MASK]) { |
michael@0 | 917 | effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EFFECT_MASK].get()); |
michael@0 | 918 | sourceMask = effectMask->mMaskTexture->AsSourceOGL(); |
michael@0 | 919 | |
michael@0 | 920 | // NS_ASSERTION(textureMask->IsAlpha(), |
michael@0 | 921 | // "OpenGL mask layers must be backed by alpha surfaces"); |
michael@0 | 922 | |
michael@0 | 923 | // We're assuming that the gl backend won't cheat and use NPOT |
michael@0 | 924 | // textures when glContext says it can't (which seems to happen |
michael@0 | 925 | // on a mac when you force POT textures) |
michael@0 | 926 | IntSize maskSize = CalculatePOTSize(effectMask->mSize, mGLContext); |
michael@0 | 927 | |
michael@0 | 928 | const gfx::Matrix4x4& maskTransform = effectMask->mMaskTransform; |
michael@0 | 929 | NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!"); |
michael@0 | 930 | Rect bounds = Rect(Point(), Size(maskSize)); |
michael@0 | 931 | bounds = maskTransform.As2D().TransformBounds(bounds); |
michael@0 | 932 | |
michael@0 | 933 | maskQuadTransform._11 = 1.0f/bounds.width; |
michael@0 | 934 | maskQuadTransform._22 = 1.0f/bounds.height; |
michael@0 | 935 | maskQuadTransform._41 = float(-bounds.x)/bounds.width; |
michael@0 | 936 | maskQuadTransform._42 = float(-bounds.y)/bounds.height; |
michael@0 | 937 | |
michael@0 | 938 | maskType = effectMask->mIs3D |
michael@0 | 939 | ? Mask3d |
michael@0 | 940 | : Mask2d; |
michael@0 | 941 | } else { |
michael@0 | 942 | maskType = MaskNone; |
michael@0 | 943 | } |
michael@0 | 944 | |
michael@0 | 945 | mPixelsFilled += aRect.width * aRect.height; |
michael@0 | 946 | |
michael@0 | 947 | // Determine the color if this is a color shader and fold the opacity into |
michael@0 | 948 | // the color since color shaders don't have an opacity uniform. |
michael@0 | 949 | Color color; |
michael@0 | 950 | if (aEffectChain.mPrimaryEffect->mType == EFFECT_SOLID_COLOR) { |
michael@0 | 951 | EffectSolidColor* effectSolidColor = |
michael@0 | 952 | static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get()); |
michael@0 | 953 | color = effectSolidColor->mColor; |
michael@0 | 954 | |
michael@0 | 955 | Float opacity = aOpacity * color.a; |
michael@0 | 956 | color.r *= opacity; |
michael@0 | 957 | color.g *= opacity; |
michael@0 | 958 | color.b *= opacity; |
michael@0 | 959 | color.a = opacity; |
michael@0 | 960 | |
michael@0 | 961 | // We can fold opacity into the color, so no need to consider it further. |
michael@0 | 962 | aOpacity = 1.f; |
michael@0 | 963 | } |
michael@0 | 964 | |
michael@0 | 965 | ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect, maskType); |
michael@0 | 966 | config.SetOpacity(aOpacity != 1.f); |
michael@0 | 967 | ShaderProgramOGL *program = GetShaderProgramFor(config); |
michael@0 | 968 | program->Activate(); |
michael@0 | 969 | program->SetProjectionMatrix(mProjMatrix); |
michael@0 | 970 | program->SetLayerQuadRect(aRect); |
michael@0 | 971 | program->SetLayerTransform(aTransform); |
michael@0 | 972 | IntPoint offset = mCurrentRenderTarget->GetOrigin(); |
michael@0 | 973 | program->SetRenderOffset(offset.x, offset.y); |
michael@0 | 974 | if (aOpacity != 1.f) |
michael@0 | 975 | program->SetLayerOpacity(aOpacity); |
michael@0 | 976 | if (config.mFeatures & ENABLE_TEXTURE_RECT) { |
michael@0 | 977 | TexturedEffect* texturedEffect = |
michael@0 | 978 | static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get()); |
michael@0 | 979 | TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL(); |
michael@0 | 980 | // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1. |
michael@0 | 981 | program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height); |
michael@0 | 982 | } |
michael@0 | 983 | |
michael@0 | 984 | switch (aEffectChain.mPrimaryEffect->mType) { |
michael@0 | 985 | case EFFECT_SOLID_COLOR: { |
michael@0 | 986 | program->SetRenderColor(color); |
michael@0 | 987 | |
michael@0 | 988 | if (maskType != MaskNone) { |
michael@0 | 989 | BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform); |
michael@0 | 990 | } |
michael@0 | 991 | |
michael@0 | 992 | BindAndDrawQuad(program, aDrawMode); |
michael@0 | 993 | } |
michael@0 | 994 | break; |
michael@0 | 995 | |
michael@0 | 996 | case EFFECT_RGB: { |
michael@0 | 997 | TexturedEffect* texturedEffect = |
michael@0 | 998 | static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get()); |
michael@0 | 999 | TextureSource *source = texturedEffect->mTexture; |
michael@0 | 1000 | |
michael@0 | 1001 | if (!texturedEffect->mPremultiplied) { |
michael@0 | 1002 | mGLContext->fBlendFuncSeparate(LOCAL_GL_SRC_ALPHA, LOCAL_GL_ONE_MINUS_SRC_ALPHA, |
michael@0 | 1003 | LOCAL_GL_ONE, LOCAL_GL_ONE); |
michael@0 | 1004 | } |
michael@0 | 1005 | |
michael@0 | 1006 | gfx::Filter filter = texturedEffect->mFilter; |
michael@0 | 1007 | gfx3DMatrix textureTransform; |
michael@0 | 1008 | gfx::To3DMatrix(source->AsSourceOGL()->GetTextureTransform(), textureTransform); |
michael@0 | 1009 | |
michael@0 | 1010 | #ifdef MOZ_WIDGET_ANDROID |
michael@0 | 1011 | gfxMatrix textureTransform2D; |
michael@0 | 1012 | if (filter != gfx::Filter::POINT && |
michael@0 | 1013 | aTransform.Is2DIntegerTranslation() && |
michael@0 | 1014 | textureTransform.Is2D(&textureTransform2D) && |
michael@0 | 1015 | textureTransform2D.HasOnlyIntegerTranslation()) { |
michael@0 | 1016 | // On Android we encounter small resampling errors in what should be |
michael@0 | 1017 | // pixel-aligned compositing operations. This works around them. This |
michael@0 | 1018 | // code should not be needed! |
michael@0 | 1019 | filter = gfx::Filter::POINT; |
michael@0 | 1020 | } |
michael@0 | 1021 | #endif |
michael@0 | 1022 | source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, filter); |
michael@0 | 1023 | |
michael@0 | 1024 | program->SetTextureUnit(0); |
michael@0 | 1025 | |
michael@0 | 1026 | if (maskType != MaskNone) { |
michael@0 | 1027 | BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform); |
michael@0 | 1028 | } |
michael@0 | 1029 | |
michael@0 | 1030 | BindAndDrawQuadWithTextureRect(program, textureTransform, |
michael@0 | 1031 | texturedEffect->mTextureCoords, source); |
michael@0 | 1032 | |
michael@0 | 1033 | if (!texturedEffect->mPremultiplied) { |
michael@0 | 1034 | mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, |
michael@0 | 1035 | LOCAL_GL_ONE, LOCAL_GL_ONE); |
michael@0 | 1036 | } |
michael@0 | 1037 | } |
michael@0 | 1038 | break; |
michael@0 | 1039 | case EFFECT_YCBCR: { |
michael@0 | 1040 | EffectYCbCr* effectYCbCr = |
michael@0 | 1041 | static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get()); |
michael@0 | 1042 | TextureSource* sourceYCbCr = effectYCbCr->mTexture; |
michael@0 | 1043 | const int Y = 0, Cb = 1, Cr = 2; |
michael@0 | 1044 | TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL(); |
michael@0 | 1045 | TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL(); |
michael@0 | 1046 | TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL(); |
michael@0 | 1047 | |
michael@0 | 1048 | if (!sourceY && !sourceCb && !sourceCr) { |
michael@0 | 1049 | NS_WARNING("Invalid layer texture."); |
michael@0 | 1050 | return; |
michael@0 | 1051 | } |
michael@0 | 1052 | |
michael@0 | 1053 | sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectYCbCr->mFilter); |
michael@0 | 1054 | sourceCb->BindTexture(LOCAL_GL_TEXTURE1, effectYCbCr->mFilter); |
michael@0 | 1055 | sourceCr->BindTexture(LOCAL_GL_TEXTURE2, effectYCbCr->mFilter); |
michael@0 | 1056 | |
michael@0 | 1057 | program->SetYCbCrTextureUnits(Y, Cb, Cr); |
michael@0 | 1058 | |
michael@0 | 1059 | if (maskType != MaskNone) { |
michael@0 | 1060 | BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform); |
michael@0 | 1061 | } |
michael@0 | 1062 | BindAndDrawQuadWithTextureRect(program, |
michael@0 | 1063 | gfx3DMatrix(), |
michael@0 | 1064 | effectYCbCr->mTextureCoords, |
michael@0 | 1065 | sourceYCbCr->GetSubSource(Y)); |
michael@0 | 1066 | } |
michael@0 | 1067 | break; |
michael@0 | 1068 | case EFFECT_RENDER_TARGET: { |
michael@0 | 1069 | EffectRenderTarget* effectRenderTarget = |
michael@0 | 1070 | static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get()); |
michael@0 | 1071 | RefPtr<CompositingRenderTargetOGL> surface |
michael@0 | 1072 | = static_cast<CompositingRenderTargetOGL*>(effectRenderTarget->mRenderTarget.get()); |
michael@0 | 1073 | |
michael@0 | 1074 | surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget); |
michael@0 | 1075 | |
michael@0 | 1076 | // Drawing is always flipped, but when copying between surfaces we want to avoid |
michael@0 | 1077 | // this, so apply a flip here to cancel the other one out. |
michael@0 | 1078 | Matrix transform; |
michael@0 | 1079 | transform.Translate(0.0, 1.0); |
michael@0 | 1080 | transform.Scale(1.0f, -1.0f); |
michael@0 | 1081 | program->SetTextureTransform(Matrix4x4::From2D(transform)); |
michael@0 | 1082 | program->SetTextureUnit(0); |
michael@0 | 1083 | |
michael@0 | 1084 | if (maskType != MaskNone) { |
michael@0 | 1085 | sourceMask->BindTexture(LOCAL_GL_TEXTURE1, gfx::Filter::LINEAR); |
michael@0 | 1086 | program->SetMaskTextureUnit(1); |
michael@0 | 1087 | program->SetMaskLayerTransform(maskQuadTransform); |
michael@0 | 1088 | } |
michael@0 | 1089 | |
michael@0 | 1090 | if (config.mFeatures & ENABLE_TEXTURE_RECT) { |
michael@0 | 1091 | // 2DRect case, get the multiplier right for a sampler2DRect |
michael@0 | 1092 | program->SetTexCoordMultiplier(aRect.width, aRect.height); |
michael@0 | 1093 | } |
michael@0 | 1094 | |
michael@0 | 1095 | // Drawing is always flipped, but when copying between surfaces we want to avoid |
michael@0 | 1096 | // this. Pass true for the flip parameter to introduce a second flip |
michael@0 | 1097 | // that cancels the other one out. |
michael@0 | 1098 | BindAndDrawQuad(program); |
michael@0 | 1099 | } |
michael@0 | 1100 | break; |
michael@0 | 1101 | case EFFECT_COMPONENT_ALPHA: { |
michael@0 | 1102 | MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled()); |
michael@0 | 1103 | EffectComponentAlpha* effectComponentAlpha = |
michael@0 | 1104 | static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get()); |
michael@0 | 1105 | TextureSourceOGL* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceOGL(); |
michael@0 | 1106 | TextureSourceOGL* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceOGL(); |
michael@0 | 1107 | |
michael@0 | 1108 | if (!sourceOnBlack->IsValid() || |
michael@0 | 1109 | !sourceOnWhite->IsValid()) { |
michael@0 | 1110 | NS_WARNING("Invalid layer texture for component alpha"); |
michael@0 | 1111 | return; |
michael@0 | 1112 | } |
michael@0 | 1113 | |
michael@0 | 1114 | sourceOnBlack->BindTexture(LOCAL_GL_TEXTURE0, effectComponentAlpha->mFilter); |
michael@0 | 1115 | sourceOnWhite->BindTexture(LOCAL_GL_TEXTURE1, effectComponentAlpha->mFilter); |
michael@0 | 1116 | |
michael@0 | 1117 | program->SetBlackTextureUnit(0); |
michael@0 | 1118 | program->SetWhiteTextureUnit(1); |
michael@0 | 1119 | program->SetTextureTransform(gfx::Matrix4x4()); |
michael@0 | 1120 | |
michael@0 | 1121 | if (maskType != MaskNone) { |
michael@0 | 1122 | BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform); |
michael@0 | 1123 | } |
michael@0 | 1124 | // Pass 1. |
michael@0 | 1125 | gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR, |
michael@0 | 1126 | LOCAL_GL_ONE, LOCAL_GL_ONE); |
michael@0 | 1127 | program->SetTexturePass2(false); |
michael@0 | 1128 | BindAndDrawQuadWithTextureRect(program, |
michael@0 | 1129 | gfx3DMatrix(), |
michael@0 | 1130 | effectComponentAlpha->mTextureCoords, |
michael@0 | 1131 | effectComponentAlpha->mOnBlack); |
michael@0 | 1132 | |
michael@0 | 1133 | // Pass 2. |
michael@0 | 1134 | gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE, |
michael@0 | 1135 | LOCAL_GL_ONE, LOCAL_GL_ONE); |
michael@0 | 1136 | |
michael@0 | 1137 | #ifdef XP_MACOSX |
michael@0 | 1138 | if (gl()->WorkAroundDriverBugs() && |
michael@0 | 1139 | gl()->Vendor() == GLVendor::NVIDIA && |
michael@0 | 1140 | !nsCocoaFeatures::OnMavericksOrLater()) { |
michael@0 | 1141 | // Bug 987497: With some GPUs the nvidia driver on 10.8 and below |
michael@0 | 1142 | // won't pick up the TexturePass2 uniform change below if we don't do |
michael@0 | 1143 | // something to force it. Re-activating the shader seems to be one way |
michael@0 | 1144 | // of achieving that. |
michael@0 | 1145 | program->Activate(); |
michael@0 | 1146 | } |
michael@0 | 1147 | #endif |
michael@0 | 1148 | |
michael@0 | 1149 | program->SetTexturePass2(true); |
michael@0 | 1150 | BindAndDrawQuadWithTextureRect(program, |
michael@0 | 1151 | gfx3DMatrix(), |
michael@0 | 1152 | effectComponentAlpha->mTextureCoords, |
michael@0 | 1153 | effectComponentAlpha->mOnBlack); |
michael@0 | 1154 | |
michael@0 | 1155 | mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, |
michael@0 | 1156 | LOCAL_GL_ONE, LOCAL_GL_ONE); |
michael@0 | 1157 | } |
michael@0 | 1158 | break; |
michael@0 | 1159 | default: |
michael@0 | 1160 | MOZ_ASSERT(false, "Unhandled effect type"); |
michael@0 | 1161 | break; |
michael@0 | 1162 | } |
michael@0 | 1163 | |
michael@0 | 1164 | // in case rendering has used some other GL context |
michael@0 | 1165 | MakeCurrent(); |
michael@0 | 1166 | } |
michael@0 | 1167 | |
michael@0 | 1168 | void |
michael@0 | 1169 | CompositorOGL::EndFrame() |
michael@0 | 1170 | { |
michael@0 | 1171 | PROFILER_LABEL("CompositorOGL", "EndFrame"); |
michael@0 | 1172 | MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored"); |
michael@0 | 1173 | |
michael@0 | 1174 | #ifdef MOZ_DUMP_PAINTING |
michael@0 | 1175 | if (gfxUtils::sDumpPainting) { |
michael@0 | 1176 | nsIntRect rect; |
michael@0 | 1177 | if (mUseExternalSurfaceSize) { |
michael@0 | 1178 | rect = nsIntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height); |
michael@0 | 1179 | } else { |
michael@0 | 1180 | mWidget->GetBounds(rect); |
michael@0 | 1181 | } |
michael@0 | 1182 | RefPtr<DrawTarget> target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(rect.width, rect.height), SurfaceFormat::B8G8R8A8); |
michael@0 | 1183 | CopyToTarget(target, mCurrentRenderTarget->GetTransform()); |
michael@0 | 1184 | |
michael@0 | 1185 | WriteSnapshotToDumpFile(this, target); |
michael@0 | 1186 | } |
michael@0 | 1187 | #endif |
michael@0 | 1188 | |
michael@0 | 1189 | mFrameInProgress = false; |
michael@0 | 1190 | |
michael@0 | 1191 | LayerScope::EndFrame(mGLContext); |
michael@0 | 1192 | |
michael@0 | 1193 | if (mTarget) { |
michael@0 | 1194 | CopyToTarget(mTarget, mCurrentRenderTarget->GetTransform()); |
michael@0 | 1195 | mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); |
michael@0 | 1196 | mCurrentRenderTarget = nullptr; |
michael@0 | 1197 | return; |
michael@0 | 1198 | } |
michael@0 | 1199 | |
michael@0 | 1200 | mCurrentRenderTarget = nullptr; |
michael@0 | 1201 | |
michael@0 | 1202 | if (mTexturePool) { |
michael@0 | 1203 | mTexturePool->EndFrame(); |
michael@0 | 1204 | } |
michael@0 | 1205 | |
michael@0 | 1206 | mGLContext->SwapBuffers(); |
michael@0 | 1207 | mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); |
michael@0 | 1208 | |
michael@0 | 1209 | // Unbind all textures |
michael@0 | 1210 | mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); |
michael@0 | 1211 | mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0); |
michael@0 | 1212 | if (!mGLContext->IsGLES()) { |
michael@0 | 1213 | mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0); |
michael@0 | 1214 | } |
michael@0 | 1215 | |
michael@0 | 1216 | mGLContext->fActiveTexture(LOCAL_GL_TEXTURE1); |
michael@0 | 1217 | mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0); |
michael@0 | 1218 | if (!mGLContext->IsGLES()) { |
michael@0 | 1219 | mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0); |
michael@0 | 1220 | } |
michael@0 | 1221 | |
michael@0 | 1222 | mGLContext->fActiveTexture(LOCAL_GL_TEXTURE2); |
michael@0 | 1223 | mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0); |
michael@0 | 1224 | if (!mGLContext->IsGLES()) { |
michael@0 | 1225 | mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0); |
michael@0 | 1226 | } |
michael@0 | 1227 | } |
michael@0 | 1228 | |
michael@0 | 1229 | #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 |
michael@0 | 1230 | void |
michael@0 | 1231 | CompositorOGL::SetFBAcquireFence(Layer* aLayer) |
michael@0 | 1232 | { |
michael@0 | 1233 | // OpenGL does not provide ReleaseFence for rendering. |
michael@0 | 1234 | // Instead use FBAcquireFence as layer buffer's ReleaseFence |
michael@0 | 1235 | // to prevent flickering and tearing. |
michael@0 | 1236 | // FBAcquireFence is FramebufferSurface's AcquireFence. |
michael@0 | 1237 | // AcquireFence will be signaled when a buffer's content is available. |
michael@0 | 1238 | // See Bug 974152. |
michael@0 | 1239 | |
michael@0 | 1240 | if (!aLayer) { |
michael@0 | 1241 | return; |
michael@0 | 1242 | } |
michael@0 | 1243 | |
michael@0 | 1244 | const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion(); |
michael@0 | 1245 | if (visibleRegion.IsEmpty()) { |
michael@0 | 1246 | return; |
michael@0 | 1247 | } |
michael@0 | 1248 | |
michael@0 | 1249 | // Set FBAcquireFence on ContainerLayer's childs |
michael@0 | 1250 | ContainerLayer* container = aLayer->AsContainerLayer(); |
michael@0 | 1251 | if (container) { |
michael@0 | 1252 | for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) { |
michael@0 | 1253 | SetFBAcquireFence(child); |
michael@0 | 1254 | } |
michael@0 | 1255 | return; |
michael@0 | 1256 | } |
michael@0 | 1257 | |
michael@0 | 1258 | // Set FBAcquireFence as tiles' ReleaseFence on TiledLayerComposer. |
michael@0 | 1259 | TiledLayerComposer* composer = nullptr; |
michael@0 | 1260 | LayerComposite* shadow = aLayer->AsLayerComposite(); |
michael@0 | 1261 | if (shadow) { |
michael@0 | 1262 | composer = shadow->GetTiledLayerComposer(); |
michael@0 | 1263 | if (composer) { |
michael@0 | 1264 | composer->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd())); |
michael@0 | 1265 | return; |
michael@0 | 1266 | } |
michael@0 | 1267 | } |
michael@0 | 1268 | |
michael@0 | 1269 | // Set FBAcquireFence as layer buffer's ReleaseFence |
michael@0 | 1270 | LayerRenderState state = aLayer->GetRenderState(); |
michael@0 | 1271 | if (!state.mTexture) { |
michael@0 | 1272 | return; |
michael@0 | 1273 | } |
michael@0 | 1274 | TextureHostOGL* texture = state.mTexture->AsHostOGL(); |
michael@0 | 1275 | if (!texture) { |
michael@0 | 1276 | return; |
michael@0 | 1277 | } |
michael@0 | 1278 | texture->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd())); |
michael@0 | 1279 | } |
michael@0 | 1280 | #else |
michael@0 | 1281 | void |
michael@0 | 1282 | CompositorOGL::SetFBAcquireFence(Layer* aLayer) |
michael@0 | 1283 | { |
michael@0 | 1284 | } |
michael@0 | 1285 | #endif |
michael@0 | 1286 | |
michael@0 | 1287 | void |
michael@0 | 1288 | CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform) |
michael@0 | 1289 | { |
michael@0 | 1290 | // This lets us reftest and screenshot content rendered externally |
michael@0 | 1291 | if (mTarget) { |
michael@0 | 1292 | MakeCurrent(); |
michael@0 | 1293 | CopyToTarget(mTarget, aTransform); |
michael@0 | 1294 | mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); |
michael@0 | 1295 | } |
michael@0 | 1296 | if (mTexturePool) { |
michael@0 | 1297 | mTexturePool->EndFrame(); |
michael@0 | 1298 | } |
michael@0 | 1299 | } |
michael@0 | 1300 | |
michael@0 | 1301 | void |
michael@0 | 1302 | CompositorOGL::AbortFrame() |
michael@0 | 1303 | { |
michael@0 | 1304 | mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); |
michael@0 | 1305 | mFrameInProgress = false; |
michael@0 | 1306 | mCurrentRenderTarget = nullptr; |
michael@0 | 1307 | |
michael@0 | 1308 | if (mTexturePool) { |
michael@0 | 1309 | mTexturePool->EndFrame(); |
michael@0 | 1310 | } |
michael@0 | 1311 | } |
michael@0 | 1312 | |
michael@0 | 1313 | void |
michael@0 | 1314 | CompositorOGL::SetDestinationSurfaceSize(const gfx::IntSize& aSize) |
michael@0 | 1315 | { |
michael@0 | 1316 | mSurfaceSize.width = aSize.width; |
michael@0 | 1317 | mSurfaceSize.height = aSize.height; |
michael@0 | 1318 | } |
michael@0 | 1319 | |
michael@0 | 1320 | void |
michael@0 | 1321 | CompositorOGL::CopyToTarget(DrawTarget *aTarget, const gfx::Matrix& aTransform) |
michael@0 | 1322 | { |
michael@0 | 1323 | IntRect rect; |
michael@0 | 1324 | if (mUseExternalSurfaceSize) { |
michael@0 | 1325 | rect = IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height); |
michael@0 | 1326 | } else { |
michael@0 | 1327 | rect = IntRect(0, 0, mWidgetSize.width, mWidgetSize.height); |
michael@0 | 1328 | } |
michael@0 | 1329 | GLint width = rect.width; |
michael@0 | 1330 | GLint height = rect.height; |
michael@0 | 1331 | |
michael@0 | 1332 | if ((int64_t(width) * int64_t(height) * int64_t(4)) > INT32_MAX) { |
michael@0 | 1333 | NS_ERROR("Widget size too big - integer overflow!"); |
michael@0 | 1334 | return; |
michael@0 | 1335 | } |
michael@0 | 1336 | |
michael@0 | 1337 | mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); |
michael@0 | 1338 | |
michael@0 | 1339 | if (!mGLContext->IsGLES()) { |
michael@0 | 1340 | // GLES2 promises that binding to any custom FBO will attach |
michael@0 | 1341 | // to GL_COLOR_ATTACHMENT0 attachment point. |
michael@0 | 1342 | mGLContext->fReadBuffer(LOCAL_GL_BACK); |
michael@0 | 1343 | } |
michael@0 | 1344 | |
michael@0 | 1345 | RefPtr<DataSourceSurface> source = |
michael@0 | 1346 | Factory::CreateDataSourceSurface(rect.Size(), gfx::SurfaceFormat::B8G8R8A8); |
michael@0 | 1347 | |
michael@0 | 1348 | DataSourceSurface::MappedSurface map; |
michael@0 | 1349 | source->Map(DataSourceSurface::MapType::WRITE, &map); |
michael@0 | 1350 | // XXX we should do this properly one day without using the gfxImageSurface |
michael@0 | 1351 | nsRefPtr<gfxImageSurface> surf = |
michael@0 | 1352 | new gfxImageSurface(map.mData, |
michael@0 | 1353 | gfxIntSize(width, height), |
michael@0 | 1354 | map.mStride, |
michael@0 | 1355 | gfxImageFormat::ARGB32); |
michael@0 | 1356 | ReadPixelsIntoImageSurface(mGLContext, surf); |
michael@0 | 1357 | source->Unmap(); |
michael@0 | 1358 | |
michael@0 | 1359 | // Map from GL space to Cairo space and reverse the world transform. |
michael@0 | 1360 | Matrix glToCairoTransform = aTransform; |
michael@0 | 1361 | glToCairoTransform.Invert(); |
michael@0 | 1362 | glToCairoTransform.Scale(1.0, -1.0); |
michael@0 | 1363 | glToCairoTransform.Translate(0.0, -height); |
michael@0 | 1364 | |
michael@0 | 1365 | Matrix oldMatrix = aTarget->GetTransform(); |
michael@0 | 1366 | aTarget->SetTransform(glToCairoTransform); |
michael@0 | 1367 | Rect floatRect = Rect(rect.x, rect.y, rect.width, rect.height); |
michael@0 | 1368 | aTarget->DrawSurface(source, floatRect, floatRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE)); |
michael@0 | 1369 | aTarget->SetTransform(oldMatrix); |
michael@0 | 1370 | aTarget->Flush(); |
michael@0 | 1371 | } |
michael@0 | 1372 | |
michael@0 | 1373 | void |
michael@0 | 1374 | CompositorOGL::Pause() |
michael@0 | 1375 | { |
michael@0 | 1376 | #ifdef MOZ_WIDGET_ANDROID |
michael@0 | 1377 | if (!gl() || gl()->IsDestroyed()) |
michael@0 | 1378 | return; |
michael@0 | 1379 | |
michael@0 | 1380 | // ReleaseSurface internally calls MakeCurrent. |
michael@0 | 1381 | gl()->ReleaseSurface(); |
michael@0 | 1382 | #endif |
michael@0 | 1383 | } |
michael@0 | 1384 | |
michael@0 | 1385 | bool |
michael@0 | 1386 | CompositorOGL::Resume() |
michael@0 | 1387 | { |
michael@0 | 1388 | #ifdef MOZ_WIDGET_ANDROID |
michael@0 | 1389 | if (!gl() || gl()->IsDestroyed()) |
michael@0 | 1390 | return false; |
michael@0 | 1391 | |
michael@0 | 1392 | // RenewSurface internally calls MakeCurrent. |
michael@0 | 1393 | return gl()->RenewSurface(); |
michael@0 | 1394 | #endif |
michael@0 | 1395 | return true; |
michael@0 | 1396 | } |
michael@0 | 1397 | |
michael@0 | 1398 | TemporaryRef<DataTextureSource> |
michael@0 | 1399 | CompositorOGL::CreateDataTextureSource(TextureFlags aFlags) |
michael@0 | 1400 | { |
michael@0 | 1401 | RefPtr<DataTextureSource> result = |
michael@0 | 1402 | new TextureImageTextureSourceOGL(mGLContext, aFlags); |
michael@0 | 1403 | return result; |
michael@0 | 1404 | } |
michael@0 | 1405 | |
michael@0 | 1406 | bool |
michael@0 | 1407 | CompositorOGL::SupportsPartialTextureUpdate() |
michael@0 | 1408 | { |
michael@0 | 1409 | return CanUploadSubTextures(mGLContext); |
michael@0 | 1410 | } |
michael@0 | 1411 | |
michael@0 | 1412 | int32_t |
michael@0 | 1413 | CompositorOGL::GetMaxTextureSize() const |
michael@0 | 1414 | { |
michael@0 | 1415 | MOZ_ASSERT(mGLContext); |
michael@0 | 1416 | GLint texSize = 0; |
michael@0 | 1417 | mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, |
michael@0 | 1418 | &texSize); |
michael@0 | 1419 | MOZ_ASSERT(texSize != 0); |
michael@0 | 1420 | return texSize; |
michael@0 | 1421 | } |
michael@0 | 1422 | |
michael@0 | 1423 | void |
michael@0 | 1424 | CompositorOGL::MakeCurrent(MakeCurrentFlags aFlags) { |
michael@0 | 1425 | if (mDestroyed) { |
michael@0 | 1426 | NS_WARNING("Call on destroyed layer manager"); |
michael@0 | 1427 | return; |
michael@0 | 1428 | } |
michael@0 | 1429 | mGLContext->MakeCurrent(aFlags & ForceMakeCurrent); |
michael@0 | 1430 | } |
michael@0 | 1431 | |
michael@0 | 1432 | void |
michael@0 | 1433 | CompositorOGL::BindQuadVBO() { |
michael@0 | 1434 | mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO); |
michael@0 | 1435 | } |
michael@0 | 1436 | |
michael@0 | 1437 | void |
michael@0 | 1438 | CompositorOGL::QuadVBOVerticesAttrib(GLuint aAttribIndex) { |
michael@0 | 1439 | mGLContext->fVertexAttribPointer(aAttribIndex, 2, |
michael@0 | 1440 | LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, |
michael@0 | 1441 | (GLvoid*) QuadVBOVertexOffset()); |
michael@0 | 1442 | } |
michael@0 | 1443 | |
michael@0 | 1444 | void |
michael@0 | 1445 | CompositorOGL::QuadVBOTexCoordsAttrib(GLuint aAttribIndex) { |
michael@0 | 1446 | mGLContext->fVertexAttribPointer(aAttribIndex, 2, |
michael@0 | 1447 | LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, |
michael@0 | 1448 | (GLvoid*) QuadVBOTexCoordOffset()); |
michael@0 | 1449 | } |
michael@0 | 1450 | |
michael@0 | 1451 | void |
michael@0 | 1452 | CompositorOGL::BindAndDrawQuad(GLuint aVertAttribIndex, |
michael@0 | 1453 | GLuint aTexCoordAttribIndex, |
michael@0 | 1454 | GLuint aDrawMode) |
michael@0 | 1455 | { |
michael@0 | 1456 | BindQuadVBO(); |
michael@0 | 1457 | QuadVBOVerticesAttrib(aVertAttribIndex); |
michael@0 | 1458 | |
michael@0 | 1459 | if (aTexCoordAttribIndex != GLuint(-1)) { |
michael@0 | 1460 | QuadVBOTexCoordsAttrib(aTexCoordAttribIndex); |
michael@0 | 1461 | mGLContext->fEnableVertexAttribArray(aTexCoordAttribIndex); |
michael@0 | 1462 | } |
michael@0 | 1463 | |
michael@0 | 1464 | mGLContext->fEnableVertexAttribArray(aVertAttribIndex); |
michael@0 | 1465 | if (aDrawMode == LOCAL_GL_LINE_STRIP) { |
michael@0 | 1466 | mGLContext->fDrawArrays(aDrawMode, 1, 2); |
michael@0 | 1467 | } else { |
michael@0 | 1468 | mGLContext->fDrawArrays(aDrawMode, 0, 4); |
michael@0 | 1469 | } |
michael@0 | 1470 | } |
michael@0 | 1471 | |
michael@0 | 1472 | void |
michael@0 | 1473 | CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg, |
michael@0 | 1474 | GLuint aDrawMode) |
michael@0 | 1475 | { |
michael@0 | 1476 | NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized"); |
michael@0 | 1477 | BindAndDrawQuad(aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib), |
michael@0 | 1478 | aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib), |
michael@0 | 1479 | aDrawMode); |
michael@0 | 1480 | } |
michael@0 | 1481 | |
michael@0 | 1482 | GLuint |
michael@0 | 1483 | CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit) |
michael@0 | 1484 | { |
michael@0 | 1485 | if (!mTexturePool) { |
michael@0 | 1486 | #ifdef MOZ_WIDGET_GONK |
michael@0 | 1487 | mTexturePool = new PerFrameTexturePoolOGL(gl()); |
michael@0 | 1488 | #else |
michael@0 | 1489 | mTexturePool = new PerUnitTexturePoolOGL(gl()); |
michael@0 | 1490 | #endif |
michael@0 | 1491 | } |
michael@0 | 1492 | return mTexturePool->GetTexture(aTarget, aUnit); |
michael@0 | 1493 | } |
michael@0 | 1494 | |
michael@0 | 1495 | GLuint |
michael@0 | 1496 | PerUnitTexturePoolOGL::GetTexture(GLenum aTarget, GLenum aTextureUnit) |
michael@0 | 1497 | { |
michael@0 | 1498 | if (mTextureTarget == 0) { |
michael@0 | 1499 | mTextureTarget = aTarget; |
michael@0 | 1500 | } |
michael@0 | 1501 | MOZ_ASSERT(mTextureTarget == aTarget); |
michael@0 | 1502 | |
michael@0 | 1503 | size_t index = aTextureUnit - LOCAL_GL_TEXTURE0; |
michael@0 | 1504 | // lazily grow the array of temporary textures |
michael@0 | 1505 | if (mTextures.Length() <= index) { |
michael@0 | 1506 | size_t prevLength = mTextures.Length(); |
michael@0 | 1507 | mTextures.SetLength(index + 1); |
michael@0 | 1508 | for(unsigned int i = prevLength; i <= index; ++i) { |
michael@0 | 1509 | mTextures[i] = 0; |
michael@0 | 1510 | } |
michael@0 | 1511 | } |
michael@0 | 1512 | // lazily initialize the temporary textures |
michael@0 | 1513 | if (!mTextures[index]) { |
michael@0 | 1514 | if (!mGL->MakeCurrent()) { |
michael@0 | 1515 | return 0; |
michael@0 | 1516 | } |
michael@0 | 1517 | mGL->fGenTextures(1, &mTextures[index]); |
michael@0 | 1518 | mGL->fBindTexture(aTarget, mTextures[index]); |
michael@0 | 1519 | mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); |
michael@0 | 1520 | mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); |
michael@0 | 1521 | } |
michael@0 | 1522 | return mTextures[index]; |
michael@0 | 1523 | } |
michael@0 | 1524 | |
michael@0 | 1525 | void |
michael@0 | 1526 | PerUnitTexturePoolOGL::DestroyTextures() |
michael@0 | 1527 | { |
michael@0 | 1528 | if (mGL && mGL->MakeCurrent()) { |
michael@0 | 1529 | if (mTextures.Length() > 0) { |
michael@0 | 1530 | mGL->fDeleteTextures(mTextures.Length(), &mTextures[0]); |
michael@0 | 1531 | } |
michael@0 | 1532 | } |
michael@0 | 1533 | mTextures.SetLength(0); |
michael@0 | 1534 | } |
michael@0 | 1535 | |
michael@0 | 1536 | void |
michael@0 | 1537 | PerFrameTexturePoolOGL::DestroyTextures() |
michael@0 | 1538 | { |
michael@0 | 1539 | if (!mGL->MakeCurrent()) { |
michael@0 | 1540 | return; |
michael@0 | 1541 | } |
michael@0 | 1542 | |
michael@0 | 1543 | if (mUnusedTextures.Length() > 0) { |
michael@0 | 1544 | mGL->fDeleteTextures(mUnusedTextures.Length(), &mUnusedTextures[0]); |
michael@0 | 1545 | mUnusedTextures.Clear(); |
michael@0 | 1546 | } |
michael@0 | 1547 | |
michael@0 | 1548 | if (mCreatedTextures.Length() > 0) { |
michael@0 | 1549 | mGL->fDeleteTextures(mCreatedTextures.Length(), &mCreatedTextures[0]); |
michael@0 | 1550 | mCreatedTextures.Clear(); |
michael@0 | 1551 | } |
michael@0 | 1552 | } |
michael@0 | 1553 | |
michael@0 | 1554 | GLuint |
michael@0 | 1555 | PerFrameTexturePoolOGL::GetTexture(GLenum aTarget, GLenum) |
michael@0 | 1556 | { |
michael@0 | 1557 | if (mTextureTarget == 0) { |
michael@0 | 1558 | mTextureTarget = aTarget; |
michael@0 | 1559 | } |
michael@0 | 1560 | |
michael@0 | 1561 | // The pool should always use the same texture target because it is illegal |
michael@0 | 1562 | // to change the target of an already exisiting gl texture. |
michael@0 | 1563 | // If we need to use several targets, a pool with several sub-pools (one per |
michael@0 | 1564 | // target) will have to be implemented. |
michael@0 | 1565 | // At the moment this pool is only used with tiling on b2g so we always need |
michael@0 | 1566 | // the same target. |
michael@0 | 1567 | MOZ_ASSERT(mTextureTarget == aTarget); |
michael@0 | 1568 | |
michael@0 | 1569 | GLuint texture = 0; |
michael@0 | 1570 | |
michael@0 | 1571 | if (!mUnusedTextures.IsEmpty()) { |
michael@0 | 1572 | // Try to reuse one from the unused pile first |
michael@0 | 1573 | texture = mUnusedTextures[0]; |
michael@0 | 1574 | mUnusedTextures.RemoveElementAt(0); |
michael@0 | 1575 | } else if (mGL->MakeCurrent()) { |
michael@0 | 1576 | // There isn't one to reuse, create one. |
michael@0 | 1577 | mGL->fGenTextures(1, &texture); |
michael@0 | 1578 | mGL->fBindTexture(aTarget, texture); |
michael@0 | 1579 | mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); |
michael@0 | 1580 | mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); |
michael@0 | 1581 | } |
michael@0 | 1582 | |
michael@0 | 1583 | if (texture) { |
michael@0 | 1584 | mCreatedTextures.AppendElement(texture); |
michael@0 | 1585 | } |
michael@0 | 1586 | |
michael@0 | 1587 | return texture; |
michael@0 | 1588 | } |
michael@0 | 1589 | |
michael@0 | 1590 | void |
michael@0 | 1591 | PerFrameTexturePoolOGL::EndFrame() |
michael@0 | 1592 | { |
michael@0 | 1593 | if (!mGL->MakeCurrent()) { |
michael@0 | 1594 | // this means the context got destroyed underneith us somehow, and the driver |
michael@0 | 1595 | // already has destroyed the textures. |
michael@0 | 1596 | mCreatedTextures.Clear(); |
michael@0 | 1597 | mUnusedTextures.Clear(); |
michael@0 | 1598 | return; |
michael@0 | 1599 | } |
michael@0 | 1600 | |
michael@0 | 1601 | // Some platforms have issues unlocking Gralloc buffers even when they're |
michael@0 | 1602 | // rebound. |
michael@0 | 1603 | if (gfxPrefs::OverzealousGrallocUnlocking()) { |
michael@0 | 1604 | mUnusedTextures.AppendElements(mCreatedTextures); |
michael@0 | 1605 | mCreatedTextures.Clear(); |
michael@0 | 1606 | } |
michael@0 | 1607 | |
michael@0 | 1608 | // Delete unused textures |
michael@0 | 1609 | for (size_t i = 0; i < mUnusedTextures.Length(); i++) { |
michael@0 | 1610 | GLuint texture = mUnusedTextures[i]; |
michael@0 | 1611 | mGL->fDeleteTextures(1, &texture); |
michael@0 | 1612 | } |
michael@0 | 1613 | mUnusedTextures.Clear(); |
michael@0 | 1614 | |
michael@0 | 1615 | // Move all created textures into the unused pile |
michael@0 | 1616 | mUnusedTextures.AppendElements(mCreatedTextures); |
michael@0 | 1617 | mCreatedTextures.Clear(); |
michael@0 | 1618 | } |
michael@0 | 1619 | |
michael@0 | 1620 | } /* layers */ |
michael@0 | 1621 | } /* mozilla */ |