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/graphics/StaticBitmapImage.h" | 10 #include "platform/graphics/SkiaTextureHolder.h" |
11 #include "platform/graphics/gpu/SharedGpuContext.h" | 11 #include "platform/graphics/gpu/SharedGpuContext.h" |
12 #include "platform/graphics/skia/SkiaUtils.h" | 12 #include "platform/graphics/skia/SkiaUtils.h" |
13 #include "public/platform/Platform.h" | 13 #include "public/platform/Platform.h" |
14 #include "public/platform/WebGraphicsContext3DProvider.h" | 14 #include "public/platform/WebGraphicsContext3DProvider.h" |
15 #include "public/platform/WebTaskRunner.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 gpu::gles2::GLES2Interface* gl, |
| 35 IntSize mailboxSize) { |
| 36 return adoptRef(new AcceleratedStaticBitmapImage(mailbox, syncToken, |
| 37 textureId, gl, 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_texture = 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 gpu::gles2::GLES2Interface* gl, |
53 m_hasMailbox(true), | 51 IntSize mailboxSize) { |
54 m_mailbox(mailbox), | 52 m_texture = |
55 m_syncToken(syncToken) { | 53 new MailboxTextureHolder(mailbox, syncToken, textureId, gl, 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 // Avoid leaking mailboxes in cases where the texture gets recycled by skia. |
65 if (m_hasMailbox && SharedGpuContext::isValid()) | 59 if (!m_texture->isSkiaTextureHolder() && SharedGpuContext::isValid()) { |
66 SharedGpuContext::gl()->ProduceTextureDirectCHROMIUM(0, GL_TEXTURE_2D, | 60 SharedGpuContext::gl()->ProduceTextureDirectCHROMIUM( |
67 m_mailbox.name); | 61 0, GL_TEXTURE_2D, m_texture->getMailbox().name); |
68 releaseImageThreadSafe(); | 62 } |
| 63 // Do release image only when it is a skiaTextureHolder |
| 64 if (m_texture->isSkiaTextureHolder()) |
| 65 m_texture->releaseImageThreadSafe(); |
| 66 } |
| 67 |
| 68 IntSize AcceleratedStaticBitmapImage::size() const { |
| 69 return m_texture->size(); |
69 } | 70 } |
70 | 71 |
71 void AcceleratedStaticBitmapImage::copyToTexture( | 72 void AcceleratedStaticBitmapImage::copyToTexture( |
72 WebGraphicsContext3DProvider* destProvider, | 73 WebGraphicsContext3DProvider* destProvider, |
73 GLuint destTextureId, | 74 GLuint destTextureId, |
74 GLenum internalFormat, | 75 GLenum internalFormat, |
75 GLenum destType, | 76 GLenum destType, |
76 bool flipY) { | 77 bool flipY) { |
77 checkThread(); | 78 checkThread(); |
78 if (!isValid()) | 79 if (!isValid()) |
79 return; | 80 return; |
80 // |destProvider| may not be the same context as the one used for |m_image|, | 81 // |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. | 82 // so we use a mailbox to generate a texture id for |destProvider| to access. |
82 ensureMailbox(); | 83 ensureMailbox(); |
83 | 84 |
84 // Get a texture id that |destProvider| knows about and copy from it. | 85 // Get a texture id that |destProvider| knows about and copy from it. |
85 gpu::gles2::GLES2Interface* destGL = destProvider->contextGL(); | 86 gpu::gles2::GLES2Interface* destGL = destProvider->contextGL(); |
86 destGL->WaitSyncTokenCHROMIUM(m_syncToken.GetData()); | 87 destGL->WaitSyncTokenCHROMIUM(m_texture->getSyncToken().GetData()); |
87 GLuint sourceTextureId = | 88 GLuint sourceTextureId = destGL->CreateAndConsumeTextureCHROMIUM( |
88 destGL->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, m_mailbox.name); | 89 GL_TEXTURE_2D, m_texture->getMailbox().name); |
89 destGL->CopyTextureCHROMIUM(sourceTextureId, destTextureId, internalFormat, | 90 destGL->CopyTextureCHROMIUM(sourceTextureId, destTextureId, internalFormat, |
90 destType, flipY, false, false); | 91 destType, flipY, false, false); |
91 // This drops the |destGL| context's reference on our |m_mailbox|, but it's | 92 // This drops the |destGL| context's reference on our |m_mailbox|, but it's |
92 // still held alive by our SkImage. | 93 // still held alive by our SkImage. |
93 destGL->DeleteTextures(1, &sourceTextureId); | 94 destGL->DeleteTextures(1, &sourceTextureId); |
94 } | 95 } |
95 | 96 |
96 sk_sp<SkImage> AcceleratedStaticBitmapImage::imageForCurrentFrame() { | 97 sk_sp<SkImage> AcceleratedStaticBitmapImage::imageForCurrentFrame() { |
97 checkThread(); | 98 checkThread(); |
98 if (!isValid()) | 99 if (!isValid()) |
99 return nullptr; | 100 return nullptr; |
100 createImageFromMailboxIfNeeded(); | 101 createImageFromMailboxIfNeeded(); |
101 return m_image; | 102 return m_texture->getSkImage(); |
102 } | 103 } |
103 | 104 |
104 void AcceleratedStaticBitmapImage::draw( | 105 void AcceleratedStaticBitmapImage::draw( |
105 SkCanvas* canvas, | 106 SkCanvas* canvas, |
106 const SkPaint& paint, | 107 const SkPaint& paint, |
107 const FloatRect& dstRect, | 108 const FloatRect& dstRect, |
108 const FloatRect& srcRect, | 109 const FloatRect& srcRect, |
109 RespectImageOrientationEnum respectImageOrientation, | 110 RespectImageOrientationEnum respectImageOrientation, |
110 ImageClampingMode imageClampingMode) { | 111 ImageClampingMode imageClampingMode) { |
111 checkThread(); | 112 checkThread(); |
112 if (!isValid()) | 113 if (!isValid()) |
113 return; | 114 return; |
114 createImageFromMailboxIfNeeded(); | 115 createImageFromMailboxIfNeeded(); |
| 116 m_image = m_texture->getSkImage(); |
115 StaticBitmapImage::draw(canvas, paint, dstRect, srcRect, | 117 StaticBitmapImage::draw(canvas, paint, dstRect, srcRect, |
116 respectImageOrientation, imageClampingMode); | 118 respectImageOrientation, imageClampingMode); |
117 } | 119 } |
118 | 120 |
119 bool AcceleratedStaticBitmapImage::isValid() { | 121 bool AcceleratedStaticBitmapImage::isValid() { |
120 if (!m_image) | 122 if (!m_texture) |
121 return false; | 123 return false; |
122 if (!SharedGpuContext::isValid()) | 124 if (!SharedGpuContext::isValid()) |
123 return false; // Gpu context was lost | 125 return false; // Gpu context was lost |
124 if (imageBelongsToSharedContext() && | 126 unsigned sharedContextId = m_texture->sharedContextId(); |
125 m_sharedContextId != SharedGpuContext::contextId()) { | 127 if (sharedContextId != SharedGpuContext::kNoSharedContext && |
| 128 sharedContextId != SharedGpuContext::contextId()) { |
126 // Gpu context was lost and restored since the resource was created. | 129 // Gpu context was lost and restored since the resource was created. |
127 return false; | 130 return false; |
128 } | 131 } |
129 return true; | 132 return true; |
130 } | 133 } |
131 | 134 |
132 bool AcceleratedStaticBitmapImage::imageBelongsToSharedContext() { | |
133 return m_sharedContextId != SharedGpuContext::kNoSharedContext; | |
134 } | |
135 | |
136 void AcceleratedStaticBitmapImage::createImageFromMailboxIfNeeded() { | 135 void AcceleratedStaticBitmapImage::createImageFromMailboxIfNeeded() { |
137 if (imageBelongsToSharedContext()) | 136 if (m_texture->sharedContextId() != SharedGpuContext::kNoSharedContext) |
138 return; | 137 return; |
139 DCHECK(m_hasMailbox); | 138 if (m_texture->isSkiaTextureHolder()) |
140 gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); | 139 return; |
141 GrContext* sharedGrContext = SharedGpuContext::gr(); | 140 m_texture = |
142 DCHECK(sharedGL && | 141 new SkiaTextureHolder(m_texture->getMailbox(), m_texture->getSyncToken(), |
143 sharedGrContext); // context isValid already checked in callers | 142 m_texture->getMailboxSize()); |
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 } | 143 } |
166 | 144 |
167 void AcceleratedStaticBitmapImage::ensureMailbox() { | 145 void AcceleratedStaticBitmapImage::ensureMailbox() { |
168 if (m_hasMailbox) | 146 if (!m_texture->isSkiaTextureHolder()) |
169 return; | 147 return; |
170 | 148 |
171 DCHECK(m_image); | 149 sk_sp<SkImage> image = m_texture->getSkImage(); |
| 150 DCHECK(image); |
172 | 151 |
173 gpu::gles2::GLES2Interface* sharedGL = SharedGpuContext::gl(); | 152 m_texture = new MailboxTextureHolder(std::move(image)); |
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 } | 153 } |
197 | 154 |
198 void AcceleratedStaticBitmapImage::transfer() { | 155 void AcceleratedStaticBitmapImage::transfer() { |
199 checkThread(); | 156 checkThread(); |
200 ensureMailbox(); | 157 ensureMailbox(); |
201 m_sharedContextId = SharedGpuContext::kNoSharedContext; | |
202 // If |m_imageThread| is set, it means that the image has been consumed on the | |
203 // current thread, which may happen when we have chained transfers. When that | |
204 // is the case, we must not reset |m_imageThread|, so we ensure that | |
205 // releaseImage() is called on the right thread. | |
206 if (!m_imageThread) | |
207 m_imageThread = Platform::current()->currentThread(); | |
208 m_detachThreadAtNextCheck = true; | 158 m_detachThreadAtNextCheck = true; |
209 } | 159 } |
210 | 160 |
211 void AcceleratedStaticBitmapImage::checkThread() { | 161 void AcceleratedStaticBitmapImage::checkThread() { |
212 if (m_detachThreadAtNextCheck) { | 162 if (m_detachThreadAtNextCheck) { |
213 m_threadChecker.DetachFromThread(); | 163 m_threadChecker.DetachFromThread(); |
214 m_detachThreadAtNextCheck = false; | 164 m_detachThreadAtNextCheck = false; |
215 } | 165 } |
216 CHECK(m_threadChecker.CalledOnValidThread()); | 166 CHECK(m_threadChecker.CalledOnValidThread()); |
217 } | 167 } |
218 | 168 |
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 | 169 } // namespace blink |
OLD | NEW |