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