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" | |
10 #include "platform/graphics/StaticBitmapImage.h" | 9 #include "platform/graphics/StaticBitmapImage.h" |
11 #include "platform/graphics/gpu/SharedGpuContext.h" | |
12 #include "platform/graphics/skia/SkiaUtils.h" | 10 #include "platform/graphics/skia/SkiaUtils.h" |
13 #include "public/platform/Platform.h" | 11 #include "public/platform/Platform.h" |
14 #include "public/platform/WebGraphicsContext3DProvider.h" | 12 #include "public/platform/WebGraphicsContext3DProvider.h" |
15 #include "public/platform/WebTaskRunner.h" | |
16 #include "skia/ext/texture_handle.h" | 13 #include "skia/ext/texture_handle.h" |
17 #include "third_party/skia/include/core/SkImage.h" | 14 #include "third_party/skia/include/core/SkImage.h" |
18 #include "third_party/skia/include/gpu/GrContext.h" | 15 #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> AcceleratedStaticBitmapImage::createFro
mSharedContextImage(sk_sp<SkImage> image) | 23 PassRefPtr<AcceleratedStaticBitmapImage> AcceleratedStaticBitmapImage::create(sk
_sp<SkImage> image) |
27 { | 24 { |
28 return adoptRef(new AcceleratedStaticBitmapImage(std::move(image))); | 25 return adoptRef(new AcceleratedStaticBitmapImage(std::move(image))); |
29 } | 26 } |
30 | 27 |
31 PassRefPtr<AcceleratedStaticBitmapImage> AcceleratedStaticBitmapImage::createFro
mWebGLContextImage(sk_sp<SkImage> image, const gpu::Mailbox& mailbox, const gpu:
:SyncToken& syncToken) | 28 PassRefPtr<AcceleratedStaticBitmapImage> AcceleratedStaticBitmapImage::create(sk
_sp<SkImage> image, sk_sp<GrContext> grContext, const gpu::Mailbox& mailbox, con
st gpu::SyncToken& syncToken) |
32 { | 29 { |
33 return adoptRef(new AcceleratedStaticBitmapImage(std::move(image), mailbox,
syncToken)); | 30 return adoptRef(new AcceleratedStaticBitmapImage(std::move(image), std::move
(grContext), mailbox, syncToken)); |
34 } | 31 } |
35 | 32 |
36 AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(sk_sp<SkImage> image) | 33 AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(sk_sp<SkImage> image) |
37 : StaticBitmapImage(std::move(image)) | 34 : StaticBitmapImage(std::move(image)) |
38 , m_sharedContextId(SharedGpuContext::contextId()) | 35 , m_imageIsForSharedMainThreadContext(true) |
39 { | 36 { |
40 m_threadChecker.DetachFromThread(); | |
41 } | 37 } |
42 | 38 |
43 AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(sk_sp<SkImage> image,
const gpu::Mailbox& mailbox, const gpu::SyncToken& syncToken) | 39 AcceleratedStaticBitmapImage::AcceleratedStaticBitmapImage(sk_sp<SkImage> image,
sk_sp<GrContext> grContext, const gpu::Mailbox& mailbox, const gpu::SyncToken&
syncToken) |
44 : StaticBitmapImage(std::move(image)) | 40 : StaticBitmapImage(std::move(image)) |
45 , m_sharedContextId(SharedGpuContext::kNoSharedContext) | 41 , m_imageIsForSharedMainThreadContext(false) // TODO(danakj): Could be true
though, caller would know. |
| 42 , m_grContext(std::move(grContext)) |
46 , m_hasMailbox(true) | 43 , m_hasMailbox(true) |
47 , m_mailbox(mailbox) | 44 , m_mailbox(mailbox) |
48 , m_syncToken(syncToken) | 45 , m_syncToken(syncToken) |
49 { | 46 { |
50 m_threadChecker.DetachFromThread(); | 47 DCHECK(m_grContext); |
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. | |
55 } | 48 } |
56 | 49 |
57 AcceleratedStaticBitmapImage::~AcceleratedStaticBitmapImage() | 50 AcceleratedStaticBitmapImage::~AcceleratedStaticBitmapImage() = default; |
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 } | |
64 | 51 |
65 void AcceleratedStaticBitmapImage::copyToTexture(WebGraphicsContext3DProvider* d
estProvider, GLuint destTextureId, GLenum internalFormat, GLenum destType, bool
flipY) | 52 void AcceleratedStaticBitmapImage::copyToTexture(WebGraphicsContext3DProvider* d
estProvider, GLuint destTextureId, GLenum internalFormat, GLenum destType, bool
flipY) |
66 { | 53 { |
67 checkThread(); | |
68 if (!isValid()) | |
69 return; | |
70 // |destProvider| may not be the same context as the one used for |m_image|
so we use a mailbox to | 54 // |destProvider| may not be the same context as the one used for |m_image|
so we use a mailbox to |
71 // generate a texture id for |destProvider| to access. | 55 // generate a texture id for |destProvider| to access. |
72 ensureMailbox(); | 56 ensureMailbox(); |
73 | 57 |
74 // Get a texture id that |destProvider| knows about and copy from it. | 58 // Get a texture id that |destProvider| knows about and copy from it. |
75 gpu::gles2::GLES2Interface* destGL = destProvider->contextGL(); | 59 gpu::gles2::GLES2Interface* destGL = destProvider->contextGL(); |
76 destGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); | 60 destGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); |
77 GLuint sourceTextureId = destGL->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_
2D, m_mailbox.name); | 61 GLuint sourceTextureId = destGL->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_
2D, m_mailbox.name); |
78 destGL->CopyTextureCHROMIUM(sourceTextureId, destTextureId, internalFormat,
destType, flipY, false, false); | 62 destGL->CopyTextureCHROMIUM(sourceTextureId, destTextureId, internalFormat,
destType, flipY, false, false); |
79 // This drops the |destGL| context's reference on our |m_mailbox|, but it's
still held alive by our SkImage. | 63 // This drops the |destGL| context's reference on our |m_mailbox|, but it's
still held alive by our SkImage. |
80 destGL->DeleteTextures(1, &sourceTextureId); | 64 destGL->DeleteTextures(1, &sourceTextureId); |
81 } | 65 } |
82 | 66 |
83 sk_sp<SkImage> AcceleratedStaticBitmapImage::imageForCurrentFrame() | 67 sk_sp<SkImage> AcceleratedStaticBitmapImage::imageForCurrentFrame() |
84 { | 68 { |
85 checkThread(); | 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 if (!isValid()) | 70 if (m_imageIsForSharedMainThreadContext) |
87 return nullptr; | 71 return m_image; |
88 createImageFromMailboxIfNeeded(); | |
89 return m_image; | |
90 } | |
91 | 72 |
92 void AcceleratedStaticBitmapImage::draw(SkCanvas* canvas, const SkPaint& paint,
const FloatRect& dstRect, const FloatRect& srcRect, RespectImageOrientationEnum
respectImageOrientation, ImageClampingMode imageClampingMode) | 73 // TODO(xidachen): make this work on a worker thread. |
93 { | 74 DCHECK(isMainThread()); |
94 checkThread(); | |
95 if (!isValid()) | |
96 return; | |
97 createImageFromMailboxIfNeeded(); | |
98 StaticBitmapImage::draw(canvas, paint, dstRect, srcRect, respectImageOrienta
tion, imageClampingMode); | |
99 } | |
100 | 75 |
101 bool AcceleratedStaticBitmapImage::isValid() | 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 { | 77 // use the mailbox to generate a texture id for the shared main thread conte
xt to use. |
103 if (!m_image) | 78 DCHECK(m_hasMailbox); |
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 | 79 |
112 bool AcceleratedStaticBitmapImage::imageBelongsToSharedContext() | 80 auto sharedMainThreadContextProvider = wrapUnique(Platform::current()->creat
eSharedOffscreenGraphicsContext3DProvider()); |
113 { | 81 gpu::gles2::GLES2Interface* sharedGL = sharedMainThreadContextProvider->cont
extGL(); |
114 return m_sharedContextId != SharedGpuContext::kNoSharedContext; | 82 GrContext* sharedGrContext = sharedMainThreadContextProvider->grContext(); |
115 } | 83 if (!sharedGrContext) |
116 | 84 return nullptr; // Can happen if the context is lost, the SkImage won't
be any good now anyway. |
117 void AcceleratedStaticBitmapImage::createImageFromMailboxIfNeeded() | |
118 { | |
119 if (imageBelongsToSharedContext()) | |
120 return; | |
121 DCHECK(m_hasMailbox); | |
122 gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); | |
123 GrContext* sharedGrContext = SharedGpuContext::gr(); | |
124 DCHECK(sharedGL && sharedGrContext); // context isValid already checked in c
allers | |
125 | 85 |
126 sharedGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); | 86 sharedGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); |
127 GLuint sharedContextTextureId = sharedGL->CreateAndConsumeTextureCHROMIUM(GL
_TEXTURE_2D, m_mailbox.name); | 87 GLuint sharedContextTextureId = sharedGL->CreateAndConsumeTextureCHROMIUM(GL
_TEXTURE_2D, m_mailbox.name); |
| 88 |
128 GrGLTextureInfo textureInfo; | 89 GrGLTextureInfo textureInfo; |
129 textureInfo.fTarget = GL_TEXTURE_2D; | 90 textureInfo.fTarget = GL_TEXTURE_2D; |
130 textureInfo.fID = sharedContextTextureId; | 91 textureInfo.fID = sharedContextTextureId; |
131 GrBackendTextureDesc backendTexture; | 92 GrBackendTextureDesc backendTexture; |
132 backendTexture.fOrigin = kBottomLeft_GrSurfaceOrigin; | 93 backendTexture.fOrigin = kBottomLeft_GrSurfaceOrigin; |
133 backendTexture.fWidth = size().width(); | 94 backendTexture.fWidth = size().width(); |
134 backendTexture.fHeight = size().height(); | 95 backendTexture.fHeight = size().height(); |
135 backendTexture.fConfig = kSkia8888_GrPixelConfig; | 96 backendTexture.fConfig = kSkia8888_GrPixelConfig; |
136 backendTexture.fTextureHandle = skia::GrGLTextureInfoToGrBackendObject(textu
reInfo); | 97 backendTexture.fTextureHandle = skia::GrGLTextureInfoToGrBackendObject(textu
reInfo); |
137 | 98 |
138 sk_sp<SkImage> newImage = SkImage::MakeFromAdoptedTexture(sharedGrContext, b
ackendTexture); | 99 m_image = SkImage::MakeFromAdoptedTexture(sharedGrContext, backendTexture); |
139 releaseImageThreadSafe(); | 100 m_imageIsForSharedMainThreadContext = true; |
140 m_image = newImage; | 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 | 102 m_grContext = nullptr; |
142 m_sharedContextId = SharedGpuContext::contextId(); | 103 return m_image; |
143 } | 104 } |
144 | 105 |
145 void AcceleratedStaticBitmapImage::ensureMailbox() | 106 void AcceleratedStaticBitmapImage::ensureMailbox() |
146 { | 107 { |
147 if (m_hasMailbox) | 108 if (m_hasMailbox) |
148 return; | 109 return; |
149 | 110 |
150 DCHECK(m_image); | 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. |
| 112 DCHECK(m_imageIsForSharedMainThreadContext); |
| 113 auto sharedMainThreadContextProvider = wrapUnique(Platform::current()->creat
eSharedOffscreenGraphicsContext3DProvider()); |
151 | 114 |
152 gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); | 115 gpu::gles2::GLES2Interface* sharedGL = sharedMainThreadContextProvider->cont
extGL(); |
153 GrContext* sharedGrContext = SharedGpuContext::gr(); | 116 GrContext* sharedGrContext = sharedMainThreadContextProvider->grContext(); |
154 if (!sharedGrContext) | 117 if (!sharedGrContext) |
155 return; // Can happen if the context is lost, the SkImage won't be any g
ood now anyway. | 118 return; // Can happen if the context is lost, the SkImage won't be any g
ood now anyway. |
| 119 |
156 GLuint imageTextureId = skia::GrBackendObjectToGrGLTextureInfo(m_image->getT
extureHandle(true))->fID; | 120 GLuint imageTextureId = skia::GrBackendObjectToGrGLTextureInfo(m_image->getT
extureHandle(true))->fID; |
157 sharedGL->BindTexture(GL_TEXTURE_2D, imageTextureId); | 121 sharedGL->BindTexture(GL_TEXTURE_2D, imageTextureId); |
158 | 122 |
159 sharedGL->GenMailboxCHROMIUM(m_mailbox.name); | 123 sharedGL->GenMailboxCHROMIUM(m_mailbox.name); |
160 sharedGL->ProduceTextureCHROMIUM(GL_TEXTURE_2D, m_mailbox.name); | 124 sharedGL->ProduceTextureCHROMIUM(GL_TEXTURE_2D, m_mailbox.name); |
161 const GLuint64 fenceSync = sharedGL->InsertFenceSyncCHROMIUM(); | 125 const GLuint64 fenceSync = sharedGL->InsertFenceSyncCHROMIUM(); |
162 sharedGL->Flush(); | 126 sharedGL->Flush(); |
163 sharedGL->GenSyncTokenCHROMIUM(fenceSync, m_syncToken.GetData()); | 127 sharedGL->GenSyncTokenCHROMIUM(fenceSync, m_syncToken.GetData()); |
164 | 128 |
165 sharedGL->BindTexture(GL_TEXTURE_2D, 0); | 129 sharedGL->BindTexture(GL_TEXTURE_2D, 0); |
166 // We changed bound textures in this function, so reset the GrContext. | 130 // We changed bound textures in this function, so reset the GrContext. |
167 sharedGrContext->resetContext(kTextureBinding_GrGLBackendState); | 131 sharedGrContext->resetContext(kTextureBinding_GrGLBackendState); |
168 | 132 |
169 m_hasMailbox = true; | 133 m_hasMailbox = true; |
170 } | 134 } |
171 | 135 |
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 | |
217 } // namespace blink | 136 } // namespace blink |
OLD | NEW |