Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / gpu / command_buffer / service / mailbox_synchronizer.cc
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_implementation.h"
11
12 namespace gpu {
13 namespace gles2 {
14
15 namespace {
16
17 MailboxSynchronizer* g_instance = NULL;
18
19 }  // anonymous namespace
20
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)
31       {
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;
39         }
40       }
41       break;
42 #endif
43     default:
44       NOTREACHED();
45       return false;
46   }
47   g_instance = new MailboxSynchronizer;
48   return true;
49 }
50
51 // static
52 void MailboxSynchronizer::Terminate() {
53   DCHECK(g_instance);
54   delete g_instance;
55   g_instance = NULL;
56 }
57
58 // static
59 MailboxSynchronizer* MailboxSynchronizer::GetInstance() {
60   return g_instance;
61 }
62
63 MailboxSynchronizer::TargetName::TargetName(unsigned target,
64                                             const Mailbox& mailbox)
65     : target(target), mailbox(mailbox) {}
66
67 MailboxSynchronizer::TextureGroup::TextureGroup(
68     const TextureDefinition& definition)
69     : definition(definition) {}
70
71 MailboxSynchronizer::TextureGroup::~TextureGroup() {}
72
73 MailboxSynchronizer::TextureVersion::TextureVersion(
74     linked_ptr<TextureGroup> group)
75     : version(group->definition.version()), group(group) {}
76
77 MailboxSynchronizer::TextureVersion::~TextureVersion() {}
78
79 MailboxSynchronizer::MailboxSynchronizer() {}
80
81 MailboxSynchronizer::~MailboxSynchronizer() {
82   DCHECK_EQ(0U, textures_.size());
83 }
84
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);
96     }
97   }
98   group->mailboxes.insert(target_name);
99 }
100
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;
110   }
111   return make_linked_ptr<MailboxSynchronizer::TextureGroup>(NULL);
112 }
113
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;
124   }
125
126   return NULL;
127 }
128
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);
136   }
137 }
138
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;
154
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);
165       }
166       UpdateTextureLocked(texture, texture_version);
167
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;
173
174       linked_ptr<TextureGroup> group = make_linked_ptr(new TextureGroup(
175           TextureDefinition(target_name.target, texture, 1, NULL)));
176
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)));
180     }
181   }
182 }
183
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();
190
191   // Make sure we don't clobber with an older version
192   if (!group->definition.IsOlderThan(texture_version.version))
193     return;
194
195   // Also don't push redundant updates. Note that it would break the
196   // versioning.
197   if (group->definition.Matches(texture))
198     return;
199
200   if (gl_image && !image_buffer->IsClient(gl_image)) {
201     LOG(ERROR) << "MailboxSync: Incompatible attachment";
202     return;
203   }
204
205   group->definition = TextureDefinition(texture->target(),
206                                         texture,
207                                         ++texture_version.version,
208                                         gl_image ? image_buffer : NULL);
209 }
210
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);
226     }
227   }
228 }
229
230 }  // namespace gles2
231 }  // namespace gpu