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