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