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