gfx/angle/src/libGLESv2/Texture.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 #include "precompiled.h"
michael@0 2 //
michael@0 3 // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
michael@0 4 // Use of this source code is governed by a BSD-style license that can be
michael@0 5 // found in the LICENSE file.
michael@0 6 //
michael@0 7
michael@0 8 // Texture.cpp: Implements the gl::Texture class and its derived classes
michael@0 9 // Texture2D and TextureCubeMap. Implements GL texture objects and related
michael@0 10 // functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
michael@0 11
michael@0 12 #include "libGLESv2/Texture.h"
michael@0 13
michael@0 14 #include "libGLESv2/main.h"
michael@0 15 #include "libGLESv2/mathutil.h"
michael@0 16 #include "libGLESv2/utilities.h"
michael@0 17 #include "libGLESv2/renderer/Blit.h"
michael@0 18 #include "libGLESv2/Renderbuffer.h"
michael@0 19 #include "libGLESv2/renderer/Image.h"
michael@0 20 #include "libGLESv2/renderer/Renderer.h"
michael@0 21 #include "libGLESv2/renderer/TextureStorage.h"
michael@0 22 #include "libEGL/Surface.h"
michael@0 23
michael@0 24 namespace gl
michael@0 25 {
michael@0 26
michael@0 27 Texture::Texture(rx::Renderer *renderer, GLuint id) : RefCountObject(id)
michael@0 28 {
michael@0 29 mRenderer = renderer;
michael@0 30
michael@0 31 mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
michael@0 32 mSamplerState.magFilter = GL_LINEAR;
michael@0 33 mSamplerState.wrapS = GL_REPEAT;
michael@0 34 mSamplerState.wrapT = GL_REPEAT;
michael@0 35 mSamplerState.maxAnisotropy = 1.0f;
michael@0 36 mSamplerState.lodOffset = 0;
michael@0 37 mUsage = GL_NONE;
michael@0 38
michael@0 39 mDirtyImages = true;
michael@0 40
michael@0 41 mImmutable = false;
michael@0 42 }
michael@0 43
michael@0 44 Texture::~Texture()
michael@0 45 {
michael@0 46 }
michael@0 47
michael@0 48 // Returns true on successful filter state update (valid enum parameter)
michael@0 49 bool Texture::setMinFilter(GLenum filter)
michael@0 50 {
michael@0 51 switch (filter)
michael@0 52 {
michael@0 53 case GL_NEAREST:
michael@0 54 case GL_LINEAR:
michael@0 55 case GL_NEAREST_MIPMAP_NEAREST:
michael@0 56 case GL_LINEAR_MIPMAP_NEAREST:
michael@0 57 case GL_NEAREST_MIPMAP_LINEAR:
michael@0 58 case GL_LINEAR_MIPMAP_LINEAR:
michael@0 59 mSamplerState.minFilter = filter;
michael@0 60 return true;
michael@0 61 default:
michael@0 62 return false;
michael@0 63 }
michael@0 64 }
michael@0 65
michael@0 66 // Returns true on successful filter state update (valid enum parameter)
michael@0 67 bool Texture::setMagFilter(GLenum filter)
michael@0 68 {
michael@0 69 switch (filter)
michael@0 70 {
michael@0 71 case GL_NEAREST:
michael@0 72 case GL_LINEAR:
michael@0 73 mSamplerState.magFilter = filter;
michael@0 74 return true;
michael@0 75 default:
michael@0 76 return false;
michael@0 77 }
michael@0 78 }
michael@0 79
michael@0 80 // Returns true on successful wrap state update (valid enum parameter)
michael@0 81 bool Texture::setWrapS(GLenum wrap)
michael@0 82 {
michael@0 83 switch (wrap)
michael@0 84 {
michael@0 85 case GL_REPEAT:
michael@0 86 case GL_CLAMP_TO_EDGE:
michael@0 87 case GL_MIRRORED_REPEAT:
michael@0 88 mSamplerState.wrapS = wrap;
michael@0 89 return true;
michael@0 90 default:
michael@0 91 return false;
michael@0 92 }
michael@0 93 }
michael@0 94
michael@0 95 // Returns true on successful wrap state update (valid enum parameter)
michael@0 96 bool Texture::setWrapT(GLenum wrap)
michael@0 97 {
michael@0 98 switch (wrap)
michael@0 99 {
michael@0 100 case GL_REPEAT:
michael@0 101 case GL_CLAMP_TO_EDGE:
michael@0 102 case GL_MIRRORED_REPEAT:
michael@0 103 mSamplerState.wrapT = wrap;
michael@0 104 return true;
michael@0 105 default:
michael@0 106 return false;
michael@0 107 }
michael@0 108 }
michael@0 109
michael@0 110 // Returns true on successful max anisotropy update (valid anisotropy value)
michael@0 111 bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
michael@0 112 {
michael@0 113 textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
michael@0 114 if (textureMaxAnisotropy < 1.0f)
michael@0 115 {
michael@0 116 return false;
michael@0 117 }
michael@0 118
michael@0 119 mSamplerState.maxAnisotropy = textureMaxAnisotropy;
michael@0 120
michael@0 121 return true;
michael@0 122 }
michael@0 123
michael@0 124 // Returns true on successful usage state update (valid enum parameter)
michael@0 125 bool Texture::setUsage(GLenum usage)
michael@0 126 {
michael@0 127 switch (usage)
michael@0 128 {
michael@0 129 case GL_NONE:
michael@0 130 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
michael@0 131 mUsage = usage;
michael@0 132 return true;
michael@0 133 default:
michael@0 134 return false;
michael@0 135 }
michael@0 136 }
michael@0 137
michael@0 138 GLenum Texture::getMinFilter() const
michael@0 139 {
michael@0 140 return mSamplerState.minFilter;
michael@0 141 }
michael@0 142
michael@0 143 GLenum Texture::getMagFilter() const
michael@0 144 {
michael@0 145 return mSamplerState.magFilter;
michael@0 146 }
michael@0 147
michael@0 148 GLenum Texture::getWrapS() const
michael@0 149 {
michael@0 150 return mSamplerState.wrapS;
michael@0 151 }
michael@0 152
michael@0 153 GLenum Texture::getWrapT() const
michael@0 154 {
michael@0 155 return mSamplerState.wrapT;
michael@0 156 }
michael@0 157
michael@0 158 float Texture::getMaxAnisotropy() const
michael@0 159 {
michael@0 160 return mSamplerState.maxAnisotropy;
michael@0 161 }
michael@0 162
michael@0 163 int Texture::getLodOffset()
michael@0 164 {
michael@0 165 rx::TextureStorageInterface *texture = getStorage(false);
michael@0 166 return texture ? texture->getLodOffset() : 0;
michael@0 167 }
michael@0 168
michael@0 169 void Texture::getSamplerState(SamplerState *sampler)
michael@0 170 {
michael@0 171 *sampler = mSamplerState;
michael@0 172 sampler->lodOffset = getLodOffset();
michael@0 173 }
michael@0 174
michael@0 175 GLenum Texture::getUsage() const
michael@0 176 {
michael@0 177 return mUsage;
michael@0 178 }
michael@0 179
michael@0 180 bool Texture::isMipmapFiltered() const
michael@0 181 {
michael@0 182 switch (mSamplerState.minFilter)
michael@0 183 {
michael@0 184 case GL_NEAREST:
michael@0 185 case GL_LINEAR:
michael@0 186 return false;
michael@0 187 case GL_NEAREST_MIPMAP_NEAREST:
michael@0 188 case GL_LINEAR_MIPMAP_NEAREST:
michael@0 189 case GL_NEAREST_MIPMAP_LINEAR:
michael@0 190 case GL_LINEAR_MIPMAP_LINEAR:
michael@0 191 return true;
michael@0 192 default: UNREACHABLE();
michael@0 193 return false;
michael@0 194 }
michael@0 195 }
michael@0 196
michael@0 197 void Texture::setImage(GLint unpackAlignment, const void *pixels, rx::Image *image)
michael@0 198 {
michael@0 199 if (pixels != NULL)
michael@0 200 {
michael@0 201 image->loadData(0, 0, image->getWidth(), image->getHeight(), unpackAlignment, pixels);
michael@0 202 mDirtyImages = true;
michael@0 203 }
michael@0 204 }
michael@0 205
michael@0 206 void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
michael@0 207 {
michael@0 208 if (pixels != NULL)
michael@0 209 {
michael@0 210 image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels);
michael@0 211 mDirtyImages = true;
michael@0 212 }
michael@0 213 }
michael@0 214
michael@0 215 bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, rx::Image *image)
michael@0 216 {
michael@0 217 if (pixels != NULL)
michael@0 218 {
michael@0 219 image->loadData(xoffset, yoffset, width, height, unpackAlignment, pixels);
michael@0 220 mDirtyImages = true;
michael@0 221 }
michael@0 222
michael@0 223 return true;
michael@0 224 }
michael@0 225
michael@0 226 bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
michael@0 227 {
michael@0 228 if (pixels != NULL)
michael@0 229 {
michael@0 230 image->loadCompressedData(xoffset, yoffset, width, height, pixels);
michael@0 231 mDirtyImages = true;
michael@0 232 }
michael@0 233
michael@0 234 return true;
michael@0 235 }
michael@0 236
michael@0 237 rx::TextureStorageInterface *Texture::getNativeTexture()
michael@0 238 {
michael@0 239 // ensure the underlying texture is created
michael@0 240
michael@0 241 rx::TextureStorageInterface *storage = getStorage(false);
michael@0 242 if (storage)
michael@0 243 {
michael@0 244 updateTexture();
michael@0 245 }
michael@0 246
michael@0 247 return storage;
michael@0 248 }
michael@0 249
michael@0 250 bool Texture::hasDirtyImages() const
michael@0 251 {
michael@0 252 return mDirtyImages;
michael@0 253 }
michael@0 254
michael@0 255 void Texture::resetDirty()
michael@0 256 {
michael@0 257 mDirtyImages = false;
michael@0 258 }
michael@0 259
michael@0 260 unsigned int Texture::getTextureSerial()
michael@0 261 {
michael@0 262 rx::TextureStorageInterface *texture = getStorage(false);
michael@0 263 return texture ? texture->getTextureSerial() : 0;
michael@0 264 }
michael@0 265
michael@0 266 unsigned int Texture::getRenderTargetSerial(GLenum target)
michael@0 267 {
michael@0 268 rx::TextureStorageInterface *texture = getStorage(true);
michael@0 269 return texture ? texture->getRenderTargetSerial(target) : 0;
michael@0 270 }
michael@0 271
michael@0 272 bool Texture::isImmutable() const
michael@0 273 {
michael@0 274 return mImmutable;
michael@0 275 }
michael@0 276
michael@0 277 GLint Texture::creationLevels(GLsizei width, GLsizei height) const
michael@0 278 {
michael@0 279 if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
michael@0 280 {
michael@0 281 return 0; // Maximum number of levels
michael@0 282 }
michael@0 283 else
michael@0 284 {
michael@0 285 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
michael@0 286 return 1;
michael@0 287 }
michael@0 288 }
michael@0 289
michael@0 290 GLint Texture::creationLevels(GLsizei size) const
michael@0 291 {
michael@0 292 return creationLevels(size, size);
michael@0 293 }
michael@0 294
michael@0 295 Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
michael@0 296 {
michael@0 297 mTexStorage = NULL;
michael@0 298 mSurface = NULL;
michael@0 299 mColorbufferProxy = NULL;
michael@0 300 mProxyRefs = 0;
michael@0 301
michael@0 302 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
michael@0 303 {
michael@0 304 mImageArray[i] = renderer->createImage();
michael@0 305 }
michael@0 306 }
michael@0 307
michael@0 308 Texture2D::~Texture2D()
michael@0 309 {
michael@0 310 mColorbufferProxy = NULL;
michael@0 311
michael@0 312 delete mTexStorage;
michael@0 313 mTexStorage = NULL;
michael@0 314
michael@0 315 if (mSurface)
michael@0 316 {
michael@0 317 mSurface->setBoundTexture(NULL);
michael@0 318 mSurface = NULL;
michael@0 319 }
michael@0 320
michael@0 321 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
michael@0 322 {
michael@0 323 delete mImageArray[i];
michael@0 324 }
michael@0 325 }
michael@0 326
michael@0 327 // We need to maintain a count of references to renderbuffers acting as
michael@0 328 // proxies for this texture, so that we do not attempt to use a pointer
michael@0 329 // to a renderbuffer proxy which has been deleted.
michael@0 330 void Texture2D::addProxyRef(const Renderbuffer *proxy)
michael@0 331 {
michael@0 332 mProxyRefs++;
michael@0 333 }
michael@0 334
michael@0 335 void Texture2D::releaseProxy(const Renderbuffer *proxy)
michael@0 336 {
michael@0 337 if (mProxyRefs > 0)
michael@0 338 mProxyRefs--;
michael@0 339
michael@0 340 if (mProxyRefs == 0)
michael@0 341 mColorbufferProxy = NULL;
michael@0 342 }
michael@0 343
michael@0 344 GLenum Texture2D::getTarget() const
michael@0 345 {
michael@0 346 return GL_TEXTURE_2D;
michael@0 347 }
michael@0 348
michael@0 349 GLsizei Texture2D::getWidth(GLint level) const
michael@0 350 {
michael@0 351 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
michael@0 352 return mImageArray[level]->getWidth();
michael@0 353 else
michael@0 354 return 0;
michael@0 355 }
michael@0 356
michael@0 357 GLsizei Texture2D::getHeight(GLint level) const
michael@0 358 {
michael@0 359 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
michael@0 360 return mImageArray[level]->getHeight();
michael@0 361 else
michael@0 362 return 0;
michael@0 363 }
michael@0 364
michael@0 365 GLenum Texture2D::getInternalFormat(GLint level) const
michael@0 366 {
michael@0 367 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
michael@0 368 return mImageArray[level]->getInternalFormat();
michael@0 369 else
michael@0 370 return GL_NONE;
michael@0 371 }
michael@0 372
michael@0 373 GLenum Texture2D::getActualFormat(GLint level) const
michael@0 374 {
michael@0 375 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
michael@0 376 return mImageArray[level]->getActualFormat();
michael@0 377 else
michael@0 378 return D3DFMT_UNKNOWN;
michael@0 379 }
michael@0 380
michael@0 381 void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
michael@0 382 {
michael@0 383 releaseTexImage();
michael@0 384
michael@0 385 // If there currently is a corresponding storage texture image, it has these parameters
michael@0 386 const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
michael@0 387 const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
michael@0 388 const int storageFormat = mImageArray[0]->getInternalFormat();
michael@0 389
michael@0 390 mImageArray[level]->redefine(mRenderer, internalformat, width, height, false);
michael@0 391
michael@0 392 if (mTexStorage)
michael@0 393 {
michael@0 394 const int storageLevels = mTexStorage->levelCount();
michael@0 395
michael@0 396 if ((level >= storageLevels && storageLevels != 0) ||
michael@0 397 width != storageWidth ||
michael@0 398 height != storageHeight ||
michael@0 399 internalformat != storageFormat) // Discard mismatched storage
michael@0 400 {
michael@0 401 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
michael@0 402 {
michael@0 403 mImageArray[i]->markDirty();
michael@0 404 }
michael@0 405
michael@0 406 delete mTexStorage;
michael@0 407 mTexStorage = NULL;
michael@0 408 mDirtyImages = true;
michael@0 409 }
michael@0 410 }
michael@0 411 }
michael@0 412
michael@0 413 void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
michael@0 414 {
michael@0 415 GLint internalformat = ConvertSizedInternalFormat(format, type);
michael@0 416 redefineImage(level, internalformat, width, height);
michael@0 417
michael@0 418 Texture::setImage(unpackAlignment, pixels, mImageArray[level]);
michael@0 419 }
michael@0 420
michael@0 421 void Texture2D::bindTexImage(egl::Surface *surface)
michael@0 422 {
michael@0 423 releaseTexImage();
michael@0 424
michael@0 425 GLint internalformat = surface->getFormat();
michael@0 426
michael@0 427 mImageArray[0]->redefine(mRenderer, internalformat, surface->getWidth(), surface->getHeight(), true);
michael@0 428
michael@0 429 delete mTexStorage;
michael@0 430 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
michael@0 431
michael@0 432 mDirtyImages = true;
michael@0 433 mSurface = surface;
michael@0 434 mSurface->setBoundTexture(this);
michael@0 435 }
michael@0 436
michael@0 437 void Texture2D::releaseTexImage()
michael@0 438 {
michael@0 439 if (mSurface)
michael@0 440 {
michael@0 441 mSurface->setBoundTexture(NULL);
michael@0 442 mSurface = NULL;
michael@0 443
michael@0 444 if (mTexStorage)
michael@0 445 {
michael@0 446 delete mTexStorage;
michael@0 447 mTexStorage = NULL;
michael@0 448 }
michael@0 449
michael@0 450 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
michael@0 451 {
michael@0 452 mImageArray[i]->redefine(mRenderer, GL_NONE, 0, 0, true);
michael@0 453 }
michael@0 454 }
michael@0 455 }
michael@0 456
michael@0 457 void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
michael@0 458 {
michael@0 459 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
michael@0 460 redefineImage(level, format, width, height);
michael@0 461
michael@0 462 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
michael@0 463 }
michael@0 464
michael@0 465 void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
michael@0 466 {
michael@0 467 if (level < levelCount())
michael@0 468 {
michael@0 469 rx::Image *image = mImageArray[level];
michael@0 470 if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
michael@0 471 {
michael@0 472 image->markClean();
michael@0 473 }
michael@0 474 }
michael@0 475 }
michael@0 476
michael@0 477 void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
michael@0 478 {
michael@0 479 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, mImageArray[level]))
michael@0 480 {
michael@0 481 commitRect(level, xoffset, yoffset, width, height);
michael@0 482 }
michael@0 483 }
michael@0 484
michael@0 485 void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
michael@0 486 {
michael@0 487 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, mImageArray[level]))
michael@0 488 {
michael@0 489 commitRect(level, xoffset, yoffset, width, height);
michael@0 490 }
michael@0 491 }
michael@0 492
michael@0 493 void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
michael@0 494 {
michael@0 495 GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
michael@0 496 redefineImage(level, internalformat, width, height);
michael@0 497
michael@0 498 if (!mImageArray[level]->isRenderableFormat())
michael@0 499 {
michael@0 500 mImageArray[level]->copy(0, 0, x, y, width, height, source);
michael@0 501 mDirtyImages = true;
michael@0 502 }
michael@0 503 else
michael@0 504 {
michael@0 505 if (!mTexStorage || !mTexStorage->isRenderTarget())
michael@0 506 {
michael@0 507 convertToRenderTarget();
michael@0 508 }
michael@0 509
michael@0 510 mImageArray[level]->markClean();
michael@0 511
michael@0 512 if (width != 0 && height != 0 && level < levelCount())
michael@0 513 {
michael@0 514 gl::Rectangle sourceRect;
michael@0 515 sourceRect.x = x;
michael@0 516 sourceRect.width = width;
michael@0 517 sourceRect.y = y;
michael@0 518 sourceRect.height = height;
michael@0 519
michael@0 520 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
michael@0 521 }
michael@0 522 }
michael@0 523 }
michael@0 524
michael@0 525 void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
michael@0 526 {
michael@0 527 if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight())
michael@0 528 {
michael@0 529 return gl::error(GL_INVALID_VALUE);
michael@0 530 }
michael@0 531
michael@0 532 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
michael@0 533 {
michael@0 534 mImageArray[level]->copy(xoffset, yoffset, x, y, width, height, source);
michael@0 535 mDirtyImages = true;
michael@0 536 }
michael@0 537 else
michael@0 538 {
michael@0 539 if (!mTexStorage || !mTexStorage->isRenderTarget())
michael@0 540 {
michael@0 541 convertToRenderTarget();
michael@0 542 }
michael@0 543
michael@0 544 updateTexture();
michael@0 545
michael@0 546 if (level < levelCount())
michael@0 547 {
michael@0 548 gl::Rectangle sourceRect;
michael@0 549 sourceRect.x = x;
michael@0 550 sourceRect.width = width;
michael@0 551 sourceRect.y = y;
michael@0 552 sourceRect.height = height;
michael@0 553
michael@0 554 mRenderer->copyImage(source, sourceRect,
michael@0 555 gl::ExtractFormat(mImageArray[0]->getInternalFormat()),
michael@0 556 xoffset, yoffset, mTexStorage, level);
michael@0 557 }
michael@0 558 }
michael@0 559 }
michael@0 560
michael@0 561 void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
michael@0 562 {
michael@0 563 delete mTexStorage;
michael@0 564 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
michael@0 565 mImmutable = true;
michael@0 566
michael@0 567 for (int level = 0; level < levels; level++)
michael@0 568 {
michael@0 569 mImageArray[level]->redefine(mRenderer, internalformat, width, height, true);
michael@0 570 width = std::max(1, width >> 1);
michael@0 571 height = std::max(1, height >> 1);
michael@0 572 }
michael@0 573
michael@0 574 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
michael@0 575 {
michael@0 576 mImageArray[level]->redefine(mRenderer, GL_NONE, 0, 0, true);
michael@0 577 }
michael@0 578
michael@0 579 if (mTexStorage->isManaged())
michael@0 580 {
michael@0 581 int levels = levelCount();
michael@0 582
michael@0 583 for (int level = 0; level < levels; level++)
michael@0 584 {
michael@0 585 mImageArray[level]->setManagedSurface(mTexStorage, level);
michael@0 586 }
michael@0 587 }
michael@0 588 }
michael@0 589
michael@0 590 // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
michael@0 591 bool Texture2D::isSamplerComplete() const
michael@0 592 {
michael@0 593 GLsizei width = mImageArray[0]->getWidth();
michael@0 594 GLsizei height = mImageArray[0]->getHeight();
michael@0 595
michael@0 596 if (width <= 0 || height <= 0)
michael@0 597 {
michael@0 598 return false;
michael@0 599 }
michael@0 600
michael@0 601 bool mipmapping = isMipmapFiltered();
michael@0 602 bool filtering, renderable;
michael@0 603
michael@0 604 if ((IsFloat32Format(getInternalFormat(0)) && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
michael@0 605 (IsFloat16Format(getInternalFormat(0)) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
michael@0 606 {
michael@0 607 if (mSamplerState.magFilter != GL_NEAREST ||
michael@0 608 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
michael@0 609 {
michael@0 610 return false;
michael@0 611 }
michael@0 612 }
michael@0 613
michael@0 614 bool npotSupport = mRenderer->getNonPower2TextureSupport();
michael@0 615
michael@0 616 if (!npotSupport)
michael@0 617 {
michael@0 618 if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
michael@0 619 (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
michael@0 620 {
michael@0 621 return false;
michael@0 622 }
michael@0 623 }
michael@0 624
michael@0 625 if (mipmapping)
michael@0 626 {
michael@0 627 if (!npotSupport)
michael@0 628 {
michael@0 629 if (!isPow2(width) || !isPow2(height))
michael@0 630 {
michael@0 631 return false;
michael@0 632 }
michael@0 633 }
michael@0 634
michael@0 635 if (!isMipmapComplete())
michael@0 636 {
michael@0 637 return false;
michael@0 638 }
michael@0 639 }
michael@0 640
michael@0 641 return true;
michael@0 642 }
michael@0 643
michael@0 644 // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
michael@0 645 bool Texture2D::isMipmapComplete() const
michael@0 646 {
michael@0 647 if (isImmutable())
michael@0 648 {
michael@0 649 return true;
michael@0 650 }
michael@0 651
michael@0 652 GLsizei width = mImageArray[0]->getWidth();
michael@0 653 GLsizei height = mImageArray[0]->getHeight();
michael@0 654
michael@0 655 if (width <= 0 || height <= 0)
michael@0 656 {
michael@0 657 return false;
michael@0 658 }
michael@0 659
michael@0 660 int q = log2(std::max(width, height));
michael@0 661
michael@0 662 for (int level = 1; level <= q; level++)
michael@0 663 {
michael@0 664 if (mImageArray[level]->getInternalFormat() != mImageArray[0]->getInternalFormat())
michael@0 665 {
michael@0 666 return false;
michael@0 667 }
michael@0 668
michael@0 669 if (mImageArray[level]->getWidth() != std::max(1, width >> level))
michael@0 670 {
michael@0 671 return false;
michael@0 672 }
michael@0 673
michael@0 674 if (mImageArray[level]->getHeight() != std::max(1, height >> level))
michael@0 675 {
michael@0 676 return false;
michael@0 677 }
michael@0 678 }
michael@0 679
michael@0 680 return true;
michael@0 681 }
michael@0 682
michael@0 683 bool Texture2D::isCompressed(GLint level) const
michael@0 684 {
michael@0 685 return IsCompressed(getInternalFormat(level));
michael@0 686 }
michael@0 687
michael@0 688 bool Texture2D::isDepth(GLint level) const
michael@0 689 {
michael@0 690 return IsDepthTexture(getInternalFormat(level));
michael@0 691 }
michael@0 692
michael@0 693 // Constructs a native texture resource from the texture images
michael@0 694 void Texture2D::createTexture()
michael@0 695 {
michael@0 696 GLsizei width = mImageArray[0]->getWidth();
michael@0 697 GLsizei height = mImageArray[0]->getHeight();
michael@0 698
michael@0 699 if (!(width > 0 && height > 0))
michael@0 700 return; // do not attempt to create native textures for nonexistant data
michael@0 701
michael@0 702 GLint levels = creationLevels(width, height);
michael@0 703 GLenum internalformat = mImageArray[0]->getInternalFormat();
michael@0 704
michael@0 705 delete mTexStorage;
michael@0 706 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
michael@0 707
michael@0 708 if (mTexStorage->isManaged())
michael@0 709 {
michael@0 710 int levels = levelCount();
michael@0 711
michael@0 712 for (int level = 0; level < levels; level++)
michael@0 713 {
michael@0 714 mImageArray[level]->setManagedSurface(mTexStorage, level);
michael@0 715 }
michael@0 716 }
michael@0 717
michael@0 718 mDirtyImages = true;
michael@0 719 }
michael@0 720
michael@0 721 void Texture2D::updateTexture()
michael@0 722 {
michael@0 723 bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
michael@0 724
michael@0 725 int levels = (mipmapping ? levelCount() : 1);
michael@0 726
michael@0 727 for (int level = 0; level < levels; level++)
michael@0 728 {
michael@0 729 rx::Image *image = mImageArray[level];
michael@0 730
michael@0 731 if (image->isDirty())
michael@0 732 {
michael@0 733 commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
michael@0 734 }
michael@0 735 }
michael@0 736 }
michael@0 737
michael@0 738 void Texture2D::convertToRenderTarget()
michael@0 739 {
michael@0 740 rx::TextureStorageInterface2D *newTexStorage = NULL;
michael@0 741
michael@0 742 if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0)
michael@0 743 {
michael@0 744 GLsizei width = mImageArray[0]->getWidth();
michael@0 745 GLsizei height = mImageArray[0]->getHeight();
michael@0 746 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
michael@0 747 GLenum internalformat = mImageArray[0]->getInternalFormat();
michael@0 748
michael@0 749 newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
michael@0 750
michael@0 751 if (mTexStorage != NULL)
michael@0 752 {
michael@0 753 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
michael@0 754 {
michael@0 755 delete newTexStorage;
michael@0 756 return gl::error(GL_OUT_OF_MEMORY);
michael@0 757 }
michael@0 758 }
michael@0 759 }
michael@0 760
michael@0 761 delete mTexStorage;
michael@0 762 mTexStorage = newTexStorage;
michael@0 763
michael@0 764 mDirtyImages = true;
michael@0 765 }
michael@0 766
michael@0 767 void Texture2D::generateMipmaps()
michael@0 768 {
michael@0 769 if (!mRenderer->getNonPower2TextureSupport())
michael@0 770 {
michael@0 771 if (!isPow2(mImageArray[0]->getWidth()) || !isPow2(mImageArray[0]->getHeight()))
michael@0 772 {
michael@0 773 return gl::error(GL_INVALID_OPERATION);
michael@0 774 }
michael@0 775 }
michael@0 776
michael@0 777 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
michael@0 778 unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
michael@0 779 for (unsigned int i = 1; i <= q; i++)
michael@0 780 {
michael@0 781 redefineImage(i, mImageArray[0]->getInternalFormat(),
michael@0 782 std::max(mImageArray[0]->getWidth() >> i, 1),
michael@0 783 std::max(mImageArray[0]->getHeight() >> i, 1));
michael@0 784 }
michael@0 785
michael@0 786 if (mTexStorage && mTexStorage->isRenderTarget())
michael@0 787 {
michael@0 788 for (unsigned int i = 1; i <= q; i++)
michael@0 789 {
michael@0 790 mTexStorage->generateMipmap(i);
michael@0 791
michael@0 792 mImageArray[i]->markClean();
michael@0 793 }
michael@0 794 }
michael@0 795 else
michael@0 796 {
michael@0 797 for (unsigned int i = 1; i <= q; i++)
michael@0 798 {
michael@0 799 mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
michael@0 800 }
michael@0 801 }
michael@0 802 }
michael@0 803
michael@0 804 Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
michael@0 805 {
michael@0 806 if (target != GL_TEXTURE_2D)
michael@0 807 {
michael@0 808 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
michael@0 809 }
michael@0 810
michael@0 811 if (mColorbufferProxy == NULL)
michael@0 812 {
michael@0 813 mColorbufferProxy = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, target));
michael@0 814 }
michael@0 815
michael@0 816 return mColorbufferProxy;
michael@0 817 }
michael@0 818
michael@0 819 rx::RenderTarget *Texture2D::getRenderTarget(GLenum target)
michael@0 820 {
michael@0 821 ASSERT(target == GL_TEXTURE_2D);
michael@0 822
michael@0 823 // ensure the underlying texture is created
michael@0 824 if (getStorage(true) == NULL)
michael@0 825 {
michael@0 826 return NULL;
michael@0 827 }
michael@0 828
michael@0 829 updateTexture();
michael@0 830
michael@0 831 // ensure this is NOT a depth texture
michael@0 832 if (isDepth(0))
michael@0 833 {
michael@0 834 return NULL;
michael@0 835 }
michael@0 836
michael@0 837 return mTexStorage->getRenderTarget();
michael@0 838 }
michael@0 839
michael@0 840 rx::RenderTarget *Texture2D::getDepthStencil(GLenum target)
michael@0 841 {
michael@0 842 ASSERT(target == GL_TEXTURE_2D);
michael@0 843
michael@0 844 // ensure the underlying texture is created
michael@0 845 if (getStorage(true) == NULL)
michael@0 846 {
michael@0 847 return NULL;
michael@0 848 }
michael@0 849
michael@0 850 updateTexture();
michael@0 851
michael@0 852 // ensure this is actually a depth texture
michael@0 853 if (!isDepth(0))
michael@0 854 {
michael@0 855 return NULL;
michael@0 856 }
michael@0 857 return mTexStorage->getRenderTarget();
michael@0 858 }
michael@0 859
michael@0 860 int Texture2D::levelCount()
michael@0 861 {
michael@0 862 return mTexStorage ? mTexStorage->levelCount() : 0;
michael@0 863 }
michael@0 864
michael@0 865 rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
michael@0 866 {
michael@0 867 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
michael@0 868 {
michael@0 869 if (renderTarget)
michael@0 870 {
michael@0 871 convertToRenderTarget();
michael@0 872 }
michael@0 873 else
michael@0 874 {
michael@0 875 createTexture();
michael@0 876 }
michael@0 877 }
michael@0 878
michael@0 879 return mTexStorage;
michael@0 880 }
michael@0 881
michael@0 882 TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
michael@0 883 {
michael@0 884 mTexStorage = NULL;
michael@0 885 for (int i = 0; i < 6; i++)
michael@0 886 {
michael@0 887 mFaceProxies[i] = NULL;
michael@0 888 mFaceProxyRefs[i] = 0;
michael@0 889
michael@0 890 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
michael@0 891 {
michael@0 892 mImageArray[i][j] = renderer->createImage();
michael@0 893 }
michael@0 894 }
michael@0 895 }
michael@0 896
michael@0 897 TextureCubeMap::~TextureCubeMap()
michael@0 898 {
michael@0 899 for (int i = 0; i < 6; i++)
michael@0 900 {
michael@0 901 mFaceProxies[i] = NULL;
michael@0 902
michael@0 903 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
michael@0 904 {
michael@0 905 delete mImageArray[i][j];
michael@0 906 }
michael@0 907 }
michael@0 908
michael@0 909 delete mTexStorage;
michael@0 910 mTexStorage = NULL;
michael@0 911 }
michael@0 912
michael@0 913 // We need to maintain a count of references to renderbuffers acting as
michael@0 914 // proxies for this texture, so that the texture is not deleted while
michael@0 915 // proxy references still exist. If the reference count drops to zero,
michael@0 916 // we set our proxy pointer NULL, so that a new attempt at referencing
michael@0 917 // will cause recreation.
michael@0 918 void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
michael@0 919 {
michael@0 920 for (int i = 0; i < 6; i++)
michael@0 921 {
michael@0 922 if (mFaceProxies[i] == proxy)
michael@0 923 mFaceProxyRefs[i]++;
michael@0 924 }
michael@0 925 }
michael@0 926
michael@0 927 void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
michael@0 928 {
michael@0 929 for (int i = 0; i < 6; i++)
michael@0 930 {
michael@0 931 if (mFaceProxies[i] == proxy)
michael@0 932 {
michael@0 933 if (mFaceProxyRefs[i] > 0)
michael@0 934 mFaceProxyRefs[i]--;
michael@0 935
michael@0 936 if (mFaceProxyRefs[i] == 0)
michael@0 937 mFaceProxies[i] = NULL;
michael@0 938 }
michael@0 939 }
michael@0 940 }
michael@0 941
michael@0 942 GLenum TextureCubeMap::getTarget() const
michael@0 943 {
michael@0 944 return GL_TEXTURE_CUBE_MAP;
michael@0 945 }
michael@0 946
michael@0 947 GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
michael@0 948 {
michael@0 949 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
michael@0 950 return mImageArray[faceIndex(target)][level]->getWidth();
michael@0 951 else
michael@0 952 return 0;
michael@0 953 }
michael@0 954
michael@0 955 GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
michael@0 956 {
michael@0 957 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
michael@0 958 return mImageArray[faceIndex(target)][level]->getHeight();
michael@0 959 else
michael@0 960 return 0;
michael@0 961 }
michael@0 962
michael@0 963 GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
michael@0 964 {
michael@0 965 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
michael@0 966 return mImageArray[faceIndex(target)][level]->getInternalFormat();
michael@0 967 else
michael@0 968 return GL_NONE;
michael@0 969 }
michael@0 970
michael@0 971 GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
michael@0 972 {
michael@0 973 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
michael@0 974 return mImageArray[faceIndex(target)][level]->getActualFormat();
michael@0 975 else
michael@0 976 return D3DFMT_UNKNOWN;
michael@0 977 }
michael@0 978
michael@0 979 void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
michael@0 980 {
michael@0 981 setImage(0, level, width, height, format, type, unpackAlignment, pixels);
michael@0 982 }
michael@0 983
michael@0 984 void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
michael@0 985 {
michael@0 986 setImage(1, level, width, height, format, type, unpackAlignment, pixels);
michael@0 987 }
michael@0 988
michael@0 989 void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
michael@0 990 {
michael@0 991 setImage(2, level, width, height, format, type, unpackAlignment, pixels);
michael@0 992 }
michael@0 993
michael@0 994 void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
michael@0 995 {
michael@0 996 setImage(3, level, width, height, format, type, unpackAlignment, pixels);
michael@0 997 }
michael@0 998
michael@0 999 void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
michael@0 1000 {
michael@0 1001 setImage(4, level, width, height, format, type, unpackAlignment, pixels);
michael@0 1002 }
michael@0 1003
michael@0 1004 void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
michael@0 1005 {
michael@0 1006 setImage(5, level, width, height, format, type, unpackAlignment, pixels);
michael@0 1007 }
michael@0 1008
michael@0 1009 void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
michael@0 1010 {
michael@0 1011 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
michael@0 1012 redefineImage(faceIndex(face), level, format, width, height);
michael@0 1013
michael@0 1014 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
michael@0 1015 }
michael@0 1016
michael@0 1017 void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
michael@0 1018 {
michael@0 1019 if (level < levelCount())
michael@0 1020 {
michael@0 1021 rx::Image *image = mImageArray[face][level];
michael@0 1022 if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
michael@0 1023 image->markClean();
michael@0 1024 }
michael@0 1025 }
michael@0 1026
michael@0 1027 void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
michael@0 1028 {
michael@0 1029 if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, mImageArray[faceIndex(target)][level]))
michael@0 1030 {
michael@0 1031 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
michael@0 1032 }
michael@0 1033 }
michael@0 1034
michael@0 1035 void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
michael@0 1036 {
michael@0 1037 if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
michael@0 1038 {
michael@0 1039 commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
michael@0 1040 }
michael@0 1041 }
michael@0 1042
michael@0 1043 // Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
michael@0 1044 bool TextureCubeMap::isSamplerComplete() const
michael@0 1045 {
michael@0 1046 int size = mImageArray[0][0]->getWidth();
michael@0 1047
michael@0 1048 bool mipmapping = isMipmapFiltered();
michael@0 1049 bool filtering, renderable;
michael@0 1050
michael@0 1051 if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
michael@0 1052 (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
michael@0 1053 {
michael@0 1054 if (mSamplerState.magFilter != GL_NEAREST ||
michael@0 1055 (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
michael@0 1056 {
michael@0 1057 return false;
michael@0 1058 }
michael@0 1059 }
michael@0 1060
michael@0 1061 if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
michael@0 1062 {
michael@0 1063 if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
michael@0 1064 {
michael@0 1065 return false;
michael@0 1066 }
michael@0 1067 }
michael@0 1068
michael@0 1069 if (!mipmapping)
michael@0 1070 {
michael@0 1071 if (!isCubeComplete())
michael@0 1072 {
michael@0 1073 return false;
michael@0 1074 }
michael@0 1075 }
michael@0 1076 else
michael@0 1077 {
michael@0 1078 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
michael@0 1079 {
michael@0 1080 return false;
michael@0 1081 }
michael@0 1082 }
michael@0 1083
michael@0 1084 return true;
michael@0 1085 }
michael@0 1086
michael@0 1087 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
michael@0 1088 bool TextureCubeMap::isCubeComplete() const
michael@0 1089 {
michael@0 1090 if (mImageArray[0][0]->getWidth() <= 0 || mImageArray[0][0]->getHeight() != mImageArray[0][0]->getWidth())
michael@0 1091 {
michael@0 1092 return false;
michael@0 1093 }
michael@0 1094
michael@0 1095 for (unsigned int face = 1; face < 6; face++)
michael@0 1096 {
michael@0 1097 if (mImageArray[face][0]->getWidth() != mImageArray[0][0]->getWidth() ||
michael@0 1098 mImageArray[face][0]->getWidth() != mImageArray[0][0]->getHeight() ||
michael@0 1099 mImageArray[face][0]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
michael@0 1100 {
michael@0 1101 return false;
michael@0 1102 }
michael@0 1103 }
michael@0 1104
michael@0 1105 return true;
michael@0 1106 }
michael@0 1107
michael@0 1108 bool TextureCubeMap::isMipmapCubeComplete() const
michael@0 1109 {
michael@0 1110 if (isImmutable())
michael@0 1111 {
michael@0 1112 return true;
michael@0 1113 }
michael@0 1114
michael@0 1115 if (!isCubeComplete())
michael@0 1116 {
michael@0 1117 return false;
michael@0 1118 }
michael@0 1119
michael@0 1120 GLsizei size = mImageArray[0][0]->getWidth();
michael@0 1121
michael@0 1122 int q = log2(size);
michael@0 1123
michael@0 1124 for (int face = 0; face < 6; face++)
michael@0 1125 {
michael@0 1126 for (int level = 1; level <= q; level++)
michael@0 1127 {
michael@0 1128 if (mImageArray[face][level]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
michael@0 1129 {
michael@0 1130 return false;
michael@0 1131 }
michael@0 1132
michael@0 1133 if (mImageArray[face][level]->getWidth() != std::max(1, size >> level))
michael@0 1134 {
michael@0 1135 return false;
michael@0 1136 }
michael@0 1137 }
michael@0 1138 }
michael@0 1139
michael@0 1140 return true;
michael@0 1141 }
michael@0 1142
michael@0 1143 bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
michael@0 1144 {
michael@0 1145 return IsCompressed(getInternalFormat(target, level));
michael@0 1146 }
michael@0 1147
michael@0 1148 // Constructs a native texture resource from the texture images, or returns an existing one
michael@0 1149 void TextureCubeMap::createTexture()
michael@0 1150 {
michael@0 1151 GLsizei size = mImageArray[0][0]->getWidth();
michael@0 1152
michael@0 1153 if (!(size > 0))
michael@0 1154 return; // do not attempt to create native textures for nonexistant data
michael@0 1155
michael@0 1156 GLint levels = creationLevels(size);
michael@0 1157 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
michael@0 1158
michael@0 1159 delete mTexStorage;
michael@0 1160 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
michael@0 1161
michael@0 1162 if (mTexStorage->isManaged())
michael@0 1163 {
michael@0 1164 int levels = levelCount();
michael@0 1165
michael@0 1166 for (int face = 0; face < 6; face++)
michael@0 1167 {
michael@0 1168 for (int level = 0; level < levels; level++)
michael@0 1169 {
michael@0 1170 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
michael@0 1171 }
michael@0 1172 }
michael@0 1173 }
michael@0 1174
michael@0 1175 mDirtyImages = true;
michael@0 1176 }
michael@0 1177
michael@0 1178 void TextureCubeMap::updateTexture()
michael@0 1179 {
michael@0 1180 bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete();
michael@0 1181
michael@0 1182 for (int face = 0; face < 6; face++)
michael@0 1183 {
michael@0 1184 int levels = (mipmapping ? levelCount() : 1);
michael@0 1185
michael@0 1186 for (int level = 0; level < levels; level++)
michael@0 1187 {
michael@0 1188 rx::Image *image = mImageArray[face][level];
michael@0 1189
michael@0 1190 if (image->isDirty())
michael@0 1191 {
michael@0 1192 commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
michael@0 1193 }
michael@0 1194 }
michael@0 1195 }
michael@0 1196 }
michael@0 1197
michael@0 1198 void TextureCubeMap::convertToRenderTarget()
michael@0 1199 {
michael@0 1200 rx::TextureStorageInterfaceCube *newTexStorage = NULL;
michael@0 1201
michael@0 1202 if (mImageArray[0][0]->getWidth() != 0)
michael@0 1203 {
michael@0 1204 GLsizei size = mImageArray[0][0]->getWidth();
michael@0 1205 GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
michael@0 1206 GLenum internalformat = mImageArray[0][0]->getInternalFormat();
michael@0 1207
michael@0 1208 newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
michael@0 1209
michael@0 1210 if (mTexStorage != NULL)
michael@0 1211 {
michael@0 1212 if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
michael@0 1213 {
michael@0 1214 delete newTexStorage;
michael@0 1215 return gl::error(GL_OUT_OF_MEMORY);
michael@0 1216 }
michael@0 1217 }
michael@0 1218 }
michael@0 1219
michael@0 1220 delete mTexStorage;
michael@0 1221 mTexStorage = newTexStorage;
michael@0 1222
michael@0 1223 mDirtyImages = true;
michael@0 1224 }
michael@0 1225
michael@0 1226 void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
michael@0 1227 {
michael@0 1228 GLint internalformat = ConvertSizedInternalFormat(format, type);
michael@0 1229 redefineImage(faceIndex, level, internalformat, width, height);
michael@0 1230
michael@0 1231 Texture::setImage(unpackAlignment, pixels, mImageArray[faceIndex][level]);
michael@0 1232 }
michael@0 1233
michael@0 1234 unsigned int TextureCubeMap::faceIndex(GLenum face)
michael@0 1235 {
michael@0 1236 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
michael@0 1237 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
michael@0 1238 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
michael@0 1239 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
michael@0 1240 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
michael@0 1241
michael@0 1242 return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
michael@0 1243 }
michael@0 1244
michael@0 1245 void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
michael@0 1246 {
michael@0 1247 // If there currently is a corresponding storage texture image, it has these parameters
michael@0 1248 const int storageWidth = std::max(1, mImageArray[0][0]->getWidth() >> level);
michael@0 1249 const int storageHeight = std::max(1, mImageArray[0][0]->getHeight() >> level);
michael@0 1250 const int storageFormat = mImageArray[0][0]->getInternalFormat();
michael@0 1251
michael@0 1252 mImageArray[face][level]->redefine(mRenderer, internalformat, width, height, false);
michael@0 1253
michael@0 1254 if (mTexStorage)
michael@0 1255 {
michael@0 1256 const int storageLevels = mTexStorage->levelCount();
michael@0 1257
michael@0 1258 if ((level >= storageLevels && storageLevels != 0) ||
michael@0 1259 width != storageWidth ||
michael@0 1260 height != storageHeight ||
michael@0 1261 internalformat != storageFormat) // Discard mismatched storage
michael@0 1262 {
michael@0 1263 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
michael@0 1264 {
michael@0 1265 for (int f = 0; f < 6; f++)
michael@0 1266 {
michael@0 1267 mImageArray[f][i]->markDirty();
michael@0 1268 }
michael@0 1269 }
michael@0 1270
michael@0 1271 delete mTexStorage;
michael@0 1272 mTexStorage = NULL;
michael@0 1273
michael@0 1274 mDirtyImages = true;
michael@0 1275 }
michael@0 1276 }
michael@0 1277 }
michael@0 1278
michael@0 1279 void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
michael@0 1280 {
michael@0 1281 unsigned int faceindex = faceIndex(target);
michael@0 1282 GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
michael@0 1283 redefineImage(faceindex, level, internalformat, width, height);
michael@0 1284
michael@0 1285 if (!mImageArray[faceindex][level]->isRenderableFormat())
michael@0 1286 {
michael@0 1287 mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source);
michael@0 1288 mDirtyImages = true;
michael@0 1289 }
michael@0 1290 else
michael@0 1291 {
michael@0 1292 if (!mTexStorage || !mTexStorage->isRenderTarget())
michael@0 1293 {
michael@0 1294 convertToRenderTarget();
michael@0 1295 }
michael@0 1296
michael@0 1297 mImageArray[faceindex][level]->markClean();
michael@0 1298
michael@0 1299 ASSERT(width == height);
michael@0 1300
michael@0 1301 if (width > 0 && level < levelCount())
michael@0 1302 {
michael@0 1303 gl::Rectangle sourceRect;
michael@0 1304 sourceRect.x = x;
michael@0 1305 sourceRect.width = width;
michael@0 1306 sourceRect.y = y;
michael@0 1307 sourceRect.height = height;
michael@0 1308
michael@0 1309 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
michael@0 1310 }
michael@0 1311 }
michael@0 1312 }
michael@0 1313
michael@0 1314 void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
michael@0 1315 {
michael@0 1316 GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
michael@0 1317
michael@0 1318 if (xoffset + width > size || yoffset + height > size)
michael@0 1319 {
michael@0 1320 return gl::error(GL_INVALID_VALUE);
michael@0 1321 }
michael@0 1322
michael@0 1323 unsigned int faceindex = faceIndex(target);
michael@0 1324
michael@0 1325 if (!mImageArray[faceindex][level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
michael@0 1326 {
michael@0 1327 mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source);
michael@0 1328 mDirtyImages = true;
michael@0 1329 }
michael@0 1330 else
michael@0 1331 {
michael@0 1332 if (!mTexStorage || !mTexStorage->isRenderTarget())
michael@0 1333 {
michael@0 1334 convertToRenderTarget();
michael@0 1335 }
michael@0 1336
michael@0 1337 updateTexture();
michael@0 1338
michael@0 1339 if (level < levelCount())
michael@0 1340 {
michael@0 1341 gl::Rectangle sourceRect;
michael@0 1342 sourceRect.x = x;
michael@0 1343 sourceRect.width = width;
michael@0 1344 sourceRect.y = y;
michael@0 1345 sourceRect.height = height;
michael@0 1346
michael@0 1347 mRenderer->copyImage(source, sourceRect, gl::ExtractFormat(mImageArray[0][0]->getInternalFormat()),
michael@0 1348 xoffset, yoffset, mTexStorage, target, level);
michael@0 1349 }
michael@0 1350 }
michael@0 1351 }
michael@0 1352
michael@0 1353 void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
michael@0 1354 {
michael@0 1355 delete mTexStorage;
michael@0 1356 mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
michael@0 1357 mImmutable = true;
michael@0 1358
michael@0 1359 for (int level = 0; level < levels; level++)
michael@0 1360 {
michael@0 1361 for (int face = 0; face < 6; face++)
michael@0 1362 {
michael@0 1363 mImageArray[face][level]->redefine(mRenderer, internalformat, size, size, true);
michael@0 1364 size = std::max(1, size >> 1);
michael@0 1365 }
michael@0 1366 }
michael@0 1367
michael@0 1368 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
michael@0 1369 {
michael@0 1370 for (int face = 0; face < 6; face++)
michael@0 1371 {
michael@0 1372 mImageArray[face][level]->redefine(mRenderer, GL_NONE, 0, 0, true);
michael@0 1373 }
michael@0 1374 }
michael@0 1375
michael@0 1376 if (mTexStorage->isManaged())
michael@0 1377 {
michael@0 1378 int levels = levelCount();
michael@0 1379
michael@0 1380 for (int face = 0; face < 6; face++)
michael@0 1381 {
michael@0 1382 for (int level = 0; level < levels; level++)
michael@0 1383 {
michael@0 1384 mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
michael@0 1385 }
michael@0 1386 }
michael@0 1387 }
michael@0 1388 }
michael@0 1389
michael@0 1390 void TextureCubeMap::generateMipmaps()
michael@0 1391 {
michael@0 1392 if (!isCubeComplete())
michael@0 1393 {
michael@0 1394 return gl::error(GL_INVALID_OPERATION);
michael@0 1395 }
michael@0 1396
michael@0 1397 if (!mRenderer->getNonPower2TextureSupport())
michael@0 1398 {
michael@0 1399 if (!isPow2(mImageArray[0][0]->getWidth()))
michael@0 1400 {
michael@0 1401 return gl::error(GL_INVALID_OPERATION);
michael@0 1402 }
michael@0 1403 }
michael@0 1404
michael@0 1405 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
michael@0 1406 unsigned int q = log2(mImageArray[0][0]->getWidth());
michael@0 1407 for (unsigned int f = 0; f < 6; f++)
michael@0 1408 {
michael@0 1409 for (unsigned int i = 1; i <= q; i++)
michael@0 1410 {
michael@0 1411 redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
michael@0 1412 std::max(mImageArray[f][0]->getWidth() >> i, 1),
michael@0 1413 std::max(mImageArray[f][0]->getWidth() >> i, 1));
michael@0 1414 }
michael@0 1415 }
michael@0 1416
michael@0 1417 if (mTexStorage && mTexStorage->isRenderTarget())
michael@0 1418 {
michael@0 1419 for (unsigned int f = 0; f < 6; f++)
michael@0 1420 {
michael@0 1421 for (unsigned int i = 1; i <= q; i++)
michael@0 1422 {
michael@0 1423 mTexStorage->generateMipmap(f, i);
michael@0 1424
michael@0 1425 mImageArray[f][i]->markClean();
michael@0 1426 }
michael@0 1427 }
michael@0 1428 }
michael@0 1429 else
michael@0 1430 {
michael@0 1431 for (unsigned int f = 0; f < 6; f++)
michael@0 1432 {
michael@0 1433 for (unsigned int i = 1; i <= q; i++)
michael@0 1434 {
michael@0 1435 mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
michael@0 1436 }
michael@0 1437 }
michael@0 1438 }
michael@0 1439 }
michael@0 1440
michael@0 1441 Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
michael@0 1442 {
michael@0 1443 if (!IsCubemapTextureTarget(target))
michael@0 1444 {
michael@0 1445 return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
michael@0 1446 }
michael@0 1447
michael@0 1448 unsigned int face = faceIndex(target);
michael@0 1449
michael@0 1450 if (mFaceProxies[face] == NULL)
michael@0 1451 {
michael@0 1452 mFaceProxies[face] = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target));
michael@0 1453 }
michael@0 1454
michael@0 1455 return mFaceProxies[face];
michael@0 1456 }
michael@0 1457
michael@0 1458 rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target)
michael@0 1459 {
michael@0 1460 ASSERT(IsCubemapTextureTarget(target));
michael@0 1461
michael@0 1462 // ensure the underlying texture is created
michael@0 1463 if (getStorage(true) == NULL)
michael@0 1464 {
michael@0 1465 return NULL;
michael@0 1466 }
michael@0 1467
michael@0 1468 updateTexture();
michael@0 1469
michael@0 1470 return mTexStorage->getRenderTarget(target);
michael@0 1471 }
michael@0 1472
michael@0 1473 int TextureCubeMap::levelCount()
michael@0 1474 {
michael@0 1475 return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
michael@0 1476 }
michael@0 1477
michael@0 1478 rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
michael@0 1479 {
michael@0 1480 if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
michael@0 1481 {
michael@0 1482 if (renderTarget)
michael@0 1483 {
michael@0 1484 convertToRenderTarget();
michael@0 1485 }
michael@0 1486 else
michael@0 1487 {
michael@0 1488 createTexture();
michael@0 1489 }
michael@0 1490 }
michael@0 1491
michael@0 1492 return mTexStorage;
michael@0 1493 }
michael@0 1494
michael@0 1495 }

mercurial