TextureD3D.cpp (178360B)
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 "libANGLE/renderer/d3d/TextureD3D.h" 10 11 #include "common/mathutil.h" 12 #include "common/utilities.h" 13 #include "libANGLE/Buffer.h" 14 #include "libANGLE/Config.h" 15 #include "libANGLE/Context.h" 16 #include "libANGLE/Framebuffer.h" 17 #include "libANGLE/Image.h" 18 #include "libANGLE/Surface.h" 19 #include "libANGLE/Texture.h" 20 #include "libANGLE/formatutils.h" 21 #include "libANGLE/renderer/BufferImpl.h" 22 #include "libANGLE/renderer/d3d/BufferD3D.h" 23 #include "libANGLE/renderer/d3d/ContextD3D.h" 24 #include "libANGLE/renderer/d3d/EGLImageD3D.h" 25 #include "libANGLE/renderer/d3d/ImageD3D.h" 26 #include "libANGLE/renderer/d3d/RenderTargetD3D.h" 27 #include "libANGLE/renderer/d3d/SurfaceD3D.h" 28 #include "libANGLE/renderer/d3d/TextureStorage.h" 29 30 namespace rx 31 { 32 33 namespace 34 { 35 36 angle::Result GetUnpackPointer(const gl::Context *context, 37 const gl::PixelUnpackState &unpack, 38 gl::Buffer *unpackBuffer, 39 const uint8_t *pixels, 40 ptrdiff_t layerOffset, 41 const uint8_t **pointerOut) 42 { 43 if (unpackBuffer) 44 { 45 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not 46 // supported 47 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels); 48 49 // TODO: this is the only place outside of renderer that asks for a buffers raw data. 50 // This functionality should be moved into renderer and the getData method of BufferImpl 51 // removed. 52 BufferD3D *bufferD3D = GetImplAs<BufferD3D>(unpackBuffer); 53 ASSERT(bufferD3D); 54 const uint8_t *bufferData = nullptr; 55 ANGLE_TRY(bufferD3D->getData(context, &bufferData)); 56 *pointerOut = bufferData + offset; 57 } 58 else 59 { 60 *pointerOut = pixels; 61 } 62 63 // Offset the pointer for 2D array layer (if it's valid) 64 if (*pointerOut != nullptr) 65 { 66 *pointerOut += layerOffset; 67 } 68 69 return angle::Result::Continue; 70 } 71 72 bool IsRenderTargetUsage(GLenum usage) 73 { 74 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); 75 } 76 } // namespace 77 78 TextureD3D::TextureD3D(const gl::TextureState &state, RendererD3D *renderer) 79 : TextureImpl(state), 80 mRenderer(renderer), 81 mDirtyImages(true), 82 mImmutable(false), 83 mTexStorage(nullptr), 84 mTexStorageObserverBinding(this, kTextureStorageObserverMessageIndex), 85 mBaseLevel(0) 86 {} 87 88 TextureD3D::~TextureD3D() 89 { 90 ASSERT(!mTexStorage); 91 } 92 93 angle::Result TextureD3D::getNativeTexture(const gl::Context *context, TextureStorage **outStorage) 94 { 95 // ensure the underlying texture is created 96 ANGLE_TRY(initializeStorage(context, BindFlags())); 97 98 if (mTexStorage) 99 { 100 ANGLE_TRY(updateStorage(context)); 101 } 102 103 ASSERT(outStorage); 104 105 *outStorage = mTexStorage; 106 return angle::Result::Continue; 107 } 108 109 angle::Result TextureD3D::getImageAndSyncFromStorage(const gl::Context *context, 110 const gl::ImageIndex &index, 111 ImageD3D **outImage) 112 { 113 ImageD3D *image = getImage(index); 114 if (mTexStorage && mTexStorage->isRenderTarget()) 115 { 116 ANGLE_TRY(image->copyFromTexStorage(context, index, mTexStorage)); 117 mDirtyImages = true; 118 } 119 image->markClean(); 120 *outImage = image; 121 return angle::Result::Continue; 122 } 123 124 GLint TextureD3D::getLevelZeroWidth() const 125 { 126 ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelWidth())) > getBaseLevel()); 127 return getBaseLevelWidth() << mBaseLevel; 128 } 129 130 GLint TextureD3D::getLevelZeroHeight() const 131 { 132 ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelHeight())) > getBaseLevel()); 133 return getBaseLevelHeight() << mBaseLevel; 134 } 135 136 GLint TextureD3D::getLevelZeroDepth() const 137 { 138 return getBaseLevelDepth(); 139 } 140 141 GLint TextureD3D::getBaseLevelWidth() const 142 { 143 const ImageD3D *baseImage = getBaseLevelImage(); 144 return (baseImage ? baseImage->getWidth() : 0); 145 } 146 147 GLint TextureD3D::getBaseLevelHeight() const 148 { 149 const ImageD3D *baseImage = getBaseLevelImage(); 150 return (baseImage ? baseImage->getHeight() : 0); 151 } 152 153 GLint TextureD3D::getBaseLevelDepth() const 154 { 155 const ImageD3D *baseImage = getBaseLevelImage(); 156 return (baseImage ? baseImage->getDepth() : 0); 157 } 158 159 // Note: "base level image" is loosely defined to be any image from the base level, 160 // where in the base of 2D array textures and cube maps there are several. Don't use 161 // the base level image for anything except querying texture format and size. 162 GLenum TextureD3D::getBaseLevelInternalFormat() const 163 { 164 const ImageD3D *baseImage = getBaseLevelImage(); 165 return (baseImage ? baseImage->getInternalFormat() : GL_NONE); 166 } 167 168 angle::Result TextureD3D::setStorage(const gl::Context *context, 169 gl::TextureType type, 170 size_t levels, 171 GLenum internalFormat, 172 const gl::Extents &size) 173 { 174 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 175 return angle::Result::Continue; 176 } 177 178 angle::Result TextureD3D::setStorageMultisample(const gl::Context *context, 179 gl::TextureType type, 180 GLsizei samples, 181 GLint internalformat, 182 const gl::Extents &size, 183 bool fixedSampleLocations) 184 { 185 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 186 return angle::Result::Continue; 187 } 188 189 angle::Result TextureD3D::setBuffer(const gl::Context *context, GLenum internalFormat) 190 { 191 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 192 return angle::Result::Continue; 193 } 194 195 angle::Result TextureD3D::setStorageExternalMemory(const gl::Context *context, 196 gl::TextureType type, 197 size_t levels, 198 GLenum internalFormat, 199 const gl::Extents &size, 200 gl::MemoryObject *memoryObject, 201 GLuint64 offset, 202 GLbitfield createFlags, 203 GLbitfield usageFlags, 204 const void *imageCreateInfoPNext) 205 { 206 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 207 return angle::Result::Continue; 208 } 209 210 bool TextureD3D::couldUseSetData() const 211 { 212 if (!mRenderer->getFeatures().setDataFasterThanImageUpload.enabled) 213 { 214 return false; 215 } 216 217 if (!mRenderer->getFeatures().setDataFasterThanImageUploadOn128bitFormats.enabled) 218 { 219 gl::InternalFormat internalFormat = 220 gl::GetSizedInternalFormatInfo(getBaseLevelInternalFormat()); 221 return internalFormat.pixelBytes < 16; 222 } 223 224 return true; 225 } 226 227 bool TextureD3D::shouldUseSetData(const ImageD3D *image) const 228 { 229 if (!couldUseSetData()) 230 { 231 return false; 232 } 233 234 if (image->isDirty()) 235 { 236 return false; 237 } 238 239 gl::InternalFormat internalFormat = gl::GetSizedInternalFormatInfo(image->getInternalFormat()); 240 241 // We can only handle full updates for depth-stencil textures, so to avoid complications 242 // disable them entirely. 243 if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0) 244 { 245 return false; 246 } 247 248 // TODO(jmadill): Handle compressed internal formats 249 return (mTexStorage && !internalFormat.compressed); 250 } 251 252 angle::Result TextureD3D::setImageImpl(const gl::Context *context, 253 const gl::ImageIndex &index, 254 GLenum type, 255 const gl::PixelUnpackState &unpack, 256 gl::Buffer *unpackBuffer, 257 const uint8_t *pixels, 258 ptrdiff_t layerOffset) 259 { 260 ImageD3D *image = getImage(index); 261 ASSERT(image); 262 263 // No-op 264 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) 265 { 266 return angle::Result::Continue; 267 } 268 269 // We no longer need the "GLenum format" parameter to TexImage to determine what data format 270 // "pixels" contains. From our image internal format we know how many channels to expect, and 271 // "type" gives the format of pixel's components. 272 const uint8_t *pixelData = nullptr; 273 ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); 274 275 if (pixelData != nullptr) 276 { 277 if (shouldUseSetData(image)) 278 { 279 ANGLE_TRY( 280 mTexStorage->setData(context, index, image, nullptr, type, unpack, pixelData)); 281 } 282 else 283 { 284 gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), 285 image->getDepth()); 286 ANGLE_TRY(image->loadData(context, fullImageArea, unpack, type, pixelData, 287 index.usesTex3D())); 288 } 289 290 mDirtyImages = true; 291 } 292 293 return angle::Result::Continue; 294 } 295 296 angle::Result TextureD3D::subImage(const gl::Context *context, 297 const gl::ImageIndex &index, 298 const gl::Box &area, 299 GLenum format, 300 GLenum type, 301 const gl::PixelUnpackState &unpack, 302 gl::Buffer *unpackBuffer, 303 const uint8_t *pixels, 304 ptrdiff_t layerOffset) 305 { 306 // CPU readback & copy where direct GPU copy is not supported 307 const uint8_t *pixelData = nullptr; 308 ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); 309 310 if (pixelData != nullptr) 311 { 312 ImageD3D *image = getImage(index); 313 ASSERT(image); 314 315 if (shouldUseSetData(image)) 316 { 317 return mTexStorage->setData(context, index, image, &area, type, unpack, pixelData); 318 } 319 320 ANGLE_TRY(image->loadData(context, area, unpack, type, pixelData, index.usesTex3D())); 321 ANGLE_TRY(commitRegion(context, index, area)); 322 mDirtyImages = true; 323 } 324 325 return angle::Result::Continue; 326 } 327 328 angle::Result TextureD3D::setCompressedImageImpl(const gl::Context *context, 329 const gl::ImageIndex &index, 330 const gl::PixelUnpackState &unpack, 331 const uint8_t *pixels, 332 ptrdiff_t layerOffset) 333 { 334 ImageD3D *image = getImage(index); 335 ASSERT(image); 336 337 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) 338 { 339 return angle::Result::Continue; 340 } 341 342 // We no longer need the "GLenum format" parameter to TexImage to determine what data format 343 // "pixels" contains. From our image internal format we know how many channels to expect, and 344 // "type" gives the format of pixel's components. 345 const uint8_t *pixelData = nullptr; 346 gl::Buffer *unpackBuffer = context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack); 347 ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); 348 349 if (pixelData != nullptr) 350 { 351 gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); 352 ANGLE_TRY(image->loadCompressedData(context, fullImageArea, pixelData)); 353 354 mDirtyImages = true; 355 } 356 357 return angle::Result::Continue; 358 } 359 360 angle::Result TextureD3D::subImageCompressed(const gl::Context *context, 361 const gl::ImageIndex &index, 362 const gl::Box &area, 363 GLenum format, 364 const gl::PixelUnpackState &unpack, 365 const uint8_t *pixels, 366 ptrdiff_t layerOffset) 367 { 368 const uint8_t *pixelData = nullptr; 369 gl::Buffer *unpackBuffer = context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack); 370 ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData)); 371 372 if (pixelData != nullptr) 373 { 374 ImageD3D *image = getImage(index); 375 ASSERT(image); 376 377 ANGLE_TRY(image->loadCompressedData(context, area, pixelData)); 378 379 mDirtyImages = true; 380 } 381 382 return angle::Result::Continue; 383 } 384 385 bool TextureD3D::isFastUnpackable(const gl::Buffer *unpackBuffer, 386 const gl::PixelUnpackState &unpack, 387 GLenum sizedInternalFormat) 388 { 389 return unpackBuffer != nullptr && unpack.skipRows == 0 && unpack.skipPixels == 0 && 390 unpack.imageHeight == 0 && unpack.skipImages == 0 && 391 mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat); 392 } 393 394 angle::Result TextureD3D::fastUnpackPixels(const gl::Context *context, 395 const gl::PixelUnpackState &unpack, 396 gl::Buffer *unpackBuffer, 397 const uint8_t *pixels, 398 const gl::Box &destArea, 399 GLenum sizedInternalFormat, 400 GLenum type, 401 RenderTargetD3D *destRenderTarget) 402 { 403 bool check = (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 || 404 unpack.skipImages != 0); 405 ANGLE_CHECK(GetImplAs<ContextD3D>(context), !check, 406 "Unimplemented pixel store parameters in fastUnpackPixels", GL_INVALID_OPERATION); 407 408 // No-op 409 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0) 410 { 411 return angle::Result::Continue; 412 } 413 414 // In order to perform the fast copy through the shader, we must have the right format, and be 415 // able to create a render target. 416 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat)); 417 418 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels); 419 420 ANGLE_TRY(mRenderer->fastCopyBufferToTexture( 421 context, unpack, unpackBuffer, static_cast<unsigned int>(offset), destRenderTarget, 422 sizedInternalFormat, type, destArea)); 423 424 return angle::Result::Continue; 425 } 426 427 GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const 428 { 429 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || 430 mRenderer->getNativeExtensions().textureNpotOES) 431 { 432 // Maximum number of levels 433 return gl::log2(std::max(std::max(width, height), depth)) + 1; 434 } 435 else 436 { 437 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. 438 return 1; 439 } 440 } 441 442 TextureStorage *TextureD3D::getStorage() 443 { 444 ASSERT(mTexStorage); 445 return mTexStorage; 446 } 447 448 ImageD3D *TextureD3D::getBaseLevelImage() const 449 { 450 if (mBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 451 { 452 return nullptr; 453 } 454 return getImage(getImageIndex(mBaseLevel, 0)); 455 } 456 457 angle::Result TextureD3D::setImageExternal(const gl::Context *context, 458 gl::TextureType type, 459 egl::Stream *stream, 460 const egl::Stream::GLTextureDescription &desc) 461 { 462 // Only external images can accept external textures 463 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 464 return angle::Result::Continue; 465 } 466 467 angle::Result TextureD3D::generateMipmap(const gl::Context *context) 468 { 469 const GLuint baseLevel = mState.getEffectiveBaseLevel(); 470 const GLuint maxLevel = mState.getMipmapMaxLevel(); 471 ASSERT(maxLevel > baseLevel); // Should be checked before calling this. 472 473 if (mTexStorage && mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) 474 { 475 // Switch to using the mipmapped texture. 476 TextureStorage *textureStorageEXT = nullptr; 477 ANGLE_TRY(getNativeTexture(context, &textureStorageEXT)); 478 ANGLE_TRY(textureStorageEXT->useLevelZeroWorkaroundTexture(context, false)); 479 } 480 481 // Set up proper mipmap chain in our Image array. 482 ANGLE_TRY(initMipmapImages(context)); 483 484 if (mTexStorage && mTexStorage->supportsNativeMipmapFunction()) 485 { 486 ANGLE_TRY(updateStorage(context)); 487 488 // Generate the mipmap chain using the ad-hoc DirectX function. 489 ANGLE_TRY(mRenderer->generateMipmapUsingD3D(context, mTexStorage, mState)); 490 } 491 else 492 { 493 // Generate the mipmap chain, one level at a time. 494 ANGLE_TRY(generateMipmapUsingImages(context, maxLevel)); 495 } 496 497 return angle::Result::Continue; 498 } 499 500 angle::Result TextureD3D::generateMipmapUsingImages(const gl::Context *context, 501 const GLuint maxLevel) 502 { 503 // We know that all layers have the same dimension, for the texture to be complete 504 GLint layerCount = static_cast<GLint>(getLayerCount(mBaseLevel)); 505 506 if (mTexStorage && !mTexStorage->isRenderTarget() && 507 canCreateRenderTargetForImage(getImageIndex(mBaseLevel, 0)) && 508 mRenderer->getRendererClass() == RENDERER_D3D11) 509 { 510 if (!mRenderer->getFeatures().setDataFasterThanImageUpload.enabled) 511 { 512 ANGLE_TRY(updateStorage(context)); 513 } 514 ANGLE_TRY(ensureRenderTarget(context)); 515 } 516 else if (couldUseSetData() && mTexStorage) 517 { 518 // When making mipmaps with the setData workaround enabled, the texture storage has 519 // the image data already. For non-render-target storage, we have to pull it out into 520 // an image layer. 521 if (!mTexStorage->isRenderTarget()) 522 { 523 // Copy from the storage mip 0 to Image mip 0 524 for (GLint layer = 0; layer < layerCount; ++layer) 525 { 526 gl::ImageIndex srcIndex = getImageIndex(mBaseLevel, layer); 527 528 ImageD3D *image = getImage(srcIndex); 529 ANGLE_TRY(image->copyFromTexStorage(context, srcIndex, mTexStorage)); 530 } 531 } 532 else 533 { 534 ANGLE_TRY(updateStorage(context)); 535 } 536 } 537 538 // TODO: Decouple this from zeroMaxLodWorkaround. This is a 9_3 restriction, unrelated to 539 // zeroMaxLodWorkaround. The restriction is because Feature Level 9_3 can't create SRVs on 540 // individual levels of the texture. As a result, even if the storage is a rendertarget, we 541 // can't use the GPU to generate the mipmaps without further work. The D3D9 renderer works 542 // around this by copying each level of the texture into its own single-layer GPU texture (in 543 // Blit9::boxFilter). Feature Level 9_3 could do something similar, or it could continue to use 544 // CPU-side mipmap generation, or something else. 545 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget() && 546 !(mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)); 547 if (renderableStorage) 548 { 549 ANGLE_TRY(updateStorage(context)); 550 } 551 552 for (GLint layer = 0; layer < layerCount; ++layer) 553 { 554 for (GLuint mip = mBaseLevel + 1; mip <= maxLevel; ++mip) 555 { 556 ASSERT(getLayerCount(mip) == layerCount); 557 558 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer); 559 gl::ImageIndex destIndex = getImageIndex(mip, layer); 560 561 if (renderableStorage) 562 { 563 // GPU-side mipmapping 564 ANGLE_TRY(mTexStorage->generateMipmap(context, sourceIndex, destIndex)); 565 } 566 else 567 { 568 // CPU-side mipmapping 569 ANGLE_TRY( 570 mRenderer->generateMipmap(context, getImage(destIndex), getImage(sourceIndex))); 571 } 572 } 573 } 574 575 mDirtyImages = !renderableStorage; 576 577 if (mTexStorage && mDirtyImages) 578 { 579 ANGLE_TRY(updateStorage(context)); 580 } 581 582 return angle::Result::Continue; 583 } 584 585 bool TextureD3D::isBaseImageZeroSize() const 586 { 587 ImageD3D *baseImage = getBaseLevelImage(); 588 589 if (!baseImage || baseImage->getWidth() <= 0 || baseImage->getHeight() <= 0) 590 { 591 return true; 592 } 593 594 if (baseImage->getType() == gl::TextureType::_3D && baseImage->getDepth() <= 0) 595 { 596 return true; 597 } 598 599 if (baseImage->getType() == gl::TextureType::_2DArray && getLayerCount(getBaseLevel()) <= 0) 600 { 601 return true; 602 } 603 604 return false; 605 } 606 607 angle::Result TextureD3D::ensureBindFlags(const gl::Context *context, BindFlags bindFlags) 608 { 609 ANGLE_TRY(initializeStorage(context, bindFlags)); 610 611 // initializeStorage can fail with NoError if the texture is not complete. This is not 612 // an error for incomplete sampling, but it is a big problem for rendering. 613 if (!mTexStorage) 614 { 615 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 616 return angle::Result::Stop; 617 } 618 619 if (!isBaseImageZeroSize()) 620 { 621 ASSERT(mTexStorage); 622 if ((bindFlags.renderTarget && !mTexStorage->isRenderTarget()) || 623 (bindFlags.unorderedAccess && !mTexStorage->isUnorderedAccess())) 624 { 625 TexStoragePointer newRenderTargetStorage; 626 ANGLE_TRY(createCompleteStorage(context, bindFlags, &newRenderTargetStorage)); 627 628 ANGLE_TRY(mTexStorage->copyToStorage(context, newRenderTargetStorage.get())); 629 ANGLE_TRY(setCompleteTexStorage(context, newRenderTargetStorage.get())); 630 newRenderTargetStorage.release(); 631 // If this texture is used in compute shader, we should invalidate this texture so that 632 // the UAV/SRV is rebound again with this new texture storage in next dispatch call. 633 mTexStorage->invalidateTextures(); 634 } 635 } 636 637 return angle::Result::Continue; 638 } 639 640 angle::Result TextureD3D::ensureRenderTarget(const gl::Context *context) 641 { 642 return ensureBindFlags(context, BindFlags::RenderTarget()); 643 } 644 645 angle::Result TextureD3D::ensureUnorderedAccess(const gl::Context *context) 646 { 647 return ensureBindFlags(context, BindFlags::UnorderedAccess()); 648 } 649 650 bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const 651 { 652 if (index.getType() == gl::TextureType::_2DMultisample || 653 index.getType() == gl::TextureType::_2DMultisampleArray) 654 { 655 ASSERT(index.getType() != gl::TextureType::_2DMultisampleArray || index.hasLayer()); 656 return true; 657 } 658 659 ImageD3D *image = getImage(index); 660 ASSERT(image); 661 bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0))); 662 return (image->isRenderableFormat() && levelsComplete); 663 } 664 665 angle::Result TextureD3D::commitRegion(const gl::Context *context, 666 const gl::ImageIndex &index, 667 const gl::Box ®ion) 668 { 669 if (mTexStorage) 670 { 671 ASSERT(isValidIndex(index)); 672 ImageD3D *image = getImage(index); 673 ANGLE_TRY(image->copyToStorage(context, mTexStorage, index, region)); 674 image->markClean(); 675 } 676 677 return angle::Result::Continue; 678 } 679 680 angle::Result TextureD3D::getAttachmentRenderTarget(const gl::Context *context, 681 GLenum binding, 682 const gl::ImageIndex &imageIndex, 683 GLsizei samples, 684 FramebufferAttachmentRenderTarget **rtOut) 685 { 686 RenderTargetD3D *rtD3D = nullptr; 687 ANGLE_TRY(getRenderTarget(context, imageIndex, samples, &rtD3D)); 688 *rtOut = static_cast<FramebufferAttachmentRenderTarget *>(rtD3D); 689 return angle::Result::Continue; 690 } 691 692 angle::Result TextureD3D::setBaseLevel(const gl::Context *context, GLuint baseLevel) 693 { 694 const int oldStorageWidth = std::max(1, getLevelZeroWidth()); 695 const int oldStorageHeight = std::max(1, getLevelZeroHeight()); 696 const int oldStorageDepth = std::max(1, getLevelZeroDepth()); 697 const int oldStorageFormat = getBaseLevelInternalFormat(); 698 mBaseLevel = baseLevel; 699 700 // When the base level changes, the texture storage might not be valid anymore, since it could 701 // have been created based on the dimensions of the previous specified level range. 702 const int newStorageWidth = std::max(1, getLevelZeroWidth()); 703 const int newStorageHeight = std::max(1, getLevelZeroHeight()); 704 const int newStorageDepth = std::max(1, getLevelZeroDepth()); 705 const int newStorageFormat = getBaseLevelInternalFormat(); 706 if (mTexStorage && 707 (newStorageWidth != oldStorageWidth || newStorageHeight != oldStorageHeight || 708 newStorageDepth != oldStorageDepth || newStorageFormat != oldStorageFormat)) 709 { 710 markAllImagesDirty(); 711 712 // Iterate over all images, and backup the content if it's been used as a render target. The 713 // D3D11 backend can automatically restore images on storage destroy, but it only works for 714 // images that have been associated with the texture storage before, which is insufficient 715 // here. 716 if (mTexStorage->isRenderTarget()) 717 { 718 gl::ImageIndexIterator iterator = imageIterator(); 719 while (iterator.hasNext()) 720 { 721 const gl::ImageIndex index = iterator.next(); 722 const GLsizei samples = getRenderToTextureSamples(); 723 RenderTargetD3D *renderTarget = nullptr; 724 ANGLE_TRY(mTexStorage->findRenderTarget(context, index, samples, &renderTarget)); 725 if (renderTarget) 726 { 727 ANGLE_TRY(getImage(index)->copyFromTexStorage(context, index, mTexStorage)); 728 } 729 } 730 } 731 732 ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask())); 733 } 734 735 return angle::Result::Continue; 736 } 737 738 angle::Result TextureD3D::onLabelUpdate(const gl::Context *context) 739 { 740 if (mTexStorage) 741 { 742 mTexStorage->setLabel(mState.getLabel()); 743 } 744 return angle::Result::Continue; 745 } 746 747 angle::Result TextureD3D::syncState(const gl::Context *context, 748 const gl::Texture::DirtyBits &dirtyBits, 749 gl::Command source) 750 { 751 // This could be improved using dirty bits. 752 return angle::Result::Continue; 753 } 754 755 angle::Result TextureD3D::releaseTexStorage(const gl::Context *context, 756 const gl::TexLevelMask ©StorageToImagesMask) 757 { 758 if (!mTexStorage) 759 { 760 return angle::Result::Continue; 761 } 762 763 if (mTexStorage->isRenderTarget()) 764 { 765 const GLenum storageFormat = getBaseLevelInternalFormat(); 766 const size_t storageLevels = mTexStorage->getLevelCount(); 767 768 gl::ImageIndexIterator iterator = imageIterator(); 769 while (iterator.hasNext()) 770 { 771 const gl::ImageIndex index = iterator.next(); 772 ImageD3D *image = getImage(index); 773 const int storageWidth = std::max(1, getLevelZeroWidth() >> index.getLevelIndex()); 774 const int storageHeight = std::max(1, getLevelZeroHeight() >> index.getLevelIndex()); 775 if (image && isImageComplete(index) && image->getWidth() == storageWidth && 776 image->getHeight() == storageHeight && 777 image->getInternalFormat() == storageFormat && 778 index.getLevelIndex() < static_cast<int>(storageLevels) && 779 copyStorageToImagesMask[index.getLevelIndex()]) 780 { 781 ANGLE_TRY(image->copyFromTexStorage(context, index, mTexStorage)); 782 } 783 } 784 } 785 786 onStateChange(angle::SubjectMessage::StorageReleased); 787 788 auto err = mTexStorage->onDestroy(context); 789 SafeDelete(mTexStorage); 790 return err; 791 } 792 793 void TextureD3D::onDestroy(const gl::Context *context) 794 { 795 (void)releaseTexStorage(context, gl::TexLevelMask()); 796 } 797 798 angle::Result TextureD3D::initializeContents(const gl::Context *context, 799 GLenum binding, 800 const gl::ImageIndex &imageIndex) 801 { 802 ContextD3D *contextD3D = GetImplAs<ContextD3D>(context); 803 gl::ImageIndex index = imageIndex; 804 805 // Special case for D3D11 3D textures. We can't create render targets for individual layers of a 806 // 3D texture, so force the clear to the entire mip. There shouldn't ever be a case where we 807 // would lose existing data. 808 if (index.getType() == gl::TextureType::_3D) 809 { 810 index = gl::ImageIndex::Make3D(index.getLevelIndex(), gl::ImageIndex::kEntireLevel); 811 } 812 else if (index.getType() == gl::TextureType::_2DArray && !index.hasLayer()) 813 { 814 std::array<GLint, gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS> tempLayerCounts; 815 816 GLint levelIndex = index.getLevelIndex(); 817 tempLayerCounts[levelIndex] = getLayerCount(levelIndex); 818 gl::ImageIndexIterator iterator = 819 gl::ImageIndexIterator::Make2DArray(levelIndex, levelIndex + 1, tempLayerCounts.data()); 820 while (iterator.hasNext()) 821 { 822 ANGLE_TRY(initializeContents(context, GL_NONE, iterator.next())); 823 } 824 return angle::Result::Continue; 825 } 826 else if (index.getType() == gl::TextureType::_2DMultisampleArray && !index.hasLayer()) 827 { 828 std::array<GLint, gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS> tempLayerCounts; 829 830 ASSERT(index.getLevelIndex() == 0); 831 tempLayerCounts[0] = getLayerCount(0); 832 gl::ImageIndexIterator iterator = 833 gl::ImageIndexIterator::Make2DMultisampleArray(tempLayerCounts.data()); 834 while (iterator.hasNext()) 835 { 836 ANGLE_TRY(initializeContents(context, GL_NONE, iterator.next())); 837 } 838 return angle::Result::Continue; 839 } 840 841 // Force image clean. 842 ImageD3D *image = getImage(index); 843 if (image) 844 { 845 image->markClean(); 846 } 847 848 // Fast path: can use a render target clear. 849 // We don't use the fast path with the zero max lod workaround because it would introduce a race 850 // between the rendertarget and the staging images. 851 const angle::FeaturesD3D &features = mRenderer->getFeatures(); 852 bool shouldUseClear = (image == nullptr); 853 if (canCreateRenderTargetForImage(index) && !features.zeroMaxLodWorkaround.enabled && 854 (shouldUseClear || features.allowClearForRobustResourceInit.enabled)) 855 { 856 ANGLE_TRY(ensureRenderTarget(context)); 857 ASSERT(mTexStorage); 858 RenderTargetD3D *renderTarget = nullptr; 859 ANGLE_TRY(mTexStorage->getRenderTarget(context, index, 0, &renderTarget)); 860 ANGLE_TRY(mRenderer->initRenderTarget(context, renderTarget)); 861 862 // Force image clean again, the texture storage may have been re-created and the image used. 863 if (image) 864 { 865 image->markClean(); 866 } 867 868 return angle::Result::Continue; 869 } 870 871 ASSERT(image != nullptr); 872 873 // Slow path: non-renderable texture or the texture levels aren't set up. 874 const auto &formatInfo = gl::GetSizedInternalFormatInfo(image->getInternalFormat()); 875 876 GLuint imageBytes = 0; 877 ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeRowPitch(formatInfo.type, image->getWidth(), 878 1, 0, &imageBytes)); 879 imageBytes *= image->getHeight() * image->getDepth(); 880 881 gl::PixelUnpackState zeroDataUnpackState; 882 zeroDataUnpackState.alignment = 1; 883 884 angle::MemoryBuffer *zeroBuffer = nullptr; 885 ANGLE_CHECK_GL_ALLOC(contextD3D, context->getZeroFilledBuffer(imageBytes, &zeroBuffer)); 886 887 if (shouldUseSetData(image)) 888 { 889 ANGLE_TRY(mTexStorage->setData(context, index, image, nullptr, formatInfo.type, 890 zeroDataUnpackState, zeroBuffer->data())); 891 } 892 else 893 { 894 gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); 895 ANGLE_TRY(image->loadData(context, fullImageArea, zeroDataUnpackState, formatInfo.type, 896 zeroBuffer->data(), false)); 897 898 // Force an update to the tex storage so we avoid problems with subImage and dirty regions. 899 if (mTexStorage) 900 { 901 ANGLE_TRY(commitRegion(context, index, fullImageArea)); 902 image->markClean(); 903 } 904 else 905 { 906 mDirtyImages = true; 907 } 908 } 909 return angle::Result::Continue; 910 } 911 912 GLsizei TextureD3D::getRenderToTextureSamples() 913 { 914 if (mTexStorage) 915 { 916 return mTexStorage->getRenderToTextureSamples(); 917 } 918 return 0; 919 } 920 921 void TextureD3D::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) 922 { 923 onStateChange(message); 924 } 925 926 TextureD3D_2D::TextureD3D_2D(const gl::TextureState &state, RendererD3D *renderer) 927 : TextureD3D(state, renderer) 928 { 929 mEGLImageTarget = false; 930 for (auto &image : mImageArray) 931 { 932 image.reset(renderer->createImage()); 933 } 934 } 935 936 void TextureD3D_2D::onDestroy(const gl::Context *context) 937 { 938 // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage 939 // for some of their data. If TextureStorage is deleted before the Images, then their data will 940 // be wastefully copied back from the GPU before we delete the Images. 941 for (auto &image : mImageArray) 942 { 943 image.reset(); 944 } 945 return TextureD3D::onDestroy(context); 946 } 947 948 TextureD3D_2D::~TextureD3D_2D() {} 949 950 ImageD3D *TextureD3D_2D::getImage(int level, int layer) const 951 { 952 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 953 ASSERT(layer == 0); 954 return mImageArray[level].get(); 955 } 956 957 ImageD3D *TextureD3D_2D::getImage(const gl::ImageIndex &index) const 958 { 959 ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 960 ASSERT(!index.hasLayer()); 961 ASSERT(index.getType() == gl::TextureType::_2D || 962 index.getType() == gl::TextureType::VideoImage); 963 return mImageArray[index.getLevelIndex()].get(); 964 } 965 966 GLsizei TextureD3D_2D::getLayerCount(int level) const 967 { 968 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 969 return 1; 970 } 971 972 GLsizei TextureD3D_2D::getWidth(GLint level) const 973 { 974 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 975 return mImageArray[level]->getWidth(); 976 else 977 return 0; 978 } 979 980 GLsizei TextureD3D_2D::getHeight(GLint level) const 981 { 982 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 983 return mImageArray[level]->getHeight(); 984 else 985 return 0; 986 } 987 988 GLenum TextureD3D_2D::getInternalFormat(GLint level) const 989 { 990 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 991 return mImageArray[level]->getInternalFormat(); 992 else 993 return GL_NONE; 994 } 995 996 bool TextureD3D_2D::isDepth(GLint level) const 997 { 998 return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0; 999 } 1000 1001 bool TextureD3D_2D::isSRGB(GLint level) const 1002 { 1003 return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB; 1004 } 1005 1006 angle::Result TextureD3D_2D::setImage(const gl::Context *context, 1007 const gl::ImageIndex &index, 1008 GLenum internalFormat, 1009 const gl::Extents &size, 1010 GLenum format, 1011 GLenum type, 1012 const gl::PixelUnpackState &unpack, 1013 gl::Buffer *unpackBuffer, 1014 const uint8_t *pixels) 1015 { 1016 ASSERT((index.getTarget() == gl::TextureTarget::_2D || 1017 index.getTarget() == gl::TextureTarget::VideoImage) && 1018 size.depth == 1); 1019 1020 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); 1021 1022 bool fastUnpacked = false; 1023 1024 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat, 1025 size, false)); 1026 1027 // Attempt a fast gpu copy of the pixel data to the surface 1028 if (mTexStorage) 1029 { 1030 ANGLE_TRY(mTexStorage->releaseMultisampledTexStorageForLevel(index.getLevelIndex())); 1031 } 1032 if (isFastUnpackable(unpackBuffer, unpack, internalFormatInfo.sizedInternalFormat) && 1033 isLevelComplete(index.getLevelIndex())) 1034 { 1035 // Will try to create RT storage if it does not exist 1036 RenderTargetD3D *destRenderTarget = nullptr; 1037 ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget)); 1038 1039 gl::Box destArea(0, 0, 0, getWidth(index.getLevelIndex()), getHeight(index.getLevelIndex()), 1040 1); 1041 1042 ANGLE_TRY(fastUnpackPixels(context, unpack, unpackBuffer, pixels, destArea, 1043 internalFormatInfo.sizedInternalFormat, type, destRenderTarget)); 1044 1045 // Ensure we don't overwrite our newly initialized data 1046 mImageArray[index.getLevelIndex()]->markClean(); 1047 1048 fastUnpacked = true; 1049 } 1050 1051 if (!fastUnpacked) 1052 { 1053 ANGLE_TRY(setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0)); 1054 } 1055 1056 return angle::Result::Continue; 1057 } 1058 1059 angle::Result TextureD3D_2D::setSubImage(const gl::Context *context, 1060 const gl::ImageIndex &index, 1061 const gl::Box &area, 1062 GLenum format, 1063 GLenum type, 1064 const gl::PixelUnpackState &unpack, 1065 gl::Buffer *unpackBuffer, 1066 const uint8_t *pixels) 1067 { 1068 ASSERT(index.getTarget() == gl::TextureTarget::_2D && area.depth == 1 && area.z == 0); 1069 1070 GLenum mipFormat = getInternalFormat(index.getLevelIndex()); 1071 if (mTexStorage) 1072 { 1073 ANGLE_TRY(mTexStorage->releaseMultisampledTexStorageForLevel(index.getLevelIndex())); 1074 } 1075 if (isFastUnpackable(unpackBuffer, unpack, mipFormat) && isLevelComplete(index.getLevelIndex())) 1076 { 1077 RenderTargetD3D *renderTarget = nullptr; 1078 ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &renderTarget)); 1079 ASSERT(!mImageArray[index.getLevelIndex()]->isDirty()); 1080 1081 return fastUnpackPixels(context, unpack, unpackBuffer, pixels, area, mipFormat, type, 1082 renderTarget); 1083 } 1084 else 1085 { 1086 return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer, 1087 pixels, 0); 1088 } 1089 } 1090 1091 angle::Result TextureD3D_2D::setCompressedImage(const gl::Context *context, 1092 const gl::ImageIndex &index, 1093 GLenum internalFormat, 1094 const gl::Extents &size, 1095 const gl::PixelUnpackState &unpack, 1096 size_t imageSize, 1097 const uint8_t *pixels) 1098 { 1099 ASSERT(index.getTarget() == gl::TextureTarget::_2D && size.depth == 1); 1100 1101 // compressed formats don't have separate sized internal formats-- we can just use the 1102 // compressed format directly 1103 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false)); 1104 1105 return setCompressedImageImpl(context, index, unpack, pixels, 0); 1106 } 1107 1108 angle::Result TextureD3D_2D::setCompressedSubImage(const gl::Context *context, 1109 const gl::ImageIndex &index, 1110 const gl::Box &area, 1111 GLenum format, 1112 const gl::PixelUnpackState &unpack, 1113 size_t imageSize, 1114 const uint8_t *pixels) 1115 { 1116 ASSERT(index.getTarget() == gl::TextureTarget::_2D && area.depth == 1 && area.z == 0); 1117 ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0)); 1118 1119 return commitRegion(context, index, area); 1120 } 1121 1122 angle::Result TextureD3D_2D::copyImage(const gl::Context *context, 1123 const gl::ImageIndex &index, 1124 const gl::Rectangle &sourceArea, 1125 GLenum internalFormat, 1126 gl::Framebuffer *source) 1127 { 1128 ASSERT(index.getTarget() == gl::TextureTarget::_2D); 1129 1130 const gl::InternalFormat &internalFormatInfo = 1131 gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE); 1132 gl::Extents sourceExtents(sourceArea.width, sourceArea.height, 1); 1133 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat, 1134 sourceExtents, false)); 1135 1136 gl::Extents fbSize = source->getReadColorAttachment()->getSize(); 1137 1138 // Does the read area extend beyond the framebuffer? 1139 bool outside = sourceArea.x < 0 || sourceArea.y < 0 || 1140 sourceArea.x + sourceArea.width > fbSize.width || 1141 sourceArea.y + sourceArea.height > fbSize.height; 1142 1143 // WebGL requires that pixels that would be outside the framebuffer are treated as zero values, 1144 // so clear the mip level to 0 prior to making the copy if any pixel would be sampled outside. 1145 // Same thing for robust resource init. 1146 if (outside && (context->isWebGL() || context->isRobustResourceInitEnabled())) 1147 { 1148 ANGLE_TRY(initializeContents(context, GL_NONE, index)); 1149 } 1150 1151 gl::Rectangle clippedArea; 1152 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea)) 1153 { 1154 // Empty source area, nothing to do. 1155 return angle::Result::Continue; 1156 } 1157 1158 gl::Offset destOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y, 0); 1159 1160 // If the zero max LOD workaround is active, then we can't sample from individual layers of the 1161 // framebuffer in shaders, so we should use the non-rendering copy path. 1162 if (!canCreateRenderTargetForImage(index) || 1163 mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) 1164 { 1165 ANGLE_TRY(mImageArray[index.getLevelIndex()]->copyFromFramebuffer(context, destOffset, 1166 clippedArea, source)); 1167 mDirtyImages = true; 1168 } 1169 else 1170 { 1171 ANGLE_TRY(ensureRenderTarget(context)); 1172 1173 if (clippedArea.width != 0 && clippedArea.height != 0 && 1174 isValidLevel(index.getLevelIndex())) 1175 { 1176 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex())); 1177 ANGLE_TRY(mRenderer->copyImage2D(context, source, clippedArea, internalFormat, 1178 destOffset, mTexStorage, index.getLevelIndex())); 1179 } 1180 } 1181 1182 return angle::Result::Continue; 1183 } 1184 1185 angle::Result TextureD3D_2D::copySubImage(const gl::Context *context, 1186 const gl::ImageIndex &index, 1187 const gl::Offset &destOffset, 1188 const gl::Rectangle &sourceArea, 1189 gl::Framebuffer *source) 1190 { 1191 ASSERT(index.getTarget() == gl::TextureTarget::_2D && destOffset.z == 0); 1192 1193 gl::Extents fbSize = source->getReadColorAttachment()->getSize(); 1194 gl::Rectangle clippedArea; 1195 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea)) 1196 { 1197 return angle::Result::Continue; 1198 } 1199 const gl::Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x, 1200 destOffset.y + clippedArea.y - sourceArea.y, 0); 1201 1202 // can only make our texture storage to a render target if level 0 is defined (with a width & 1203 // height) and the current level we're copying to is defined (with appropriate format, width & 1204 // height) 1205 1206 // If the zero max LOD workaround is active, then we can't sample from individual layers of the 1207 // framebuffer in shaders, so we should use the non-rendering copy path. 1208 if (!canCreateRenderTargetForImage(index) || 1209 mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) 1210 { 1211 ANGLE_TRY(mImageArray[index.getLevelIndex()]->copyFromFramebuffer(context, clippedOffset, 1212 clippedArea, source)); 1213 mDirtyImages = true; 1214 onStateChange(angle::SubjectMessage::DirtyBitsFlagged); 1215 } 1216 else 1217 { 1218 ANGLE_TRY(ensureRenderTarget(context)); 1219 1220 if (isValidLevel(index.getLevelIndex())) 1221 { 1222 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex())); 1223 ANGLE_TRY(mRenderer->copyImage2D(context, source, clippedArea, 1224 gl::GetUnsizedFormat(getBaseLevelInternalFormat()), 1225 clippedOffset, mTexStorage, index.getLevelIndex())); 1226 } 1227 } 1228 1229 return angle::Result::Continue; 1230 } 1231 1232 angle::Result TextureD3D_2D::copyTexture(const gl::Context *context, 1233 const gl::ImageIndex &index, 1234 GLenum internalFormat, 1235 GLenum type, 1236 GLint sourceLevel, 1237 bool unpackFlipY, 1238 bool unpackPremultiplyAlpha, 1239 bool unpackUnmultiplyAlpha, 1240 const gl::Texture *source) 1241 { 1242 ASSERT(index.getTarget() == gl::TextureTarget::_2D); 1243 1244 gl::TextureType sourceType = source->getType(); 1245 1246 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); 1247 gl::Extents size( 1248 static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)), 1249 static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)), 1250 1); 1251 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat, 1252 size, false)); 1253 1254 gl::Box sourceBox(0, 0, 0, size.width, size.height, 1); 1255 gl::Offset destOffset(0, 0, 0); 1256 1257 if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(index)) 1258 { 1259 ANGLE_TRY(ensureRenderTarget(context)); 1260 ASSERT(isValidLevel(index.getLevelIndex())); 1261 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex())); 1262 1263 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D, 1264 sourceBox, internalFormatInfo.format, 1265 internalFormatInfo.type, destOffset, mTexStorage, 1266 index.getTarget(), index.getLevelIndex(), unpackFlipY, 1267 unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); 1268 } 1269 else 1270 { 1271 gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel); 1272 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source); 1273 ImageD3D *sourceImage = nullptr; 1274 ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); 1275 1276 ImageD3D *destImage = nullptr; 1277 ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage)); 1278 1279 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset, 1280 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); 1281 1282 mDirtyImages = true; 1283 1284 gl::Box destRegion(destOffset, size); 1285 ANGLE_TRY(commitRegion(context, index, destRegion)); 1286 } 1287 1288 return angle::Result::Continue; 1289 } 1290 1291 angle::Result TextureD3D_2D::copySubTexture(const gl::Context *context, 1292 const gl::ImageIndex &index, 1293 const gl::Offset &destOffset, 1294 GLint sourceLevel, 1295 const gl::Box &sourceBox, 1296 bool unpackFlipY, 1297 bool unpackPremultiplyAlpha, 1298 bool unpackUnmultiplyAlpha, 1299 const gl::Texture *source) 1300 { 1301 ASSERT(index.getTarget() == gl::TextureTarget::_2D); 1302 1303 if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(index)) 1304 { 1305 ANGLE_TRY(ensureRenderTarget(context)); 1306 ASSERT(isValidLevel(index.getLevelIndex())); 1307 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex())); 1308 1309 const gl::InternalFormat &internalFormatInfo = 1310 gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex())); 1311 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D, 1312 sourceBox, internalFormatInfo.format, 1313 internalFormatInfo.type, destOffset, mTexStorage, 1314 index.getTarget(), index.getLevelIndex(), unpackFlipY, 1315 unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); 1316 } 1317 else 1318 { 1319 gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel); 1320 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source); 1321 ImageD3D *sourceImage = nullptr; 1322 ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); 1323 1324 ImageD3D *destImage = nullptr; 1325 ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage)); 1326 1327 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset, 1328 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); 1329 1330 mDirtyImages = true; 1331 1332 gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceBox.width, sourceBox.height, 1); 1333 ANGLE_TRY(commitRegion(context, index, destRegion)); 1334 } 1335 1336 return angle::Result::Continue; 1337 } 1338 1339 angle::Result TextureD3D_2D::copyCompressedTexture(const gl::Context *context, 1340 const gl::Texture *source) 1341 { 1342 gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType()); 1343 GLint sourceLevel = 0; 1344 1345 GLint destLevel = 0; 1346 1347 GLenum sizedInternalFormat = 1348 source->getFormat(sourceTarget, sourceLevel).info->sizedInternalFormat; 1349 gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)), 1350 static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1); 1351 ANGLE_TRY(redefineImage(context, destLevel, sizedInternalFormat, size, false)); 1352 1353 ANGLE_TRY(initializeStorage(context, BindFlags())); 1354 ASSERT(mTexStorage); 1355 1356 ANGLE_TRY( 1357 mRenderer->copyCompressedTexture(context, source, sourceLevel, mTexStorage, destLevel)); 1358 1359 return angle::Result::Continue; 1360 } 1361 1362 angle::Result TextureD3D_2D::setStorage(const gl::Context *context, 1363 gl::TextureType type, 1364 size_t levels, 1365 GLenum internalFormat, 1366 const gl::Extents &size) 1367 { 1368 ASSERT(type == gl::TextureType::_2D && size.depth == 1); 1369 1370 for (size_t level = 0; level < levels; level++) 1371 { 1372 gl::Extents levelSize(std::max(1, size.width >> level), std::max(1, size.height >> level), 1373 1); 1374 ANGLE_TRY(redefineImage(context, level, internalFormat, levelSize, true)); 1375 } 1376 1377 for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 1378 { 1379 ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true)); 1380 } 1381 1382 // TODO(geofflang): Verify storage creation had no errors 1383 BindFlags flags; 1384 flags.renderTarget = IsRenderTargetUsage(mState.getUsage()); 1385 TexStoragePointer storage = { 1386 mRenderer->createTextureStorage2D(internalFormat, flags, size.width, size.height, 1387 static_cast<int>(levels), mState.getLabel(), false), 1388 context}; 1389 1390 ANGLE_TRY(setCompleteTexStorage(context, storage.get())); 1391 storage.release(); 1392 1393 ANGLE_TRY(updateStorage(context)); 1394 1395 mImmutable = true; 1396 1397 return angle::Result::Continue; 1398 } 1399 1400 angle::Result TextureD3D_2D::bindTexImage(const gl::Context *context, egl::Surface *surface) 1401 { 1402 GLenum internalformat = surface->getConfig()->renderTargetFormat; 1403 1404 gl::Extents size(surface->getWidth(), surface->getHeight(), 1); 1405 ANGLE_TRY(redefineImage(context, 0, internalformat, size, true)); 1406 1407 ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask())); 1408 1409 SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface); 1410 ASSERT(surfaceD3D); 1411 1412 mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain(), mState.getLabel()); 1413 mEGLImageTarget = false; 1414 1415 mDirtyImages = false; 1416 mImageArray[0]->markClean(); 1417 1418 return angle::Result::Continue; 1419 } 1420 1421 angle::Result TextureD3D_2D::releaseTexImage(const gl::Context *context) 1422 { 1423 if (mTexStorage) 1424 { 1425 ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask())); 1426 } 1427 1428 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 1429 { 1430 ANGLE_TRY(redefineImage(context, i, GL_NONE, gl::Extents(0, 0, 1), true)); 1431 } 1432 1433 return angle::Result::Continue; 1434 } 1435 1436 angle::Result TextureD3D_2D::setEGLImageTarget(const gl::Context *context, 1437 gl::TextureType type, 1438 egl::Image *image) 1439 { 1440 EGLImageD3D *eglImaged3d = GetImplAs<EGLImageD3D>(image); 1441 1442 // Set the properties of the base mip level from the EGL image 1443 const auto &format = image->getFormat(); 1444 gl::Extents size(static_cast<int>(image->getWidth()), static_cast<int>(image->getHeight()), 1); 1445 ANGLE_TRY(redefineImage(context, 0, format.info->sizedInternalFormat, size, true)); 1446 1447 // Clear all other images. 1448 for (size_t level = 1; level < mImageArray.size(); level++) 1449 { 1450 ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true)); 1451 } 1452 1453 ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask())); 1454 mImageArray[0]->markClean(); 1455 1456 // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error. 1457 RenderTargetD3D *renderTargetD3D = nullptr; 1458 ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D)); 1459 1460 mTexStorage = 1461 mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D, mState.getLabel()); 1462 mEGLImageTarget = true; 1463 1464 return angle::Result::Continue; 1465 } 1466 1467 angle::Result TextureD3D_2D::initMipmapImages(const gl::Context *context) 1468 { 1469 const GLuint baseLevel = mState.getEffectiveBaseLevel(); 1470 const GLuint maxLevel = mState.getMipmapMaxLevel(); 1471 // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap 1472 // levels. 1473 for (GLuint level = baseLevel + 1; level <= maxLevel; level++) 1474 { 1475 gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1), 1476 std::max(getLevelZeroHeight() >> level, 1), 1); 1477 1478 ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false)); 1479 } 1480 1481 // We should be mip-complete now so generate the storage. 1482 ANGLE_TRY(initializeStorage(context, BindFlags::RenderTarget())); 1483 1484 return angle::Result::Continue; 1485 } 1486 1487 angle::Result TextureD3D_2D::getRenderTarget(const gl::Context *context, 1488 const gl::ImageIndex &index, 1489 GLsizei samples, 1490 RenderTargetD3D **outRT) 1491 { 1492 ASSERT(!index.hasLayer()); 1493 1494 // ensure the underlying texture is created 1495 ANGLE_TRY(ensureRenderTarget(context)); 1496 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex())); 1497 1498 return mTexStorage->getRenderTarget(context, index, samples, outRT); 1499 } 1500 1501 bool TextureD3D_2D::isValidLevel(int level) const 1502 { 1503 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false); 1504 } 1505 1506 bool TextureD3D_2D::isLevelComplete(int level) const 1507 { 1508 if (isImmutable()) 1509 { 1510 return true; 1511 } 1512 1513 GLsizei width = getLevelZeroWidth(); 1514 GLsizei height = getLevelZeroHeight(); 1515 1516 if (width <= 0 || height <= 0) 1517 { 1518 return false; 1519 } 1520 1521 // The base image level is complete if the width and height are positive 1522 if (level == static_cast<int>(getBaseLevel())) 1523 { 1524 return true; 1525 } 1526 1527 ASSERT(level >= 0 && level <= static_cast<int>(mImageArray.size()) && 1528 mImageArray[level] != nullptr); 1529 ImageD3D *image = mImageArray[level].get(); 1530 1531 if (image->getInternalFormat() != getBaseLevelInternalFormat()) 1532 { 1533 return false; 1534 } 1535 1536 if (image->getWidth() != std::max(1, width >> level)) 1537 { 1538 return false; 1539 } 1540 1541 if (image->getHeight() != std::max(1, height >> level)) 1542 { 1543 return false; 1544 } 1545 1546 return true; 1547 } 1548 1549 bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const 1550 { 1551 return isLevelComplete(index.getLevelIndex()); 1552 } 1553 1554 // Constructs a native texture resource from the texture images 1555 angle::Result TextureD3D_2D::initializeStorage(const gl::Context *context, BindFlags bindFlags) 1556 { 1557 // Only initialize the first time this texture is used as a render target or shader resource 1558 if (mTexStorage) 1559 { 1560 return angle::Result::Continue; 1561 } 1562 1563 // do not attempt to create storage for nonexistant data 1564 if (!isLevelComplete(getBaseLevel())) 1565 { 1566 return angle::Result::Continue; 1567 } 1568 1569 bindFlags.renderTarget |= IsRenderTargetUsage(mState.getUsage()); 1570 1571 TexStoragePointer storage; 1572 ANGLE_TRY(createCompleteStorage(context, bindFlags, &storage)); 1573 1574 ANGLE_TRY(setCompleteTexStorage(context, storage.get())); 1575 storage.release(); 1576 1577 ASSERT(mTexStorage); 1578 1579 // flush image data to the storage 1580 ANGLE_TRY(updateStorage(context)); 1581 1582 return angle::Result::Continue; 1583 } 1584 1585 angle::Result TextureD3D_2D::createCompleteStorage(const gl::Context *context, 1586 BindFlags bindFlags, 1587 TexStoragePointer *outStorage) const 1588 { 1589 GLsizei width = getLevelZeroWidth(); 1590 GLsizei height = getLevelZeroHeight(); 1591 GLenum internalFormat = getBaseLevelInternalFormat(); 1592 1593 ASSERT(width > 0 && height > 0); 1594 1595 // use existing storage level count, when previously specified by TexStorage*D 1596 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); 1597 1598 bool hintLevelZeroOnly = false; 1599 if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) 1600 { 1601 // If any of the CPU images (levels >= 1) are dirty, then the textureStorage2D should use 1602 // the mipped texture to begin with. Otherwise, it should use the level-zero-only texture. 1603 hintLevelZeroOnly = true; 1604 for (int level = 1; level < levels && hintLevelZeroOnly; level++) 1605 { 1606 hintLevelZeroOnly = !(mImageArray[level]->isDirty() && isLevelComplete(level)); 1607 } 1608 } 1609 1610 // TODO(geofflang): Determine if the texture creation succeeded 1611 *outStorage = {mRenderer->createTextureStorage2D(internalFormat, bindFlags, width, height, 1612 levels, mState.getLabel(), hintLevelZeroOnly), 1613 context}; 1614 1615 return angle::Result::Continue; 1616 } 1617 1618 angle::Result TextureD3D_2D::setCompleteTexStorage(const gl::Context *context, 1619 TextureStorage *newCompleteTexStorage) 1620 { 1621 if (newCompleteTexStorage && newCompleteTexStorage->isManaged()) 1622 { 1623 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++) 1624 { 1625 ANGLE_TRY( 1626 mImageArray[level]->setManagedSurface2D(context, newCompleteTexStorage, level)); 1627 } 1628 } 1629 1630 gl::TexLevelMask copyImageMask; 1631 copyImageMask.set(); 1632 1633 ANGLE_TRY(releaseTexStorage(context, copyImageMask)); 1634 mTexStorage = newCompleteTexStorage; 1635 mTexStorageObserverBinding.bind(mTexStorage); 1636 1637 mDirtyImages = true; 1638 1639 return angle::Result::Continue; 1640 } 1641 1642 angle::Result TextureD3D_2D::updateStorage(const gl::Context *context) 1643 { 1644 if (!mDirtyImages) 1645 { 1646 return angle::Result::Continue; 1647 } 1648 1649 ASSERT(mTexStorage != nullptr); 1650 GLint storageLevels = mTexStorage->getLevelCount(); 1651 for (int level = 0; level < storageLevels; level++) 1652 { 1653 if (mImageArray[level]->isDirty() && isLevelComplete(level)) 1654 { 1655 ANGLE_TRY(updateStorageLevel(context, level)); 1656 } 1657 } 1658 1659 mDirtyImages = false; 1660 return angle::Result::Continue; 1661 } 1662 1663 angle::Result TextureD3D_2D::updateStorageLevel(const gl::Context *context, int level) 1664 { 1665 ASSERT(level <= static_cast<int>(mImageArray.size()) && mImageArray[level] != nullptr); 1666 ASSERT(isLevelComplete(level)); 1667 1668 if (mImageArray[level]->isDirty()) 1669 { 1670 gl::ImageIndex index = gl::ImageIndex::Make2D(level); 1671 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); 1672 ANGLE_TRY(commitRegion(context, index, region)); 1673 } 1674 1675 return angle::Result::Continue; 1676 } 1677 1678 angle::Result TextureD3D_2D::redefineImage(const gl::Context *context, 1679 size_t level, 1680 GLenum internalformat, 1681 const gl::Extents &size, 1682 bool forceRelease) 1683 { 1684 ASSERT(size.depth == 1); 1685 1686 // If there currently is a corresponding storage texture image, it has these parameters 1687 const int storageWidth = std::max(1, getLevelZeroWidth() >> level); 1688 const int storageHeight = std::max(1, getLevelZeroHeight() >> level); 1689 const GLenum storageFormat = getBaseLevelInternalFormat(); 1690 1691 if (mTexStorage) 1692 { 1693 const size_t storageLevels = mTexStorage->getLevelCount(); 1694 1695 // If the storage was from an EGL image, copy it back into local images to preserve it 1696 // while orphaning 1697 if (level != 0 && mEGLImageTarget) 1698 { 1699 ANGLE_TRY(mImageArray[0]->copyFromTexStorage(context, gl::ImageIndex::Make2D(0), 1700 mTexStorage)); 1701 } 1702 1703 if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth || 1704 size.height != storageHeight || internalformat != storageFormat || 1705 mEGLImageTarget) // Discard mismatched storage 1706 { 1707 gl::TexLevelMask copyImageMask; 1708 copyImageMask.set(); 1709 copyImageMask.set(level, false); 1710 1711 ANGLE_TRY(releaseTexStorage(context, copyImageMask)); 1712 markAllImagesDirty(); 1713 } 1714 } 1715 1716 mImageArray[level]->redefine(gl::TextureType::_2D, internalformat, size, forceRelease); 1717 mDirtyImages = mDirtyImages || mImageArray[level]->isDirty(); 1718 1719 // Can't be an EGL image target after being redefined 1720 mEGLImageTarget = false; 1721 1722 return angle::Result::Continue; 1723 } 1724 1725 gl::ImageIndexIterator TextureD3D_2D::imageIterator() const 1726 { 1727 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount()); 1728 } 1729 1730 gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const 1731 { 1732 // "layer" does not apply to 2D Textures. 1733 return gl::ImageIndex::Make2D(mip); 1734 } 1735 1736 bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const 1737 { 1738 return (mTexStorage && index.getType() == gl::TextureType::_2D && index.getLevelIndex() >= 0 && 1739 index.getLevelIndex() < mTexStorage->getLevelCount()); 1740 } 1741 1742 void TextureD3D_2D::markAllImagesDirty() 1743 { 1744 for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 1745 { 1746 mImageArray[i]->markDirty(); 1747 } 1748 mDirtyImages = true; 1749 } 1750 1751 TextureD3D_Cube::TextureD3D_Cube(const gl::TextureState &state, RendererD3D *renderer) 1752 : TextureD3D(state, renderer) 1753 { 1754 for (auto &face : mImageArray) 1755 { 1756 for (auto &image : face) 1757 { 1758 image.reset(renderer->createImage()); 1759 } 1760 } 1761 } 1762 1763 void TextureD3D_Cube::onDestroy(const gl::Context *context) 1764 { 1765 // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage 1766 // for some of their data. If TextureStorage is deleted before the Images, then their data will 1767 // be wastefully copied back from the GPU before we delete the Images. 1768 for (auto &face : mImageArray) 1769 { 1770 for (auto &image : face) 1771 { 1772 image.reset(); 1773 } 1774 } 1775 return TextureD3D::onDestroy(context); 1776 } 1777 1778 TextureD3D_Cube::~TextureD3D_Cube() {} 1779 1780 ImageD3D *TextureD3D_Cube::getImage(int level, int layer) const 1781 { 1782 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 1783 ASSERT(layer >= 0 && static_cast<size_t>(layer) < gl::kCubeFaceCount); 1784 return mImageArray[layer][level].get(); 1785 } 1786 1787 ImageD3D *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const 1788 { 1789 ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 1790 ASSERT(gl::IsCubeMapFaceTarget(index.getTarget())); 1791 return mImageArray[index.cubeMapFaceIndex()][index.getLevelIndex()].get(); 1792 } 1793 1794 GLsizei TextureD3D_Cube::getLayerCount(int level) const 1795 { 1796 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 1797 return gl::kCubeFaceCount; 1798 } 1799 1800 GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const 1801 { 1802 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 1803 return mImageArray[layer][level]->getInternalFormat(); 1804 else 1805 return GL_NONE; 1806 } 1807 1808 bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const 1809 { 1810 return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0; 1811 } 1812 1813 bool TextureD3D_Cube::isSRGB(GLint level, GLint layer) const 1814 { 1815 return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).colorEncoding == GL_SRGB; 1816 } 1817 1818 angle::Result TextureD3D_Cube::setEGLImageTarget(const gl::Context *context, 1819 gl::TextureType type, 1820 egl::Image *image) 1821 { 1822 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 1823 return angle::Result::Continue; 1824 } 1825 1826 angle::Result TextureD3D_Cube::setImage(const gl::Context *context, 1827 const gl::ImageIndex &index, 1828 GLenum internalFormat, 1829 const gl::Extents &size, 1830 GLenum format, 1831 GLenum type, 1832 const gl::PixelUnpackState &unpack, 1833 gl::Buffer *unpackBuffer, 1834 const uint8_t *pixels) 1835 { 1836 ASSERT(size.depth == 1); 1837 1838 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); 1839 ANGLE_TRY(redefineImage(context, index.cubeMapFaceIndex(), index.getLevelIndex(), 1840 internalFormatInfo.sizedInternalFormat, size, false)); 1841 1842 return setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0); 1843 } 1844 1845 angle::Result TextureD3D_Cube::setSubImage(const gl::Context *context, 1846 const gl::ImageIndex &index, 1847 const gl::Box &area, 1848 GLenum format, 1849 GLenum type, 1850 const gl::PixelUnpackState &unpack, 1851 gl::Buffer *unpackBuffer, 1852 const uint8_t *pixels) 1853 { 1854 ASSERT(area.depth == 1 && area.z == 0); 1855 return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer, pixels, 1856 0); 1857 } 1858 1859 angle::Result TextureD3D_Cube::setCompressedImage(const gl::Context *context, 1860 const gl::ImageIndex &index, 1861 GLenum internalFormat, 1862 const gl::Extents &size, 1863 const gl::PixelUnpackState &unpack, 1864 size_t imageSize, 1865 const uint8_t *pixels) 1866 { 1867 ASSERT(size.depth == 1); 1868 1869 // compressed formats don't have separate sized internal formats-- we can just use the 1870 // compressed format directly 1871 ANGLE_TRY(redefineImage(context, index.cubeMapFaceIndex(), index.getLevelIndex(), 1872 internalFormat, size, false)); 1873 1874 return setCompressedImageImpl(context, index, unpack, pixels, 0); 1875 } 1876 1877 angle::Result TextureD3D_Cube::setCompressedSubImage(const gl::Context *context, 1878 const gl::ImageIndex &index, 1879 const gl::Box &area, 1880 GLenum format, 1881 const gl::PixelUnpackState &unpack, 1882 size_t imageSize, 1883 const uint8_t *pixels) 1884 { 1885 ASSERT(area.depth == 1 && area.z == 0); 1886 1887 ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0)); 1888 return commitRegion(context, index, area); 1889 } 1890 1891 angle::Result TextureD3D_Cube::copyImage(const gl::Context *context, 1892 const gl::ImageIndex &index, 1893 const gl::Rectangle &sourceArea, 1894 GLenum internalFormat, 1895 gl::Framebuffer *source) 1896 { 1897 GLint faceIndex = index.cubeMapFaceIndex(); 1898 const gl::InternalFormat &internalFormatInfo = 1899 gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE); 1900 1901 gl::Extents size(sourceArea.width, sourceArea.height, 1); 1902 ANGLE_TRY(redefineImage(context, faceIndex, index.getLevelIndex(), 1903 internalFormatInfo.sizedInternalFormat, size, false)); 1904 1905 gl::Extents fbSize = source->getReadColorAttachment()->getSize(); 1906 1907 // Does the read area extend beyond the framebuffer? 1908 bool outside = sourceArea.x < 0 || sourceArea.y < 0 || 1909 sourceArea.x + sourceArea.width > fbSize.width || 1910 sourceArea.y + sourceArea.height > fbSize.height; 1911 1912 // WebGL requires that pixels that would be outside the framebuffer are treated as zero values, 1913 // so clear the mip level to 0 prior to making the copy if any pixel would be sampled outside. 1914 // Same thing for robust resource init. 1915 if (outside && (context->isWebGL() || context->isRobustResourceInitEnabled())) 1916 { 1917 ANGLE_TRY(initializeContents(context, GL_NONE, index)); 1918 } 1919 1920 gl::Rectangle clippedArea; 1921 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea)) 1922 { 1923 // Empty source area, nothing to do. 1924 return angle::Result::Continue; 1925 } 1926 1927 gl::Offset destOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y, 0); 1928 1929 // If the zero max LOD workaround is active, then we can't sample from individual layers of the 1930 // framebuffer in shaders, so we should use the non-rendering copy path. 1931 if (!canCreateRenderTargetForImage(index) || 1932 mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) 1933 { 1934 ANGLE_TRY(mImageArray[faceIndex][index.getLevelIndex()]->copyFromFramebuffer( 1935 context, destOffset, clippedArea, source)); 1936 mDirtyImages = true; 1937 onStateChange(angle::SubjectMessage::DirtyBitsFlagged); 1938 } 1939 else 1940 { 1941 ANGLE_TRY(ensureRenderTarget(context)); 1942 1943 ASSERT(size.width == size.height); 1944 1945 if (size.width > 0 && isValidFaceLevel(faceIndex, index.getLevelIndex())) 1946 { 1947 ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex())); 1948 ANGLE_TRY(mRenderer->copyImageCube(context, source, clippedArea, internalFormat, 1949 destOffset, mTexStorage, index.getTarget(), 1950 index.getLevelIndex())); 1951 } 1952 } 1953 1954 return angle::Result::Continue; 1955 } 1956 1957 angle::Result TextureD3D_Cube::copySubImage(const gl::Context *context, 1958 const gl::ImageIndex &index, 1959 const gl::Offset &destOffset, 1960 const gl::Rectangle &sourceArea, 1961 gl::Framebuffer *source) 1962 { 1963 gl::Extents fbSize = source->getReadColorAttachment()->getSize(); 1964 gl::Rectangle clippedArea; 1965 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea)) 1966 { 1967 return angle::Result::Continue; 1968 } 1969 const gl::Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x, 1970 destOffset.y + clippedArea.y - sourceArea.y, 0); 1971 1972 GLint faceIndex = index.cubeMapFaceIndex(); 1973 1974 // If the zero max LOD workaround is active, then we can't sample from individual layers of the 1975 // framebuffer in shaders, so we should use the non-rendering copy path. 1976 if (!canCreateRenderTargetForImage(index) || 1977 mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) 1978 { 1979 ANGLE_TRY(mImageArray[faceIndex][index.getLevelIndex()]->copyFromFramebuffer( 1980 context, clippedOffset, clippedArea, source)); 1981 mDirtyImages = true; 1982 onStateChange(angle::SubjectMessage::DirtyBitsFlagged); 1983 } 1984 else 1985 { 1986 ANGLE_TRY(ensureRenderTarget(context)); 1987 if (isValidFaceLevel(faceIndex, index.getLevelIndex())) 1988 { 1989 ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex())); 1990 ANGLE_TRY(mRenderer->copyImageCube( 1991 context, source, clippedArea, gl::GetUnsizedFormat(getBaseLevelInternalFormat()), 1992 clippedOffset, mTexStorage, index.getTarget(), index.getLevelIndex())); 1993 } 1994 } 1995 1996 return angle::Result::Continue; 1997 } 1998 1999 angle::Result TextureD3D_Cube::copyTexture(const gl::Context *context, 2000 const gl::ImageIndex &index, 2001 GLenum internalFormat, 2002 GLenum type, 2003 GLint sourceLevel, 2004 bool unpackFlipY, 2005 bool unpackPremultiplyAlpha, 2006 bool unpackUnmultiplyAlpha, 2007 const gl::Texture *source) 2008 { 2009 ASSERT(gl::IsCubeMapFaceTarget(index.getTarget())); 2010 2011 gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType()); 2012 2013 GLint faceIndex = index.cubeMapFaceIndex(); 2014 2015 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); 2016 gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)), 2017 static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1); 2018 ANGLE_TRY(redefineImage(context, faceIndex, index.getLevelIndex(), 2019 internalFormatInfo.sizedInternalFormat, size, false)); 2020 2021 gl::Box sourceBox(0, 0, 0, size.width, size.height, 1); 2022 gl::Offset destOffset(0, 0, 0); 2023 2024 if (!isSRGB(index.getLevelIndex(), faceIndex) && canCreateRenderTargetForImage(index)) 2025 { 2026 2027 ANGLE_TRY(ensureRenderTarget(context)); 2028 ASSERT(isValidFaceLevel(faceIndex, index.getLevelIndex())); 2029 ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex())); 2030 2031 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D, 2032 sourceBox, internalFormatInfo.format, 2033 internalFormatInfo.type, destOffset, mTexStorage, 2034 index.getTarget(), index.getLevelIndex(), unpackFlipY, 2035 unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); 2036 } 2037 else 2038 { 2039 gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel); 2040 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source); 2041 ImageD3D *sourceImage = nullptr; 2042 ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); 2043 2044 ImageD3D *destImage = nullptr; 2045 ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage)); 2046 2047 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset, 2048 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); 2049 2050 mDirtyImages = true; 2051 2052 gl::Box destRegion(destOffset, size); 2053 ANGLE_TRY(commitRegion(context, index, destRegion)); 2054 } 2055 2056 return angle::Result::Continue; 2057 } 2058 2059 angle::Result TextureD3D_Cube::copySubTexture(const gl::Context *context, 2060 const gl::ImageIndex &index, 2061 const gl::Offset &destOffset, 2062 GLint sourceLevel, 2063 const gl::Box &sourceBox, 2064 bool unpackFlipY, 2065 bool unpackPremultiplyAlpha, 2066 bool unpackUnmultiplyAlpha, 2067 const gl::Texture *source) 2068 { 2069 ASSERT(gl::IsCubeMapFaceTarget(index.getTarget())); 2070 2071 GLint faceIndex = index.cubeMapFaceIndex(); 2072 2073 if (!isSRGB(index.getLevelIndex(), faceIndex) && canCreateRenderTargetForImage(index)) 2074 { 2075 ANGLE_TRY(ensureRenderTarget(context)); 2076 ASSERT(isValidFaceLevel(faceIndex, index.getLevelIndex())); 2077 ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex())); 2078 2079 const gl::InternalFormat &internalFormatInfo = 2080 gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex(), faceIndex)); 2081 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D, 2082 sourceBox, internalFormatInfo.format, 2083 internalFormatInfo.type, destOffset, mTexStorage, 2084 index.getTarget(), index.getLevelIndex(), unpackFlipY, 2085 unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); 2086 } 2087 else 2088 { 2089 gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel); 2090 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source); 2091 ImageD3D *sourceImage = nullptr; 2092 ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); 2093 2094 ImageD3D *destImage = nullptr; 2095 ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage)); 2096 2097 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset, 2098 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); 2099 2100 mDirtyImages = true; 2101 2102 gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceBox.width, sourceBox.height, 1); 2103 ANGLE_TRY(commitRegion(context, index, destRegion)); 2104 } 2105 2106 return angle::Result::Continue; 2107 } 2108 2109 angle::Result TextureD3D_Cube::setStorage(const gl::Context *context, 2110 gl::TextureType type, 2111 size_t levels, 2112 GLenum internalFormat, 2113 const gl::Extents &size) 2114 { 2115 ASSERT(size.width == size.height); 2116 ASSERT(size.depth == 1); 2117 2118 for (size_t level = 0; level < levels; level++) 2119 { 2120 GLsizei mipSize = std::max(1, size.width >> level); 2121 for (size_t faceIndex = 0; faceIndex < gl::kCubeFaceCount; faceIndex++) 2122 { 2123 mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, internalFormat, 2124 gl::Extents(mipSize, mipSize, 1), true); 2125 } 2126 } 2127 2128 for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 2129 { 2130 for (size_t faceIndex = 0; faceIndex < gl::kCubeFaceCount; faceIndex++) 2131 { 2132 mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, GL_NONE, 2133 gl::Extents(0, 0, 0), true); 2134 } 2135 } 2136 2137 // TODO(geofflang): Verify storage creation had no errors 2138 BindFlags bindFlags; 2139 bindFlags.renderTarget = IsRenderTargetUsage(mState.getUsage()); 2140 2141 TexStoragePointer storage = { 2142 mRenderer->createTextureStorageCube(internalFormat, bindFlags, size.width, 2143 static_cast<int>(levels), false, mState.getLabel()), 2144 context}; 2145 2146 ANGLE_TRY(setCompleteTexStorage(context, storage.get())); 2147 storage.release(); 2148 2149 ANGLE_TRY(updateStorage(context)); 2150 2151 mImmutable = true; 2152 2153 return angle::Result::Continue; 2154 } 2155 2156 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. 2157 bool TextureD3D_Cube::isCubeComplete() const 2158 { 2159 int baseWidth = getBaseLevelWidth(); 2160 int baseHeight = getBaseLevelHeight(); 2161 GLenum baseFormat = getBaseLevelInternalFormat(); 2162 2163 if (baseWidth <= 0 || baseWidth != baseHeight) 2164 { 2165 return false; 2166 } 2167 2168 for (size_t faceIndex = 1; faceIndex < gl::kCubeFaceCount; faceIndex++) 2169 { 2170 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][getBaseLevel()]; 2171 2172 if (faceBaseImage.getWidth() != baseWidth || faceBaseImage.getHeight() != baseHeight || 2173 faceBaseImage.getInternalFormat() != baseFormat) 2174 { 2175 return false; 2176 } 2177 } 2178 2179 return true; 2180 } 2181 2182 angle::Result TextureD3D_Cube::bindTexImage(const gl::Context *context, egl::Surface *surface) 2183 { 2184 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 2185 return angle::Result::Continue; 2186 } 2187 2188 angle::Result TextureD3D_Cube::releaseTexImage(const gl::Context *context) 2189 { 2190 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 2191 return angle::Result::Continue; 2192 } 2193 2194 angle::Result TextureD3D_Cube::initMipmapImages(const gl::Context *context) 2195 { 2196 const GLuint baseLevel = mState.getEffectiveBaseLevel(); 2197 const GLuint maxLevel = mState.getMipmapMaxLevel(); 2198 // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap 2199 // levels. 2200 for (int faceIndex = 0; faceIndex < static_cast<int>(gl::kCubeFaceCount); faceIndex++) 2201 { 2202 for (GLuint level = baseLevel + 1; level <= maxLevel; level++) 2203 { 2204 int faceLevelSize = 2205 (std::max(mImageArray[faceIndex][baseLevel]->getWidth() >> (level - baseLevel), 1)); 2206 ANGLE_TRY(redefineImage(context, faceIndex, level, 2207 mImageArray[faceIndex][baseLevel]->getInternalFormat(), 2208 gl::Extents(faceLevelSize, faceLevelSize, 1), false)); 2209 } 2210 } 2211 2212 // We should be mip-complete now so generate the storage. 2213 ANGLE_TRY(initializeStorage(context, BindFlags::RenderTarget())); 2214 2215 return angle::Result::Continue; 2216 } 2217 2218 angle::Result TextureD3D_Cube::getRenderTarget(const gl::Context *context, 2219 const gl::ImageIndex &index, 2220 GLsizei samples, 2221 RenderTargetD3D **outRT) 2222 { 2223 ASSERT(gl::IsCubeMapFaceTarget(index.getTarget())); 2224 2225 // ensure the underlying texture is created 2226 ANGLE_TRY(ensureRenderTarget(context)); 2227 ANGLE_TRY(updateStorageFaceLevel(context, index.cubeMapFaceIndex(), index.getLevelIndex())); 2228 2229 return mTexStorage->getRenderTarget(context, index, samples, outRT); 2230 } 2231 2232 angle::Result TextureD3D_Cube::initializeStorage(const gl::Context *context, BindFlags bindFlags) 2233 { 2234 // Only initialize the first time this texture is used as a render target or shader resource 2235 if (mTexStorage) 2236 { 2237 return angle::Result::Continue; 2238 } 2239 2240 // do not attempt to create storage for nonexistant data 2241 if (!isFaceLevelComplete(0, getBaseLevel())) 2242 { 2243 return angle::Result::Continue; 2244 } 2245 2246 bindFlags.renderTarget |= IsRenderTargetUsage(mState.getUsage()); 2247 2248 TexStoragePointer storage; 2249 ANGLE_TRY(createCompleteStorage(context, bindFlags, &storage)); 2250 2251 ANGLE_TRY(setCompleteTexStorage(context, storage.get())); 2252 storage.release(); 2253 2254 ASSERT(mTexStorage); 2255 2256 // flush image data to the storage 2257 ANGLE_TRY(updateStorage(context)); 2258 2259 return angle::Result::Continue; 2260 } 2261 2262 angle::Result TextureD3D_Cube::createCompleteStorage(const gl::Context *context, 2263 BindFlags bindFlags, 2264 TexStoragePointer *outStorage) const 2265 { 2266 GLsizei size = getLevelZeroWidth(); 2267 2268 ASSERT(size > 0); 2269 2270 // use existing storage level count, when previously specified by TexStorage*D 2271 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1)); 2272 2273 bool hintLevelZeroOnly = false; 2274 if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled) 2275 { 2276 // If any of the CPU images (levels >= 1) are dirty, then the textureStorageEXT should use 2277 // the mipped texture to begin with. Otherwise, it should use the level-zero-only texture. 2278 hintLevelZeroOnly = true; 2279 for (int faceIndex = 0; 2280 faceIndex < static_cast<int>(gl::kCubeFaceCount) && hintLevelZeroOnly; faceIndex++) 2281 { 2282 for (int level = 1; level < levels && hintLevelZeroOnly; level++) 2283 { 2284 hintLevelZeroOnly = !(mImageArray[faceIndex][level]->isDirty() && 2285 isFaceLevelComplete(faceIndex, level)); 2286 } 2287 } 2288 } 2289 2290 // TODO (geofflang): detect if storage creation succeeded 2291 *outStorage = { 2292 mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), bindFlags, size, levels, 2293 hintLevelZeroOnly, mState.getLabel()), 2294 context}; 2295 2296 return angle::Result::Continue; 2297 } 2298 2299 angle::Result TextureD3D_Cube::setCompleteTexStorage(const gl::Context *context, 2300 TextureStorage *newCompleteTexStorage) 2301 { 2302 if (newCompleteTexStorage && newCompleteTexStorage->isManaged()) 2303 { 2304 for (int faceIndex = 0; faceIndex < static_cast<int>(gl::kCubeFaceCount); faceIndex++) 2305 { 2306 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++) 2307 { 2308 ANGLE_TRY(mImageArray[faceIndex][level]->setManagedSurfaceCube( 2309 context, newCompleteTexStorage, faceIndex, level)); 2310 } 2311 } 2312 } 2313 2314 gl::TexLevelMask copyImageMask; 2315 copyImageMask.set(); 2316 2317 ANGLE_TRY(releaseTexStorage(context, copyImageMask)); 2318 mTexStorage = newCompleteTexStorage; 2319 mTexStorageObserverBinding.bind(mTexStorage); 2320 2321 mDirtyImages = true; 2322 return angle::Result::Continue; 2323 } 2324 2325 angle::Result TextureD3D_Cube::updateStorage(const gl::Context *context) 2326 { 2327 if (!mDirtyImages) 2328 { 2329 return angle::Result::Continue; 2330 } 2331 2332 ASSERT(mTexStorage != nullptr); 2333 GLint storageLevels = mTexStorage->getLevelCount(); 2334 for (int face = 0; face < static_cast<int>(gl::kCubeFaceCount); face++) 2335 { 2336 for (int level = 0; level < storageLevels; level++) 2337 { 2338 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level)) 2339 { 2340 ANGLE_TRY(updateStorageFaceLevel(context, face, level)); 2341 } 2342 } 2343 } 2344 2345 mDirtyImages = false; 2346 return angle::Result::Continue; 2347 } 2348 2349 bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const 2350 { 2351 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); 2352 } 2353 2354 bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const 2355 { 2356 if (getBaseLevel() >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 2357 { 2358 return false; 2359 } 2360 ASSERT(level >= 0 && static_cast<size_t>(faceIndex) < gl::kCubeFaceCount && 2361 level < static_cast<int>(mImageArray[faceIndex].size()) && 2362 mImageArray[faceIndex][level] != nullptr); 2363 2364 if (isImmutable()) 2365 { 2366 return true; 2367 } 2368 2369 int levelZeroSize = getLevelZeroWidth(); 2370 2371 if (levelZeroSize <= 0) 2372 { 2373 return false; 2374 } 2375 2376 // Check that non-zero levels are consistent with the base level. 2377 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level].get(); 2378 2379 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat()) 2380 { 2381 return false; 2382 } 2383 2384 if (faceLevelImage->getWidth() != std::max(1, levelZeroSize >> level)) 2385 { 2386 return false; 2387 } 2388 2389 return true; 2390 } 2391 2392 bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const 2393 { 2394 return isFaceLevelComplete(index.cubeMapFaceIndex(), index.getLevelIndex()); 2395 } 2396 2397 angle::Result TextureD3D_Cube::updateStorageFaceLevel(const gl::Context *context, 2398 int faceIndex, 2399 int level) 2400 { 2401 ASSERT(level >= 0 && static_cast<size_t>(faceIndex) < gl::kCubeFaceCount && 2402 level < static_cast<int>(mImageArray[faceIndex].size()) && 2403 mImageArray[faceIndex][level] != nullptr); 2404 ImageD3D *image = mImageArray[faceIndex][level].get(); 2405 2406 if (image->isDirty()) 2407 { 2408 gl::TextureTarget faceTarget = gl::CubeFaceIndexToTextureTarget(faceIndex); 2409 gl::ImageIndex index = gl::ImageIndex::MakeCubeMapFace(faceTarget, level); 2410 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1); 2411 ANGLE_TRY(commitRegion(context, index, region)); 2412 } 2413 2414 return angle::Result::Continue; 2415 } 2416 2417 angle::Result TextureD3D_Cube::redefineImage(const gl::Context *context, 2418 int faceIndex, 2419 GLint level, 2420 GLenum internalformat, 2421 const gl::Extents &size, 2422 bool forceRelease) 2423 { 2424 // If there currently is a corresponding storage texture image, it has these parameters 2425 const int storageWidth = std::max(1, getLevelZeroWidth() >> level); 2426 const int storageHeight = std::max(1, getLevelZeroHeight() >> level); 2427 const GLenum storageFormat = getBaseLevelInternalFormat(); 2428 2429 if (mTexStorage) 2430 { 2431 const int storageLevels = mTexStorage->getLevelCount(); 2432 2433 if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth || 2434 size.height != storageHeight || 2435 internalformat != storageFormat) // Discard mismatched storage 2436 { 2437 markAllImagesDirty(); 2438 2439 gl::TexLevelMask copyImageMask; 2440 copyImageMask.set(); 2441 copyImageMask.set(level, false); 2442 2443 ANGLE_TRY(releaseTexStorage(context, copyImageMask)); 2444 } 2445 } 2446 2447 mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, internalformat, size, 2448 forceRelease); 2449 mDirtyImages = mDirtyImages || mImageArray[faceIndex][level]->isDirty(); 2450 2451 return angle::Result::Continue; 2452 } 2453 2454 gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const 2455 { 2456 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount()); 2457 } 2458 2459 gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const 2460 { 2461 // The "layer" of the image index corresponds to the cube face 2462 return gl::ImageIndex::MakeCubeMapFace(gl::CubeFaceIndexToTextureTarget(layer), mip); 2463 } 2464 2465 bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const 2466 { 2467 return (mTexStorage && index.getType() == gl::TextureType::CubeMap && 2468 gl::IsCubeMapFaceTarget(index.getTarget()) && index.getLevelIndex() >= 0 && 2469 index.getLevelIndex() < mTexStorage->getLevelCount()); 2470 } 2471 2472 void TextureD3D_Cube::markAllImagesDirty() 2473 { 2474 for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) 2475 { 2476 for (size_t dirtyFace = 0; dirtyFace < gl::kCubeFaceCount; dirtyFace++) 2477 { 2478 mImageArray[dirtyFace][dirtyLevel]->markDirty(); 2479 } 2480 } 2481 mDirtyImages = true; 2482 } 2483 2484 TextureD3D_3D::TextureD3D_3D(const gl::TextureState &state, RendererD3D *renderer) 2485 : TextureD3D(state, renderer) 2486 { 2487 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) 2488 { 2489 mImageArray[i].reset(renderer->createImage()); 2490 } 2491 } 2492 2493 void TextureD3D_3D::onDestroy(const gl::Context *context) 2494 { 2495 // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage 2496 // for some of their data. If TextureStorage is deleted before the Images, then their data will 2497 // be wastefully copied back from the GPU before we delete the Images. 2498 for (auto &image : mImageArray) 2499 { 2500 image.reset(); 2501 } 2502 return TextureD3D::onDestroy(context); 2503 } 2504 2505 TextureD3D_3D::~TextureD3D_3D() {} 2506 2507 ImageD3D *TextureD3D_3D::getImage(int level, int layer) const 2508 { 2509 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 2510 ASSERT(layer == 0); 2511 return mImageArray[level].get(); 2512 } 2513 2514 ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const 2515 { 2516 ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 2517 ASSERT(!index.hasLayer()); 2518 ASSERT(index.getType() == gl::TextureType::_3D); 2519 return mImageArray[index.getLevelIndex()].get(); 2520 } 2521 2522 GLsizei TextureD3D_3D::getLayerCount(int level) const 2523 { 2524 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 2525 return 1; 2526 } 2527 2528 GLsizei TextureD3D_3D::getWidth(GLint level) const 2529 { 2530 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 2531 return mImageArray[level]->getWidth(); 2532 else 2533 return 0; 2534 } 2535 2536 GLsizei TextureD3D_3D::getHeight(GLint level) const 2537 { 2538 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 2539 return mImageArray[level]->getHeight(); 2540 else 2541 return 0; 2542 } 2543 2544 GLsizei TextureD3D_3D::getDepth(GLint level) const 2545 { 2546 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 2547 return mImageArray[level]->getDepth(); 2548 else 2549 return 0; 2550 } 2551 2552 GLenum TextureD3D_3D::getInternalFormat(GLint level) const 2553 { 2554 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 2555 return mImageArray[level]->getInternalFormat(); 2556 else 2557 return GL_NONE; 2558 } 2559 2560 bool TextureD3D_3D::isDepth(GLint level) const 2561 { 2562 return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0; 2563 } 2564 2565 bool TextureD3D_3D::isSRGB(GLint level) const 2566 { 2567 return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB; 2568 } 2569 2570 angle::Result TextureD3D_3D::setEGLImageTarget(const gl::Context *context, 2571 gl::TextureType type, 2572 egl::Image *image) 2573 { 2574 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 2575 return angle::Result::Continue; 2576 } 2577 2578 angle::Result TextureD3D_3D::setImage(const gl::Context *context, 2579 const gl::ImageIndex &index, 2580 GLenum internalFormat, 2581 const gl::Extents &size, 2582 GLenum format, 2583 GLenum type, 2584 const gl::PixelUnpackState &unpack, 2585 gl::Buffer *unpackBuffer, 2586 const uint8_t *pixels) 2587 { 2588 ASSERT(index.getTarget() == gl::TextureTarget::_3D); 2589 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); 2590 2591 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat, 2592 size, false)); 2593 2594 bool fastUnpacked = false; 2595 2596 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer 2597 if (isFastUnpackable(unpackBuffer, unpack, internalFormatInfo.sizedInternalFormat) && 2598 !size.empty() && isLevelComplete(index.getLevelIndex())) 2599 { 2600 // Will try to create RT storage if it does not exist 2601 RenderTargetD3D *destRenderTarget = nullptr; 2602 ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget)); 2603 2604 gl::Box destArea(0, 0, 0, getWidth(index.getLevelIndex()), getHeight(index.getLevelIndex()), 2605 getDepth(index.getLevelIndex())); 2606 2607 ANGLE_TRY(fastUnpackPixels(context, unpack, unpackBuffer, pixels, destArea, 2608 internalFormatInfo.sizedInternalFormat, type, destRenderTarget)); 2609 2610 // Ensure we don't overwrite our newly initialized data 2611 mImageArray[index.getLevelIndex()]->markClean(); 2612 2613 fastUnpacked = true; 2614 } 2615 2616 if (!fastUnpacked) 2617 { 2618 ANGLE_TRY(setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0)); 2619 } 2620 2621 return angle::Result::Continue; 2622 } 2623 2624 angle::Result TextureD3D_3D::setSubImage(const gl::Context *context, 2625 const gl::ImageIndex &index, 2626 const gl::Box &area, 2627 GLenum format, 2628 GLenum type, 2629 const gl::PixelUnpackState &unpack, 2630 gl::Buffer *unpackBuffer, 2631 const uint8_t *pixels) 2632 { 2633 ASSERT(index.getTarget() == gl::TextureTarget::_3D); 2634 2635 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer 2636 GLenum mipFormat = getInternalFormat(index.getLevelIndex()); 2637 if (isFastUnpackable(unpackBuffer, unpack, mipFormat) && isLevelComplete(index.getLevelIndex())) 2638 { 2639 RenderTargetD3D *destRenderTarget = nullptr; 2640 ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget)); 2641 ASSERT(!mImageArray[index.getLevelIndex()]->isDirty()); 2642 2643 return fastUnpackPixels(context, unpack, unpackBuffer, pixels, area, mipFormat, type, 2644 destRenderTarget); 2645 } 2646 else 2647 { 2648 return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer, 2649 pixels, 0); 2650 } 2651 } 2652 2653 angle::Result TextureD3D_3D::setCompressedImage(const gl::Context *context, 2654 const gl::ImageIndex &index, 2655 GLenum internalFormat, 2656 const gl::Extents &size, 2657 const gl::PixelUnpackState &unpack, 2658 size_t imageSize, 2659 const uint8_t *pixels) 2660 { 2661 ASSERT(index.getTarget() == gl::TextureTarget::_3D); 2662 2663 // compressed formats don't have separate sized internal formats-- we can just use the 2664 // compressed format directly 2665 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false)); 2666 2667 return setCompressedImageImpl(context, index, unpack, pixels, 0); 2668 } 2669 2670 angle::Result TextureD3D_3D::setCompressedSubImage(const gl::Context *context, 2671 const gl::ImageIndex &index, 2672 const gl::Box &area, 2673 GLenum format, 2674 const gl::PixelUnpackState &unpack, 2675 size_t imageSize, 2676 const uint8_t *pixels) 2677 { 2678 ASSERT(index.getTarget() == gl::TextureTarget::_3D); 2679 2680 ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0)); 2681 return commitRegion(context, index, area); 2682 } 2683 2684 angle::Result TextureD3D_3D::copyImage(const gl::Context *context, 2685 const gl::ImageIndex &index, 2686 const gl::Rectangle &sourceArea, 2687 GLenum internalFormat, 2688 gl::Framebuffer *source) 2689 { 2690 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 2691 return angle::Result::Continue; 2692 } 2693 2694 angle::Result TextureD3D_3D::copySubImage(const gl::Context *context, 2695 const gl::ImageIndex &index, 2696 const gl::Offset &destOffset, 2697 const gl::Rectangle &sourceArea, 2698 gl::Framebuffer *source) 2699 { 2700 ASSERT(index.getTarget() == gl::TextureTarget::_3D); 2701 2702 gl::Extents fbSize = source->getReadColorAttachment()->getSize(); 2703 gl::Rectangle clippedSourceArea; 2704 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), 2705 &clippedSourceArea)) 2706 { 2707 return angle::Result::Continue; 2708 } 2709 const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x, 2710 destOffset.y + clippedSourceArea.y - sourceArea.y, 2711 destOffset.z); 2712 2713 // Currently, copying directly to the storage is not possible because it's not possible to 2714 // create an SRV from a single layer of a 3D texture. Instead, make sure the image is up to 2715 // date before the copy and then copy back to the storage afterwards if needed. 2716 // TODO: Investigate 3D blits in D3D11. 2717 2718 bool syncTexStorage = mTexStorage && isLevelComplete(index.getLevelIndex()); 2719 if (syncTexStorage) 2720 { 2721 ANGLE_TRY( 2722 mImageArray[index.getLevelIndex()]->copyFromTexStorage(context, index, mTexStorage)); 2723 } 2724 ANGLE_TRY(mImageArray[index.getLevelIndex()]->copyFromFramebuffer(context, clippedDestOffset, 2725 clippedSourceArea, source)); 2726 mDirtyImages = true; 2727 onStateChange(angle::SubjectMessage::DirtyBitsFlagged); 2728 2729 if (syncTexStorage) 2730 { 2731 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex())); 2732 } 2733 2734 return angle::Result::Continue; 2735 } 2736 2737 angle::Result TextureD3D_3D::copyTexture(const gl::Context *context, 2738 const gl::ImageIndex &index, 2739 GLenum internalFormat, 2740 GLenum type, 2741 GLint sourceLevel, 2742 bool unpackFlipY, 2743 bool unpackPremultiplyAlpha, 2744 bool unpackUnmultiplyAlpha, 2745 const gl::Texture *source) 2746 { 2747 ASSERT(index.getTarget() == gl::TextureTarget::_3D); 2748 2749 gl::TextureType sourceType = source->getType(); 2750 2751 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); 2752 gl::Extents size( 2753 static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)), 2754 static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)), 2755 static_cast<int>(source->getDepth(NonCubeTextureTypeToTarget(sourceType), sourceLevel))); 2756 2757 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat, 2758 size, false)); 2759 2760 gl::Box sourceBox(0, 0, 0, size.width, size.height, size.depth); 2761 gl::Offset destOffset(0, 0, 0); 2762 gl::ImageIndex destIndex = gl::ImageIndex::Make3D(static_cast<GLint>(index.getLevelIndex())); 2763 2764 if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(destIndex)) 2765 { 2766 ANGLE_TRY(ensureRenderTarget(context)); 2767 ASSERT(isValidLevel(index.getLevelIndex())); 2768 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex())); 2769 2770 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_3D, 2771 sourceBox, internalFormatInfo.format, 2772 internalFormatInfo.type, destOffset, mTexStorage, 2773 index.getTarget(), index.getLevelIndex(), unpackFlipY, 2774 unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); 2775 } 2776 else 2777 { 2778 gl::ImageIndex sourceIndex = gl::ImageIndex::Make3D(sourceLevel); 2779 ImageD3D *sourceImage = nullptr; 2780 ImageD3D *destImage = nullptr; 2781 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source); 2782 2783 ANGLE_TRY(getImageAndSyncFromStorage(context, destIndex, &destImage)); 2784 ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceIndex, &sourceImage)); 2785 2786 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset, 2787 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); 2788 2789 mDirtyImages = true; 2790 2791 gl::Box destRegion(0, 0, 0, sourceBox.width, sourceBox.height, sourceBox.depth); 2792 ANGLE_TRY(commitRegion(context, destIndex, destRegion)); 2793 } 2794 2795 return angle::Result::Continue; 2796 } 2797 angle::Result TextureD3D_3D::copySubTexture(const gl::Context *context, 2798 const gl::ImageIndex &index, 2799 const gl::Offset &destOffset, 2800 GLint sourceLevel, 2801 const gl::Box &sourceBox, 2802 bool unpackFlipY, 2803 bool unpackPremultiplyAlpha, 2804 bool unpackUnmultiplyAlpha, 2805 const gl::Texture *source) 2806 { 2807 ASSERT(index.getTarget() == gl::TextureTarget::_3D); 2808 2809 gl::ImageIndex destIndex = gl::ImageIndex::Make3D(static_cast<GLint>(index.getLevelIndex())); 2810 2811 if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(destIndex)) 2812 { 2813 ANGLE_TRY(ensureRenderTarget(context)); 2814 ASSERT(isValidLevel(index.getLevelIndex())); 2815 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex())); 2816 2817 const gl::InternalFormat &internalFormatInfo = 2818 gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex())); 2819 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_3D, 2820 sourceBox, internalFormatInfo.format, 2821 internalFormatInfo.type, destOffset, mTexStorage, 2822 index.getTarget(), index.getLevelIndex(), unpackFlipY, 2823 unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); 2824 } 2825 else 2826 { 2827 gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make3D(sourceLevel); 2828 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source); 2829 ImageD3D *sourceImage = nullptr; 2830 ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage)); 2831 2832 ImageD3D *destImage = nullptr; 2833 ANGLE_TRY(getImageAndSyncFromStorage(context, destIndex, &destImage)); 2834 2835 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset, 2836 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); 2837 2838 mDirtyImages = true; 2839 2840 gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width, 2841 sourceBox.height, sourceBox.depth); 2842 ANGLE_TRY(commitRegion(context, destIndex, destRegion)); 2843 } 2844 2845 return angle::Result::Continue; 2846 } 2847 2848 angle::Result TextureD3D_3D::setStorage(const gl::Context *context, 2849 gl::TextureType type, 2850 size_t levels, 2851 GLenum internalFormat, 2852 const gl::Extents &size) 2853 { 2854 ASSERT(type == gl::TextureType::_3D); 2855 2856 for (size_t level = 0; level < levels; level++) 2857 { 2858 gl::Extents levelSize(std::max(1, size.width >> level), std::max(1, size.height >> level), 2859 std::max(1, size.depth >> level)); 2860 mImageArray[level]->redefine(gl::TextureType::_3D, internalFormat, levelSize, true); 2861 } 2862 2863 for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 2864 { 2865 mImageArray[level]->redefine(gl::TextureType::_3D, GL_NONE, gl::Extents(0, 0, 0), true); 2866 } 2867 2868 // TODO(geofflang): Verify storage creation had no errors 2869 BindFlags bindFlags; 2870 bindFlags.renderTarget = IsRenderTargetUsage(mState.getUsage()); 2871 TexStoragePointer storage = { 2872 mRenderer->createTextureStorage3D(internalFormat, bindFlags, size.width, size.height, 2873 size.depth, static_cast<int>(levels), mState.getLabel()), 2874 context}; 2875 2876 ANGLE_TRY(setCompleteTexStorage(context, storage.get())); 2877 storage.release(); 2878 2879 ANGLE_TRY(updateStorage(context)); 2880 2881 mImmutable = true; 2882 2883 return angle::Result::Continue; 2884 } 2885 2886 angle::Result TextureD3D_3D::bindTexImage(const gl::Context *context, egl::Surface *surface) 2887 { 2888 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 2889 return angle::Result::Continue; 2890 } 2891 2892 angle::Result TextureD3D_3D::releaseTexImage(const gl::Context *context) 2893 { 2894 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 2895 return angle::Result::Continue; 2896 } 2897 2898 angle::Result TextureD3D_3D::initMipmapImages(const gl::Context *context) 2899 { 2900 const GLuint baseLevel = mState.getEffectiveBaseLevel(); 2901 const GLuint maxLevel = mState.getMipmapMaxLevel(); 2902 // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap 2903 // levels. 2904 for (GLuint level = baseLevel + 1; level <= maxLevel; level++) 2905 { 2906 gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1), 2907 std::max(getLevelZeroHeight() >> level, 1), 2908 std::max(getLevelZeroDepth() >> level, 1)); 2909 ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false)); 2910 } 2911 2912 // We should be mip-complete now so generate the storage. 2913 ANGLE_TRY(initializeStorage(context, BindFlags::RenderTarget())); 2914 2915 return angle::Result::Continue; 2916 } 2917 2918 angle::Result TextureD3D_3D::getRenderTarget(const gl::Context *context, 2919 const gl::ImageIndex &index, 2920 GLsizei samples, 2921 RenderTargetD3D **outRT) 2922 { 2923 // ensure the underlying texture is created 2924 ANGLE_TRY(ensureRenderTarget(context)); 2925 2926 if (index.hasLayer()) 2927 { 2928 ANGLE_TRY(updateStorage(context)); 2929 } 2930 else 2931 { 2932 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex())); 2933 } 2934 2935 return mTexStorage->getRenderTarget(context, index, samples, outRT); 2936 } 2937 2938 angle::Result TextureD3D_3D::initializeStorage(const gl::Context *context, BindFlags bindFlags) 2939 { 2940 // Only initialize the first time this texture is used as a render target or shader resource 2941 if (mTexStorage) 2942 { 2943 return angle::Result::Continue; 2944 } 2945 2946 // do not attempt to create storage for nonexistant data 2947 if (!isLevelComplete(getBaseLevel())) 2948 { 2949 return angle::Result::Continue; 2950 } 2951 2952 TexStoragePointer storage; 2953 ANGLE_TRY(createCompleteStorage(context, bindFlags, &storage)); 2954 2955 ANGLE_TRY(setCompleteTexStorage(context, storage.get())); 2956 storage.release(); 2957 2958 ASSERT(mTexStorage); 2959 2960 // flush image data to the storage 2961 ANGLE_TRY(updateStorage(context)); 2962 2963 return angle::Result::Continue; 2964 } 2965 2966 angle::Result TextureD3D_3D::createCompleteStorage(const gl::Context *context, 2967 BindFlags bindFlags, 2968 TexStoragePointer *outStorage) const 2969 { 2970 GLsizei width = getLevelZeroWidth(); 2971 GLsizei height = getLevelZeroHeight(); 2972 GLsizei depth = getLevelZeroDepth(); 2973 GLenum internalFormat = getBaseLevelInternalFormat(); 2974 2975 ASSERT(width > 0 && height > 0 && depth > 0); 2976 2977 // use existing storage level count, when previously specified by TexStorage*D 2978 GLint levels = 2979 (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth)); 2980 2981 // TODO: Verify creation of the storage succeeded 2982 *outStorage = {mRenderer->createTextureStorage3D(internalFormat, bindFlags, width, height, 2983 depth, levels, mState.getLabel()), 2984 context}; 2985 2986 return angle::Result::Continue; 2987 } 2988 2989 angle::Result TextureD3D_3D::setCompleteTexStorage(const gl::Context *context, 2990 TextureStorage *newCompleteTexStorage) 2991 { 2992 gl::TexLevelMask copyImageMask; 2993 copyImageMask.set(); 2994 2995 ANGLE_TRY(releaseTexStorage(context, copyImageMask)); 2996 mTexStorage = newCompleteTexStorage; 2997 mTexStorageObserverBinding.bind(mTexStorage); 2998 mDirtyImages = true; 2999 3000 // We do not support managed 3D storage, as that is D3D9/ES2-only 3001 ASSERT(!mTexStorage->isManaged()); 3002 3003 return angle::Result::Continue; 3004 } 3005 3006 angle::Result TextureD3D_3D::updateStorage(const gl::Context *context) 3007 { 3008 if (!mDirtyImages) 3009 { 3010 return angle::Result::Continue; 3011 } 3012 3013 ASSERT(mTexStorage != nullptr); 3014 GLint storageLevels = mTexStorage->getLevelCount(); 3015 for (int level = 0; level < storageLevels; level++) 3016 { 3017 if (mImageArray[level]->isDirty() && isLevelComplete(level)) 3018 { 3019 ANGLE_TRY(updateStorageLevel(context, level)); 3020 } 3021 } 3022 3023 mDirtyImages = false; 3024 return angle::Result::Continue; 3025 } 3026 3027 bool TextureD3D_3D::isValidLevel(int level) const 3028 { 3029 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); 3030 } 3031 3032 bool TextureD3D_3D::isLevelComplete(int level) const 3033 { 3034 ASSERT(level >= 0 && level < static_cast<int>(mImageArray.size()) && 3035 mImageArray[level] != nullptr); 3036 3037 if (isImmutable()) 3038 { 3039 return true; 3040 } 3041 3042 GLsizei width = getLevelZeroWidth(); 3043 GLsizei height = getLevelZeroHeight(); 3044 GLsizei depth = getLevelZeroDepth(); 3045 3046 if (width <= 0 || height <= 0 || depth <= 0) 3047 { 3048 return false; 3049 } 3050 3051 if (level == static_cast<int>(getBaseLevel())) 3052 { 3053 return true; 3054 } 3055 3056 ImageD3D *levelImage = mImageArray[level].get(); 3057 3058 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat()) 3059 { 3060 return false; 3061 } 3062 3063 if (levelImage->getWidth() != std::max(1, width >> level)) 3064 { 3065 return false; 3066 } 3067 3068 if (levelImage->getHeight() != std::max(1, height >> level)) 3069 { 3070 return false; 3071 } 3072 3073 if (levelImage->getDepth() != std::max(1, depth >> level)) 3074 { 3075 return false; 3076 } 3077 3078 return true; 3079 } 3080 3081 bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const 3082 { 3083 return isLevelComplete(index.getLevelIndex()); 3084 } 3085 3086 angle::Result TextureD3D_3D::updateStorageLevel(const gl::Context *context, int level) 3087 { 3088 ASSERT(level >= 0 && level < static_cast<int>(mImageArray.size()) && 3089 mImageArray[level] != nullptr); 3090 ASSERT(isLevelComplete(level)); 3091 3092 if (mImageArray[level]->isDirty()) 3093 { 3094 gl::ImageIndex index = gl::ImageIndex::Make3D(level); 3095 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); 3096 ANGLE_TRY(commitRegion(context, index, region)); 3097 } 3098 3099 return angle::Result::Continue; 3100 } 3101 3102 angle::Result TextureD3D_3D::redefineImage(const gl::Context *context, 3103 GLint level, 3104 GLenum internalformat, 3105 const gl::Extents &size, 3106 bool forceRelease) 3107 { 3108 // If there currently is a corresponding storage texture image, it has these parameters 3109 const int storageWidth = std::max(1, getLevelZeroWidth() >> level); 3110 const int storageHeight = std::max(1, getLevelZeroHeight() >> level); 3111 const int storageDepth = std::max(1, getLevelZeroDepth() >> level); 3112 const GLenum storageFormat = getBaseLevelInternalFormat(); 3113 3114 if (mTexStorage) 3115 { 3116 const int storageLevels = mTexStorage->getLevelCount(); 3117 3118 if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth || 3119 size.height != storageHeight || size.depth != storageDepth || 3120 internalformat != storageFormat) // Discard mismatched storage 3121 { 3122 markAllImagesDirty(); 3123 3124 gl::TexLevelMask copyImageMask; 3125 copyImageMask.set(); 3126 copyImageMask.set(level, false); 3127 3128 ANGLE_TRY(releaseTexStorage(context, copyImageMask)); 3129 } 3130 } 3131 3132 mImageArray[level]->redefine(gl::TextureType::_3D, internalformat, size, forceRelease); 3133 mDirtyImages = mDirtyImages || mImageArray[level]->isDirty(); 3134 3135 return angle::Result::Continue; 3136 } 3137 3138 gl::ImageIndexIterator TextureD3D_3D::imageIterator() const 3139 { 3140 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(), 3141 gl::ImageIndex::kEntireLevel, 3142 gl::ImageIndex::kEntireLevel); 3143 } 3144 3145 gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const 3146 { 3147 // The "layer" here does not apply to 3D images. We use one Image per mip. 3148 return gl::ImageIndex::Make3D(mip); 3149 } 3150 3151 bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const 3152 { 3153 return (mTexStorage && index.getType() == gl::TextureType::_3D && index.getLevelIndex() >= 0 && 3154 index.getLevelIndex() < mTexStorage->getLevelCount()); 3155 } 3156 3157 void TextureD3D_3D::markAllImagesDirty() 3158 { 3159 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) 3160 { 3161 mImageArray[i]->markDirty(); 3162 } 3163 mDirtyImages = true; 3164 } 3165 3166 GLint TextureD3D_3D::getLevelZeroDepth() const 3167 { 3168 ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelDepth())) > getBaseLevel()); 3169 return getBaseLevelDepth() << getBaseLevel(); 3170 } 3171 3172 TextureD3D_2DArray::TextureD3D_2DArray(const gl::TextureState &state, RendererD3D *renderer) 3173 : TextureD3D(state, renderer) 3174 { 3175 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) 3176 { 3177 mLayerCounts[level] = 0; 3178 mImageArray[level] = nullptr; 3179 } 3180 } 3181 3182 void TextureD3D_2DArray::onDestroy(const gl::Context *context) 3183 { 3184 // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage 3185 // for some of their data. If TextureStorage is deleted before the Images, then their data will 3186 // be wastefully copied back from the GPU before we delete the Images. 3187 deleteImages(); 3188 return TextureD3D::onDestroy(context); 3189 } 3190 3191 TextureD3D_2DArray::~TextureD3D_2DArray() {} 3192 3193 ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const 3194 { 3195 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 3196 ASSERT((layer == 0 && mLayerCounts[level] == 0) || layer < mLayerCounts[level]); 3197 return (mImageArray[level] ? mImageArray[level][layer] : nullptr); 3198 } 3199 3200 ImageD3D *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const 3201 { 3202 ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 3203 ASSERT(index.hasLayer()); 3204 ASSERT((index.getLayerIndex() == 0 && mLayerCounts[index.getLevelIndex()] == 0) || 3205 index.getLayerIndex() < mLayerCounts[index.getLevelIndex()]); 3206 ASSERT(index.getType() == gl::TextureType::_2DArray); 3207 return (mImageArray[index.getLevelIndex()] 3208 ? mImageArray[index.getLevelIndex()][index.getLayerIndex()] 3209 : nullptr); 3210 } 3211 3212 GLsizei TextureD3D_2DArray::getLayerCount(int level) const 3213 { 3214 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 3215 return mLayerCounts[level]; 3216 } 3217 3218 GLsizei TextureD3D_2DArray::getWidth(GLint level) const 3219 { 3220 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) 3221 ? mImageArray[level][0]->getWidth() 3222 : 0; 3223 } 3224 3225 GLsizei TextureD3D_2DArray::getHeight(GLint level) const 3226 { 3227 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) 3228 ? mImageArray[level][0]->getHeight() 3229 : 0; 3230 } 3231 3232 GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const 3233 { 3234 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) 3235 ? mImageArray[level][0]->getInternalFormat() 3236 : GL_NONE; 3237 } 3238 3239 bool TextureD3D_2DArray::isDepth(GLint level) const 3240 { 3241 return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0; 3242 } 3243 3244 bool TextureD3D_2DArray::isSRGB(GLint level) const 3245 { 3246 return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB; 3247 } 3248 3249 angle::Result TextureD3D_2DArray::setEGLImageTarget(const gl::Context *context, 3250 gl::TextureType type, 3251 egl::Image *image) 3252 { 3253 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 3254 return angle::Result::Continue; 3255 } 3256 3257 angle::Result TextureD3D_2DArray::setImage(const gl::Context *context, 3258 const gl::ImageIndex &index, 3259 GLenum internalFormat, 3260 const gl::Extents &size, 3261 GLenum format, 3262 GLenum type, 3263 const gl::PixelUnpackState &unpack, 3264 gl::Buffer *unpackBuffer, 3265 const uint8_t *pixels) 3266 { 3267 ASSERT(index.getTarget() == gl::TextureTarget::_2DArray); 3268 3269 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type); 3270 3271 ANGLE_TRY( 3272 redefineImage(context, index.getLevelIndex(), formatInfo.sizedInternalFormat, size, false)); 3273 3274 ContextD3D *contextD3D = GetImplAs<ContextD3D>(context); 3275 3276 GLuint inputDepthPitch = 0; 3277 ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeDepthPitch( 3278 type, size.width, size.height, unpack.alignment, 3279 unpack.rowLength, unpack.imageHeight, &inputDepthPitch)); 3280 3281 for (int i = 0; i < size.depth; i++) 3282 { 3283 const ptrdiff_t layerOffset = (inputDepthPitch * i); 3284 gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), i); 3285 ANGLE_TRY( 3286 setImageImpl(context, layerIndex, type, unpack, unpackBuffer, pixels, layerOffset)); 3287 } 3288 3289 return angle::Result::Continue; 3290 } 3291 3292 angle::Result TextureD3D_2DArray::setSubImage(const gl::Context *context, 3293 const gl::ImageIndex &index, 3294 const gl::Box &area, 3295 GLenum format, 3296 GLenum type, 3297 const gl::PixelUnpackState &unpack, 3298 gl::Buffer *unpackBuffer, 3299 const uint8_t *pixels) 3300 { 3301 ContextD3D *contextD3D = GetImplAs<ContextD3D>(context); 3302 3303 ASSERT(index.getTarget() == gl::TextureTarget::_2DArray); 3304 const gl::InternalFormat &formatInfo = 3305 gl::GetInternalFormatInfo(getInternalFormat(index.getLevelIndex()), type); 3306 GLuint inputDepthPitch = 0; 3307 ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeDepthPitch( 3308 type, area.width, area.height, unpack.alignment, 3309 unpack.rowLength, unpack.imageHeight, &inputDepthPitch)); 3310 3311 for (int i = 0; i < area.depth; i++) 3312 { 3313 int layer = area.z + i; 3314 const ptrdiff_t layerOffset = (inputDepthPitch * i); 3315 3316 gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1); 3317 3318 gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), layer); 3319 ANGLE_TRY(TextureD3D::subImage(context, layerIndex, layerArea, format, type, unpack, 3320 unpackBuffer, pixels, layerOffset)); 3321 } 3322 3323 return angle::Result::Continue; 3324 } 3325 3326 angle::Result TextureD3D_2DArray::setCompressedImage(const gl::Context *context, 3327 const gl::ImageIndex &index, 3328 GLenum internalFormat, 3329 const gl::Extents &size, 3330 const gl::PixelUnpackState &unpack, 3331 size_t imageSize, 3332 const uint8_t *pixels) 3333 { 3334 ASSERT(index.getTarget() == gl::TextureTarget::_2DArray); 3335 3336 ContextD3D *contextD3D = GetImplAs<ContextD3D>(context); 3337 3338 // compressed formats don't have separate sized internal formats-- we can just use the 3339 // compressed format directly 3340 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false)); 3341 3342 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); 3343 GLuint inputDepthPitch = 0; 3344 ANGLE_CHECK_GL_MATH( 3345 contextD3D, formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0, 0, 3346 &inputDepthPitch)); 3347 3348 for (int i = 0; i < size.depth; i++) 3349 { 3350 const ptrdiff_t layerOffset = (inputDepthPitch * i); 3351 3352 gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), i); 3353 ANGLE_TRY(setCompressedImageImpl(context, layerIndex, unpack, pixels, layerOffset)); 3354 } 3355 3356 return angle::Result::Continue; 3357 } 3358 3359 angle::Result TextureD3D_2DArray::setCompressedSubImage(const gl::Context *context, 3360 const gl::ImageIndex &index, 3361 const gl::Box &area, 3362 GLenum format, 3363 const gl::PixelUnpackState &unpack, 3364 size_t imageSize, 3365 const uint8_t *pixels) 3366 { 3367 ASSERT(index.getTarget() == gl::TextureTarget::_2DArray); 3368 3369 ContextD3D *contextD3D = GetImplAs<ContextD3D>(context); 3370 3371 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(format); 3372 GLuint inputDepthPitch = 0; 3373 ANGLE_CHECK_GL_MATH( 3374 contextD3D, formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0, 0, 3375 &inputDepthPitch)); 3376 3377 for (int i = 0; i < area.depth; i++) 3378 { 3379 int layer = area.z + i; 3380 const ptrdiff_t layerOffset = (inputDepthPitch * i); 3381 3382 gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1); 3383 3384 gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), layer); 3385 ANGLE_TRY(TextureD3D::subImageCompressed(context, layerIndex, layerArea, format, unpack, 3386 pixels, layerOffset)); 3387 ANGLE_TRY(commitRegion(context, layerIndex, layerArea)); 3388 } 3389 3390 return angle::Result::Continue; 3391 } 3392 3393 angle::Result TextureD3D_2DArray::copyImage(const gl::Context *context, 3394 const gl::ImageIndex &index, 3395 const gl::Rectangle &sourceArea, 3396 GLenum internalFormat, 3397 gl::Framebuffer *source) 3398 { 3399 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 3400 return angle::Result::Continue; 3401 } 3402 3403 angle::Result TextureD3D_2DArray::copySubImage(const gl::Context *context, 3404 const gl::ImageIndex &index, 3405 const gl::Offset &destOffset, 3406 const gl::Rectangle &sourceArea, 3407 gl::Framebuffer *source) 3408 { 3409 ASSERT(index.getTarget() == gl::TextureTarget::_2DArray); 3410 3411 gl::Extents fbSize = source->getReadColorAttachment()->getSize(); 3412 gl::Rectangle clippedSourceArea; 3413 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), 3414 &clippedSourceArea)) 3415 { 3416 return angle::Result::Continue; 3417 } 3418 const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x, 3419 destOffset.y + clippedSourceArea.y - sourceArea.y, 3420 destOffset.z); 3421 3422 if (!canCreateRenderTargetForImage(index)) 3423 { 3424 gl::Offset destLayerOffset(clippedDestOffset.x, clippedDestOffset.y, 0); 3425 ANGLE_TRY(mImageArray[index.getLevelIndex()][clippedDestOffset.z]->copyFromFramebuffer( 3426 context, destLayerOffset, clippedSourceArea, source)); 3427 mDirtyImages = true; 3428 onStateChange(angle::SubjectMessage::DirtyBitsFlagged); 3429 } 3430 else 3431 { 3432 ANGLE_TRY(ensureRenderTarget(context)); 3433 3434 if (isValidLevel(index.getLevelIndex())) 3435 { 3436 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex())); 3437 ANGLE_TRY( 3438 mRenderer->copyImage2DArray(context, source, clippedSourceArea, 3439 gl::GetUnsizedFormat(getInternalFormat(getBaseLevel())), 3440 clippedDestOffset, mTexStorage, index.getLevelIndex())); 3441 } 3442 } 3443 return angle::Result::Continue; 3444 } 3445 3446 angle::Result TextureD3D_2DArray::copyTexture(const gl::Context *context, 3447 const gl::ImageIndex &index, 3448 GLenum internalFormat, 3449 GLenum type, 3450 GLint sourceLevel, 3451 bool unpackFlipY, 3452 bool unpackPremultiplyAlpha, 3453 bool unpackUnmultiplyAlpha, 3454 const gl::Texture *source) 3455 { 3456 ASSERT(index.getTarget() == gl::TextureTarget::_2DArray); 3457 3458 gl::TextureType sourceType = source->getType(); 3459 3460 const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); 3461 gl::Extents size( 3462 static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)), 3463 static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)), 3464 static_cast<int>(source->getDepth(NonCubeTextureTypeToTarget(sourceType), sourceLevel))); 3465 3466 ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat, 3467 size, false)); 3468 3469 gl::Box sourceBox(0, 0, 0, size.width, size.height, size.depth); 3470 gl::Offset destOffset(0, 0, 0); 3471 3472 gl::ImageIndex destIndex = 3473 gl::ImageIndex::Make2DArrayRange(index.getLevelIndex(), 0, size.depth); 3474 3475 if (!isSRGB(index.getLevelIndex()) && 3476 canCreateRenderTargetForImage( 3477 gl::ImageIndex::Make2DArrayRange(index.getLevelIndex(), 0, size.depth))) 3478 { 3479 ANGLE_TRY(ensureRenderTarget(context)); 3480 ASSERT(isValidLevel(index.getLevelIndex())); 3481 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex())); 3482 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2DArray, 3483 sourceBox, internalFormatInfo.format, 3484 internalFormatInfo.type, destOffset, mTexStorage, 3485 index.getTarget(), index.getLevelIndex(), unpackFlipY, 3486 unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); 3487 } 3488 else 3489 { 3490 for (int i = 0; i < size.depth; i++) 3491 { 3492 gl::ImageIndex currentSourceDepthIndex = gl::ImageIndex::Make2DArray(sourceLevel, i); 3493 gl::ImageIndex currentDestDepthIndex = 3494 gl::ImageIndex::Make2DArray(index.getLevelIndex(), i); 3495 ImageD3D *sourceImage = nullptr; 3496 ImageD3D *destImage = nullptr; 3497 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source); 3498 3499 ANGLE_TRY(getImageAndSyncFromStorage(context, currentDestDepthIndex, &destImage)); 3500 ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, currentSourceDepthIndex, 3501 &sourceImage)); 3502 gl::Box imageBox(sourceBox.x, sourceBox.y, 0, sourceBox.width, sourceBox.height, 1); 3503 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, imageBox, destOffset, 3504 unpackFlipY, unpackPremultiplyAlpha, 3505 unpackUnmultiplyAlpha)); 3506 } 3507 3508 mDirtyImages = true; 3509 3510 gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width, 3511 sourceBox.height, sourceBox.depth); 3512 ANGLE_TRY(commitRegion(context, destIndex, destRegion)); 3513 } 3514 3515 return angle::Result::Continue; 3516 } 3517 3518 angle::Result TextureD3D_2DArray::copySubTexture(const gl::Context *context, 3519 const gl::ImageIndex &index, 3520 const gl::Offset &destOffset, 3521 GLint sourceLevel, 3522 const gl::Box &sourceBox, 3523 bool unpackFlipY, 3524 bool unpackPremultiplyAlpha, 3525 bool unpackUnmultiplyAlpha, 3526 const gl::Texture *source) 3527 { 3528 ASSERT(index.getTarget() == gl::TextureTarget::_2DArray); 3529 3530 gl::ImageIndex destIndex = gl::ImageIndex::Make2DArrayRange( 3531 static_cast<GLint>(index.getLevelIndex()), destOffset.z, sourceBox.depth - destOffset.z); 3532 3533 if (!isSRGB(destIndex.getLevelIndex()) && canCreateRenderTargetForImage(destIndex)) 3534 { 3535 ANGLE_TRY(ensureRenderTarget(context)); 3536 ASSERT(isValidLevel(destIndex.getLevelIndex())); 3537 ANGLE_TRY(updateStorageLevel(context, destIndex.getLevelIndex())); 3538 3539 const gl::InternalFormat &internalFormatInfo = 3540 gl::GetSizedInternalFormatInfo(getInternalFormat(destIndex.getLevelIndex())); 3541 ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2DArray, 3542 sourceBox, internalFormatInfo.format, 3543 internalFormatInfo.type, destOffset, mTexStorage, 3544 index.getTarget(), index.getLevelIndex(), unpackFlipY, 3545 unpackPremultiplyAlpha, unpackUnmultiplyAlpha)); 3546 } 3547 else 3548 { 3549 for (int i = 0; i < sourceBox.depth; i++) 3550 { 3551 gl::ImageIndex currentSourceIndex = 3552 gl::ImageIndex::Make2DArray(sourceLevel, i + sourceBox.z); 3553 gl::ImageIndex currentDestIndex = 3554 gl::ImageIndex::Make2DArray(index.getLevelIndex(), i + destOffset.z); 3555 3556 gl::Box currentLayerBox(sourceBox.x, sourceBox.y, 0, sourceBox.width, sourceBox.height, 3557 1); 3558 3559 TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source); 3560 ImageD3D *sourceImage = nullptr; 3561 ANGLE_TRY( 3562 sourceD3D->getImageAndSyncFromStorage(context, currentSourceIndex, &sourceImage)); 3563 3564 ImageD3D *destImage = nullptr; 3565 ANGLE_TRY(getImageAndSyncFromStorage(context, currentDestIndex, &destImage)); 3566 3567 ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, currentLayerBox, 3568 destOffset, unpackFlipY, unpackPremultiplyAlpha, 3569 unpackUnmultiplyAlpha)); 3570 } 3571 3572 mDirtyImages = true; 3573 3574 gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width, 3575 sourceBox.height, sourceBox.depth); 3576 ANGLE_TRY(commitRegion(context, destIndex, destRegion)); 3577 } 3578 3579 return angle::Result::Continue; 3580 } 3581 3582 angle::Result TextureD3D_2DArray::setStorage(const gl::Context *context, 3583 gl::TextureType type, 3584 size_t levels, 3585 GLenum internalFormat, 3586 const gl::Extents &size) 3587 { 3588 ASSERT(type == gl::TextureType::_2DArray); 3589 3590 deleteImages(); 3591 3592 for (size_t level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) 3593 { 3594 gl::Extents levelLayerSize(std::max(1, size.width >> level), 3595 std::max(1, size.height >> level), 1); 3596 3597 mLayerCounts[level] = (level < levels ? size.depth : 0); 3598 3599 if (mLayerCounts[level] > 0) 3600 { 3601 // Create new images for this level 3602 mImageArray[level] = new ImageD3D *[mLayerCounts[level]]; 3603 3604 for (int layer = 0; layer < mLayerCounts[level]; layer++) 3605 { 3606 mImageArray[level][layer] = mRenderer->createImage(); 3607 mImageArray[level][layer]->redefine(gl::TextureType::_2DArray, internalFormat, 3608 levelLayerSize, true); 3609 } 3610 } 3611 } 3612 3613 // TODO(geofflang): Verify storage creation had no errors 3614 BindFlags bindFlags; 3615 bindFlags.renderTarget = IsRenderTargetUsage(mState.getUsage()); 3616 TexStoragePointer storage = {mRenderer->createTextureStorage2DArray( 3617 internalFormat, bindFlags, size.width, size.height, size.depth, 3618 static_cast<int>(levels), mState.getLabel()), 3619 context}; 3620 3621 ANGLE_TRY(setCompleteTexStorage(context, storage.get())); 3622 storage.release(); 3623 3624 ANGLE_TRY(updateStorage(context)); 3625 3626 mImmutable = true; 3627 3628 return angle::Result::Continue; 3629 } 3630 3631 angle::Result TextureD3D_2DArray::bindTexImage(const gl::Context *context, egl::Surface *surface) 3632 { 3633 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 3634 return angle::Result::Continue; 3635 } 3636 3637 angle::Result TextureD3D_2DArray::releaseTexImage(const gl::Context *context) 3638 { 3639 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 3640 return angle::Result::Continue; 3641 } 3642 3643 angle::Result TextureD3D_2DArray::initMipmapImages(const gl::Context *context) 3644 { 3645 const GLuint baseLevel = mState.getEffectiveBaseLevel(); 3646 const GLuint maxLevel = mState.getMipmapMaxLevel(); 3647 int baseWidth = getLevelZeroWidth(); 3648 int baseHeight = getLevelZeroHeight(); 3649 int baseDepth = getLayerCount(getBaseLevel()); 3650 GLenum baseFormat = getBaseLevelInternalFormat(); 3651 3652 // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap 3653 // levels. 3654 for (GLuint level = baseLevel + 1u; level <= maxLevel; level++) 3655 { 3656 ASSERT((baseWidth >> level) > 0 || (baseHeight >> level) > 0); 3657 gl::Extents levelLayerSize(std::max(baseWidth >> level, 1), 3658 std::max(baseHeight >> level, 1), baseDepth); 3659 ANGLE_TRY(redefineImage(context, level, baseFormat, levelLayerSize, false)); 3660 } 3661 3662 // We should be mip-complete now so generate the storage. 3663 ANGLE_TRY(initializeStorage(context, BindFlags::RenderTarget())); 3664 3665 return angle::Result::Continue; 3666 } 3667 3668 angle::Result TextureD3D_2DArray::getRenderTarget(const gl::Context *context, 3669 const gl::ImageIndex &index, 3670 GLsizei samples, 3671 RenderTargetD3D **outRT) 3672 { 3673 // ensure the underlying texture is created 3674 ANGLE_TRY(ensureRenderTarget(context)); 3675 ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex())); 3676 return mTexStorage->getRenderTarget(context, index, samples, outRT); 3677 } 3678 3679 angle::Result TextureD3D_2DArray::initializeStorage(const gl::Context *context, BindFlags bindFlags) 3680 { 3681 // Only initialize the first time this texture is used as a render target or shader resource 3682 if (mTexStorage) 3683 { 3684 return angle::Result::Continue; 3685 } 3686 3687 // do not attempt to create storage for nonexistant data 3688 if (!isLevelComplete(getBaseLevel())) 3689 { 3690 return angle::Result::Continue; 3691 } 3692 3693 bindFlags.renderTarget |= IsRenderTargetUsage(mState.getUsage()); 3694 3695 TexStoragePointer storage; 3696 ANGLE_TRY(createCompleteStorage(context, bindFlags, &storage)); 3697 3698 ANGLE_TRY(setCompleteTexStorage(context, storage.get())); 3699 storage.release(); 3700 3701 ASSERT(mTexStorage); 3702 3703 // flush image data to the storage 3704 ANGLE_TRY(updateStorage(context)); 3705 3706 return angle::Result::Continue; 3707 } 3708 3709 angle::Result TextureD3D_2DArray::createCompleteStorage(const gl::Context *context, 3710 BindFlags bindFlags, 3711 TexStoragePointer *outStorage) const 3712 { 3713 GLsizei width = getLevelZeroWidth(); 3714 GLsizei height = getLevelZeroHeight(); 3715 GLsizei depth = getLayerCount(getBaseLevel()); 3716 GLenum internalFormat = getBaseLevelInternalFormat(); 3717 3718 ASSERT(width > 0 && height > 0 && depth > 0); 3719 3720 // use existing storage level count, when previously specified by TexStorage*D 3721 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); 3722 3723 // TODO(geofflang): Verify storage creation succeeds 3724 *outStorage = {mRenderer->createTextureStorage2DArray(internalFormat, bindFlags, width, height, 3725 depth, levels, mState.getLabel()), 3726 context}; 3727 3728 return angle::Result::Continue; 3729 } 3730 3731 angle::Result TextureD3D_2DArray::setCompleteTexStorage(const gl::Context *context, 3732 TextureStorage *newCompleteTexStorage) 3733 { 3734 gl::TexLevelMask copyImageMask; 3735 copyImageMask.set(); 3736 3737 ANGLE_TRY(releaseTexStorage(context, copyImageMask)); 3738 mTexStorage = newCompleteTexStorage; 3739 mTexStorageObserverBinding.bind(mTexStorage); 3740 mDirtyImages = true; 3741 3742 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only 3743 ASSERT(!mTexStorage->isManaged()); 3744 3745 return angle::Result::Continue; 3746 } 3747 3748 angle::Result TextureD3D_2DArray::updateStorage(const gl::Context *context) 3749 { 3750 if (!mDirtyImages) 3751 { 3752 return angle::Result::Continue; 3753 } 3754 3755 ASSERT(mTexStorage != nullptr); 3756 GLint storageLevels = mTexStorage->getLevelCount(); 3757 for (int level = 0; level < storageLevels; level++) 3758 { 3759 if (isLevelComplete(level)) 3760 { 3761 ANGLE_TRY(updateStorageLevel(context, level)); 3762 } 3763 } 3764 3765 mDirtyImages = false; 3766 return angle::Result::Continue; 3767 } 3768 3769 bool TextureD3D_2DArray::isValidLevel(int level) const 3770 { 3771 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); 3772 } 3773 3774 bool TextureD3D_2DArray::isLevelComplete(int level) const 3775 { 3776 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray)); 3777 3778 if (isImmutable()) 3779 { 3780 return true; 3781 } 3782 3783 GLsizei width = getLevelZeroWidth(); 3784 GLsizei height = getLevelZeroHeight(); 3785 3786 if (width <= 0 || height <= 0) 3787 { 3788 return false; 3789 } 3790 3791 // Layers check needs to happen after the above checks, otherwise out-of-range base level may be 3792 // queried. 3793 GLsizei layers = getLayerCount(getBaseLevel()); 3794 3795 if (layers <= 0) 3796 { 3797 return false; 3798 } 3799 3800 if (level == static_cast<int>(getBaseLevel())) 3801 { 3802 return true; 3803 } 3804 3805 if (getInternalFormat(level) != getInternalFormat(getBaseLevel())) 3806 { 3807 return false; 3808 } 3809 3810 if (getWidth(level) != std::max(1, width >> level)) 3811 { 3812 return false; 3813 } 3814 3815 if (getHeight(level) != std::max(1, height >> level)) 3816 { 3817 return false; 3818 } 3819 3820 if (getLayerCount(level) != layers) 3821 { 3822 return false; 3823 } 3824 3825 return true; 3826 } 3827 3828 bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const 3829 { 3830 return isLevelComplete(index.getLevelIndex()); 3831 } 3832 3833 angle::Result TextureD3D_2DArray::updateStorageLevel(const gl::Context *context, int level) 3834 { 3835 ASSERT(level >= 0 && level < static_cast<int>(ArraySize(mLayerCounts))); 3836 ASSERT(isLevelComplete(level)); 3837 3838 for (int layer = 0; layer < mLayerCounts[level]; layer++) 3839 { 3840 ASSERT(mImageArray[level] != nullptr && mImageArray[level][layer] != nullptr); 3841 if (mImageArray[level][layer]->isDirty()) 3842 { 3843 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); 3844 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); 3845 ANGLE_TRY(commitRegion(context, index, region)); 3846 } 3847 } 3848 3849 return angle::Result::Continue; 3850 } 3851 3852 void TextureD3D_2DArray::deleteImages() 3853 { 3854 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) 3855 { 3856 for (int layer = 0; layer < mLayerCounts[level]; ++layer) 3857 { 3858 delete mImageArray[level][layer]; 3859 } 3860 delete[] mImageArray[level]; 3861 mImageArray[level] = nullptr; 3862 mLayerCounts[level] = 0; 3863 } 3864 } 3865 3866 angle::Result TextureD3D_2DArray::redefineImage(const gl::Context *context, 3867 GLint level, 3868 GLenum internalformat, 3869 const gl::Extents &size, 3870 bool forceRelease) 3871 { 3872 // If there currently is a corresponding storage texture image, it has these parameters 3873 const int storageWidth = std::max(1, getLevelZeroWidth() >> level); 3874 const int storageHeight = std::max(1, getLevelZeroHeight() >> level); 3875 const GLuint baseLevel = getBaseLevel(); 3876 const GLenum storageFormat = getBaseLevelInternalFormat(); 3877 3878 int storageDepth = 0; 3879 if (baseLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) 3880 { 3881 storageDepth = getLayerCount(baseLevel); 3882 } 3883 3884 // Only reallocate the layers if the size doesn't match 3885 if (size.depth != mLayerCounts[level]) 3886 { 3887 for (int layer = 0; layer < mLayerCounts[level]; layer++) 3888 { 3889 SafeDelete(mImageArray[level][layer]); 3890 } 3891 SafeDeleteArray(mImageArray[level]); 3892 mLayerCounts[level] = size.depth; 3893 3894 if (size.depth > 0) 3895 { 3896 mImageArray[level] = new ImageD3D *[size.depth]; 3897 for (int layer = 0; layer < mLayerCounts[level]; layer++) 3898 { 3899 mImageArray[level][layer] = mRenderer->createImage(); 3900 } 3901 } 3902 } 3903 3904 if (mTexStorage) 3905 { 3906 const int storageLevels = mTexStorage->getLevelCount(); 3907 3908 if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth || 3909 size.height != storageHeight || size.depth != storageDepth || 3910 internalformat != storageFormat) // Discard mismatched storage 3911 { 3912 markAllImagesDirty(); 3913 3914 gl::TexLevelMask copyImageMask; 3915 copyImageMask.set(); 3916 copyImageMask.set(level, false); 3917 3918 ANGLE_TRY(releaseTexStorage(context, copyImageMask)); 3919 } 3920 } 3921 3922 if (size.depth > 0) 3923 { 3924 for (int layer = 0; layer < mLayerCounts[level]; layer++) 3925 { 3926 mImageArray[level][layer]->redefine(gl::TextureType::_2DArray, internalformat, 3927 gl::Extents(size.width, size.height, 1), 3928 forceRelease); 3929 mDirtyImages = mDirtyImages || mImageArray[level][layer]->isDirty(); 3930 } 3931 } 3932 3933 return angle::Result::Continue; 3934 } 3935 3936 gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const 3937 { 3938 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts); 3939 } 3940 3941 gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const 3942 { 3943 return gl::ImageIndex::Make2DArray(mip, layer); 3944 } 3945 3946 bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const 3947 { 3948 // Check for having a storage and the right type of index 3949 if (!mTexStorage || index.getType() != gl::TextureType::_2DArray) 3950 { 3951 return false; 3952 } 3953 3954 // Check the mip index 3955 if (index.getLevelIndex() < 0 || index.getLevelIndex() >= mTexStorage->getLevelCount()) 3956 { 3957 return false; 3958 } 3959 3960 // Check the layer index 3961 return (!index.hasLayer() || (index.getLayerIndex() >= 0 && 3962 index.getLayerIndex() < mLayerCounts[index.getLevelIndex()])); 3963 } 3964 3965 void TextureD3D_2DArray::markAllImagesDirty() 3966 { 3967 for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) 3968 { 3969 for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++) 3970 { 3971 mImageArray[dirtyLevel][dirtyLayer]->markDirty(); 3972 } 3973 } 3974 mDirtyImages = true; 3975 } 3976 3977 TextureD3DImmutableBase::TextureD3DImmutableBase(const gl::TextureState &state, 3978 RendererD3D *renderer) 3979 : TextureD3D(state, renderer) 3980 {} 3981 3982 TextureD3DImmutableBase::~TextureD3DImmutableBase() {} 3983 3984 ImageD3D *TextureD3DImmutableBase::getImage(const gl::ImageIndex &index) const 3985 { 3986 return nullptr; 3987 } 3988 3989 angle::Result TextureD3DImmutableBase::setImage(const gl::Context *context, 3990 const gl::ImageIndex &index, 3991 GLenum internalFormat, 3992 const gl::Extents &size, 3993 GLenum format, 3994 GLenum type, 3995 const gl::PixelUnpackState &unpack, 3996 gl::Buffer *unpackBuffer, 3997 const uint8_t *pixels) 3998 { 3999 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4000 return angle::Result::Continue; 4001 } 4002 4003 angle::Result TextureD3DImmutableBase::setSubImage(const gl::Context *context, 4004 const gl::ImageIndex &index, 4005 const gl::Box &area, 4006 GLenum format, 4007 GLenum type, 4008 const gl::PixelUnpackState &unpack, 4009 gl::Buffer *unpackBuffer, 4010 const uint8_t *pixels) 4011 { 4012 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4013 return angle::Result::Continue; 4014 } 4015 4016 angle::Result TextureD3DImmutableBase::setCompressedImage(const gl::Context *context, 4017 const gl::ImageIndex &index, 4018 GLenum internalFormat, 4019 const gl::Extents &size, 4020 const gl::PixelUnpackState &unpack, 4021 size_t imageSize, 4022 const uint8_t *pixels) 4023 { 4024 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4025 return angle::Result::Continue; 4026 } 4027 4028 angle::Result TextureD3DImmutableBase::setCompressedSubImage(const gl::Context *context, 4029 const gl::ImageIndex &index, 4030 const gl::Box &area, 4031 GLenum format, 4032 const gl::PixelUnpackState &unpack, 4033 size_t imageSize, 4034 const uint8_t *pixels) 4035 { 4036 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4037 return angle::Result::Continue; 4038 } 4039 4040 angle::Result TextureD3DImmutableBase::copyImage(const gl::Context *context, 4041 const gl::ImageIndex &index, 4042 const gl::Rectangle &sourceArea, 4043 GLenum internalFormat, 4044 gl::Framebuffer *source) 4045 { 4046 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4047 return angle::Result::Continue; 4048 } 4049 4050 angle::Result TextureD3DImmutableBase::copySubImage(const gl::Context *context, 4051 const gl::ImageIndex &index, 4052 const gl::Offset &destOffset, 4053 const gl::Rectangle &sourceArea, 4054 gl::Framebuffer *source) 4055 { 4056 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4057 return angle::Result::Continue; 4058 } 4059 4060 angle::Result TextureD3DImmutableBase::bindTexImage(const gl::Context *context, 4061 egl::Surface *surface) 4062 { 4063 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4064 return angle::Result::Continue; 4065 } 4066 4067 angle::Result TextureD3DImmutableBase::releaseTexImage(const gl::Context *context) 4068 { 4069 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4070 return angle::Result::Continue; 4071 } 4072 4073 TextureD3D_External::TextureD3D_External(const gl::TextureState &state, RendererD3D *renderer) 4074 : TextureD3DImmutableBase(state, renderer) 4075 {} 4076 4077 TextureD3D_External::~TextureD3D_External() {} 4078 4079 GLsizei TextureD3D_External::getLayerCount(int level) const 4080 { 4081 return 1; 4082 } 4083 4084 angle::Result TextureD3D_External::setImageExternal(const gl::Context *context, 4085 gl::TextureType type, 4086 egl::Stream *stream, 4087 const egl::Stream::GLTextureDescription &desc) 4088 { 4089 ASSERT(type == gl::TextureType::External); 4090 4091 ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask())); 4092 4093 // If the stream is null, the external image is unbound and we release the storage 4094 if (stream != nullptr) 4095 { 4096 mTexStorage = mRenderer->createTextureStorageExternal(stream, desc, mState.getLabel()); 4097 } 4098 4099 return angle::Result::Continue; 4100 } 4101 4102 angle::Result TextureD3D_External::setEGLImageTarget(const gl::Context *context, 4103 gl::TextureType type, 4104 egl::Image *image) 4105 { 4106 EGLImageD3D *eglImaged3d = GetImplAs<EGLImageD3D>(image); 4107 4108 // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error. 4109 RenderTargetD3D *renderTargetD3D = nullptr; 4110 ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D)); 4111 4112 ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask())); 4113 mTexStorage = 4114 mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D, mState.getLabel()); 4115 4116 return angle::Result::Continue; 4117 } 4118 4119 angle::Result TextureD3D_External::initMipmapImages(const gl::Context *context) 4120 { 4121 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4122 return angle::Result::Stop; 4123 } 4124 4125 angle::Result TextureD3D_External::getRenderTarget(const gl::Context *context, 4126 const gl::ImageIndex &index, 4127 GLsizei samples, 4128 RenderTargetD3D **outRT) 4129 { 4130 UNREACHABLE(); 4131 return angle::Result::Stop; 4132 } 4133 4134 bool TextureD3D_External::isImageComplete(const gl::ImageIndex &index) const 4135 { 4136 return (index.getLevelIndex() == 0) ? (mTexStorage != nullptr) : false; 4137 } 4138 4139 angle::Result TextureD3D_External::initializeStorage(const gl::Context *context, 4140 BindFlags bindFlags) 4141 { 4142 // Texture storage is created when an external image is bound 4143 ASSERT(mTexStorage); 4144 return angle::Result::Continue; 4145 } 4146 4147 angle::Result TextureD3D_External::createCompleteStorage(const gl::Context *context, 4148 BindFlags bindFlags, 4149 TexStoragePointer *outStorage) const 4150 { 4151 UNREACHABLE(); 4152 return angle::Result::Continue; 4153 } 4154 4155 angle::Result TextureD3D_External::setCompleteTexStorage(const gl::Context *context, 4156 TextureStorage *newCompleteTexStorage) 4157 { 4158 UNREACHABLE(); 4159 return angle::Result::Continue; 4160 } 4161 4162 angle::Result TextureD3D_External::updateStorage(const gl::Context *context) 4163 { 4164 // Texture storage does not need to be updated since it is already loaded with the latest 4165 // external image 4166 ASSERT(mTexStorage); 4167 return angle::Result::Continue; 4168 } 4169 4170 gl::ImageIndexIterator TextureD3D_External::imageIterator() const 4171 { 4172 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount()); 4173 } 4174 4175 gl::ImageIndex TextureD3D_External::getImageIndex(GLint mip, GLint /*layer*/) const 4176 { 4177 // "layer" does not apply to 2D Textures. 4178 return gl::ImageIndex::Make2D(mip); 4179 } 4180 4181 bool TextureD3D_External::isValidIndex(const gl::ImageIndex &index) const 4182 { 4183 return (mTexStorage && index.getType() == gl::TextureType::External && 4184 index.getLevelIndex() == 0); 4185 } 4186 4187 void TextureD3D_External::markAllImagesDirty() 4188 { 4189 UNREACHABLE(); 4190 } 4191 4192 TextureD3D_2DMultisample::TextureD3D_2DMultisample(const gl::TextureState &state, 4193 RendererD3D *renderer) 4194 : TextureD3DImmutableBase(state, renderer) 4195 {} 4196 4197 TextureD3D_2DMultisample::~TextureD3D_2DMultisample() {} 4198 4199 angle::Result TextureD3D_2DMultisample::setStorageMultisample(const gl::Context *context, 4200 gl::TextureType type, 4201 GLsizei samples, 4202 GLint internalformat, 4203 const gl::Extents &size, 4204 bool fixedSampleLocations) 4205 { 4206 ASSERT(type == gl::TextureType::_2DMultisample && size.depth == 1); 4207 4208 // We allocate storage immediately instead of doing it lazily like other TextureD3D classes do. 4209 // This requires less state in this class. 4210 TexStoragePointer storage = {mRenderer->createTextureStorage2DMultisample( 4211 internalformat, size.width, size.height, static_cast<int>(0), 4212 samples, fixedSampleLocations, mState.getLabel()), 4213 context}; 4214 4215 ANGLE_TRY(setCompleteTexStorage(context, storage.get())); 4216 storage.release(); 4217 4218 mImmutable = true; 4219 4220 return angle::Result::Continue; 4221 } 4222 4223 angle::Result TextureD3D_2DMultisample::setEGLImageTarget(const gl::Context *context, 4224 gl::TextureType type, 4225 egl::Image *image) 4226 { 4227 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4228 return angle::Result::Continue; 4229 } 4230 4231 angle::Result TextureD3D_2DMultisample::getRenderTarget(const gl::Context *context, 4232 const gl::ImageIndex &index, 4233 GLsizei samples, 4234 RenderTargetD3D **outRT) 4235 { 4236 ASSERT(!index.hasLayer()); 4237 4238 // ensure the underlying texture is created 4239 ANGLE_TRY(ensureRenderTarget(context)); 4240 4241 return mTexStorage->getRenderTarget(context, index, samples, outRT); 4242 } 4243 4244 gl::ImageIndexIterator TextureD3D_2DMultisample::imageIterator() const 4245 { 4246 return gl::ImageIndexIterator::Make2DMultisample(); 4247 } 4248 4249 gl::ImageIndex TextureD3D_2DMultisample::getImageIndex(GLint mip, GLint layer) const 4250 { 4251 return gl::ImageIndex::Make2DMultisample(); 4252 } 4253 4254 bool TextureD3D_2DMultisample::isValidIndex(const gl::ImageIndex &index) const 4255 { 4256 return (mTexStorage && index.getType() == gl::TextureType::_2DMultisample && 4257 index.getLevelIndex() == 0); 4258 } 4259 4260 GLsizei TextureD3D_2DMultisample::getLayerCount(int level) const 4261 { 4262 return 1; 4263 } 4264 4265 void TextureD3D_2DMultisample::markAllImagesDirty() {} 4266 4267 angle::Result TextureD3D_2DMultisample::initializeStorage(const gl::Context *context, 4268 BindFlags bindFlags) 4269 { 4270 // initializeStorage should only be called in a situation where the texture already has storage 4271 // associated with it (storage is created in setStorageMultisample). 4272 ASSERT(mTexStorage); 4273 return angle::Result::Continue; 4274 } 4275 4276 angle::Result TextureD3D_2DMultisample::createCompleteStorage(const gl::Context *context, 4277 BindFlags bindFlags, 4278 TexStoragePointer *outStorage) const 4279 { 4280 UNREACHABLE(); 4281 *outStorage = {mTexStorage, context}; 4282 return angle::Result::Continue; 4283 } 4284 4285 angle::Result TextureD3D_2DMultisample::setCompleteTexStorage(const gl::Context *context, 4286 TextureStorage *newCompleteTexStorage) 4287 { 4288 // These textures are immutable, so this should only be ever called once. 4289 ASSERT(!mTexStorage); 4290 mTexStorage = newCompleteTexStorage; 4291 mTexStorageObserverBinding.bind(mTexStorage); 4292 return angle::Result::Continue; 4293 } 4294 4295 angle::Result TextureD3D_2DMultisample::updateStorage(const gl::Context *context) 4296 { 4297 return angle::Result::Continue; 4298 } 4299 4300 angle::Result TextureD3D_2DMultisample::initMipmapImages(const gl::Context *context) 4301 { 4302 UNREACHABLE(); 4303 return angle::Result::Continue; 4304 } 4305 4306 bool TextureD3D_2DMultisample::isImageComplete(const gl::ImageIndex &index) const 4307 { 4308 return true; 4309 } 4310 4311 TextureD3D_2DMultisampleArray::TextureD3D_2DMultisampleArray(const gl::TextureState &state, 4312 RendererD3D *renderer) 4313 : TextureD3DImmutableBase(state, renderer) 4314 {} 4315 4316 TextureD3D_2DMultisampleArray::~TextureD3D_2DMultisampleArray() {} 4317 4318 angle::Result TextureD3D_2DMultisampleArray::setStorageMultisample(const gl::Context *context, 4319 gl::TextureType type, 4320 GLsizei samples, 4321 GLint internalformat, 4322 const gl::Extents &size, 4323 bool fixedSampleLocations) 4324 { 4325 ASSERT(type == gl::TextureType::_2DMultisampleArray); 4326 4327 mLayerCount = size.depth; 4328 4329 TexStoragePointer storage = { 4330 mRenderer->createTextureStorage2DMultisampleArray(internalformat, size.width, size.height, 4331 size.depth, static_cast<int>(0), samples, 4332 fixedSampleLocations, mState.getLabel()), 4333 context}; 4334 4335 ANGLE_TRY(setCompleteTexStorage(context, storage.get())); 4336 storage.release(); 4337 4338 mImmutable = true; 4339 4340 return angle::Result::Continue; 4341 } 4342 4343 angle::Result TextureD3D_2DMultisampleArray::setEGLImageTarget(const gl::Context *context, 4344 gl::TextureType type, 4345 egl::Image *image) 4346 { 4347 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4348 return angle::Result::Continue; 4349 } 4350 4351 angle::Result TextureD3D_2DMultisampleArray::getRenderTarget(const gl::Context *context, 4352 const gl::ImageIndex &index, 4353 GLsizei samples, 4354 RenderTargetD3D **outRT) 4355 { 4356 // ensure the underlying texture is created 4357 ANGLE_TRY(ensureRenderTarget(context)); 4358 4359 return mTexStorage->getRenderTarget(context, index, samples, outRT); 4360 } 4361 4362 gl::ImageIndexIterator TextureD3D_2DMultisampleArray::imageIterator() const 4363 { 4364 return gl::ImageIndexIterator::Make2DMultisampleArray(&mLayerCount); 4365 } 4366 4367 gl::ImageIndex TextureD3D_2DMultisampleArray::getImageIndex(GLint mip, GLint layer) const 4368 { 4369 return gl::ImageIndex::Make2DMultisampleArray(layer); 4370 } 4371 4372 bool TextureD3D_2DMultisampleArray::isValidIndex(const gl::ImageIndex &index) const 4373 { 4374 return (mTexStorage && index.getType() == gl::TextureType::_2DMultisampleArray && 4375 index.getLevelIndex() == 0); 4376 } 4377 4378 GLsizei TextureD3D_2DMultisampleArray::getLayerCount(int level) const 4379 { 4380 return mLayerCount; 4381 } 4382 4383 void TextureD3D_2DMultisampleArray::markAllImagesDirty() {} 4384 4385 angle::Result TextureD3D_2DMultisampleArray::initializeStorage(const gl::Context *context, 4386 BindFlags bindFlags) 4387 { 4388 // initializeStorage should only be called in a situation where the texture already has storage 4389 // associated with it (storage is created in setStorageMultisample). 4390 ASSERT(mTexStorage); 4391 return angle::Result::Continue; 4392 } 4393 4394 angle::Result TextureD3D_2DMultisampleArray::createCompleteStorage( 4395 const gl::Context *context, 4396 BindFlags bindFlags, 4397 TexStoragePointer *outStorage) const 4398 { 4399 UNREACHABLE(); 4400 *outStorage = {mTexStorage, context}; 4401 return angle::Result::Continue; 4402 } 4403 4404 angle::Result TextureD3D_2DMultisampleArray::setCompleteTexStorage( 4405 const gl::Context *context, 4406 TextureStorage *newCompleteTexStorage) 4407 { 4408 // These textures are immutable, so this should only be ever called once. 4409 ASSERT(!mTexStorage); 4410 mTexStorage = newCompleteTexStorage; 4411 mTexStorageObserverBinding.bind(mTexStorage); 4412 return angle::Result::Continue; 4413 } 4414 4415 angle::Result TextureD3D_2DMultisampleArray::updateStorage(const gl::Context *context) 4416 { 4417 return angle::Result::Continue; 4418 } 4419 4420 angle::Result TextureD3D_2DMultisampleArray::initMipmapImages(const gl::Context *context) 4421 { 4422 UNIMPLEMENTED(); 4423 return angle::Result::Continue; 4424 } 4425 4426 bool TextureD3D_2DMultisampleArray::isImageComplete(const gl::ImageIndex &index) const 4427 { 4428 return true; 4429 } 4430 4431 TextureD3D_Buffer::TextureD3D_Buffer(const gl::TextureState &state, RendererD3D *renderer) 4432 : TextureD3D(state, renderer), mInternalFormat(GL_INVALID_ENUM) 4433 {} 4434 4435 TextureD3D_Buffer::~TextureD3D_Buffer() {} 4436 4437 angle::Result TextureD3D_Buffer::setImage(const gl::Context *context, 4438 const gl::ImageIndex &index, 4439 GLenum internalFormat, 4440 const gl::Extents &size, 4441 GLenum format, 4442 GLenum type, 4443 const gl::PixelUnpackState &unpack, 4444 gl::Buffer *unpackBuffer, 4445 const uint8_t *pixels) 4446 { 4447 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4448 return angle::Result::Continue; 4449 } 4450 4451 angle::Result TextureD3D_Buffer::setSubImage(const gl::Context *context, 4452 const gl::ImageIndex &index, 4453 const gl::Box &area, 4454 GLenum format, 4455 GLenum type, 4456 const gl::PixelUnpackState &unpack, 4457 gl::Buffer *unpackBuffer, 4458 const uint8_t *pixels) 4459 { 4460 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4461 return angle::Result::Continue; 4462 } 4463 4464 angle::Result TextureD3D_Buffer::setCompressedImage(const gl::Context *context, 4465 const gl::ImageIndex &index, 4466 GLenum internalFormat, 4467 const gl::Extents &size, 4468 const gl::PixelUnpackState &unpack, 4469 size_t imageSize, 4470 const uint8_t *pixels) 4471 { 4472 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4473 return angle::Result::Continue; 4474 } 4475 4476 angle::Result TextureD3D_Buffer::setCompressedSubImage(const gl::Context *context, 4477 const gl::ImageIndex &index, 4478 const gl::Box &area, 4479 GLenum format, 4480 const gl::PixelUnpackState &unpack, 4481 size_t imageSize, 4482 const uint8_t *pixels) 4483 { 4484 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4485 return angle::Result::Continue; 4486 } 4487 4488 angle::Result TextureD3D_Buffer::copyImage(const gl::Context *context, 4489 const gl::ImageIndex &index, 4490 const gl::Rectangle &sourceArea, 4491 GLenum internalFormat, 4492 gl::Framebuffer *source) 4493 { 4494 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4495 return angle::Result::Continue; 4496 } 4497 4498 angle::Result TextureD3D_Buffer::copySubImage(const gl::Context *context, 4499 const gl::ImageIndex &index, 4500 const gl::Offset &destOffset, 4501 const gl::Rectangle &sourceArea, 4502 gl::Framebuffer *source) 4503 { 4504 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4505 return angle::Result::Continue; 4506 } 4507 4508 angle::Result TextureD3D_Buffer::bindTexImage(const gl::Context *context, egl::Surface *surface) 4509 { 4510 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4511 return angle::Result::Continue; 4512 } 4513 4514 angle::Result TextureD3D_Buffer::releaseTexImage(const gl::Context *context) 4515 { 4516 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4517 return angle::Result::Continue; 4518 } 4519 4520 GLsizei TextureD3D_Buffer::getLayerCount(int level) const 4521 { 4522 return 1; 4523 } 4524 4525 angle::Result TextureD3D_Buffer::initMipmapImages(const gl::Context *context) 4526 { 4527 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4528 return angle::Result::Stop; 4529 } 4530 4531 bool TextureD3D_Buffer::isImageComplete(const gl::ImageIndex &index) const 4532 { 4533 return (index.getLevelIndex() == 0) ? (mTexStorage != nullptr) : false; 4534 } 4535 4536 angle::Result TextureD3D_Buffer::initializeStorage(const gl::Context *context, BindFlags bindFlags) 4537 { 4538 ASSERT(mTexStorage); 4539 return angle::Result::Continue; 4540 } 4541 4542 angle::Result TextureD3D_Buffer::createCompleteStorage(const gl::Context *context, 4543 BindFlags bindFlags, 4544 TexStoragePointer *outStorage) const 4545 { 4546 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4547 return angle::Result::Continue; 4548 } 4549 4550 angle::Result TextureD3D_Buffer::setCompleteTexStorage(const gl::Context *context, 4551 TextureStorage *newCompleteTexStorage) 4552 { 4553 ANGLE_TRY(releaseTexStorage(context, gl::TexLevelMask())); 4554 mTexStorage = newCompleteTexStorage; 4555 mTexStorageObserverBinding.bind(mTexStorage); 4556 4557 mDirtyImages = true; 4558 4559 return angle::Result::Continue; 4560 } 4561 4562 angle::Result TextureD3D_Buffer::updateStorage(const gl::Context *context) 4563 { 4564 ASSERT(mTexStorage); 4565 return angle::Result::Continue; 4566 } 4567 4568 gl::ImageIndexIterator TextureD3D_Buffer::imageIterator() const 4569 { 4570 return gl::ImageIndexIterator::MakeBuffer(); 4571 } 4572 4573 gl::ImageIndex TextureD3D_Buffer::getImageIndex(GLint mip, GLint layer) const 4574 { 4575 return gl::ImageIndex::MakeBuffer(); 4576 } 4577 4578 bool TextureD3D_Buffer::isValidIndex(const gl::ImageIndex &index) const 4579 { 4580 return (mTexStorage && index.getType() == gl::TextureType::Buffer && 4581 index.getLevelIndex() == 0); 4582 } 4583 4584 void TextureD3D_Buffer::markAllImagesDirty() 4585 { 4586 UNREACHABLE(); 4587 } 4588 4589 angle::Result TextureD3D_Buffer::setEGLImageTarget(const gl::Context *context, 4590 gl::TextureType type, 4591 egl::Image *image) 4592 { 4593 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4594 return angle::Result::Continue; 4595 } 4596 4597 angle::Result TextureD3D_Buffer::getRenderTarget(const gl::Context *context, 4598 const gl::ImageIndex &index, 4599 GLsizei samples, 4600 RenderTargetD3D **outRT) 4601 { 4602 ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context)); 4603 return angle::Result::Continue; 4604 } 4605 4606 ImageD3D *TextureD3D_Buffer::getImage(const gl::ImageIndex &index) const 4607 { 4608 return nullptr; 4609 } 4610 4611 angle::Result TextureD3D_Buffer::setBuffer(const gl::Context *context, GLenum internalFormat) 4612 { 4613 ASSERT(mState.getType() == gl::TextureType::Buffer); 4614 TexStoragePointer storage; 4615 storage.reset(mRenderer->createTextureStorageBuffer(mState.getBuffer(), internalFormat, 4616 mState.getLabel())); 4617 ANGLE_TRY(setCompleteTexStorage(context, storage.get())); 4618 storage.release(); 4619 mInternalFormat = internalFormat; 4620 mImmutable = false; 4621 return angle::Result::Continue; 4622 } 4623 4624 angle::Result TextureD3D_Buffer::syncState(const gl::Context *context, 4625 const gl::Texture::DirtyBits &dirtyBits, 4626 gl::Command source) 4627 { 4628 ASSERT(mState.getType() == gl::TextureType::Buffer); 4629 if (dirtyBits.test(gl::Texture::DirtyBitType::DIRTY_BIT_IMPLEMENTATION) && 4630 mState.getBuffer().get() != nullptr) 4631 { 4632 // buffer data have been changed. Buffer data may out of sync 4633 // give up the old TexStorage, create a new one. 4634 // this may not efficient, since staging buffer may be patially updated. 4635 ANGLE_TRY(setBuffer(context, mInternalFormat)); 4636 } 4637 return angle::Result::Continue; 4638 } 4639 4640 } // namespace rx