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/texture_definition.h"
      6 
      7 #include <list>
      8 
      9 #include "base/memory/linked_ptr.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/synchronization/lock.h"
     12 #include "gpu/command_buffer/service/texture_manager.h"
     13 #include "ui/gl/gl_image.h"
     14 #include "ui/gl/gl_implementation.h"
     15 #include "ui/gl/scoped_binders.h"
     16 
     17 #if !defined(OS_MACOSX)
     18 #include "ui/gl/gl_surface_egl.h"
     19 #endif
     20 
     21 namespace gpu {
     22 namespace gles2 {
     23 
     24 namespace {
     25 
     26 class GLImageSync : public gfx::GLImage {
     27  public:
     28   explicit GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer,
     29                        const gfx::Size& size);
     30 
     31   // Implement GLImage.
     32   virtual void Destroy(bool have_context) OVERRIDE;
     33   virtual gfx::Size GetSize() OVERRIDE;
     34   virtual bool BindTexImage(unsigned target) OVERRIDE;
     35   virtual void ReleaseTexImage(unsigned target) OVERRIDE;
     36   virtual bool CopyTexImage(unsigned target) OVERRIDE;
     37   virtual void WillUseTexImage() OVERRIDE;
     38   virtual void WillModifyTexImage() OVERRIDE;
     39   virtual void DidModifyTexImage() OVERRIDE;
     40   virtual void DidUseTexImage() OVERRIDE;
     41   virtual bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
     42                                     int z_order,
     43                                     gfx::OverlayTransform transform,
     44                                     const gfx::Rect& bounds_rect,
     45                                     const gfx::RectF& crop_rect) OVERRIDE;
     46   virtual void SetReleaseAfterUse() OVERRIDE;
     47 
     48  protected:
     49   virtual ~GLImageSync();
     50 
     51  private:
     52   scoped_refptr<NativeImageBuffer> buffer_;
     53   gfx::Size size_;
     54 
     55   DISALLOW_COPY_AND_ASSIGN(GLImageSync);
     56 };
     57 
     58 GLImageSync::GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer,
     59                          const gfx::Size& size)
     60     : buffer_(buffer), size_(size) {
     61   if (buffer.get())
     62     buffer->AddClient(this);
     63 }
     64 
     65 GLImageSync::~GLImageSync() {
     66   if (buffer_.get())
     67     buffer_->RemoveClient(this);
     68 }
     69 
     70 void GLImageSync::Destroy(bool have_context) {
     71 }
     72 
     73 gfx::Size GLImageSync::GetSize() {
     74   return size_;
     75 }
     76 
     77 bool GLImageSync::BindTexImage(unsigned target) {
     78   NOTREACHED();
     79   return false;
     80 }
     81 
     82 void GLImageSync::ReleaseTexImage(unsigned target) {
     83   NOTREACHED();
     84 }
     85 
     86 bool GLImageSync::CopyTexImage(unsigned target) {
     87   return false;
     88 }
     89 
     90 void GLImageSync::WillUseTexImage() {
     91 }
     92 
     93 void GLImageSync::DidUseTexImage() {
     94 }
     95 
     96 void GLImageSync::WillModifyTexImage() {
     97 }
     98 
     99 void GLImageSync::DidModifyTexImage() {
    100 }
    101 
    102 bool GLImageSync::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
    103                                        int z_order,
    104                                        gfx::OverlayTransform transform,
    105                                        const gfx::Rect& bounds_rect,
    106                                        const gfx::RectF& crop_rect) {
    107   NOTREACHED();
    108   return false;
    109 }
    110 
    111 void GLImageSync::SetReleaseAfterUse() {
    112   NOTREACHED();
    113 }
    114 
    115 #if !defined(OS_MACOSX)
    116 class NativeImageBufferEGL : public NativeImageBuffer {
    117  public:
    118   static scoped_refptr<NativeImageBufferEGL> Create(GLuint texture_id);
    119 
    120  private:
    121   NativeImageBufferEGL(EGLDisplay display, EGLImageKHR image);
    122   virtual ~NativeImageBufferEGL();
    123   virtual void AddClient(gfx::GLImage* client) OVERRIDE;
    124   virtual void RemoveClient(gfx::GLImage* client) OVERRIDE;
    125   virtual bool IsClient(gfx::GLImage* client) OVERRIDE;
    126   virtual void BindToTexture(GLenum target) OVERRIDE;
    127 
    128   EGLDisplay egl_display_;
    129   EGLImageKHR egl_image_;
    130 
    131   base::Lock lock_;
    132 
    133   struct ClientInfo {
    134     ClientInfo(gfx::GLImage* client);
    135     ~ClientInfo();
    136 
    137     gfx::GLImage* client;
    138     bool needs_wait_before_read;
    139   };
    140   std::list<ClientInfo> client_infos_;
    141   gfx::GLImage* write_client_;
    142 
    143   DISALLOW_COPY_AND_ASSIGN(NativeImageBufferEGL);
    144 };
    145 
    146 scoped_refptr<NativeImageBufferEGL> NativeImageBufferEGL::Create(
    147     GLuint texture_id) {
    148   EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
    149   EGLContext egl_context = eglGetCurrentContext();
    150 
    151   DCHECK_NE(EGL_NO_CONTEXT, egl_context);
    152   DCHECK_NE(EGL_NO_DISPLAY, egl_display);
    153   DCHECK(glIsTexture(texture_id));
    154 
    155   DCHECK(gfx::g_driver_egl.ext.b_EGL_KHR_image_base &&
    156          gfx::g_driver_egl.ext.b_EGL_KHR_gl_texture_2D_image &&
    157          gfx::g_driver_gl.ext.b_GL_OES_EGL_image);
    158 
    159   const EGLint egl_attrib_list[] = {
    160       EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
    161   EGLClientBuffer egl_buffer = reinterpret_cast<EGLClientBuffer>(texture_id);
    162   EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR; // TODO
    163 
    164   EGLImageKHR egl_image = eglCreateImageKHR(
    165       egl_display, egl_context, egl_target, egl_buffer, egl_attrib_list);
    166 
    167   if (egl_image == EGL_NO_IMAGE_KHR)
    168     return NULL;
    169 
    170   return new NativeImageBufferEGL(egl_display, egl_image);
    171 }
    172 
    173 NativeImageBufferEGL::ClientInfo::ClientInfo(gfx::GLImage* client)
    174     : client(client), needs_wait_before_read(true) {}
    175 
    176 NativeImageBufferEGL::ClientInfo::~ClientInfo() {}
    177 
    178 NativeImageBufferEGL::NativeImageBufferEGL(EGLDisplay display,
    179                                            EGLImageKHR image)
    180     : NativeImageBuffer(),
    181       egl_display_(display),
    182       egl_image_(image),
    183       write_client_(NULL) {
    184   DCHECK(egl_display_ != EGL_NO_DISPLAY);
    185   DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
    186 }
    187 
    188 NativeImageBufferEGL::~NativeImageBufferEGL() {
    189   DCHECK(client_infos_.empty());
    190   if (egl_image_ != EGL_NO_IMAGE_KHR)
    191     eglDestroyImageKHR(egl_display_, egl_image_);
    192 }
    193 
    194 void NativeImageBufferEGL::AddClient(gfx::GLImage* client) {
    195   base::AutoLock lock(lock_);
    196   client_infos_.push_back(ClientInfo(client));
    197 }
    198 
    199 void NativeImageBufferEGL::RemoveClient(gfx::GLImage* client) {
    200   base::AutoLock lock(lock_);
    201   if (write_client_ == client)
    202     write_client_ = NULL;
    203   for (std::list<ClientInfo>::iterator it = client_infos_.begin();
    204        it != client_infos_.end();
    205        it++) {
    206     if (it->client == client) {
    207       client_infos_.erase(it);
    208       return;
    209     }
    210   }
    211   NOTREACHED();
    212 }
    213 
    214 bool NativeImageBufferEGL::IsClient(gfx::GLImage* client) {
    215   base::AutoLock lock(lock_);
    216   for (std::list<ClientInfo>::iterator it = client_infos_.begin();
    217        it != client_infos_.end();
    218        it++) {
    219     if (it->client == client)
    220       return true;
    221   }
    222   return false;
    223 }
    224 
    225 void NativeImageBufferEGL::BindToTexture(GLenum target) {
    226   DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
    227   glEGLImageTargetTexture2DOES(target, egl_image_);
    228   DCHECK_EQ(static_cast<EGLint>(EGL_SUCCESS), eglGetError());
    229   DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
    230 }
    231 
    232 #endif
    233 
    234 class NativeImageBufferStub : public NativeImageBuffer {
    235  public:
    236   NativeImageBufferStub() : NativeImageBuffer() {}
    237 
    238  private:
    239   virtual ~NativeImageBufferStub() {}
    240   virtual void AddClient(gfx::GLImage* client) OVERRIDE {}
    241   virtual void RemoveClient(gfx::GLImage* client) OVERRIDE {}
    242   virtual bool IsClient(gfx::GLImage* client) OVERRIDE { return true; }
    243   virtual void BindToTexture(GLenum target) OVERRIDE {}
    244 
    245   DISALLOW_COPY_AND_ASSIGN(NativeImageBufferStub);
    246 };
    247 
    248 }  // anonymous namespace
    249 
    250 // static
    251 scoped_refptr<NativeImageBuffer> NativeImageBuffer::Create(GLuint texture_id) {
    252   switch (gfx::GetGLImplementation()) {
    253 #if !defined(OS_MACOSX)
    254     case gfx::kGLImplementationEGLGLES2:
    255       return NativeImageBufferEGL::Create(texture_id);
    256 #endif
    257     case gfx::kGLImplementationMockGL:
    258       return new NativeImageBufferStub;
    259     default:
    260       NOTREACHED();
    261       return NULL;
    262   }
    263 }
    264 
    265 TextureDefinition::LevelInfo::LevelInfo(GLenum target,
    266                                         GLenum internal_format,
    267                                         GLsizei width,
    268                                         GLsizei height,
    269                                         GLsizei depth,
    270                                         GLint border,
    271                                         GLenum format,
    272                                         GLenum type,
    273                                         bool cleared)
    274     : target(target),
    275       internal_format(internal_format),
    276       width(width),
    277       height(height),
    278       depth(depth),
    279       border(border),
    280       format(format),
    281       type(type),
    282       cleared(cleared) {}
    283 
    284 TextureDefinition::LevelInfo::~LevelInfo() {}
    285 
    286 TextureDefinition::TextureDefinition(
    287     GLenum target,
    288     Texture* texture,
    289     unsigned int version,
    290     const scoped_refptr<NativeImageBuffer>& image_buffer)
    291     : version_(version),
    292       target_(target),
    293       image_buffer_(image_buffer.get()
    294                         ? image_buffer
    295                         : NativeImageBuffer::Create(texture->service_id())),
    296       min_filter_(texture->min_filter()),
    297       mag_filter_(texture->mag_filter()),
    298       wrap_s_(texture->wrap_s()),
    299       wrap_t_(texture->wrap_t()),
    300       usage_(texture->usage()),
    301       immutable_(texture->IsImmutable()) {
    302   // TODO
    303   DCHECK(!texture->level_infos_.empty());
    304   DCHECK(!texture->level_infos_[0].empty());
    305   DCHECK(!texture->NeedsMips());
    306   DCHECK(texture->level_infos_[0][0].width);
    307   DCHECK(texture->level_infos_[0][0].height);
    308 
    309   scoped_refptr<gfx::GLImage> gl_image(
    310       new GLImageSync(image_buffer_,
    311                       gfx::Size(texture->level_infos_[0][0].width,
    312                                 texture->level_infos_[0][0].height)));
    313   texture->SetLevelImage(NULL, target, 0, gl_image.get());
    314 
    315   // TODO: all levels
    316   level_infos_.clear();
    317   const Texture::LevelInfo& level = texture->level_infos_[0][0];
    318   LevelInfo info(level.target,
    319                  level.internal_format,
    320                  level.width,
    321                  level.height,
    322                  level.depth,
    323                  level.border,
    324                  level.format,
    325                  level.type,
    326                  level.cleared);
    327   std::vector<LevelInfo> infos;
    328   infos.push_back(info);
    329   level_infos_.push_back(infos);
    330 }
    331 
    332 TextureDefinition::~TextureDefinition() {
    333 }
    334 
    335 Texture* TextureDefinition::CreateTexture() const {
    336   if (!image_buffer_.get())
    337     return NULL;
    338 
    339   GLuint texture_id;
    340   glGenTextures(1, &texture_id);
    341 
    342   Texture* texture(new Texture(texture_id));
    343   UpdateTexture(texture);
    344 
    345   return texture;
    346 }
    347 
    348 void TextureDefinition::UpdateTexture(Texture* texture) const {
    349   gfx::ScopedTextureBinder texture_binder(target_, texture->service_id());
    350   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_);
    351   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_);
    352   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s_);
    353   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_);
    354   if (image_buffer_.get())
    355     image_buffer_->BindToTexture(target_);
    356   // We have to make sure the changes are visible to other clients in this share
    357   // group. As far as the clients are concerned, the mailbox semantics only
    358   // demand a single flush from the client after changes are first made,
    359   // and it is not visible to them when another share group boundary is crossed.
    360   // We could probably track this and be a bit smarter about when to flush
    361   // though.
    362   glFlush();
    363 
    364   texture->level_infos_.resize(1);
    365   for (size_t i = 0; i < level_infos_.size(); i++) {
    366     const LevelInfo& base_info = level_infos_[i][0];
    367     const size_t levels_needed = TextureManager::ComputeMipMapCount(
    368         base_info.target, base_info.width, base_info.height, base_info.depth);
    369     DCHECK(level_infos_.size() <= levels_needed);
    370     texture->level_infos_[0].resize(levels_needed);
    371     for (size_t n = 0; n < level_infos_.size(); n++) {
    372       const LevelInfo& info = level_infos_[i][n];
    373       texture->SetLevelInfo(NULL,
    374                             info.target,
    375                             i,
    376                             info.internal_format,
    377                             info.width,
    378                             info.height,
    379                             info.depth,
    380                             info.border,
    381                             info.format,
    382                             info.type,
    383                             info.cleared);
    384     }
    385   }
    386   if (image_buffer_.get()) {
    387     texture->SetLevelImage(
    388         NULL,
    389         target_,
    390         0,
    391         new GLImageSync(
    392             image_buffer_,
    393             gfx::Size(level_infos_[0][0].width, level_infos_[0][0].height)));
    394   }
    395 
    396   texture->target_ = target_;
    397   texture->SetImmutable(immutable_);
    398   texture->min_filter_ = min_filter_;
    399   texture->mag_filter_ = mag_filter_;
    400   texture->wrap_s_ = wrap_s_;
    401   texture->wrap_t_ = wrap_t_;
    402   texture->usage_ = usage_;
    403 }
    404 
    405 bool TextureDefinition::Matches(const Texture* texture) const {
    406   DCHECK(target_ == texture->target());
    407   if (texture->min_filter_ != min_filter_ ||
    408       texture->mag_filter_ != mag_filter_ ||
    409       texture->wrap_s_ != wrap_s_ ||
    410       texture->wrap_t_ != wrap_t_) {
    411     return false;
    412   }
    413 
    414   // All structural changes should have orphaned the texture.
    415   if (image_buffer_.get() && !texture->GetLevelImage(texture->target(), 0))
    416     return false;
    417 
    418   return true;
    419 }
    420 
    421 }  // namespace gles2
    422 }  // namespace gpu
    423