Chromium Code Reviews| 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/StaticBitmapImage.h" | 10 #include "platform/graphics/StaticBitmapImage.h" |
| 11 #include "platform/graphics/gpu/SharedGpuContext.h" | |
| 10 #include "platform/graphics/skia/SkiaUtils.h" | 12 #include "platform/graphics/skia/SkiaUtils.h" |
| 11 #include "public/platform/Platform.h" | 13 #include "public/platform/Platform.h" |
| 12 #include "public/platform/WebGraphicsContext3DProvider.h" | 14 #include "public/platform/WebGraphicsContext3DProvider.h" |
| 15 #include "public/platform/WebTaskRunner.h" | |
| 13 #include "skia/ext/texture_handle.h" | 16 #include "skia/ext/texture_handle.h" |
| 14 #include "third_party/skia/include/core/SkImage.h" | 17 #include "third_party/skia/include/core/SkImage.h" |
| 15 #include "third_party/skia/include/gpu/GrContext.h" | 18 #include "third_party/skia/include/gpu/GrContext.h" |
| 16 #include "wtf/PtrUtil.h" | 19 #include "wtf/PtrUtil.h" |
| 17 | 20 |
| 18 #include <memory> | 21 #include <memory> |
| 19 #include <utility> | 22 #include <utility> |
| 20 | 23 |
| 21 namespace blink { | 24 namespace blink { |
| 22 | 25 |
| 23 PassRefPtr<AcceleratedStaticBitmapImage> AcceleratedStaticBitmapImage::create(Pa ssRefPtr<SkImage> image) | 26 PassRefPtr<AcceleratedStaticBitmapImage> AcceleratedStaticBitmapImage::create(Pa ssRefPtr<SkImage> image) |
| 24 { | 27 { |
| 25 return adoptRef(new AcceleratedStaticBitmapImage(image)); | 28 return adoptRef(new AcceleratedStaticBitmapImage(image)); |
| 26 } | 29 } |
| 27 | 30 |
| 28 PassRefPtr<AcceleratedStaticBitmapImage> AcceleratedStaticBitmapImage::create(Pa ssRefPtr<SkImage> image, sk_sp<GrContext> grContext, const gpu::Mailbox& mailbox , const gpu::SyncToken& syncToken) | 31 PassRefPtr<AcceleratedStaticBitmapImage> AcceleratedStaticBitmapImage::create(Pa ssRefPtr<SkImage> image, GrContext* grContext, const gpu::Mailbox& mailbox, cons t gpu::SyncToken& syncToken) |
| 29 { | 32 { |
| 30 return adoptRef(new AcceleratedStaticBitmapImage(image, std::move(grContext) , mailbox, syncToken)); | 33 return adoptRef(new AcceleratedStaticBitmapImage(image, std::move(grContext) , mailbox, syncToken)); |
|
Stephen White
2016/09/01 15:43:53
Note: now calling std::move() on a bare ptr.
| |
| 31 } | 34 } |
| 32 | 35 |
| 33 AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(PassRefPtr<SkImage> i mage) | 36 AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(PassRefPtr<SkImage> i mage) |
| 34 : StaticBitmapImage(std::move(image)) | 37 : StaticBitmapImage(std::move(image)) |
| 35 , m_imageIsForSharedMainThreadContext(true) | 38 , m_sharedContextId(SharedGpuContext::contextId()) |
| 36 { | 39 { |
| 40 m_threadChecker.DetachFromThread(); | |
| 37 } | 41 } |
| 38 | 42 |
| 39 AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(PassRefPtr<SkImage> i mage, sk_sp<GrContext> grContext, const gpu::Mailbox& mailbox, const gpu::SyncTo ken& syncToken) | 43 AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(PassRefPtr<SkImage> i mage, GrContext* grContext, const gpu::Mailbox& mailbox, const gpu::SyncToken& s yncToken) |
| 40 : StaticBitmapImage(std::move(image)) | 44 : StaticBitmapImage(std::move(image)) |
| 41 , m_imageIsForSharedMainThreadContext(false) // TODO(danakj): Could be true though, caller would know. | 45 , m_sharedContextId(SharedGpuContext::kNoSharedContext) |
| 42 , m_grContext(std::move(grContext)) | |
| 43 , m_hasMailbox(true) | 46 , m_hasMailbox(true) |
| 44 , m_mailbox(mailbox) | 47 , m_mailbox(mailbox) |
| 45 , m_syncToken(syncToken) | 48 , m_syncToken(syncToken) |
| 46 { | 49 { |
| 47 DCHECK(m_grContext); | 50 DCHECK(grContext); |
| 51 m_threadChecker.DetachFromThread(); | |
| 52 GrContext* sharedGr = SharedGpuContext::gr(); | |
| 53 if (!grContext || grContext == sharedGr) { | |
|
Stephen White
2016/09/01 15:43:53
As discussed, use this create() method only for ou
| |
| 54 m_sharedContextId = SharedGpuContext::contextId(); | |
| 55 } | |
| 48 } | 56 } |
| 49 | 57 |
| 50 AcceleratedStaticBitmapImage::~AcceleratedStaticBitmapImage() = default; | 58 AcceleratedStaticBitmapImage::~AcceleratedStaticBitmapImage() |
| 59 { | |
| 60 // Avoid leaking mailboxes in cases where the texture gets recycled by skia. | |
| 61 if (m_hasMailbox && SharedGpuContext::isValid()) | |
| 62 SharedGpuContext::gl()->ProduceTextureDirectCHROMIUM(0, GL_TEXTURE_2D, m _mailbox.name); | |
| 63 releaseImageThreadSafe(); | |
| 64 } | |
| 51 | 65 |
| 52 void AcceleratedStaticBitmapImage::copyToTexture(WebGraphicsContext3DProvider* d estProvider, GLuint destTextureId, GLenum internalFormat, GLenum destType, bool flipY) | 66 void AcceleratedStaticBitmapImage::copyToTexture(WebGraphicsContext3DProvider* d estProvider, GLuint destTextureId, GLenum internalFormat, GLenum destType, bool flipY) |
| 53 { | 67 { |
| 68 checkThread(); | |
| 69 if (!isValid()) | |
| 70 return; | |
| 54 // |destProvider| may not be the same context as the one used for |m_image| so we use a mailbox to | 71 // |destProvider| may not be the same context as the one used for |m_image| so we use a mailbox to |
| 55 // generate a texture id for |destProvider| to access. | 72 // generate a texture id for |destProvider| to access. |
| 56 ensureMailbox(); | 73 ensureMailbox(); |
| 57 | 74 |
| 58 // Get a texture id that |destProvider| knows about and copy from it. | 75 // Get a texture id that |destProvider| knows about and copy from it. |
| 59 gpu::gles2::GLES2Interface* destGL = destProvider->contextGL(); | 76 gpu::gles2::GLES2Interface* destGL = destProvider->contextGL(); |
| 60 destGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); | 77 destGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); |
| 61 GLuint sourceTextureId = destGL->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_ 2D, m_mailbox.name); | 78 GLuint sourceTextureId = destGL->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_ 2D, m_mailbox.name); |
| 62 destGL->CopyTextureCHROMIUM(sourceTextureId, destTextureId, internalFormat, destType, flipY, false, false); | 79 destGL->CopyTextureCHROMIUM(sourceTextureId, destTextureId, internalFormat, destType, flipY, false, false); |
| 63 // This drops the |destGL| context's reference on our |m_mailbox|, but it's still held alive by our SkImage. | 80 // This drops the |destGL| context's reference on our |m_mailbox|, but it's still held alive by our SkImage. |
| 64 destGL->DeleteTextures(1, &sourceTextureId); | 81 destGL->DeleteTextures(1, &sourceTextureId); |
| 65 } | 82 } |
| 66 | 83 |
| 67 PassRefPtr<SkImage> AcceleratedStaticBitmapImage::imageForCurrentFrame() | 84 PassRefPtr<SkImage> AcceleratedStaticBitmapImage::imageForCurrentFrame() |
| 68 { | 85 { |
| 69 // This must return an SkImage that can be used with the shared main thread context. If |m_image| satisfies that, we are done. | 86 checkThread(); |
| 70 if (m_imageIsForSharedMainThreadContext) | 87 if (!isValid()) |
| 71 return m_image; | 88 return nullptr; |
| 89 createImageFromMailboxIfNeeded(); | |
| 90 return m_image; | |
| 91 } | |
| 72 | 92 |
| 73 // TODO(xidachen): make this work on a worker thread. | 93 void AcceleratedStaticBitmapImage::draw(SkCanvas* canvas, const SkPaint& paint, const FloatRect& dstRect, const FloatRect& srcRect, RespectImageOrientationEnum respectImageOrientation, ImageClampingMode imageClampingMode) |
| 74 DCHECK(isMainThread()); | 94 { |
| 95 checkThread(); | |
| 96 if (!isValid()) | |
| 97 return; | |
| 98 createImageFromMailboxIfNeeded(); | |
| 99 StaticBitmapImage::draw(canvas, paint, dstRect, srcRect, respectImageOrienta tion, imageClampingMode); | |
| 100 } | |
| 75 | 101 |
| 76 // If the SkImage came from any other context than the shared main thread on e, we expect to be given a mailbox at construction. We | 102 bool AcceleratedStaticBitmapImage::isValid() |
| 77 // use the mailbox to generate a texture id for the shared main thread conte xt to use. | 103 { |
| 104 if (!m_image) | |
| 105 return false; | |
| 106 if (!SharedGpuContext::isValid()) | |
| 107 return false; // Gpu context was lost | |
| 108 if (imageBelongsToSharedContext() && m_sharedContextId != SharedGpuContext:: contextId()) | |
| 109 return false; // Gpu context was lost an restored since resource was cre ated | |
| 110 return true; | |
| 111 } | |
| 112 | |
| 113 bool AcceleratedStaticBitmapImage::imageBelongsToSharedContext() | |
| 114 { | |
| 115 return m_sharedContextId != SharedGpuContext::kNoSharedContext; | |
| 116 } | |
| 117 | |
| 118 void AcceleratedStaticBitmapImage::createImageFromMailboxIfNeeded() | |
| 119 { | |
| 120 if (imageBelongsToSharedContext()) | |
| 121 return; | |
| 78 DCHECK(m_hasMailbox); | 122 DCHECK(m_hasMailbox); |
| 79 | 123 gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); |
| 80 auto sharedMainThreadContextProvider = wrapUnique(Platform::current()->creat eSharedOffscreenGraphicsContext3DProvider()); | 124 GrContext* sharedGrContext = SharedGpuContext::gr(); |
| 81 gpu::gles2::GLES2Interface* sharedGL = sharedMainThreadContextProvider->cont extGL(); | 125 DCHECK(sharedGL && sharedGrContext); // context isValid already checked in c allers |
| 82 GrContext* sharedGrContext = sharedMainThreadContextProvider->grContext(); | |
| 83 if (!sharedGrContext) | |
| 84 return nullptr; // Can happen if the context is lost, the SkImage won't be any good now anyway. | |
| 85 | 126 |
| 86 sharedGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); | 127 sharedGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); |
| 87 GLuint sharedContextTextureId = sharedGL->CreateAndConsumeTextureCHROMIUM(GL _TEXTURE_2D, m_mailbox.name); | 128 GLuint sharedContextTextureId = sharedGL->CreateAndConsumeTextureCHROMIUM(GL _TEXTURE_2D, m_mailbox.name); |
| 88 | |
| 89 GrGLTextureInfo textureInfo; | 129 GrGLTextureInfo textureInfo; |
| 90 textureInfo.fTarget = GL_TEXTURE_2D; | 130 textureInfo.fTarget = GL_TEXTURE_2D; |
| 91 textureInfo.fID = sharedContextTextureId; | 131 textureInfo.fID = sharedContextTextureId; |
| 92 GrBackendTextureDesc backendTexture; | 132 GrBackendTextureDesc backendTexture; |
| 93 backendTexture.fOrigin = kBottomLeft_GrSurfaceOrigin; | 133 backendTexture.fOrigin = kBottomLeft_GrSurfaceOrigin; |
| 94 backendTexture.fWidth = size().width(); | 134 backendTexture.fWidth = size().width(); |
| 95 backendTexture.fHeight = size().height(); | 135 backendTexture.fHeight = size().height(); |
| 96 backendTexture.fConfig = kSkia8888_GrPixelConfig; | 136 backendTexture.fConfig = kSkia8888_GrPixelConfig; |
| 97 backendTexture.fTextureHandle = skia::GrGLTextureInfoToGrBackendObject(textu reInfo); | 137 backendTexture.fTextureHandle = skia::GrGLTextureInfoToGrBackendObject(textu reInfo); |
| 98 | 138 |
| 99 m_image = fromSkSp(SkImage::MakeFromAdoptedTexture(sharedGrContext, backendT exture)); | 139 RefPtr<SkImage> newImage = fromSkSp(SkImage::MakeFromAdoptedTexture(sharedGr Context, backendTexture)); |
|
Stephen White
2016/09/01 15:43:53
Nit: could also use an sk_sp<> for newImage, then
| |
| 100 m_imageIsForSharedMainThreadContext = true; | 140 releaseImageThreadSafe(); |
| 101 // Can drop the ref on the GrContext since m_image is now backed by a textur e from the shared main thread context. | 141 m_image = newImage; |
| 102 m_grContext = nullptr; | 142 |
| 103 return m_image; | 143 m_sharedContextId = SharedGpuContext::contextId(); |
| 104 } | 144 } |
| 105 | 145 |
| 106 void AcceleratedStaticBitmapImage::ensureMailbox() | 146 void AcceleratedStaticBitmapImage::ensureMailbox() |
| 107 { | 147 { |
| 108 if (m_hasMailbox) | 148 if (m_hasMailbox) |
| 109 return; | 149 return; |
| 110 | 150 |
| 111 // If we weren't given a mailbox at creation, then we were given a SkImage t hat is assumed to be from the shared main thread context. | 151 DCHECK(m_image); |
| 112 DCHECK(m_imageIsForSharedMainThreadContext); | |
| 113 auto sharedMainThreadContextProvider = wrapUnique(Platform::current()->creat eSharedOffscreenGraphicsContext3DProvider()); | |
| 114 | 152 |
| 115 gpu::gles2::GLES2Interface* sharedGL = sharedMainThreadContextProvider->cont extGL(); | 153 gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); |
| 116 GrContext* sharedGrContext = sharedMainThreadContextProvider->grContext(); | 154 GrContext* sharedGrContext = SharedGpuContext::gr(); |
| 117 if (!sharedGrContext) | 155 if (!sharedGrContext) |
| 118 return; // Can happen if the context is lost, the SkImage won't be any g ood now anyway. | 156 return; // Can happen if the context is lost, the SkImage won't be any g ood now anyway. |
| 119 | |
| 120 GLuint imageTextureId = skia::GrBackendObjectToGrGLTextureInfo(m_image->getT extureHandle(true))->fID; | 157 GLuint imageTextureId = skia::GrBackendObjectToGrGLTextureInfo(m_image->getT extureHandle(true))->fID; |
| 121 sharedGL->BindTexture(GL_TEXTURE_2D, imageTextureId); | 158 sharedGL->BindTexture(GL_TEXTURE_2D, imageTextureId); |
| 122 | 159 |
| 123 sharedGL->GenMailboxCHROMIUM(m_mailbox.name); | 160 sharedGL->GenMailboxCHROMIUM(m_mailbox.name); |
| 124 sharedGL->ProduceTextureCHROMIUM(GL_TEXTURE_2D, m_mailbox.name); | 161 sharedGL->ProduceTextureCHROMIUM(GL_TEXTURE_2D, m_mailbox.name); |
| 125 const GLuint64 fenceSync = sharedGL->InsertFenceSyncCHROMIUM(); | 162 const GLuint64 fenceSync = sharedGL->InsertFenceSyncCHROMIUM(); |
| 126 sharedGL->Flush(); | 163 sharedGL->Flush(); |
| 127 sharedGL->GenSyncTokenCHROMIUM(fenceSync, m_syncToken.GetData()); | 164 sharedGL->GenSyncTokenCHROMIUM(fenceSync, m_syncToken.GetData()); |
| 128 | 165 |
| 129 sharedGL->BindTexture(GL_TEXTURE_2D, 0); | 166 sharedGL->BindTexture(GL_TEXTURE_2D, 0); |
| 130 // We changed bound textures in this function, so reset the GrContext. | 167 // We changed bound textures in this function, so reset the GrContext. |
| 131 sharedGrContext->resetContext(kTextureBinding_GrGLBackendState); | 168 sharedGrContext->resetContext(kTextureBinding_GrGLBackendState); |
| 132 | 169 |
| 133 m_hasMailbox = true; | 170 m_hasMailbox = true; |
| 134 } | 171 } |
| 135 | 172 |
| 173 void AcceleratedStaticBitmapImage::transfer() | |
| 174 { | |
| 175 checkThread(); | |
| 176 ensureMailbox(); | |
| 177 m_sharedContextId = SharedGpuContext::kNoSharedContext; | |
| 178 // If image thread is set, it means that the image has been consumed on the current thread, | |
| 179 // which may happen when we have chained transfers. When that is the case, w e must not | |
| 180 // reset m_imageThread to ensure that releaseImage is called on the right th read. | |
| 181 if (!m_imageThread) | |
| 182 m_imageThread = Platform::current()->currentThread(); | |
| 183 m_detachThreadAtNextCheck = true; | |
| 184 } | |
| 185 | |
| 186 void AcceleratedStaticBitmapImage::checkThread() | |
| 187 { | |
| 188 if (m_detachThreadAtNextCheck) { | |
| 189 m_threadChecker.DetachFromThread(); | |
| 190 m_detachThreadAtNextCheck = false; | |
| 191 } | |
| 192 CHECK(m_threadChecker.CalledOnValidThread()); | |
| 193 } | |
| 194 | |
| 195 void releaseImage(SkImage* image, std::unique_ptr<gpu::SyncToken>&& syncToken) | |
| 196 { | |
| 197 if (SharedGpuContext::isValid()) | |
| 198 SharedGpuContext::gl()->WaitSyncTokenCHROMIUM(syncToken->GetData()); | |
| 199 image->unref(); | |
|
Stephen White
2016/09/01 15:43:53
It's unfortunate to have explit unref() here. Coul
| |
| 200 } | |
| 201 | |
| 202 void AcceleratedStaticBitmapImage::releaseImageThreadSafe() | |
| 203 { | |
| 204 // If m_image belongs to a GrContext that is on another thread, it | |
| 205 // must be released on that thread. | |
| 206 if (m_imageThread && m_image && m_imageThread != Platform::current()->curren tThread() && SharedGpuContext::isValid()) { | |
| 207 gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); | |
| 208 std::unique_ptr<gpu::SyncToken> releaseSyncToken(new gpu::SyncToken); | |
| 209 const GLuint64 fenceSync = sharedGL->InsertFenceSyncCHROMIUM(); | |
| 210 sharedGL->Flush(); | |
| 211 sharedGL->GenSyncTokenCHROMIUM(fenceSync, releaseSyncToken->GetData()); | |
| 212 m_imageThread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, crossThread Bind(&releaseImage, crossThreadUnretained(m_image.release().leakRef()), passed(s td::move(releaseSyncToken)))); | |
| 213 } | |
| 214 m_image = nullptr; | |
| 215 m_imageThread = nullptr; | |
| 216 } | |
| 217 | |
| 136 } // namespace blink | 218 } // namespace blink |
| OLD | NEW |