Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / html / canvas / WebGLTexture.cpp
1 /*
2  * Copyright (C) 2009 Apple 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
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #include "core/html/canvas/WebGLTexture.h"
29
30 #include "core/html/canvas/WebGLRenderingContextBase.h"
31
32 namespace blink {
33
34 PassRefPtrWillBeRawPtr<WebGLTexture> WebGLTexture::create(WebGLRenderingContextBase* ctx)
35 {
36     return adoptRefWillBeNoop(new WebGLTexture(ctx));
37 }
38
39 WebGLTexture::WebGLTexture(WebGLRenderingContextBase* ctx)
40     : WebGLSharedObject(ctx)
41     , m_target(0)
42     , m_minFilter(GL_NEAREST_MIPMAP_LINEAR)
43     , m_magFilter(GL_LINEAR)
44     , m_wrapS(GL_REPEAT)
45     , m_wrapT(GL_REPEAT)
46     , m_isNPOT(false)
47     , m_isCubeComplete(false)
48     , m_isComplete(false)
49     , m_needToUseBlackTexture(false)
50     , m_isFloatType(false)
51     , m_isHalfFloatType(false)
52 {
53     ScriptWrappable::init(this);
54     setObject(ctx->webContext()->createTexture());
55 }
56
57 WebGLTexture::~WebGLTexture()
58 {
59     // Always perform detach here to ensure that platform object
60     // deletion happens with Oilpan enabled. It keeps the code regular
61     // to do it with or without Oilpan enabled.
62     //
63     // See comment in WebGLBuffer's destructor for additional
64     // information on why this is done for WebGLSharedObject-derived
65     // objects.
66     detachAndDeleteObject();
67 }
68
69 void WebGLTexture::setTarget(GLenum target, GLint maxLevel)
70 {
71     if (!object())
72         return;
73     // Target is finalized the first time bindTexture() is called.
74     if (m_target)
75         return;
76     switch (target) {
77     case GL_TEXTURE_2D:
78         m_target = target;
79         m_info.resize(1);
80         m_info[0].resize(maxLevel);
81         break;
82     case GL_TEXTURE_CUBE_MAP:
83         m_target = target;
84         m_info.resize(6);
85         for (int ii = 0; ii < 6; ++ii)
86             m_info[ii].resize(maxLevel);
87         break;
88     }
89 }
90
91 void WebGLTexture::setParameteri(GLenum pname, GLint param)
92 {
93     if (!object() || !m_target)
94         return;
95     switch (pname) {
96     case GL_TEXTURE_MIN_FILTER:
97         switch (param) {
98         case GL_NEAREST:
99         case GL_LINEAR:
100         case GL_NEAREST_MIPMAP_NEAREST:
101         case GL_LINEAR_MIPMAP_NEAREST:
102         case GL_NEAREST_MIPMAP_LINEAR:
103         case GL_LINEAR_MIPMAP_LINEAR:
104             m_minFilter = param;
105             break;
106         }
107         break;
108     case GL_TEXTURE_MAG_FILTER:
109         switch (param) {
110         case GL_NEAREST:
111         case GL_LINEAR:
112             m_magFilter = param;
113             break;
114         }
115         break;
116     case GL_TEXTURE_WRAP_S:
117         switch (param) {
118         case GL_CLAMP_TO_EDGE:
119         case GL_MIRRORED_REPEAT:
120         case GL_REPEAT:
121             m_wrapS = param;
122             break;
123         }
124         break;
125     case GL_TEXTURE_WRAP_T:
126         switch (param) {
127         case GL_CLAMP_TO_EDGE:
128         case GL_MIRRORED_REPEAT:
129         case GL_REPEAT:
130             m_wrapT = param;
131             break;
132         }
133         break;
134     default:
135         return;
136     }
137     update();
138 }
139
140 void WebGLTexture::setParameterf(GLenum pname, GLfloat param)
141 {
142     if (!object() || !m_target)
143         return;
144     GLint iparam = static_cast<GLint>(param);
145     setParameteri(pname, iparam);
146 }
147
148 void WebGLTexture::setLevelInfo(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)
149 {
150     if (!object() || !m_target)
151         return;
152     // We assume level, internalFormat, width, height, and type have all been
153     // validated already.
154     int index = mapTargetToIndex(target);
155     if (index < 0)
156         return;
157     m_info[index][level].setInfo(internalFormat, width, height, type);
158     update();
159 }
160
161 void WebGLTexture::generateMipmapLevelInfo()
162 {
163     if (!object() || !m_target)
164         return;
165     if (!canGenerateMipmaps())
166         return;
167     if (!m_isComplete) {
168         for (size_t ii = 0; ii < m_info.size(); ++ii) {
169             const LevelInfo& info0 = m_info[ii][0];
170             GLsizei width = info0.width;
171             GLsizei height = info0.height;
172             GLint levelCount = computeLevelCount(width, height);
173             for (GLint level = 1; level < levelCount; ++level) {
174                 width = std::max(1, width >> 1);
175                 height = std::max(1, height >> 1);
176                 LevelInfo& info = m_info[ii][level];
177                 info.setInfo(info0.internalFormat, width, height, info0.type);
178             }
179         }
180         m_isComplete = true;
181     }
182     m_needToUseBlackTexture = false;
183 }
184
185 GLenum WebGLTexture::getInternalFormat(GLenum target, GLint level) const
186 {
187     const LevelInfo* info = getLevelInfo(target, level);
188     if (!info)
189         return 0;
190     return info->internalFormat;
191 }
192
193 GLenum WebGLTexture::getType(GLenum target, GLint level) const
194 {
195     const LevelInfo* info = getLevelInfo(target, level);
196     if (!info)
197         return 0;
198     return info->type;
199 }
200
201 GLsizei WebGLTexture::getWidth(GLenum target, GLint level) const
202 {
203     const LevelInfo* info = getLevelInfo(target, level);
204     if (!info)
205         return 0;
206     return info->width;
207 }
208
209 GLsizei WebGLTexture::getHeight(GLenum target, GLint level) const
210 {
211     const LevelInfo* info = getLevelInfo(target, level);
212     if (!info)
213         return 0;
214     return info->height;
215 }
216
217 bool WebGLTexture::isValid(GLenum target, GLint level) const
218 {
219     const LevelInfo* info = getLevelInfo(target, level);
220     if (!info)
221         return 0;
222     return info->valid;
223 }
224
225 bool WebGLTexture::isNPOT(GLsizei width, GLsizei height)
226 {
227     ASSERT(width >= 0 && height >= 0);
228     if (!width || !height)
229         return false;
230     if ((width & (width - 1)) || (height & (height - 1)))
231         return true;
232     return false;
233 }
234
235 bool WebGLTexture::isNPOT() const
236 {
237     if (!object())
238         return false;
239     return m_isNPOT;
240 }
241
242 bool WebGLTexture::needToUseBlackTexture(TextureExtensionFlag flag) const
243 {
244     if (!object())
245         return false;
246     if (m_needToUseBlackTexture)
247         return true;
248     if ((m_isFloatType && !(flag & TextureFloatLinearExtensionEnabled)) || (m_isHalfFloatType && !(flag && TextureHalfFloatLinearExtensionEnabled))) {
249         if (m_magFilter != GL_NEAREST || (m_minFilter != GL_NEAREST && m_minFilter != GL_NEAREST_MIPMAP_NEAREST))
250             return true;
251     }
252     return false;
253 }
254
255 void WebGLTexture::deleteObjectImpl(blink::WebGraphicsContext3D* context3d, Platform3DObject object)
256 {
257     context3d->deleteTexture(object);
258 }
259
260 int WebGLTexture::mapTargetToIndex(GLenum target) const
261 {
262     if (m_target == GL_TEXTURE_2D) {
263         if (target == GL_TEXTURE_2D)
264             return 0;
265     } else if (m_target == GL_TEXTURE_CUBE_MAP) {
266         switch (target) {
267         case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
268             return 0;
269         case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
270             return 1;
271         case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
272             return 2;
273         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
274             return 3;
275         case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
276             return 4;
277         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
278             return 5;
279         }
280     }
281     return -1;
282 }
283
284 bool WebGLTexture::canGenerateMipmaps()
285 {
286     if (isNPOT())
287         return false;
288     const LevelInfo& first = m_info[0][0];
289     for (size_t ii = 0; ii < m_info.size(); ++ii) {
290         const LevelInfo& info = m_info[ii][0];
291         if (!info.valid
292             || info.width != first.width || info.height != first.height
293             || info.internalFormat != first.internalFormat || info.type != first.type
294             || (m_info.size() > 1 && !m_isCubeComplete))
295             return false;
296     }
297     return true;
298 }
299
300 GLint WebGLTexture::computeLevelCount(GLsizei width, GLsizei height)
301 {
302     // return 1 + log2Floor(std::max(width, height));
303     GLsizei n = std::max(width, height);
304     if (n <= 0)
305         return 0;
306     GLint log = 0;
307     GLsizei value = n;
308     for (int ii = 4; ii >= 0; --ii) {
309         int shift = (1 << ii);
310         GLsizei x = (value >> shift);
311         if (x) {
312             value = x;
313             log += shift;
314         }
315     }
316     ASSERT(value == 1);
317     return log + 1;
318 }
319
320 void WebGLTexture::update()
321 {
322     m_isNPOT = false;
323     for (size_t ii = 0; ii < m_info.size(); ++ii) {
324         if (isNPOT(m_info[ii][0].width, m_info[ii][0].height)) {
325             m_isNPOT = true;
326             break;
327         }
328     }
329     m_isComplete = true;
330     m_isCubeComplete = true;
331     const LevelInfo& first = m_info[0][0];
332     GLint levelCount = computeLevelCount(first.width, first.height);
333     if (levelCount < 1)
334         m_isComplete = false;
335     else {
336         for (size_t ii = 0; ii < m_info.size() && m_isComplete; ++ii) {
337             const LevelInfo& info0 = m_info[ii][0];
338             if (!info0.valid
339                 || info0.width != first.width || info0.height != first.height
340                 || info0.internalFormat != first.internalFormat || info0.type != first.type
341                 || (m_info.size() > 1 && info0.width != info0.height)) {
342                 if (m_info.size() > 1)
343                     m_isCubeComplete = false;
344                 m_isComplete = false;
345                 break;
346             }
347             GLsizei width = info0.width;
348             GLsizei height = info0.height;
349             for (GLint level = 1; level < levelCount; ++level) {
350                 width = std::max(1, width >> 1);
351                 height = std::max(1, height >> 1);
352                 const LevelInfo& info = m_info[ii][level];
353                 if (!info.valid
354                     || info.width != width || info.height != height
355                     || info.internalFormat != info0.internalFormat || info.type != info0.type) {
356                     m_isComplete = false;
357                     break;
358                 }
359
360             }
361         }
362     }
363     m_isFloatType = m_info[0][0].type == GL_FLOAT;
364     m_isHalfFloatType = m_info[0][0].type == GL_HALF_FLOAT_OES;
365
366     m_needToUseBlackTexture = false;
367     // NPOT
368     if (m_isNPOT && ((m_minFilter != GL_NEAREST && m_minFilter != GL_LINEAR)
369         || m_wrapS != GL_CLAMP_TO_EDGE || m_wrapT != GL_CLAMP_TO_EDGE))
370         m_needToUseBlackTexture = true;
371     // If it is a Cube texture, check Cube Completeness first
372     if (m_info.size() > 1 && !m_isCubeComplete)
373         m_needToUseBlackTexture = true;
374     // Completeness
375     if (!m_isComplete && m_minFilter != GL_NEAREST && m_minFilter != GL_LINEAR)
376         m_needToUseBlackTexture = true;
377 }
378
379 const WebGLTexture::LevelInfo* WebGLTexture::getLevelInfo(GLenum target, GLint level) const
380 {
381     if (!object() || !m_target)
382         return 0;
383     int targetIndex = mapTargetToIndex(target);
384     if (targetIndex < 0 || targetIndex >= static_cast<int>(m_info.size()))
385         return 0;
386     if (level < 0 || level >= static_cast<GLint>(m_info[targetIndex].size()))
387         return 0;
388     return &(m_info[targetIndex][level]);
389 }
390
391 }