summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/html/canvas/WebGLTexture.cpp
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/html/canvas/WebGLTexture.cpp
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/html/canvas/WebGLTexture.cpp')
-rw-r--r--Source/WebCore/html/canvas/WebGLTexture.cpp355
1 files changed, 355 insertions, 0 deletions
diff --git a/Source/WebCore/html/canvas/WebGLTexture.cpp b/Source/WebCore/html/canvas/WebGLTexture.cpp
new file mode 100644
index 0000000..2982e51
--- /dev/null
+++ b/Source/WebCore/html/canvas/WebGLTexture.cpp
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "WebGLTexture.h"
+
+#include "WebGLFramebuffer.h"
+#include "WebGLRenderingContext.h"
+
+namespace WebCore {
+
+PassRefPtr<WebGLTexture> WebGLTexture::create(WebGLRenderingContext* ctx)
+{
+ return adoptRef(new WebGLTexture(ctx));
+}
+
+WebGLTexture::WebGLTexture(WebGLRenderingContext* ctx)
+ : WebGLObject(ctx)
+ , m_target(0)
+ , m_minFilter(GraphicsContext3D::NEAREST_MIPMAP_LINEAR)
+ , m_magFilter(GraphicsContext3D::LINEAR)
+ , m_wrapS(GraphicsContext3D::REPEAT)
+ , m_wrapT(GraphicsContext3D::REPEAT)
+ , m_isNPOT(false)
+ , m_isComplete(false)
+ , m_needToUseBlackTexture(false)
+{
+ setObject(context()->graphicsContext3D()->createTexture());
+}
+
+void WebGLTexture::setTarget(unsigned long target, int maxLevel)
+{
+ if (!object())
+ return;
+ // Target is finalized the first time bindTexture() is called.
+ if (m_target)
+ return;
+ switch (target) {
+ case GraphicsContext3D::TEXTURE_2D:
+ m_target = target;
+ m_info.resize(1);
+ m_info[0].resize(maxLevel);
+ break;
+ case GraphicsContext3D::TEXTURE_CUBE_MAP:
+ m_target = target;
+ m_info.resize(6);
+ for (int ii = 0; ii < 6; ++ii)
+ m_info[ii].resize(maxLevel);
+ break;
+ }
+}
+
+void WebGLTexture::setParameteri(unsigned long pname, int param)
+{
+ if (!object() || !m_target)
+ return;
+ switch (pname) {
+ case GraphicsContext3D::TEXTURE_MIN_FILTER:
+ switch (param) {
+ case GraphicsContext3D::NEAREST:
+ case GraphicsContext3D::LINEAR:
+ case GraphicsContext3D::NEAREST_MIPMAP_NEAREST:
+ case GraphicsContext3D::LINEAR_MIPMAP_NEAREST:
+ case GraphicsContext3D::NEAREST_MIPMAP_LINEAR:
+ case GraphicsContext3D::LINEAR_MIPMAP_LINEAR:
+ m_minFilter = param;
+ break;
+ }
+ break;
+ case GraphicsContext3D::TEXTURE_MAG_FILTER:
+ switch (param) {
+ case GraphicsContext3D::NEAREST:
+ case GraphicsContext3D::LINEAR:
+ m_magFilter = param;
+ break;
+ }
+ break;
+ case GraphicsContext3D::TEXTURE_WRAP_S:
+ switch (param) {
+ case GraphicsContext3D::CLAMP_TO_EDGE:
+ case GraphicsContext3D::MIRRORED_REPEAT:
+ case GraphicsContext3D::REPEAT:
+ m_wrapS = param;
+ break;
+ }
+ break;
+ case GraphicsContext3D::TEXTURE_WRAP_T:
+ switch (param) {
+ case GraphicsContext3D::CLAMP_TO_EDGE:
+ case GraphicsContext3D::MIRRORED_REPEAT:
+ case GraphicsContext3D::REPEAT:
+ m_wrapT = param;
+ break;
+ }
+ break;
+ default:
+ return;
+ }
+ update();
+}
+
+void WebGLTexture::setParameterf(unsigned long pname, float param)
+{
+ if (!object() || !m_target)
+ return;
+ int iparam = static_cast<int>(param);
+ setParameteri(pname, iparam);
+}
+
+void WebGLTexture::setLevelInfo(unsigned long target, int level, unsigned long internalFormat, int width, int height, unsigned long type)
+{
+ if (!object() || !m_target)
+ return;
+ // We assume level, internalFormat, width, height, and type have all been
+ // validated already.
+ int index = mapTargetToIndex(target);
+ if (index < 0)
+ return;
+ m_info[index][level].setInfo(internalFormat, width, height, type);
+ update();
+}
+
+void WebGLTexture::generateMipmapLevelInfo()
+{
+ if (!object() || !m_target)
+ return;
+ if (!canGenerateMipmaps())
+ return;
+ if (!m_isComplete) {
+ for (size_t ii = 0; ii < m_info.size(); ++ii) {
+ const LevelInfo& info0 = m_info[ii][0];
+ int width = info0.width;
+ int height = info0.height;
+ int levelCount = computeLevelCount(width, height);
+ for (int level = 1; level < levelCount; ++level) {
+ width = std::max(1, width >> 1);
+ height = std::max(1, height >> 1);
+ LevelInfo& info = m_info[ii][level];
+ info.setInfo(info0.internalFormat, width, height, info0.type);
+ }
+ }
+ m_isComplete = true;
+ }
+ m_needToUseBlackTexture = false;
+}
+
+unsigned long WebGLTexture::getInternalFormat(unsigned long target, int level) const
+{
+ const LevelInfo* info = getLevelInfo(target, level);
+ if (!info)
+ return 0;
+ return info->internalFormat;
+}
+
+unsigned long WebGLTexture::getType(unsigned long target, int level) const
+{
+ const LevelInfo* info = getLevelInfo(target, level);
+ if (!info)
+ return 0;
+ return info->type;
+}
+
+int WebGLTexture::getWidth(unsigned long target, int level) const
+{
+ const LevelInfo* info = getLevelInfo(target, level);
+ if (!info)
+ return 0;
+ return info->width;
+}
+
+int WebGLTexture::getHeight(unsigned long target, int level) const
+{
+ const LevelInfo* info = getLevelInfo(target, level);
+ if (!info)
+ return 0;
+ return info->height;
+}
+
+bool WebGLTexture::isNPOT(unsigned width, unsigned height)
+{
+ if (!width || !height)
+ return false;
+ if ((width & (width - 1)) || (height & (height - 1)))
+ return true;
+ return false;
+}
+
+bool WebGLTexture::isNPOT() const
+{
+ if (!object())
+ return false;
+ return m_isNPOT;
+}
+
+bool WebGLTexture::needToUseBlackTexture() const
+{
+ if (!object())
+ return false;
+ return m_needToUseBlackTexture;
+}
+
+void WebGLTexture::deleteObjectImpl(Platform3DObject object)
+{
+ context()->graphicsContext3D()->deleteTexture(object);
+}
+
+int WebGLTexture::mapTargetToIndex(unsigned long target) const
+{
+ if (m_target == GraphicsContext3D::TEXTURE_2D) {
+ if (target == GraphicsContext3D::TEXTURE_2D)
+ return 0;
+ } else if (m_target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
+ switch (target) {
+ case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
+ return 0;
+ case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
+ return 1;
+ case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
+ return 2;
+ case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ return 3;
+ case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
+ return 4;
+ case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ return 5;
+ }
+ }
+ return -1;
+}
+
+bool WebGLTexture::canGenerateMipmaps()
+{
+ if (isNPOT())
+ return false;
+ const LevelInfo& first = m_info[0][0];
+ for (size_t ii = 0; ii < m_info.size(); ++ii) {
+ const LevelInfo& info = m_info[ii][0];
+ if (!info.valid
+ || info.width != first.width || info.height != first.height
+ || info.internalFormat != first.internalFormat || info.type != first.type)
+ return false;
+ }
+ return true;
+}
+
+int WebGLTexture::computeLevelCount(int width, int height)
+{
+ // return 1 + log2Floor(std::max(width, height));
+ int n = std::max(width, height);
+ if (n <= 0)
+ return 0;
+ int log = 0;
+ int value = n;
+ for (int ii = 4; ii >= 0; --ii) {
+ int shift = (1 << ii);
+ int x = (value >> shift);
+ if (x) {
+ value = x;
+ log += shift;
+ }
+ }
+ ASSERT(value == 1);
+ return log + 1;
+}
+
+void WebGLTexture::update()
+{
+ m_isNPOT = false;
+ for (size_t ii = 0; ii < m_info.size(); ++ii) {
+ if (isNPOT(m_info[ii][0].width, m_info[ii][0].height)) {
+ m_isNPOT = true;
+ break;
+ }
+ }
+ m_isComplete = true;
+ const LevelInfo& first = m_info[0][0];
+ int levelCount = computeLevelCount(first.width, first.height);
+ if (levelCount < 1)
+ m_isComplete = false;
+ else {
+ for (size_t ii = 0; ii < m_info.size() && m_isComplete; ++ii) {
+ const LevelInfo& info0 = m_info[ii][0];
+ if (!info0.valid
+ || info0.width != first.width || info0.height != first.height
+ || info0.internalFormat != first.internalFormat || info0.type != first.type) {
+ m_isComplete = false;
+ break;
+ }
+ int width = info0.width;
+ int height = info0.height;
+ for (int level = 1; level < levelCount; ++level) {
+ width = std::max(1, width >> 1);
+ height = std::max(1, height >> 1);
+ const LevelInfo& info = m_info[ii][level];
+ if (!info.valid
+ || info.width != width || info.height != height
+ || info.internalFormat != info0.internalFormat || info.type != info0.type) {
+ m_isComplete = false;
+ break;
+ }
+
+ }
+ }
+ }
+
+ m_needToUseBlackTexture = false;
+ // NPOT
+ if (m_isNPOT && ((m_minFilter != GraphicsContext3D::NEAREST && m_minFilter != GraphicsContext3D::LINEAR)
+ || m_wrapS != GraphicsContext3D::CLAMP_TO_EDGE || m_wrapT != GraphicsContext3D::CLAMP_TO_EDGE))
+ m_needToUseBlackTexture = true;
+ // Completeness
+ if (!m_isComplete && m_minFilter != GraphicsContext3D::NEAREST && m_minFilter != GraphicsContext3D::LINEAR)
+ m_needToUseBlackTexture = true;
+}
+
+const WebGLTexture::LevelInfo* WebGLTexture::getLevelInfo(unsigned long target, int level) const
+{
+ if (!object() || !m_target)
+ return 0;
+ int targetIndex = mapTargetToIndex(target);
+ if (targetIndex < 0 || targetIndex >= static_cast<int>(m_info.size()))
+ return 0;
+ if (level < 0 || level >= static_cast<int>(m_info[targetIndex].size()))
+ return 0;
+ return &(m_info[targetIndex][level]);
+}
+
+}
+
+#endif // ENABLE(3D_CANVAS)