2 * Copyright (c) 2010, Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 #if ENABLE(ACCELERATED_2D_CANVAS)
37 #include "Extensions3D.h"
38 #include "FloatRect.h"
39 #include "GraphicsContext3D.h"
43 #include <wtf/OwnArrayPtr.h>
50 Texture::Texture(GraphicsContext3D* context, PassOwnPtr<Vector<unsigned int> > tileTextureIds, Format format, int width, int height, int maxTextureSize)
53 , m_tiles(maxTextureSize, width, height, true)
54 , m_tileTextureIds(tileTextureIds)
60 for (unsigned int i = 0; i < m_tileTextureIds->size(); i++)
61 m_context->deleteTexture(m_tileTextureIds->at(i));
64 static void convertFormat(GraphicsContext3D* context, Texture::Format format, unsigned int* glFormat, unsigned int* glType, bool* swizzle)
69 *glFormat = GraphicsContext3D::RGBA;
70 *glType = GraphicsContext3D::UNSIGNED_BYTE;
73 if (context->getExtensions()->supports("GL_EXT_texture_format_BGRA8888")) {
74 *glFormat = Extensions3D::BGRA_EXT;
75 *glType = GraphicsContext3D::UNSIGNED_BYTE;
77 *glFormat = GraphicsContext3D::RGBA;
78 *glType = GraphicsContext3D::UNSIGNED_BYTE;
88 PassRefPtr<Texture> Texture::create(GraphicsContext3D* context, Format format, int width, int height)
90 int maxTextureSize = 0;
91 context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &maxTextureSize);
92 TilingData tiling(maxTextureSize, width, height, true);
93 int numTiles = tiling.numTiles();
95 OwnPtr<Vector<unsigned int> > textureIds = adoptPtr(new Vector<unsigned int>(numTiles));
96 textureIds->fill(0, numTiles);
98 for (int i = 0; i < numTiles; i++) {
99 int textureId = context->createTexture();
101 for (int i = 0; i < numTiles; i++)
102 context->deleteTexture(textureIds->at(i));
105 textureIds->at(i) = textureId;
107 IntRect tileBoundsWithBorder = tiling.tileBoundsWithBorder(i);
109 unsigned int glFormat = 0;
110 unsigned int glType = 0;
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);
119 return adoptRef(new Texture(context, textureIds.release(), format, width, height, maxTextureSize));
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)
125 uint32_t* srcOffset = src + srcX + srcY * srcStride;
127 if (!swizzle && width == srcStride)
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);
140 for (int y = 0; y < height; ++y) {
141 memcpy(dst + y * width, srcOffset + y * srcStride, 4 * width);
147 void Texture::load(void* pixels)
149 updateSubRect(pixels, IntRect(0, 0, m_tiles.totalSizeX(), m_tiles.totalSizeY()));
152 void Texture::updateSubRect(void* pixels, const IntRect& updateRect)
154 IntRect updateRectSanitized(updateRect);
155 updateRectSanitized.intersect(IntRect(0, 0, m_tiles.totalSizeX(), m_tiles.totalSizeY()));
157 uint32_t* pixels32 = static_cast<uint32_t*>(pixels);
158 unsigned int glFormat = 0;
159 unsigned int glType = 0;
161 convertFormat(m_context, m_format, &glFormat, &glType, &swizzle);
163 ASSERT(glFormat == GraphicsContext3D::RGBA && glType == GraphicsContext3D::UNSIGNED_BYTE);
164 // FIXME: This could use PBO's to save doing an extra copy here.
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]);
171 for (int tile = 0; tile < m_tiles.numTiles(); tile++) {
172 // Intersect with tile
173 IntRect tileBoundsWithBorder = m_tiles.tileBoundsWithBorder(tile);
175 IntRect updateRectIntersected = updateRectSanitized;
176 updateRectIntersected.intersect(tileBoundsWithBorder);
178 IntRect dstRect = updateRectIntersected;
179 dstRect.moveBy(-tileBoundsWithBorder.location());
181 if (updateRectIntersected.isEmpty())
184 // Copy sub rectangle out of larger pixel data
185 uint32_t* uploadBuff = 0;
187 uploadBuff = copySubRect<true>(
188 pixels32, updateRectIntersected.x(), updateRectIntersected.y(),
189 tempBuff.get(), updateRectIntersected.width(), updateRectIntersected.height(), m_tiles.totalSizeX());
191 uploadBuff = copySubRect<false>(
192 pixels32, updateRectIntersected.x(), updateRectIntersected.y(),
193 tempBuff.get(), updateRectIntersected.width(), updateRectIntersected.height(), m_tiles.totalSizeX());
196 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_tileTextureIds->at(tile));
197 m_context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0 /* level */,
200 updateRectIntersected.width(),
201 updateRectIntersected.height(), glFormat, glType, uploadBuff);
205 void Texture::bindTile(int tile)
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);