1 // 2 // Copyright 2014 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends. 8 9 #include "libGLESv2/renderer/d3d/TextureD3D.h" 10 #include "libGLESv2/renderer/d3d/TextureStorage.h" 11 #include "libGLESv2/renderer/d3d/ImageD3D.h" 12 #include "libGLESv2/Buffer.h" 13 #include "libGLESv2/Framebuffer.h" 14 #include "libGLESv2/Texture.h" 15 #include "libGLESv2/main.h" 16 #include "libGLESv2/formatutils.h" 17 #include "libGLESv2/renderer/BufferImpl.h" 18 #include "libGLESv2/renderer/RenderTarget.h" 19 #include "libGLESv2/renderer/Renderer.h" 20 21 #include "libEGL/Surface.h" 22 23 #include "common/mathutil.h" 24 #include "common/utilities.h" 25 26 namespace rx 27 { 28 29 bool IsRenderTargetUsage(GLenum usage) 30 { 31 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); 32 } 33 34 TextureD3D::TextureD3D(Renderer *renderer) 35 : mRenderer(renderer), 36 mUsage(GL_NONE), 37 mDirtyImages(true), 38 mImmutable(false) 39 { 40 } 41 42 TextureD3D::~TextureD3D() 43 { 44 } 45 46 TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture) 47 { 48 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture)); 49 return static_cast<TextureD3D*>(texture); 50 } 51 52 TextureStorage *TextureD3D::getNativeTexture() 53 { 54 // ensure the underlying texture is created 55 initializeStorage(false); 56 57 TextureStorage *storage = getBaseLevelStorage(); 58 if (storage) 59 { 60 updateStorage(); 61 } 62 63 return storage; 64 } 65 66 GLint TextureD3D::getBaseLevelWidth() const 67 { 68 const Image *baseImage = getBaseLevelImage(); 69 return (baseImage ? baseImage->getWidth() : 0); 70 } 71 72 GLint TextureD3D::getBaseLevelHeight() const 73 { 74 const Image *baseImage = getBaseLevelImage(); 75 return (baseImage ? baseImage->getHeight() : 0); 76 } 77 78 GLint TextureD3D::getBaseLevelDepth() const 79 { 80 const Image *baseImage = getBaseLevelImage(); 81 return (baseImage ? baseImage->getDepth() : 0); 82 } 83 84 // Note: "base level image" is loosely defined to be any image from the base level, 85 // where in the base of 2D array textures and cube maps there are several. Don't use 86 // the base level image for anything except querying texture format and size. 87 GLenum TextureD3D::getBaseLevelInternalFormat() const 88 { 89 const Image *baseImage = getBaseLevelImage(); 90 return (baseImage ? baseImage->getInternalFormat() : GL_NONE); 91 } 92 93 void TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image) 94 { 95 // No-op 96 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) 97 { 98 return; 99 } 100 101 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains. 102 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components. 103 const void *pixelData = pixels; 104 105 if (unpack.pixelBuffer.id() != 0) 106 { 107 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported 108 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get(); 109 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels); 110 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data. 111 // This functionality should be moved into renderer and the getData method of BufferImpl removed. 112 const void *bufferData = pixelBuffer->getImplementation()->getData(); 113 pixelData = static_cast<const unsigned char *>(bufferData) + offset; 114 } 115 116 if (pixelData != NULL) 117 { 118 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData); 119 mDirtyImages = true; 120 } 121 } 122 123 bool TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, 124 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index) 125 { 126 const void *pixelData = pixels; 127 128 // CPU readback & copy where direct GPU copy is not supported 129 if (unpack.pixelBuffer.id() != 0) 130 { 131 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get(); 132 unsigned int offset = reinterpret_cast<unsigned int>(pixels); 133 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data. 134 // This functionality should be moved into renderer and the getData method of BufferImpl removed. 135 const void *bufferData = pixelBuffer->getImplementation()->getData(); 136 pixelData = static_cast<const unsigned char *>(bufferData) + offset; 137 } 138 139 if (pixelData != NULL) 140 { 141 Image *image = getImage(index); 142 ASSERT(image); 143 144 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData); 145 mDirtyImages = true; 146 } 147 148 return true; 149 } 150 151 void TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image) 152 { 153 if (pixels != NULL) 154 { 155 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels); 156 mDirtyImages = true; 157 } 158 } 159 160 bool TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, 161 GLenum format, GLsizei imageSize, const void *pixels, Image *image) 162 { 163 if (pixels != NULL) 164 { 165 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels); 166 mDirtyImages = true; 167 } 168 169 return true; 170 } 171 172 bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat) 173 { 174 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat); 175 } 176 177 bool TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea, 178 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget) 179 { 180 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0) 181 { 182 return true; 183 } 184 185 // In order to perform the fast copy through the shader, we must have the right format, and be able 186 // to create a render target. 187 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat)); 188 189 unsigned int offset = reinterpret_cast<unsigned int>(pixels); 190 191 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea); 192 } 193 194 GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const 195 { 196 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT) 197 { 198 // Maximum number of levels 199 return gl::log2(std::max(std::max(width, height), depth)) + 1; 200 } 201 else 202 { 203 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. 204 return 1; 205 } 206 } 207 208 int TextureD3D::mipLevels() const 209 { 210 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1; 211 } 212 213 214 TextureD3D_2D::TextureD3D_2D(Renderer *renderer) 215 : TextureD3D(renderer), 216 mTexStorage(NULL) 217 { 218 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) 219 { 220 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage()); 221 } 222 } 223 224 TextureD3D_2D::~TextureD3D_2D() 225 { 226 // Delete the Images before the TextureStorage. 227 // Images might be relying on the TextureStorage for some of their data. 228 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. 229 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) 230 { 231 delete mImageArray[i]; 232 } 233 234 SafeDelete(mTexStorage); 235 } 236 237 Image *TextureD3D_2D::getImage(int level, int layer) const 238 { 239 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 240 ASSERT(layer == 0); 241 return mImageArray[level]; 242 } 243 244 Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const 245 { 246 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 247 ASSERT(!index.hasLayer()); 248 ASSERT(index.type == GL_TEXTURE_2D); 249 return mImageArray[index.mipIndex]; 250 } 251 252 GLsizei TextureD3D_2D::getLayerCount(int level) const 253 { 254 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 255 return 1; 256 } 257 258 GLsizei TextureD3D_2D::getWidth(GLint level) const 259 { 260 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 261 return mImageArray[level]->getWidth(); 262 else 263 return 0; 264 } 265 266 GLsizei TextureD3D_2D::getHeight(GLint level) const 267 { 268 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 269 return mImageArray[level]->getHeight(); 270 else 271 return 0; 272 } 273 274 GLenum TextureD3D_2D::getInternalFormat(GLint level) const 275 { 276 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 277 return mImageArray[level]->getInternalFormat(); 278 else 279 return GL_NONE; 280 } 281 282 GLenum TextureD3D_2D::getActualFormat(GLint level) const 283 { 284 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 285 return mImageArray[level]->getActualFormat(); 286 else 287 return GL_NONE; 288 } 289 290 bool TextureD3D_2D::isDepth(GLint level) const 291 { 292 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; 293 } 294 295 void TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) 296 { 297 ASSERT(target == GL_TEXTURE_2D && depth == 1); 298 299 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); 300 301 bool fastUnpacked = false; 302 303 redefineImage(level, sizedInternalFormat, width, height); 304 305 // Attempt a fast gpu copy of the pixel data to the surface 306 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level)) 307 { 308 gl::ImageIndex index = gl::ImageIndex::Make2D(level); 309 310 // Will try to create RT storage if it does not exist 311 RenderTarget *destRenderTarget = getRenderTarget(index); 312 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1); 313 314 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget)) 315 { 316 // Ensure we don't overwrite our newly initialized data 317 mImageArray[level]->markClean(); 318 319 fastUnpacked = true; 320 } 321 } 322 323 if (!fastUnpacked) 324 { 325 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]); 326 } 327 } 328 329 void TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) 330 { 331 ASSERT(target == GL_TEXTURE_2D && depth == 1); 332 333 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly 334 redefineImage(level, format, width, height); 335 336 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]); 337 } 338 339 void TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) 340 { 341 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0); 342 343 bool fastUnpacked = false; 344 345 gl::ImageIndex index = gl::ImageIndex::Make2D(level); 346 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level)) 347 { 348 RenderTarget *renderTarget = getRenderTarget(index); 349 gl::Box destArea(xoffset, yoffset, 0, width, height, 1); 350 351 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget)) 352 { 353 // Ensure we don't overwrite our newly initialized data 354 mImageArray[level]->markClean(); 355 356 fastUnpacked = true; 357 } 358 } 359 360 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index)) 361 { 362 commitRect(level, xoffset, yoffset, width, height); 363 } 364 } 365 366 void TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) 367 { 368 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0); 369 370 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level])) 371 { 372 commitRect(level, xoffset, yoffset, width, height); 373 } 374 } 375 376 void TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) 377 { 378 ASSERT(target == GL_TEXTURE_2D); 379 380 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); 381 redefineImage(level, sizedInternalFormat, width, height); 382 383 if (!mImageArray[level]->isRenderableFormat()) 384 { 385 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source); 386 mDirtyImages = true; 387 } 388 else 389 { 390 ensureRenderTarget(); 391 mImageArray[level]->markClean(); 392 393 if (width != 0 && height != 0 && isValidLevel(level)) 394 { 395 gl::Rectangle sourceRect; 396 sourceRect.x = x; 397 sourceRect.width = width; 398 sourceRect.y = y; 399 sourceRect.height = height; 400 401 mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level); 402 } 403 } 404 } 405 406 void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) 407 { 408 ASSERT(target == GL_TEXTURE_2D && zoffset == 0); 409 410 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and 411 // the current level we're copying to is defined (with appropriate format, width & height) 412 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0); 413 414 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) 415 { 416 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source); 417 mDirtyImages = true; 418 } 419 else 420 { 421 ensureRenderTarget(); 422 423 if (isValidLevel(level)) 424 { 425 updateStorageLevel(level); 426 427 gl::Rectangle sourceRect; 428 sourceRect.x = x; 429 sourceRect.width = width; 430 sourceRect.y = y; 431 sourceRect.height = height; 432 433 mRenderer->copyImage2D(source, sourceRect, 434 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, 435 xoffset, yoffset, mTexStorage, level); 436 } 437 } 438 } 439 440 void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) 441 { 442 ASSERT(target == GL_TEXTURE_2D && depth == 1); 443 444 for (int level = 0; level < levels; level++) 445 { 446 GLsizei levelWidth = std::max(1, width >> level); 447 GLsizei levelHeight = std::max(1, height >> level); 448 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true); 449 } 450 451 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 452 { 453 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true); 454 } 455 456 mImmutable = true; 457 458 bool renderTarget = IsRenderTargetUsage(mUsage); 459 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels); 460 setCompleteTexStorage(storage); 461 } 462 463 void TextureD3D_2D::bindTexImage(egl::Surface *surface) 464 { 465 GLenum internalformat = surface->getFormat(); 466 467 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true); 468 469 if (mTexStorage) 470 { 471 SafeDelete(mTexStorage); 472 } 473 474 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain()); 475 476 mDirtyImages = true; 477 } 478 479 void TextureD3D_2D::releaseTexImage() 480 { 481 if (mTexStorage) 482 { 483 SafeDelete(mTexStorage); 484 } 485 486 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 487 { 488 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true); 489 } 490 } 491 492 void TextureD3D_2D::generateMipmaps() 493 { 494 // Purge array levels 1 through q and reset them to represent the generated mipmap levels. 495 int levelCount = mipLevels(); 496 for (int level = 1; level < levelCount; level++) 497 { 498 redefineImage(level, getBaseLevelInternalFormat(), 499 std::max(getBaseLevelWidth() >> level, 1), 500 std::max(getBaseLevelHeight() >> level, 1)); 501 } 502 503 if (mTexStorage && mTexStorage->isRenderTarget()) 504 { 505 mTexStorage->generateMipmaps(); 506 for (int level = 1; level < levelCount; level++) 507 { 508 mImageArray[level]->markClean(); 509 } 510 } 511 else 512 { 513 for (int level = 1; level < levelCount; level++) 514 { 515 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]); 516 } 517 } 518 } 519 520 unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index) 521 { 522 ASSERT(!index.hasLayer()); 523 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0); 524 } 525 526 RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index) 527 { 528 ASSERT(!index.hasLayer()); 529 530 // ensure the underlying texture is created 531 if (!ensureRenderTarget()) 532 { 533 return NULL; 534 } 535 536 updateStorageLevel(index.mipIndex); 537 return mTexStorage->getRenderTarget(index); 538 } 539 540 bool TextureD3D_2D::isValidLevel(int level) const 541 { 542 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false); 543 } 544 545 bool TextureD3D_2D::isLevelComplete(int level) const 546 { 547 if (isImmutable()) 548 { 549 return true; 550 } 551 552 const Image *baseImage = getBaseLevelImage(); 553 554 GLsizei width = baseImage->getWidth(); 555 GLsizei height = baseImage->getHeight(); 556 557 if (width <= 0 || height <= 0) 558 { 559 return false; 560 } 561 562 // The base image level is complete if the width and height are positive 563 if (level == 0) 564 { 565 return true; 566 } 567 568 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); 569 ImageD3D *image = mImageArray[level]; 570 571 if (image->getInternalFormat() != baseImage->getInternalFormat()) 572 { 573 return false; 574 } 575 576 if (image->getWidth() != std::max(1, width >> level)) 577 { 578 return false; 579 } 580 581 if (image->getHeight() != std::max(1, height >> level)) 582 { 583 return false; 584 } 585 586 return true; 587 } 588 589 // Constructs a native texture resource from the texture images 590 void TextureD3D_2D::initializeStorage(bool renderTarget) 591 { 592 // Only initialize the first time this texture is used as a render target or shader resource 593 if (mTexStorage) 594 { 595 return; 596 } 597 598 // do not attempt to create storage for nonexistant data 599 if (!isLevelComplete(0)) 600 { 601 return; 602 } 603 604 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); 605 606 setCompleteTexStorage(createCompleteStorage(createRenderTarget)); 607 ASSERT(mTexStorage); 608 609 // flush image data to the storage 610 updateStorage(); 611 } 612 613 TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const 614 { 615 GLsizei width = getBaseLevelWidth(); 616 GLsizei height = getBaseLevelHeight(); 617 GLenum internalFormat = getBaseLevelInternalFormat(); 618 619 ASSERT(width > 0 && height > 0); 620 621 // use existing storage level count, when previously specified by TexStorage*D 622 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); 623 624 return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels); 625 } 626 627 void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) 628 { 629 SafeDelete(mTexStorage); 630 mTexStorage = newCompleteTexStorage; 631 632 if (mTexStorage && mTexStorage->isManaged()) 633 { 634 for (int level = 0; level < mTexStorage->getLevelCount(); level++) 635 { 636 mImageArray[level]->setManagedSurface2D(mTexStorage, level); 637 } 638 } 639 640 mDirtyImages = true; 641 } 642 643 void TextureD3D_2D::updateStorage() 644 { 645 ASSERT(mTexStorage != NULL); 646 GLint storageLevels = mTexStorage->getLevelCount(); 647 for (int level = 0; level < storageLevels; level++) 648 { 649 if (mImageArray[level]->isDirty() && isLevelComplete(level)) 650 { 651 updateStorageLevel(level); 652 } 653 } 654 } 655 656 bool TextureD3D_2D::ensureRenderTarget() 657 { 658 initializeStorage(true); 659 660 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0) 661 { 662 ASSERT(mTexStorage); 663 if (!mTexStorage->isRenderTarget()) 664 { 665 TextureStorage *newRenderTargetStorage = createCompleteStorage(true); 666 667 if (!mRenderer->copyToRenderTarget2D(newRenderTargetStorage, mTexStorage)) 668 { 669 delete newRenderTargetStorage; 670 return gl::error(GL_OUT_OF_MEMORY, false); 671 } 672 673 setCompleteTexStorage(newRenderTargetStorage); 674 } 675 } 676 677 return (mTexStorage && mTexStorage->isRenderTarget()); 678 } 679 680 TextureStorage *TextureD3D_2D::getBaseLevelStorage() 681 { 682 return mTexStorage; 683 } 684 685 const ImageD3D *TextureD3D_2D::getBaseLevelImage() const 686 { 687 return mImageArray[0]; 688 } 689 690 void TextureD3D_2D::updateStorageLevel(int level) 691 { 692 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); 693 ASSERT(isLevelComplete(level)); 694 695 if (mImageArray[level]->isDirty()) 696 { 697 commitRect(level, 0, 0, getWidth(level), getHeight(level)); 698 } 699 } 700 701 void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height) 702 { 703 // If there currently is a corresponding storage texture image, it has these parameters 704 const int storageWidth = std::max(1, getBaseLevelWidth() >> level); 705 const int storageHeight = std::max(1, getBaseLevelHeight() >> level); 706 const GLenum storageFormat = getBaseLevelInternalFormat(); 707 708 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false); 709 710 if (mTexStorage) 711 { 712 const int storageLevels = mTexStorage->getLevelCount(); 713 714 if ((level >= storageLevels && storageLevels != 0) || 715 width != storageWidth || 716 height != storageHeight || 717 internalformat != storageFormat) // Discard mismatched storage 718 { 719 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 720 { 721 mImageArray[i]->markDirty(); 722 } 723 724 SafeDelete(mTexStorage); 725 mDirtyImages = true; 726 } 727 } 728 } 729 730 void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) 731 { 732 if (isValidLevel(level)) 733 { 734 ImageD3D *image = mImageArray[level]; 735 if (image->copyToStorage2D(mTexStorage, level, xoffset, yoffset, width, height)) 736 { 737 image->markClean(); 738 } 739 } 740 } 741 742 743 TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer) 744 : TextureD3D(renderer), 745 mTexStorage(NULL) 746 { 747 for (int i = 0; i < 6; i++) 748 { 749 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) 750 { 751 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage()); 752 } 753 } 754 } 755 756 TextureD3D_Cube::~TextureD3D_Cube() 757 { 758 // Delete the Images before the TextureStorage. 759 // Images might be relying on the TextureStorage for some of their data. 760 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. 761 for (int i = 0; i < 6; i++) 762 { 763 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) 764 { 765 SafeDelete(mImageArray[i][j]); 766 } 767 } 768 769 SafeDelete(mTexStorage); 770 } 771 772 Image *TextureD3D_Cube::getImage(int level, int layer) const 773 { 774 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 775 ASSERT(layer < 6); 776 return mImageArray[layer][level]; 777 } 778 779 Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const 780 { 781 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 782 ASSERT(index.layerIndex < 6); 783 return mImageArray[index.layerIndex][index.mipIndex]; 784 } 785 786 GLsizei TextureD3D_Cube::getLayerCount(int level) const 787 { 788 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 789 return 6; 790 } 791 792 GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const 793 { 794 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 795 return mImageArray[layer][level]->getInternalFormat(); 796 else 797 return GL_NONE; 798 } 799 800 bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const 801 { 802 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0; 803 } 804 805 void TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) 806 { 807 ASSERT(depth == 1); 808 809 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); 810 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); 811 812 redefineImage(faceIndex, level, sizedInternalFormat, width, height); 813 814 TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]); 815 } 816 817 void TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) 818 { 819 ASSERT(depth == 1); 820 821 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly 822 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); 823 824 redefineImage(faceIndex, level, format, width, height); 825 826 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]); 827 } 828 829 void TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) 830 { 831 ASSERT(depth == 1 && zoffset == 0); 832 833 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); 834 835 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); 836 if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index)) 837 { 838 commitRect(faceIndex, level, xoffset, yoffset, width, height); 839 } 840 } 841 842 void TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) 843 { 844 ASSERT(depth == 1 && zoffset == 0); 845 846 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); 847 848 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level])) 849 { 850 commitRect(faceIndex, level, xoffset, yoffset, width, height); 851 } 852 } 853 854 void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) 855 { 856 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); 857 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); 858 859 redefineImage(faceIndex, level, sizedInternalFormat, width, height); 860 861 if (!mImageArray[faceIndex][level]->isRenderableFormat()) 862 { 863 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source); 864 mDirtyImages = true; 865 } 866 else 867 { 868 ensureRenderTarget(); 869 mImageArray[faceIndex][level]->markClean(); 870 871 ASSERT(width == height); 872 873 if (width > 0 && isValidFaceLevel(faceIndex, level)) 874 { 875 gl::Rectangle sourceRect; 876 sourceRect.x = x; 877 sourceRect.width = width; 878 sourceRect.y = y; 879 sourceRect.height = height; 880 881 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level); 882 } 883 } 884 } 885 886 void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) 887 { 888 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); 889 890 // We can only make our texture storage to a render target if the level we're copying *to* is complete 891 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot 892 // rely on the "getBaseLevel*" methods reliably otherwise. 893 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete(); 894 895 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) 896 { 897 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source); 898 mDirtyImages = true; 899 } 900 else 901 { 902 ensureRenderTarget(); 903 904 if (isValidFaceLevel(faceIndex, level)) 905 { 906 updateStorageFaceLevel(faceIndex, level); 907 908 gl::Rectangle sourceRect; 909 sourceRect.x = x; 910 sourceRect.width = width; 911 sourceRect.y = y; 912 sourceRect.height = height; 913 914 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, 915 xoffset, yoffset, mTexStorage, target, level); 916 } 917 } 918 } 919 920 void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) 921 { 922 ASSERT(width == height); 923 ASSERT(depth == 1); 924 925 for (int level = 0; level < levels; level++) 926 { 927 GLsizei mipSize = std::max(1, width >> level); 928 for (int faceIndex = 0; faceIndex < 6; faceIndex++) 929 { 930 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true); 931 } 932 } 933 934 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 935 { 936 for (int faceIndex = 0; faceIndex < 6; faceIndex++) 937 { 938 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true); 939 } 940 } 941 942 mImmutable = true; 943 944 bool renderTarget = IsRenderTargetUsage(mUsage); 945 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels); 946 setCompleteTexStorage(storage); 947 } 948 949 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. 950 bool TextureD3D_Cube::isCubeComplete() const 951 { 952 int baseWidth = getBaseLevelWidth(); 953 int baseHeight = getBaseLevelHeight(); 954 GLenum baseFormat = getBaseLevelInternalFormat(); 955 956 if (baseWidth <= 0 || baseWidth != baseHeight) 957 { 958 return false; 959 } 960 961 for (int faceIndex = 1; faceIndex < 6; faceIndex++) 962 { 963 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0]; 964 965 if (faceBaseImage.getWidth() != baseWidth || 966 faceBaseImage.getHeight() != baseHeight || 967 faceBaseImage.getInternalFormat() != baseFormat ) 968 { 969 return false; 970 } 971 } 972 973 return true; 974 } 975 976 void TextureD3D_Cube::bindTexImage(egl::Surface *surface) 977 { 978 UNREACHABLE(); 979 } 980 981 void TextureD3D_Cube::releaseTexImage() 982 { 983 UNREACHABLE(); 984 } 985 986 987 void TextureD3D_Cube::generateMipmaps() 988 { 989 // Purge array levels 1 through q and reset them to represent the generated mipmap levels. 990 int levelCount = mipLevels(); 991 for (int faceIndex = 0; faceIndex < 6; faceIndex++) 992 { 993 for (int level = 1; level < levelCount; level++) 994 { 995 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1)); 996 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize); 997 } 998 } 999 1000 if (mTexStorage && mTexStorage->isRenderTarget()) 1001 { 1002 mTexStorage->generateMipmaps(); 1003 1004 for (int faceIndex = 0; faceIndex < 6; faceIndex++) 1005 { 1006 for (int level = 1; level < levelCount; level++) 1007 { 1008 mImageArray[faceIndex][level]->markClean(); 1009 } 1010 } 1011 } 1012 else 1013 { 1014 for (int faceIndex = 0; faceIndex < 6; faceIndex++) 1015 { 1016 for (int level = 1; level < levelCount; level++) 1017 { 1018 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]); 1019 } 1020 } 1021 } 1022 } 1023 1024 unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index) 1025 { 1026 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0); 1027 } 1028 1029 RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index) 1030 { 1031 ASSERT(gl::IsCubemapTextureTarget(index.type)); 1032 1033 // ensure the underlying texture is created 1034 if (!ensureRenderTarget()) 1035 { 1036 return NULL; 1037 } 1038 1039 updateStorageFaceLevel(index.layerIndex, index.mipIndex); 1040 return mTexStorage->getRenderTarget(index); 1041 } 1042 1043 void TextureD3D_Cube::initializeStorage(bool renderTarget) 1044 { 1045 // Only initialize the first time this texture is used as a render target or shader resource 1046 if (mTexStorage) 1047 { 1048 return; 1049 } 1050 1051 // do not attempt to create storage for nonexistant data 1052 if (!isFaceLevelComplete(0, 0)) 1053 { 1054 return; 1055 } 1056 1057 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); 1058 1059 setCompleteTexStorage(createCompleteStorage(createRenderTarget)); 1060 ASSERT(mTexStorage); 1061 1062 // flush image data to the storage 1063 updateStorage(); 1064 } 1065 1066 TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const 1067 { 1068 GLsizei size = getBaseLevelWidth(); 1069 1070 ASSERT(size > 0); 1071 1072 // use existing storage level count, when previously specified by TexStorage*D 1073 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1)); 1074 1075 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels); 1076 } 1077 1078 void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) 1079 { 1080 SafeDelete(mTexStorage); 1081 mTexStorage = newCompleteTexStorage; 1082 1083 if (mTexStorage && mTexStorage->isManaged()) 1084 { 1085 for (int faceIndex = 0; faceIndex < 6; faceIndex++) 1086 { 1087 for (int level = 0; level < mTexStorage->getLevelCount(); level++) 1088 { 1089 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level); 1090 } 1091 } 1092 } 1093 1094 mDirtyImages = true; 1095 } 1096 1097 void TextureD3D_Cube::updateStorage() 1098 { 1099 ASSERT(mTexStorage != NULL); 1100 GLint storageLevels = mTexStorage->getLevelCount(); 1101 for (int face = 0; face < 6; face++) 1102 { 1103 for (int level = 0; level < storageLevels; level++) 1104 { 1105 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level)) 1106 { 1107 updateStorageFaceLevel(face, level); 1108 } 1109 } 1110 } 1111 } 1112 1113 bool TextureD3D_Cube::ensureRenderTarget() 1114 { 1115 initializeStorage(true); 1116 1117 if (getBaseLevelWidth() > 0) 1118 { 1119 ASSERT(mTexStorage); 1120 if (!mTexStorage->isRenderTarget()) 1121 { 1122 TextureStorage *newRenderTargetStorage = createCompleteStorage(true); 1123 1124 if (!mRenderer->copyToRenderTargetCube(newRenderTargetStorage, mTexStorage)) 1125 { 1126 delete newRenderTargetStorage; 1127 return gl::error(GL_OUT_OF_MEMORY, false); 1128 } 1129 1130 setCompleteTexStorage(newRenderTargetStorage); 1131 } 1132 } 1133 1134 return (mTexStorage && mTexStorage->isRenderTarget()); 1135 } 1136 1137 TextureStorage *TextureD3D_Cube::getBaseLevelStorage() 1138 { 1139 return mTexStorage; 1140 } 1141 1142 const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const 1143 { 1144 // Note: if we are not cube-complete, there is no single base level image that can describe all 1145 // cube faces, so this method is only well-defined for a cube-complete base level. 1146 return mImageArray[0][0]; 1147 } 1148 1149 bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const 1150 { 1151 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); 1152 } 1153 1154 bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const 1155 { 1156 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); 1157 1158 if (isImmutable()) 1159 { 1160 return true; 1161 } 1162 1163 int baseSize = getBaseLevelWidth(); 1164 1165 if (baseSize <= 0) 1166 { 1167 return false; 1168 } 1169 1170 // "isCubeComplete" checks for base level completeness and we must call that 1171 // to determine if any face at level 0 is complete. We omit that check here 1172 // to avoid re-checking cube-completeness for every face at level 0. 1173 if (level == 0) 1174 { 1175 return true; 1176 } 1177 1178 // Check that non-zero levels are consistent with the base level. 1179 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level]; 1180 1181 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat()) 1182 { 1183 return false; 1184 } 1185 1186 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level)) 1187 { 1188 return false; 1189 } 1190 1191 return true; 1192 } 1193 1194 void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level) 1195 { 1196 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); 1197 ImageD3D *image = mImageArray[faceIndex][level]; 1198 1199 if (image->isDirty()) 1200 { 1201 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight()); 1202 } 1203 } 1204 1205 void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height) 1206 { 1207 // If there currently is a corresponding storage texture image, it has these parameters 1208 const int storageWidth = std::max(1, getBaseLevelWidth() >> level); 1209 const int storageHeight = std::max(1, getBaseLevelHeight() >> level); 1210 const GLenum storageFormat = getBaseLevelInternalFormat(); 1211 1212 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false); 1213 1214 if (mTexStorage) 1215 { 1216 const int storageLevels = mTexStorage->getLevelCount(); 1217 1218 if ((level >= storageLevels && storageLevels != 0) || 1219 width != storageWidth || 1220 height != storageHeight || 1221 internalformat != storageFormat) // Discard mismatched storage 1222 { 1223 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 1224 { 1225 for (int faceIndex = 0; faceIndex < 6; faceIndex++) 1226 { 1227 mImageArray[faceIndex][level]->markDirty(); 1228 } 1229 } 1230 1231 SafeDelete(mTexStorage); 1232 1233 mDirtyImages = true; 1234 } 1235 } 1236 } 1237 1238 void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) 1239 { 1240 if (isValidFaceLevel(faceIndex, level)) 1241 { 1242 ImageD3D *image = mImageArray[faceIndex][level]; 1243 if (image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height)) 1244 image->markClean(); 1245 } 1246 } 1247 1248 1249 TextureD3D_3D::TextureD3D_3D(Renderer *renderer) 1250 : TextureD3D(renderer), 1251 mTexStorage(NULL) 1252 { 1253 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) 1254 { 1255 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage()); 1256 } 1257 } 1258 1259 TextureD3D_3D::~TextureD3D_3D() 1260 { 1261 // Delete the Images before the TextureStorage. 1262 // Images might be relying on the TextureStorage for some of their data. 1263 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. 1264 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) 1265 { 1266 delete mImageArray[i]; 1267 } 1268 1269 SafeDelete(mTexStorage); 1270 } 1271 1272 Image *TextureD3D_3D::getImage(int level, int layer) const 1273 { 1274 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 1275 ASSERT(layer == 0); 1276 return mImageArray[level]; 1277 } 1278 1279 Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const 1280 { 1281 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 1282 ASSERT(!index.hasLayer()); 1283 ASSERT(index.type == GL_TEXTURE_3D); 1284 return mImageArray[index.mipIndex]; 1285 } 1286 1287 GLsizei TextureD3D_3D::getLayerCount(int level) const 1288 { 1289 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 1290 return 1; 1291 } 1292 1293 GLsizei TextureD3D_3D::getWidth(GLint level) const 1294 { 1295 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1296 return mImageArray[level]->getWidth(); 1297 else 1298 return 0; 1299 } 1300 1301 GLsizei TextureD3D_3D::getHeight(GLint level) const 1302 { 1303 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1304 return mImageArray[level]->getHeight(); 1305 else 1306 return 0; 1307 } 1308 1309 GLsizei TextureD3D_3D::getDepth(GLint level) const 1310 { 1311 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1312 return mImageArray[level]->getDepth(); 1313 else 1314 return 0; 1315 } 1316 1317 GLenum TextureD3D_3D::getInternalFormat(GLint level) const 1318 { 1319 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1320 return mImageArray[level]->getInternalFormat(); 1321 else 1322 return GL_NONE; 1323 } 1324 1325 bool TextureD3D_3D::isDepth(GLint level) const 1326 { 1327 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; 1328 } 1329 1330 void TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) 1331 { 1332 ASSERT(target == GL_TEXTURE_3D); 1333 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); 1334 1335 redefineImage(level, sizedInternalFormat, width, height, depth); 1336 1337 bool fastUnpacked = false; 1338 1339 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer 1340 if (isFastUnpackable(unpack, sizedInternalFormat)) 1341 { 1342 // Will try to create RT storage if it does not exist 1343 gl::ImageIndex index = gl::ImageIndex::Make3D(level); 1344 RenderTarget *destRenderTarget = getRenderTarget(index); 1345 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); 1346 1347 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget)) 1348 { 1349 // Ensure we don't overwrite our newly initialized data 1350 mImageArray[level]->markClean(); 1351 1352 fastUnpacked = true; 1353 } 1354 } 1355 1356 if (!fastUnpacked) 1357 { 1358 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]); 1359 } 1360 } 1361 1362 void TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) 1363 { 1364 ASSERT(target == GL_TEXTURE_3D); 1365 1366 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly 1367 redefineImage(level, format, width, height, depth); 1368 1369 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]); 1370 } 1371 1372 void TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) 1373 { 1374 ASSERT(target == GL_TEXTURE_3D); 1375 1376 bool fastUnpacked = false; 1377 1378 gl::ImageIndex index = gl::ImageIndex::Make3D(level); 1379 1380 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer 1381 if (isFastUnpackable(unpack, getInternalFormat(level))) 1382 { 1383 RenderTarget *destRenderTarget = getRenderTarget(index); 1384 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth); 1385 1386 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget)) 1387 { 1388 // Ensure we don't overwrite our newly initialized data 1389 mImageArray[level]->markClean(); 1390 1391 fastUnpacked = true; 1392 } 1393 } 1394 1395 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, index)) 1396 { 1397 commitRect(level, xoffset, yoffset, zoffset, width, height, depth); 1398 } 1399 } 1400 1401 void TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) 1402 { 1403 ASSERT(target == GL_TEXTURE_3D); 1404 1405 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level])) 1406 { 1407 commitRect(level, xoffset, yoffset, zoffset, width, height, depth); 1408 } 1409 } 1410 1411 void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) 1412 { 1413 UNIMPLEMENTED(); 1414 } 1415 1416 void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) 1417 { 1418 ASSERT(target == GL_TEXTURE_3D); 1419 1420 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and 1421 // the current level we're copying to is defined (with appropriate format, width & height) 1422 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0); 1423 1424 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) 1425 { 1426 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source); 1427 mDirtyImages = true; 1428 } 1429 else 1430 { 1431 ensureRenderTarget(); 1432 1433 if (isValidLevel(level)) 1434 { 1435 updateStorageLevel(level); 1436 1437 gl::Rectangle sourceRect; 1438 sourceRect.x = x; 1439 sourceRect.width = width; 1440 sourceRect.y = y; 1441 sourceRect.height = height; 1442 1443 mRenderer->copyImage3D(source, sourceRect, 1444 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, 1445 xoffset, yoffset, zoffset, mTexStorage, level); 1446 } 1447 } 1448 } 1449 1450 void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) 1451 { 1452 ASSERT(target == GL_TEXTURE_3D); 1453 1454 for (int level = 0; level < levels; level++) 1455 { 1456 GLsizei levelWidth = std::max(1, width >> level); 1457 GLsizei levelHeight = std::max(1, height >> level); 1458 GLsizei levelDepth = std::max(1, depth >> level); 1459 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true); 1460 } 1461 1462 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 1463 { 1464 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true); 1465 } 1466 1467 mImmutable = true; 1468 1469 bool renderTarget = IsRenderTargetUsage(mUsage); 1470 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels); 1471 setCompleteTexStorage(storage); 1472 } 1473 1474 void TextureD3D_3D::bindTexImage(egl::Surface *surface) 1475 { 1476 UNREACHABLE(); 1477 } 1478 1479 void TextureD3D_3D::releaseTexImage() 1480 { 1481 UNREACHABLE(); 1482 } 1483 1484 1485 void TextureD3D_3D::generateMipmaps() 1486 { 1487 // Purge array levels 1 through q and reset them to represent the generated mipmap levels. 1488 int levelCount = mipLevels(); 1489 for (int level = 1; level < levelCount; level++) 1490 { 1491 redefineImage(level, getBaseLevelInternalFormat(), 1492 std::max(getBaseLevelWidth() >> level, 1), 1493 std::max(getBaseLevelHeight() >> level, 1), 1494 std::max(getBaseLevelDepth() >> level, 1)); 1495 } 1496 1497 if (mTexStorage && mTexStorage->isRenderTarget()) 1498 { 1499 mTexStorage->generateMipmaps(); 1500 1501 for (int level = 1; level < levelCount; level++) 1502 { 1503 mImageArray[level]->markClean(); 1504 } 1505 } 1506 else 1507 { 1508 for (int level = 1; level < levelCount; level++) 1509 { 1510 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]); 1511 } 1512 } 1513 } 1514 1515 unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index) 1516 { 1517 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0); 1518 } 1519 1520 RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index) 1521 { 1522 // ensure the underlying texture is created 1523 if (!ensureRenderTarget()) 1524 { 1525 return NULL; 1526 } 1527 1528 if (index.hasLayer()) 1529 { 1530 updateStorage(); 1531 } 1532 else 1533 { 1534 updateStorageLevel(index.mipIndex); 1535 } 1536 1537 return mTexStorage->getRenderTarget(index); 1538 } 1539 1540 void TextureD3D_3D::initializeStorage(bool renderTarget) 1541 { 1542 // Only initialize the first time this texture is used as a render target or shader resource 1543 if (mTexStorage) 1544 { 1545 return; 1546 } 1547 1548 // do not attempt to create storage for nonexistant data 1549 if (!isLevelComplete(0)) 1550 { 1551 return; 1552 } 1553 1554 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); 1555 1556 setCompleteTexStorage(createCompleteStorage(createRenderTarget)); 1557 ASSERT(mTexStorage); 1558 1559 // flush image data to the storage 1560 updateStorage(); 1561 } 1562 1563 TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const 1564 { 1565 GLsizei width = getBaseLevelWidth(); 1566 GLsizei height = getBaseLevelHeight(); 1567 GLsizei depth = getBaseLevelDepth(); 1568 GLenum internalFormat = getBaseLevelInternalFormat(); 1569 1570 ASSERT(width > 0 && height > 0 && depth > 0); 1571 1572 // use existing storage level count, when previously specified by TexStorage*D 1573 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth)); 1574 1575 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels); 1576 } 1577 1578 void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) 1579 { 1580 SafeDelete(mTexStorage); 1581 mTexStorage = newCompleteTexStorage; 1582 mDirtyImages = true; 1583 1584 // We do not support managed 3D storage, as that is D3D9/ES2-only 1585 ASSERT(!mTexStorage->isManaged()); 1586 } 1587 1588 void TextureD3D_3D::updateStorage() 1589 { 1590 ASSERT(mTexStorage != NULL); 1591 GLint storageLevels = mTexStorage->getLevelCount(); 1592 for (int level = 0; level < storageLevels; level++) 1593 { 1594 if (mImageArray[level]->isDirty() && isLevelComplete(level)) 1595 { 1596 updateStorageLevel(level); 1597 } 1598 } 1599 } 1600 1601 bool TextureD3D_3D::ensureRenderTarget() 1602 { 1603 initializeStorage(true); 1604 1605 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0) 1606 { 1607 ASSERT(mTexStorage); 1608 if (!mTexStorage->isRenderTarget()) 1609 { 1610 TextureStorage *newRenderTargetStorage = createCompleteStorage(true); 1611 1612 if (!mRenderer->copyToRenderTarget3D(newRenderTargetStorage, mTexStorage)) 1613 { 1614 delete newRenderTargetStorage; 1615 return gl::error(GL_OUT_OF_MEMORY, false); 1616 } 1617 1618 setCompleteTexStorage(newRenderTargetStorage); 1619 } 1620 } 1621 1622 return (mTexStorage && mTexStorage->isRenderTarget()); 1623 } 1624 1625 TextureStorage *TextureD3D_3D::getBaseLevelStorage() 1626 { 1627 return mTexStorage; 1628 } 1629 1630 const ImageD3D *TextureD3D_3D::getBaseLevelImage() const 1631 { 1632 return mImageArray[0]; 1633 } 1634 1635 bool TextureD3D_3D::isValidLevel(int level) const 1636 { 1637 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); 1638 } 1639 1640 bool TextureD3D_3D::isLevelComplete(int level) const 1641 { 1642 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); 1643 1644 if (isImmutable()) 1645 { 1646 return true; 1647 } 1648 1649 GLsizei width = getBaseLevelWidth(); 1650 GLsizei height = getBaseLevelHeight(); 1651 GLsizei depth = getBaseLevelDepth(); 1652 1653 if (width <= 0 || height <= 0 || depth <= 0) 1654 { 1655 return false; 1656 } 1657 1658 if (level == 0) 1659 { 1660 return true; 1661 } 1662 1663 ImageD3D *levelImage = mImageArray[level]; 1664 1665 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat()) 1666 { 1667 return false; 1668 } 1669 1670 if (levelImage->getWidth() != std::max(1, width >> level)) 1671 { 1672 return false; 1673 } 1674 1675 if (levelImage->getHeight() != std::max(1, height >> level)) 1676 { 1677 return false; 1678 } 1679 1680 if (levelImage->getDepth() != std::max(1, depth >> level)) 1681 { 1682 return false; 1683 } 1684 1685 return true; 1686 } 1687 1688 void TextureD3D_3D::updateStorageLevel(int level) 1689 { 1690 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); 1691 ASSERT(isLevelComplete(level)); 1692 1693 if (mImageArray[level]->isDirty()) 1694 { 1695 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); 1696 } 1697 } 1698 1699 void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) 1700 { 1701 // If there currently is a corresponding storage texture image, it has these parameters 1702 const int storageWidth = std::max(1, getBaseLevelWidth() >> level); 1703 const int storageHeight = std::max(1, getBaseLevelHeight() >> level); 1704 const int storageDepth = std::max(1, getBaseLevelDepth() >> level); 1705 const GLenum storageFormat = getBaseLevelInternalFormat(); 1706 1707 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false); 1708 1709 if (mTexStorage) 1710 { 1711 const int storageLevels = mTexStorage->getLevelCount(); 1712 1713 if ((level >= storageLevels && storageLevels != 0) || 1714 width != storageWidth || 1715 height != storageHeight || 1716 depth != storageDepth || 1717 internalformat != storageFormat) // Discard mismatched storage 1718 { 1719 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 1720 { 1721 mImageArray[i]->markDirty(); 1722 } 1723 1724 SafeDelete(mTexStorage); 1725 mDirtyImages = true; 1726 } 1727 } 1728 } 1729 1730 void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) 1731 { 1732 if (isValidLevel(level)) 1733 { 1734 ImageD3D *image = mImageArray[level]; 1735 if (image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth)) 1736 { 1737 image->markClean(); 1738 } 1739 } 1740 } 1741 1742 1743 TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer) 1744 : TextureD3D(renderer), 1745 mTexStorage(NULL) 1746 { 1747 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) 1748 { 1749 mLayerCounts[level] = 0; 1750 mImageArray[level] = NULL; 1751 } 1752 } 1753 1754 TextureD3D_2DArray::~TextureD3D_2DArray() 1755 { 1756 // Delete the Images before the TextureStorage. 1757 // Images might be relying on the TextureStorage for some of their data. 1758 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. 1759 deleteImages(); 1760 SafeDelete(mTexStorage); 1761 } 1762 1763 Image *TextureD3D_2DArray::getImage(int level, int layer) const 1764 { 1765 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 1766 ASSERT(layer < mLayerCounts[level]); 1767 return mImageArray[level][layer]; 1768 } 1769 1770 Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const 1771 { 1772 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 1773 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]); 1774 ASSERT(index.type == GL_TEXTURE_2D_ARRAY); 1775 return mImageArray[index.mipIndex][index.layerIndex]; 1776 } 1777 1778 GLsizei TextureD3D_2DArray::getLayerCount(int level) const 1779 { 1780 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 1781 return mLayerCounts[level]; 1782 } 1783 1784 GLsizei TextureD3D_2DArray::getWidth(GLint level) const 1785 { 1786 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0; 1787 } 1788 1789 GLsizei TextureD3D_2DArray::getHeight(GLint level) const 1790 { 1791 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0; 1792 } 1793 1794 GLsizei TextureD3D_2DArray::getLayers(GLint level) const 1795 { 1796 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0; 1797 } 1798 1799 GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const 1800 { 1801 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE; 1802 } 1803 1804 bool TextureD3D_2DArray::isDepth(GLint level) const 1805 { 1806 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; 1807 } 1808 1809 void TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) 1810 { 1811 ASSERT(target == GL_TEXTURE_2D_ARRAY); 1812 1813 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); 1814 1815 redefineImage(level, sizedInternalFormat, width, height, depth); 1816 1817 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat); 1818 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment); 1819 1820 for (int i = 0; i < depth; i++) 1821 { 1822 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL; 1823 TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]); 1824 } 1825 } 1826 1827 void TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) 1828 { 1829 ASSERT(target == GL_TEXTURE_2D_ARRAY); 1830 1831 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly 1832 redefineImage(level, format, width, height, depth); 1833 1834 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format); 1835 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1); 1836 1837 for (int i = 0; i < depth; i++) 1838 { 1839 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL; 1840 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]); 1841 } 1842 } 1843 1844 void TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) 1845 { 1846 ASSERT(target == GL_TEXTURE_2D_ARRAY); 1847 1848 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level)); 1849 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment); 1850 1851 for (int i = 0; i < depth; i++) 1852 { 1853 int layer = zoffset + i; 1854 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL; 1855 1856 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); 1857 if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, index)) 1858 { 1859 commitRect(level, xoffset, yoffset, layer, width, height); 1860 } 1861 } 1862 } 1863 1864 void TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) 1865 { 1866 ASSERT(target == GL_TEXTURE_2D_ARRAY); 1867 1868 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format); 1869 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1); 1870 1871 for (int i = 0; i < depth; i++) 1872 { 1873 int layer = zoffset + i; 1874 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL; 1875 1876 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer])) 1877 { 1878 commitRect(level, xoffset, yoffset, layer, width, height); 1879 } 1880 } 1881 } 1882 1883 void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) 1884 { 1885 UNIMPLEMENTED(); 1886 } 1887 1888 void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) 1889 { 1890 ASSERT(target == GL_TEXTURE_2D_ARRAY); 1891 1892 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and 1893 // the current level we're copying to is defined (with appropriate format, width & height) 1894 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0); 1895 1896 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) 1897 { 1898 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source); 1899 mDirtyImages = true; 1900 } 1901 else 1902 { 1903 ensureRenderTarget(); 1904 1905 if (isValidLevel(level)) 1906 { 1907 updateStorageLevel(level); 1908 1909 gl::Rectangle sourceRect; 1910 sourceRect.x = x; 1911 sourceRect.width = width; 1912 sourceRect.y = y; 1913 sourceRect.height = height; 1914 1915 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format, 1916 xoffset, yoffset, zoffset, mTexStorage, level); 1917 } 1918 } 1919 } 1920 1921 void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) 1922 { 1923 ASSERT(target == GL_TEXTURE_2D_ARRAY); 1924 1925 deleteImages(); 1926 1927 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 1928 { 1929 GLsizei levelWidth = std::max(1, width >> level); 1930 GLsizei levelHeight = std::max(1, height >> level); 1931 1932 mLayerCounts[level] = (level < levels ? depth : 0); 1933 1934 if (mLayerCounts[level] > 0) 1935 { 1936 // Create new images for this level 1937 mImageArray[level] = new ImageD3D*[mLayerCounts[level]]; 1938 1939 for (int layer = 0; layer < mLayerCounts[level]; layer++) 1940 { 1941 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage()); 1942 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth, 1943 levelHeight, 1, true); 1944 } 1945 } 1946 } 1947 1948 mImmutable = true; 1949 1950 bool renderTarget = IsRenderTargetUsage(mUsage); 1951 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels); 1952 setCompleteTexStorage(storage); 1953 } 1954 1955 void TextureD3D_2DArray::bindTexImage(egl::Surface *surface) 1956 { 1957 UNREACHABLE(); 1958 } 1959 1960 void TextureD3D_2DArray::releaseTexImage() 1961 { 1962 UNREACHABLE(); 1963 } 1964 1965 1966 void TextureD3D_2DArray::generateMipmaps() 1967 { 1968 int baseWidth = getBaseLevelWidth(); 1969 int baseHeight = getBaseLevelHeight(); 1970 int baseDepth = getBaseLevelDepth(); 1971 GLenum baseFormat = getBaseLevelInternalFormat(); 1972 1973 // Purge array levels 1 through q and reset them to represent the generated mipmap levels. 1974 int levelCount = mipLevels(); 1975 for (int level = 1; level < levelCount; level++) 1976 { 1977 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth); 1978 } 1979 1980 if (mTexStorage && mTexStorage->isRenderTarget()) 1981 { 1982 mTexStorage->generateMipmaps(); 1983 1984 for (int level = 1; level < levelCount; level++) 1985 { 1986 for (int layer = 0; layer < mLayerCounts[level]; layer++) 1987 { 1988 mImageArray[level][layer]->markClean(); 1989 } 1990 } 1991 } 1992 else 1993 { 1994 for (int level = 1; level < levelCount; level++) 1995 { 1996 for (int layer = 0; layer < mLayerCounts[level]; layer++) 1997 { 1998 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]); 1999 } 2000 } 2001 } 2002 } 2003 2004 unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index) 2005 { 2006 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0); 2007 } 2008 2009 RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index) 2010 { 2011 // ensure the underlying texture is created 2012 if (!ensureRenderTarget()) 2013 { 2014 return NULL; 2015 } 2016 2017 updateStorageLevel(index.mipIndex); 2018 return mTexStorage->getRenderTarget(index); 2019 } 2020 2021 void TextureD3D_2DArray::initializeStorage(bool renderTarget) 2022 { 2023 // Only initialize the first time this texture is used as a render target or shader resource 2024 if (mTexStorage) 2025 { 2026 return; 2027 } 2028 2029 // do not attempt to create storage for nonexistant data 2030 if (!isLevelComplete(0)) 2031 { 2032 return; 2033 } 2034 2035 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); 2036 2037 setCompleteTexStorage(createCompleteStorage(createRenderTarget)); 2038 ASSERT(mTexStorage); 2039 2040 // flush image data to the storage 2041 updateStorage(); 2042 } 2043 2044 TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const 2045 { 2046 GLsizei width = getBaseLevelWidth(); 2047 GLsizei height = getBaseLevelHeight(); 2048 GLsizei depth = getLayers(0); 2049 GLenum internalFormat = getBaseLevelInternalFormat(); 2050 2051 ASSERT(width > 0 && height > 0 && depth > 0); 2052 2053 // use existing storage level count, when previously specified by TexStorage*D 2054 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); 2055 2056 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels); 2057 } 2058 2059 void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) 2060 { 2061 SafeDelete(mTexStorage); 2062 mTexStorage = newCompleteTexStorage; 2063 mDirtyImages = true; 2064 2065 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only 2066 ASSERT(!mTexStorage->isManaged()); 2067 } 2068 2069 void TextureD3D_2DArray::updateStorage() 2070 { 2071 ASSERT(mTexStorage != NULL); 2072 GLint storageLevels = mTexStorage->getLevelCount(); 2073 for (int level = 0; level < storageLevels; level++) 2074 { 2075 if (isLevelComplete(level)) 2076 { 2077 updateStorageLevel(level); 2078 } 2079 } 2080 } 2081 2082 bool TextureD3D_2DArray::ensureRenderTarget() 2083 { 2084 initializeStorage(true); 2085 2086 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0) 2087 { 2088 ASSERT(mTexStorage); 2089 if (!mTexStorage->isRenderTarget()) 2090 { 2091 TextureStorage *newRenderTargetStorage = createCompleteStorage(true); 2092 2093 if (!mRenderer->copyToRenderTarget2DArray(newRenderTargetStorage, mTexStorage)) 2094 { 2095 delete newRenderTargetStorage; 2096 return gl::error(GL_OUT_OF_MEMORY, false); 2097 } 2098 2099 setCompleteTexStorage(newRenderTargetStorage); 2100 } 2101 } 2102 2103 return (mTexStorage && mTexStorage->isRenderTarget()); 2104 } 2105 2106 const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const 2107 { 2108 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL); 2109 } 2110 2111 TextureStorage *TextureD3D_2DArray::getBaseLevelStorage() 2112 { 2113 return mTexStorage; 2114 } 2115 2116 bool TextureD3D_2DArray::isValidLevel(int level) const 2117 { 2118 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); 2119 } 2120 2121 bool TextureD3D_2DArray::isLevelComplete(int level) const 2122 { 2123 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray)); 2124 2125 if (isImmutable()) 2126 { 2127 return true; 2128 } 2129 2130 GLsizei width = getBaseLevelWidth(); 2131 GLsizei height = getBaseLevelHeight(); 2132 GLsizei layers = getLayers(0); 2133 2134 if (width <= 0 || height <= 0 || layers <= 0) 2135 { 2136 return false; 2137 } 2138 2139 if (level == 0) 2140 { 2141 return true; 2142 } 2143 2144 if (getInternalFormat(level) != getInternalFormat(0)) 2145 { 2146 return false; 2147 } 2148 2149 if (getWidth(level) != std::max(1, width >> level)) 2150 { 2151 return false; 2152 } 2153 2154 if (getHeight(level) != std::max(1, height >> level)) 2155 { 2156 return false; 2157 } 2158 2159 if (getLayers(level) != layers) 2160 { 2161 return false; 2162 } 2163 2164 return true; 2165 } 2166 2167 void TextureD3D_2DArray::updateStorageLevel(int level) 2168 { 2169 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts)); 2170 ASSERT(isLevelComplete(level)); 2171 2172 for (int layer = 0; layer < mLayerCounts[level]; layer++) 2173 { 2174 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL); 2175 if (mImageArray[level][layer]->isDirty()) 2176 { 2177 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level)); 2178 } 2179 } 2180 } 2181 2182 void TextureD3D_2DArray::deleteImages() 2183 { 2184 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) 2185 { 2186 for (int layer = 0; layer < mLayerCounts[level]; ++layer) 2187 { 2188 delete mImageArray[level][layer]; 2189 } 2190 delete[] mImageArray[level]; 2191 mImageArray[level] = NULL; 2192 mLayerCounts[level] = 0; 2193 } 2194 } 2195 2196 void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) 2197 { 2198 // If there currently is a corresponding storage texture image, it has these parameters 2199 const int storageWidth = std::max(1, getBaseLevelWidth() >> level); 2200 const int storageHeight = std::max(1, getBaseLevelHeight() >> level); 2201 const int storageDepth = getLayers(0); 2202 const GLenum storageFormat = getBaseLevelInternalFormat(); 2203 2204 for (int layer = 0; layer < mLayerCounts[level]; layer++) 2205 { 2206 delete mImageArray[level][layer]; 2207 } 2208 delete[] mImageArray[level]; 2209 mImageArray[level] = NULL; 2210 mLayerCounts[level] = depth; 2211 2212 if (depth > 0) 2213 { 2214 mImageArray[level] = new ImageD3D*[depth](); 2215 2216 for (int layer = 0; layer < mLayerCounts[level]; layer++) 2217 { 2218 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage()); 2219 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false); 2220 } 2221 } 2222 2223 if (mTexStorage) 2224 { 2225 const int storageLevels = mTexStorage->getLevelCount(); 2226 2227 if ((level >= storageLevels && storageLevels != 0) || 2228 width != storageWidth || 2229 height != storageHeight || 2230 depth != storageDepth || 2231 internalformat != storageFormat) // Discard mismatched storage 2232 { 2233 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 2234 { 2235 for (int layer = 0; layer < mLayerCounts[level]; layer++) 2236 { 2237 mImageArray[level][layer]->markDirty(); 2238 } 2239 } 2240 2241 delete mTexStorage; 2242 mTexStorage = NULL; 2243 mDirtyImages = true; 2244 } 2245 } 2246 } 2247 2248 void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height) 2249 { 2250 if (isValidLevel(level) && layerTarget < getLayers(level)) 2251 { 2252 ImageD3D *image = mImageArray[level][layerTarget]; 2253 if (image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height)) 2254 { 2255 image->markClean(); 2256 } 2257 } 2258 } 2259 2260 } 2261