Chromium Code Reviews| Index: third_party/WebKit/Source/platform/graphics/AcceleratedStaticBitmapImage.cpp |
| diff --git a/third_party/WebKit/Source/platform/graphics/AcceleratedStaticBitmapImage.cpp b/third_party/WebKit/Source/platform/graphics/AcceleratedStaticBitmapImage.cpp |
| index 0ec750ec1b6c1019be6bd2499f8338e5872d67da..bd305a51c33be232e5427f42150bd68adf67ccf8 100644 |
| --- a/third_party/WebKit/Source/platform/graphics/AcceleratedStaticBitmapImage.cpp |
| +++ b/third_party/WebKit/Source/platform/graphics/AcceleratedStaticBitmapImage.cpp |
| @@ -6,10 +6,13 @@ |
| #include "gpu/command_buffer/client/gles2_interface.h" |
| #include "gpu/command_buffer/common/sync_token.h" |
| +#include "platform/CrossThreadFunctional.h" |
| #include "platform/graphics/StaticBitmapImage.h" |
| +#include "platform/graphics/gpu/SharedGpuContext.h" |
| #include "platform/graphics/skia/SkiaUtils.h" |
| #include "public/platform/Platform.h" |
| #include "public/platform/WebGraphicsContext3DProvider.h" |
| +#include "public/platform/WebTaskRunner.h" |
| #include "skia/ext/texture_handle.h" |
| #include "third_party/skia/include/core/SkImage.h" |
| #include "third_party/skia/include/gpu/GrContext.h" |
| @@ -25,32 +28,46 @@ PassRefPtr<AcceleratedStaticBitmapImage> AcceleratedStaticBitmapImage::create(Pa |
| return adoptRef(new AcceleratedStaticBitmapImage(image)); |
| } |
| -PassRefPtr<AcceleratedStaticBitmapImage> AcceleratedStaticBitmapImage::create(PassRefPtr<SkImage> image, sk_sp<GrContext> grContext, const gpu::Mailbox& mailbox, const gpu::SyncToken& syncToken) |
| +PassRefPtr<AcceleratedStaticBitmapImage> AcceleratedStaticBitmapImage::create(PassRefPtr<SkImage> image, GrContext* grContext, const gpu::Mailbox& mailbox, const gpu::SyncToken& syncToken) |
| { |
| 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.
|
| } |
| AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(PassRefPtr<SkImage> image) |
| : StaticBitmapImage(std::move(image)) |
| - , m_imageIsForSharedMainThreadContext(true) |
| + , m_sharedContextId(SharedGpuContext::contextId()) |
| { |
| + m_threadChecker.DetachFromThread(); |
| } |
| -AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(PassRefPtr<SkImage> image, sk_sp<GrContext> grContext, const gpu::Mailbox& mailbox, const gpu::SyncToken& syncToken) |
| +AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(PassRefPtr<SkImage> image, GrContext* grContext, const gpu::Mailbox& mailbox, const gpu::SyncToken& syncToken) |
| : StaticBitmapImage(std::move(image)) |
| - , m_imageIsForSharedMainThreadContext(false) // TODO(danakj): Could be true though, caller would know. |
| - , m_grContext(std::move(grContext)) |
| + , m_sharedContextId(SharedGpuContext::kNoSharedContext) |
| , m_hasMailbox(true) |
| , m_mailbox(mailbox) |
| , m_syncToken(syncToken) |
| { |
| - DCHECK(m_grContext); |
| + DCHECK(grContext); |
| + m_threadChecker.DetachFromThread(); |
| + GrContext* sharedGr = SharedGpuContext::gr(); |
| + if (!grContext || grContext == sharedGr) { |
|
Stephen White
2016/09/01 15:43:53
As discussed, use this create() method only for ou
|
| + m_sharedContextId = SharedGpuContext::contextId(); |
| + } |
| } |
| -AcceleratedStaticBitmapImage::~AcceleratedStaticBitmapImage() = default; |
| +AcceleratedStaticBitmapImage::~AcceleratedStaticBitmapImage() |
| +{ |
| + // Avoid leaking mailboxes in cases where the texture gets recycled by skia. |
| + if (m_hasMailbox && SharedGpuContext::isValid()) |
| + SharedGpuContext::gl()->ProduceTextureDirectCHROMIUM(0, GL_TEXTURE_2D, m_mailbox.name); |
| + releaseImageThreadSafe(); |
| +} |
| void AcceleratedStaticBitmapImage::copyToTexture(WebGraphicsContext3DProvider* destProvider, GLuint destTextureId, GLenum internalFormat, GLenum destType, bool flipY) |
| { |
| + checkThread(); |
| + if (!isValid()) |
| + return; |
| // |destProvider| may not be the same context as the one used for |m_image| so we use a mailbox to |
| // generate a texture id for |destProvider| to access. |
| ensureMailbox(); |
| @@ -66,26 +83,49 @@ void AcceleratedStaticBitmapImage::copyToTexture(WebGraphicsContext3DProvider* d |
| PassRefPtr<SkImage> AcceleratedStaticBitmapImage::imageForCurrentFrame() |
| { |
| - // This must return an SkImage that can be used with the shared main thread context. If |m_image| satisfies that, we are done. |
| - if (m_imageIsForSharedMainThreadContext) |
| - return m_image; |
| + checkThread(); |
| + if (!isValid()) |
| + return nullptr; |
| + createImageFromMailboxIfNeeded(); |
| + return m_image; |
| +} |
| - // TODO(xidachen): make this work on a worker thread. |
| - DCHECK(isMainThread()); |
| +void AcceleratedStaticBitmapImage::draw(SkCanvas* canvas, const SkPaint& paint, const FloatRect& dstRect, const FloatRect& srcRect, RespectImageOrientationEnum respectImageOrientation, ImageClampingMode imageClampingMode) |
| +{ |
| + checkThread(); |
| + if (!isValid()) |
| + return; |
| + createImageFromMailboxIfNeeded(); |
| + StaticBitmapImage::draw(canvas, paint, dstRect, srcRect, respectImageOrientation, imageClampingMode); |
| +} |
| - // If the SkImage came from any other context than the shared main thread one, we expect to be given a mailbox at construction. We |
| - // use the mailbox to generate a texture id for the shared main thread context to use. |
| - DCHECK(m_hasMailbox); |
| +bool AcceleratedStaticBitmapImage::isValid() |
| +{ |
| + if (!m_image) |
| + return false; |
| + if (!SharedGpuContext::isValid()) |
| + return false; // Gpu context was lost |
| + if (imageBelongsToSharedContext() && m_sharedContextId != SharedGpuContext::contextId()) |
| + return false; // Gpu context was lost an restored since resource was created |
| + return true; |
| +} |
| - auto sharedMainThreadContextProvider = wrapUnique(Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); |
| - gpu::gles2::GLES2Interface* sharedGL = sharedMainThreadContextProvider->contextGL(); |
| - GrContext* sharedGrContext = sharedMainThreadContextProvider->grContext(); |
| - if (!sharedGrContext) |
| - return nullptr; // Can happen if the context is lost, the SkImage won't be any good now anyway. |
| +bool AcceleratedStaticBitmapImage::imageBelongsToSharedContext() |
| +{ |
| + return m_sharedContextId != SharedGpuContext::kNoSharedContext; |
| +} |
| + |
| +void AcceleratedStaticBitmapImage::createImageFromMailboxIfNeeded() |
| +{ |
| + if (imageBelongsToSharedContext()) |
| + return; |
| + DCHECK(m_hasMailbox); |
| + gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); |
| + GrContext* sharedGrContext = SharedGpuContext::gr(); |
| + DCHECK(sharedGL && sharedGrContext); // context isValid already checked in callers |
| sharedGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); |
| GLuint sharedContextTextureId = sharedGL->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, m_mailbox.name); |
| - |
| GrGLTextureInfo textureInfo; |
| textureInfo.fTarget = GL_TEXTURE_2D; |
| textureInfo.fID = sharedContextTextureId; |
| @@ -96,11 +136,11 @@ PassRefPtr<SkImage> AcceleratedStaticBitmapImage::imageForCurrentFrame() |
| backendTexture.fConfig = kSkia8888_GrPixelConfig; |
| backendTexture.fTextureHandle = skia::GrGLTextureInfoToGrBackendObject(textureInfo); |
| - m_image = fromSkSp(SkImage::MakeFromAdoptedTexture(sharedGrContext, backendTexture)); |
| - m_imageIsForSharedMainThreadContext = true; |
| - // Can drop the ref on the GrContext since m_image is now backed by a texture from the shared main thread context. |
| - m_grContext = nullptr; |
| - return m_image; |
| + RefPtr<SkImage> newImage = fromSkSp(SkImage::MakeFromAdoptedTexture(sharedGrContext, backendTexture)); |
|
Stephen White
2016/09/01 15:43:53
Nit: could also use an sk_sp<> for newImage, then
|
| + releaseImageThreadSafe(); |
| + m_image = newImage; |
| + |
| + m_sharedContextId = SharedGpuContext::contextId(); |
| } |
| void AcceleratedStaticBitmapImage::ensureMailbox() |
| @@ -108,15 +148,12 @@ void AcceleratedStaticBitmapImage::ensureMailbox() |
| if (m_hasMailbox) |
| return; |
| - // If we weren't given a mailbox at creation, then we were given a SkImage that is assumed to be from the shared main thread context. |
| - DCHECK(m_imageIsForSharedMainThreadContext); |
| - auto sharedMainThreadContextProvider = wrapUnique(Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); |
| + DCHECK(m_image); |
| - gpu::gles2::GLES2Interface* sharedGL = sharedMainThreadContextProvider->contextGL(); |
| - GrContext* sharedGrContext = sharedMainThreadContextProvider->grContext(); |
| + gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); |
| + GrContext* sharedGrContext = SharedGpuContext::gr(); |
| if (!sharedGrContext) |
| return; // Can happen if the context is lost, the SkImage won't be any good now anyway. |
| - |
| GLuint imageTextureId = skia::GrBackendObjectToGrGLTextureInfo(m_image->getTextureHandle(true))->fID; |
| sharedGL->BindTexture(GL_TEXTURE_2D, imageTextureId); |
| @@ -133,4 +170,49 @@ void AcceleratedStaticBitmapImage::ensureMailbox() |
| m_hasMailbox = true; |
| } |
| +void AcceleratedStaticBitmapImage::transfer() |
| +{ |
| + checkThread(); |
| + ensureMailbox(); |
| + m_sharedContextId = SharedGpuContext::kNoSharedContext; |
| + // If image thread is set, it means that the image has been consumed on the current thread, |
| + // which may happen when we have chained transfers. When that is the case, we must not |
| + // reset m_imageThread to ensure that releaseImage is called on the right thread. |
| + if (!m_imageThread) |
| + m_imageThread = Platform::current()->currentThread(); |
| + m_detachThreadAtNextCheck = true; |
| +} |
| + |
| +void AcceleratedStaticBitmapImage::checkThread() |
| +{ |
| + if (m_detachThreadAtNextCheck) { |
| + m_threadChecker.DetachFromThread(); |
| + m_detachThreadAtNextCheck = false; |
| + } |
| + CHECK(m_threadChecker.CalledOnValidThread()); |
| +} |
| + |
| +void releaseImage(SkImage* image, std::unique_ptr<gpu::SyncToken>&& syncToken) |
| +{ |
| + if (SharedGpuContext::isValid()) |
| + SharedGpuContext::gl()->WaitSyncTokenCHROMIUM(syncToken->GetData()); |
| + image->unref(); |
|
Stephen White
2016/09/01 15:43:53
It's unfortunate to have explit unref() here. Coul
|
| +} |
| + |
| +void AcceleratedStaticBitmapImage::releaseImageThreadSafe() |
| +{ |
| + // If m_image belongs to a GrContext that is on another thread, it |
| + // must be released on that thread. |
| + if (m_imageThread && m_image && m_imageThread != Platform::current()->currentThread() && SharedGpuContext::isValid()) { |
| + gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); |
| + std::unique_ptr<gpu::SyncToken> releaseSyncToken(new gpu::SyncToken); |
| + const GLuint64 fenceSync = sharedGL->InsertFenceSyncCHROMIUM(); |
| + sharedGL->Flush(); |
| + sharedGL->GenSyncTokenCHROMIUM(fenceSync, releaseSyncToken->GetData()); |
| + m_imageThread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, crossThreadBind(&releaseImage, crossThreadUnretained(m_image.release().leakRef()), passed(std::move(releaseSyncToken)))); |
| + } |
| + m_image = nullptr; |
| + m_imageThread = nullptr; |
| +} |
| + |
| } // namespace blink |