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