1 /* 2 * Copyright (c) 2010, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 33 #if ENABLE(ACCELERATED_2D_CANVAS) 34 35 #include "Texture.h" 36 37 #include "Extensions3D.h" 38 #include "FloatRect.h" 39 #include "GraphicsContext3D.h" 40 #include "IntRect.h" 41 42 #include <algorithm> 43 #include <wtf/OwnArrayPtr.h> 44 45 using namespace std; 46 47 namespace WebCore { 48 49 50 Texture::Texture(GraphicsContext3D* context, PassOwnPtr<Vector<unsigned int> > tileTextureIds, Format format, int width, int height, int maxTextureSize) 51 : m_context(context) 52 , m_format(format) 53 , m_tiles(maxTextureSize, width, height, true) 54 , m_tileTextureIds(tileTextureIds) 55 { 56 } 57 58 Texture::~Texture() 59 { 60 for (unsigned int i = 0; i < m_tileTextureIds->size(); i++) 61 m_context->deleteTexture(m_tileTextureIds->at(i)); 62 } 63 64 static void convertFormat(GraphicsContext3D* context, Texture::Format format, unsigned int* glFormat, unsigned int* glType, bool* swizzle) 65 { 66 *swizzle = false; 67 switch (format) { 68 case Texture::RGBA8: 69 *glFormat = GraphicsContext3D::RGBA; 70 *glType = GraphicsContext3D::UNSIGNED_BYTE; 71 break; 72 case Texture::BGRA8: 73 if (context->getExtensions()->supports("GL_EXT_texture_format_BGRA8888")) { 74 *glFormat = Extensions3D::BGRA_EXT; 75 *glType = GraphicsContext3D::UNSIGNED_BYTE; 76 } else { 77 *glFormat = GraphicsContext3D::RGBA; 78 *glType = GraphicsContext3D::UNSIGNED_BYTE; 79 *swizzle = true; 80 } 81 break; 82 default: 83 ASSERT_NOT_REACHED(); 84 break; 85 } 86 } 87 88 PassRefPtr<Texture> Texture::create(GraphicsContext3D* context, Format format, int width, int height) 89 { 90 int maxTextureSize = 0; 91 context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &maxTextureSize); 92 TilingData tiling(maxTextureSize, width, height, true); 93 int numTiles = tiling.numTiles(); 94 95 OwnPtr<Vector<unsigned int> > textureIds(new Vector<unsigned int>(numTiles)); 96 textureIds->fill(0, numTiles); 97 98 for (int i = 0; i < numTiles; i++) { 99 int textureId = context->createTexture(); 100 if (!textureId) { 101 for (int i = 0; i < numTiles; i++) 102 context->deleteTexture(textureIds->at(i)); 103 return 0; 104 } 105 textureIds->at(i) = textureId; 106 107 IntRect tileBoundsWithBorder = tiling.tileBoundsWithBorder(i); 108 109 unsigned int glFormat = 0; 110 unsigned int glType = 0; 111 bool swizzle; 112 convertFormat(context, format, &glFormat, &glType, &swizzle); 113 context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId); 114 context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, glFormat, 115 tileBoundsWithBorder.width(), 116 tileBoundsWithBorder.height(), 117 0, glFormat, glType); 118 } 119 return adoptRef(new Texture(context, textureIds.leakPtr(), format, width, height, maxTextureSize)); 120 } 121 122 template <bool swizzle> 123 static uint32_t* copySubRect(uint32_t* src, int srcX, int srcY, uint32_t* dst, int width, int height, int srcStride) 124 { 125 uint32_t* srcOffset = src + srcX + srcY * srcStride; 126 127 if (!swizzle && width == srcStride) 128 return srcOffset; 129 130 if (swizzle) { 131 uint32_t* dstPixel = dst; 132 for (int y = 0; y < height; ++y) { 133 for (int x = 0; x < width ; ++x) { 134 uint32_t pixel = srcOffset[x + y * srcStride]; 135 *dstPixel = (pixel & 0xFF00FF00) | ((pixel & 0x00FF0000) >> 16) | ((pixel & 0x000000FF) << 16); 136 dstPixel++; 137 } 138 } 139 } else { 140 for (int y = 0; y < height; ++y) { 141 memcpy(dst + y * width, srcOffset + y * srcStride, 4 * width); 142 } 143 } 144 return dst; 145 } 146 147 void Texture::load(void* pixels) 148 { 149 updateSubRect(pixels, IntRect(0, 0, m_tiles.totalSizeX(), m_tiles.totalSizeY())); 150 } 151 152 void Texture::updateSubRect(void* pixels, const IntRect& updateRect) 153 { 154 IntRect updateRectSanitized(updateRect); 155 updateRectSanitized.intersect(IntRect(0, 0, m_tiles.totalSizeX(), m_tiles.totalSizeY())); 156 157 uint32_t* pixels32 = static_cast<uint32_t*>(pixels); 158 unsigned int glFormat = 0; 159 unsigned int glType = 0; 160 bool swizzle; 161 convertFormat(m_context, m_format, &glFormat, &glType, &swizzle); 162 if (swizzle) { 163 ASSERT(glFormat == GraphicsContext3D::RGBA && glType == GraphicsContext3D::UNSIGNED_BYTE); 164 // FIXME: This could use PBO's to save doing an extra copy here. 165 } 166 int tempBuffSize = // Temporary buffer size is the smaller of the max texture size or the updateRectSanitized 167 min(m_tiles.maxTextureSize(), m_tiles.borderTexels() + updateRectSanitized.width()) * 168 min(m_tiles.maxTextureSize(), m_tiles.borderTexels() + updateRectSanitized.height()); 169 OwnArrayPtr<uint32_t> tempBuff = adoptArrayPtr(new uint32_t[tempBuffSize]); 170 171 for (int tile = 0; tile < m_tiles.numTiles(); tile++) { 172 // Intersect with tile 173 IntRect tileBoundsWithBorder = m_tiles.tileBoundsWithBorder(tile); 174 175 IntRect updateRectIntersected = updateRectSanitized; 176 updateRectIntersected.intersect(tileBoundsWithBorder); 177 178 IntRect dstRect = updateRectIntersected; 179 dstRect.move(-tileBoundsWithBorder.x(), -tileBoundsWithBorder.y()); 180 181 if (updateRectIntersected.isEmpty()) 182 continue; 183 184 // Copy sub rectangle out of larger pixel data 185 uint32_t* uploadBuff = 0; 186 if (swizzle) { 187 uploadBuff = copySubRect<true>( 188 pixels32, updateRectIntersected.x(), updateRectIntersected.y(), 189 tempBuff.get(), updateRectIntersected.width(), updateRectIntersected.height(), m_tiles.totalSizeX()); 190 } else { 191 uploadBuff = copySubRect<false>( 192 pixels32, updateRectIntersected.x(), updateRectIntersected.y(), 193 tempBuff.get(), updateRectIntersected.width(), updateRectIntersected.height(), m_tiles.totalSizeX()); 194 } 195 196 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_tileTextureIds->at(tile)); 197 m_context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0 /* level */, 198 dstRect.x(), 199 dstRect.y(), 200 updateRectIntersected.width(), 201 updateRectIntersected.height(), glFormat, glType, uploadBuff); 202 } 203 } 204 205 void Texture::bindTile(int tile) 206 { 207 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_tileTextureIds->at(tile)); 208 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); 209 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); 210 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); 211 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); 212 } 213 214 } 215 216 #endif 217