Home | History | Annotate | Download | only in service
      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
     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
     57 void MailboxSynchronizer::Terminate() {
     58   DCHECK(g_instance);
     59   delete g_instance;
     60   g_instance = NULL;
     61 }
     62 
     63 // static
     64 MailboxSynchronizer* MailboxSynchronizer::GetInstance() {
     65   return g_instance;
     66 }
     67 
     68 MailboxSynchronizer::TargetName::TargetName(unsigned target,
     69                                             const Mailbox& mailbox)
     70     : target(target), mailbox(mailbox) {}
     71 
     72 MailboxSynchronizer::TextureGroup::TextureGroup(
     73     const TextureDefinition& definition)
     74     : definition(definition) {}
     75 
     76 MailboxSynchronizer::TextureGroup::~TextureGroup() {}
     77 
     78 MailboxSynchronizer::TextureVersion::TextureVersion(
     79     linked_ptr<TextureGroup> group)
     80     : version(group->definition.version()), group(group) {}
     81 
     82 MailboxSynchronizer::TextureVersion::~TextureVersion() {}
     83 
     84 MailboxSynchronizer::MailboxSynchronizer() {}
     85 
     86 MailboxSynchronizer::~MailboxSynchronizer() {
     87   DCHECK_EQ(0U, textures_.size());
     88 }
     89 
     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>
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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