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