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_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