Home | History | Annotate | Download | only in gpu
      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