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