• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "gpu/command_buffer/service/mailbox_synchronizer.h"
6 
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_fence.h"
11 #include "ui/gl/gl_implementation.h"
12 
13 #if !defined(OS_MACOSX)
14 #include "ui/gl/gl_fence_egl.h"
15 #endif
16 
17 namespace gpu {
18 namespace gles2 {
19 
20 namespace {
21 
22 MailboxSynchronizer* g_instance = NULL;
23 
24 }  // anonymous namespace
25 
26 // static
Initialize()27 bool MailboxSynchronizer::Initialize() {
28   DCHECK(!g_instance);
29   DCHECK(gfx::GetGLImplementation() != gfx::kGLImplementationNone)
30       << "GL bindings not initialized";
31   switch (gfx::GetGLImplementation()) {
32     case gfx::kGLImplementationMockGL:
33       break;
34     case gfx::kGLImplementationEGLGLES2:
35 #if !defined(OS_MACOSX)
36       {
37         if (!gfx::g_driver_egl.ext.b_EGL_KHR_image_base ||
38             !gfx::g_driver_egl.ext.b_EGL_KHR_gl_texture_2D_image ||
39             !gfx::g_driver_gl.ext.b_GL_OES_EGL_image ||
40             !gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync) {
41           LOG(WARNING) << "MailboxSync not supported due to missing EGL "
42                           "image/fence support";
43           return false;
44         }
45       }
46       break;
47 #endif
48     default:
49       NOTREACHED();
50       return false;
51   }
52   g_instance = new MailboxSynchronizer;
53   return true;
54 }
55 
56 // static
Terminate()57 void MailboxSynchronizer::Terminate() {
58   DCHECK(g_instance);
59   delete g_instance;
60   g_instance = NULL;
61 }
62 
63 // static
GetInstance()64 MailboxSynchronizer* MailboxSynchronizer::GetInstance() {
65   return g_instance;
66 }
67 
TargetName(unsigned target,const Mailbox & mailbox)68 MailboxSynchronizer::TargetName::TargetName(unsigned target,
69                                             const Mailbox& mailbox)
70     : target(target), mailbox(mailbox) {}
71 
TextureGroup(const TextureDefinition & definition)72 MailboxSynchronizer::TextureGroup::TextureGroup(
73     const TextureDefinition& definition)
74     : definition(definition) {}
75 
~TextureGroup()76 MailboxSynchronizer::TextureGroup::~TextureGroup() {}
77 
TextureVersion(linked_ptr<TextureGroup> group)78 MailboxSynchronizer::TextureVersion::TextureVersion(
79     linked_ptr<TextureGroup> group)
80     : version(group->definition.version()), group(group) {}
81 
~TextureVersion()82 MailboxSynchronizer::TextureVersion::~TextureVersion() {}
83 
MailboxSynchronizer()84 MailboxSynchronizer::MailboxSynchronizer() {}
85 
~MailboxSynchronizer()86 MailboxSynchronizer::~MailboxSynchronizer() {
87   DCHECK_EQ(0U, textures_.size());
88 }
89 
ReassociateMailboxLocked(const TargetName & target_name,TextureGroup * group)90 void MailboxSynchronizer::ReassociateMailboxLocked(
91     const TargetName& target_name,
92     TextureGroup* group) {
93   lock_.AssertAcquired();
94   for (TextureMap::iterator it = textures_.begin(); it != textures_.end();
95        it++) {
96     std::set<TargetName>::iterator mb_it =
97         it->second.group->mailboxes.find(target_name);
98     if (it->second.group != group &&
99         mb_it != it->second.group->mailboxes.end()) {
100       it->second.group->mailboxes.erase(mb_it);
101     }
102   }
103   group->mailboxes.insert(target_name);
104 }
105 
106 linked_ptr<MailboxSynchronizer::TextureGroup>
GetGroupForMailboxLocked(const TargetName & target_name)107 MailboxSynchronizer::GetGroupForMailboxLocked(const TargetName& target_name) {
108   lock_.AssertAcquired();
109   for (TextureMap::iterator it = textures_.begin(); it != textures_.end();
110        it++) {
111     std::set<TargetName>::const_iterator mb_it =
112         it->second.group->mailboxes.find(target_name);
113     if (mb_it != it->second.group->mailboxes.end())
114       return it->second.group;
115   }
116   return make_linked_ptr<MailboxSynchronizer::TextureGroup>(NULL);
117 }
118 
CreateTextureFromMailbox(unsigned target,const Mailbox & mailbox)119 Texture* MailboxSynchronizer::CreateTextureFromMailbox(unsigned target,
120                                                        const Mailbox& mailbox) {
121   base::AutoLock lock(lock_);
122   TargetName target_name(target, mailbox);
123   linked_ptr<TextureGroup> group = GetGroupForMailboxLocked(target_name);
124   if (group.get()) {
125     Texture* new_texture = group->definition.CreateTexture();
126     if (new_texture)
127       textures_.insert(std::make_pair(new_texture, TextureVersion(group)));
128     return new_texture;
129   }
130 
131   return NULL;
132 }
133 
TextureDeleted(Texture * texture)134 void MailboxSynchronizer::TextureDeleted(Texture* texture) {
135   base::AutoLock lock(lock_);
136   TextureMap::iterator it = textures_.find(texture);
137   if (it != textures_.end()) {
138     // TODO: We could avoid the update if this was the last ref.
139     UpdateTextureLocked(it->first, it->second);
140     textures_.erase(it);
141   }
142 }
143 
PushTextureUpdates(MailboxManager * manager,uint32 sync_point)144 void MailboxSynchronizer::PushTextureUpdates(MailboxManager* manager,
145                                              uint32 sync_point) {
146   base::AutoLock lock(lock_);
147   for (MailboxManager::MailboxToTextureMap::const_iterator texture_it =
148            manager->mailbox_to_textures_.begin();
149        texture_it != manager->mailbox_to_textures_.end();
150        texture_it++) {
151     TargetName target_name(texture_it->first.target, texture_it->first.mailbox);
152     Texture* texture = texture_it->second->first;
153     // TODO(sievers): crbug.com/352274
154     // Should probably only fail if it already *has* mipmaps, while allowing
155     // incomplete textures here. Also reconsider how to fail otherwise.
156     bool needs_mips = texture->min_filter() != GL_NEAREST &&
157                       texture->min_filter() != GL_LINEAR;
158     if (target_name.target != GL_TEXTURE_2D || needs_mips)
159       continue;
160 
161     TextureMap::iterator it = textures_.find(texture);
162     if (it != textures_.end()) {
163       TextureVersion& texture_version = it->second;
164       TextureGroup* group = texture_version.group.get();
165       std::set<TargetName>::const_iterator mb_it =
166           group->mailboxes.find(target_name);
167       if (mb_it == group->mailboxes.end()) {
168         // We previously did not associate this texture with the given mailbox.
169         // Unlink other texture groups from the mailbox.
170         ReassociateMailboxLocked(target_name, group);
171       }
172       UpdateTextureLocked(texture, texture_version);
173 
174     } else {
175       // Skip compositor resources/tile textures.
176       // TODO: Remove this, see crbug.com/399226.
177       if (texture->pool() == GL_TEXTURE_POOL_MANAGED_CHROMIUM)
178         continue;
179 
180       linked_ptr<TextureGroup> group = make_linked_ptr(new TextureGroup(
181           TextureDefinition(target_name.target, texture, 1, NULL)));
182 
183       // Unlink other textures from this mailbox in case the name is not new.
184       ReassociateMailboxLocked(target_name, group.get());
185       textures_.insert(std::make_pair(texture, TextureVersion(group)));
186     }
187   }
188 
189   CreateFenceLocked(sync_point);
190 }
191 
CreateFenceLocked(uint32 sync_point)192 void MailboxSynchronizer::CreateFenceLocked(uint32 sync_point) {
193   lock_.AssertAcquired();
194   if (gfx::GetGLImplementation() == gfx::kGLImplementationMockGL)
195     return;
196 
197 #if !defined(OS_MACOSX)
198   if (sync_point) {
199     while (!sync_points_.empty() &&
200            sync_points_.front()->second->HasCompleted()) {
201       sync_point_to_fence_.erase(sync_points_.front());
202       sync_points_.pop();
203     }
204     // Need to use EGL fences since we are likely not in a single share group.
205     linked_ptr<gfx::GLFence> fence(make_linked_ptr(new gfx::GLFenceEGL(true)));
206     if (fence.get()) {
207       std::pair<SyncPointToFenceMap::iterator, bool> result =
208           sync_point_to_fence_.insert(std::make_pair(sync_point, fence));
209       DCHECK(result.second);
210       sync_points_.push(result.first);
211     }
212     DCHECK(sync_points_.size() == sync_point_to_fence_.size());
213   }
214 #endif
215 }
216 
UpdateTextureLocked(Texture * texture,TextureVersion & texture_version)217 void MailboxSynchronizer::UpdateTextureLocked(Texture* texture,
218                                               TextureVersion& texture_version) {
219   lock_.AssertAcquired();
220   gfx::GLImage* gl_image = texture->GetLevelImage(texture->target(), 0);
221   TextureGroup* group = texture_version.group.get();
222   scoped_refptr<NativeImageBuffer> image_buffer = group->definition.image();
223 
224   // Make sure we don't clobber with an older version
225   if (!group->definition.IsOlderThan(texture_version.version))
226     return;
227 
228   // Also don't push redundant updates. Note that it would break the
229   // versioning.
230   if (group->definition.Matches(texture))
231     return;
232 
233   if (gl_image && !image_buffer->IsClient(gl_image)) {
234     LOG(ERROR) << "MailboxSync: Incompatible attachment";
235     return;
236   }
237 
238   group->definition = TextureDefinition(texture->target(),
239                                         texture,
240                                         ++texture_version.version,
241                                         gl_image ? image_buffer : NULL);
242 }
243 
AcquireFenceLocked(uint32 sync_point)244 void MailboxSynchronizer::AcquireFenceLocked(uint32 sync_point) {
245   lock_.AssertAcquired();
246   SyncPointToFenceMap::iterator fence_it =
247       sync_point_to_fence_.find(sync_point);
248   if (fence_it != sync_point_to_fence_.end()) {
249     fence_it->second->ServerWait();
250   }
251 }
252 
PullTextureUpdates(MailboxManager * manager,uint32 sync_point)253 void MailboxSynchronizer::PullTextureUpdates(MailboxManager* manager,
254                                              uint32 sync_point) {
255   base::AutoLock lock(lock_);
256   AcquireFenceLocked(sync_point);
257 
258   for (MailboxManager::MailboxToTextureMap::const_iterator texture_it =
259            manager->mailbox_to_textures_.begin();
260        texture_it != manager->mailbox_to_textures_.end();
261        texture_it++) {
262     Texture* texture = texture_it->second->first;
263     TextureMap::iterator it = textures_.find(texture);
264     if (it != textures_.end()) {
265       TextureDefinition& definition = it->second.group->definition;
266       if (it->second.version == definition.version() ||
267           definition.IsOlderThan(it->second.version))
268         continue;
269       it->second.version = definition.version();
270       definition.UpdateTexture(texture);
271     }
272   }
273 }
274 
275 }  // namespace gles2
276 }  // namespace gpu
277