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 |