Fix crash in SpeechRecognizerImpl introduced in AudioParams refactor.
[chromium-blink-merge.git] / gpu / command_buffer / service / mailbox_manager_sync.cc
blobbe12b3a8fe86cbe3408c57cbfb65ca6411ddaec2
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"
7 #include <algorithm>
8 #include <queue>
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"
18 #endif
20 namespace gpu {
21 namespace gles2 {
23 namespace {
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;
33 #endif
35 void CreateFenceLocked(uint32 sync_point) {
36 g_lock.Get().AssertAcquired();
37 if (gfx::GetGLImplementation() == gfx::kGLImplementationMockGL)
38 return;
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();
43 if (sync_point) {
44 while (!sync_points.empty() &&
45 sync_points.front()->second->HasCompleted()) {
46 sync_point_to_fence.erase(sync_points.front());
47 sync_points.pop();
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));
51 if (fence.get()) {
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());
59 #endif
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;
79 // static
80 MailboxManagerSync::TextureGroup* MailboxManagerSync::TextureGroup::FromName(
81 const Mailbox& name) {
82 MailboxToGroupMap::iterator it = mailbox_to_group_.Get().find(name);
83 if (it == mailbox_to_group_.Get().end())
84 return NULL;
86 return it->second.get();
89 MailboxManagerSync::TextureGroup::TextureGroup(
90 const TextureDefinition& definition)
91 : definition_(definition) {
94 MailboxManagerSync::TextureGroup::~TextureGroup() {
97 void MailboxManagerSync::TextureGroup::AddName(const Mailbox& name) {
98 g_lock.Get().AssertAcquired();
99 DCHECK(std::find(names_.begin(), names_.end(), name) == names_.end());
100 names_.push_back(name);
101 DCHECK(mailbox_to_group_.Get().find(name) == mailbox_to_group_.Get().end());
102 mailbox_to_group_.Get()[name] = this;
105 void MailboxManagerSync::TextureGroup::RemoveName(const Mailbox& name) {
106 g_lock.Get().AssertAcquired();
107 std::vector<Mailbox>::iterator names_it =
108 std::find(names_.begin(), names_.end(), name);
109 DCHECK(names_it != names_.end());
110 names_.erase(names_it);
111 MailboxToGroupMap::iterator it = mailbox_to_group_.Get().find(name);
112 DCHECK(it != mailbox_to_group_.Get().end());
113 mailbox_to_group_.Get().erase(it);
116 void MailboxManagerSync::TextureGroup::AddTexture(MailboxManagerSync* manager,
117 Texture* texture) {
118 g_lock.Get().AssertAcquired();
119 DCHECK(std::find(textures_.begin(), textures_.end(),
120 std::make_pair(manager, texture)) == textures_.end());
121 textures_.push_back(std::make_pair(manager, texture));
124 bool MailboxManagerSync::TextureGroup::RemoveTexture(
125 MailboxManagerSync* manager,
126 Texture* texture) {
127 g_lock.Get().AssertAcquired();
128 TextureGroup::TextureList::iterator tex_list_it = std::find(
129 textures_.begin(), textures_.end(), std::make_pair(manager, texture));
130 DCHECK(tex_list_it != textures_.end());
131 if (textures_.size() == 1) {
132 // This is the last texture so the group is going away.
133 for (size_t n = 0; n < names_.size(); n++) {
134 const Mailbox& name = names_[n];
135 MailboxToGroupMap::iterator mbox_it =
136 mailbox_to_group_.Get().find(name);
137 DCHECK(mbox_it != mailbox_to_group_.Get().end());
138 DCHECK(mbox_it->second.get() == this);
139 mailbox_to_group_.Get().erase(mbox_it);
141 return false;
142 } else {
143 textures_.erase(tex_list_it);
144 return true;
148 Texture* MailboxManagerSync::TextureGroup::FindTexture(
149 MailboxManagerSync* manager) {
150 g_lock.Get().AssertAcquired();
151 for (TextureGroup::TextureList::iterator it = textures_.begin();
152 it != textures_.end(); it++) {
153 if (it->first == manager)
154 return it->second;
156 return NULL;
159 MailboxManagerSync::TextureGroupRef::TextureGroupRef(unsigned version,
160 TextureGroup* group)
161 : version(version), group(group) {
164 MailboxManagerSync::TextureGroupRef::~TextureGroupRef() {
167 MailboxManagerSync::MailboxManagerSync() {
170 MailboxManagerSync::~MailboxManagerSync() {
171 DCHECK_EQ(0U, texture_to_group_.size());
174 // static
175 bool MailboxManagerSync::SkipTextureWorkarounds(const Texture* texture) {
176 // Cannot support mips due to support mismatch between
177 // EGL_KHR_gl_texture_2D_image and glEGLImageTargetTexture2DOES for
178 // texture levels.
179 bool has_mips = texture->NeedsMips() && texture->texture_complete();
180 return texture->target() != GL_TEXTURE_2D || has_mips;
183 bool MailboxManagerSync::UsesSync() {
184 return true;
187 Texture* MailboxManagerSync::ConsumeTexture(const Mailbox& mailbox) {
188 base::AutoLock lock(g_lock.Get());
189 TextureGroup* group = TextureGroup::FromName(mailbox);
190 if (!group)
191 return NULL;
193 // Check if a texture already exists in this share group.
194 Texture* texture = group->FindTexture(this);
195 if (texture)
196 return texture;
198 // Otherwise create a new texture.
199 texture = group->GetDefinition().CreateTexture();
200 if (texture) {
201 DCHECK(!SkipTextureWorkarounds(texture));
202 texture->SetMailboxManager(this);
203 group->AddTexture(this, texture);
205 TextureGroupRef new_ref =
206 TextureGroupRef(group->GetDefinition().version(), group);
207 texture_to_group_.insert(std::make_pair(texture, new_ref));
210 return texture;
213 void MailboxManagerSync::ProduceTexture(const Mailbox& mailbox,
214 Texture* texture) {
215 base::AutoLock lock(g_lock.Get());
217 TextureToGroupMap::iterator tex_it = texture_to_group_.find(texture);
218 TextureGroup* group_for_mailbox = TextureGroup::FromName(mailbox);
219 TextureGroup* group_for_texture = NULL;
221 if (tex_it != texture_to_group_.end()) {
222 group_for_texture = tex_it->second.group.get();
223 DCHECK(group_for_texture);
224 if (group_for_mailbox == group_for_texture) {
225 // The texture is already known under this name.
226 return;
230 if (group_for_mailbox) {
231 // Unlink the mailbox from its current group.
232 group_for_mailbox->RemoveName(mailbox);
235 if (group_for_texture) {
236 group_for_texture->AddName(mailbox);
237 } else {
238 // This is a new texture, so create a new group.
239 texture->SetMailboxManager(this);
240 TextureDefinition definition;
241 if (!SkipTextureWorkarounds(texture)) {
242 base::AutoUnlock unlock(g_lock.Get());
243 definition = TextureDefinition(texture, kNewTextureVersion, NULL);
245 group_for_texture = new TextureGroup(definition);
246 group_for_texture->AddTexture(this, texture);
247 group_for_texture->AddName(mailbox);
248 texture_to_group_.insert(std::make_pair(
249 texture, TextureGroupRef(kNewTextureVersion, group_for_texture)));
252 DCHECK(texture->mailbox_manager_ == this);
255 void MailboxManagerSync::TextureDeleted(Texture* texture) {
256 base::AutoLock lock(g_lock.Get());
257 TextureToGroupMap::iterator tex_it = texture_to_group_.find(texture);
258 DCHECK(tex_it != texture_to_group_.end());
259 TextureGroup* group_for_texture = tex_it->second.group.get();
260 if (group_for_texture->RemoveTexture(this, texture))
261 UpdateDefinitionLocked(texture, &tex_it->second);
262 texture_to_group_.erase(tex_it);
265 void MailboxManagerSync::UpdateDefinitionLocked(
266 Texture* texture,
267 TextureGroupRef* group_ref) {
268 g_lock.Get().AssertAcquired();
270 if (SkipTextureWorkarounds(texture))
271 return;
273 gfx::GLImage* gl_image = texture->GetLevelImage(texture->target(), 0);
274 TextureGroup* group = group_ref->group.get();
275 const TextureDefinition& definition = group->GetDefinition();
276 scoped_refptr<NativeImageBuffer> image_buffer = definition.image();
278 // Make sure we don't clobber with an older version
279 if (!definition.IsOlderThan(group_ref->version))
280 return;
282 // Also don't push redundant updates. Note that it would break the
283 // versioning.
284 if (definition.Matches(texture))
285 return;
287 DCHECK_IMPLIES(gl_image, image_buffer.get());
288 if (gl_image && !image_buffer->IsClient(gl_image)) {
289 LOG(ERROR) << "MailboxSync: Incompatible attachment";
290 return;
293 group->SetDefinition(TextureDefinition(texture, ++group_ref->version,
294 gl_image ? image_buffer : NULL));
297 void MailboxManagerSync::PushTextureUpdates(uint32 sync_point) {
298 base::AutoLock lock(g_lock.Get());
300 for (TextureToGroupMap::iterator it = texture_to_group_.begin();
301 it != texture_to_group_.end(); it++) {
302 UpdateDefinitionLocked(it->first, &it->second);
304 CreateFenceLocked(sync_point);
307 void MailboxManagerSync::PullTextureUpdates(uint32 sync_point) {
308 using TextureUpdatePair = std::pair<Texture*, TextureDefinition>;
309 std::vector<TextureUpdatePair> needs_update;
311 base::AutoLock lock(g_lock.Get());
312 AcquireFenceLocked(sync_point);
314 for (TextureToGroupMap::iterator it = texture_to_group_.begin();
315 it != texture_to_group_.end(); it++) {
316 const TextureDefinition& definition = it->second.group->GetDefinition();
317 Texture* texture = it->first;
318 unsigned& texture_version = it->second.version;
319 if (texture_version == definition.version() ||
320 definition.IsOlderThan(texture_version))
321 continue;
322 texture_version = definition.version();
323 needs_update.push_back(TextureUpdatePair(texture, definition));
327 if (!needs_update.empty()) {
328 ScopedUpdateTexture scoped_update_texture;
329 for (const TextureUpdatePair& pair : needs_update) {
330 pair.second.UpdateTexture(pair.first);
335 } // namespace gles2
336 } // namespace gpu