Handle account removal correctly on all platforms.
[chromium-blink-merge.git] / gpu / command_buffer / service / mailbox_synchronizer.cc
blobeac31f95e48f94db8ad6fa9646bb9ce73b82aaec
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_synchronizer.h"
7 #include "base/bind.h"
8 #include "gpu/command_buffer/service/mailbox_manager.h"
9 #include "gpu/command_buffer/service/texture_manager.h"
10 #include "ui/gl/gl_implementation.h"
12 namespace gpu {
13 namespace gles2 {
15 namespace {
17 MailboxSynchronizer* g_instance = NULL;
19 } // anonymous namespace
21 // static
22 bool MailboxSynchronizer::Initialize() {
23 DCHECK(!g_instance);
24 DCHECK(gfx::GetGLImplementation() != gfx::kGLImplementationNone)
25 << "GL bindings not initialized";
26 switch (gfx::GetGLImplementation()) {
27 case gfx::kGLImplementationMockGL:
28 break;
29 case gfx::kGLImplementationEGLGLES2:
30 #if !defined(OS_MACOSX)
32 if (!gfx::g_driver_egl.ext.b_EGL_KHR_image_base ||
33 !gfx::g_driver_egl.ext.b_EGL_KHR_gl_texture_2D_image ||
34 !gfx::g_driver_gl.ext.b_GL_OES_EGL_image ||
35 !gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync) {
36 LOG(WARNING) << "MailboxSync not supported due to missing EGL "
37 "image/fence support";
38 return false;
41 break;
42 #endif
43 default:
44 NOTREACHED();
45 return false;
47 g_instance = new MailboxSynchronizer;
48 return true;
51 // static
52 void MailboxSynchronizer::Terminate() {
53 DCHECK(g_instance);
54 delete g_instance;
55 g_instance = NULL;
58 // static
59 MailboxSynchronizer* MailboxSynchronizer::GetInstance() {
60 return g_instance;
63 MailboxSynchronizer::TargetName::TargetName(unsigned target,
64 const Mailbox& mailbox)
65 : target(target), mailbox(mailbox) {}
67 MailboxSynchronizer::TextureGroup::TextureGroup(
68 const TextureDefinition& definition)
69 : definition(definition) {}
71 MailboxSynchronizer::TextureGroup::~TextureGroup() {}
73 MailboxSynchronizer::TextureVersion::TextureVersion(
74 linked_ptr<TextureGroup> group)
75 : version(group->definition.version()), group(group) {}
77 MailboxSynchronizer::TextureVersion::~TextureVersion() {}
79 MailboxSynchronizer::MailboxSynchronizer() {}
81 MailboxSynchronizer::~MailboxSynchronizer() {
82 DCHECK_EQ(0U, textures_.size());
85 void MailboxSynchronizer::ReassociateMailboxLocked(
86 const TargetName& target_name,
87 TextureGroup* group) {
88 lock_.AssertAcquired();
89 for (TextureMap::iterator it = textures_.begin(); it != textures_.end();
90 it++) {
91 std::set<TargetName>::iterator mb_it =
92 it->second.group->mailboxes.find(target_name);
93 if (it->second.group != group &&
94 mb_it != it->second.group->mailboxes.end()) {
95 it->second.group->mailboxes.erase(mb_it);
98 group->mailboxes.insert(target_name);
101 linked_ptr<MailboxSynchronizer::TextureGroup>
102 MailboxSynchronizer::GetGroupForMailboxLocked(const TargetName& target_name) {
103 lock_.AssertAcquired();
104 for (TextureMap::iterator it = textures_.begin(); it != textures_.end();
105 it++) {
106 std::set<TargetName>::const_iterator mb_it =
107 it->second.group->mailboxes.find(target_name);
108 if (mb_it != it->second.group->mailboxes.end())
109 return it->second.group;
111 return make_linked_ptr<MailboxSynchronizer::TextureGroup>(NULL);
114 Texture* MailboxSynchronizer::CreateTextureFromMailbox(unsigned target,
115 const Mailbox& mailbox) {
116 base::AutoLock lock(lock_);
117 TargetName target_name(target, mailbox);
118 linked_ptr<TextureGroup> group = GetGroupForMailboxLocked(target_name);
119 if (group.get()) {
120 Texture* new_texture = group->definition.CreateTexture();
121 if (new_texture)
122 textures_.insert(std::make_pair(new_texture, TextureVersion(group)));
123 return new_texture;
126 return NULL;
129 void MailboxSynchronizer::TextureDeleted(Texture* texture) {
130 base::AutoLock lock(lock_);
131 TextureMap::iterator it = textures_.find(texture);
132 if (it != textures_.end()) {
133 // TODO: We could avoid the update if this was the last ref.
134 UpdateTextureLocked(it->first, it->second);
135 textures_.erase(it);
139 void MailboxSynchronizer::PushTextureUpdates(MailboxManager* manager) {
140 base::AutoLock lock(lock_);
141 for (MailboxManager::MailboxToTextureMap::const_iterator texture_it =
142 manager->mailbox_to_textures_.begin();
143 texture_it != manager->mailbox_to_textures_.end();
144 texture_it++) {
145 TargetName target_name(texture_it->first.target, texture_it->first.mailbox);
146 Texture* texture = texture_it->second->first;
147 // TODO(sievers): crbug.com/352274
148 // Should probably only fail if it already *has* mipmaps, while allowing
149 // incomplete textures here. Also reconsider how to fail otherwise.
150 bool needs_mips = texture->min_filter() != GL_NEAREST &&
151 texture->min_filter() != GL_LINEAR;
152 if (target_name.target != GL_TEXTURE_2D || needs_mips)
153 continue;
155 TextureMap::iterator it = textures_.find(texture);
156 if (it != textures_.end()) {
157 TextureVersion& texture_version = it->second;
158 TextureGroup* group = texture_version.group.get();
159 std::set<TargetName>::const_iterator mb_it =
160 group->mailboxes.find(target_name);
161 if (mb_it == group->mailboxes.end()) {
162 // We previously did not associate this texture with the given mailbox.
163 // Unlink other texture groups from the mailbox.
164 ReassociateMailboxLocked(target_name, group);
166 UpdateTextureLocked(texture, texture_version);
168 } else {
169 // Skip compositor resources/tile textures.
170 // TODO: Remove this, see crbug.com/399226.
171 if (texture->pool() == GL_TEXTURE_POOL_MANAGED_CHROMIUM)
172 continue;
174 linked_ptr<TextureGroup> group = make_linked_ptr(new TextureGroup(
175 TextureDefinition(target_name.target, texture, 1, NULL)));
177 // Unlink other textures from this mailbox in case the name is not new.
178 ReassociateMailboxLocked(target_name, group.get());
179 textures_.insert(std::make_pair(texture, TextureVersion(group)));
184 void MailboxSynchronizer::UpdateTextureLocked(Texture* texture,
185 TextureVersion& texture_version) {
186 lock_.AssertAcquired();
187 gfx::GLImage* gl_image = texture->GetLevelImage(texture->target(), 0);
188 TextureGroup* group = texture_version.group.get();
189 scoped_refptr<NativeImageBuffer> image_buffer = group->definition.image();
191 // Make sure we don't clobber with an older version
192 if (!group->definition.IsOlderThan(texture_version.version))
193 return;
195 // Also don't push redundant updates. Note that it would break the
196 // versioning.
197 if (group->definition.Matches(texture))
198 return;
200 if (gl_image && !image_buffer->IsClient(gl_image)) {
201 LOG(ERROR) << "MailboxSync: Incompatible attachment";
202 return;
205 group->definition = TextureDefinition(texture->target(),
206 texture,
207 ++texture_version.version,
208 gl_image ? image_buffer : NULL);
211 void MailboxSynchronizer::PullTextureUpdates(MailboxManager* manager) {
212 base::AutoLock lock(lock_);
213 for (MailboxManager::MailboxToTextureMap::const_iterator texture_it =
214 manager->mailbox_to_textures_.begin();
215 texture_it != manager->mailbox_to_textures_.end();
216 texture_it++) {
217 Texture* texture = texture_it->second->first;
218 TextureMap::iterator it = textures_.find(texture);
219 if (it != textures_.end()) {
220 TextureDefinition& definition = it->second.group->definition;
221 if (it->second.version == definition.version() ||
222 definition.IsOlderThan(it->second.version))
223 continue;
224 it->second.version = definition.version();
225 definition.UpdateTexture(texture);
230 } // namespace gles2
231 } // namespace gpu