Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / gpu / command_buffer / service / texture_definition.cc
blob377675cf90d9b80239659e435bc238fa2ef2752d
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.
5 #include "gpu/command_buffer/service/texture_definition.h"
7 #include <list>
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"
17 #if !defined(OS_MACOSX)
18 #include "ui/gl/gl_fence_egl.h"
19 #include "ui/gl/gl_surface_egl.h"
20 #endif
22 namespace gpu {
23 namespace gles2 {
25 namespace {
27 class GLImageSync : public gfx::GLImage {
28 public:
29 explicit GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer,
30 const gfx::Size& size);
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;
48 protected:
49 virtual ~GLImageSync();
51 private:
52 scoped_refptr<NativeImageBuffer> buffer_;
53 gfx::Size size_;
55 DISALLOW_COPY_AND_ASSIGN(GLImageSync);
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);
65 GLImageSync::~GLImageSync() {
66 if (buffer_.get())
67 buffer_->RemoveClient(this);
70 void GLImageSync::Destroy(bool have_context) {
73 gfx::Size GLImageSync::GetSize() {
74 return size_;
77 bool GLImageSync::BindTexImage(unsigned target) {
78 NOTREACHED();
79 return false;
82 void GLImageSync::ReleaseTexImage(unsigned target) {
83 NOTREACHED();
86 void GLImageSync::WillUseTexImage() {
87 if (buffer_.get())
88 buffer_->WillRead(this);
91 void GLImageSync::DidUseTexImage() {
92 if (buffer_.get())
93 buffer_->DidRead(this);
96 void GLImageSync::WillModifyTexImage() {
97 if (buffer_.get())
98 buffer_->WillWrite(this);
101 void GLImageSync::DidModifyTexImage() {
102 if (buffer_.get())
103 buffer_->DidWrite(this);
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;
115 void GLImageSync::SetReleaseAfterUse() {
116 NOTREACHED();
119 #if !defined(OS_MACOSX)
120 class NativeImageBufferEGL : public NativeImageBuffer {
121 public:
122 static scoped_refptr<NativeImageBufferEGL> Create(GLuint texture_id);
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;
136 EGLDisplay egl_display_;
137 EGLImageKHR egl_image_;
139 base::Lock lock_;
141 struct ClientInfo {
142 ClientInfo(gfx::GLImage* client);
143 ~ClientInfo();
145 gfx::GLImage* client;
146 bool needs_wait_before_read;
147 linked_ptr<gfx::GLFence> read_fence;
149 std::list<ClientInfo> client_infos_;
150 scoped_ptr<gfx::GLFence> write_fence_;
151 gfx::GLImage* write_client_;
153 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferEGL);
156 scoped_refptr<NativeImageBufferEGL> NativeImageBufferEGL::Create(
157 GLuint texture_id) {
158 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
159 EGLContext egl_context = eglGetCurrentContext();
161 DCHECK_NE(EGL_NO_CONTEXT, egl_context);
162 DCHECK_NE(EGL_NO_DISPLAY, egl_display);
163 DCHECK(glIsTexture(texture_id));
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);
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
175 EGLImageKHR egl_image = eglCreateImageKHR(
176 egl_display, egl_context, egl_target, egl_buffer, egl_attrib_list);
178 if (egl_image == EGL_NO_IMAGE_KHR)
179 return NULL;
181 return new NativeImageBufferEGL(egl_display, egl_image);
184 NativeImageBufferEGL::ClientInfo::ClientInfo(gfx::GLImage* client)
185 : client(client), needs_wait_before_read(true) {}
187 NativeImageBufferEGL::ClientInfo::~ClientInfo() {}
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);
200 NativeImageBufferEGL::~NativeImageBufferEGL() {
201 DCHECK(client_infos_.empty());
202 if (egl_image_ != EGL_NO_IMAGE_KHR)
203 eglDestroyImageKHR(egl_display_, egl_image_);
206 void NativeImageBufferEGL::AddClient(gfx::GLImage* client) {
207 base::AutoLock lock(lock_);
208 client_infos_.push_back(ClientInfo(client));
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;
223 NOTREACHED();
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;
234 return false;
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());
244 void NativeImageBufferEGL::WillRead(gfx::GLImage* client) {
245 base::AutoLock lock(lock_);
246 if (!write_fence_.get() || write_client_ == client)
247 return;
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();
257 return;
260 NOTREACHED();
263 void NativeImageBufferEGL::WillWrite(gfx::GLImage* client) {
264 base::AutoLock lock(lock_);
265 if (write_client_ != client)
266 write_fence_->ServerWait();
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();
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;
286 NOTREACHED();
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;
302 #endif
304 class NativeImageBufferStub : public NativeImageBuffer {
305 public:
306 NativeImageBufferStub() : NativeImageBuffer() {}
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 {}
319 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferStub);
322 } // anonymous namespace
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;
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) {}
358 TextureDefinition::LevelInfo::~LevelInfo() {}
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.get()
368 ? image_buffer
369 : NativeImageBuffer::Create(texture->service_id())),
370 min_filter_(texture->min_filter()),
371 mag_filter_(texture->mag_filter()),
372 wrap_s_(texture->wrap_s()),
373 wrap_t_(texture->wrap_t()),
374 usage_(texture->usage()),
375 immutable_(texture->IsImmutable()) {
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);
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.get());
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);
406 TextureDefinition::~TextureDefinition() {
409 Texture* TextureDefinition::CreateTexture() const {
410 if (!image_buffer_.get())
411 return NULL;
413 GLuint texture_id;
414 glGenTextures(1, &texture_id);
416 Texture* texture(new Texture(texture_id));
417 UpdateTexture(texture);
419 return texture;
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_.get())
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();
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,
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);
460 if (image_buffer_.get()) {
461 texture->SetLevelImage(
462 NULL,
463 target_,
465 new GLImageSync(
466 image_buffer_,
467 gfx::Size(level_infos_[0][0].width, level_infos_[0][0].height)));
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_;
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;
488 // All structural changes should have orphaned the texture.
489 if (image_buffer_.get() && !texture->GetLevelImage(texture->target(), 0))
490 return false;
492 return true;
495 } // namespace gles2
496 } // namespace gpu