initial import
[vuplus_webkit] / Source / WebCore / platform / graphics / gpu / Texture.cpp
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 = adoptPtr(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.release(), 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.moveBy(-tileBoundsWithBorder.location());
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