1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/angle/src/libGLESv2/Texture.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1495 @@ 1.4 +#include "precompiled.h" 1.5 +// 1.6 +// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. 1.7 +// Use of this source code is governed by a BSD-style license that can be 1.8 +// found in the LICENSE file. 1.9 +// 1.10 + 1.11 +// Texture.cpp: Implements the gl::Texture class and its derived classes 1.12 +// Texture2D and TextureCubeMap. Implements GL texture objects and related 1.13 +// functionality. [OpenGL ES 2.0.24] section 3.7 page 63. 1.14 + 1.15 +#include "libGLESv2/Texture.h" 1.16 + 1.17 +#include "libGLESv2/main.h" 1.18 +#include "libGLESv2/mathutil.h" 1.19 +#include "libGLESv2/utilities.h" 1.20 +#include "libGLESv2/renderer/Blit.h" 1.21 +#include "libGLESv2/Renderbuffer.h" 1.22 +#include "libGLESv2/renderer/Image.h" 1.23 +#include "libGLESv2/renderer/Renderer.h" 1.24 +#include "libGLESv2/renderer/TextureStorage.h" 1.25 +#include "libEGL/Surface.h" 1.26 + 1.27 +namespace gl 1.28 +{ 1.29 + 1.30 +Texture::Texture(rx::Renderer *renderer, GLuint id) : RefCountObject(id) 1.31 +{ 1.32 + mRenderer = renderer; 1.33 + 1.34 + mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR; 1.35 + mSamplerState.magFilter = GL_LINEAR; 1.36 + mSamplerState.wrapS = GL_REPEAT; 1.37 + mSamplerState.wrapT = GL_REPEAT; 1.38 + mSamplerState.maxAnisotropy = 1.0f; 1.39 + mSamplerState.lodOffset = 0; 1.40 + mUsage = GL_NONE; 1.41 + 1.42 + mDirtyImages = true; 1.43 + 1.44 + mImmutable = false; 1.45 +} 1.46 + 1.47 +Texture::~Texture() 1.48 +{ 1.49 +} 1.50 + 1.51 +// Returns true on successful filter state update (valid enum parameter) 1.52 +bool Texture::setMinFilter(GLenum filter) 1.53 +{ 1.54 + switch (filter) 1.55 + { 1.56 + case GL_NEAREST: 1.57 + case GL_LINEAR: 1.58 + case GL_NEAREST_MIPMAP_NEAREST: 1.59 + case GL_LINEAR_MIPMAP_NEAREST: 1.60 + case GL_NEAREST_MIPMAP_LINEAR: 1.61 + case GL_LINEAR_MIPMAP_LINEAR: 1.62 + mSamplerState.minFilter = filter; 1.63 + return true; 1.64 + default: 1.65 + return false; 1.66 + } 1.67 +} 1.68 + 1.69 +// Returns true on successful filter state update (valid enum parameter) 1.70 +bool Texture::setMagFilter(GLenum filter) 1.71 +{ 1.72 + switch (filter) 1.73 + { 1.74 + case GL_NEAREST: 1.75 + case GL_LINEAR: 1.76 + mSamplerState.magFilter = filter; 1.77 + return true; 1.78 + default: 1.79 + return false; 1.80 + } 1.81 +} 1.82 + 1.83 +// Returns true on successful wrap state update (valid enum parameter) 1.84 +bool Texture::setWrapS(GLenum wrap) 1.85 +{ 1.86 + switch (wrap) 1.87 + { 1.88 + case GL_REPEAT: 1.89 + case GL_CLAMP_TO_EDGE: 1.90 + case GL_MIRRORED_REPEAT: 1.91 + mSamplerState.wrapS = wrap; 1.92 + return true; 1.93 + default: 1.94 + return false; 1.95 + } 1.96 +} 1.97 + 1.98 +// Returns true on successful wrap state update (valid enum parameter) 1.99 +bool Texture::setWrapT(GLenum wrap) 1.100 +{ 1.101 + switch (wrap) 1.102 + { 1.103 + case GL_REPEAT: 1.104 + case GL_CLAMP_TO_EDGE: 1.105 + case GL_MIRRORED_REPEAT: 1.106 + mSamplerState.wrapT = wrap; 1.107 + return true; 1.108 + default: 1.109 + return false; 1.110 + } 1.111 +} 1.112 + 1.113 +// Returns true on successful max anisotropy update (valid anisotropy value) 1.114 +bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy) 1.115 +{ 1.116 + textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy); 1.117 + if (textureMaxAnisotropy < 1.0f) 1.118 + { 1.119 + return false; 1.120 + } 1.121 + 1.122 + mSamplerState.maxAnisotropy = textureMaxAnisotropy; 1.123 + 1.124 + return true; 1.125 +} 1.126 + 1.127 +// Returns true on successful usage state update (valid enum parameter) 1.128 +bool Texture::setUsage(GLenum usage) 1.129 +{ 1.130 + switch (usage) 1.131 + { 1.132 + case GL_NONE: 1.133 + case GL_FRAMEBUFFER_ATTACHMENT_ANGLE: 1.134 + mUsage = usage; 1.135 + return true; 1.136 + default: 1.137 + return false; 1.138 + } 1.139 +} 1.140 + 1.141 +GLenum Texture::getMinFilter() const 1.142 +{ 1.143 + return mSamplerState.minFilter; 1.144 +} 1.145 + 1.146 +GLenum Texture::getMagFilter() const 1.147 +{ 1.148 + return mSamplerState.magFilter; 1.149 +} 1.150 + 1.151 +GLenum Texture::getWrapS() const 1.152 +{ 1.153 + return mSamplerState.wrapS; 1.154 +} 1.155 + 1.156 +GLenum Texture::getWrapT() const 1.157 +{ 1.158 + return mSamplerState.wrapT; 1.159 +} 1.160 + 1.161 +float Texture::getMaxAnisotropy() const 1.162 +{ 1.163 + return mSamplerState.maxAnisotropy; 1.164 +} 1.165 + 1.166 +int Texture::getLodOffset() 1.167 +{ 1.168 + rx::TextureStorageInterface *texture = getStorage(false); 1.169 + return texture ? texture->getLodOffset() : 0; 1.170 +} 1.171 + 1.172 +void Texture::getSamplerState(SamplerState *sampler) 1.173 +{ 1.174 + *sampler = mSamplerState; 1.175 + sampler->lodOffset = getLodOffset(); 1.176 +} 1.177 + 1.178 +GLenum Texture::getUsage() const 1.179 +{ 1.180 + return mUsage; 1.181 +} 1.182 + 1.183 +bool Texture::isMipmapFiltered() const 1.184 +{ 1.185 + switch (mSamplerState.minFilter) 1.186 + { 1.187 + case GL_NEAREST: 1.188 + case GL_LINEAR: 1.189 + return false; 1.190 + case GL_NEAREST_MIPMAP_NEAREST: 1.191 + case GL_LINEAR_MIPMAP_NEAREST: 1.192 + case GL_NEAREST_MIPMAP_LINEAR: 1.193 + case GL_LINEAR_MIPMAP_LINEAR: 1.194 + return true; 1.195 + default: UNREACHABLE(); 1.196 + return false; 1.197 + } 1.198 +} 1.199 + 1.200 +void Texture::setImage(GLint unpackAlignment, const void *pixels, rx::Image *image) 1.201 +{ 1.202 + if (pixels != NULL) 1.203 + { 1.204 + image->loadData(0, 0, image->getWidth(), image->getHeight(), unpackAlignment, pixels); 1.205 + mDirtyImages = true; 1.206 + } 1.207 +} 1.208 + 1.209 +void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image) 1.210 +{ 1.211 + if (pixels != NULL) 1.212 + { 1.213 + image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels); 1.214 + mDirtyImages = true; 1.215 + } 1.216 +} 1.217 + 1.218 +bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, rx::Image *image) 1.219 +{ 1.220 + if (pixels != NULL) 1.221 + { 1.222 + image->loadData(xoffset, yoffset, width, height, unpackAlignment, pixels); 1.223 + mDirtyImages = true; 1.224 + } 1.225 + 1.226 + return true; 1.227 +} 1.228 + 1.229 +bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image) 1.230 +{ 1.231 + if (pixels != NULL) 1.232 + { 1.233 + image->loadCompressedData(xoffset, yoffset, width, height, pixels); 1.234 + mDirtyImages = true; 1.235 + } 1.236 + 1.237 + return true; 1.238 +} 1.239 + 1.240 +rx::TextureStorageInterface *Texture::getNativeTexture() 1.241 +{ 1.242 + // ensure the underlying texture is created 1.243 + 1.244 + rx::TextureStorageInterface *storage = getStorage(false); 1.245 + if (storage) 1.246 + { 1.247 + updateTexture(); 1.248 + } 1.249 + 1.250 + return storage; 1.251 +} 1.252 + 1.253 +bool Texture::hasDirtyImages() const 1.254 +{ 1.255 + return mDirtyImages; 1.256 +} 1.257 + 1.258 +void Texture::resetDirty() 1.259 +{ 1.260 + mDirtyImages = false; 1.261 +} 1.262 + 1.263 +unsigned int Texture::getTextureSerial() 1.264 +{ 1.265 + rx::TextureStorageInterface *texture = getStorage(false); 1.266 + return texture ? texture->getTextureSerial() : 0; 1.267 +} 1.268 + 1.269 +unsigned int Texture::getRenderTargetSerial(GLenum target) 1.270 +{ 1.271 + rx::TextureStorageInterface *texture = getStorage(true); 1.272 + return texture ? texture->getRenderTargetSerial(target) : 0; 1.273 +} 1.274 + 1.275 +bool Texture::isImmutable() const 1.276 +{ 1.277 + return mImmutable; 1.278 +} 1.279 + 1.280 +GLint Texture::creationLevels(GLsizei width, GLsizei height) const 1.281 +{ 1.282 + if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport()) 1.283 + { 1.284 + return 0; // Maximum number of levels 1.285 + } 1.286 + else 1.287 + { 1.288 + // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. 1.289 + return 1; 1.290 + } 1.291 +} 1.292 + 1.293 +GLint Texture::creationLevels(GLsizei size) const 1.294 +{ 1.295 + return creationLevels(size, size); 1.296 +} 1.297 + 1.298 +Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id) 1.299 +{ 1.300 + mTexStorage = NULL; 1.301 + mSurface = NULL; 1.302 + mColorbufferProxy = NULL; 1.303 + mProxyRefs = 0; 1.304 + 1.305 + for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) 1.306 + { 1.307 + mImageArray[i] = renderer->createImage(); 1.308 + } 1.309 +} 1.310 + 1.311 +Texture2D::~Texture2D() 1.312 +{ 1.313 + mColorbufferProxy = NULL; 1.314 + 1.315 + delete mTexStorage; 1.316 + mTexStorage = NULL; 1.317 + 1.318 + if (mSurface) 1.319 + { 1.320 + mSurface->setBoundTexture(NULL); 1.321 + mSurface = NULL; 1.322 + } 1.323 + 1.324 + for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) 1.325 + { 1.326 + delete mImageArray[i]; 1.327 + } 1.328 +} 1.329 + 1.330 +// We need to maintain a count of references to renderbuffers acting as 1.331 +// proxies for this texture, so that we do not attempt to use a pointer 1.332 +// to a renderbuffer proxy which has been deleted. 1.333 +void Texture2D::addProxyRef(const Renderbuffer *proxy) 1.334 +{ 1.335 + mProxyRefs++; 1.336 +} 1.337 + 1.338 +void Texture2D::releaseProxy(const Renderbuffer *proxy) 1.339 +{ 1.340 + if (mProxyRefs > 0) 1.341 + mProxyRefs--; 1.342 + 1.343 + if (mProxyRefs == 0) 1.344 + mColorbufferProxy = NULL; 1.345 +} 1.346 + 1.347 +GLenum Texture2D::getTarget() const 1.348 +{ 1.349 + return GL_TEXTURE_2D; 1.350 +} 1.351 + 1.352 +GLsizei Texture2D::getWidth(GLint level) const 1.353 +{ 1.354 + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1.355 + return mImageArray[level]->getWidth(); 1.356 + else 1.357 + return 0; 1.358 +} 1.359 + 1.360 +GLsizei Texture2D::getHeight(GLint level) const 1.361 +{ 1.362 + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1.363 + return mImageArray[level]->getHeight(); 1.364 + else 1.365 + return 0; 1.366 +} 1.367 + 1.368 +GLenum Texture2D::getInternalFormat(GLint level) const 1.369 +{ 1.370 + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1.371 + return mImageArray[level]->getInternalFormat(); 1.372 + else 1.373 + return GL_NONE; 1.374 +} 1.375 + 1.376 +GLenum Texture2D::getActualFormat(GLint level) const 1.377 +{ 1.378 + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1.379 + return mImageArray[level]->getActualFormat(); 1.380 + else 1.381 + return D3DFMT_UNKNOWN; 1.382 +} 1.383 + 1.384 +void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height) 1.385 +{ 1.386 + releaseTexImage(); 1.387 + 1.388 + // If there currently is a corresponding storage texture image, it has these parameters 1.389 + const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level); 1.390 + const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level); 1.391 + const int storageFormat = mImageArray[0]->getInternalFormat(); 1.392 + 1.393 + mImageArray[level]->redefine(mRenderer, internalformat, width, height, false); 1.394 + 1.395 + if (mTexStorage) 1.396 + { 1.397 + const int storageLevels = mTexStorage->levelCount(); 1.398 + 1.399 + if ((level >= storageLevels && storageLevels != 0) || 1.400 + width != storageWidth || 1.401 + height != storageHeight || 1.402 + internalformat != storageFormat) // Discard mismatched storage 1.403 + { 1.404 + for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 1.405 + { 1.406 + mImageArray[i]->markDirty(); 1.407 + } 1.408 + 1.409 + delete mTexStorage; 1.410 + mTexStorage = NULL; 1.411 + mDirtyImages = true; 1.412 + } 1.413 + } 1.414 +} 1.415 + 1.416 +void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1.417 +{ 1.418 + GLint internalformat = ConvertSizedInternalFormat(format, type); 1.419 + redefineImage(level, internalformat, width, height); 1.420 + 1.421 + Texture::setImage(unpackAlignment, pixels, mImageArray[level]); 1.422 +} 1.423 + 1.424 +void Texture2D::bindTexImage(egl::Surface *surface) 1.425 +{ 1.426 + releaseTexImage(); 1.427 + 1.428 + GLint internalformat = surface->getFormat(); 1.429 + 1.430 + mImageArray[0]->redefine(mRenderer, internalformat, surface->getWidth(), surface->getHeight(), true); 1.431 + 1.432 + delete mTexStorage; 1.433 + mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain()); 1.434 + 1.435 + mDirtyImages = true; 1.436 + mSurface = surface; 1.437 + mSurface->setBoundTexture(this); 1.438 +} 1.439 + 1.440 +void Texture2D::releaseTexImage() 1.441 +{ 1.442 + if (mSurface) 1.443 + { 1.444 + mSurface->setBoundTexture(NULL); 1.445 + mSurface = NULL; 1.446 + 1.447 + if (mTexStorage) 1.448 + { 1.449 + delete mTexStorage; 1.450 + mTexStorage = NULL; 1.451 + } 1.452 + 1.453 + for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 1.454 + { 1.455 + mImageArray[i]->redefine(mRenderer, GL_NONE, 0, 0, true); 1.456 + } 1.457 + } 1.458 +} 1.459 + 1.460 +void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) 1.461 +{ 1.462 + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly 1.463 + redefineImage(level, format, width, height); 1.464 + 1.465 + Texture::setCompressedImage(imageSize, pixels, mImageArray[level]); 1.466 +} 1.467 + 1.468 +void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) 1.469 +{ 1.470 + if (level < levelCount()) 1.471 + { 1.472 + rx::Image *image = mImageArray[level]; 1.473 + if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height)) 1.474 + { 1.475 + image->markClean(); 1.476 + } 1.477 + } 1.478 +} 1.479 + 1.480 +void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1.481 +{ 1.482 + if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, mImageArray[level])) 1.483 + { 1.484 + commitRect(level, xoffset, yoffset, width, height); 1.485 + } 1.486 +} 1.487 + 1.488 +void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) 1.489 +{ 1.490 + if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, mImageArray[level])) 1.491 + { 1.492 + commitRect(level, xoffset, yoffset, width, height); 1.493 + } 1.494 +} 1.495 + 1.496 +void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 1.497 +{ 1.498 + GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE); 1.499 + redefineImage(level, internalformat, width, height); 1.500 + 1.501 + if (!mImageArray[level]->isRenderableFormat()) 1.502 + { 1.503 + mImageArray[level]->copy(0, 0, x, y, width, height, source); 1.504 + mDirtyImages = true; 1.505 + } 1.506 + else 1.507 + { 1.508 + if (!mTexStorage || !mTexStorage->isRenderTarget()) 1.509 + { 1.510 + convertToRenderTarget(); 1.511 + } 1.512 + 1.513 + mImageArray[level]->markClean(); 1.514 + 1.515 + if (width != 0 && height != 0 && level < levelCount()) 1.516 + { 1.517 + gl::Rectangle sourceRect; 1.518 + sourceRect.x = x; 1.519 + sourceRect.width = width; 1.520 + sourceRect.y = y; 1.521 + sourceRect.height = height; 1.522 + 1.523 + mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level); 1.524 + } 1.525 + } 1.526 +} 1.527 + 1.528 +void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 1.529 +{ 1.530 + if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight()) 1.531 + { 1.532 + return gl::error(GL_INVALID_VALUE); 1.533 + } 1.534 + 1.535 + if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) 1.536 + { 1.537 + mImageArray[level]->copy(xoffset, yoffset, x, y, width, height, source); 1.538 + mDirtyImages = true; 1.539 + } 1.540 + else 1.541 + { 1.542 + if (!mTexStorage || !mTexStorage->isRenderTarget()) 1.543 + { 1.544 + convertToRenderTarget(); 1.545 + } 1.546 + 1.547 + updateTexture(); 1.548 + 1.549 + if (level < levelCount()) 1.550 + { 1.551 + gl::Rectangle sourceRect; 1.552 + sourceRect.x = x; 1.553 + sourceRect.width = width; 1.554 + sourceRect.y = y; 1.555 + sourceRect.height = height; 1.556 + 1.557 + mRenderer->copyImage(source, sourceRect, 1.558 + gl::ExtractFormat(mImageArray[0]->getInternalFormat()), 1.559 + xoffset, yoffset, mTexStorage, level); 1.560 + } 1.561 + } 1.562 +} 1.563 + 1.564 +void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) 1.565 +{ 1.566 + delete mTexStorage; 1.567 + mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height); 1.568 + mImmutable = true; 1.569 + 1.570 + for (int level = 0; level < levels; level++) 1.571 + { 1.572 + mImageArray[level]->redefine(mRenderer, internalformat, width, height, true); 1.573 + width = std::max(1, width >> 1); 1.574 + height = std::max(1, height >> 1); 1.575 + } 1.576 + 1.577 + for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 1.578 + { 1.579 + mImageArray[level]->redefine(mRenderer, GL_NONE, 0, 0, true); 1.580 + } 1.581 + 1.582 + if (mTexStorage->isManaged()) 1.583 + { 1.584 + int levels = levelCount(); 1.585 + 1.586 + for (int level = 0; level < levels; level++) 1.587 + { 1.588 + mImageArray[level]->setManagedSurface(mTexStorage, level); 1.589 + } 1.590 + } 1.591 +} 1.592 + 1.593 +// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85. 1.594 +bool Texture2D::isSamplerComplete() const 1.595 +{ 1.596 + GLsizei width = mImageArray[0]->getWidth(); 1.597 + GLsizei height = mImageArray[0]->getHeight(); 1.598 + 1.599 + if (width <= 0 || height <= 0) 1.600 + { 1.601 + return false; 1.602 + } 1.603 + 1.604 + bool mipmapping = isMipmapFiltered(); 1.605 + bool filtering, renderable; 1.606 + 1.607 + if ((IsFloat32Format(getInternalFormat(0)) && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) || 1.608 + (IsFloat16Format(getInternalFormat(0)) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable))) 1.609 + { 1.610 + if (mSamplerState.magFilter != GL_NEAREST || 1.611 + (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST)) 1.612 + { 1.613 + return false; 1.614 + } 1.615 + } 1.616 + 1.617 + bool npotSupport = mRenderer->getNonPower2TextureSupport(); 1.618 + 1.619 + if (!npotSupport) 1.620 + { 1.621 + if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) || 1.622 + (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height))) 1.623 + { 1.624 + return false; 1.625 + } 1.626 + } 1.627 + 1.628 + if (mipmapping) 1.629 + { 1.630 + if (!npotSupport) 1.631 + { 1.632 + if (!isPow2(width) || !isPow2(height)) 1.633 + { 1.634 + return false; 1.635 + } 1.636 + } 1.637 + 1.638 + if (!isMipmapComplete()) 1.639 + { 1.640 + return false; 1.641 + } 1.642 + } 1.643 + 1.644 + return true; 1.645 +} 1.646 + 1.647 +// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. 1.648 +bool Texture2D::isMipmapComplete() const 1.649 +{ 1.650 + if (isImmutable()) 1.651 + { 1.652 + return true; 1.653 + } 1.654 + 1.655 + GLsizei width = mImageArray[0]->getWidth(); 1.656 + GLsizei height = mImageArray[0]->getHeight(); 1.657 + 1.658 + if (width <= 0 || height <= 0) 1.659 + { 1.660 + return false; 1.661 + } 1.662 + 1.663 + int q = log2(std::max(width, height)); 1.664 + 1.665 + for (int level = 1; level <= q; level++) 1.666 + { 1.667 + if (mImageArray[level]->getInternalFormat() != mImageArray[0]->getInternalFormat()) 1.668 + { 1.669 + return false; 1.670 + } 1.671 + 1.672 + if (mImageArray[level]->getWidth() != std::max(1, width >> level)) 1.673 + { 1.674 + return false; 1.675 + } 1.676 + 1.677 + if (mImageArray[level]->getHeight() != std::max(1, height >> level)) 1.678 + { 1.679 + return false; 1.680 + } 1.681 + } 1.682 + 1.683 + return true; 1.684 +} 1.685 + 1.686 +bool Texture2D::isCompressed(GLint level) const 1.687 +{ 1.688 + return IsCompressed(getInternalFormat(level)); 1.689 +} 1.690 + 1.691 +bool Texture2D::isDepth(GLint level) const 1.692 +{ 1.693 + return IsDepthTexture(getInternalFormat(level)); 1.694 +} 1.695 + 1.696 +// Constructs a native texture resource from the texture images 1.697 +void Texture2D::createTexture() 1.698 +{ 1.699 + GLsizei width = mImageArray[0]->getWidth(); 1.700 + GLsizei height = mImageArray[0]->getHeight(); 1.701 + 1.702 + if (!(width > 0 && height > 0)) 1.703 + return; // do not attempt to create native textures for nonexistant data 1.704 + 1.705 + GLint levels = creationLevels(width, height); 1.706 + GLenum internalformat = mImageArray[0]->getInternalFormat(); 1.707 + 1.708 + delete mTexStorage; 1.709 + mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height); 1.710 + 1.711 + if (mTexStorage->isManaged()) 1.712 + { 1.713 + int levels = levelCount(); 1.714 + 1.715 + for (int level = 0; level < levels; level++) 1.716 + { 1.717 + mImageArray[level]->setManagedSurface(mTexStorage, level); 1.718 + } 1.719 + } 1.720 + 1.721 + mDirtyImages = true; 1.722 +} 1.723 + 1.724 +void Texture2D::updateTexture() 1.725 +{ 1.726 + bool mipmapping = (isMipmapFiltered() && isMipmapComplete()); 1.727 + 1.728 + int levels = (mipmapping ? levelCount() : 1); 1.729 + 1.730 + for (int level = 0; level < levels; level++) 1.731 + { 1.732 + rx::Image *image = mImageArray[level]; 1.733 + 1.734 + if (image->isDirty()) 1.735 + { 1.736 + commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight()); 1.737 + } 1.738 + } 1.739 +} 1.740 + 1.741 +void Texture2D::convertToRenderTarget() 1.742 +{ 1.743 + rx::TextureStorageInterface2D *newTexStorage = NULL; 1.744 + 1.745 + if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0) 1.746 + { 1.747 + GLsizei width = mImageArray[0]->getWidth(); 1.748 + GLsizei height = mImageArray[0]->getHeight(); 1.749 + GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height); 1.750 + GLenum internalformat = mImageArray[0]->getInternalFormat(); 1.751 + 1.752 + newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height); 1.753 + 1.754 + if (mTexStorage != NULL) 1.755 + { 1.756 + if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage)) 1.757 + { 1.758 + delete newTexStorage; 1.759 + return gl::error(GL_OUT_OF_MEMORY); 1.760 + } 1.761 + } 1.762 + } 1.763 + 1.764 + delete mTexStorage; 1.765 + mTexStorage = newTexStorage; 1.766 + 1.767 + mDirtyImages = true; 1.768 +} 1.769 + 1.770 +void Texture2D::generateMipmaps() 1.771 +{ 1.772 + if (!mRenderer->getNonPower2TextureSupport()) 1.773 + { 1.774 + if (!isPow2(mImageArray[0]->getWidth()) || !isPow2(mImageArray[0]->getHeight())) 1.775 + { 1.776 + return gl::error(GL_INVALID_OPERATION); 1.777 + } 1.778 + } 1.779 + 1.780 + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. 1.781 + unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight())); 1.782 + for (unsigned int i = 1; i <= q; i++) 1.783 + { 1.784 + redefineImage(i, mImageArray[0]->getInternalFormat(), 1.785 + std::max(mImageArray[0]->getWidth() >> i, 1), 1.786 + std::max(mImageArray[0]->getHeight() >> i, 1)); 1.787 + } 1.788 + 1.789 + if (mTexStorage && mTexStorage->isRenderTarget()) 1.790 + { 1.791 + for (unsigned int i = 1; i <= q; i++) 1.792 + { 1.793 + mTexStorage->generateMipmap(i); 1.794 + 1.795 + mImageArray[i]->markClean(); 1.796 + } 1.797 + } 1.798 + else 1.799 + { 1.800 + for (unsigned int i = 1; i <= q; i++) 1.801 + { 1.802 + mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]); 1.803 + } 1.804 + } 1.805 +} 1.806 + 1.807 +Renderbuffer *Texture2D::getRenderbuffer(GLenum target) 1.808 +{ 1.809 + if (target != GL_TEXTURE_2D) 1.810 + { 1.811 + return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL); 1.812 + } 1.813 + 1.814 + if (mColorbufferProxy == NULL) 1.815 + { 1.816 + mColorbufferProxy = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, target)); 1.817 + } 1.818 + 1.819 + return mColorbufferProxy; 1.820 +} 1.821 + 1.822 +rx::RenderTarget *Texture2D::getRenderTarget(GLenum target) 1.823 +{ 1.824 + ASSERT(target == GL_TEXTURE_2D); 1.825 + 1.826 + // ensure the underlying texture is created 1.827 + if (getStorage(true) == NULL) 1.828 + { 1.829 + return NULL; 1.830 + } 1.831 + 1.832 + updateTexture(); 1.833 + 1.834 + // ensure this is NOT a depth texture 1.835 + if (isDepth(0)) 1.836 + { 1.837 + return NULL; 1.838 + } 1.839 + 1.840 + return mTexStorage->getRenderTarget(); 1.841 +} 1.842 + 1.843 +rx::RenderTarget *Texture2D::getDepthStencil(GLenum target) 1.844 +{ 1.845 + ASSERT(target == GL_TEXTURE_2D); 1.846 + 1.847 + // ensure the underlying texture is created 1.848 + if (getStorage(true) == NULL) 1.849 + { 1.850 + return NULL; 1.851 + } 1.852 + 1.853 + updateTexture(); 1.854 + 1.855 + // ensure this is actually a depth texture 1.856 + if (!isDepth(0)) 1.857 + { 1.858 + return NULL; 1.859 + } 1.860 + return mTexStorage->getRenderTarget(); 1.861 +} 1.862 + 1.863 +int Texture2D::levelCount() 1.864 +{ 1.865 + return mTexStorage ? mTexStorage->levelCount() : 0; 1.866 +} 1.867 + 1.868 +rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget) 1.869 +{ 1.870 + if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget())) 1.871 + { 1.872 + if (renderTarget) 1.873 + { 1.874 + convertToRenderTarget(); 1.875 + } 1.876 + else 1.877 + { 1.878 + createTexture(); 1.879 + } 1.880 + } 1.881 + 1.882 + return mTexStorage; 1.883 +} 1.884 + 1.885 +TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id) 1.886 +{ 1.887 + mTexStorage = NULL; 1.888 + for (int i = 0; i < 6; i++) 1.889 + { 1.890 + mFaceProxies[i] = NULL; 1.891 + mFaceProxyRefs[i] = 0; 1.892 + 1.893 + for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) 1.894 + { 1.895 + mImageArray[i][j] = renderer->createImage(); 1.896 + } 1.897 + } 1.898 +} 1.899 + 1.900 +TextureCubeMap::~TextureCubeMap() 1.901 +{ 1.902 + for (int i = 0; i < 6; i++) 1.903 + { 1.904 + mFaceProxies[i] = NULL; 1.905 + 1.906 + for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) 1.907 + { 1.908 + delete mImageArray[i][j]; 1.909 + } 1.910 + } 1.911 + 1.912 + delete mTexStorage; 1.913 + mTexStorage = NULL; 1.914 +} 1.915 + 1.916 +// We need to maintain a count of references to renderbuffers acting as 1.917 +// proxies for this texture, so that the texture is not deleted while 1.918 +// proxy references still exist. If the reference count drops to zero, 1.919 +// we set our proxy pointer NULL, so that a new attempt at referencing 1.920 +// will cause recreation. 1.921 +void TextureCubeMap::addProxyRef(const Renderbuffer *proxy) 1.922 +{ 1.923 + for (int i = 0; i < 6; i++) 1.924 + { 1.925 + if (mFaceProxies[i] == proxy) 1.926 + mFaceProxyRefs[i]++; 1.927 + } 1.928 +} 1.929 + 1.930 +void TextureCubeMap::releaseProxy(const Renderbuffer *proxy) 1.931 +{ 1.932 + for (int i = 0; i < 6; i++) 1.933 + { 1.934 + if (mFaceProxies[i] == proxy) 1.935 + { 1.936 + if (mFaceProxyRefs[i] > 0) 1.937 + mFaceProxyRefs[i]--; 1.938 + 1.939 + if (mFaceProxyRefs[i] == 0) 1.940 + mFaceProxies[i] = NULL; 1.941 + } 1.942 + } 1.943 +} 1.944 + 1.945 +GLenum TextureCubeMap::getTarget() const 1.946 +{ 1.947 + return GL_TEXTURE_CUBE_MAP; 1.948 +} 1.949 + 1.950 +GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const 1.951 +{ 1.952 + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1.953 + return mImageArray[faceIndex(target)][level]->getWidth(); 1.954 + else 1.955 + return 0; 1.956 +} 1.957 + 1.958 +GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const 1.959 +{ 1.960 + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1.961 + return mImageArray[faceIndex(target)][level]->getHeight(); 1.962 + else 1.963 + return 0; 1.964 +} 1.965 + 1.966 +GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const 1.967 +{ 1.968 + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1.969 + return mImageArray[faceIndex(target)][level]->getInternalFormat(); 1.970 + else 1.971 + return GL_NONE; 1.972 +} 1.973 + 1.974 +GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const 1.975 +{ 1.976 + if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1.977 + return mImageArray[faceIndex(target)][level]->getActualFormat(); 1.978 + else 1.979 + return D3DFMT_UNKNOWN; 1.980 +} 1.981 + 1.982 +void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1.983 +{ 1.984 + setImage(0, level, width, height, format, type, unpackAlignment, pixels); 1.985 +} 1.986 + 1.987 +void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1.988 +{ 1.989 + setImage(1, level, width, height, format, type, unpackAlignment, pixels); 1.990 +} 1.991 + 1.992 +void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1.993 +{ 1.994 + setImage(2, level, width, height, format, type, unpackAlignment, pixels); 1.995 +} 1.996 + 1.997 +void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1.998 +{ 1.999 + setImage(3, level, width, height, format, type, unpackAlignment, pixels); 1.1000 +} 1.1001 + 1.1002 +void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1.1003 +{ 1.1004 + setImage(4, level, width, height, format, type, unpackAlignment, pixels); 1.1005 +} 1.1006 + 1.1007 +void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1.1008 +{ 1.1009 + setImage(5, level, width, height, format, type, unpackAlignment, pixels); 1.1010 +} 1.1011 + 1.1012 +void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) 1.1013 +{ 1.1014 + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly 1.1015 + redefineImage(faceIndex(face), level, format, width, height); 1.1016 + 1.1017 + Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]); 1.1018 +} 1.1019 + 1.1020 +void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) 1.1021 +{ 1.1022 + if (level < levelCount()) 1.1023 + { 1.1024 + rx::Image *image = mImageArray[face][level]; 1.1025 + if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height)) 1.1026 + image->markClean(); 1.1027 + } 1.1028 +} 1.1029 + 1.1030 +void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1.1031 +{ 1.1032 + if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, mImageArray[faceIndex(target)][level])) 1.1033 + { 1.1034 + commitRect(faceIndex(target), level, xoffset, yoffset, width, height); 1.1035 + } 1.1036 +} 1.1037 + 1.1038 +void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) 1.1039 +{ 1.1040 + if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, mImageArray[faceIndex(target)][level])) 1.1041 + { 1.1042 + commitRect(faceIndex(target), level, xoffset, yoffset, width, height); 1.1043 + } 1.1044 +} 1.1045 + 1.1046 +// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86. 1.1047 +bool TextureCubeMap::isSamplerComplete() const 1.1048 +{ 1.1049 + int size = mImageArray[0][0]->getWidth(); 1.1050 + 1.1051 + bool mipmapping = isMipmapFiltered(); 1.1052 + bool filtering, renderable; 1.1053 + 1.1054 + if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) || 1.1055 + (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable))) 1.1056 + { 1.1057 + if (mSamplerState.magFilter != GL_NEAREST || 1.1058 + (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST)) 1.1059 + { 1.1060 + return false; 1.1061 + } 1.1062 + } 1.1063 + 1.1064 + if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport()) 1.1065 + { 1.1066 + if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping) 1.1067 + { 1.1068 + return false; 1.1069 + } 1.1070 + } 1.1071 + 1.1072 + if (!mipmapping) 1.1073 + { 1.1074 + if (!isCubeComplete()) 1.1075 + { 1.1076 + return false; 1.1077 + } 1.1078 + } 1.1079 + else 1.1080 + { 1.1081 + if (!isMipmapCubeComplete()) // Also tests for isCubeComplete() 1.1082 + { 1.1083 + return false; 1.1084 + } 1.1085 + } 1.1086 + 1.1087 + return true; 1.1088 +} 1.1089 + 1.1090 +// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. 1.1091 +bool TextureCubeMap::isCubeComplete() const 1.1092 +{ 1.1093 + if (mImageArray[0][0]->getWidth() <= 0 || mImageArray[0][0]->getHeight() != mImageArray[0][0]->getWidth()) 1.1094 + { 1.1095 + return false; 1.1096 + } 1.1097 + 1.1098 + for (unsigned int face = 1; face < 6; face++) 1.1099 + { 1.1100 + if (mImageArray[face][0]->getWidth() != mImageArray[0][0]->getWidth() || 1.1101 + mImageArray[face][0]->getWidth() != mImageArray[0][0]->getHeight() || 1.1102 + mImageArray[face][0]->getInternalFormat() != mImageArray[0][0]->getInternalFormat()) 1.1103 + { 1.1104 + return false; 1.1105 + } 1.1106 + } 1.1107 + 1.1108 + return true; 1.1109 +} 1.1110 + 1.1111 +bool TextureCubeMap::isMipmapCubeComplete() const 1.1112 +{ 1.1113 + if (isImmutable()) 1.1114 + { 1.1115 + return true; 1.1116 + } 1.1117 + 1.1118 + if (!isCubeComplete()) 1.1119 + { 1.1120 + return false; 1.1121 + } 1.1122 + 1.1123 + GLsizei size = mImageArray[0][0]->getWidth(); 1.1124 + 1.1125 + int q = log2(size); 1.1126 + 1.1127 + for (int face = 0; face < 6; face++) 1.1128 + { 1.1129 + for (int level = 1; level <= q; level++) 1.1130 + { 1.1131 + if (mImageArray[face][level]->getInternalFormat() != mImageArray[0][0]->getInternalFormat()) 1.1132 + { 1.1133 + return false; 1.1134 + } 1.1135 + 1.1136 + if (mImageArray[face][level]->getWidth() != std::max(1, size >> level)) 1.1137 + { 1.1138 + return false; 1.1139 + } 1.1140 + } 1.1141 + } 1.1142 + 1.1143 + return true; 1.1144 +} 1.1145 + 1.1146 +bool TextureCubeMap::isCompressed(GLenum target, GLint level) const 1.1147 +{ 1.1148 + return IsCompressed(getInternalFormat(target, level)); 1.1149 +} 1.1150 + 1.1151 +// Constructs a native texture resource from the texture images, or returns an existing one 1.1152 +void TextureCubeMap::createTexture() 1.1153 +{ 1.1154 + GLsizei size = mImageArray[0][0]->getWidth(); 1.1155 + 1.1156 + if (!(size > 0)) 1.1157 + return; // do not attempt to create native textures for nonexistant data 1.1158 + 1.1159 + GLint levels = creationLevels(size); 1.1160 + GLenum internalformat = mImageArray[0][0]->getInternalFormat(); 1.1161 + 1.1162 + delete mTexStorage; 1.1163 + mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size); 1.1164 + 1.1165 + if (mTexStorage->isManaged()) 1.1166 + { 1.1167 + int levels = levelCount(); 1.1168 + 1.1169 + for (int face = 0; face < 6; face++) 1.1170 + { 1.1171 + for (int level = 0; level < levels; level++) 1.1172 + { 1.1173 + mImageArray[face][level]->setManagedSurface(mTexStorage, face, level); 1.1174 + } 1.1175 + } 1.1176 + } 1.1177 + 1.1178 + mDirtyImages = true; 1.1179 +} 1.1180 + 1.1181 +void TextureCubeMap::updateTexture() 1.1182 +{ 1.1183 + bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete(); 1.1184 + 1.1185 + for (int face = 0; face < 6; face++) 1.1186 + { 1.1187 + int levels = (mipmapping ? levelCount() : 1); 1.1188 + 1.1189 + for (int level = 0; level < levels; level++) 1.1190 + { 1.1191 + rx::Image *image = mImageArray[face][level]; 1.1192 + 1.1193 + if (image->isDirty()) 1.1194 + { 1.1195 + commitRect(face, level, 0, 0, image->getWidth(), image->getHeight()); 1.1196 + } 1.1197 + } 1.1198 + } 1.1199 +} 1.1200 + 1.1201 +void TextureCubeMap::convertToRenderTarget() 1.1202 +{ 1.1203 + rx::TextureStorageInterfaceCube *newTexStorage = NULL; 1.1204 + 1.1205 + if (mImageArray[0][0]->getWidth() != 0) 1.1206 + { 1.1207 + GLsizei size = mImageArray[0][0]->getWidth(); 1.1208 + GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size); 1.1209 + GLenum internalformat = mImageArray[0][0]->getInternalFormat(); 1.1210 + 1.1211 + newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size); 1.1212 + 1.1213 + if (mTexStorage != NULL) 1.1214 + { 1.1215 + if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage)) 1.1216 + { 1.1217 + delete newTexStorage; 1.1218 + return gl::error(GL_OUT_OF_MEMORY); 1.1219 + } 1.1220 + } 1.1221 + } 1.1222 + 1.1223 + delete mTexStorage; 1.1224 + mTexStorage = newTexStorage; 1.1225 + 1.1226 + mDirtyImages = true; 1.1227 +} 1.1228 + 1.1229 +void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels) 1.1230 +{ 1.1231 + GLint internalformat = ConvertSizedInternalFormat(format, type); 1.1232 + redefineImage(faceIndex, level, internalformat, width, height); 1.1233 + 1.1234 + Texture::setImage(unpackAlignment, pixels, mImageArray[faceIndex][level]); 1.1235 +} 1.1236 + 1.1237 +unsigned int TextureCubeMap::faceIndex(GLenum face) 1.1238 +{ 1.1239 + META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1); 1.1240 + META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2); 1.1241 + META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3); 1.1242 + META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4); 1.1243 + META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5); 1.1244 + 1.1245 + return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X; 1.1246 +} 1.1247 + 1.1248 +void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height) 1.1249 +{ 1.1250 + // If there currently is a corresponding storage texture image, it has these parameters 1.1251 + const int storageWidth = std::max(1, mImageArray[0][0]->getWidth() >> level); 1.1252 + const int storageHeight = std::max(1, mImageArray[0][0]->getHeight() >> level); 1.1253 + const int storageFormat = mImageArray[0][0]->getInternalFormat(); 1.1254 + 1.1255 + mImageArray[face][level]->redefine(mRenderer, internalformat, width, height, false); 1.1256 + 1.1257 + if (mTexStorage) 1.1258 + { 1.1259 + const int storageLevels = mTexStorage->levelCount(); 1.1260 + 1.1261 + if ((level >= storageLevels && storageLevels != 0) || 1.1262 + width != storageWidth || 1.1263 + height != storageHeight || 1.1264 + internalformat != storageFormat) // Discard mismatched storage 1.1265 + { 1.1266 + for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 1.1267 + { 1.1268 + for (int f = 0; f < 6; f++) 1.1269 + { 1.1270 + mImageArray[f][i]->markDirty(); 1.1271 + } 1.1272 + } 1.1273 + 1.1274 + delete mTexStorage; 1.1275 + mTexStorage = NULL; 1.1276 + 1.1277 + mDirtyImages = true; 1.1278 + } 1.1279 + } 1.1280 +} 1.1281 + 1.1282 +void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 1.1283 +{ 1.1284 + unsigned int faceindex = faceIndex(target); 1.1285 + GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE); 1.1286 + redefineImage(faceindex, level, internalformat, width, height); 1.1287 + 1.1288 + if (!mImageArray[faceindex][level]->isRenderableFormat()) 1.1289 + { 1.1290 + mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source); 1.1291 + mDirtyImages = true; 1.1292 + } 1.1293 + else 1.1294 + { 1.1295 + if (!mTexStorage || !mTexStorage->isRenderTarget()) 1.1296 + { 1.1297 + convertToRenderTarget(); 1.1298 + } 1.1299 + 1.1300 + mImageArray[faceindex][level]->markClean(); 1.1301 + 1.1302 + ASSERT(width == height); 1.1303 + 1.1304 + if (width > 0 && level < levelCount()) 1.1305 + { 1.1306 + gl::Rectangle sourceRect; 1.1307 + sourceRect.x = x; 1.1308 + sourceRect.width = width; 1.1309 + sourceRect.y = y; 1.1310 + sourceRect.height = height; 1.1311 + 1.1312 + mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level); 1.1313 + } 1.1314 + } 1.1315 +} 1.1316 + 1.1317 +void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) 1.1318 +{ 1.1319 + GLsizei size = mImageArray[faceIndex(target)][level]->getWidth(); 1.1320 + 1.1321 + if (xoffset + width > size || yoffset + height > size) 1.1322 + { 1.1323 + return gl::error(GL_INVALID_VALUE); 1.1324 + } 1.1325 + 1.1326 + unsigned int faceindex = faceIndex(target); 1.1327 + 1.1328 + if (!mImageArray[faceindex][level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete())) 1.1329 + { 1.1330 + mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source); 1.1331 + mDirtyImages = true; 1.1332 + } 1.1333 + else 1.1334 + { 1.1335 + if (!mTexStorage || !mTexStorage->isRenderTarget()) 1.1336 + { 1.1337 + convertToRenderTarget(); 1.1338 + } 1.1339 + 1.1340 + updateTexture(); 1.1341 + 1.1342 + if (level < levelCount()) 1.1343 + { 1.1344 + gl::Rectangle sourceRect; 1.1345 + sourceRect.x = x; 1.1346 + sourceRect.width = width; 1.1347 + sourceRect.y = y; 1.1348 + sourceRect.height = height; 1.1349 + 1.1350 + mRenderer->copyImage(source, sourceRect, gl::ExtractFormat(mImageArray[0][0]->getInternalFormat()), 1.1351 + xoffset, yoffset, mTexStorage, target, level); 1.1352 + } 1.1353 + } 1.1354 +} 1.1355 + 1.1356 +void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size) 1.1357 +{ 1.1358 + delete mTexStorage; 1.1359 + mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size); 1.1360 + mImmutable = true; 1.1361 + 1.1362 + for (int level = 0; level < levels; level++) 1.1363 + { 1.1364 + for (int face = 0; face < 6; face++) 1.1365 + { 1.1366 + mImageArray[face][level]->redefine(mRenderer, internalformat, size, size, true); 1.1367 + size = std::max(1, size >> 1); 1.1368 + } 1.1369 + } 1.1370 + 1.1371 + for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 1.1372 + { 1.1373 + for (int face = 0; face < 6; face++) 1.1374 + { 1.1375 + mImageArray[face][level]->redefine(mRenderer, GL_NONE, 0, 0, true); 1.1376 + } 1.1377 + } 1.1378 + 1.1379 + if (mTexStorage->isManaged()) 1.1380 + { 1.1381 + int levels = levelCount(); 1.1382 + 1.1383 + for (int face = 0; face < 6; face++) 1.1384 + { 1.1385 + for (int level = 0; level < levels; level++) 1.1386 + { 1.1387 + mImageArray[face][level]->setManagedSurface(mTexStorage, face, level); 1.1388 + } 1.1389 + } 1.1390 + } 1.1391 +} 1.1392 + 1.1393 +void TextureCubeMap::generateMipmaps() 1.1394 +{ 1.1395 + if (!isCubeComplete()) 1.1396 + { 1.1397 + return gl::error(GL_INVALID_OPERATION); 1.1398 + } 1.1399 + 1.1400 + if (!mRenderer->getNonPower2TextureSupport()) 1.1401 + { 1.1402 + if (!isPow2(mImageArray[0][0]->getWidth())) 1.1403 + { 1.1404 + return gl::error(GL_INVALID_OPERATION); 1.1405 + } 1.1406 + } 1.1407 + 1.1408 + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. 1.1409 + unsigned int q = log2(mImageArray[0][0]->getWidth()); 1.1410 + for (unsigned int f = 0; f < 6; f++) 1.1411 + { 1.1412 + for (unsigned int i = 1; i <= q; i++) 1.1413 + { 1.1414 + redefineImage(f, i, mImageArray[f][0]->getInternalFormat(), 1.1415 + std::max(mImageArray[f][0]->getWidth() >> i, 1), 1.1416 + std::max(mImageArray[f][0]->getWidth() >> i, 1)); 1.1417 + } 1.1418 + } 1.1419 + 1.1420 + if (mTexStorage && mTexStorage->isRenderTarget()) 1.1421 + { 1.1422 + for (unsigned int f = 0; f < 6; f++) 1.1423 + { 1.1424 + for (unsigned int i = 1; i <= q; i++) 1.1425 + { 1.1426 + mTexStorage->generateMipmap(f, i); 1.1427 + 1.1428 + mImageArray[f][i]->markClean(); 1.1429 + } 1.1430 + } 1.1431 + } 1.1432 + else 1.1433 + { 1.1434 + for (unsigned int f = 0; f < 6; f++) 1.1435 + { 1.1436 + for (unsigned int i = 1; i <= q; i++) 1.1437 + { 1.1438 + mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]); 1.1439 + } 1.1440 + } 1.1441 + } 1.1442 +} 1.1443 + 1.1444 +Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target) 1.1445 +{ 1.1446 + if (!IsCubemapTextureTarget(target)) 1.1447 + { 1.1448 + return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL); 1.1449 + } 1.1450 + 1.1451 + unsigned int face = faceIndex(target); 1.1452 + 1.1453 + if (mFaceProxies[face] == NULL) 1.1454 + { 1.1455 + mFaceProxies[face] = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target)); 1.1456 + } 1.1457 + 1.1458 + return mFaceProxies[face]; 1.1459 +} 1.1460 + 1.1461 +rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target) 1.1462 +{ 1.1463 + ASSERT(IsCubemapTextureTarget(target)); 1.1464 + 1.1465 + // ensure the underlying texture is created 1.1466 + if (getStorage(true) == NULL) 1.1467 + { 1.1468 + return NULL; 1.1469 + } 1.1470 + 1.1471 + updateTexture(); 1.1472 + 1.1473 + return mTexStorage->getRenderTarget(target); 1.1474 +} 1.1475 + 1.1476 +int TextureCubeMap::levelCount() 1.1477 +{ 1.1478 + return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0; 1.1479 +} 1.1480 + 1.1481 +rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget) 1.1482 +{ 1.1483 + if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget())) 1.1484 + { 1.1485 + if (renderTarget) 1.1486 + { 1.1487 + convertToRenderTarget(); 1.1488 + } 1.1489 + else 1.1490 + { 1.1491 + createTexture(); 1.1492 + } 1.1493 + } 1.1494 + 1.1495 + return mTexStorage; 1.1496 +} 1.1497 + 1.1498 +}