 Chromium Code Reviews
 Chromium Code Reviews Issue 2455983005:
  Refactor AcceleratedStaticBitmapImage  (Closed)
    
  
    Issue 2455983005:
  Refactor AcceleratedStaticBitmapImage  (Closed) 
  | OLD | NEW | 
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "platform/graphics/AcceleratedStaticBitmapImage.h" | 5 #include "platform/graphics/AcceleratedStaticBitmapImage.h" | 
| 6 | 6 | 
| 7 #include "gpu/command_buffer/client/gles2_interface.h" | 7 #include "gpu/command_buffer/client/gles2_interface.h" | 
| 8 #include "gpu/command_buffer/common/sync_token.h" | 8 #include "gpu/command_buffer/common/sync_token.h" | 
| 9 #include "platform/CrossThreadFunctional.h" | 9 #include "platform/graphics/MailboxTextureHolder.h" | 
| 10 #include "platform/WebTaskRunner.h" | 10 #include "platform/graphics/SkiaTextureHolder.h" | 
| 11 #include "platform/graphics/StaticBitmapImage.h" | |
| 12 #include "platform/graphics/gpu/SharedGpuContext.h" | 11 #include "platform/graphics/gpu/SharedGpuContext.h" | 
| 13 #include "platform/graphics/skia/SkiaUtils.h" | 12 #include "platform/graphics/skia/SkiaUtils.h" | 
| 14 #include "public/platform/Platform.h" | 13 #include "public/platform/Platform.h" | 
| 15 #include "public/platform/WebGraphicsContext3DProvider.h" | 14 #include "public/platform/WebGraphicsContext3DProvider.h" | 
| 16 #include "skia/ext/texture_handle.h" | |
| 17 #include "third_party/skia/include/core/SkImage.h" | 15 #include "third_party/skia/include/core/SkImage.h" | 
| 18 #include "third_party/skia/include/gpu/GrContext.h" | |
| 19 #include "wtf/PtrUtil.h" | 16 #include "wtf/PtrUtil.h" | 
| 20 | 17 | 
| 21 #include <memory> | 18 #include <memory> | 
| 22 #include <utility> | 19 #include <utility> | 
| 23 | 20 | 
| 24 namespace blink { | 21 namespace blink { | 
| 25 | 22 | 
| 26 PassRefPtr<AcceleratedStaticBitmapImage> | 23 PassRefPtr<AcceleratedStaticBitmapImage> | 
| 27 AcceleratedStaticBitmapImage::createFromSharedContextImage( | 24 AcceleratedStaticBitmapImage::createFromSharedContextImage( | 
| 28 sk_sp<SkImage> image) { | 25 sk_sp<SkImage> image) { | 
| 29 return adoptRef(new AcceleratedStaticBitmapImage(std::move(image))); | 26 return adoptRef(new AcceleratedStaticBitmapImage(std::move(image))); | 
| 30 } | 27 } | 
| 31 | 28 | 
| 32 PassRefPtr<AcceleratedStaticBitmapImage> | 29 PassRefPtr<AcceleratedStaticBitmapImage> | 
| 33 AcceleratedStaticBitmapImage::createFromWebGLContextImage( | 30 AcceleratedStaticBitmapImage::createFromWebGLContextImage( | 
| 34 sk_sp<SkImage> image, | |
| 35 const gpu::Mailbox& mailbox, | 31 const gpu::Mailbox& mailbox, | 
| 36 const gpu::SyncToken& syncToken) { | 32 const gpu::SyncToken& syncToken, | 
| 37 return adoptRef( | 33 unsigned textureId, | 
| 38 new AcceleratedStaticBitmapImage(std::move(image), mailbox, syncToken)); | 34 WeakPtr<DrawingBuffer> drawingBuffer, | 
| 35 IntSize mailboxSize) { | |
| 36 return adoptRef(new AcceleratedStaticBitmapImage( | |
| 37 mailbox, syncToken, textureId, drawingBuffer, mailboxSize)); | |
| 39 } | 38 } | 
| 40 | 39 | 
| 41 AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(sk_sp<SkImage> image) | 40 AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage( | 
| 42 : StaticBitmapImage(std::move(image)), | 41 sk_sp<SkImage> image) { | 
| 43 m_sharedContextId(SharedGpuContext::contextId()) { | 42 m_textureHolder = wrapUnique(new SkiaTextureHolder(std::move(image))); | 
| 44 m_threadChecker.DetachFromThread(); | 43 m_threadChecker.DetachFromThread(); | 
| 45 } | 44 } | 
| 46 | 45 | 
| 47 AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage( | 46 AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage( | 
| 48 sk_sp<SkImage> image, | |
| 49 const gpu::Mailbox& mailbox, | 47 const gpu::Mailbox& mailbox, | 
| 50 const gpu::SyncToken& syncToken) | 48 const gpu::SyncToken& syncToken, | 
| 51 : StaticBitmapImage(std::move(image)), | 49 unsigned textureId, | 
| 52 m_sharedContextId(SharedGpuContext::kNoSharedContext), | 50 WeakPtr<DrawingBuffer> drawingBuffer, | 
| 53 m_hasMailbox(true), | 51 IntSize mailboxSize) { | 
| 54 m_mailbox(mailbox), | 52 m_textureHolder = wrapUnique(new MailboxTextureHolder( | 
| 55 m_syncToken(syncToken) { | 53 mailbox, syncToken, textureId, drawingBuffer, mailboxSize)); | 
| 56 m_threadChecker.DetachFromThread(); | 54 m_threadChecker.DetachFromThread(); | 
| 57 | |
| 58 // Note: In this case, m_image is not usable directly because it is not in the | |
| 59 // shared context. It is just used to hold a reference to the texture object | |
| 60 // in the origin context until the mailbox can be consumed. | |
| 61 } | 55 } | 
| 62 | 56 | 
| 63 AcceleratedStaticBitmapImage::~AcceleratedStaticBitmapImage() { | 57 AcceleratedStaticBitmapImage::~AcceleratedStaticBitmapImage() {} | 
| 64 // Avoid leaking mailboxes in cases where the texture gets recycled by skia. | 58 | 
| 65 if (m_hasMailbox && SharedGpuContext::isValid()) | 59 IntSize AcceleratedStaticBitmapImage::size() const { | 
| 66 SharedGpuContext::gl()->ProduceTextureDirectCHROMIUM(0, GL_TEXTURE_2D, | 60 return m_textureHolder->size(); | 
| 67 m_mailbox.name); | 61 } | 
| 68 releaseImageThreadSafe(); | 62 | 
| 63 void AcceleratedStaticBitmapImage::updateSyncToken(gpu::SyncToken syncToken) { | |
| 64 m_textureHolder->updateSyncToken(syncToken); | |
| 69 } | 65 } | 
| 70 | 66 | 
| 71 void AcceleratedStaticBitmapImage::copyToTexture( | 67 void AcceleratedStaticBitmapImage::copyToTexture( | 
| 72 WebGraphicsContext3DProvider* destProvider, | 68 WebGraphicsContext3DProvider* destProvider, | 
| 73 GLuint destTextureId, | 69 GLuint destTextureId, | 
| 74 GLenum internalFormat, | 70 GLenum internalFormat, | 
| 75 GLenum destType, | 71 GLenum destType, | 
| 76 bool flipY) { | 72 bool flipY) { | 
| 77 checkThread(); | 73 checkThread(); | 
| 78 if (!isValid()) | 74 if (!isValid()) | 
| 79 return; | 75 return; | 
| 80 // |destProvider| may not be the same context as the one used for |m_image|, | 76 // |destProvider| may not be the same context as the one used for |m_image|, | 
| 81 // so we use a mailbox to generate a texture id for |destProvider| to access. | 77 // so we use a mailbox to generate a texture id for |destProvider| to access. | 
| 82 ensureMailbox(); | 78 ensureMailbox(); | 
| 83 | 79 | 
| 84 // Get a texture id that |destProvider| knows about and copy from it. | 80 // Get a texture id that |destProvider| knows about and copy from it. | 
| 85 gpu::gles2::GLES2Interface* destGL = destProvider->contextGL(); | 81 gpu::gles2::GLES2Interface* destGL = destProvider->contextGL(); | 
| 86 destGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); | 82 destGL->WaitSyncTokenCHROMIUM(m_textureHolder->syncToken().GetData()); | 
| 87 GLuint sourceTextureId = | 83 GLuint sourceTextureId = destGL->CreateAndConsumeTextureCHROMIUM( | 
| 88 destGL->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, m_mailbox.name); | 84 GL_TEXTURE_2D, m_textureHolder->mailbox().name); | 
| 89 destGL->CopyTextureCHROMIUM(sourceTextureId, destTextureId, internalFormat, | 85 destGL->CopyTextureCHROMIUM(sourceTextureId, destTextureId, internalFormat, | 
| 90 destType, flipY, false, false); | 86 destType, flipY, false, false); | 
| 91 // This drops the |destGL| context's reference on our |m_mailbox|, but it's | 87 // This drops the |destGL| context's reference on our |m_mailbox|, but it's | 
| 92 // still held alive by our SkImage. | 88 // still held alive by our SkImage. | 
| 93 destGL->DeleteTextures(1, &sourceTextureId); | 89 destGL->DeleteTextures(1, &sourceTextureId); | 
| 94 } | 90 } | 
| 95 | 91 | 
| 96 sk_sp<SkImage> AcceleratedStaticBitmapImage::imageForCurrentFrame() { | 92 sk_sp<SkImage> AcceleratedStaticBitmapImage::imageForCurrentFrame() { | 
| 97 checkThread(); | 93 checkThread(); | 
| 98 if (!isValid()) | 94 if (!isValid()) | 
| 99 return nullptr; | 95 return nullptr; | 
| 100 createImageFromMailboxIfNeeded(); | 96 createImageFromMailboxIfNeeded(); | 
| 101 return m_image; | 97 return m_textureHolder->skImage(); | 
| 102 } | 98 } | 
| 103 | 99 | 
| 104 void AcceleratedStaticBitmapImage::draw( | 100 void AcceleratedStaticBitmapImage::draw(SkCanvas* canvas, | 
| 105 SkCanvas* canvas, | 101 const SkPaint& paint, | 
| 106 const SkPaint& paint, | 102 const FloatRect& dstRect, | 
| 107 const FloatRect& dstRect, | 103 const FloatRect& srcRect, | 
| 108 const FloatRect& srcRect, | 104 RespectImageOrientationEnum, | 
| 109 RespectImageOrientationEnum respectImageOrientation, | 105 ImageClampingMode imageClampingMode) { | 
| 110 ImageClampingMode imageClampingMode) { | |
| 111 checkThread(); | 106 checkThread(); | 
| 112 if (!isValid()) | 107 if (!isValid()) | 
| 113 return; | 108 return; | 
| 114 createImageFromMailboxIfNeeded(); | 109 createImageFromMailboxIfNeeded(); | 
| 115 StaticBitmapImage::draw(canvas, paint, dstRect, srcRect, | 110 sk_sp<SkImage> image = m_textureHolder->skImage(); | 
| 116 respectImageOrientation, imageClampingMode); | 111 StaticBitmapImage::drawHelper(canvas, paint, dstRect, srcRect, | 
| 112 imageClampingMode, image); | |
| 117 } | 113 } | 
| 118 | 114 | 
| 119 bool AcceleratedStaticBitmapImage::isValid() { | 115 bool AcceleratedStaticBitmapImage::isValid() { | 
| 120 if (!m_image) | 116 if (!m_textureHolder) | 
| 121 return false; | 117 return false; | 
| 122 if (!SharedGpuContext::isValid()) | 118 if (!SharedGpuContext::isValid()) | 
| 123 return false; // Gpu context was lost | 119 return false; // Gpu context was lost | 
| 124 if (imageBelongsToSharedContext() && | 120 unsigned sharedContextId = m_textureHolder->sharedContextId(); | 
| 125 m_sharedContextId != SharedGpuContext::contextId()) { | 121 if (sharedContextId != SharedGpuContext::kNoSharedContext && | 
| 122 sharedContextId != SharedGpuContext::contextId()) { | |
| 126 // Gpu context was lost and restored since the resource was created. | 123 // Gpu context was lost and restored since the resource was created. | 
| 127 return false; | 124 return false; | 
| 128 } | 125 } | 
| 129 return true; | 126 return true; | 
| 130 } | 127 } | 
| 131 | 128 | 
| 132 bool AcceleratedStaticBitmapImage::imageBelongsToSharedContext() { | |
| 133 return m_sharedContextId != SharedGpuContext::kNoSharedContext; | |
| 134 } | |
| 135 | |
| 136 void AcceleratedStaticBitmapImage::createImageFromMailboxIfNeeded() { | 129 void AcceleratedStaticBitmapImage::createImageFromMailboxIfNeeded() { | 
| 137 if (imageBelongsToSharedContext()) | 130 if (m_textureHolder->sharedContextId() != SharedGpuContext::kNoSharedContext) | 
| 138 return; | 131 return; | 
| 139 DCHECK(m_hasMailbox); | 132 if (m_textureHolder->isSkiaTextureHolder()) | 
| 140 gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); | 133 return; | 
| 141 GrContext* sharedGrContext = SharedGpuContext::gr(); | 134 m_textureHolder = | 
| 142 DCHECK(sharedGL && | 135 wrapUnique(new SkiaTextureHolder(std::move(m_textureHolder))); | 
| 143 sharedGrContext); // context isValid already checked in callers | |
| 144 | |
| 145 sharedGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); | |
| 146 GLuint sharedContextTextureId = | |
| 147 sharedGL->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, m_mailbox.name); | |
| 148 GrGLTextureInfo textureInfo; | |
| 149 textureInfo.fTarget = GL_TEXTURE_2D; | |
| 150 textureInfo.fID = sharedContextTextureId; | |
| 151 GrBackendTextureDesc backendTexture; | |
| 152 backendTexture.fOrigin = kBottomLeft_GrSurfaceOrigin; | |
| 153 backendTexture.fWidth = size().width(); | |
| 154 backendTexture.fHeight = size().height(); | |
| 155 backendTexture.fConfig = kSkia8888_GrPixelConfig; | |
| 156 backendTexture.fTextureHandle = | |
| 157 skia::GrGLTextureInfoToGrBackendObject(textureInfo); | |
| 158 | |
| 159 sk_sp<SkImage> newImage = | |
| 160 SkImage::MakeFromAdoptedTexture(sharedGrContext, backendTexture); | |
| 161 releaseImageThreadSafe(); | |
| 162 m_image = newImage; | |
| 163 | |
| 164 m_sharedContextId = SharedGpuContext::contextId(); | |
| 165 } | 136 } | 
| 166 | 137 | 
| 167 void AcceleratedStaticBitmapImage::ensureMailbox() { | 138 void AcceleratedStaticBitmapImage::ensureMailbox() { | 
| 168 if (m_hasMailbox) | 139 if (m_textureHolder->isMailboxTextureHolder()) | 
| 169 return; | 140 return; | 
| 170 | 141 | 
| 171 DCHECK(m_image); | 142 m_textureHolder = | 
| 172 | 143 wrapUnique(new MailboxTextureHolder(std::move(m_textureHolder))); | 
| 173 gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); | |
| 174 GrContext* sharedGrContext = SharedGpuContext::gr(); | |
| 175 if (!sharedGrContext) { | |
| 176 // Can happen if the context is lost. The SkImage won't be any good now | |
| 177 // anyway. | |
| 178 return; | |
| 179 } | |
| 180 GLuint imageTextureId = | |
| 181 skia::GrBackendObjectToGrGLTextureInfo(m_image->getTextureHandle(true)) | |
| 182 ->fID; | |
| 183 sharedGL->BindTexture(GL_TEXTURE_2D, imageTextureId); | |
| 184 | |
| 185 sharedGL->GenMailboxCHROMIUM(m_mailbox.name); | |
| 186 sharedGL->ProduceTextureCHROMIUM(GL_TEXTURE_2D, m_mailbox.name); | |
| 187 const GLuint64 fenceSync = sharedGL->InsertFenceSyncCHROMIUM(); | |
| 188 sharedGL->Flush(); | |
| 189 sharedGL->GenSyncTokenCHROMIUM(fenceSync, m_syncToken.GetData()); | |
| 190 | |
| 191 sharedGL->BindTexture(GL_TEXTURE_2D, 0); | |
| 192 // We changed bound textures in this function, so reset the GrContext. | |
| 193 sharedGrContext->resetContext(kTextureBinding_GrGLBackendState); | |
| 194 | |
| 195 m_hasMailbox = true; | |
| 196 } | 144 } | 
| 197 | 145 | 
| 198 void AcceleratedStaticBitmapImage::transfer() { | 146 void AcceleratedStaticBitmapImage::transfer() { | 
| 199 checkThread(); | 147 checkThread(); | 
| 200 ensureMailbox(); | 148 ensureMailbox(); | 
| 201 m_sharedContextId = SharedGpuContext::kNoSharedContext; | 149 m_textureHolder->deleteTexture(); | 
| 
xidachen
2016/11/04 17:23:06
junov@: Please take a look at this change here. I
 | |
| 202 // If |m_imageThread| is set, it means that the image has been consumed on the | 150 // If |m_imageThreadTaskRunner| in SkiaTextureHolder is set, it means that | 
| 203 // current thread, which may happen when we have chained transfers. When that | 151 // the |m_image| in that class has been consumed on the current thread, which | 
| 204 // is the case, we must not reset |m_imageThread|, so we ensure that | 152 // may happen when we have chained transfers. When that is the case, we must | 
| 205 // releaseImage() is called on the right thread. | 153 // not reset |m_imageThreadTaskRunner|, so we ensure that releaseImage() is | 
| 206 if (!m_imageThread) | 154 // called on the right thread. | 
| 207 m_imageThread = Platform::current()->currentThread(); | 155 if (!m_textureHolder->imageThread()) { | 
| 156 WebThread* currentThread = Platform::current()->currentThread(); | |
| 157 m_textureHolder->setImageThread(currentThread); | |
| 158 m_textureHolder->setImageThreadTaskRunner( | |
| 159 currentThread->getWebTaskRunner()->clone()); | |
| 160 } | |
| 208 m_detachThreadAtNextCheck = true; | 161 m_detachThreadAtNextCheck = true; | 
| 209 } | 162 } | 
| 210 | 163 | 
| 164 bool AcceleratedStaticBitmapImage::currentFrameKnownToBeOpaque( | |
| 165 MetadataMode metadataMode) { | |
| 166 return m_textureHolder->currentFrameKnownToBeOpaque(metadataMode); | |
| 167 } | |
| 168 | |
| 211 void AcceleratedStaticBitmapImage::checkThread() { | 169 void AcceleratedStaticBitmapImage::checkThread() { | 
| 212 if (m_detachThreadAtNextCheck) { | 170 if (m_detachThreadAtNextCheck) { | 
| 213 m_threadChecker.DetachFromThread(); | 171 m_threadChecker.DetachFromThread(); | 
| 214 m_detachThreadAtNextCheck = false; | 172 m_detachThreadAtNextCheck = false; | 
| 215 } | 173 } | 
| 216 CHECK(m_threadChecker.CalledOnValidThread()); | 174 CHECK(m_threadChecker.CalledOnValidThread()); | 
| 217 } | 175 } | 
| 218 | 176 | 
| 219 void releaseImage(sk_sp<SkImage>&& image, | |
| 220 std::unique_ptr<gpu::SyncToken>&& syncToken) { | |
| 221 if (SharedGpuContext::isValid() && syncToken->HasData()) | |
| 222 SharedGpuContext::gl()->WaitSyncTokenCHROMIUM(syncToken->GetData()); | |
| 223 image.reset(); | |
| 224 } | |
| 225 | |
| 226 void AcceleratedStaticBitmapImage::releaseImageThreadSafe() { | |
| 227 // If m_image belongs to a GrContext that is on another thread, it | |
| 228 // must be released on that thread. | |
| 229 if (m_imageThread && m_image && | |
| 230 m_imageThread != Platform::current()->currentThread() && | |
| 231 SharedGpuContext::isValid()) { | |
| 232 gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); | |
| 233 std::unique_ptr<gpu::SyncToken> releaseSyncToken(new gpu::SyncToken); | |
| 234 const GLuint64 fenceSync = sharedGL->InsertFenceSyncCHROMIUM(); | |
| 235 sharedGL->Flush(); | |
| 236 sharedGL->GenSyncTokenCHROMIUM(fenceSync, releaseSyncToken->GetData()); | |
| 237 m_imageThread->getWebTaskRunner()->postTask( | |
| 238 BLINK_FROM_HERE, | |
| 239 crossThreadBind(&releaseImage, passed(std::move(m_image)), | |
| 240 passed(std::move(releaseSyncToken)))); | |
| 241 } | |
| 242 m_image = nullptr; | |
| 243 m_imageThread = nullptr; | |
| 244 } | |
| 245 | |
| 246 } // namespace blink | 177 } // namespace blink | 
| OLD | NEW |