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#if ENABLE(WEBGL) 29 30#include "WebGLTexture.h" 31 32#include "WebGLContextGroup.h" 33#include "WebGLFramebuffer.h" 34#include "WebGLRenderingContext.h" 35 36namespace WebCore { 37 38PassRefPtr<WebGLTexture> WebGLTexture::create(WebGLRenderingContext* ctx) 39{ 40 return adoptRef(new WebGLTexture(ctx)); 41} 42 43WebGLTexture::WebGLTexture(WebGLRenderingContext* ctx) 44 : WebGLSharedObject(ctx) 45 , m_target(0) 46 , m_minFilter(GraphicsContext3D::NEAREST_MIPMAP_LINEAR) 47 , m_magFilter(GraphicsContext3D::LINEAR) 48 , m_wrapS(GraphicsContext3D::REPEAT) 49 , m_wrapT(GraphicsContext3D::REPEAT) 50 , m_isNPOT(false) 51 , m_isComplete(false) 52 , m_needToUseBlackTexture(false) 53{ 54 setObject(ctx->graphicsContext3D()->createTexture()); 55} 56 57WebGLTexture::~WebGLTexture() 58{ 59 deleteObject(0); 60} 61 62void WebGLTexture::setTarget(GC3Denum target, GC3Dint 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 GraphicsContext3D::TEXTURE_2D: 71 m_target = target; 72 m_info.resize(1); 73 m_info[0].resize(maxLevel); 74 break; 75 case GraphicsContext3D::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 84void WebGLTexture::setParameteri(GC3Denum pname, GC3Dint param) 85{ 86 if (!object() || !m_target) 87 return; 88 switch (pname) { 89 case GraphicsContext3D::TEXTURE_MIN_FILTER: 90 switch (param) { 91 case GraphicsContext3D::NEAREST: 92 case GraphicsContext3D::LINEAR: 93 case GraphicsContext3D::NEAREST_MIPMAP_NEAREST: 94 case GraphicsContext3D::LINEAR_MIPMAP_NEAREST: 95 case GraphicsContext3D::NEAREST_MIPMAP_LINEAR: 96 case GraphicsContext3D::LINEAR_MIPMAP_LINEAR: 97 m_minFilter = param; 98 break; 99 } 100 break; 101 case GraphicsContext3D::TEXTURE_MAG_FILTER: 102 switch (param) { 103 case GraphicsContext3D::NEAREST: 104 case GraphicsContext3D::LINEAR: 105 m_magFilter = param; 106 break; 107 } 108 break; 109 case GraphicsContext3D::TEXTURE_WRAP_S: 110 switch (param) { 111 case GraphicsContext3D::CLAMP_TO_EDGE: 112 case GraphicsContext3D::MIRRORED_REPEAT: 113 case GraphicsContext3D::REPEAT: 114 m_wrapS = param; 115 break; 116 } 117 break; 118 case GraphicsContext3D::TEXTURE_WRAP_T: 119 switch (param) { 120 case GraphicsContext3D::CLAMP_TO_EDGE: 121 case GraphicsContext3D::MIRRORED_REPEAT: 122 case GraphicsContext3D::REPEAT: 123 m_wrapT = param; 124 break; 125 } 126 break; 127 default: 128 return; 129 } 130 update(); 131} 132 133void WebGLTexture::setParameterf(GC3Denum pname, GC3Dfloat param) 134{ 135 if (!object() || !m_target) 136 return; 137 GC3Dint iparam = static_cast<GC3Dint>(param); 138 setParameteri(pname, iparam); 139} 140 141void WebGLTexture::setLevelInfo(GC3Denum target, GC3Dint level, GC3Denum internalFormat, GC3Dsizei width, GC3Dsizei height, GC3Denum 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 154void 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 GC3Dsizei width = info0.width; 164 GC3Dsizei height = info0.height; 165 GC3Dint levelCount = computeLevelCount(width, height); 166 for (GC3Dint 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 178GC3Denum WebGLTexture::getInternalFormat(GC3Denum target, GC3Dint level) const 179{ 180 const LevelInfo* info = getLevelInfo(target, level); 181 if (!info) 182 return 0; 183 return info->internalFormat; 184} 185 186GC3Denum WebGLTexture::getType(GC3Denum target, GC3Dint level) const 187{ 188 const LevelInfo* info = getLevelInfo(target, level); 189 if (!info) 190 return 0; 191 return info->type; 192} 193 194GC3Dsizei WebGLTexture::getWidth(GC3Denum target, GC3Dint level) const 195{ 196 const LevelInfo* info = getLevelInfo(target, level); 197 if (!info) 198 return 0; 199 return info->width; 200} 201 202GC3Dsizei WebGLTexture::getHeight(GC3Denum target, GC3Dint level) const 203{ 204 const LevelInfo* info = getLevelInfo(target, level); 205 if (!info) 206 return 0; 207 return info->height; 208} 209 210bool WebGLTexture::isValid(GC3Denum target, GC3Dint level) const 211{ 212 const LevelInfo* info = getLevelInfo(target, level); 213 if (!info) 214 return 0; 215 return info->valid; 216} 217 218bool WebGLTexture::isNPOT(GC3Dsizei width, GC3Dsizei 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 228bool WebGLTexture::isNPOT() const 229{ 230 if (!object()) 231 return false; 232 return m_isNPOT; 233} 234 235bool WebGLTexture::needToUseBlackTexture() const 236{ 237 if (!object()) 238 return false; 239 return m_needToUseBlackTexture; 240} 241 242void WebGLTexture::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject object) 243{ 244 context3d->deleteTexture(object); 245} 246 247int WebGLTexture::mapTargetToIndex(GC3Denum target) const 248{ 249 if (m_target == GraphicsContext3D::TEXTURE_2D) { 250 if (target == GraphicsContext3D::TEXTURE_2D) 251 return 0; 252 } else if (m_target == GraphicsContext3D::TEXTURE_CUBE_MAP) { 253 switch (target) { 254 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X: 255 return 0; 256 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X: 257 return 1; 258 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y: 259 return 2; 260 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y: 261 return 3; 262 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z: 263 return 4; 264 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z: 265 return 5; 266 } 267 } 268 return -1; 269} 270 271bool WebGLTexture::canGenerateMipmaps() 272{ 273 if (isNPOT()) 274 return false; 275 const LevelInfo& first = m_info[0][0]; 276 for (size_t ii = 0; ii < m_info.size(); ++ii) { 277 const LevelInfo& info = m_info[ii][0]; 278 if (!info.valid 279 || info.width != first.width || info.height != first.height 280 || info.internalFormat != first.internalFormat || info.type != first.type) 281 return false; 282 } 283 return true; 284} 285 286GC3Dint WebGLTexture::computeLevelCount(GC3Dsizei width, GC3Dsizei height) 287{ 288 // return 1 + log2Floor(std::max(width, height)); 289 GC3Dsizei n = std::max(width, height); 290 if (n <= 0) 291 return 0; 292 GC3Dint log = 0; 293 GC3Dsizei value = n; 294 for (int ii = 4; ii >= 0; --ii) { 295 int shift = (1 << ii); 296 GC3Dsizei x = (value >> shift); 297 if (x) { 298 value = x; 299 log += shift; 300 } 301 } 302 ASSERT(value == 1); 303 return log + 1; 304} 305 306void WebGLTexture::update() 307{ 308 m_isNPOT = false; 309 for (size_t ii = 0; ii < m_info.size(); ++ii) { 310 if (isNPOT(m_info[ii][0].width, m_info[ii][0].height)) { 311 m_isNPOT = true; 312 break; 313 } 314 } 315 m_isComplete = true; 316 const LevelInfo& first = m_info[0][0]; 317 GC3Dint levelCount = computeLevelCount(first.width, first.height); 318 if (levelCount < 1) 319 m_isComplete = false; 320 else { 321 for (size_t ii = 0; ii < m_info.size() && m_isComplete; ++ii) { 322 const LevelInfo& info0 = m_info[ii][0]; 323 if (!info0.valid 324 || info0.width != first.width || info0.height != first.height 325 || info0.internalFormat != first.internalFormat || info0.type != first.type) { 326 m_isComplete = false; 327 break; 328 } 329 GC3Dsizei width = info0.width; 330 GC3Dsizei height = info0.height; 331 for (GC3Dint level = 1; level < levelCount; ++level) { 332 width = std::max(1, width >> 1); 333 height = std::max(1, height >> 1); 334 const LevelInfo& info = m_info[ii][level]; 335 if (!info.valid 336 || info.width != width || info.height != height 337 || info.internalFormat != info0.internalFormat || info.type != info0.type) { 338 m_isComplete = false; 339 break; 340 } 341 342 } 343 } 344 } 345 346 m_needToUseBlackTexture = false; 347 // NPOT 348 if (m_isNPOT && ((m_minFilter != GraphicsContext3D::NEAREST && m_minFilter != GraphicsContext3D::LINEAR) 349 || m_wrapS != GraphicsContext3D::CLAMP_TO_EDGE || m_wrapT != GraphicsContext3D::CLAMP_TO_EDGE)) 350 m_needToUseBlackTexture = true; 351 // Completeness 352 if (!m_isComplete && m_minFilter != GraphicsContext3D::NEAREST && m_minFilter != GraphicsContext3D::LINEAR) 353 m_needToUseBlackTexture = true; 354} 355 356const WebGLTexture::LevelInfo* WebGLTexture::getLevelInfo(GC3Denum target, GC3Dint level) const 357{ 358 if (!object() || !m_target) 359 return 0; 360 int targetIndex = mapTargetToIndex(target); 361 if (targetIndex < 0 || targetIndex >= static_cast<int>(m_info.size())) 362 return 0; 363 if (level < 0 || level >= static_cast<GC3Dint>(m_info[targetIndex].size())) 364 return 0; 365 return &(m_info[targetIndex][level]); 366} 367 368} 369 370#endif // ENABLE(WEBGL) 371