/src/mozilla-central/gfx/layers/opengl/CompositorOGL.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "CompositorOGL.h" |
8 | | #include <stddef.h> // for size_t |
9 | | #include <stdint.h> // for uint32_t, uint8_t |
10 | | #include <stdlib.h> // for free, malloc |
11 | | #include "GLContextProvider.h" // for GLContextProvider |
12 | | #include "GLContext.h" // for GLContext |
13 | | #include "GLUploadHelpers.h" |
14 | | #include "Layers.h" // for WriteSnapshotToDumpFile |
15 | | #include "LayerScope.h" // for LayerScope |
16 | | #include "gfxCrashReporterUtils.h" // for ScopedGfxFeatureReporter |
17 | | #include "gfxEnv.h" // for gfxEnv |
18 | | #include "gfxPlatform.h" // for gfxPlatform |
19 | | #include "gfxPrefs.h" // for gfxPrefs |
20 | | #include "gfxRect.h" // for gfxRect |
21 | | #include "gfxUtils.h" // for gfxUtils, etc |
22 | | #include "mozilla/ArrayUtils.h" // for ArrayLength |
23 | | #include "mozilla/Preferences.h" // for Preferences |
24 | | #include "mozilla/gfx/BasePoint.h" // for BasePoint |
25 | | #include "mozilla/gfx/Matrix.h" // for Matrix4x4, Matrix |
26 | | #include "mozilla/gfx/Triangle.h" // for Triangle |
27 | | #include "mozilla/gfx/gfxVars.h" // for gfxVars |
28 | | #include "mozilla/layers/ImageDataSerializer.h" |
29 | | #include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite, etc |
30 | | #include "mozilla/layers/CompositingRenderTargetOGL.h" |
31 | | #include "mozilla/layers/Effects.h" // for EffectChain, TexturedEffect, etc |
32 | | #include "mozilla/layers/TextureHost.h" // for TextureSource, etc |
33 | | #include "mozilla/layers/TextureHostOGL.h" // for TextureSourceOGL, etc |
34 | | #include "mozilla/layers/PTextureParent.h" // for OtherPid() on PTextureParent |
35 | | #ifdef XP_DARWIN |
36 | | #include "mozilla/layers/TextureSync.h" // for TextureSync::etc. |
37 | | #endif |
38 | | #include "mozilla/mozalloc.h" // for operator delete, etc |
39 | | #include "nsAppRunner.h" |
40 | | #include "nsAString.h" |
41 | | #include "nsIConsoleService.h" // for nsIConsoleService, etc |
42 | | #include "nsIWidget.h" // for nsIWidget |
43 | | #include "nsLiteralString.h" // for NS_LITERAL_STRING |
44 | | #include "nsMathUtils.h" // for NS_roundf |
45 | | #include "nsRect.h" // for mozilla::gfx::IntRect |
46 | | #include "nsServiceManagerUtils.h" // for do_GetService |
47 | | #include "nsString.h" // for nsString, nsAutoCString, etc |
48 | | #include "ScopedGLHelpers.h" |
49 | | #include "GLReadTexImageHelper.h" |
50 | | #include "GLBlitTextureImageHelper.h" |
51 | | #include "HeapCopyOfStackArray.h" |
52 | | #include "GLBlitHelper.h" |
53 | | #include "mozilla/gfx/Swizzle.h" |
54 | | |
55 | | #if MOZ_WIDGET_ANDROID |
56 | | #include "GeneratedJNIWrappers.h" |
57 | | #endif |
58 | | |
59 | | #include "GeckoProfiler.h" |
60 | | |
61 | | namespace mozilla { |
62 | | |
63 | | using namespace std; |
64 | | using namespace gfx; |
65 | | |
66 | | namespace layers { |
67 | | |
68 | | using namespace mozilla::gl; |
69 | | |
70 | | static const GLuint kCoordinateAttributeIndex = 0; |
71 | | static const GLuint kTexCoordinateAttributeIndex = 1; |
72 | | |
73 | | class AsyncReadbackBufferOGL final : public AsyncReadbackBuffer |
74 | | { |
75 | | public: |
76 | | AsyncReadbackBufferOGL(GLContext* aGL, const IntSize& aSize); |
77 | | |
78 | | bool MapAndCopyInto(DataSourceSurface* aSurface, |
79 | | const IntSize& aReadSize) const override; |
80 | | |
81 | | void Bind() const |
82 | 0 | { |
83 | 0 | mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, mBufferHandle); |
84 | 0 | mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 1); |
85 | 0 | } |
86 | | |
87 | | protected: |
88 | | ~AsyncReadbackBufferOGL() override; |
89 | | |
90 | | private: |
91 | | GLContext* mGL; |
92 | | GLuint mBufferHandle; |
93 | | }; |
94 | | |
95 | | AsyncReadbackBufferOGL::AsyncReadbackBufferOGL(GLContext* aGL, |
96 | | const IntSize& aSize) |
97 | | : AsyncReadbackBuffer(aSize) |
98 | | , mGL(aGL) |
99 | | , mBufferHandle(0) |
100 | 0 | { |
101 | 0 | size_t bufferByteCount = mSize.width * mSize.height * 4; |
102 | 0 | mGL->fGenBuffers(1, &mBufferHandle); |
103 | 0 |
|
104 | 0 | ScopedPackState scopedPackState(mGL); |
105 | 0 | Bind(); |
106 | 0 | mGL->fBufferData(LOCAL_GL_PIXEL_PACK_BUFFER, bufferByteCount, nullptr, |
107 | 0 | LOCAL_GL_STREAM_READ); |
108 | 0 | } |
109 | | |
110 | | AsyncReadbackBufferOGL::~AsyncReadbackBufferOGL() |
111 | 0 | { |
112 | 0 | if (mGL && mGL->MakeCurrent()) { |
113 | 0 | mGL->fDeleteBuffers(1, &mBufferHandle); |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | | bool |
118 | | AsyncReadbackBufferOGL::MapAndCopyInto(DataSourceSurface* aSurface, |
119 | | const IntSize& aReadSize) const |
120 | 0 | { |
121 | 0 | MOZ_RELEASE_ASSERT(aReadSize <= aSurface->GetSize()); |
122 | 0 |
|
123 | 0 | if (!mGL || !mGL->MakeCurrent()) { |
124 | 0 | return false; |
125 | 0 | } |
126 | 0 | |
127 | 0 | ScopedPackState scopedPackState(mGL); |
128 | 0 | Bind(); |
129 | 0 | uint8_t* srcData = static_cast<uint8_t*>( |
130 | 0 | mGL->fMapBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, LOCAL_GL_READ_ONLY)); |
131 | 0 |
|
132 | 0 | if (!srcData) { |
133 | 0 | return false; |
134 | 0 | } |
135 | 0 | |
136 | 0 | int32_t srcStride = mSize.width * 4; // Bind() sets an alignment of 1 |
137 | 0 | DataSourceSurface::ScopedMap map(aSurface, DataSourceSurface::WRITE); |
138 | 0 | uint8_t* destData = map.GetData(); |
139 | 0 | int32_t destStride = map.GetStride(); |
140 | 0 | SurfaceFormat destFormat = aSurface->GetFormat(); |
141 | 0 | for (int32_t destRow = 0; destRow < aReadSize.height; destRow++) { |
142 | 0 | // Turn srcData upside down during the copy. |
143 | 0 | int32_t srcRow = aReadSize.height - 1 - destRow; |
144 | 0 | uint8_t* src = &srcData[srcRow * srcStride]; |
145 | 0 | uint8_t* dest = &destData[destRow * destStride]; |
146 | 0 | SwizzleData(src, srcStride, SurfaceFormat::R8G8B8A8, |
147 | 0 | dest, destStride, destFormat, IntSize(aReadSize.width, 1)); |
148 | 0 | } |
149 | 0 |
|
150 | 0 | mGL->fUnmapBuffer(LOCAL_GL_PIXEL_PACK_BUFFER); |
151 | 0 |
|
152 | 0 | return true; |
153 | 0 | } |
154 | | |
155 | | static void |
156 | | BindMaskForProgram(ShaderProgramOGL* aProgram, TextureSourceOGL* aSourceMask, |
157 | | GLenum aTexUnit, const gfx::Matrix4x4& aTransform) |
158 | 0 | { |
159 | 0 | MOZ_ASSERT(LOCAL_GL_TEXTURE0 <= aTexUnit && aTexUnit <= LOCAL_GL_TEXTURE31); |
160 | 0 | aSourceMask->BindTexture(aTexUnit, gfx::SamplingFilter::LINEAR); |
161 | 0 | aProgram->SetMaskTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0); |
162 | 0 | aProgram->SetMaskLayerTransform(aTransform); |
163 | 0 | } |
164 | | |
165 | | void |
166 | | CompositorOGL::BindBackdrop(ShaderProgramOGL* aProgram, GLuint aBackdrop, GLenum aTexUnit) |
167 | 0 | { |
168 | 0 | MOZ_ASSERT(aBackdrop); |
169 | 0 |
|
170 | 0 | mGLContext->fActiveTexture(aTexUnit); |
171 | 0 | mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, aBackdrop); |
172 | 0 | mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); |
173 | 0 | mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); |
174 | 0 | aProgram->SetBackdropTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0); |
175 | 0 | } |
176 | | |
177 | | CompositorOGL::CompositorOGL(CompositorBridgeParent* aParent, |
178 | | widget::CompositorWidget* aWidget, |
179 | | int aSurfaceWidth, int aSurfaceHeight, |
180 | | bool aUseExternalSurfaceSize) |
181 | | : Compositor(aWidget, aParent) |
182 | | , mWidgetSize(-1, -1) |
183 | | , mSurfaceSize(aSurfaceWidth, aSurfaceHeight) |
184 | | , mFBOTextureTarget(0) |
185 | | , mWindowRenderTarget(nullptr) |
186 | | , mQuadVBO(0) |
187 | | , mTriangleVBO(0) |
188 | | , mHasBGRA(0) |
189 | | , mUseExternalSurfaceSize(aUseExternalSurfaceSize) |
190 | | , mFrameInProgress(false) |
191 | | , mDestroyed(false) |
192 | | , mViewportSize(0, 0) |
193 | | , mCurrentProgram(nullptr) |
194 | 0 | { |
195 | | #ifdef XP_DARWIN |
196 | | TextureSync::RegisterTextureSourceProvider(this); |
197 | | #endif |
198 | | MOZ_COUNT_CTOR(CompositorOGL); |
199 | 0 | } |
200 | | |
201 | | CompositorOGL::~CompositorOGL() |
202 | 0 | { |
203 | | #ifdef XP_DARWIN |
204 | | TextureSync::UnregisterTextureSourceProvider(this); |
205 | | #endif |
206 | | MOZ_COUNT_DTOR(CompositorOGL); |
207 | 0 | Destroy(); |
208 | 0 | } |
209 | | |
210 | | already_AddRefed<mozilla::gl::GLContext> |
211 | | CompositorOGL::CreateContext() |
212 | 0 | { |
213 | 0 | RefPtr<GLContext> context; |
214 | 0 |
|
215 | 0 | // Used by mock widget to create an offscreen context |
216 | 0 | nsIWidget* widget = mWidget->RealWidget(); |
217 | 0 | void* widgetOpenGLContext = widget ? widget->GetNativeData(NS_NATIVE_OPENGL_CONTEXT) : nullptr; |
218 | 0 | if (widgetOpenGLContext) { |
219 | 0 | GLContext* alreadyRefed = reinterpret_cast<GLContext*>(widgetOpenGLContext); |
220 | 0 | return already_AddRefed<GLContext>(alreadyRefed); |
221 | 0 | } |
222 | 0 | |
223 | | #ifdef XP_WIN |
224 | | if (gfxEnv::LayersPreferEGL()) { |
225 | | printf_stderr("Trying GL layers...\n"); |
226 | | context = gl::GLContextProviderEGL::CreateForCompositorWidget(mWidget, false); |
227 | | } |
228 | | #endif |
229 | | |
230 | 0 | // Allow to create offscreen GL context for main Layer Manager |
231 | 0 | if (!context && gfxEnv::LayersPreferOffscreen()) { |
232 | 0 | SurfaceCaps caps = SurfaceCaps::ForRGB(); |
233 | 0 | caps.preserve = false; |
234 | 0 | caps.bpp16 = gfxVars::OffscreenFormat() == SurfaceFormat::R5G6B5_UINT16; |
235 | 0 |
|
236 | 0 | nsCString discardFailureId; |
237 | 0 | context = GLContextProvider::CreateOffscreen(mSurfaceSize, |
238 | 0 | caps, CreateContextFlags::REQUIRE_COMPAT_PROFILE, |
239 | 0 | &discardFailureId); |
240 | 0 | } |
241 | 0 |
|
242 | 0 | if (!context) { |
243 | 0 | context = gl::GLContextProvider::CreateForCompositorWidget(mWidget, |
244 | 0 | gfxVars::RequiresAcceleratedGLContextForCompositorOGL()); |
245 | 0 | } |
246 | 0 |
|
247 | 0 | if (!context) { |
248 | 0 | NS_WARNING("Failed to create CompositorOGL context"); |
249 | 0 | } |
250 | 0 |
|
251 | 0 | return context.forget(); |
252 | 0 | } |
253 | | |
254 | | void |
255 | | CompositorOGL::Destroy() |
256 | 0 | { |
257 | 0 | Compositor::Destroy(); |
258 | 0 |
|
259 | 0 | if (mTexturePool) { |
260 | 0 | mTexturePool->Clear(); |
261 | 0 | mTexturePool = nullptr; |
262 | 0 | } |
263 | 0 |
|
264 | | #ifdef XP_DARWIN |
265 | | mMaybeUnlockBeforeNextComposition.Clear(); |
266 | | #endif |
267 | |
|
268 | 0 | if (!mDestroyed) { |
269 | 0 | mDestroyed = true; |
270 | 0 | CleanupResources(); |
271 | 0 | } |
272 | 0 | } |
273 | | |
274 | | void |
275 | | CompositorOGL::CleanupResources() |
276 | 0 | { |
277 | 0 | if (!mGLContext) |
278 | 0 | return; |
279 | 0 | |
280 | 0 | RefPtr<GLContext> ctx = mGLContext->GetSharedContext(); |
281 | 0 | if (!ctx) { |
282 | 0 | ctx = mGLContext; |
283 | 0 | } |
284 | 0 |
|
285 | 0 | if (!ctx->MakeCurrent()) { |
286 | 0 | // Leak resources! |
287 | 0 | mQuadVBO = 0; |
288 | 0 | mTriangleVBO = 0; |
289 | 0 | mGLContext = nullptr; |
290 | 0 | mPrograms.clear(); |
291 | 0 | return; |
292 | 0 | } |
293 | 0 | |
294 | 0 | for (std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.begin(); |
295 | 0 | iter != mPrograms.end(); |
296 | 0 | iter++) { |
297 | 0 | delete iter->second; |
298 | 0 | } |
299 | 0 | mPrograms.clear(); |
300 | 0 |
|
301 | 0 | ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); |
302 | 0 |
|
303 | 0 | if (mQuadVBO) { |
304 | 0 | ctx->fDeleteBuffers(1, &mQuadVBO); |
305 | 0 | mQuadVBO = 0; |
306 | 0 | } |
307 | 0 |
|
308 | 0 | if (mTriangleVBO) { |
309 | 0 | ctx->fDeleteBuffers(1, &mTriangleVBO); |
310 | 0 | mTriangleVBO = 0; |
311 | 0 | } |
312 | 0 |
|
313 | 0 | mGLContext->MakeCurrent(); |
314 | 0 |
|
315 | 0 | mBlitTextureImageHelper = nullptr; |
316 | 0 |
|
317 | 0 | // On the main thread the Widget will be destroyed soon and calling MakeCurrent |
318 | 0 | // after that could cause a crash (at least with GLX, see bug 1059793), unless |
319 | 0 | // context is marked as destroyed. |
320 | 0 | // There may be some textures still alive that will try to call MakeCurrent on |
321 | 0 | // the context so let's make sure it is marked destroyed now. |
322 | 0 | mGLContext->MarkDestroyed(); |
323 | 0 |
|
324 | 0 | mGLContext = nullptr; |
325 | 0 | } |
326 | | |
327 | | bool |
328 | | CompositorOGL::Initialize(nsCString* const out_failureReason) |
329 | 0 | { |
330 | 0 | ScopedGfxFeatureReporter reporter("GL Layers"); |
331 | 0 |
|
332 | 0 | // Do not allow double initialization |
333 | 0 | MOZ_ASSERT(mGLContext == nullptr, "Don't reinitialize CompositorOGL"); |
334 | 0 |
|
335 | 0 | mGLContext = CreateContext(); |
336 | 0 |
|
337 | | #ifdef MOZ_WIDGET_ANDROID |
338 | | if (!mGLContext){ |
339 | | *out_failureReason = "FEATURE_FAILURE_OPENGL_NO_ANDROID_CONTEXT"; |
340 | | MOZ_CRASH("We need a context on Android"); |
341 | | } |
342 | | #endif |
343 | |
|
344 | 0 | if (!mGLContext){ |
345 | 0 | *out_failureReason = "FEATURE_FAILURE_OPENGL_CREATE_CONTEXT"; |
346 | 0 | return false; |
347 | 0 | } |
348 | 0 | |
349 | 0 | MakeCurrent(); |
350 | 0 |
|
351 | 0 | mHasBGRA = |
352 | 0 | mGLContext->IsExtensionSupported(gl::GLContext::EXT_texture_format_BGRA8888) || |
353 | 0 | mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra); |
354 | 0 |
|
355 | 0 | mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, |
356 | 0 | LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA); |
357 | 0 | mGLContext->fEnable(LOCAL_GL_BLEND); |
358 | 0 |
|
359 | 0 | // initialise a common shader to check that we can actually compile a shader |
360 | 0 | RefPtr<EffectSolidColor> effect = new EffectSolidColor(Color(0, 0, 0, 0)); |
361 | 0 | ShaderConfigOGL config = GetShaderConfigFor(effect); |
362 | 0 | if (!GetShaderProgramFor(config)) { |
363 | 0 | *out_failureReason = "FEATURE_FAILURE_OPENGL_COMPILE_SHADER"; |
364 | 0 | return false; |
365 | 0 | } |
366 | 0 | |
367 | 0 | if (mGLContext->WorkAroundDriverBugs()) { |
368 | 0 | /** |
369 | 0 | * We'll test the ability here to bind NPOT textures to a framebuffer, if |
370 | 0 | * this fails we'll try ARB_texture_rectangle. |
371 | 0 | */ |
372 | 0 |
|
373 | 0 | GLenum textureTargets[] = { |
374 | 0 | LOCAL_GL_TEXTURE_2D, |
375 | 0 | LOCAL_GL_NONE |
376 | 0 | }; |
377 | 0 |
|
378 | 0 | if (!mGLContext->IsGLES()) { |
379 | 0 | // No TEXTURE_RECTANGLE_ARB available on ES2 |
380 | 0 | textureTargets[1] = LOCAL_GL_TEXTURE_RECTANGLE_ARB; |
381 | 0 | } |
382 | 0 |
|
383 | 0 | mFBOTextureTarget = LOCAL_GL_NONE; |
384 | 0 |
|
385 | 0 | GLuint testFBO = 0; |
386 | 0 | mGLContext->fGenFramebuffers(1, &testFBO); |
387 | 0 | GLuint testTexture = 0; |
388 | 0 |
|
389 | 0 | for (uint32_t i = 0; i < ArrayLength(textureTargets); i++) { |
390 | 0 | GLenum target = textureTargets[i]; |
391 | 0 | if (!target) |
392 | 0 | continue; |
393 | 0 | |
394 | 0 | mGLContext->fGenTextures(1, &testTexture); |
395 | 0 | mGLContext->fBindTexture(target, testTexture); |
396 | 0 | mGLContext->fTexParameteri(target, |
397 | 0 | LOCAL_GL_TEXTURE_MIN_FILTER, |
398 | 0 | LOCAL_GL_NEAREST); |
399 | 0 | mGLContext->fTexParameteri(target, |
400 | 0 | LOCAL_GL_TEXTURE_MAG_FILTER, |
401 | 0 | LOCAL_GL_NEAREST); |
402 | 0 | mGLContext->fTexImage2D(target, |
403 | 0 | 0, |
404 | 0 | LOCAL_GL_RGBA, |
405 | 0 | 5, 3, /* sufficiently NPOT */ |
406 | 0 | 0, |
407 | 0 | LOCAL_GL_RGBA, |
408 | 0 | LOCAL_GL_UNSIGNED_BYTE, |
409 | 0 | nullptr); |
410 | 0 |
|
411 | 0 | // unbind this texture, in preparation for binding it to the FBO |
412 | 0 | mGLContext->fBindTexture(target, 0); |
413 | 0 |
|
414 | 0 | mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, testFBO); |
415 | 0 | mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, |
416 | 0 | LOCAL_GL_COLOR_ATTACHMENT0, |
417 | 0 | target, |
418 | 0 | testTexture, |
419 | 0 | 0); |
420 | 0 |
|
421 | 0 | if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) == |
422 | 0 | LOCAL_GL_FRAMEBUFFER_COMPLETE) |
423 | 0 | { |
424 | 0 | mFBOTextureTarget = target; |
425 | 0 | mGLContext->fDeleteTextures(1, &testTexture); |
426 | 0 | break; |
427 | 0 | } |
428 | 0 | |
429 | 0 | mGLContext->fDeleteTextures(1, &testTexture); |
430 | 0 | } |
431 | 0 |
|
432 | 0 | if (testFBO) { |
433 | 0 | mGLContext->fDeleteFramebuffers(1, &testFBO); |
434 | 0 | } |
435 | 0 |
|
436 | 0 | if (mFBOTextureTarget == LOCAL_GL_NONE) { |
437 | 0 | /* Unable to find a texture target that works with FBOs and NPOT textures */ |
438 | 0 | *out_failureReason = "FEATURE_FAILURE_OPENGL_NO_TEXTURE_TARGET"; |
439 | 0 | return false; |
440 | 0 | } |
441 | 0 | } else { |
442 | 0 | // not trying to work around driver bugs, so TEXTURE_2D should just work |
443 | 0 | mFBOTextureTarget = LOCAL_GL_TEXTURE_2D; |
444 | 0 | } |
445 | 0 |
|
446 | 0 | // back to default framebuffer, to avoid confusion |
447 | 0 | mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); |
448 | 0 |
|
449 | 0 | if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) { |
450 | 0 | /* If we're using TEXTURE_RECTANGLE, then we must have the ARB |
451 | 0 | * extension -- the EXT variant does not provide support for |
452 | 0 | * texture rectangle access inside GLSL (sampler2DRect, |
453 | 0 | * texture2DRect). |
454 | 0 | */ |
455 | 0 | if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle)){ |
456 | 0 | *out_failureReason = "FEATURE_FAILURE_OPENGL_ARB_EXT"; |
457 | 0 | return false; |
458 | 0 | } |
459 | 0 | } |
460 | 0 | |
461 | 0 | // Create a VBO for triangle vertices. |
462 | 0 | mGLContext->fGenBuffers(1, &mTriangleVBO); |
463 | 0 |
|
464 | 0 | /* Create a simple quad VBO */ |
465 | 0 | mGLContext->fGenBuffers(1, &mQuadVBO); |
466 | 0 |
|
467 | 0 | // 4 quads, with the number of the quad (vertexID) encoded in w. |
468 | 0 | GLfloat vertices[] = { |
469 | 0 | 0.0f, 0.0f, 0.0f, 0.0f, |
470 | 0 | 1.0f, 0.0f, 0.0f, 0.0f, |
471 | 0 | 0.0f, 1.0f, 0.0f, 0.0f, |
472 | 0 | 1.0f, 0.0f, 0.0f, 0.0f, |
473 | 0 | 0.0f, 1.0f, 0.0f, 0.0f, |
474 | 0 | 1.0f, 1.0f, 0.0f, 0.0f, |
475 | 0 |
|
476 | 0 | 0.0f, 0.0f, 0.0f, 1.0f, |
477 | 0 | 1.0f, 0.0f, 0.0f, 1.0f, |
478 | 0 | 0.0f, 1.0f, 0.0f, 1.0f, |
479 | 0 | 1.0f, 0.0f, 0.0f, 1.0f, |
480 | 0 | 0.0f, 1.0f, 0.0f, 1.0f, |
481 | 0 | 1.0f, 1.0f, 0.0f, 1.0f, |
482 | 0 |
|
483 | 0 | 0.0f, 0.0f, 0.0f, 2.0f, |
484 | 0 | 1.0f, 0.0f, 0.0f, 2.0f, |
485 | 0 | 0.0f, 1.0f, 0.0f, 2.0f, |
486 | 0 | 1.0f, 0.0f, 0.0f, 2.0f, |
487 | 0 | 0.0f, 1.0f, 0.0f, 2.0f, |
488 | 0 | 1.0f, 1.0f, 0.0f, 2.0f, |
489 | 0 |
|
490 | 0 | 0.0f, 0.0f, 0.0f, 3.0f, |
491 | 0 | 1.0f, 0.0f, 0.0f, 3.0f, |
492 | 0 | 0.0f, 1.0f, 0.0f, 3.0f, |
493 | 0 | 1.0f, 0.0f, 0.0f, 3.0f, |
494 | 0 | 0.0f, 1.0f, 0.0f, 3.0f, |
495 | 0 | 1.0f, 1.0f, 0.0f, 3.0f, |
496 | 0 | }; |
497 | 0 | HeapCopyOfStackArray<GLfloat> verticesOnHeap(vertices); |
498 | 0 |
|
499 | 0 | mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO); |
500 | 0 | mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, |
501 | 0 | verticesOnHeap.ByteLength(), |
502 | 0 | verticesOnHeap.Data(), |
503 | 0 | LOCAL_GL_STATIC_DRAW); |
504 | 0 | mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); |
505 | 0 |
|
506 | 0 | nsCOMPtr<nsIConsoleService> |
507 | 0 | console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); |
508 | 0 |
|
509 | 0 | if (console) { |
510 | 0 | nsString msg; |
511 | 0 | msg += |
512 | 0 | NS_LITERAL_STRING("OpenGL compositor Initialized Succesfully.\nVersion: "); |
513 | 0 | msg += NS_ConvertUTF8toUTF16( |
514 | 0 | nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VERSION))); |
515 | 0 | msg += NS_LITERAL_STRING("\nVendor: "); |
516 | 0 | msg += NS_ConvertUTF8toUTF16( |
517 | 0 | nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VENDOR))); |
518 | 0 | msg += NS_LITERAL_STRING("\nRenderer: "); |
519 | 0 | msg += NS_ConvertUTF8toUTF16( |
520 | 0 | nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_RENDERER))); |
521 | 0 | msg += NS_LITERAL_STRING("\nFBO Texture Target: "); |
522 | 0 | if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D) |
523 | 0 | msg += NS_LITERAL_STRING("TEXTURE_2D"); |
524 | 0 | else |
525 | 0 | msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE"); |
526 | 0 | console->LogStringMessage(msg.get()); |
527 | 0 | } |
528 | 0 |
|
529 | 0 | reporter.SetSuccessful(); |
530 | 0 |
|
531 | 0 | return true; |
532 | 0 | } |
533 | | |
534 | | /* |
535 | | * Returns a size that is equal to, or larger than and closest to, |
536 | | * aSize where both width and height are powers of two. |
537 | | * If the OpenGL setup is capable of using non-POT textures, |
538 | | * then it will just return aSize. |
539 | | */ |
540 | | static IntSize |
541 | | CalculatePOTSize(const IntSize& aSize, GLContext* gl) |
542 | 0 | { |
543 | 0 | if (CanUploadNonPowerOfTwo(gl)) |
544 | 0 | return aSize; |
545 | 0 | |
546 | 0 | return IntSize(RoundUpPow2(aSize.width), RoundUpPow2(aSize.height)); |
547 | 0 | } |
548 | | |
549 | | gfx::Rect |
550 | | CompositorOGL::GetTextureCoordinates(gfx::Rect textureRect, TextureSource* aTexture) |
551 | 0 | { |
552 | 0 | // If the OpenGL setup does not support non-power-of-two textures then the |
553 | 0 | // texture's width and height will have been increased to the next |
554 | 0 | // power-of-two (unless already a power of two). In that case we must scale |
555 | 0 | // the texture coordinates to account for that. |
556 | 0 | if (!CanUploadNonPowerOfTwo(mGLContext)) { |
557 | 0 | const IntSize& textureSize = aTexture->GetSize(); |
558 | 0 | const IntSize potSize = CalculatePOTSize(textureSize, mGLContext); |
559 | 0 | if (potSize != textureSize) { |
560 | 0 | const float xScale = (float)textureSize.width / (float)potSize.width; |
561 | 0 | const float yScale = (float)textureSize.height / (float)potSize.height; |
562 | 0 | textureRect.Scale(xScale, yScale); |
563 | 0 | } |
564 | 0 | } |
565 | 0 |
|
566 | 0 | return textureRect; |
567 | 0 | } |
568 | | |
569 | | void |
570 | | CompositorOGL::PrepareViewport(CompositingRenderTargetOGL* aRenderTarget) |
571 | 0 | { |
572 | 0 | MOZ_ASSERT(aRenderTarget); |
573 | 0 | // Logical surface size. |
574 | 0 | const gfx::IntSize& size = aRenderTarget->mInitParams.mSize; |
575 | 0 | // Physical surface size. |
576 | 0 | const gfx::IntSize& phySize = aRenderTarget->mInitParams.mPhySize; |
577 | 0 |
|
578 | 0 | // Set the viewport correctly. |
579 | 0 | mGLContext->fViewport(0, 0, phySize.width, phySize.height); |
580 | 0 |
|
581 | 0 | mViewportSize = size; |
582 | 0 |
|
583 | 0 | if (!aRenderTarget->HasComplexProjection()) { |
584 | 0 | // We flip the view matrix around so that everything is right-side up; we're |
585 | 0 | // drawing directly into the window's back buffer, so this keeps things |
586 | 0 | // looking correct. |
587 | 0 | // XXX: We keep track of whether the window size changed, so we could skip |
588 | 0 | // this update if it hadn't changed since the last call. |
589 | 0 |
|
590 | 0 | // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0, |
591 | 0 | // 2, 2) and flip the contents. |
592 | 0 | Matrix viewMatrix; |
593 | 0 | if (mGLContext->IsOffscreen() && !gIsGtest) { |
594 | 0 | // In case of rendering via GL Offscreen context, disable Y-Flipping |
595 | 0 | viewMatrix.PreTranslate(-1.0, -1.0); |
596 | 0 | viewMatrix.PreScale(2.0f / float(size.width), 2.0f / float(size.height)); |
597 | 0 | } else { |
598 | 0 | viewMatrix.PreTranslate(-1.0, 1.0); |
599 | 0 | viewMatrix.PreScale(2.0f / float(size.width), 2.0f / float(size.height)); |
600 | 0 | viewMatrix.PreScale(1.0f, -1.0f); |
601 | 0 | } |
602 | 0 |
|
603 | 0 | MOZ_ASSERT(mCurrentRenderTarget, "No destination"); |
604 | 0 | // If we're drawing directly to the window then we want to offset |
605 | 0 | // drawing by the render offset. |
606 | 0 | if (!mTarget && mCurrentRenderTarget->IsWindow()) { |
607 | 0 | viewMatrix.PreTranslate(mRenderOffset.x, mRenderOffset.y); |
608 | 0 | } |
609 | 0 |
|
610 | 0 | Matrix4x4 matrix3d = Matrix4x4::From2D(viewMatrix); |
611 | 0 | matrix3d._33 = 0.0f; |
612 | 0 | mProjMatrix = matrix3d; |
613 | 0 | mGLContext->fDepthRange(0.0f, 1.0f); |
614 | 0 | } else { |
615 | 0 | // XXX take into account mRenderOffset |
616 | 0 | bool depthEnable; |
617 | 0 | float zNear, zFar; |
618 | 0 | aRenderTarget->GetProjection(mProjMatrix, depthEnable, zNear, zFar); |
619 | 0 | mGLContext->fDepthRange(zNear, zFar); |
620 | 0 | } |
621 | 0 | } |
622 | | |
623 | | already_AddRefed<CompositingRenderTarget> |
624 | | CompositorOGL::CreateRenderTarget(const IntRect &aRect, SurfaceInitMode aInit) |
625 | 0 | { |
626 | 0 | MOZ_ASSERT(!aRect.IsZeroArea(), "Trying to create a render target of invalid size"); |
627 | 0 |
|
628 | 0 | if (aRect.IsZeroArea()) { |
629 | 0 | return nullptr; |
630 | 0 | } |
631 | 0 | |
632 | 0 | if (!gl()) { |
633 | 0 | // CompositingRenderTargetOGL does not work without a gl context. |
634 | 0 | return nullptr; |
635 | 0 | } |
636 | 0 | |
637 | 0 | GLuint tex = 0; |
638 | 0 | GLuint fbo = 0; |
639 | 0 | IntRect rect = aRect; |
640 | 0 | IntSize FBOSize; |
641 | 0 | CreateFBOWithTexture(rect, false, 0, &fbo, &tex, &FBOSize); |
642 | 0 | RefPtr<CompositingRenderTargetOGL> surface |
643 | 0 | = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo); |
644 | 0 | surface->Initialize(aRect.Size(), FBOSize, mFBOTextureTarget, aInit); |
645 | 0 | return surface.forget(); |
646 | 0 | } |
647 | | |
648 | | already_AddRefed<CompositingRenderTarget> |
649 | | CompositorOGL::CreateRenderTargetFromSource(const IntRect &aRect, |
650 | | const CompositingRenderTarget *aSource, |
651 | | const IntPoint &aSourcePoint) |
652 | 0 | { |
653 | 0 | MOZ_ASSERT(!aRect.IsZeroArea(), "Trying to create a render target of invalid size"); |
654 | 0 |
|
655 | 0 | if (aRect.IsZeroArea()) { |
656 | 0 | return nullptr; |
657 | 0 | } |
658 | 0 | |
659 | 0 | if (!gl()) { |
660 | 0 | return nullptr; |
661 | 0 | } |
662 | 0 | |
663 | 0 | GLuint tex = 0; |
664 | 0 | GLuint fbo = 0; |
665 | 0 | const CompositingRenderTargetOGL* sourceSurface |
666 | 0 | = static_cast<const CompositingRenderTargetOGL*>(aSource); |
667 | 0 | IntRect sourceRect(aSourcePoint, aRect.Size()); |
668 | 0 | if (aSource) { |
669 | 0 | CreateFBOWithTexture(sourceRect, true, sourceSurface->GetFBO(), |
670 | 0 | &fbo, &tex); |
671 | 0 | } else { |
672 | 0 | CreateFBOWithTexture(sourceRect, true, 0, |
673 | 0 | &fbo, &tex); |
674 | 0 | } |
675 | 0 |
|
676 | 0 | RefPtr<CompositingRenderTargetOGL> surface |
677 | 0 | = new CompositingRenderTargetOGL(this, aRect.TopLeft(), tex, fbo); |
678 | 0 | surface->Initialize(aRect.Size(), |
679 | 0 | sourceRect.Size(), |
680 | 0 | mFBOTextureTarget, |
681 | 0 | INIT_MODE_NONE); |
682 | 0 | return surface.forget(); |
683 | 0 | } |
684 | | |
685 | | void |
686 | | CompositorOGL::SetRenderTarget(CompositingRenderTarget *aSurface) |
687 | 0 | { |
688 | 0 | MOZ_ASSERT(aSurface); |
689 | 0 | CompositingRenderTargetOGL* surface |
690 | 0 | = static_cast<CompositingRenderTargetOGL*>(aSurface); |
691 | 0 | if (mCurrentRenderTarget != surface) { |
692 | 0 | mCurrentRenderTarget = surface; |
693 | 0 | surface->BindRenderTarget(); |
694 | 0 | } |
695 | 0 |
|
696 | 0 | PrepareViewport(mCurrentRenderTarget); |
697 | 0 | } |
698 | | |
699 | | CompositingRenderTarget* |
700 | | CompositorOGL::GetCurrentRenderTarget() const |
701 | 0 | { |
702 | 0 | return mCurrentRenderTarget; |
703 | 0 | } |
704 | | |
705 | | CompositingRenderTarget* |
706 | | CompositorOGL::GetWindowRenderTarget() const |
707 | 0 | { |
708 | 0 | return mWindowRenderTarget; |
709 | 0 | } |
710 | | |
711 | | already_AddRefed<AsyncReadbackBuffer> |
712 | | CompositorOGL::CreateAsyncReadbackBuffer(const IntSize& aSize) |
713 | 0 | { |
714 | 0 | return MakeAndAddRef<AsyncReadbackBufferOGL>(mGLContext, aSize); |
715 | 0 | } |
716 | | |
717 | | bool |
718 | | CompositorOGL::ReadbackRenderTarget(CompositingRenderTarget* aSource, |
719 | | AsyncReadbackBuffer* aDest) |
720 | 0 | { |
721 | 0 | IntSize size = aSource->GetSize(); |
722 | 0 | MOZ_RELEASE_ASSERT(aDest->GetSize() == size); |
723 | 0 |
|
724 | 0 | RefPtr<CompositingRenderTarget> previousTarget = GetCurrentRenderTarget(); |
725 | 0 | if (previousTarget != aSource) { |
726 | 0 | SetRenderTarget(aSource); |
727 | 0 | } |
728 | 0 |
|
729 | 0 | ScopedPackState scopedPackState(mGLContext); |
730 | 0 | static_cast<AsyncReadbackBufferOGL*>(aDest)->Bind(); |
731 | 0 |
|
732 | 0 | mGLContext->fReadPixels(0, 0, size.width, size.height, |
733 | 0 | LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, 0); |
734 | 0 |
|
735 | 0 | if (previousTarget != aSource) { |
736 | 0 | SetRenderTarget(previousTarget); |
737 | 0 | } |
738 | 0 | return true; |
739 | 0 | } |
740 | | |
741 | | bool |
742 | | CompositorOGL::BlitRenderTarget(CompositingRenderTarget* aSource, |
743 | | const gfx::IntSize& aSourceSize, |
744 | | const gfx::IntSize& aDestSize) |
745 | 0 | { |
746 | 0 | if (!mGLContext->IsSupported(GLFeature::framebuffer_blit)) { |
747 | 0 | return false; |
748 | 0 | } |
749 | 0 | CompositingRenderTargetOGL* source = |
750 | 0 | static_cast<CompositingRenderTargetOGL*>(aSource); |
751 | 0 | GLuint srcFBO = source->GetFBO(); |
752 | 0 | GLuint destFBO = mCurrentRenderTarget->GetFBO(); |
753 | 0 | mGLContext->BlitHelper()-> |
754 | 0 | BlitFramebufferToFramebuffer(srcFBO, destFBO, aSourceSize, aDestSize, |
755 | 0 | LOCAL_GL_LINEAR); |
756 | 0 | return true; |
757 | 0 | } |
758 | | |
759 | | static GLenum |
760 | | GetFrameBufferInternalFormat(GLContext* gl, |
761 | | GLuint aFrameBuffer, |
762 | | mozilla::widget::CompositorWidget* aWidget) |
763 | 0 | { |
764 | 0 | if (aFrameBuffer == 0) { // default framebuffer |
765 | 0 | return aWidget->GetGLFrameBufferFormat(); |
766 | 0 | } |
767 | 0 | return LOCAL_GL_RGBA; |
768 | 0 | } |
769 | | |
770 | | void |
771 | | CompositorOGL::ClearRect(const gfx::Rect& aRect) |
772 | 0 | { |
773 | 0 | // Map aRect to OGL coordinates, origin:bottom-left |
774 | 0 | GLint y = mViewportSize.height - aRect.YMost(); |
775 | 0 |
|
776 | 0 | ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true); |
777 | 0 | ScopedScissorRect autoScissorRect(mGLContext, aRect.X(), y, aRect.Width(), aRect.Height()); |
778 | 0 | mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0); |
779 | 0 | mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); |
780 | 0 | } |
781 | | |
782 | | void |
783 | | CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion, |
784 | | const IntRect *aClipRectIn, |
785 | | const IntRect& aRenderBounds, |
786 | | const nsIntRegion& aOpaqueRegion, |
787 | | IntRect *aClipRectOut, |
788 | | IntRect *aRenderBoundsOut) |
789 | 0 | { |
790 | 0 | AUTO_PROFILER_LABEL("CompositorOGL::BeginFrame", GRAPHICS); |
791 | 0 |
|
792 | 0 | MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame"); |
793 | 0 |
|
794 | 0 | gfx::IntRect rect; |
795 | 0 | if (mUseExternalSurfaceSize) { |
796 | 0 | rect = gfx::IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height); |
797 | 0 | } else { |
798 | 0 | rect = gfx::IntRect(aRenderBounds.X(), aRenderBounds.Y(), aRenderBounds.Width(), aRenderBounds.Height()); |
799 | 0 | } |
800 | 0 |
|
801 | 0 | if (aRenderBoundsOut) { |
802 | 0 | *aRenderBoundsOut = rect; |
803 | 0 | } |
804 | 0 |
|
805 | 0 | auto width = rect.Width(); |
806 | 0 | auto height = rect.Height(); |
807 | 0 |
|
808 | 0 | // We can't draw anything to something with no area |
809 | 0 | // so just return |
810 | 0 | if (width == 0 || height == 0) |
811 | 0 | return; |
812 | 0 | |
813 | 0 | // We're about to actually draw a frame. |
814 | 0 | mFrameInProgress = true; |
815 | 0 |
|
816 | 0 | // If the widget size changed, we have to force a MakeCurrent |
817 | 0 | // to make sure that GL sees the updated widget size. |
818 | 0 | if (mWidgetSize.width != width || |
819 | 0 | mWidgetSize.height != height) |
820 | 0 | { |
821 | 0 | MakeCurrent(ForceMakeCurrent); |
822 | 0 |
|
823 | 0 | mWidgetSize.width = width; |
824 | 0 | mWidgetSize.height = height; |
825 | 0 | } else { |
826 | 0 | MakeCurrent(); |
827 | 0 | } |
828 | 0 |
|
829 | 0 | mPixelsPerFrame = width * height; |
830 | 0 | mPixelsFilled = 0; |
831 | 0 |
|
832 | | #ifdef MOZ_WIDGET_ANDROID |
833 | | java::GeckoSurfaceTexture::DestroyUnused((int64_t)mGLContext.get()); |
834 | | #endif |
835 | |
|
836 | 0 | // Default blend function implements "OVER" |
837 | 0 | mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, |
838 | 0 | LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA); |
839 | 0 | mGLContext->fEnable(LOCAL_GL_BLEND); |
840 | 0 |
|
841 | 0 | RefPtr<CompositingRenderTargetOGL> rt = |
842 | 0 | CompositingRenderTargetOGL::RenderTargetForWindow(this, |
843 | 0 | IntSize(width, height)); |
844 | 0 | SetRenderTarget(rt); |
845 | 0 | mWindowRenderTarget = mCurrentRenderTarget; |
846 | 0 |
|
847 | 0 | if (aClipRectOut && !aClipRectIn) { |
848 | 0 | aClipRectOut->SetRect(0, 0, width, height); |
849 | 0 | } |
850 | 0 |
|
851 | 0 | mGLContext->fClearColor(mClearColor.r, mClearColor.g, mClearColor.b, mClearColor.a); |
852 | 0 | mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); |
853 | 0 | } |
854 | | |
855 | | void |
856 | | CompositorOGL::CreateFBOWithTexture(const gfx::IntRect& aRect, |
857 | | bool aCopyFromSource, |
858 | | GLuint aSourceFrameBuffer, |
859 | | GLuint *aFBO, GLuint *aTexture, |
860 | | gfx::IntSize* aAllocSize) |
861 | 0 | { |
862 | 0 | *aTexture = CreateTexture(aRect, aCopyFromSource, aSourceFrameBuffer, |
863 | 0 | aAllocSize); |
864 | 0 | mGLContext->fGenFramebuffers(1, aFBO); |
865 | 0 | } |
866 | | |
867 | | GLuint |
868 | | CompositorOGL::CreateTexture(const IntRect& aRect, bool aCopyFromSource, |
869 | | GLuint aSourceFrameBuffer, IntSize* aAllocSize) |
870 | 0 | { |
871 | 0 | // we're about to create a framebuffer backed by textures to use as an intermediate |
872 | 0 | // surface. What to do if its size (as given by aRect) would exceed the |
873 | 0 | // maximum texture size supported by the GL? The present code chooses the compromise |
874 | 0 | // of just clamping the framebuffer's size to the max supported size. |
875 | 0 | // This gives us a lower resolution rendering of the intermediate surface (children layers). |
876 | 0 | // See bug 827170 for a discussion. |
877 | 0 | IntRect clampedRect = aRect; |
878 | 0 | int32_t maxTexSize = GetMaxTextureSize(); |
879 | 0 | clampedRect.SetWidth(std::min(clampedRect.Width(), maxTexSize)); |
880 | 0 | clampedRect.SetHeight(std::min(clampedRect.Height(), maxTexSize)); |
881 | 0 |
|
882 | 0 | auto clampedRectWidth = clampedRect.Width(); |
883 | 0 | auto clampedRectHeight = clampedRect.Height(); |
884 | 0 |
|
885 | 0 | GLuint tex; |
886 | 0 |
|
887 | 0 | mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0); |
888 | 0 | mGLContext->fGenTextures(1, &tex); |
889 | 0 | mGLContext->fBindTexture(mFBOTextureTarget, tex); |
890 | 0 |
|
891 | 0 | if (aCopyFromSource) { |
892 | 0 | GLuint curFBO = mCurrentRenderTarget->GetFBO(); |
893 | 0 | if (curFBO != aSourceFrameBuffer) { |
894 | 0 | mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aSourceFrameBuffer); |
895 | 0 | } |
896 | 0 |
|
897 | 0 | // We're going to create an RGBA temporary fbo. But to |
898 | 0 | // CopyTexImage() from the current framebuffer, the framebuffer's |
899 | 0 | // format has to be compatible with the new texture's. So we |
900 | 0 | // check the format of the framebuffer here and take a slow path |
901 | 0 | // if it's incompatible. |
902 | 0 | GLenum format = |
903 | 0 | GetFrameBufferInternalFormat(gl(), aSourceFrameBuffer, mWidget); |
904 | 0 |
|
905 | 0 | bool isFormatCompatibleWithRGBA |
906 | 0 | = gl()->IsGLES() ? (format == LOCAL_GL_RGBA) |
907 | 0 | : true; |
908 | 0 |
|
909 | 0 | if (isFormatCompatibleWithRGBA) { |
910 | 0 | mGLContext->fCopyTexImage2D(mFBOTextureTarget, |
911 | 0 | 0, |
912 | 0 | LOCAL_GL_RGBA, |
913 | 0 | clampedRect.X(), FlipY(clampedRect.YMost()), |
914 | 0 | clampedRectWidth, clampedRectHeight, |
915 | 0 | 0); |
916 | 0 | } else { |
917 | 0 | // Curses, incompatible formats. Take a slow path. |
918 | 0 |
|
919 | 0 | // RGBA |
920 | 0 | size_t bufferSize = clampedRectWidth * clampedRectHeight * 4; |
921 | 0 | auto buf = MakeUnique<uint8_t[]>(bufferSize); |
922 | 0 |
|
923 | 0 | mGLContext->fReadPixels(clampedRect.X(), clampedRect.Y(), |
924 | 0 | clampedRectWidth, clampedRectHeight, |
925 | 0 | LOCAL_GL_RGBA, |
926 | 0 | LOCAL_GL_UNSIGNED_BYTE, |
927 | 0 | buf.get()); |
928 | 0 | mGLContext->fTexImage2D(mFBOTextureTarget, |
929 | 0 | 0, |
930 | 0 | LOCAL_GL_RGBA, |
931 | 0 | clampedRectWidth, clampedRectHeight, |
932 | 0 | 0, |
933 | 0 | LOCAL_GL_RGBA, |
934 | 0 | LOCAL_GL_UNSIGNED_BYTE, |
935 | 0 | buf.get()); |
936 | 0 | } |
937 | 0 |
|
938 | 0 | GLenum error = mGLContext->fGetError(); |
939 | 0 | if (error != LOCAL_GL_NO_ERROR) { |
940 | 0 | nsAutoCString msg; |
941 | 0 | msg.AppendPrintf("Texture initialization failed! -- error 0x%x, Source %d, Source format %d, RGBA Compat %d", |
942 | 0 | error, aSourceFrameBuffer, format, isFormatCompatibleWithRGBA); |
943 | 0 | NS_ERROR(msg.get()); |
944 | 0 | } |
945 | 0 | } else { |
946 | 0 | mGLContext->fTexImage2D(mFBOTextureTarget, |
947 | 0 | 0, |
948 | 0 | LOCAL_GL_RGBA, |
949 | 0 | clampedRectWidth, clampedRectHeight, |
950 | 0 | 0, |
951 | 0 | LOCAL_GL_RGBA, |
952 | 0 | LOCAL_GL_UNSIGNED_BYTE, |
953 | 0 | nullptr); |
954 | 0 | } |
955 | 0 | mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER, |
956 | 0 | LOCAL_GL_LINEAR); |
957 | 0 | mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER, |
958 | 0 | LOCAL_GL_LINEAR); |
959 | 0 | mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_S, |
960 | 0 | LOCAL_GL_CLAMP_TO_EDGE); |
961 | 0 | mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_WRAP_T, |
962 | 0 | LOCAL_GL_CLAMP_TO_EDGE); |
963 | 0 | mGLContext->fBindTexture(mFBOTextureTarget, 0); |
964 | 0 |
|
965 | 0 | if (aAllocSize) { |
966 | 0 | aAllocSize->width = clampedRectWidth; |
967 | 0 | aAllocSize->height = clampedRectHeight; |
968 | 0 | } |
969 | 0 |
|
970 | 0 | return tex; |
971 | 0 | } |
972 | | |
973 | | ShaderConfigOGL |
974 | | CompositorOGL::GetShaderConfigFor(Effect *aEffect, |
975 | | TextureSourceOGL *aSourceMask, |
976 | | gfx::CompositionOp aOp, |
977 | | bool aColorMatrix, |
978 | | bool aDEAAEnabled) const |
979 | 0 | { |
980 | 0 | ShaderConfigOGL config; |
981 | 0 |
|
982 | 0 | switch(aEffect->mType) { |
983 | 0 | case EffectTypes::SOLID_COLOR: |
984 | 0 | config.SetRenderColor(true); |
985 | 0 | break; |
986 | 0 | case EffectTypes::YCBCR: |
987 | 0 | { |
988 | 0 | config.SetYCbCr(true); |
989 | 0 | EffectYCbCr* effectYCbCr = |
990 | 0 | static_cast<EffectYCbCr*>(aEffect); |
991 | 0 | uint32_t pixelBits = (8 * BytesPerPixel(SurfaceFormatForAlphaBitDepth(effectYCbCr->mBitDepth))); |
992 | 0 | uint32_t paddingBits = pixelBits - effectYCbCr->mBitDepth; |
993 | 0 | // OpenGL expects values between [0,255], this range needs to be adjusted |
994 | 0 | // according to the bit depth. |
995 | 0 | // So we will scale the YUV values by this amount. |
996 | 0 | config.SetColorMultiplier(pow(2, paddingBits)); |
997 | 0 | config.SetTextureTarget(effectYCbCr->mTexture->AsSourceOGL()->GetTextureTarget()); |
998 | 0 | break; |
999 | 0 | } |
1000 | 0 | case EffectTypes::NV12: |
1001 | 0 | config.SetNV12(true); |
1002 | 0 | config.SetTextureTarget(LOCAL_GL_TEXTURE_RECTANGLE_ARB); |
1003 | 0 | break; |
1004 | 0 | case EffectTypes::COMPONENT_ALPHA: |
1005 | 0 | { |
1006 | 0 | config.SetComponentAlpha(true); |
1007 | 0 | EffectComponentAlpha* effectComponentAlpha = |
1008 | 0 | static_cast<EffectComponentAlpha*>(aEffect); |
1009 | 0 | gfx::SurfaceFormat format = effectComponentAlpha->mOnWhite->GetFormat(); |
1010 | 0 | config.SetRBSwap(format == gfx::SurfaceFormat::B8G8R8A8 || |
1011 | 0 | format == gfx::SurfaceFormat::B8G8R8X8); |
1012 | 0 | TextureSourceOGL* source = effectComponentAlpha->mOnWhite->AsSourceOGL(); |
1013 | 0 | config.SetTextureTarget(source->GetTextureTarget()); |
1014 | 0 | break; |
1015 | 0 | } |
1016 | 0 | case EffectTypes::RENDER_TARGET: |
1017 | 0 | config.SetTextureTarget(mFBOTextureTarget); |
1018 | 0 | break; |
1019 | 0 | default: |
1020 | 0 | { |
1021 | 0 | MOZ_ASSERT(aEffect->mType == EffectTypes::RGB); |
1022 | 0 | TexturedEffect* texturedEffect = |
1023 | 0 | static_cast<TexturedEffect*>(aEffect); |
1024 | 0 | TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL(); |
1025 | 0 | MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_EXTERNAL, |
1026 | 0 | source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 || |
1027 | 0 | source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 || |
1028 | 0 | source->GetFormat() == gfx::SurfaceFormat::B8G8R8A8 || |
1029 | 0 | source->GetFormat() == gfx::SurfaceFormat::B8G8R8X8 || |
1030 | 0 | source->GetFormat() == gfx::SurfaceFormat::R5G6B5_UINT16); |
1031 | 0 | MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB, |
1032 | 0 | source->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 || |
1033 | 0 | source->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 || |
1034 | 0 | source->GetFormat() == gfx::SurfaceFormat::R5G6B5_UINT16 || |
1035 | 0 | source->GetFormat() == gfx::SurfaceFormat::YUV422 ); |
1036 | 0 | config = ShaderConfigFromTargetAndFormat(source->GetTextureTarget(), |
1037 | 0 | source->GetFormat()); |
1038 | 0 | if (!texturedEffect->mPremultiplied) { |
1039 | 0 | config.SetNoPremultipliedAlpha(); |
1040 | 0 | } |
1041 | 0 | break; |
1042 | 0 | } |
1043 | 0 | } |
1044 | 0 | config.SetColorMatrix(aColorMatrix); |
1045 | 0 | config.SetMask(!!aSourceMask); |
1046 | 0 | if (aSourceMask) { |
1047 | 0 | config.SetMaskTextureTarget(aSourceMask->GetTextureTarget()); |
1048 | 0 | } |
1049 | 0 | config.SetDEAA(aDEAAEnabled); |
1050 | 0 | config.SetCompositionOp(aOp); |
1051 | 0 | return config; |
1052 | 0 | } |
1053 | | |
1054 | | ShaderProgramOGL* |
1055 | | CompositorOGL::GetShaderProgramFor(const ShaderConfigOGL &aConfig) |
1056 | 0 | { |
1057 | 0 | std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.find(aConfig); |
1058 | 0 | if (iter != mPrograms.end()) |
1059 | 0 | return iter->second; |
1060 | 0 | |
1061 | 0 | ProgramProfileOGL profile = ProgramProfileOGL::GetProfileFor(aConfig); |
1062 | 0 | ShaderProgramOGL *shader = new ShaderProgramOGL(gl(), profile); |
1063 | 0 | if (!shader->Initialize()) { |
1064 | 0 | gfxCriticalError() << "Shader compilation failure, cfg:" |
1065 | 0 | << " features: " << gfx::hexa(aConfig.mFeatures) |
1066 | 0 | << " multiplier: " << aConfig.mMultiplier |
1067 | 0 | << " op: " << aConfig.mCompositionOp; |
1068 | 0 | delete shader; |
1069 | 0 | return nullptr; |
1070 | 0 | } |
1071 | 0 |
|
1072 | 0 | mPrograms[aConfig] = shader; |
1073 | 0 | return shader; |
1074 | 0 | } |
1075 | | |
1076 | | void |
1077 | | CompositorOGL::ActivateProgram(ShaderProgramOGL* aProg) |
1078 | 0 | { |
1079 | 0 | if (mCurrentProgram != aProg) { |
1080 | 0 | gl()->fUseProgram(aProg->GetProgram()); |
1081 | 0 | mCurrentProgram = aProg; |
1082 | 0 | } |
1083 | 0 | } |
1084 | | |
1085 | | void |
1086 | | CompositorOGL::ResetProgram() |
1087 | 0 | { |
1088 | 0 | mCurrentProgram = nullptr; |
1089 | 0 | } |
1090 | | |
1091 | | static bool SetBlendMode(GLContext* aGL, gfx::CompositionOp aBlendMode, bool aIsPremultiplied = true) |
1092 | 0 | { |
1093 | 0 | if (BlendOpIsMixBlendMode(aBlendMode)) { |
1094 | 0 | // Mix-blend modes require an extra step (or more) that cannot be expressed |
1095 | 0 | // in the fixed-function blending capabilities of opengl. We handle them |
1096 | 0 | // separately in shaders, and the shaders assume we will use our default |
1097 | 0 | // blend function for compositing (premultiplied OP_OVER). |
1098 | 0 | return false; |
1099 | 0 | } |
1100 | 0 | if (aBlendMode == gfx::CompositionOp::OP_OVER && aIsPremultiplied) { |
1101 | 0 | return false; |
1102 | 0 | } |
1103 | 0 | |
1104 | 0 | GLenum srcBlend; |
1105 | 0 | GLenum dstBlend; |
1106 | 0 | GLenum srcAlphaBlend = LOCAL_GL_ONE; |
1107 | 0 | GLenum dstAlphaBlend = LOCAL_GL_ONE_MINUS_SRC_ALPHA; |
1108 | 0 |
|
1109 | 0 | switch (aBlendMode) { |
1110 | 0 | case gfx::CompositionOp::OP_OVER: |
1111 | 0 | MOZ_ASSERT(!aIsPremultiplied); |
1112 | 0 | srcBlend = LOCAL_GL_SRC_ALPHA; |
1113 | 0 | dstBlend = LOCAL_GL_ONE_MINUS_SRC_ALPHA; |
1114 | 0 | break; |
1115 | 0 | case gfx::CompositionOp::OP_SOURCE: |
1116 | 0 | srcBlend = aIsPremultiplied ? LOCAL_GL_ONE : LOCAL_GL_SRC_ALPHA; |
1117 | 0 | dstBlend = LOCAL_GL_ZERO; |
1118 | 0 | srcAlphaBlend = LOCAL_GL_ONE; |
1119 | 0 | dstAlphaBlend = LOCAL_GL_ZERO; |
1120 | 0 | break; |
1121 | 0 | default: |
1122 | 0 | MOZ_ASSERT_UNREACHABLE("Unsupported blend mode!"); |
1123 | 0 | return false; |
1124 | 0 | } |
1125 | 0 |
|
1126 | 0 | aGL->fBlendFuncSeparate(srcBlend, dstBlend, |
1127 | 0 | srcAlphaBlend, dstAlphaBlend); |
1128 | 0 | return true; |
1129 | 0 | } |
1130 | | |
1131 | | gfx::Point3D |
1132 | | CompositorOGL::GetLineCoefficients(const gfx::Point& aPoint1, |
1133 | | const gfx::Point& aPoint2) |
1134 | 0 | { |
1135 | 0 | // Return standard coefficients for a line between aPoint1 and aPoint2 |
1136 | 0 | // for standard line equation: |
1137 | 0 | // |
1138 | 0 | // Ax + By + C = 0 |
1139 | 0 | // |
1140 | 0 | // A = (p1.y – p2.y) |
1141 | 0 | // B = (p2.x – p1.x) |
1142 | 0 | // C = (p1.x * p2.y) – (p2.x * p1.y) |
1143 | 0 |
|
1144 | 0 | gfx::Point3D coeffecients; |
1145 | 0 | coeffecients.x = aPoint1.y - aPoint2.y; |
1146 | 0 | coeffecients.y = aPoint2.x - aPoint1.x; |
1147 | 0 | coeffecients.z = aPoint1.x * aPoint2.y - aPoint2.x * aPoint1.y; |
1148 | 0 |
|
1149 | 0 | coeffecients *= 1.0f / sqrtf(coeffecients.x * coeffecients.x + |
1150 | 0 | coeffecients.y * coeffecients.y); |
1151 | 0 |
|
1152 | 0 | // Offset outwards by 0.5 pixel as the edge is considered to be 1 pixel |
1153 | 0 | // wide and included within the interior of the polygon |
1154 | 0 | coeffecients.z += 0.5f; |
1155 | 0 |
|
1156 | 0 | return coeffecients; |
1157 | 0 | } |
1158 | | |
1159 | | void |
1160 | | CompositorOGL::DrawQuad(const Rect& aRect, |
1161 | | const IntRect& aClipRect, |
1162 | | const EffectChain &aEffectChain, |
1163 | | Float aOpacity, |
1164 | | const gfx::Matrix4x4& aTransform, |
1165 | | const gfx::Rect& aVisibleRect) |
1166 | 0 | { |
1167 | 0 | AUTO_PROFILER_LABEL("CompositorOGL::DrawQuad", GRAPHICS); |
1168 | 0 |
|
1169 | 0 | DrawGeometry(aRect, aRect, aClipRect, aEffectChain, |
1170 | 0 | aOpacity, aTransform, aVisibleRect); |
1171 | 0 | } |
1172 | | |
1173 | | void |
1174 | | CompositorOGL::DrawTriangles(const nsTArray<gfx::TexturedTriangle>& aTriangles, |
1175 | | const gfx::Rect& aRect, |
1176 | | const gfx::IntRect& aClipRect, |
1177 | | const EffectChain& aEffectChain, |
1178 | | gfx::Float aOpacity, |
1179 | | const gfx::Matrix4x4& aTransform, |
1180 | | const gfx::Rect& aVisibleRect) |
1181 | 0 | { |
1182 | 0 | AUTO_PROFILER_LABEL("CompositorOGL::DrawTriangles", GRAPHICS); |
1183 | 0 |
|
1184 | 0 | DrawGeometry(aTriangles, aRect, aClipRect, aEffectChain, |
1185 | 0 | aOpacity, aTransform, aVisibleRect); |
1186 | 0 | } |
1187 | | |
1188 | | template<typename Geometry> |
1189 | | void |
1190 | | CompositorOGL::DrawGeometry(const Geometry& aGeometry, |
1191 | | const gfx::Rect& aRect, |
1192 | | const gfx::IntRect& aClipRect, |
1193 | | const EffectChain& aEffectChain, |
1194 | | gfx::Float aOpacity, |
1195 | | const gfx::Matrix4x4& aTransform, |
1196 | | const gfx::Rect& aVisibleRect) |
1197 | 0 | { |
1198 | 0 | MOZ_ASSERT(mFrameInProgress, "frame not started"); |
1199 | 0 | MOZ_ASSERT(mCurrentRenderTarget, "No destination"); |
1200 | 0 |
|
1201 | 0 | MakeCurrent(); |
1202 | 0 |
|
1203 | 0 | IntPoint offset = mCurrentRenderTarget->GetOrigin(); |
1204 | 0 | IntSize size = mCurrentRenderTarget->GetSize(); |
1205 | 0 |
|
1206 | 0 | Rect renderBound(0, 0, size.width, size.height); |
1207 | 0 | renderBound.IntersectRect(renderBound, Rect(aClipRect)); |
1208 | 0 | renderBound.MoveBy(offset); |
1209 | 0 |
|
1210 | 0 | Rect destRect = aTransform.TransformAndClipBounds(aRect, renderBound); |
1211 | 0 |
|
1212 | 0 | // XXX: This doesn't handle 3D transforms. It also doesn't handled rotated |
1213 | 0 | // quads. Fix me. |
1214 | 0 | mPixelsFilled += destRect.Width() * destRect.Height(); |
1215 | 0 |
|
1216 | 0 | // Do a simple culling if this rect is out of target buffer. |
1217 | 0 | // Inflate a small size to avoid some numerical imprecision issue. |
1218 | 0 | destRect.Inflate(1, 1); |
1219 | 0 | destRect.MoveBy(-offset); |
1220 | 0 | renderBound = Rect(0, 0, size.width, size.height); |
1221 | 0 | if (!renderBound.Intersects(destRect)) { |
1222 | 0 | return; |
1223 | 0 | } |
1224 | 0 | |
1225 | 0 | LayerScope::DrawBegin(); |
1226 | 0 |
|
1227 | 0 |
|
1228 | 0 | IntRect clipRect = aClipRect; |
1229 | 0 |
|
1230 | 0 | EffectMask* effectMask; |
1231 | 0 | Rect maskBounds; |
1232 | 0 | if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) { |
1233 | 0 | effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get()); |
1234 | 0 |
|
1235 | 0 | // We're assuming that the gl backend won't cheat and use NPOT |
1236 | 0 | // textures when glContext says it can't (which seems to happen |
1237 | 0 | // on a mac when you force POT textures) |
1238 | 0 | IntSize maskSize = CalculatePOTSize(effectMask->mSize, mGLContext); |
1239 | 0 |
|
1240 | 0 | const gfx::Matrix4x4& maskTransform = effectMask->mMaskTransform; |
1241 | 0 | NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!"); |
1242 | 0 | maskBounds = Rect(Point(), Size(maskSize)); |
1243 | 0 | maskBounds = maskTransform.As2D().TransformBounds(maskBounds); |
1244 | 0 |
|
1245 | 0 | clipRect = clipRect.Intersect(RoundedOut(maskBounds) - offset); |
1246 | 0 | } |
1247 | 0 |
|
1248 | 0 | // aClipRect is in destination coordinate space (after all |
1249 | 0 | // transforms and offsets have been applied) so if our |
1250 | 0 | // drawing is going to be shifted by mRenderOffset then we need |
1251 | 0 | // to shift the clip rect by the same amount. |
1252 | 0 | if (!mTarget && mCurrentRenderTarget->IsWindow()) { |
1253 | 0 | clipRect.MoveBy(mRenderOffset.x, mRenderOffset.y); |
1254 | 0 | } |
1255 | 0 |
|
1256 | 0 | ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true); |
1257 | 0 | ScopedScissorRect autoScissorRect(mGLContext, clipRect.X(), FlipY(clipRect.Y() + clipRect.Height()), |
1258 | 0 | clipRect.Width(), clipRect.Height()); |
1259 | 0 |
|
1260 | 0 | MaskType maskType; |
1261 | 0 | TextureSourceOGL* sourceMask = nullptr; |
1262 | 0 | gfx::Matrix4x4 maskQuadTransform; |
1263 | 0 | if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) { |
1264 | 0 | sourceMask = effectMask->mMaskTexture->AsSourceOGL(); |
1265 | 0 |
|
1266 | 0 | // NS_ASSERTION(textureMask->IsAlpha(), |
1267 | 0 | // "OpenGL mask layers must be backed by alpha surfaces"); |
1268 | 0 |
|
1269 | 0 | maskQuadTransform._11 = 1.0f/maskBounds.Width(); |
1270 | 0 | maskQuadTransform._22 = 1.0f/maskBounds.Height(); |
1271 | 0 | maskQuadTransform._41 = float(-maskBounds.X())/maskBounds.Width(); |
1272 | 0 | maskQuadTransform._42 = float(-maskBounds.Y())/maskBounds.Height(); |
1273 | 0 |
|
1274 | 0 | maskType = MaskType::Mask; |
1275 | 0 | } else { |
1276 | 0 | maskType = MaskType::MaskNone; |
1277 | 0 | } |
1278 | 0 |
|
1279 | 0 | // Determine the color if this is a color shader and fold the opacity into |
1280 | 0 | // the color since color shaders don't have an opacity uniform. |
1281 | 0 | Color color; |
1282 | 0 | if (aEffectChain.mPrimaryEffect->mType == EffectTypes::SOLID_COLOR) { |
1283 | 0 | EffectSolidColor* effectSolidColor = |
1284 | 0 | static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get()); |
1285 | 0 | color = effectSolidColor->mColor; |
1286 | 0 |
|
1287 | 0 | Float opacity = aOpacity * color.a; |
1288 | 0 | color.r *= opacity; |
1289 | 0 | color.g *= opacity; |
1290 | 0 | color.b *= opacity; |
1291 | 0 | color.a = opacity; |
1292 | 0 |
|
1293 | 0 | // We can fold opacity into the color, so no need to consider it further. |
1294 | 0 | aOpacity = 1.f; |
1295 | 0 | } |
1296 | 0 |
|
1297 | 0 | bool createdMixBlendBackdropTexture = false; |
1298 | 0 | GLuint mixBlendBackdrop = 0; |
1299 | 0 | gfx::CompositionOp blendMode = gfx::CompositionOp::OP_OVER; |
1300 | 0 |
|
1301 | 0 | if (aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE]) { |
1302 | 0 | EffectBlendMode *blendEffect = |
1303 | 0 | static_cast<EffectBlendMode*>(aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get()); |
1304 | 0 | blendMode = blendEffect->mBlendMode; |
1305 | 0 | } |
1306 | 0 |
|
1307 | 0 | // Only apply DEAA to quads that have been transformed such that aliasing |
1308 | 0 | // could be visible |
1309 | 0 | bool bEnableAA = gfxPrefs::LayersDEAAEnabled() && |
1310 | 0 | !aTransform.Is2DIntegerTranslation(); |
1311 | 0 |
|
1312 | 0 | bool colorMatrix = aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX]; |
1313 | 0 | ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect, |
1314 | 0 | sourceMask, blendMode, colorMatrix, |
1315 | 0 | bEnableAA); |
1316 | 0 |
|
1317 | 0 | config.SetOpacity(aOpacity != 1.f); |
1318 | 0 | ApplyPrimitiveConfig(config, aGeometry); |
1319 | 0 |
|
1320 | 0 | ShaderProgramOGL *program = GetShaderProgramFor(config); |
1321 | 0 | MOZ_DIAGNOSTIC_ASSERT(program); |
1322 | 0 | if (!program) { |
1323 | 0 | return; |
1324 | 0 | } |
1325 | 0 | ActivateProgram(program); |
1326 | 0 | program->SetProjectionMatrix(mProjMatrix); |
1327 | 0 | program->SetLayerTransform(aTransform); |
1328 | 0 | LayerScope::SetLayerTransform(aTransform); |
1329 | 0 |
|
1330 | 0 | if (colorMatrix) { |
1331 | 0 | EffectColorMatrix* effectColorMatrix = |
1332 | 0 | static_cast<EffectColorMatrix*>(aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX].get()); |
1333 | 0 | program->SetColorMatrix(effectColorMatrix->mColorMatrix); |
1334 | 0 | } |
1335 | 0 |
|
1336 | 0 | if (BlendOpIsMixBlendMode(blendMode)) { |
1337 | 0 | gfx::Matrix4x4 backdropTransform; |
1338 | 0 |
|
1339 | 0 | if (gl()->IsExtensionSupported(GLContext::NV_texture_barrier)) { |
1340 | 0 | // The NV_texture_barrier extension lets us read directly from the |
1341 | 0 | // backbuffer. Let's do that. |
1342 | 0 | // We need to tell OpenGL about this, so that it can make sure everything |
1343 | 0 | // on the GPU is happening in the right order. |
1344 | 0 | gl()->fTextureBarrier(); |
1345 | 0 | mixBlendBackdrop = mCurrentRenderTarget->GetTextureHandle(); |
1346 | 0 | } else { |
1347 | 0 | gfx::IntRect rect = ComputeBackdropCopyRect(aRect, aClipRect, |
1348 | 0 | aTransform, &backdropTransform); |
1349 | 0 | mixBlendBackdrop = CreateTexture(rect, true, mCurrentRenderTarget->GetFBO()); |
1350 | 0 | createdMixBlendBackdropTexture = true; |
1351 | 0 | } |
1352 | 0 | program->SetBackdropTransform(backdropTransform); |
1353 | 0 | } |
1354 | 0 |
|
1355 | 0 | program->SetRenderOffset(offset.x, offset.y); |
1356 | 0 | LayerScope::SetRenderOffset(offset.x, offset.y); |
1357 | 0 |
|
1358 | 0 | if (aOpacity != 1.f) |
1359 | 0 | program->SetLayerOpacity(aOpacity); |
1360 | 0 |
|
1361 | 0 | if (config.mFeatures & ENABLE_TEXTURE_RECT) { |
1362 | 0 | TextureSourceOGL* source = nullptr; |
1363 | 0 | if (aEffectChain.mPrimaryEffect->mType == EffectTypes::COMPONENT_ALPHA) { |
1364 | 0 | EffectComponentAlpha* effectComponentAlpha = |
1365 | 0 | static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get()); |
1366 | 0 | source = effectComponentAlpha->mOnWhite->AsSourceOGL(); |
1367 | 0 | } else { |
1368 | 0 | TexturedEffect* texturedEffect = |
1369 | 0 | static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get()); |
1370 | 0 | source = texturedEffect->mTexture->AsSourceOGL(); |
1371 | 0 | } |
1372 | 0 | // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1. |
1373 | 0 | program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height); |
1374 | 0 | } |
1375 | 0 |
|
1376 | 0 | if (sourceMask && config.mFeatures & ENABLE_MASK_TEXTURE_RECT) { |
1377 | 0 | program->SetMaskCoordMultiplier(sourceMask->GetSize().width, |
1378 | 0 | sourceMask->GetSize().height); |
1379 | 0 | } |
1380 | 0 |
|
1381 | 0 | // XXX kip - These calculations could be performed once per layer rather than |
1382 | 0 | // for every tile. This might belong in Compositor.cpp once DEAA |
1383 | 0 | // is implemented for DirectX. |
1384 | 0 | if (bEnableAA) { |
1385 | 0 | // Calculate the transformed vertices of aVisibleRect in screen space |
1386 | 0 | // pixels, mirroring the calculations in the vertex shader |
1387 | 0 | Matrix4x4 flatTransform = aTransform; |
1388 | 0 | flatTransform.PostTranslate(-offset.x, -offset.y, 0.0f); |
1389 | 0 | flatTransform *= mProjMatrix; |
1390 | 0 |
|
1391 | 0 | Rect viewportClip = Rect(-1.0f, -1.0f, 2.0f, 2.0f); |
1392 | 0 | size_t edgeCount = 0; |
1393 | 0 | Point3D coefficients[4]; |
1394 | 0 |
|
1395 | 0 | Point points[Matrix4x4::kTransformAndClipRectMaxVerts]; |
1396 | 0 | size_t pointCount = flatTransform.TransformAndClipRect(aVisibleRect, viewportClip, points); |
1397 | 0 | for (size_t i = 0; i < pointCount; i++) { |
1398 | 0 | points[i] = Point((points[i].x * 0.5f + 0.5f) * mViewportSize.width, |
1399 | 0 | (points[i].y * 0.5f + 0.5f) * mViewportSize.height); |
1400 | 0 | } |
1401 | 0 | if (pointCount > 2) { |
1402 | 0 | // Use shoelace formula on a triangle in the clipped quad to determine if |
1403 | 0 | // winding order is reversed. Iterate through the triangles until one is |
1404 | 0 | // found with a non-zero area. |
1405 | 0 | float winding = 0.0f; |
1406 | 0 | size_t wp = 0; |
1407 | 0 | while (winding == 0.0f && wp < pointCount) { |
1408 | 0 | int wp1 = (wp + 1) % pointCount; |
1409 | 0 | int wp2 = (wp + 2) % pointCount; |
1410 | 0 | winding = (points[wp1].x - points[wp].x) * (points[wp1].y + points[wp].y) + |
1411 | 0 | (points[wp2].x - points[wp1].x) * (points[wp2].y + points[wp1].y) + |
1412 | 0 | (points[wp].x - points[wp2].x) * (points[wp].y + points[wp2].y); |
1413 | 0 | wp++; |
1414 | 0 | } |
1415 | 0 | bool frontFacing = winding >= 0.0f; |
1416 | 0 |
|
1417 | 0 | // Calculate the line coefficients used by the DEAA shader to determine the |
1418 | 0 | // sub-pixel coverage of the edge pixels |
1419 | 0 | for (size_t i=0; i<pointCount; i++) { |
1420 | 0 | const Point& p1 = points[i]; |
1421 | 0 | const Point& p2 = points[(i + 1) % pointCount]; |
1422 | 0 | // Create a DEAA edge for any non-straight lines, to a maximum of 4 |
1423 | 0 | if (p1.x != p2.x && p1.y != p2.y && edgeCount < 4) { |
1424 | 0 | if (frontFacing) { |
1425 | 0 | coefficients[edgeCount++] = GetLineCoefficients(p2, p1); |
1426 | 0 | } else { |
1427 | 0 | coefficients[edgeCount++] = GetLineCoefficients(p1, p2); |
1428 | 0 | } |
1429 | 0 | } |
1430 | 0 | } |
1431 | 0 | } |
1432 | 0 |
|
1433 | 0 | // The coefficients that are not needed must not cull any fragments. |
1434 | 0 | // We fill these unused coefficients with a clipping plane that has no |
1435 | 0 | // effect. |
1436 | 0 | for (size_t i = edgeCount; i < 4; i++) { |
1437 | 0 | coefficients[i] = Point3D(0.0f, 1.0f, mViewportSize.height); |
1438 | 0 | } |
1439 | 0 |
|
1440 | 0 | // Set uniforms required by DEAA shader |
1441 | 0 | Matrix4x4 transformInverted = aTransform; |
1442 | 0 | transformInverted.Invert(); |
1443 | 0 | program->SetLayerTransformInverse(transformInverted); |
1444 | 0 | program->SetDEAAEdges(coefficients); |
1445 | 0 | program->SetVisibleCenter(aVisibleRect.Center()); |
1446 | 0 | program->SetViewportSize(mViewportSize); |
1447 | 0 | } |
1448 | 0 |
|
1449 | 0 | bool didSetBlendMode = false; |
1450 | 0 |
|
1451 | 0 | switch (aEffectChain.mPrimaryEffect->mType) { |
1452 | 0 | case EffectTypes::SOLID_COLOR: { |
1453 | 0 | program->SetRenderColor(color); |
1454 | 0 |
|
1455 | 0 | if (maskType != MaskType::MaskNone) { |
1456 | 0 | BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE0, maskQuadTransform); |
1457 | 0 | } |
1458 | 0 | if (mixBlendBackdrop) { |
1459 | 0 | BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE1); |
1460 | 0 | } |
1461 | 0 |
|
1462 | 0 | didSetBlendMode = SetBlendMode(gl(), blendMode); |
1463 | 0 |
|
1464 | 0 | BindAndDrawGeometry(program, aGeometry); |
1465 | 0 | } |
1466 | 0 | break; |
1467 | 0 |
|
1468 | 0 | case EffectTypes::RGB: { |
1469 | 0 | TexturedEffect* texturedEffect = |
1470 | 0 | static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get()); |
1471 | 0 | TextureSource *source = texturedEffect->mTexture; |
1472 | 0 |
|
1473 | 0 | didSetBlendMode = SetBlendMode(gl(), blendMode, texturedEffect->mPremultiplied); |
1474 | 0 |
|
1475 | 0 | gfx::SamplingFilter samplingFilter = texturedEffect->mSamplingFilter; |
1476 | 0 |
|
1477 | 0 | source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, samplingFilter); |
1478 | 0 |
|
1479 | 0 | program->SetTextureUnit(0); |
1480 | 0 |
|
1481 | 0 | Matrix4x4 textureTransform = source->AsSourceOGL()->GetTextureTransform(); |
1482 | 0 | program->SetTextureTransform(textureTransform); |
1483 | 0 |
|
1484 | 0 | if (maskType != MaskType::MaskNone) { |
1485 | 0 | BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform); |
1486 | 0 | } |
1487 | 0 | if (mixBlendBackdrop) { |
1488 | 0 | BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE2); |
1489 | 0 | } |
1490 | 0 |
|
1491 | 0 | BindAndDrawGeometryWithTextureRect(program, aGeometry, |
1492 | 0 | texturedEffect->mTextureCoords, source); |
1493 | 0 | } |
1494 | 0 | break; |
1495 | 0 | case EffectTypes::YCBCR: { |
1496 | 0 | EffectYCbCr* effectYCbCr = |
1497 | 0 | static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get()); |
1498 | 0 | TextureSource* sourceYCbCr = effectYCbCr->mTexture; |
1499 | 0 | const int Y = 0, Cb = 1, Cr = 2; |
1500 | 0 | TextureSourceOGL* sourceY = sourceYCbCr->GetSubSource(Y)->AsSourceOGL(); |
1501 | 0 | TextureSourceOGL* sourceCb = sourceYCbCr->GetSubSource(Cb)->AsSourceOGL(); |
1502 | 0 | TextureSourceOGL* sourceCr = sourceYCbCr->GetSubSource(Cr)->AsSourceOGL(); |
1503 | 0 |
|
1504 | 0 | if (!sourceY || !sourceCb || !sourceCr) { |
1505 | 0 | NS_WARNING("Invalid layer texture."); |
1506 | 0 | return; |
1507 | 0 | } |
1508 | 0 |
|
1509 | 0 | sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectYCbCr->mSamplingFilter); |
1510 | 0 | sourceCb->BindTexture(LOCAL_GL_TEXTURE1, effectYCbCr->mSamplingFilter); |
1511 | 0 | sourceCr->BindTexture(LOCAL_GL_TEXTURE2, effectYCbCr->mSamplingFilter); |
1512 | 0 |
|
1513 | 0 | if (config.mFeatures & ENABLE_TEXTURE_RECT) { |
1514 | 0 | // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1. |
1515 | 0 | program->SetCbCrTexCoordMultiplier(sourceCb->GetSize().width, sourceCb->GetSize().height); |
1516 | 0 | } |
1517 | 0 |
|
1518 | 0 | program->SetYCbCrTextureUnits(Y, Cb, Cr); |
1519 | 0 | program->SetTextureTransform(Matrix4x4()); |
1520 | 0 | program->SetYUVColorSpace(effectYCbCr->mYUVColorSpace); |
1521 | 0 |
|
1522 | 0 | if (maskType != MaskType::MaskNone) { |
1523 | 0 | BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform); |
1524 | 0 | } |
1525 | 0 | if (mixBlendBackdrop) { |
1526 | 0 | BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE4); |
1527 | 0 | } |
1528 | 0 | didSetBlendMode = SetBlendMode(gl(), blendMode); |
1529 | 0 | BindAndDrawGeometryWithTextureRect(program, |
1530 | 0 | aGeometry, |
1531 | 0 | effectYCbCr->mTextureCoords, |
1532 | 0 | sourceYCbCr->GetSubSource(Y)); |
1533 | 0 | } |
1534 | 0 | break; |
1535 | 0 | case EffectTypes::NV12: { |
1536 | 0 | EffectNV12* effectNV12 = |
1537 | 0 | static_cast<EffectNV12*>(aEffectChain.mPrimaryEffect.get()); |
1538 | 0 | TextureSource* sourceNV12 = effectNV12->mTexture; |
1539 | 0 | const int Y = 0, CbCr = 1; |
1540 | 0 | TextureSourceOGL* sourceY = sourceNV12->GetSubSource(Y)->AsSourceOGL(); |
1541 | 0 | TextureSourceOGL* sourceCbCr = sourceNV12->GetSubSource(CbCr)->AsSourceOGL(); |
1542 | 0 |
|
1543 | 0 | if (!sourceY || !sourceCbCr) { |
1544 | 0 | NS_WARNING("Invalid layer texture."); |
1545 | 0 | return; |
1546 | 0 | } |
1547 | 0 |
|
1548 | 0 | sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectNV12->mSamplingFilter); |
1549 | 0 | sourceCbCr->BindTexture(LOCAL_GL_TEXTURE1, effectNV12->mSamplingFilter); |
1550 | 0 |
|
1551 | 0 | if (config.mFeatures & ENABLE_TEXTURE_RECT) { |
1552 | 0 | // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1. |
1553 | 0 | program->SetCbCrTexCoordMultiplier(sourceCbCr->GetSize().width, sourceCbCr->GetSize().height); |
1554 | 0 | } |
1555 | 0 |
|
1556 | 0 | program->SetNV12TextureUnits(Y, CbCr); |
1557 | 0 | program->SetTextureTransform(Matrix4x4()); |
1558 | 0 |
|
1559 | 0 | if (maskType != MaskType::MaskNone) { |
1560 | 0 | BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform); |
1561 | 0 | } |
1562 | 0 | if (mixBlendBackdrop) { |
1563 | 0 | BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE3); |
1564 | 0 | } |
1565 | 0 | didSetBlendMode = SetBlendMode(gl(), blendMode); |
1566 | 0 | BindAndDrawGeometryWithTextureRect(program, |
1567 | 0 | aGeometry, |
1568 | 0 | effectNV12->mTextureCoords, |
1569 | 0 | sourceNV12->GetSubSource(Y)); |
1570 | 0 | } |
1571 | 0 | break; |
1572 | 0 | case EffectTypes::RENDER_TARGET: { |
1573 | 0 | EffectRenderTarget* effectRenderTarget = |
1574 | 0 | static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get()); |
1575 | 0 | RefPtr<CompositingRenderTargetOGL> surface |
1576 | 0 | = static_cast<CompositingRenderTargetOGL*>(effectRenderTarget->mRenderTarget.get()); |
1577 | 0 |
|
1578 | 0 | surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget); |
1579 | 0 |
|
1580 | 0 | // Drawing is always flipped, but when copying between surfaces we want to avoid |
1581 | 0 | // this, so apply a flip here to cancel the other one out. |
1582 | 0 | Matrix transform; |
1583 | 0 | transform.PreTranslate(0.0, 1.0); |
1584 | 0 | transform.PreScale(1.0f, -1.0f); |
1585 | 0 | program->SetTextureTransform(Matrix4x4::From2D(transform)); |
1586 | 0 | program->SetTextureUnit(0); |
1587 | 0 |
|
1588 | 0 | if (maskType != MaskType::MaskNone) { |
1589 | 0 | BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform); |
1590 | 0 | } |
1591 | 0 | if (mixBlendBackdrop) { |
1592 | 0 | BindBackdrop(program, mixBlendBackdrop, LOCAL_GL_TEXTURE2); |
1593 | 0 | } |
1594 | 0 |
|
1595 | 0 | if (config.mFeatures & ENABLE_TEXTURE_RECT) { |
1596 | 0 | // 2DRect case, get the multiplier right for a sampler2DRect |
1597 | 0 | program->SetTexCoordMultiplier(surface->GetSize().width, |
1598 | 0 | surface->GetSize().height); |
1599 | 0 | } |
1600 | 0 |
|
1601 | 0 | // Drawing is always flipped, but when copying between surfaces we want to avoid |
1602 | 0 | // this. Pass true for the flip parameter to introduce a second flip |
1603 | 0 | // that cancels the other one out. |
1604 | 0 | didSetBlendMode = SetBlendMode(gl(), blendMode); |
1605 | 0 | BindAndDrawGeometry(program, aGeometry); |
1606 | 0 | } |
1607 | 0 | break; |
1608 | 0 | case EffectTypes::COMPONENT_ALPHA: { |
1609 | 0 | MOZ_ASSERT(gfxPrefs::ComponentAlphaEnabled()); |
1610 | 0 | MOZ_ASSERT(blendMode == gfx::CompositionOp::OP_OVER, "Can't support blend modes with component alpha!"); |
1611 | 0 | EffectComponentAlpha* effectComponentAlpha = |
1612 | 0 | static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get()); |
1613 | 0 | TextureSourceOGL* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceOGL(); |
1614 | 0 | TextureSourceOGL* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceOGL(); |
1615 | 0 |
|
1616 | 0 | if (!sourceOnBlack->IsValid() || |
1617 | 0 | !sourceOnWhite->IsValid()) { |
1618 | 0 | NS_WARNING("Invalid layer texture for component alpha"); |
1619 | 0 | return; |
1620 | 0 | } |
1621 | 0 |
|
1622 | 0 | sourceOnBlack->BindTexture(LOCAL_GL_TEXTURE0, effectComponentAlpha->mSamplingFilter); |
1623 | 0 | sourceOnWhite->BindTexture(LOCAL_GL_TEXTURE1, effectComponentAlpha->mSamplingFilter); |
1624 | 0 |
|
1625 | 0 | program->SetBlackTextureUnit(0); |
1626 | 0 | program->SetWhiteTextureUnit(1); |
1627 | 0 | program->SetTextureTransform(Matrix4x4()); |
1628 | 0 |
|
1629 | 0 | if (maskType != MaskType::MaskNone) { |
1630 | 0 | BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform); |
1631 | 0 | } |
1632 | 0 | // Pass 1. |
1633 | 0 | gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR, |
1634 | 0 | LOCAL_GL_ONE, LOCAL_GL_ONE); |
1635 | 0 | program->SetTexturePass2(false); |
1636 | 0 | BindAndDrawGeometryWithTextureRect(program, |
1637 | 0 | aGeometry, |
1638 | 0 | effectComponentAlpha->mTextureCoords, |
1639 | 0 | effectComponentAlpha->mOnBlack); |
1640 | 0 |
|
1641 | 0 | // Pass 2. |
1642 | 0 | gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE, |
1643 | 0 | LOCAL_GL_ONE, LOCAL_GL_ONE); |
1644 | 0 | program->SetTexturePass2(true); |
1645 | 0 | BindAndDrawGeometryWithTextureRect(program, |
1646 | 0 | aGeometry, |
1647 | 0 | effectComponentAlpha->mTextureCoords, |
1648 | 0 | effectComponentAlpha->mOnBlack); |
1649 | 0 |
|
1650 | 0 | mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, |
1651 | 0 | LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA); |
1652 | 0 | } |
1653 | 0 | break; |
1654 | 0 | default: |
1655 | 0 | MOZ_ASSERT(false, "Unhandled effect type"); |
1656 | 0 | break; |
1657 | 0 | } |
1658 | 0 |
|
1659 | 0 | if (didSetBlendMode) { |
1660 | 0 | gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, |
1661 | 0 | LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA); |
1662 | 0 | } |
1663 | 0 | if (createdMixBlendBackdropTexture) { |
1664 | 0 | gl()->fDeleteTextures(1, &mixBlendBackdrop); |
1665 | 0 | } |
1666 | 0 |
|
1667 | 0 | // in case rendering has used some other GL context |
1668 | 0 | MakeCurrent(); |
1669 | 0 |
|
1670 | 0 | LayerScope::DrawEnd(mGLContext, aEffectChain, |
1671 | 0 | aRect.Width(), aRect.Height()); |
1672 | 0 | } Unexecuted instantiation: void mozilla::layers::CompositorOGL::DrawGeometry<mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> >(mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const&, mozilla::layers::EffectChain const&, float, mozilla::gfx::Matrix4x4Typed<mozilla::gfx::UnknownUnits, mozilla::gfx::UnknownUnits> const&, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&) Unexecuted instantiation: void mozilla::layers::CompositorOGL::DrawGeometry<nsTArray<mozilla::gfx::TexturedTriangleTyped<mozilla::gfx::UnknownUnits, float> > >(nsTArray<mozilla::gfx::TexturedTriangleTyped<mozilla::gfx::UnknownUnits, float> > const&, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const&, mozilla::layers::EffectChain const&, float, mozilla::gfx::Matrix4x4Typed<mozilla::gfx::UnknownUnits, mozilla::gfx::UnknownUnits> const&, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const&) |
1673 | | |
1674 | | void |
1675 | | CompositorOGL::BindAndDrawGeometry(ShaderProgramOGL* aProgram, |
1676 | | const gfx::Rect& aRect) |
1677 | 0 | { |
1678 | 0 | BindAndDrawQuad(aProgram, aRect); |
1679 | 0 | } |
1680 | | |
1681 | | void |
1682 | | CompositorOGL::BindAndDrawGeometry(ShaderProgramOGL* aProgram, |
1683 | | const nsTArray<gfx::TexturedTriangle>& aTriangles) |
1684 | 0 | { |
1685 | 0 | NS_ASSERTION(aProgram->HasInitialized(), "Shader program not correctly initialized"); |
1686 | 0 |
|
1687 | 0 | const nsTArray<TexturedVertex> vertices = TexturedTrianglesToVertexArray(aTriangles); |
1688 | 0 |
|
1689 | 0 | mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTriangleVBO); |
1690 | 0 | mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, |
1691 | 0 | vertices.Length() * sizeof(TexturedVertex), |
1692 | 0 | vertices.Elements(), |
1693 | 0 | LOCAL_GL_STREAM_DRAW); |
1694 | 0 |
|
1695 | 0 | const GLsizei stride = 4 * sizeof(GLfloat); |
1696 | 0 | InitializeVAO(kCoordinateAttributeIndex, 2, stride, 0); |
1697 | 0 | InitializeVAO(kTexCoordinateAttributeIndex, 2, stride, 2 * sizeof(GLfloat)); |
1698 | 0 |
|
1699 | 0 | mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, vertices.Length()); |
1700 | 0 |
|
1701 | 0 | mGLContext->fDisableVertexAttribArray(kCoordinateAttributeIndex); |
1702 | 0 | mGLContext->fDisableVertexAttribArray(kTexCoordinateAttributeIndex); |
1703 | 0 | mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); |
1704 | 0 | } |
1705 | | |
1706 | | // |aRect| is the rectangle we want to draw to. We will draw it with |
1707 | | // up to 4 draw commands if necessary to avoid wrapping. |
1708 | | // |aTexCoordRect| is the rectangle from the texture that we want to |
1709 | | // draw using the given program. |
1710 | | // |aTexture| is the texture we are drawing. Its actual size can be |
1711 | | // larger than the rectangle given by |texCoordRect|. |
1712 | | void |
1713 | | CompositorOGL::BindAndDrawGeometryWithTextureRect(ShaderProgramOGL *aProg, |
1714 | | const Rect& aRect, |
1715 | | const Rect& aTexCoordRect, |
1716 | | TextureSource *aTexture) |
1717 | 0 | { |
1718 | 0 | Rect scaledTexCoordRect = GetTextureCoordinates(aTexCoordRect, aTexture); |
1719 | 0 | Rect layerRects[4]; |
1720 | 0 | Rect textureRects[4]; |
1721 | 0 | size_t rects = DecomposeIntoNoRepeatRects(aRect, |
1722 | 0 | scaledTexCoordRect, |
1723 | 0 | &layerRects, |
1724 | 0 | &textureRects); |
1725 | 0 |
|
1726 | 0 | BindAndDrawQuads(aProg, rects, layerRects, textureRects); |
1727 | 0 | } |
1728 | | |
1729 | | void |
1730 | | CompositorOGL::BindAndDrawGeometryWithTextureRect(ShaderProgramOGL *aProg, |
1731 | | const nsTArray<gfx::TexturedTriangle>& aTriangles, |
1732 | | const gfx::Rect& aTexCoordRect, |
1733 | | TextureSource *aTexture) |
1734 | 0 | { |
1735 | 0 | BindAndDrawGeometry(aProg, aTriangles); |
1736 | 0 | } |
1737 | | |
1738 | | void |
1739 | | CompositorOGL::BindAndDrawQuads(ShaderProgramOGL *aProg, |
1740 | | int aQuads, |
1741 | | const Rect* aLayerRects, |
1742 | | const Rect* aTextureRects) |
1743 | 0 | { |
1744 | 0 | NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized"); |
1745 | 0 |
|
1746 | 0 | mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO); |
1747 | 0 | InitializeVAO(kCoordinateAttributeIndex, 4, 0, 0); |
1748 | 0 |
|
1749 | 0 | aProg->SetLayerRects(aLayerRects); |
1750 | 0 | if (aProg->GetTextureCount() > 0) { |
1751 | 0 | aProg->SetTextureRects(aTextureRects); |
1752 | 0 | } |
1753 | 0 |
|
1754 | 0 | // We are using GL_TRIANGLES here because the Mac Intel drivers fail to properly |
1755 | 0 | // process uniform arrays with GL_TRIANGLE_STRIP. Go figure. |
1756 | 0 | mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, 6 * aQuads); |
1757 | 0 | mGLContext->fDisableVertexAttribArray(kCoordinateAttributeIndex); |
1758 | 0 | mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); |
1759 | 0 | LayerScope::SetDrawRects(aQuads, aLayerRects, aTextureRects); |
1760 | 0 | } |
1761 | | |
1762 | | void |
1763 | | CompositorOGL::InitializeVAO(const GLuint aAttrib, const GLint aComponents, |
1764 | | const GLsizei aStride, const size_t aOffset) |
1765 | 0 | { |
1766 | 0 | mGLContext->fVertexAttribPointer(aAttrib, aComponents, LOCAL_GL_FLOAT, |
1767 | 0 | LOCAL_GL_FALSE, aStride, |
1768 | 0 | reinterpret_cast<GLvoid*>(aOffset)); |
1769 | 0 | mGLContext->fEnableVertexAttribArray(aAttrib); |
1770 | 0 | } |
1771 | | |
1772 | | void |
1773 | | CompositorOGL::EndFrame() |
1774 | 0 | { |
1775 | 0 | AUTO_PROFILER_LABEL("CompositorOGL::EndFrame", GRAPHICS); |
1776 | 0 |
|
1777 | 0 | MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored"); |
1778 | 0 |
|
1779 | | #ifdef MOZ_DUMP_PAINTING |
1780 | | if (gfxEnv::DumpCompositorTextures()) { |
1781 | | LayoutDeviceIntSize size; |
1782 | | if (mUseExternalSurfaceSize) { |
1783 | | size = LayoutDeviceIntSize(mSurfaceSize.width, mSurfaceSize.height); |
1784 | | } else { |
1785 | | size = mWidget->GetClientSize(); |
1786 | | } |
1787 | | RefPtr<DrawTarget> target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(size.width, size.height), SurfaceFormat::B8G8R8A8); |
1788 | | if (target) { |
1789 | | CopyToTarget(target, nsIntPoint(), Matrix()); |
1790 | | WriteSnapshotToDumpFile(this, target); |
1791 | | } |
1792 | | } |
1793 | | #endif |
1794 | |
|
1795 | 0 | mFrameInProgress = false; |
1796 | 0 |
|
1797 | 0 | if (mTarget) { |
1798 | 0 | CopyToTarget(mTarget, mTargetBounds.TopLeft(), Matrix()); |
1799 | 0 | mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); |
1800 | 0 | mWindowRenderTarget = nullptr; |
1801 | 0 | mCurrentRenderTarget = nullptr; |
1802 | 0 | Compositor::EndFrame(); |
1803 | 0 | return; |
1804 | 0 | } |
1805 | 0 |
|
1806 | 0 | mWindowRenderTarget = nullptr; |
1807 | 0 | mCurrentRenderTarget = nullptr; |
1808 | 0 |
|
1809 | 0 | if (mTexturePool) { |
1810 | 0 | mTexturePool->EndFrame(); |
1811 | 0 | } |
1812 | 0 |
|
1813 | 0 | mGLContext->SwapBuffers(); |
1814 | 0 | mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); |
1815 | 0 |
|
1816 | 0 | // Unbind all textures |
1817 | 0 | for (GLuint i = 0; i <= 4; i++) { |
1818 | 0 | mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0 + i); |
1819 | 0 | mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, 0); |
1820 | 0 | if (!mGLContext->IsGLES()) { |
1821 | 0 | mGLContext->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0); |
1822 | 0 | } |
1823 | 0 | } |
1824 | 0 |
|
1825 | 0 | Compositor::EndFrame(); |
1826 | 0 | } |
1827 | | |
1828 | | void |
1829 | | CompositorOGL::SetDestinationSurfaceSize(const IntSize& aSize) |
1830 | 0 | { |
1831 | 0 | mSurfaceSize.width = aSize.width; |
1832 | 0 | mSurfaceSize.height = aSize.height; |
1833 | 0 | } |
1834 | | |
1835 | | void |
1836 | | CompositorOGL::CopyToTarget(DrawTarget* aTarget, const nsIntPoint& aTopLeft, const gfx::Matrix& aTransform) |
1837 | 0 | { |
1838 | 0 | MOZ_ASSERT(aTarget); |
1839 | 0 | IntRect rect; |
1840 | 0 | if (mUseExternalSurfaceSize) { |
1841 | 0 | rect = IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height); |
1842 | 0 | } else { |
1843 | 0 | rect = IntRect(0, 0, mWidgetSize.width, mWidgetSize.height); |
1844 | 0 | } |
1845 | 0 | GLint width = rect.Width(); |
1846 | 0 | GLint height = rect.Height(); |
1847 | 0 |
|
1848 | 0 | if ((int64_t(width) * int64_t(height) * int64_t(4)) > INT32_MAX) { |
1849 | 0 | NS_ERROR("Widget size too big - integer overflow!"); |
1850 | 0 | return; |
1851 | 0 | } |
1852 | 0 |
|
1853 | 0 | mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); |
1854 | 0 |
|
1855 | 0 | if (!mGLContext->IsGLES()) { |
1856 | 0 | // GLES2 promises that binding to any custom FBO will attach |
1857 | 0 | // to GL_COLOR_ATTACHMENT0 attachment point. |
1858 | 0 | mGLContext->fReadBuffer(LOCAL_GL_BACK); |
1859 | 0 | } |
1860 | 0 |
|
1861 | 0 | RefPtr<DataSourceSurface> source = |
1862 | 0 | Factory::CreateDataSourceSurface(rect.Size(), gfx::SurfaceFormat::B8G8R8A8); |
1863 | 0 | if (NS_WARN_IF(!source)) { |
1864 | 0 | return; |
1865 | 0 | } |
1866 | 0 | |
1867 | 0 | ReadPixelsIntoDataSurface(mGLContext, source); |
1868 | 0 |
|
1869 | 0 | // Map from GL space to Cairo space and reverse the world transform. |
1870 | 0 | Matrix glToCairoTransform = aTransform; |
1871 | 0 | glToCairoTransform.Invert(); |
1872 | 0 | glToCairoTransform.PreScale(1.0, -1.0); |
1873 | 0 | glToCairoTransform.PreTranslate(0.0, -height); |
1874 | 0 |
|
1875 | 0 | glToCairoTransform.PostTranslate(-aTopLeft.x, -aTopLeft.y); |
1876 | 0 |
|
1877 | 0 | Matrix oldMatrix = aTarget->GetTransform(); |
1878 | 0 | aTarget->SetTransform(glToCairoTransform); |
1879 | 0 | Rect floatRect = Rect(rect.X(), rect.Y(), width, height); |
1880 | 0 | aTarget->DrawSurface(source, floatRect, floatRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE)); |
1881 | 0 | aTarget->SetTransform(oldMatrix); |
1882 | 0 | aTarget->Flush(); |
1883 | 0 | } |
1884 | | |
1885 | | void |
1886 | | CompositorOGL::Pause() |
1887 | 0 | { |
1888 | | #ifdef MOZ_WIDGET_ANDROID |
1889 | | if (!gl() || gl()->IsDestroyed()) |
1890 | | return; |
1891 | | gl()->MakeCurrent(); |
1892 | | java::GeckoSurfaceTexture::DestroyUnused((int64_t)mGLContext.get()); |
1893 | | java::GeckoSurfaceTexture::DetachAllFromGLContext((int64_t)mGLContext.get()); |
1894 | | // ReleaseSurface internally calls MakeCurrent |
1895 | | gl()->ReleaseSurface(); |
1896 | | #endif |
1897 | | } |
1898 | | |
1899 | | bool |
1900 | | CompositorOGL::Resume() |
1901 | 0 | { |
1902 | | #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT) |
1903 | | if (!gl() || gl()->IsDestroyed()) |
1904 | | return false; |
1905 | | |
1906 | | // RenewSurface internally calls MakeCurrent. |
1907 | | return gl()->RenewSurface(GetWidget()); |
1908 | | #endif |
1909 | | return true; |
1910 | 0 | } |
1911 | | |
1912 | | already_AddRefed<DataTextureSource> |
1913 | | CompositorOGL::CreateDataTextureSource(TextureFlags aFlags) |
1914 | 0 | { |
1915 | 0 | if (!gl()) { |
1916 | 0 | return nullptr; |
1917 | 0 | } |
1918 | 0 | |
1919 | 0 | return MakeAndAddRef<TextureImageTextureSourceOGL>(this, aFlags); |
1920 | 0 | } |
1921 | | |
1922 | | already_AddRefed<DataTextureSource> |
1923 | | CompositorOGL::CreateDataTextureSourceAroundYCbCr(TextureHost* aTexture) |
1924 | 0 | { |
1925 | 0 | if (!gl()) { |
1926 | 0 | return nullptr; |
1927 | 0 | } |
1928 | 0 | |
1929 | 0 | BufferTextureHost* bufferTexture = aTexture->AsBufferTextureHost(); |
1930 | 0 | MOZ_ASSERT(bufferTexture); |
1931 | 0 |
|
1932 | 0 | if (!bufferTexture) { |
1933 | 0 | return nullptr; |
1934 | 0 | } |
1935 | 0 | |
1936 | 0 | uint8_t* buf = bufferTexture->GetBuffer(); |
1937 | 0 | const BufferDescriptor& buffDesc = bufferTexture->GetBufferDescriptor(); |
1938 | 0 | const YCbCrDescriptor& desc = buffDesc.get_YCbCrDescriptor(); |
1939 | 0 |
|
1940 | 0 | RefPtr<gfx::DataSourceSurface> tempY = |
1941 | 0 | gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetYChannel(buf, desc), |
1942 | 0 | desc.yStride(), |
1943 | 0 | desc.ySize(), |
1944 | 0 | SurfaceFormatForAlphaBitDepth(desc.bitDepth())); |
1945 | 0 | if (!tempY) { |
1946 | 0 | return nullptr; |
1947 | 0 | } |
1948 | 0 | RefPtr<gfx::DataSourceSurface> tempCb = |
1949 | 0 | gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetCbChannel(buf, desc), |
1950 | 0 | desc.cbCrStride(), |
1951 | 0 | desc.cbCrSize(), |
1952 | 0 | SurfaceFormatForAlphaBitDepth(desc.bitDepth())); |
1953 | 0 | if (!tempCb) { |
1954 | 0 | return nullptr; |
1955 | 0 | } |
1956 | 0 | RefPtr<gfx::DataSourceSurface> tempCr = |
1957 | 0 | gfx::Factory::CreateWrappingDataSourceSurface(ImageDataSerializer::GetCrChannel(buf, desc), |
1958 | 0 | desc.cbCrStride(), |
1959 | 0 | desc.cbCrSize(), |
1960 | 0 | SurfaceFormatForAlphaBitDepth(desc.bitDepth())); |
1961 | 0 | if (!tempCr) { |
1962 | 0 | return nullptr; |
1963 | 0 | } |
1964 | 0 | |
1965 | 0 | RefPtr<DirectMapTextureSource> srcY = new DirectMapTextureSource(this, tempY); |
1966 | 0 | RefPtr<DirectMapTextureSource> srcU = new DirectMapTextureSource(this, tempCb); |
1967 | 0 | RefPtr<DirectMapTextureSource> srcV = new DirectMapTextureSource(this, tempCr); |
1968 | 0 |
|
1969 | 0 | srcY->SetNextSibling(srcU); |
1970 | 0 | srcU->SetNextSibling(srcV); |
1971 | 0 |
|
1972 | 0 | return srcY.forget(); |
1973 | 0 | } |
1974 | | |
1975 | | #ifdef XP_DARWIN |
1976 | | void |
1977 | | CompositorOGL::MaybeUnlockBeforeNextComposition(TextureHost* aTextureHost) |
1978 | | { |
1979 | | auto bufferTexture = aTextureHost->AsBufferTextureHost(); |
1980 | | if (bufferTexture) { |
1981 | | mMaybeUnlockBeforeNextComposition.AppendElement(bufferTexture); |
1982 | | } |
1983 | | } |
1984 | | |
1985 | | void |
1986 | | CompositorOGL::TryUnlockTextures() |
1987 | | { |
1988 | | nsClassHashtable<nsUint32HashKey, nsTArray<uint64_t>> texturesIdsToUnlockByPid; |
1989 | | for (auto& texture : mMaybeUnlockBeforeNextComposition) { |
1990 | | if (texture->IsDirectMap() && texture->CanUnlock()) { |
1991 | | texture->ReadUnlock(); |
1992 | | auto actor = texture->GetIPDLActor(); |
1993 | | if (actor) { |
1994 | | base::ProcessId pid = actor->OtherPid(); |
1995 | | nsTArray<uint64_t>* textureIds = texturesIdsToUnlockByPid.LookupOrAdd(pid); |
1996 | | textureIds->AppendElement(TextureHost::GetTextureSerial(actor)); |
1997 | | } |
1998 | | } |
1999 | | } |
2000 | | mMaybeUnlockBeforeNextComposition.Clear(); |
2001 | | for (auto it = texturesIdsToUnlockByPid.ConstIter(); !it.Done(); it.Next()) { |
2002 | | TextureSync::SetTexturesUnlocked(it.Key(), *it.UserData()); |
2003 | | } |
2004 | | } |
2005 | | #endif |
2006 | | |
2007 | | already_AddRefed<DataTextureSource> |
2008 | | CompositorOGL::CreateDataTextureSourceAround(gfx::DataSourceSurface* aSurface) |
2009 | 0 | { |
2010 | 0 | if (!gl()) { |
2011 | 0 | return nullptr; |
2012 | 0 | } |
2013 | 0 | |
2014 | 0 | return MakeAndAddRef<DirectMapTextureSource>(this, aSurface); |
2015 | 0 | } |
2016 | | |
2017 | | bool |
2018 | | CompositorOGL::SupportsPartialTextureUpdate() |
2019 | 0 | { |
2020 | 0 | return CanUploadSubTextures(mGLContext); |
2021 | 0 | } |
2022 | | |
2023 | | int32_t |
2024 | | CompositorOGL::GetMaxTextureSize() const |
2025 | 0 | { |
2026 | 0 | MOZ_ASSERT(mGLContext); |
2027 | 0 | GLint texSize = 0; |
2028 | 0 | mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, |
2029 | 0 | &texSize); |
2030 | 0 | MOZ_ASSERT(texSize != 0); |
2031 | 0 | return texSize; |
2032 | 0 | } |
2033 | | |
2034 | | void |
2035 | 0 | CompositorOGL::MakeCurrent(MakeCurrentFlags aFlags) { |
2036 | 0 | if (mDestroyed) { |
2037 | 0 | NS_WARNING("Call on destroyed layer manager"); |
2038 | 0 | return; |
2039 | 0 | } |
2040 | 0 | mGLContext->MakeCurrent(aFlags & ForceMakeCurrent); |
2041 | 0 | } |
2042 | | |
2043 | | GLBlitTextureImageHelper* |
2044 | | CompositorOGL::BlitTextureImageHelper() |
2045 | 0 | { |
2046 | 0 | if (!mBlitTextureImageHelper) { |
2047 | 0 | mBlitTextureImageHelper = MakeUnique<GLBlitTextureImageHelper>(this); |
2048 | 0 | } |
2049 | 0 |
|
2050 | 0 | return mBlitTextureImageHelper.get(); |
2051 | 0 | } |
2052 | | |
2053 | | GLuint |
2054 | | CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit) |
2055 | 0 | { |
2056 | 0 | if (!mTexturePool) { |
2057 | 0 | mTexturePool = new PerUnitTexturePoolOGL(gl()); |
2058 | 0 | } |
2059 | 0 | return mTexturePool->GetTexture(aTarget, aUnit); |
2060 | 0 | } |
2061 | | |
2062 | | bool |
2063 | | CompositorOGL::SupportsTextureDirectMapping() |
2064 | 0 | { |
2065 | 0 | if (!gfxPrefs::AllowTextureDirectMapping()) { |
2066 | 0 | return false; |
2067 | 0 | } |
2068 | 0 | |
2069 | 0 | if (mGLContext) { |
2070 | 0 | mGLContext->MakeCurrent(); |
2071 | 0 | return mGLContext->IsExtensionSupported(gl::GLContext::APPLE_client_storage) && |
2072 | 0 | mGLContext->IsExtensionSupported(gl::GLContext::APPLE_texture_range); |
2073 | 0 | } |
2074 | 0 |
|
2075 | 0 | return false; |
2076 | 0 | } |
2077 | | |
2078 | | GLuint |
2079 | | PerUnitTexturePoolOGL::GetTexture(GLenum aTarget, GLenum aTextureUnit) |
2080 | 0 | { |
2081 | 0 | if (mTextureTarget == 0) { |
2082 | 0 | mTextureTarget = aTarget; |
2083 | 0 | } |
2084 | 0 | MOZ_ASSERT(mTextureTarget == aTarget); |
2085 | 0 |
|
2086 | 0 | size_t index = aTextureUnit - LOCAL_GL_TEXTURE0; |
2087 | 0 | // lazily grow the array of temporary textures |
2088 | 0 | if (mTextures.Length() <= index) { |
2089 | 0 | size_t prevLength = mTextures.Length(); |
2090 | 0 | mTextures.SetLength(index + 1); |
2091 | 0 | for(unsigned int i = prevLength; i <= index; ++i) { |
2092 | 0 | mTextures[i] = 0; |
2093 | 0 | } |
2094 | 0 | } |
2095 | 0 | // lazily initialize the temporary textures |
2096 | 0 | if (!mTextures[index]) { |
2097 | 0 | if (!mGL->MakeCurrent()) { |
2098 | 0 | return 0; |
2099 | 0 | } |
2100 | 0 | mGL->fGenTextures(1, &mTextures[index]); |
2101 | 0 | mGL->fBindTexture(aTarget, mTextures[index]); |
2102 | 0 | mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); |
2103 | 0 | mGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); |
2104 | 0 | } |
2105 | 0 | return mTextures[index]; |
2106 | 0 | } |
2107 | | |
2108 | | void |
2109 | | PerUnitTexturePoolOGL::DestroyTextures() |
2110 | 0 | { |
2111 | 0 | if (mGL && mGL->MakeCurrent()) { |
2112 | 0 | if (mTextures.Length() > 0) { |
2113 | 0 | mGL->fDeleteTextures(mTextures.Length(), &mTextures[0]); |
2114 | 0 | } |
2115 | 0 | } |
2116 | 0 | mTextures.SetLength(0); |
2117 | 0 | } |
2118 | | |
2119 | | bool |
2120 | | CompositorOGL::SupportsLayerGeometry() const |
2121 | 0 | { |
2122 | 0 | return gfxPrefs::OGLLayerGeometry(); |
2123 | 0 | } |
2124 | | |
2125 | | } // namespace layers |
2126 | | } // namespace mozilla |