Image.cpp (15869B)
1 // 2 // Copyright 2015 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 // Image.cpp: Implements the egl::Image class representing the EGLimage object. 8 9 #include "libANGLE/Image.h" 10 11 #include "common/debug.h" 12 #include "common/utilities.h" 13 #include "libANGLE/Context.h" 14 #include "libANGLE/Renderbuffer.h" 15 #include "libANGLE/Texture.h" 16 #include "libANGLE/angletypes.h" 17 #include "libANGLE/formatutils.h" 18 #include "libANGLE/renderer/EGLImplFactory.h" 19 #include "libANGLE/renderer/ImageImpl.h" 20 21 namespace egl 22 { 23 24 namespace 25 { 26 gl::ImageIndex GetImageIndex(EGLenum eglTarget, const egl::AttributeMap &attribs) 27 { 28 if (!IsTextureTarget(eglTarget)) 29 { 30 return gl::ImageIndex(); 31 } 32 33 gl::TextureTarget target = egl_gl::EGLImageTargetToTextureTarget(eglTarget); 34 GLint mip = static_cast<GLint>(attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0)); 35 GLint layer = static_cast<GLint>(attribs.get(EGL_GL_TEXTURE_ZOFFSET_KHR, 0)); 36 37 if (target == gl::TextureTarget::_3D) 38 { 39 return gl::ImageIndex::Make3D(mip, layer); 40 } 41 else 42 { 43 ASSERT(layer == 0); 44 return gl::ImageIndex::MakeFromTarget(target, mip, 1); 45 } 46 } 47 48 const Display *DisplayFromContext(const gl::Context *context) 49 { 50 return (context ? context->getDisplay() : nullptr); 51 } 52 53 angle::SubjectIndex kExternalImageImplSubjectIndex = 0; 54 } // anonymous namespace 55 56 ImageSibling::ImageSibling() : FramebufferAttachmentObject(), mSourcesOf(), mTargetOf() {} 57 58 ImageSibling::~ImageSibling() 59 { 60 // EGL images should hold a ref to their targets and siblings, a Texture should not be deletable 61 // while it is attached to an EGL image. 62 // Child class should orphan images before destruction. 63 ASSERT(mSourcesOf.empty()); 64 ASSERT(mTargetOf.get() == nullptr); 65 } 66 67 void ImageSibling::setTargetImage(const gl::Context *context, egl::Image *imageTarget) 68 { 69 ASSERT(imageTarget != nullptr); 70 mTargetOf.set(DisplayFromContext(context), imageTarget); 71 imageTarget->addTargetSibling(this); 72 } 73 74 angle::Result ImageSibling::orphanImages(const gl::Context *context, 75 RefCountObjectReleaser<Image> *outReleaseImage) 76 { 77 ASSERT(outReleaseImage != nullptr); 78 79 if (mTargetOf.get() != nullptr) 80 { 81 // Can't be a target and have sources. 82 ASSERT(mSourcesOf.empty()); 83 84 ANGLE_TRY(mTargetOf->orphanSibling(context, this)); 85 *outReleaseImage = mTargetOf.set(DisplayFromContext(context), nullptr); 86 } 87 else 88 { 89 for (Image *sourceImage : mSourcesOf) 90 { 91 ANGLE_TRY(sourceImage->orphanSibling(context, this)); 92 } 93 mSourcesOf.clear(); 94 } 95 96 return angle::Result::Continue; 97 } 98 99 void ImageSibling::addImageSource(egl::Image *imageSource) 100 { 101 ASSERT(imageSource != nullptr); 102 mSourcesOf.insert(imageSource); 103 } 104 105 void ImageSibling::removeImageSource(egl::Image *imageSource) 106 { 107 ASSERT(mSourcesOf.find(imageSource) != mSourcesOf.end()); 108 mSourcesOf.erase(imageSource); 109 } 110 111 bool ImageSibling::isEGLImageTarget() const 112 { 113 return (mTargetOf.get() != nullptr); 114 } 115 116 gl::InitState ImageSibling::sourceEGLImageInitState() const 117 { 118 ASSERT(isEGLImageTarget()); 119 return mTargetOf->sourceInitState(); 120 } 121 122 void ImageSibling::setSourceEGLImageInitState(gl::InitState initState) const 123 { 124 ASSERT(isEGLImageTarget()); 125 mTargetOf->setInitState(initState); 126 } 127 128 bool ImageSibling::isRenderable(const gl::Context *context, 129 GLenum binding, 130 const gl::ImageIndex &imageIndex) const 131 { 132 ASSERT(isEGLImageTarget()); 133 return mTargetOf->isRenderable(context); 134 } 135 136 bool ImageSibling::isYUV() const 137 { 138 return mTargetOf.get() && mTargetOf->isYUV(); 139 } 140 141 bool ImageSibling::isCreatedWithAHB() const 142 { 143 return mTargetOf.get() && mTargetOf->isCreatedWithAHB(); 144 } 145 146 bool ImageSibling::hasProtectedContent() const 147 { 148 return mTargetOf.get() && mTargetOf->hasProtectedContent(); 149 } 150 151 void ImageSibling::notifySiblings(angle::SubjectMessage message) 152 { 153 if (mTargetOf.get()) 154 { 155 mTargetOf->notifySiblings(this, message); 156 } 157 for (Image *source : mSourcesOf) 158 { 159 source->notifySiblings(this, message); 160 } 161 } 162 163 ExternalImageSibling::ExternalImageSibling(rx::EGLImplFactory *factory, 164 const gl::Context *context, 165 EGLenum target, 166 EGLClientBuffer buffer, 167 const AttributeMap &attribs) 168 : mImplementation(factory->createExternalImageSibling(context, target, buffer, attribs)), 169 mImplObserverBinding(this, kExternalImageImplSubjectIndex) 170 { 171 mImplObserverBinding.bind(mImplementation.get()); 172 } 173 174 ExternalImageSibling::~ExternalImageSibling() = default; 175 176 void ExternalImageSibling::onDestroy(const egl::Display *display) 177 { 178 mImplementation->onDestroy(display); 179 } 180 181 Error ExternalImageSibling::initialize(const egl::Display *display) 182 { 183 return mImplementation->initialize(display); 184 } 185 186 gl::Extents ExternalImageSibling::getAttachmentSize(const gl::ImageIndex &imageIndex) const 187 { 188 return mImplementation->getSize(); 189 } 190 191 gl::Format ExternalImageSibling::getAttachmentFormat(GLenum binding, 192 const gl::ImageIndex &imageIndex) const 193 { 194 return mImplementation->getFormat(); 195 } 196 197 GLsizei ExternalImageSibling::getAttachmentSamples(const gl::ImageIndex &imageIndex) const 198 { 199 return static_cast<GLsizei>(mImplementation->getSamples()); 200 } 201 202 GLuint ExternalImageSibling::getLevelCount() const 203 { 204 return static_cast<GLuint>(mImplementation->getLevelCount()); 205 } 206 207 bool ExternalImageSibling::isRenderable(const gl::Context *context, 208 GLenum binding, 209 const gl::ImageIndex &imageIndex) const 210 { 211 return mImplementation->isRenderable(context); 212 } 213 214 bool ExternalImageSibling::isTextureable(const gl::Context *context) const 215 { 216 return mImplementation->isTexturable(context); 217 } 218 219 bool ExternalImageSibling::isYUV() const 220 { 221 return mImplementation->isYUV(); 222 } 223 224 bool ExternalImageSibling::isCubeMap() const 225 { 226 return mImplementation->isCubeMap(); 227 } 228 229 bool ExternalImageSibling::hasProtectedContent() const 230 { 231 return mImplementation->hasProtectedContent(); 232 } 233 234 void ExternalImageSibling::onAttach(const gl::Context *context, rx::Serial framebufferSerial) {} 235 236 void ExternalImageSibling::onDetach(const gl::Context *context, rx::Serial framebufferSerial) {} 237 238 GLuint ExternalImageSibling::getId() const 239 { 240 UNREACHABLE(); 241 return 0; 242 } 243 244 gl::InitState ExternalImageSibling::initState(GLenum binding, 245 const gl::ImageIndex &imageIndex) const 246 { 247 return gl::InitState::Initialized; 248 } 249 250 void ExternalImageSibling::setInitState(GLenum binding, 251 const gl::ImageIndex &imageIndex, 252 gl::InitState initState) 253 {} 254 255 rx::ExternalImageSiblingImpl *ExternalImageSibling::getImplementation() const 256 { 257 return mImplementation.get(); 258 } 259 260 void ExternalImageSibling::onSubjectStateChange(angle::SubjectIndex index, 261 angle::SubjectMessage message) 262 { 263 onStateChange(message); 264 } 265 266 rx::FramebufferAttachmentObjectImpl *ExternalImageSibling::getAttachmentImpl() const 267 { 268 return mImplementation.get(); 269 } 270 271 ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs) 272 : label(nullptr), 273 target(target), 274 imageIndex(GetImageIndex(target, attribs)), 275 source(buffer), 276 format(GL_NONE), 277 yuv(false), 278 cubeMap(false), 279 size(), 280 samples(), 281 levelCount(1), 282 sourceType(target), 283 colorspace( 284 static_cast<EGLenum>(attribs.get(EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_DEFAULT_EXT))), 285 hasProtectedContent(static_cast<bool>(attribs.get(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE))) 286 {} 287 288 ImageState::~ImageState() {} 289 290 Image::Image(rx::EGLImplFactory *factory, 291 const gl::Context *context, 292 EGLenum target, 293 ImageSibling *buffer, 294 const AttributeMap &attribs) 295 : mState(target, buffer, attribs), 296 mImplementation(factory->createImage(mState, context, target, attribs)), 297 mOrphanedAndNeedsInit(false) 298 { 299 ASSERT(mImplementation != nullptr); 300 ASSERT(buffer != nullptr); 301 302 mState.source->addImageSource(this); 303 } 304 305 void Image::onDestroy(const Display *display) 306 { 307 // All targets should hold a ref to the egl image and it should not be deleted until there are 308 // no siblings left. 309 ASSERT([&] { 310 std::unique_lock lock(mState.targetsLock); 311 return mState.targets.empty(); 312 }()); 313 314 // Make sure the implementation gets a chance to clean up before we delete the source. 315 mImplementation->onDestroy(display); 316 317 // Tell the source that it is no longer used by this image 318 if (mState.source != nullptr) 319 { 320 mState.source->removeImageSource(this); 321 322 // If the source is an external object, delete it 323 if (IsExternalImageTarget(mState.sourceType)) 324 { 325 ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source); 326 externalSibling->onDestroy(display); 327 delete externalSibling; 328 } 329 330 mState.source = nullptr; 331 } 332 } 333 334 Image::~Image() 335 { 336 SafeDelete(mImplementation); 337 } 338 339 void Image::setLabel(EGLLabelKHR label) 340 { 341 mState.label = label; 342 } 343 344 EGLLabelKHR Image::getLabel() const 345 { 346 return mState.label; 347 } 348 349 void Image::addTargetSibling(ImageSibling *sibling) 350 { 351 std::unique_lock lock(mState.targetsLock); 352 mState.targets.insert(sibling); 353 } 354 355 angle::Result Image::orphanSibling(const gl::Context *context, ImageSibling *sibling) 356 { 357 ASSERT(sibling != nullptr); 358 359 // notify impl 360 ANGLE_TRY(mImplementation->orphan(context, sibling)); 361 362 if (mState.source == sibling) 363 { 364 // The external source of an image cannot be redefined so it cannot be orphaned. 365 ASSERT(!IsExternalImageTarget(mState.sourceType)); 366 367 // If the sibling is the source, it cannot be a target. 368 ASSERT([&] { 369 std::unique_lock lock(mState.targetsLock); 370 return mState.targets.find(sibling) == mState.targets.end(); 371 }()); 372 mState.source = nullptr; 373 mOrphanedAndNeedsInit = 374 (sibling->initState(GL_NONE, mState.imageIndex) == gl::InitState::MayNeedInit); 375 } 376 else 377 { 378 std::unique_lock lock(mState.targetsLock); 379 mState.targets.erase(sibling); 380 } 381 382 return angle::Result::Continue; 383 } 384 385 const gl::Format &Image::getFormat() const 386 { 387 return mState.format; 388 } 389 390 bool Image::isRenderable(const gl::Context *context) const 391 { 392 if (IsTextureTarget(mState.sourceType)) 393 { 394 return mState.format.info->textureAttachmentSupport(context->getClientVersion(), 395 context->getExtensions()); 396 } 397 else if (IsRenderbufferTarget(mState.sourceType)) 398 { 399 return mState.format.info->renderbufferSupport(context->getClientVersion(), 400 context->getExtensions()); 401 } 402 else if (IsExternalImageTarget(mState.sourceType)) 403 { 404 ASSERT(mState.source != nullptr); 405 return mState.source->isRenderable(context, GL_NONE, gl::ImageIndex()); 406 } 407 408 UNREACHABLE(); 409 return false; 410 } 411 412 bool Image::isTexturable(const gl::Context *context) const 413 { 414 if (IsTextureTarget(mState.sourceType)) 415 { 416 return mState.format.info->textureSupport(context->getClientVersion(), 417 context->getExtensions()); 418 } 419 else if (IsRenderbufferTarget(mState.sourceType)) 420 { 421 return true; 422 } 423 else if (IsExternalImageTarget(mState.sourceType)) 424 { 425 ASSERT(mState.source != nullptr); 426 return rx::GetAs<ExternalImageSibling>(mState.source)->isTextureable(context); 427 } 428 429 UNREACHABLE(); 430 return false; 431 } 432 433 bool Image::isYUV() const 434 { 435 return mState.yuv; 436 } 437 438 bool Image::isCreatedWithAHB() const 439 { 440 return mState.target == EGL_NATIVE_BUFFER_ANDROID; 441 } 442 443 bool Image::isCubeMap() const 444 { 445 return mState.cubeMap; 446 } 447 448 size_t Image::getWidth() const 449 { 450 return mState.size.width; 451 } 452 453 size_t Image::getHeight() const 454 { 455 return mState.size.height; 456 } 457 458 const gl::Extents &Image::getExtents() const 459 { 460 return mState.size; 461 } 462 463 bool Image::isLayered() const 464 { 465 return mState.imageIndex.isLayered(); 466 } 467 468 size_t Image::getSamples() const 469 { 470 return mState.samples; 471 } 472 473 GLuint Image::getLevelCount() const 474 { 475 return mState.levelCount; 476 } 477 478 bool Image::hasProtectedContent() const 479 { 480 return mState.hasProtectedContent; 481 } 482 483 rx::ImageImpl *Image::getImplementation() const 484 { 485 return mImplementation; 486 } 487 488 Error Image::initialize(const Display *display) 489 { 490 if (IsExternalImageTarget(mState.sourceType)) 491 { 492 ExternalImageSibling *externalSibling = rx::GetAs<ExternalImageSibling>(mState.source); 493 ANGLE_TRY(externalSibling->initialize(display)); 494 495 mState.hasProtectedContent = externalSibling->hasProtectedContent(); 496 mState.levelCount = externalSibling->getLevelCount(); 497 mState.cubeMap = externalSibling->isCubeMap(); 498 499 // External siblings can be YUV 500 mState.yuv = externalSibling->isYUV(); 501 } 502 503 mState.format = mState.source->getAttachmentFormat(GL_NONE, mState.imageIndex); 504 505 if (mState.colorspace != EGL_GL_COLORSPACE_DEFAULT_EXT) 506 { 507 GLenum nonLinearFormat = mState.format.info->sizedInternalFormat; 508 if (!gl::ColorspaceFormatOverride(mState.colorspace, &nonLinearFormat)) 509 { 510 // the colorspace format is not supported 511 return egl::EglBadMatch(); 512 } 513 mState.format = gl::Format(nonLinearFormat); 514 } 515 516 if (!IsExternalImageTarget(mState.sourceType)) 517 { 518 // Account for the fact that GL_ANGLE_yuv_internal_format extension maybe enabled, 519 // in which case the internal format itself could be YUV. 520 mState.yuv = gl::IsYuvFormat(mState.format.info->sizedInternalFormat); 521 } 522 523 mState.size = mState.source->getAttachmentSize(mState.imageIndex); 524 mState.samples = mState.source->getAttachmentSamples(mState.imageIndex); 525 526 if (IsTextureTarget(mState.sourceType)) 527 { 528 mState.size.depth = 1; 529 } 530 531 return mImplementation->initialize(display); 532 } 533 534 bool Image::orphaned() const 535 { 536 return (mState.source == nullptr); 537 } 538 539 gl::InitState Image::sourceInitState() const 540 { 541 if (orphaned()) 542 { 543 return mOrphanedAndNeedsInit ? gl::InitState::MayNeedInit : gl::InitState::Initialized; 544 } 545 546 return mState.source->initState(GL_NONE, mState.imageIndex); 547 } 548 549 void Image::setInitState(gl::InitState initState) 550 { 551 if (orphaned()) 552 { 553 mOrphanedAndNeedsInit = false; 554 } 555 556 return mState.source->setInitState(GL_NONE, mState.imageIndex, initState); 557 } 558 559 Error Image::exportVkImage(void *vkImage, void *vkImageCreateInfo) 560 { 561 return mImplementation->exportVkImage(vkImage, vkImageCreateInfo); 562 } 563 564 void Image::notifySiblings(const ImageSibling *notifier, angle::SubjectMessage message) 565 { 566 if (mState.source && mState.source != notifier) 567 { 568 mState.source->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message); 569 } 570 571 std::unique_lock lock(mState.targetsLock); 572 for (ImageSibling *target : mState.targets) 573 { 574 if (target != notifier) 575 { 576 target->onSubjectStateChange(rx::kTextureImageSiblingMessageIndex, message); 577 } 578 } 579 } 580 581 } // namespace egl