Upstream version 7.36.149.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 WebCore {
33
34 PassRefPtr<WebGLTexture> WebGLTexture::create(WebGLRenderingContextBase* ctx)
35 {
36     return adoptRef(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     deleteObject(0);
60 }
61
62 void WebGLTexture::setTarget(GLenum target, GLint maxLevel)
63 {
64     if (!object())
65         return;
66     // Target is finalized the first time bindTexture() is called.
67     if (m_target)
68         return;
69     switch (target) {
70     case GL_TEXTURE_2D:
71         m_target = target;
72         m_info.resize(1);
73         m_info[0].resize(maxLevel);
74         break;
75     case GL_TEXTURE_CUBE_MAP:
76         m_target = target;
77         m_info.resize(6);
78         for (int ii = 0; ii < 6; ++ii)
79             m_info[ii].resize(maxLevel);
80         break;
81     }
82 }
83
84 void WebGLTexture::setParameteri(GLenum pname, GLint param)
85 {
86     if (!object() || !m_target)
87         return;
88     switch (pname) {
89     case GL_TEXTURE_MIN_FILTER:
90         switch (param) {
91         case GL_NEAREST:
92         case GL_LINEAR:
93         case GL_NEAREST_MIPMAP_NEAREST:
94         case GL_LINEAR_MIPMAP_NEAREST:
95         case GL_NEAREST_MIPMAP_LINEAR:
96         case GL_LINEAR_MIPMAP_LINEAR:
97             m_minFilter = param;
98             break;
99         }
100         break;
101     case GL_TEXTURE_MAG_FILTER:
102         switch (param) {
103         case GL_NEAREST:
104         case GL_LINEAR:
105             m_magFilter = param;
106             break;
107         }
108         break;
109     case GL_TEXTURE_WRAP_S:
110         switch (param) {
111         case GL_CLAMP_TO_EDGE:
112         case GL_MIRRORED_REPEAT:
113         case GL_REPEAT:
114             m_wrapS = param;
115             break;
116         }
117         break;
118     case GL_TEXTURE_WRAP_T:
119         switch (param) {
120         case GL_CLAMP_TO_EDGE:
121         case GL_MIRRORED_REPEAT:
122         case GL_REPEAT:
123             m_wrapT = param;
124             break;
125         }
126         break;
127     default:
128         return;
129     }
130     update();
131 }
132
133 void WebGLTexture::setParameterf(GLenum pname, GLfloat param)
134 {
135     if (!object() || !m_target)
136         return;
137     GLint iparam = static_cast<GLint>(param);
138     setParameteri(pname, iparam);
139 }
140
141 void WebGLTexture::setLevelInfo(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum type)
142 {
143     if (!object() || !m_target)
144         return;
145     // We assume level, internalFormat, width, height, and type have all been
146     // validated already.
147     int index = mapTargetToIndex(target);
148     if (index < 0)
149         return;
150     m_info[index][level].setInfo(internalFormat, width, height, type);
151     update();
152 }
153
154 void WebGLTexture::generateMipmapLevelInfo()
155 {
156     if (!object() || !m_target)
157         return;
158     if (!canGenerateMipmaps())
159         return;
160     if (!m_isComplete) {
161         for (size_t ii = 0; ii < m_info.size(); ++ii) {
162             const LevelInfo& info0 = m_info[ii][0];
163             GLsizei width = info0.width;
164             GLsizei height = info0.height;
165             GLint levelCount = computeLevelCount(width, height);
166             for (GLint level = 1; level < levelCount; ++level) {
167                 width = std::max(1, width >> 1);
168                 height = std::max(1, height >> 1);
169                 LevelInfo& info = m_info[ii][level];
170                 info.setInfo(info0.internalFormat, width, height, info0.type);
171             }
172         }
173         m_isComplete = true;
174     }
175     m_needToUseBlackTexture = false;
176 }
177
178 GLenum WebGLTexture::getInternalFormat(GLenum target, GLint level) const
179 {
180     const LevelInfo* info = getLevelInfo(target, level);
181     if (!info)
182         return 0;
183     return info->internalFormat;
184 }
185
186 GLenum WebGLTexture::getType(GLenum target, GLint level) const
187 {
188     const LevelInfo* info = getLevelInfo(target, level);
189     if (!info)
190         return 0;
191     return info->type;
192 }
193
194 GLsizei WebGLTexture::getWidth(GLenum target, GLint level) const
195 {
196     const LevelInfo* info = getLevelInfo(target, level);
197     if (!info)
198         return 0;
199     return info->width;
200 }
201
202 GLsizei WebGLTexture::getHeight(GLenum target, GLint level) const
203 {
204     const LevelInfo* info = getLevelInfo(target, level);
205     if (!info)
206         return 0;
207     return info->height;
208 }
209
210 bool WebGLTexture::isValid(GLenum target, GLint level) const
211 {
212     const LevelInfo* info = getLevelInfo(target, level);
213     if (!info)
214         return 0;
215     return info->valid;
216 }
217
218 bool WebGLTexture::isNPOT(GLsizei width, GLsizei height)
219 {
220     ASSERT(width >= 0 && height >= 0);
221     if (!width || !height)
222         return false;
223     if ((width & (width - 1)) || (height & (height - 1)))
224         return true;
225     return false;
226 }
227
228 bool WebGLTexture::isNPOT() const
229 {
230     if (!object())
231         return false;
232     return m_isNPOT;
233 }
234
235 bool WebGLTexture::needToUseBlackTexture(TextureExtensionFlag flag) const
236 {
237     if (!object())
238         return false;
239     if (m_needToUseBlackTexture)
240         return true;
241     if ((m_isFloatType && !(flag & TextureFloatLinearExtensionEnabled)) || (m_isHalfFloatType && !(flag && TextureHalfFloatLinearExtensionEnabled))) {
242         if (m_magFilter != GL_NEAREST || (m_minFilter != GL_NEAREST && m_minFilter != GL_NEAREST_MIPMAP_NEAREST))
243             return true;
244     }
245     return false;
246 }
247
248 void WebGLTexture::deleteObjectImpl(blink::WebGraphicsContext3D* context3d, Platform3DObject object)
249 {
250     context3d->deleteTexture(object);
251 }
252
253 int WebGLTexture::mapTargetToIndex(GLenum target) const
254 {
255     if (m_target == GL_TEXTURE_2D) {
256         if (target == GL_TEXTURE_2D)
257             return 0;
258     } else if (m_target == GL_TEXTURE_CUBE_MAP) {
259         switch (target) {
260         case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
261             return 0;
262         case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
263             return 1;
264         case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
265             return 2;
266         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
267             return 3;
268         case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
269             return 4;
270         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
271             return 5;
272         }
273     }
274     return -1;
275 }
276
277 bool WebGLTexture::canGenerateMipmaps()
278 {
279     if (isNPOT())
280         return false;
281     const LevelInfo& first = m_info[0][0];
282     for (size_t ii = 0; ii < m_info.size(); ++ii) {
283         const LevelInfo& info = m_info[ii][0];
284         if (!info.valid
285             || info.width != first.width || info.height != first.height
286             || info.internalFormat != first.internalFormat || info.type != first.type
287             || (m_info.size() > 1 && !m_isCubeComplete))
288             return false;
289     }
290     return true;
291 }
292
293 GLint WebGLTexture::computeLevelCount(GLsizei width, GLsizei height)
294 {
295     // return 1 + log2Floor(std::max(width, height));
296     GLsizei n = std::max(width, height);
297     if (n <= 0)
298         return 0;
299     GLint log = 0;
300     GLsizei value = n;
301     for (int ii = 4; ii >= 0; --ii) {
302         int shift = (1 << ii);
303         GLsizei x = (value >> shift);
304         if (x) {
305             value = x;
306             log += shift;
307         }
308     }
309     ASSERT(value == 1);
310     return log + 1;
311 }
312
313 void WebGLTexture::update()
314 {
315     m_isNPOT = false;
316     for (size_t ii = 0; ii < m_info.size(); ++ii) {
317         if (isNPOT(m_info[ii][0].width, m_info[ii][0].height)) {
318             m_isNPOT = true;
319             break;
320         }
321     }
322     m_isComplete = true;
323     m_isCubeComplete = true;
324     const LevelInfo& first = m_info[0][0];
325     GLint levelCount = computeLevelCount(first.width, first.height);
326     if (levelCount < 1)
327         m_isComplete = false;
328     else {
329         for (size_t ii = 0; ii < m_info.size() && m_isComplete; ++ii) {
330             const LevelInfo& info0 = m_info[ii][0];
331             if (!info0.valid
332                 || info0.width != first.width || info0.height != first.height
333                 || info0.internalFormat != first.internalFormat || info0.type != first.type
334                 || (m_info.size() > 1 && info0.width != info0.height)) {
335                 if (m_info.size() > 1)
336                     m_isCubeComplete = false;
337                 m_isComplete = false;
338                 break;
339             }
340             GLsizei width = info0.width;
341             GLsizei height = info0.height;
342             for (GLint level = 1; level < levelCount; ++level) {
343                 width = std::max(1, width >> 1);
344                 height = std::max(1, height >> 1);
345                 const LevelInfo& info = m_info[ii][level];
346                 if (!info.valid
347                     || info.width != width || info.height != height
348                     || info.internalFormat != info0.internalFormat || info.type != info0.type) {
349                     m_isComplete = false;
350                     break;
351                 }
352
353             }
354         }
355     }
356     m_isFloatType = m_info[0][0].type == GL_FLOAT;
357     m_isHalfFloatType = m_info[0][0].type == GL_HALF_FLOAT_OES;
358
359     m_needToUseBlackTexture = false;
360     // NPOT
361     if (m_isNPOT && ((m_minFilter != GL_NEAREST && m_minFilter != GL_LINEAR)
362         || m_wrapS != GL_CLAMP_TO_EDGE || m_wrapT != GL_CLAMP_TO_EDGE))
363         m_needToUseBlackTexture = true;
364     // If it is a Cube texture, check Cube Completeness first
365     if (m_info.size() > 1 && !m_isCubeComplete)
366         m_needToUseBlackTexture = true;
367     // Completeness
368     if (!m_isComplete && m_minFilter != GL_NEAREST && m_minFilter != GL_LINEAR)
369         m_needToUseBlackTexture = true;
370 }
371
372 const WebGLTexture::LevelInfo* WebGLTexture::getLevelInfo(GLenum target, GLint level) const
373 {
374     if (!object() || !m_target)
375         return 0;
376     int targetIndex = mapTargetToIndex(target);
377     if (targetIndex < 0 || targetIndex >= static_cast<int>(m_info.size()))
378         return 0;
379     if (level < 0 || level >= static_cast<GLint>(m_info[targetIndex].size()))
380         return 0;
381     return &(m_info[targetIndex][level]);
382 }
383
384 }