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(sk
_sp<SkImage> image) | 26 PassRefPtr<AcceleratedStaticBitmapImage> AcceleratedStaticBitmapImage::createFro
mSharedContextImage(sk_sp<SkImage> image) |
24 { | 27 { |
25 return adoptRef(new AcceleratedStaticBitmapImage(std::move(image))); | 28 return adoptRef(new AcceleratedStaticBitmapImage(std::move(image))); |
26 } | 29 } |
27 | 30 |
28 PassRefPtr<AcceleratedStaticBitmapImage> AcceleratedStaticBitmapImage::create(sk
_sp<SkImage> image, sk_sp<GrContext> grContext, const gpu::Mailbox& mailbox, con
st gpu::SyncToken& syncToken) | 31 PassRefPtr<AcceleratedStaticBitmapImage> AcceleratedStaticBitmapImage::createFro
mWebGLContextImage(sk_sp<SkImage> image, const gpu::Mailbox& mailbox, const gpu:
:SyncToken& syncToken) |
29 { | 32 { |
30 return adoptRef(new AcceleratedStaticBitmapImage(std::move(image), std::move
(grContext), mailbox, syncToken)); | 33 return adoptRef(new AcceleratedStaticBitmapImage(std::move(image), mailbox,
syncToken)); |
31 } | 34 } |
32 | 35 |
33 AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(sk_sp<SkImage> image) | 36 AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(sk_sp<SkImage> image) |
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(sk_sp<SkImage> image,
sk_sp<GrContext> grContext, const gpu::Mailbox& mailbox, const gpu::SyncToken&
syncToken) | 43 AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(sk_sp<SkImage> image,
const gpu::Mailbox& mailbox, const gpu::SyncToken& syncToken) |
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 m_threadChecker.DetachFromThread(); |
| 51 |
| 52 // Note: In this case, m_image is not usable directly because it is not in t
he shared context. |
| 53 // It is just used to hold a reference to the texture object in the origin c
ontext until the |
| 54 // mailbox can be consumed. |
48 } | 55 } |
49 | 56 |
50 AcceleratedStaticBitmapImage::~AcceleratedStaticBitmapImage() = default; | 57 AcceleratedStaticBitmapImage::~AcceleratedStaticBitmapImage() |
| 58 { |
| 59 // Avoid leaking mailboxes in cases where the texture gets recycled by skia. |
| 60 if (m_hasMailbox && SharedGpuContext::isValid()) |
| 61 SharedGpuContext::gl()->ProduceTextureDirectCHROMIUM(0, GL_TEXTURE_2D, m
_mailbox.name); |
| 62 releaseImageThreadSafe(); |
| 63 } |
51 | 64 |
52 void AcceleratedStaticBitmapImage::copyToTexture(WebGraphicsContext3DProvider* d
estProvider, GLuint destTextureId, GLenum internalFormat, GLenum destType, bool
flipY) | 65 void AcceleratedStaticBitmapImage::copyToTexture(WebGraphicsContext3DProvider* d
estProvider, GLuint destTextureId, GLenum internalFormat, GLenum destType, bool
flipY) |
53 { | 66 { |
| 67 checkThread(); |
| 68 if (!isValid()) |
| 69 return; |
54 // |destProvider| may not be the same context as the one used for |m_image|
so we use a mailbox to | 70 // |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. | 71 // generate a texture id for |destProvider| to access. |
56 ensureMailbox(); | 72 ensureMailbox(); |
57 | 73 |
58 // Get a texture id that |destProvider| knows about and copy from it. | 74 // Get a texture id that |destProvider| knows about and copy from it. |
59 gpu::gles2::GLES2Interface* destGL = destProvider->contextGL(); | 75 gpu::gles2::GLES2Interface* destGL = destProvider->contextGL(); |
60 destGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); | 76 destGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); |
61 GLuint sourceTextureId = destGL->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_
2D, m_mailbox.name); | 77 GLuint sourceTextureId = destGL->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_
2D, m_mailbox.name); |
62 destGL->CopyTextureCHROMIUM(sourceTextureId, destTextureId, internalFormat,
destType, flipY, false, false); | 78 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. | 79 // 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); | 80 destGL->DeleteTextures(1, &sourceTextureId); |
65 } | 81 } |
66 | 82 |
67 sk_sp<SkImage> AcceleratedStaticBitmapImage::imageForCurrentFrame() | 83 sk_sp<SkImage> AcceleratedStaticBitmapImage::imageForCurrentFrame() |
68 { | 84 { |
69 // This must return an SkImage that can be used with the shared main thread
context. If |m_image| satisfies that, we are done. | 85 checkThread(); |
70 if (m_imageIsForSharedMainThreadContext) | 86 if (!isValid()) |
71 return m_image; | 87 return nullptr; |
| 88 createImageFromMailboxIfNeeded(); |
| 89 return m_image; |
| 90 } |
72 | 91 |
73 // TODO(xidachen): make this work on a worker thread. | 92 void AcceleratedStaticBitmapImage::draw(SkCanvas* canvas, const SkPaint& paint,
const FloatRect& dstRect, const FloatRect& srcRect, RespectImageOrientationEnum
respectImageOrientation, ImageClampingMode imageClampingMode) |
74 DCHECK(isMainThread()); | 93 { |
| 94 checkThread(); |
| 95 if (!isValid()) |
| 96 return; |
| 97 createImageFromMailboxIfNeeded(); |
| 98 StaticBitmapImage::draw(canvas, paint, dstRect, srcRect, respectImageOrienta
tion, imageClampingMode); |
| 99 } |
75 | 100 |
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 | 101 bool AcceleratedStaticBitmapImage::isValid() |
77 // use the mailbox to generate a texture id for the shared main thread conte
xt to use. | 102 { |
| 103 if (!m_image) |
| 104 return false; |
| 105 if (!SharedGpuContext::isValid()) |
| 106 return false; // Gpu context was lost |
| 107 if (imageBelongsToSharedContext() && m_sharedContextId != SharedGpuContext::
contextId()) |
| 108 return false; // Gpu context was lost an restored since resource was cre
ated |
| 109 return true; |
| 110 } |
| 111 |
| 112 bool AcceleratedStaticBitmapImage::imageBelongsToSharedContext() |
| 113 { |
| 114 return m_sharedContextId != SharedGpuContext::kNoSharedContext; |
| 115 } |
| 116 |
| 117 void AcceleratedStaticBitmapImage::createImageFromMailboxIfNeeded() |
| 118 { |
| 119 if (imageBelongsToSharedContext()) |
| 120 return; |
78 DCHECK(m_hasMailbox); | 121 DCHECK(m_hasMailbox); |
79 | 122 gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); |
80 auto sharedMainThreadContextProvider = wrapUnique(Platform::current()->creat
eSharedOffscreenGraphicsContext3DProvider()); | 123 GrContext* sharedGrContext = SharedGpuContext::gr(); |
81 gpu::gles2::GLES2Interface* sharedGL = sharedMainThreadContextProvider->cont
extGL(); | 124 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 | 125 |
86 sharedGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); | 126 sharedGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); |
87 GLuint sharedContextTextureId = sharedGL->CreateAndConsumeTextureCHROMIUM(GL
_TEXTURE_2D, m_mailbox.name); | 127 GLuint sharedContextTextureId = sharedGL->CreateAndConsumeTextureCHROMIUM(GL
_TEXTURE_2D, m_mailbox.name); |
88 | |
89 GrGLTextureInfo textureInfo; | 128 GrGLTextureInfo textureInfo; |
90 textureInfo.fTarget = GL_TEXTURE_2D; | 129 textureInfo.fTarget = GL_TEXTURE_2D; |
91 textureInfo.fID = sharedContextTextureId; | 130 textureInfo.fID = sharedContextTextureId; |
92 GrBackendTextureDesc backendTexture; | 131 GrBackendTextureDesc backendTexture; |
93 backendTexture.fOrigin = kBottomLeft_GrSurfaceOrigin; | 132 backendTexture.fOrigin = kBottomLeft_GrSurfaceOrigin; |
94 backendTexture.fWidth = size().width(); | 133 backendTexture.fWidth = size().width(); |
95 backendTexture.fHeight = size().height(); | 134 backendTexture.fHeight = size().height(); |
96 backendTexture.fConfig = kSkia8888_GrPixelConfig; | 135 backendTexture.fConfig = kSkia8888_GrPixelConfig; |
97 backendTexture.fTextureHandle = skia::GrGLTextureInfoToGrBackendObject(textu
reInfo); | 136 backendTexture.fTextureHandle = skia::GrGLTextureInfoToGrBackendObject(textu
reInfo); |
98 | 137 |
99 m_image = SkImage::MakeFromAdoptedTexture(sharedGrContext, backendTexture); | 138 sk_sp<SkImage> newImage = SkImage::MakeFromAdoptedTexture(sharedGrContext, b
ackendTexture); |
100 m_imageIsForSharedMainThreadContext = true; | 139 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. | 140 m_image = newImage; |
102 m_grContext = nullptr; | 141 |
103 return m_image; | 142 m_sharedContextId = SharedGpuContext::contextId(); |
104 } | 143 } |
105 | 144 |
106 void AcceleratedStaticBitmapImage::ensureMailbox() | 145 void AcceleratedStaticBitmapImage::ensureMailbox() |
107 { | 146 { |
108 if (m_hasMailbox) | 147 if (m_hasMailbox) |
109 return; | 148 return; |
110 | 149 |
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. | 150 DCHECK(m_image); |
112 DCHECK(m_imageIsForSharedMainThreadContext); | |
113 auto sharedMainThreadContextProvider = wrapUnique(Platform::current()->creat
eSharedOffscreenGraphicsContext3DProvider()); | |
114 | 151 |
115 gpu::gles2::GLES2Interface* sharedGL = sharedMainThreadContextProvider->cont
extGL(); | 152 gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); |
116 GrContext* sharedGrContext = sharedMainThreadContextProvider->grContext(); | 153 GrContext* sharedGrContext = SharedGpuContext::gr(); |
117 if (!sharedGrContext) | 154 if (!sharedGrContext) |
118 return; // Can happen if the context is lost, the SkImage won't be any g
ood now anyway. | 155 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; | 156 GLuint imageTextureId = skia::GrBackendObjectToGrGLTextureInfo(m_image->getT
extureHandle(true))->fID; |
121 sharedGL->BindTexture(GL_TEXTURE_2D, imageTextureId); | 157 sharedGL->BindTexture(GL_TEXTURE_2D, imageTextureId); |
122 | 158 |
123 sharedGL->GenMailboxCHROMIUM(m_mailbox.name); | 159 sharedGL->GenMailboxCHROMIUM(m_mailbox.name); |
124 sharedGL->ProduceTextureCHROMIUM(GL_TEXTURE_2D, m_mailbox.name); | 160 sharedGL->ProduceTextureCHROMIUM(GL_TEXTURE_2D, m_mailbox.name); |
125 const GLuint64 fenceSync = sharedGL->InsertFenceSyncCHROMIUM(); | 161 const GLuint64 fenceSync = sharedGL->InsertFenceSyncCHROMIUM(); |
126 sharedGL->Flush(); | 162 sharedGL->Flush(); |
127 sharedGL->GenSyncTokenCHROMIUM(fenceSync, m_syncToken.GetData()); | 163 sharedGL->GenSyncTokenCHROMIUM(fenceSync, m_syncToken.GetData()); |
128 | 164 |
129 sharedGL->BindTexture(GL_TEXTURE_2D, 0); | 165 sharedGL->BindTexture(GL_TEXTURE_2D, 0); |
130 // We changed bound textures in this function, so reset the GrContext. | 166 // We changed bound textures in this function, so reset the GrContext. |
131 sharedGrContext->resetContext(kTextureBinding_GrGLBackendState); | 167 sharedGrContext->resetContext(kTextureBinding_GrGLBackendState); |
132 | 168 |
133 m_hasMailbox = true; | 169 m_hasMailbox = true; |
134 } | 170 } |
135 | 171 |
| 172 void AcceleratedStaticBitmapImage::transfer() |
| 173 { |
| 174 checkThread(); |
| 175 ensureMailbox(); |
| 176 m_sharedContextId = SharedGpuContext::kNoSharedContext; |
| 177 // If image thread is set, it means that the image has been consumed on the
current thread, |
| 178 // which may happen when we have chained transfers. When that is the case, w
e must not |
| 179 // reset m_imageThread to ensure that releaseImage is called on the right th
read. |
| 180 if (!m_imageThread) |
| 181 m_imageThread = Platform::current()->currentThread(); |
| 182 m_detachThreadAtNextCheck = true; |
| 183 } |
| 184 |
| 185 void AcceleratedStaticBitmapImage::checkThread() |
| 186 { |
| 187 if (m_detachThreadAtNextCheck) { |
| 188 m_threadChecker.DetachFromThread(); |
| 189 m_detachThreadAtNextCheck = false; |
| 190 } |
| 191 CHECK(m_threadChecker.CalledOnValidThread()); |
| 192 } |
| 193 |
| 194 void releaseImage(sk_sp<SkImage>&& image, std::unique_ptr<gpu::SyncToken>&& sync
Token) |
| 195 { |
| 196 if (SharedGpuContext::isValid() && syncToken->HasData()) |
| 197 SharedGpuContext::gl()->WaitSyncTokenCHROMIUM(syncToken->GetData()); |
| 198 image.reset(); |
| 199 } |
| 200 |
| 201 void AcceleratedStaticBitmapImage::releaseImageThreadSafe() |
| 202 { |
| 203 // If m_image belongs to a GrContext that is on another thread, it |
| 204 // must be released on that thread. |
| 205 if (m_imageThread && m_image && m_imageThread != Platform::current()->curren
tThread() && SharedGpuContext::isValid()) { |
| 206 gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); |
| 207 std::unique_ptr<gpu::SyncToken> releaseSyncToken(new gpu::SyncToken); |
| 208 const GLuint64 fenceSync = sharedGL->InsertFenceSyncCHROMIUM(); |
| 209 sharedGL->Flush(); |
| 210 sharedGL->GenSyncTokenCHROMIUM(fenceSync, releaseSyncToken->GetData()); |
| 211 m_imageThread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, crossThread
Bind(&releaseImage, passed(std::move(m_image)), passed(std::move(releaseSyncToke
n)))); |
| 212 } |
| 213 m_image = nullptr; |
| 214 m_imageThread = nullptr; |
| 215 } |
| 216 |
136 } // namespace blink | 217 } // namespace blink |
OLD | NEW |