Replace WTF::move with WTFMove
[WebKit-https.git] / 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 #include <algorithm>
42 #include <wtf/StdLibExtras.h>
43
44 namespace WebCore {
45
46 Texture::Texture(GraphicsContext3D* context, std::unique_ptr<Vector<unsigned>> 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(WTFMove(tileTextureIds))
51 {
52 }
53
54 Texture::~Texture()
55 {
56     for (unsigned int i = 0; i < m_tileTextureIds->size(); i++)
57         m_context->deleteTexture(m_tileTextureIds->at(i));
58 }
59
60 static 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
84 PassRefPtr<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     auto textureIds = std::make_unique<Vector<unsigned>>(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, WTFMove(textureIds), format, width, height, maxTextureSize));
124 }
125
126 template <bool swizzle>
127 static 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
151 void Texture::load(void* pixels)
152 {
153     updateSubRect(pixels, IntRect(0, 0, m_tiles.totalSize().width(), m_tiles.totalSize().height()));
154 }
155
156 void 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
212 void 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