1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "gpu/command_buffer/service/mailbox_manager_sync.h"
10 #include "base/memory/linked_ptr.h"
11 #include "base/synchronization/lock.h"
12 #include "gpu/command_buffer/service/texture_manager.h"
13 #include "ui/gl/gl_fence.h"
14 #include "ui/gl/gl_implementation.h"
16 #if !defined(OS_MACOSX)
17 #include "ui/gl/gl_fence_egl.h"
25 base::LazyInstance
<base::Lock
> g_lock
= LAZY_INSTANCE_INITIALIZER
;
27 typedef std::map
<uint32
, linked_ptr
<gfx::GLFence
>> SyncPointToFenceMap
;
28 base::LazyInstance
<SyncPointToFenceMap
> g_sync_point_to_fence
=
29 LAZY_INSTANCE_INITIALIZER
;
30 #if !defined(OS_MACOSX)
31 base::LazyInstance
<std::queue
<SyncPointToFenceMap::iterator
>> g_sync_points
=
32 LAZY_INSTANCE_INITIALIZER
;
35 void CreateFenceLocked(uint32 sync_point
) {
36 g_lock
.Get().AssertAcquired();
37 if (gfx::GetGLImplementation() == gfx::kGLImplementationMockGL
)
40 #if !defined(OS_MACOSX)
41 std::queue
<SyncPointToFenceMap::iterator
>& sync_points
= g_sync_points
.Get();
42 SyncPointToFenceMap
& sync_point_to_fence
= g_sync_point_to_fence
.Get();
44 while (!sync_points
.empty() &&
45 sync_points
.front()->second
->HasCompleted()) {
46 sync_point_to_fence
.erase(sync_points
.front());
49 // Need to use EGL fences since we are likely not in a single share group.
50 linked_ptr
<gfx::GLFence
> fence(make_linked_ptr(new gfx::GLFenceEGL
));
52 std::pair
<SyncPointToFenceMap::iterator
, bool> result
=
53 sync_point_to_fence
.insert(std::make_pair(sync_point
, fence
));
54 DCHECK(result
.second
);
55 sync_points
.push(result
.first
);
57 DCHECK(sync_points
.size() == sync_point_to_fence
.size());
62 void AcquireFenceLocked(uint32 sync_point
) {
63 g_lock
.Get().AssertAcquired();
64 SyncPointToFenceMap::iterator fence_it
=
65 g_sync_point_to_fence
.Get().find(sync_point
);
66 if (fence_it
!= g_sync_point_to_fence
.Get().end()) {
67 fence_it
->second
->ServerWait();
71 static const unsigned kNewTextureVersion
= 1;
73 } // anonymous namespace
75 base::LazyInstance
<MailboxManagerSync::TextureGroup::MailboxToGroupMap
>
76 MailboxManagerSync::TextureGroup::mailbox_to_group_
=
77 LAZY_INSTANCE_INITIALIZER
;
80 MailboxManagerSync::TextureGroup
*
81 MailboxManagerSync::TextureGroup::CreateFromTexture(const Mailbox
& name
,
82 MailboxManagerSync
* manager
,
84 TextureGroup
* group
= new TextureGroup();
85 group
->AddTexture(manager
, texture
);
87 if (!SkipTextureWorkarounds(texture
)) {
89 TextureDefinition(texture
, kNewTextureVersion
, NULL
);
95 MailboxManagerSync::TextureGroup
* MailboxManagerSync::TextureGroup::FromName(
96 const Mailbox
& name
) {
97 MailboxToGroupMap::iterator it
= mailbox_to_group_
.Get().find(name
);
98 if (it
== mailbox_to_group_
.Get().end())
101 return it
->second
.get();
104 MailboxManagerSync::TextureGroup::TextureGroup() {
107 MailboxManagerSync::TextureGroup::~TextureGroup() {
110 void MailboxManagerSync::TextureGroup::AddName(const Mailbox
& name
) {
111 g_lock
.Get().AssertAcquired();
112 DCHECK(std::find(names_
.begin(), names_
.end(), name
) == names_
.end());
113 names_
.push_back(name
);
114 DCHECK(mailbox_to_group_
.Get().find(name
) == mailbox_to_group_
.Get().end());
115 mailbox_to_group_
.Get()[name
] = this;
118 void MailboxManagerSync::TextureGroup::RemoveName(const Mailbox
& name
) {
119 g_lock
.Get().AssertAcquired();
120 std::vector
<Mailbox
>::iterator names_it
=
121 std::find(names_
.begin(), names_
.end(), name
);
122 DCHECK(names_it
!= names_
.end());
123 names_
.erase(names_it
);
124 MailboxToGroupMap::iterator it
= mailbox_to_group_
.Get().find(name
);
125 DCHECK(it
!= mailbox_to_group_
.Get().end());
126 mailbox_to_group_
.Get().erase(it
);
129 void MailboxManagerSync::TextureGroup::AddTexture(MailboxManagerSync
* manager
,
131 g_lock
.Get().AssertAcquired();
132 DCHECK(std::find(textures_
.begin(), textures_
.end(),
133 std::make_pair(manager
, texture
)) == textures_
.end());
134 textures_
.push_back(std::make_pair(manager
, texture
));
137 bool MailboxManagerSync::TextureGroup::RemoveTexture(
138 MailboxManagerSync
* manager
,
140 g_lock
.Get().AssertAcquired();
141 TextureGroup::TextureList::iterator tex_list_it
= std::find(
142 textures_
.begin(), textures_
.end(), std::make_pair(manager
, texture
));
143 DCHECK(tex_list_it
!= textures_
.end());
144 if (textures_
.size() == 1) {
145 // This is the last texture so the group is going away.
146 for (size_t n
= 0; n
< names_
.size(); n
++) {
147 const Mailbox
& name
= names_
[n
];
148 MailboxToGroupMap::iterator mbox_it
=
149 mailbox_to_group_
.Get().find(name
);
150 DCHECK(mbox_it
!= mailbox_to_group_
.Get().end());
151 DCHECK(mbox_it
->second
.get() == this);
152 mailbox_to_group_
.Get().erase(mbox_it
);
156 textures_
.erase(tex_list_it
);
161 Texture
* MailboxManagerSync::TextureGroup::FindTexture(
162 MailboxManagerSync
* manager
) {
163 g_lock
.Get().AssertAcquired();
164 for (TextureGroup::TextureList::iterator it
= textures_
.begin();
165 it
!= textures_
.end(); it
++) {
166 if (it
->first
== manager
)
172 MailboxManagerSync::TextureGroupRef::TextureGroupRef(unsigned version
,
174 : version(version
), group(group
) {
177 MailboxManagerSync::TextureGroupRef::~TextureGroupRef() {
180 MailboxManagerSync::MailboxManagerSync() {
183 MailboxManagerSync::~MailboxManagerSync() {
184 DCHECK_EQ(0U, texture_to_group_
.size());
188 bool MailboxManagerSync::SkipTextureWorkarounds(const Texture
* texture
) {
189 // Cannot support mips due to support mismatch between
190 // EGL_KHR_gl_texture_2D_image and glEGLImageTargetTexture2DOES for
192 bool has_mips
= texture
->NeedsMips() && texture
->texture_complete();
193 return texture
->target() != GL_TEXTURE_2D
|| has_mips
;
196 bool MailboxManagerSync::UsesSync() {
200 Texture
* MailboxManagerSync::ConsumeTexture(const Mailbox
& mailbox
) {
201 base::AutoLock
lock(g_lock
.Get());
202 TextureGroup
* group
= TextureGroup::FromName(mailbox
);
206 // Check if a texture already exists in this share group.
207 Texture
* texture
= group
->FindTexture(this);
211 // Otherwise create a new texture.
212 texture
= group
->GetDefinition().CreateTexture();
214 DCHECK(!SkipTextureWorkarounds(texture
));
215 texture
->SetMailboxManager(this);
216 group
->AddTexture(this, texture
);
218 TextureGroupRef new_ref
=
219 TextureGroupRef(group
->GetDefinition().version(), group
);
220 texture_to_group_
.insert(std::make_pair(texture
, new_ref
));
226 void MailboxManagerSync::ProduceTexture(const Mailbox
& mailbox
,
228 base::AutoLock
lock(g_lock
.Get());
230 TextureToGroupMap::iterator tex_it
= texture_to_group_
.find(texture
);
231 TextureGroup
* group_for_mailbox
= TextureGroup::FromName(mailbox
);
232 TextureGroup
* group_for_texture
= NULL
;
234 if (tex_it
!= texture_to_group_
.end()) {
235 group_for_texture
= tex_it
->second
.group
.get();
236 DCHECK(group_for_texture
);
237 if (group_for_mailbox
== group_for_texture
) {
238 // The texture is already known under this name.
243 if (group_for_mailbox
) {
244 // Unlink the mailbox from its current group.
245 group_for_mailbox
->RemoveName(mailbox
);
248 if (group_for_texture
) {
249 group_for_texture
->AddName(mailbox
);
251 // This is a new texture, so create a new group.
252 texture
->SetMailboxManager(this);
254 TextureGroup::CreateFromTexture(mailbox
, this, texture
);
255 texture_to_group_
.insert(std::make_pair(
256 texture
, TextureGroupRef(kNewTextureVersion
, group_for_texture
)));
259 DCHECK(texture
->mailbox_manager_
== this);
262 void MailboxManagerSync::TextureDeleted(Texture
* texture
) {
263 base::AutoLock
lock(g_lock
.Get());
264 TextureToGroupMap::iterator tex_it
= texture_to_group_
.find(texture
);
265 DCHECK(tex_it
!= texture_to_group_
.end());
266 TextureGroup
* group_for_texture
= tex_it
->second
.group
.get();
267 if (group_for_texture
->RemoveTexture(this, texture
))
268 UpdateDefinitionLocked(texture
, &tex_it
->second
);
269 texture_to_group_
.erase(tex_it
);
272 void MailboxManagerSync::UpdateDefinitionLocked(
274 TextureGroupRef
* group_ref
) {
275 g_lock
.Get().AssertAcquired();
277 if (SkipTextureWorkarounds(texture
))
280 gfx::GLImage
* gl_image
= texture
->GetLevelImage(texture
->target(), 0);
281 TextureGroup
* group
= group_ref
->group
.get();
282 const TextureDefinition
& definition
= group
->GetDefinition();
283 scoped_refptr
<NativeImageBuffer
> image_buffer
= definition
.image();
285 // Make sure we don't clobber with an older version
286 if (!definition
.IsOlderThan(group_ref
->version
))
289 // Also don't push redundant updates. Note that it would break the
291 if (definition
.Matches(texture
))
294 DCHECK_IMPLIES(gl_image
, image_buffer
.get());
295 if (gl_image
&& !image_buffer
->IsClient(gl_image
)) {
296 LOG(ERROR
) << "MailboxSync: Incompatible attachment";
300 group
->SetDefinition(TextureDefinition(texture
, ++group_ref
->version
,
301 gl_image
? image_buffer
: NULL
));
304 void MailboxManagerSync::PushTextureUpdates(uint32 sync_point
) {
305 base::AutoLock
lock(g_lock
.Get());
307 for (TextureToGroupMap::iterator it
= texture_to_group_
.begin();
308 it
!= texture_to_group_
.end(); it
++) {
309 UpdateDefinitionLocked(it
->first
, &it
->second
);
311 CreateFenceLocked(sync_point
);
314 void MailboxManagerSync::PullTextureUpdates(uint32 sync_point
) {
315 base::AutoLock
lock(g_lock
.Get());
316 AcquireFenceLocked(sync_point
);
318 for (TextureToGroupMap::iterator it
= texture_to_group_
.begin();
319 it
!= texture_to_group_
.end(); it
++) {
320 const TextureDefinition
& definition
= it
->second
.group
->GetDefinition();
321 Texture
* texture
= it
->first
;
322 unsigned& texture_version
= it
->second
.version
;
323 if (texture_version
== definition
.version() ||
324 definition
.IsOlderThan(texture_version
))
326 texture_version
= definition
.version();
327 definition
.UpdateTexture(texture
);