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 linked_ptr<TextureGroup> group = make_linked_ptr(new TextureGroup( 170 TextureDefinition(target_name.target, texture, 1, NULL))); 171 172 // Unlink other textures from this mailbox in case the name is not new. 173 ReassociateMailboxLocked(target_name, group.get()); 174 textures_.insert(std::make_pair(texture, TextureVersion(group))); 175 } 176 } 177 // Make sure all write fences are flushed. 178 glFlush(); 179 } 180 181 void MailboxSynchronizer::UpdateTextureLocked(Texture* texture, 182 TextureVersion& texture_version) { 183 lock_.AssertAcquired(); 184 gfx::GLImage* gl_image = texture->GetLevelImage(texture->target(), 0); 185 TextureGroup* group = texture_version.group.get(); 186 scoped_refptr<NativeImageBuffer> image_buffer = group->definition.image(); 187 188 // Make sure we don't clobber with an older version 189 if (!group->definition.IsOlderThan(texture_version.version)) 190 return; 191 192 // Also don't push redundant updates. Note that it would break the 193 // versioning. 194 if (group->definition.Matches(texture)) 195 return; 196 197 if (gl_image && !image_buffer->IsClient(gl_image)) { 198 LOG(ERROR) << "MailboxSync: Incompatible attachment"; 199 return; 200 } 201 202 group->definition = TextureDefinition(texture->target(), 203 texture, 204 ++texture_version.version, 205 gl_image ? image_buffer : NULL); 206 } 207 208 void MailboxSynchronizer::PullTextureUpdates(MailboxManager* manager) { 209 base::AutoLock lock(lock_); 210 for (MailboxManager::MailboxToTextureMap::const_iterator texture_it = 211 manager->mailbox_to_textures_.begin(); 212 texture_it != manager->mailbox_to_textures_.end(); 213 texture_it++) { 214 Texture* texture = texture_it->second->first; 215 TextureMap::iterator it = textures_.find(texture); 216 if (it != textures_.end()) { 217 TextureDefinition& definition = it->second.group->definition; 218 if (it->second.version == definition.version() || 219 definition.IsOlderThan(it->second.version)) 220 continue; 221 it->second.version = definition.version(); 222 definition.UpdateTexture(texture); 223 } 224 } 225 } 226 227 } // namespace gles2 228 } // namespace gpu 229