1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/gl/GLBlitTextureImageHelper.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,281 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim: set ts=8 sts=4 et sw=4 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "GLBlitTextureImageHelper.h" 1.11 +#include "GLUploadHelpers.h" 1.12 +#include "DecomposeIntoNoRepeatTriangles.h" 1.13 +#include "GLContext.h" 1.14 +#include "ScopedGLHelpers.h" 1.15 +#include "nsRect.h" 1.16 +#include "gfx2DGlue.h" 1.17 +#include "gfxUtils.h" 1.18 + 1.19 +namespace mozilla { 1.20 +namespace gl { 1.21 + 1.22 +GLBlitTextureImageHelper::GLBlitTextureImageHelper(GLContext* gl) 1.23 + : mGL(gl) 1.24 + , mBlitProgram(0) 1.25 + , mBlitFramebuffer(0) 1.26 + 1.27 +{ 1.28 +} 1.29 + 1.30 +GLBlitTextureImageHelper::~GLBlitTextureImageHelper() 1.31 +{ 1.32 + // Likely used by OGL Layers. 1.33 + mGL->fDeleteProgram(mBlitProgram); 1.34 + mGL->fDeleteFramebuffers(1, &mBlitFramebuffer); 1.35 +} 1.36 + 1.37 +void 1.38 +GLBlitTextureImageHelper::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect, 1.39 + TextureImage *aDst, const nsIntRect& aDstRect) 1.40 +{ 1.41 + NS_ASSERTION(!aSrc->InUpdate(), "Source texture is in update!"); 1.42 + NS_ASSERTION(!aDst->InUpdate(), "Destination texture is in update!"); 1.43 + 1.44 + if (aSrcRect.IsEmpty() || aDstRect.IsEmpty()) 1.45 + return; 1.46 + 1.47 + int savedFb = 0; 1.48 + mGL->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &savedFb); 1.49 + 1.50 + ScopedGLState scopedScissorTestState(mGL, LOCAL_GL_SCISSOR_TEST, false); 1.51 + ScopedGLState scopedBlendState(mGL, LOCAL_GL_BLEND, false); 1.52 + 1.53 + // 2.0 means scale up by two 1.54 + float blitScaleX = float(aDstRect.width) / float(aSrcRect.width); 1.55 + float blitScaleY = float(aDstRect.height) / float(aSrcRect.height); 1.56 + 1.57 + // We start iterating over all destination tiles 1.58 + aDst->BeginTileIteration(); 1.59 + do { 1.60 + // calculate portion of the tile that is going to be painted to 1.61 + nsIntRect dstSubRect; 1.62 + nsIntRect dstTextureRect = ThebesIntRect(aDst->GetTileRect()); 1.63 + dstSubRect.IntersectRect(aDstRect, dstTextureRect); 1.64 + 1.65 + // this tile is not part of the destination rectangle aDstRect 1.66 + if (dstSubRect.IsEmpty()) 1.67 + continue; 1.68 + 1.69 + // (*) transform the rect of this tile into the rectangle defined by aSrcRect... 1.70 + nsIntRect dstInSrcRect(dstSubRect); 1.71 + dstInSrcRect.MoveBy(-aDstRect.TopLeft()); 1.72 + // ...which might be of different size, hence scale accordingly 1.73 + dstInSrcRect.ScaleRoundOut(1.0f / blitScaleX, 1.0f / blitScaleY); 1.74 + dstInSrcRect.MoveBy(aSrcRect.TopLeft()); 1.75 + 1.76 + SetBlitFramebufferForDestTexture(aDst->GetTextureID()); 1.77 + UseBlitProgram(); 1.78 + 1.79 + aSrc->BeginTileIteration(); 1.80 + // now iterate over all tiles in the source Image... 1.81 + do { 1.82 + // calculate portion of the source tile that is in the source rect 1.83 + nsIntRect srcSubRect; 1.84 + nsIntRect srcTextureRect = ThebesIntRect(aSrc->GetTileRect()); 1.85 + srcSubRect.IntersectRect(aSrcRect, srcTextureRect); 1.86 + 1.87 + // this tile is not part of the source rect 1.88 + if (srcSubRect.IsEmpty()) { 1.89 + continue; 1.90 + } 1.91 + // calculate intersection of source rect with destination rect 1.92 + srcSubRect.IntersectRect(srcSubRect, dstInSrcRect); 1.93 + // this tile does not overlap the current destination tile 1.94 + if (srcSubRect.IsEmpty()) { 1.95 + continue; 1.96 + } 1.97 + // We now have the intersection of 1.98 + // the current source tile 1.99 + // and the desired source rectangle 1.100 + // and the destination tile 1.101 + // and the desired destination rectange 1.102 + // in destination space. 1.103 + // We need to transform this back into destination space, inverting the transform from (*) 1.104 + nsIntRect srcSubInDstRect(srcSubRect); 1.105 + srcSubInDstRect.MoveBy(-aSrcRect.TopLeft()); 1.106 + srcSubInDstRect.ScaleRoundOut(blitScaleX, blitScaleY); 1.107 + srcSubInDstRect.MoveBy(aDstRect.TopLeft()); 1.108 + 1.109 + // we transform these rectangles to be relative to the current src and dst tiles, respectively 1.110 + nsIntSize srcSize = srcTextureRect.Size(); 1.111 + nsIntSize dstSize = dstTextureRect.Size(); 1.112 + srcSubRect.MoveBy(-srcTextureRect.x, -srcTextureRect.y); 1.113 + srcSubInDstRect.MoveBy(-dstTextureRect.x, -dstTextureRect.y); 1.114 + 1.115 + float dx0 = 2.0f * float(srcSubInDstRect.x) / float(dstSize.width) - 1.0f; 1.116 + float dy0 = 2.0f * float(srcSubInDstRect.y) / float(dstSize.height) - 1.0f; 1.117 + float dx1 = 2.0f * float(srcSubInDstRect.x + srcSubInDstRect.width) / float(dstSize.width) - 1.0f; 1.118 + float dy1 = 2.0f * float(srcSubInDstRect.y + srcSubInDstRect.height) / float(dstSize.height) - 1.0f; 1.119 + ScopedViewportRect autoViewportRect(mGL, 0, 0, dstSize.width, dstSize.height); 1.120 + 1.121 + RectTriangles rects; 1.122 + 1.123 + nsIntSize realTexSize = srcSize; 1.124 + if (!CanUploadNonPowerOfTwo(mGL)) { 1.125 + realTexSize = nsIntSize(gfx::NextPowerOfTwo(srcSize.width), 1.126 + gfx::NextPowerOfTwo(srcSize.height)); 1.127 + } 1.128 + 1.129 + if (aSrc->GetWrapMode() == LOCAL_GL_REPEAT) { 1.130 + rects.addRect(/* dest rectangle */ 1.131 + dx0, dy0, dx1, dy1, 1.132 + /* tex coords */ 1.133 + srcSubRect.x / float(realTexSize.width), 1.134 + srcSubRect.y / float(realTexSize.height), 1.135 + srcSubRect.XMost() / float(realTexSize.width), 1.136 + srcSubRect.YMost() / float(realTexSize.height)); 1.137 + } else { 1.138 + DecomposeIntoNoRepeatTriangles(srcSubRect, realTexSize, rects); 1.139 + 1.140 + // now put the coords into the d[xy]0 .. d[xy]1 coordinate space 1.141 + // from the 0..1 that it comes out of decompose 1.142 + InfallibleTArray<RectTriangles::coord>& coords = rects.vertCoords(); 1.143 + 1.144 + for (unsigned int i = 0; i < coords.Length(); ++i) { 1.145 + coords[i].x = (coords[i].x * (dx1 - dx0)) + dx0; 1.146 + coords[i].y = (coords[i].y * (dy1 - dy0)) + dy0; 1.147 + } 1.148 + } 1.149 + 1.150 + ScopedBindTextureUnit autoTexUnit(mGL, LOCAL_GL_TEXTURE0); 1.151 + ScopedBindTexture autoTex(mGL, aSrc->GetTextureID()); 1.152 + 1.153 + mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 1.154 + 1.155 + mGL->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.vertCoords().Elements()); 1.156 + mGL->fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.texCoords().Elements()); 1.157 + 1.158 + mGL->fEnableVertexAttribArray(0); 1.159 + mGL->fEnableVertexAttribArray(1); 1.160 + 1.161 + mGL->fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements()); 1.162 + 1.163 + mGL->fDisableVertexAttribArray(0); 1.164 + mGL->fDisableVertexAttribArray(1); 1.165 + 1.166 + } while (aSrc->NextTile()); 1.167 + } while (aDst->NextTile()); 1.168 + 1.169 + mGL->fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, nullptr); 1.170 + mGL->fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, nullptr); 1.171 + 1.172 + // unbind the previous texture from the framebuffer 1.173 + SetBlitFramebufferForDestTexture(0); 1.174 + 1.175 + mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, savedFb); 1.176 +} 1.177 + 1.178 +void 1.179 +GLBlitTextureImageHelper::SetBlitFramebufferForDestTexture(GLuint aTexture) 1.180 +{ 1.181 + if (!mBlitFramebuffer) { 1.182 + mGL->fGenFramebuffers(1, &mBlitFramebuffer); 1.183 + } 1.184 + 1.185 + mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBlitFramebuffer); 1.186 + mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, 1.187 + LOCAL_GL_COLOR_ATTACHMENT0, 1.188 + LOCAL_GL_TEXTURE_2D, 1.189 + aTexture, 1.190 + 0); 1.191 + 1.192 + GLenum result = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); 1.193 + if (aTexture && (result != LOCAL_GL_FRAMEBUFFER_COMPLETE)) { 1.194 + nsAutoCString msg; 1.195 + msg.Append("Framebuffer not complete -- error 0x"); 1.196 + msg.AppendInt(result, 16); 1.197 + // Note: if you are hitting this, it is likely that 1.198 + // your texture is not texture complete -- that is, you 1.199 + // allocated a texture name, but didn't actually define its 1.200 + // size via a call to TexImage2D. 1.201 + NS_RUNTIMEABORT(msg.get()); 1.202 + } 1.203 +} 1.204 + 1.205 +void 1.206 +GLBlitTextureImageHelper::UseBlitProgram() 1.207 +{ 1.208 + if (mBlitProgram) { 1.209 + mGL->fUseProgram(mBlitProgram); 1.210 + return; 1.211 + } 1.212 + 1.213 + mBlitProgram = mGL->fCreateProgram(); 1.214 + 1.215 + GLuint shaders[2]; 1.216 + shaders[0] = mGL->fCreateShader(LOCAL_GL_VERTEX_SHADER); 1.217 + shaders[1] = mGL->fCreateShader(LOCAL_GL_FRAGMENT_SHADER); 1.218 + 1.219 + const char *blitVSSrc = 1.220 + "attribute vec2 aVertex;" 1.221 + "attribute vec2 aTexCoord;" 1.222 + "varying vec2 vTexCoord;" 1.223 + "void main() {" 1.224 + " vTexCoord = aTexCoord;" 1.225 + " gl_Position = vec4(aVertex, 0.0, 1.0);" 1.226 + "}"; 1.227 + const char *blitFSSrc = "#ifdef GL_ES\nprecision mediump float;\n#endif\n" 1.228 + "uniform sampler2D uSrcTexture;" 1.229 + "varying vec2 vTexCoord;" 1.230 + "void main() {" 1.231 + " gl_FragColor = texture2D(uSrcTexture, vTexCoord);" 1.232 + "}"; 1.233 + 1.234 + mGL->fShaderSource(shaders[0], 1, (const GLchar**) &blitVSSrc, nullptr); 1.235 + mGL->fShaderSource(shaders[1], 1, (const GLchar**) &blitFSSrc, nullptr); 1.236 + 1.237 + for (int i = 0; i < 2; ++i) { 1.238 + GLint success, len = 0; 1.239 + 1.240 + mGL->fCompileShader(shaders[i]); 1.241 + mGL->fGetShaderiv(shaders[i], LOCAL_GL_COMPILE_STATUS, &success); 1.242 + NS_ASSERTION(success, "Shader compilation failed!"); 1.243 + 1.244 + if (!success) { 1.245 + nsAutoCString log; 1.246 + mGL->fGetShaderiv(shaders[i], LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len); 1.247 + log.SetCapacity(len); 1.248 + mGL->fGetShaderInfoLog(shaders[i], len, (GLint*) &len, (char*) log.BeginWriting()); 1.249 + log.SetLength(len); 1.250 + 1.251 + printf_stderr("Shader %d compilation failed:\n%s\n", i, log.get()); 1.252 + return; 1.253 + } 1.254 + 1.255 + mGL->fAttachShader(mBlitProgram, shaders[i]); 1.256 + mGL->fDeleteShader(shaders[i]); 1.257 + } 1.258 + 1.259 + mGL->fBindAttribLocation(mBlitProgram, 0, "aVertex"); 1.260 + mGL->fBindAttribLocation(mBlitProgram, 1, "aTexCoord"); 1.261 + 1.262 + mGL->fLinkProgram(mBlitProgram); 1.263 + 1.264 + GLint success, len = 0; 1.265 + mGL->fGetProgramiv(mBlitProgram, LOCAL_GL_LINK_STATUS, &success); 1.266 + NS_ASSERTION(success, "Shader linking failed!"); 1.267 + 1.268 + if (!success) { 1.269 + nsAutoCString log; 1.270 + mGL->fGetProgramiv(mBlitProgram, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len); 1.271 + log.SetCapacity(len); 1.272 + mGL->fGetProgramInfoLog(mBlitProgram, len, (GLint*) &len, (char*) log.BeginWriting()); 1.273 + log.SetLength(len); 1.274 + 1.275 + printf_stderr("Program linking failed:\n%s\n", log.get()); 1.276 + return; 1.277 + } 1.278 + 1.279 + mGL->fUseProgram(mBlitProgram); 1.280 + mGL->fUniform1i(mGL->fGetUniformLocation(mBlitProgram, "uSrcTexture"), 0); 1.281 +} 1.282 + 1.283 +} 1.284 +}