Upstream version 11.39.250.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_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