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#include <algorithm> 42#include <wtf/StdLibExtras.h> 43 44namespace WebCore { 45 46Texture::Texture(GraphicsContext3D* context, PassOwnPtr<Vector<unsigned int>> tileTextureIds, Format format, int width, int height, int maxTextureSize) 47 : m_context(context) 48 , m_format(format) 49 , m_tiles(IntSize(maxTextureSize, maxTextureSize), IntSize(width, height), true) 50 , m_tileTextureIds(tileTextureIds) 51{ 52} 53 54Texture::~Texture() 55{ 56 for (unsigned int i = 0; i < m_tileTextureIds->size(); i++) 57 m_context->deleteTexture(m_tileTextureIds->at(i)); 58} 59 60static void convertFormat(GraphicsContext3D* context, Texture::Format format, unsigned int* glFormat, unsigned int* glType, bool* swizzle) 61{ 62 *swizzle = false; 63 switch (format) { 64 case Texture::RGBA8: 65 *glFormat = GraphicsContext3D::RGBA; 66 *glType = GraphicsContext3D::UNSIGNED_BYTE; 67 break; 68 case Texture::BGRA8: 69 if (context->getExtensions()->supports("GL_EXT_texture_format_BGRA8888")) { 70 *glFormat = Extensions3D::BGRA_EXT; 71 *glType = GraphicsContext3D::UNSIGNED_BYTE; 72 } else { 73 *glFormat = GraphicsContext3D::RGBA; 74 *glType = GraphicsContext3D::UNSIGNED_BYTE; 75 *swizzle = true; 76 } 77 break; 78 default: 79 ASSERT_NOT_REACHED(); 80 break; 81 } 82} 83 84PassRefPtr<Texture> Texture::create(GraphicsContext3D* context, Format format, int width, int height) 85{ 86 int maxTextureSize = 0; 87 context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &maxTextureSize); 88 TilingData tiling(IntSize(maxTextureSize, maxTextureSize), IntSize(width, height), true); 89 90 // Check for overflow. 91 int numTiles = tiling.numTilesX() * tiling.numTilesY(); 92 if (numTiles / tiling.numTilesX() != tiling.numTilesY()) { 93 tiling.setTotalSize(IntSize()); 94 numTiles = 0; 95 } 96 97 OwnPtr<Vector<unsigned int>> textureIds = adoptPtr(new Vector<unsigned int>(numTiles)); 98 textureIds->fill(0, numTiles); 99 100 for (int i = 0; i < numTiles; i++) { 101 int textureId = context->createTexture(); 102 if (!textureId) { 103 for (int i = 0; i < numTiles; i++) 104 context->deleteTexture(textureIds->at(i)); 105 return 0; 106 } 107 textureIds->at(i) = textureId; 108 109 int xIndex = i % tiling.numTilesX(); 110 int yIndex = i / tiling.numTilesX(); 111 IntRect tileBoundsWithBorder = tiling.tileBoundsWithBorder(xIndex, yIndex); 112 113 unsigned int glFormat = 0; 114 unsigned int glType = 0; 115 bool swizzle; 116 convertFormat(context, format, &glFormat, &glType, &swizzle); 117 context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId); 118 context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, glFormat, 119 tileBoundsWithBorder.width(), 120 tileBoundsWithBorder.height(), 121 0, glFormat, glType); 122 } 123 return adoptRef(new Texture(context, textureIds.release(), format, width, height, maxTextureSize)); 124} 125 126template <bool swizzle> 127static uint32_t* copySubRect(uint32_t* src, int srcX, int srcY, uint32_t* dst, int width, int height, int srcStride) 128{ 129 uint32_t* srcOffset = src + srcX + srcY * srcStride; 130 131 if (!swizzle && width == srcStride) 132 return srcOffset; 133 134 if (swizzle) { 135 uint32_t* dstPixel = dst; 136 for (int y = 0; y < height; ++y) { 137 for (int x = 0; x < width ; ++x) { 138 uint32_t pixel = srcOffset[x + y * srcStride]; 139 *dstPixel = (pixel & 0xFF00FF00) | ((pixel & 0x00FF0000) >> 16) | ((pixel & 0x000000FF) << 16); 140 dstPixel++; 141 } 142 } 143 } else { 144 for (int y = 0; y < height; ++y) { 145 memcpy(dst + y * width, srcOffset + y * srcStride, 4 * width); 146 } 147 } 148 return dst; 149} 150 151void Texture::load(void* pixels) 152{ 153 updateSubRect(pixels, IntRect(0, 0, m_tiles.totalSize().width(), m_tiles.totalSize().height())); 154} 155 156void Texture::updateSubRect(void* pixels, const IntRect& updateRect) 157{ 158 IntRect updateRectSanitized(updateRect); 159 updateRectSanitized.intersect(IntRect(0, 0, m_tiles.totalSize().width(), m_tiles.totalSize().height())); 160 161 uint32_t* pixels32 = static_cast<uint32_t*>(pixels); 162 unsigned int glFormat = 0; 163 unsigned int glType = 0; 164 bool swizzle; 165 convertFormat(m_context, m_format, &glFormat, &glType, &swizzle); 166 if (swizzle) { 167 ASSERT(glFormat == GraphicsContext3D::RGBA && glType == GraphicsContext3D::UNSIGNED_BYTE); 168 // FIXME: This could use PBO's to save doing an extra copy here. 169 } 170 int tempBuffSize = // Temporary buffer size is the smaller of the max texture size or the updateRectSanitized 171 std::min(m_tiles.maxTextureSize().width(), m_tiles.borderTexels() + updateRectSanitized.width()) * 172 std::min(m_tiles.maxTextureSize().height(), m_tiles.borderTexels() + updateRectSanitized.height()); 173 auto tempBuff = std::make_unique<uint32_t[]>(tempBuffSize); 174 175 for (int tile = 0; tile < m_tiles.numTilesX() * m_tiles.numTilesY(); tile++) { 176 int xIndex = tile % m_tiles.numTilesX(); 177 int yIndex = tile / m_tiles.numTilesX(); 178 179 // Intersect with tile 180 IntRect tileBoundsWithBorder = m_tiles.tileBoundsWithBorder(xIndex, yIndex); 181 182 IntRect updateRectIntersected = updateRectSanitized; 183 updateRectIntersected.intersect(tileBoundsWithBorder); 184 185 IntRect dstRect = updateRectIntersected; 186 dstRect.moveBy(-tileBoundsWithBorder.location()); 187 188 if (updateRectIntersected.isEmpty()) 189 continue; 190 191 // Copy sub rectangle out of larger pixel data 192 uint32_t* uploadBuff = 0; 193 if (swizzle) { 194 uploadBuff = copySubRect<true>( 195 pixels32, updateRectIntersected.x(), updateRectIntersected.y(), 196 tempBuff.get(), updateRectIntersected.width(), updateRectIntersected.height(), m_tiles.totalSize().width()); 197 } else { 198 uploadBuff = copySubRect<false>( 199 pixels32, updateRectIntersected.x(), updateRectIntersected.y(), 200 tempBuff.get(), updateRectIntersected.width(), updateRectIntersected.height(), m_tiles.totalSize().width()); 201 } 202 203 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_tileTextureIds->at(tile)); 204 m_context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0 /* level */, 205 dstRect.x(), 206 dstRect.y(), 207 updateRectIntersected.width(), 208 updateRectIntersected.height(), glFormat, glType, uploadBuff); 209 } 210} 211 212void Texture::bindTile(int tile) 213{ 214 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_tileTextureIds->at(tile)); 215 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); 216 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); 217 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); 218 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); 219} 220 221} 222 223#endif 224