Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* vim: set ts=8 sts=4 et sw=4 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 "GLBlitTextureImageHelper.h"
8 : #include "GLUploadHelpers.h"
9 : #include "DecomposeIntoNoRepeatTriangles.h"
10 : #include "GLContext.h"
11 : #include "GLTextureImage.h"
12 : #include "ScopedGLHelpers.h"
13 : #include "nsRect.h"
14 : #include "gfx2DGlue.h"
15 : #include "gfxUtils.h"
16 : #include "CompositorOGL.h"
17 : #include "mozilla/gfx/Point.h"
18 :
19 : using namespace mozilla::gl;
20 :
21 : namespace mozilla {
22 : namespace layers {
23 :
24 0 : GLBlitTextureImageHelper::GLBlitTextureImageHelper(CompositorOGL* aCompositor)
25 : : mCompositor(aCompositor)
26 : , mBlitProgram(0)
27 0 : , mBlitFramebuffer(0)
28 :
29 : {
30 0 : }
31 :
32 0 : GLBlitTextureImageHelper::~GLBlitTextureImageHelper()
33 : {
34 0 : GLContext *gl = mCompositor->gl();
35 : // Likely used by OGL Layers.
36 0 : gl->fDeleteProgram(mBlitProgram);
37 0 : gl->fDeleteFramebuffers(1, &mBlitFramebuffer);
38 0 : }
39 :
40 : void
41 0 : GLBlitTextureImageHelper::BlitTextureImage(TextureImage *aSrc, const gfx::IntRect& aSrcRect,
42 : TextureImage *aDst, const gfx::IntRect& aDstRect)
43 : {
44 0 : GLContext *gl = mCompositor->gl();
45 :
46 0 : if (!aSrc || !aDst || aSrcRect.IsEmpty() || aDstRect.IsEmpty())
47 0 : return;
48 :
49 0 : int savedFb = 0;
50 0 : gl->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &savedFb);
51 :
52 0 : ScopedGLState scopedScissorTestState(gl, LOCAL_GL_SCISSOR_TEST, false);
53 0 : ScopedGLState scopedBlendState(gl, LOCAL_GL_BLEND, false);
54 :
55 : // 2.0 means scale up by two
56 0 : float blitScaleX = float(aDstRect.width) / float(aSrcRect.width);
57 0 : float blitScaleY = float(aDstRect.height) / float(aSrcRect.height);
58 :
59 : // We start iterating over all destination tiles
60 0 : aDst->BeginBigImageIteration();
61 0 : do {
62 : // calculate portion of the tile that is going to be painted to
63 0 : gfx::IntRect dstSubRect;
64 0 : gfx::IntRect dstTextureRect = aDst->GetTileRect();
65 0 : dstSubRect.IntersectRect(aDstRect, dstTextureRect);
66 :
67 : // this tile is not part of the destination rectangle aDstRect
68 0 : if (dstSubRect.IsEmpty())
69 0 : continue;
70 :
71 : // (*) transform the rect of this tile into the rectangle defined by aSrcRect...
72 0 : gfx::IntRect dstInSrcRect(dstSubRect);
73 0 : dstInSrcRect.MoveBy(-aDstRect.TopLeft());
74 : // ...which might be of different size, hence scale accordingly
75 0 : dstInSrcRect.ScaleRoundOut(1.0f / blitScaleX, 1.0f / blitScaleY);
76 0 : dstInSrcRect.MoveBy(aSrcRect.TopLeft());
77 :
78 0 : SetBlitFramebufferForDestTexture(aDst->GetTextureID());
79 0 : UseBlitProgram();
80 :
81 0 : aSrc->BeginBigImageIteration();
82 : // now iterate over all tiles in the source Image...
83 0 : do {
84 : // calculate portion of the source tile that is in the source rect
85 0 : gfx::IntRect srcSubRect;
86 0 : gfx::IntRect srcTextureRect = aSrc->GetTileRect();
87 0 : srcSubRect.IntersectRect(aSrcRect, srcTextureRect);
88 :
89 : // this tile is not part of the source rect
90 0 : if (srcSubRect.IsEmpty()) {
91 0 : continue;
92 : }
93 : // calculate intersection of source rect with destination rect
94 0 : srcSubRect.IntersectRect(srcSubRect, dstInSrcRect);
95 : // this tile does not overlap the current destination tile
96 0 : if (srcSubRect.IsEmpty()) {
97 0 : continue;
98 : }
99 : // We now have the intersection of
100 : // the current source tile
101 : // and the desired source rectangle
102 : // and the destination tile
103 : // and the desired destination rectange
104 : // in destination space.
105 : // We need to transform this back into destination space, inverting the transform from (*)
106 0 : gfx::IntRect srcSubInDstRect(srcSubRect);
107 0 : srcSubInDstRect.MoveBy(-aSrcRect.TopLeft());
108 0 : srcSubInDstRect.ScaleRoundOut(blitScaleX, blitScaleY);
109 0 : srcSubInDstRect.MoveBy(aDstRect.TopLeft());
110 :
111 : // we transform these rectangles to be relative to the current src and dst tiles, respectively
112 0 : gfx::IntSize srcSize = srcTextureRect.Size();
113 0 : gfx::IntSize dstSize = dstTextureRect.Size();
114 0 : srcSubRect.MoveBy(-srcTextureRect.x, -srcTextureRect.y);
115 0 : srcSubInDstRect.MoveBy(-dstTextureRect.x, -dstTextureRect.y);
116 :
117 0 : float dx0 = 2.0f * float(srcSubInDstRect.x) / float(dstSize.width) - 1.0f;
118 0 : float dy0 = 2.0f * float(srcSubInDstRect.y) / float(dstSize.height) - 1.0f;
119 0 : float dx1 = 2.0f * float(srcSubInDstRect.x + srcSubInDstRect.width) / float(dstSize.width) - 1.0f;
120 0 : float dy1 = 2.0f * float(srcSubInDstRect.y + srcSubInDstRect.height) / float(dstSize.height) - 1.0f;
121 0 : ScopedViewportRect autoViewportRect(gl, 0, 0, dstSize.width, dstSize.height);
122 :
123 0 : RectTriangles rects;
124 :
125 0 : gfx::IntSize realTexSize = srcSize;
126 0 : if (!CanUploadNonPowerOfTwo(gl)) {
127 0 : realTexSize = gfx::IntSize(RoundUpPow2(srcSize.width),
128 0 : RoundUpPow2(srcSize.height));
129 : }
130 :
131 0 : if (aSrc->GetWrapMode() == LOCAL_GL_REPEAT) {
132 0 : rects.addRect(/* dest rectangle */
133 : dx0, dy0, dx1, dy1,
134 : /* tex coords */
135 0 : srcSubRect.x / float(realTexSize.width),
136 0 : srcSubRect.y / float(realTexSize.height),
137 0 : srcSubRect.XMost() / float(realTexSize.width),
138 0 : srcSubRect.YMost() / float(realTexSize.height));
139 : } else {
140 0 : DecomposeIntoNoRepeatTriangles(srcSubRect, realTexSize, rects);
141 :
142 : // now put the coords into the d[xy]0 .. d[xy]1 coordinate space
143 : // from the 0..1 that it comes out of decompose
144 0 : InfallibleTArray<RectTriangles::coord>& coords = rects.vertCoords();
145 :
146 0 : for (unsigned int i = 0; i < coords.Length(); ++i) {
147 0 : coords[i].x = (coords[i].x * (dx1 - dx0)) + dx0;
148 0 : coords[i].y = (coords[i].y * (dy1 - dy0)) + dy0;
149 : }
150 : }
151 :
152 0 : ScopedBindTextureUnit autoTexUnit(gl, LOCAL_GL_TEXTURE0);
153 0 : ScopedBindTexture autoTex(gl, aSrc->GetTextureID());
154 0 : ScopedVertexAttribPointer autoAttrib0(gl, 0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0, rects.vertCoords().Elements());
155 0 : ScopedVertexAttribPointer autoAttrib1(gl, 1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0, rects.texCoords().Elements());
156 :
157 0 : gl->fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements());
158 :
159 0 : } while (aSrc->NextTile());
160 0 : } while (aDst->NextTile());
161 :
162 : // unbind the previous texture from the framebuffer
163 0 : SetBlitFramebufferForDestTexture(0);
164 :
165 0 : gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, savedFb);
166 : }
167 :
168 : void
169 0 : GLBlitTextureImageHelper::SetBlitFramebufferForDestTexture(GLuint aTexture)
170 : {
171 0 : GLContext *gl = mCompositor->gl();
172 0 : if (!mBlitFramebuffer) {
173 0 : gl->fGenFramebuffers(1, &mBlitFramebuffer);
174 : }
175 :
176 0 : gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBlitFramebuffer);
177 : gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
178 : LOCAL_GL_COLOR_ATTACHMENT0,
179 : LOCAL_GL_TEXTURE_2D,
180 : aTexture,
181 0 : 0);
182 :
183 0 : GLenum result = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
184 0 : if (aTexture && (result != LOCAL_GL_FRAMEBUFFER_COMPLETE)) {
185 0 : nsAutoCString msg;
186 0 : msg.AppendLiteral("Framebuffer not complete -- error 0x");
187 0 : msg.AppendInt(result, 16);
188 : // Note: if you are hitting this, it is likely that
189 : // your texture is not texture complete -- that is, you
190 : // allocated a texture name, but didn't actually define its
191 : // size via a call to TexImage2D.
192 0 : NS_RUNTIMEABORT(msg.get());
193 : }
194 0 : }
195 :
196 : void
197 0 : GLBlitTextureImageHelper::UseBlitProgram()
198 : {
199 : // XXX: GLBlitTextureImageHelper doesn't use ShaderProgramOGL
200 : // so we need to Reset the program
201 0 : mCompositor->ResetProgram();
202 :
203 0 : GLContext *gl = mCompositor->gl();
204 0 : if (mBlitProgram) {
205 0 : gl->fUseProgram(mBlitProgram);
206 0 : return;
207 : }
208 :
209 0 : mBlitProgram = gl->fCreateProgram();
210 :
211 : GLuint shaders[2];
212 0 : shaders[0] = gl->fCreateShader(LOCAL_GL_VERTEX_SHADER);
213 0 : shaders[1] = gl->fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
214 :
215 : const char *blitVSSrc =
216 : "attribute vec2 aVertex;"
217 : "attribute vec2 aTexCoord;"
218 : "varying vec2 vTexCoord;"
219 : "void main() {"
220 : " vTexCoord = aTexCoord;"
221 : " gl_Position = vec4(aVertex, 0.0, 1.0);"
222 0 : "}";
223 : const char *blitFSSrc = "#ifdef GL_ES\nprecision mediump float;\n#endif\n"
224 : "uniform sampler2D uSrcTexture;"
225 : "varying vec2 vTexCoord;"
226 : "void main() {"
227 : " gl_FragColor = texture2D(uSrcTexture, vTexCoord);"
228 0 : "}";
229 :
230 0 : gl->fShaderSource(shaders[0], 1, (const GLchar**) &blitVSSrc, nullptr);
231 0 : gl->fShaderSource(shaders[1], 1, (const GLchar**) &blitFSSrc, nullptr);
232 :
233 0 : for (int i = 0; i < 2; ++i) {
234 0 : GLint success, len = 0;
235 :
236 0 : gl->fCompileShader(shaders[i]);
237 0 : gl->fGetShaderiv(shaders[i], LOCAL_GL_COMPILE_STATUS, &success);
238 0 : NS_ASSERTION(success, "Shader compilation failed!");
239 :
240 0 : if (!success) {
241 0 : nsAutoCString log;
242 0 : gl->fGetShaderiv(shaders[i], LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len);
243 0 : log.SetCapacity(len);
244 0 : gl->fGetShaderInfoLog(shaders[i], len, (GLint*) &len, (char*) log.BeginWriting());
245 0 : log.SetLength(len);
246 :
247 0 : printf_stderr("Shader %d compilation failed:\n%s\n", i, log.get());
248 0 : return;
249 : }
250 :
251 0 : gl->fAttachShader(mBlitProgram, shaders[i]);
252 0 : gl->fDeleteShader(shaders[i]);
253 : }
254 :
255 0 : gl->fBindAttribLocation(mBlitProgram, 0, "aVertex");
256 0 : gl->fBindAttribLocation(mBlitProgram, 1, "aTexCoord");
257 :
258 0 : gl->fLinkProgram(mBlitProgram);
259 :
260 0 : GLint success, len = 0;
261 0 : gl->fGetProgramiv(mBlitProgram, LOCAL_GL_LINK_STATUS, &success);
262 0 : NS_ASSERTION(success, "Shader linking failed!");
263 :
264 0 : if (!success) {
265 0 : nsAutoCString log;
266 0 : gl->fGetProgramiv(mBlitProgram, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len);
267 0 : log.SetCapacity(len);
268 0 : gl->fGetProgramInfoLog(mBlitProgram, len, (GLint*) &len, (char*) log.BeginWriting());
269 0 : log.SetLength(len);
270 :
271 0 : printf_stderr("Program linking failed:\n%s\n", log.get());
272 0 : return;
273 : }
274 :
275 0 : gl->fUseProgram(mBlitProgram);
276 0 : gl->fUniform1i(gl->fGetUniformLocation(mBlitProgram, "uSrcTexture"), 0);
277 : }
278 :
279 : } // namespace layers
280 : } // namespace mozilla
|