Handle account removal correctly on all platforms.
[chromium-blink-merge.git] / gpu / command_buffer / service / texture_definition.cc
blob08af4aacb0253b2ec3f1a23dff4730c840d7e237
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 bool CopyTexImage(unsigned target) OVERRIDE;
38 virtual void WillUseTexImage() OVERRIDE;
39 virtual void WillModifyTexImage() OVERRIDE;
40 virtual void DidModifyTexImage() OVERRIDE;
41 virtual void DidUseTexImage() OVERRIDE;
42 virtual bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
43 int z_order,
44 gfx::OverlayTransform transform,
45 const gfx::Rect& bounds_rect,
46 const gfx::RectF& crop_rect) OVERRIDE;
47 virtual void SetReleaseAfterUse() OVERRIDE;
49 protected:
50 virtual ~GLImageSync();
52 private:
53 scoped_refptr<NativeImageBuffer> buffer_;
54 gfx::Size size_;
56 DISALLOW_COPY_AND_ASSIGN(GLImageSync);
59 GLImageSync::GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer,
60 const gfx::Size& size)
61 : buffer_(buffer), size_(size) {
62 if (buffer.get())
63 buffer->AddClient(this);
66 GLImageSync::~GLImageSync() {
67 if (buffer_.get())
68 buffer_->RemoveClient(this);
71 void GLImageSync::Destroy(bool have_context) {
74 gfx::Size GLImageSync::GetSize() {
75 return size_;
78 bool GLImageSync::BindTexImage(unsigned target) {
79 NOTREACHED();
80 return false;
83 void GLImageSync::ReleaseTexImage(unsigned target) {
84 NOTREACHED();
87 bool GLImageSync::CopyTexImage(unsigned target) {
88 return false;
91 void GLImageSync::WillUseTexImage() {
92 if (buffer_.get())
93 buffer_->WillRead(this);
96 void GLImageSync::DidUseTexImage() {
97 if (buffer_.get())
98 buffer_->DidRead(this);
101 void GLImageSync::WillModifyTexImage() {
102 if (buffer_.get())
103 buffer_->WillWrite(this);
106 void GLImageSync::DidModifyTexImage() {
107 if (buffer_.get())
108 buffer_->DidWrite(this);
111 bool GLImageSync::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
112 int z_order,
113 gfx::OverlayTransform transform,
114 const gfx::Rect& bounds_rect,
115 const gfx::RectF& crop_rect) {
116 NOTREACHED();
117 return false;
120 void GLImageSync::SetReleaseAfterUse() {
121 NOTREACHED();
124 #if !defined(OS_MACOSX)
125 class NativeImageBufferEGL : public NativeImageBuffer {
126 public:
127 static scoped_refptr<NativeImageBufferEGL> Create(GLuint texture_id);
129 private:
130 NativeImageBufferEGL(EGLDisplay display, EGLImageKHR image);
131 virtual ~NativeImageBufferEGL();
132 virtual void AddClient(gfx::GLImage* client) OVERRIDE;
133 virtual void RemoveClient(gfx::GLImage* client) OVERRIDE;
134 virtual bool IsClient(gfx::GLImage* client) OVERRIDE;
135 virtual void BindToTexture(GLenum target) OVERRIDE;
136 virtual void WillRead(gfx::GLImage* client) OVERRIDE;
137 virtual void WillWrite(gfx::GLImage* client) OVERRIDE;
138 virtual void DidRead(gfx::GLImage* client) OVERRIDE;
139 virtual void DidWrite(gfx::GLImage* client) OVERRIDE;
141 EGLDisplay egl_display_;
142 EGLImageKHR egl_image_;
144 base::Lock lock_;
146 struct ClientInfo {
147 ClientInfo(gfx::GLImage* client);
148 ~ClientInfo();
150 gfx::GLImage* client;
151 bool needs_wait_before_read;
152 linked_ptr<gfx::GLFence> read_fence;
154 std::list<ClientInfo> client_infos_;
155 scoped_ptr<gfx::GLFence> write_fence_;
156 gfx::GLImage* write_client_;
158 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferEGL);
161 scoped_refptr<NativeImageBufferEGL> NativeImageBufferEGL::Create(
162 GLuint texture_id) {
163 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
164 EGLContext egl_context = eglGetCurrentContext();
166 DCHECK_NE(EGL_NO_CONTEXT, egl_context);
167 DCHECK_NE(EGL_NO_DISPLAY, egl_display);
168 DCHECK(glIsTexture(texture_id));
170 DCHECK(gfx::g_driver_egl.ext.b_EGL_KHR_image_base &&
171 gfx::g_driver_egl.ext.b_EGL_KHR_gl_texture_2D_image &&
172 gfx::g_driver_gl.ext.b_GL_OES_EGL_image &&
173 gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync);
175 const EGLint egl_attrib_list[] = {
176 EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
177 EGLClientBuffer egl_buffer = reinterpret_cast<EGLClientBuffer>(texture_id);
178 EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR; // TODO
180 EGLImageKHR egl_image = eglCreateImageKHR(
181 egl_display, egl_context, egl_target, egl_buffer, egl_attrib_list);
183 if (egl_image == EGL_NO_IMAGE_KHR)
184 return NULL;
186 return new NativeImageBufferEGL(egl_display, egl_image);
189 NativeImageBufferEGL::ClientInfo::ClientInfo(gfx::GLImage* client)
190 : client(client), needs_wait_before_read(true) {}
192 NativeImageBufferEGL::ClientInfo::~ClientInfo() {}
194 NativeImageBufferEGL::NativeImageBufferEGL(EGLDisplay display,
195 EGLImageKHR image)
196 : NativeImageBuffer(),
197 egl_display_(display),
198 egl_image_(image),
199 write_fence_(new gfx::GLFenceEGL(true)),
200 write_client_(NULL) {
201 DCHECK(egl_display_ != EGL_NO_DISPLAY);
202 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
205 NativeImageBufferEGL::~NativeImageBufferEGL() {
206 DCHECK(client_infos_.empty());
207 if (egl_image_ != EGL_NO_IMAGE_KHR)
208 eglDestroyImageKHR(egl_display_, egl_image_);
211 void NativeImageBufferEGL::AddClient(gfx::GLImage* client) {
212 base::AutoLock lock(lock_);
213 client_infos_.push_back(ClientInfo(client));
216 void NativeImageBufferEGL::RemoveClient(gfx::GLImage* client) {
217 base::AutoLock lock(lock_);
218 if (write_client_ == client)
219 write_client_ = NULL;
220 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
221 it != client_infos_.end();
222 it++) {
223 if (it->client == client) {
224 client_infos_.erase(it);
225 return;
228 NOTREACHED();
231 bool NativeImageBufferEGL::IsClient(gfx::GLImage* client) {
232 base::AutoLock lock(lock_);
233 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
234 it != client_infos_.end();
235 it++) {
236 if (it->client == client)
237 return true;
239 return false;
242 void NativeImageBufferEGL::BindToTexture(GLenum target) {
243 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
244 glEGLImageTargetTexture2DOES(target, egl_image_);
245 DCHECK_EQ(static_cast<EGLint>(EGL_SUCCESS), eglGetError());
246 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
249 void NativeImageBufferEGL::WillRead(gfx::GLImage* client) {
250 base::AutoLock lock(lock_);
251 if (!write_fence_.get() || write_client_ == client)
252 return;
254 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
255 it != client_infos_.end();
256 it++) {
257 if (it->client == client) {
258 if (it->needs_wait_before_read) {
259 it->needs_wait_before_read = false;
260 write_fence_->ServerWait();
262 return;
265 NOTREACHED();
268 void NativeImageBufferEGL::WillWrite(gfx::GLImage* client) {
269 base::AutoLock lock(lock_);
270 if (write_client_ != client)
271 write_fence_->ServerWait();
273 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
274 it != client_infos_.end();
275 it++) {
276 if (it->read_fence.get() && it->client != client)
277 it->read_fence->ServerWait();
281 void NativeImageBufferEGL::DidRead(gfx::GLImage* client) {
282 base::AutoLock lock(lock_);
283 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
284 it != client_infos_.end();
285 it++) {
286 if (it->client == client) {
287 it->read_fence = make_linked_ptr(new gfx::GLFenceEGL(true));
288 return;
291 NOTREACHED();
294 void NativeImageBufferEGL::DidWrite(gfx::GLImage* client) {
295 base::AutoLock lock(lock_);
296 // Sharing semantics require the client to flush in order to make changes
297 // visible to other clients.
298 write_fence_.reset(new gfx::GLFenceEGL(false));
299 write_client_ = client;
300 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
301 it != client_infos_.end();
302 it++) {
303 it->needs_wait_before_read = true;
307 #endif
309 class NativeImageBufferStub : public NativeImageBuffer {
310 public:
311 NativeImageBufferStub() : NativeImageBuffer() {}
313 private:
314 virtual ~NativeImageBufferStub() {}
315 virtual void AddClient(gfx::GLImage* client) OVERRIDE {}
316 virtual void RemoveClient(gfx::GLImage* client) OVERRIDE {}
317 virtual bool IsClient(gfx::GLImage* client) OVERRIDE { return true; }
318 virtual void BindToTexture(GLenum target) OVERRIDE {}
319 virtual void WillRead(gfx::GLImage* client) OVERRIDE {}
320 virtual void WillWrite(gfx::GLImage* client) OVERRIDE {}
321 virtual void DidRead(gfx::GLImage* client) OVERRIDE {}
322 virtual void DidWrite(gfx::GLImage* client) OVERRIDE {}
324 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferStub);
327 } // anonymous namespace
329 // static
330 scoped_refptr<NativeImageBuffer> NativeImageBuffer::Create(GLuint texture_id) {
331 switch (gfx::GetGLImplementation()) {
332 #if !defined(OS_MACOSX)
333 case gfx::kGLImplementationEGLGLES2:
334 return NativeImageBufferEGL::Create(texture_id);
335 #endif
336 case gfx::kGLImplementationMockGL:
337 return new NativeImageBufferStub;
338 default:
339 NOTREACHED();
340 return NULL;
344 TextureDefinition::LevelInfo::LevelInfo(GLenum target,
345 GLenum internal_format,
346 GLsizei width,
347 GLsizei height,
348 GLsizei depth,
349 GLint border,
350 GLenum format,
351 GLenum type,
352 bool cleared)
353 : target(target),
354 internal_format(internal_format),
355 width(width),
356 height(height),
357 depth(depth),
358 border(border),
359 format(format),
360 type(type),
361 cleared(cleared) {}
363 TextureDefinition::LevelInfo::~LevelInfo() {}
365 TextureDefinition::TextureDefinition(
366 GLenum target,
367 Texture* texture,
368 unsigned int version,
369 const scoped_refptr<NativeImageBuffer>& image_buffer)
370 : version_(version),
371 target_(target),
372 image_buffer_(image_buffer.get()
373 ? image_buffer
374 : NativeImageBuffer::Create(texture->service_id())),
375 min_filter_(texture->min_filter()),
376 mag_filter_(texture->mag_filter()),
377 wrap_s_(texture->wrap_s()),
378 wrap_t_(texture->wrap_t()),
379 usage_(texture->usage()),
380 immutable_(texture->IsImmutable()) {
381 // TODO
382 DCHECK(!texture->level_infos_.empty());
383 DCHECK(!texture->level_infos_[0].empty());
384 DCHECK(!texture->NeedsMips());
385 DCHECK(texture->level_infos_[0][0].width);
386 DCHECK(texture->level_infos_[0][0].height);
388 scoped_refptr<gfx::GLImage> gl_image(
389 new GLImageSync(image_buffer_,
390 gfx::Size(texture->level_infos_[0][0].width,
391 texture->level_infos_[0][0].height)));
392 texture->SetLevelImage(NULL, target, 0, gl_image.get());
394 // TODO: all levels
395 level_infos_.clear();
396 const Texture::LevelInfo& level = texture->level_infos_[0][0];
397 LevelInfo info(level.target,
398 level.internal_format,
399 level.width,
400 level.height,
401 level.depth,
402 level.border,
403 level.format,
404 level.type,
405 level.cleared);
406 std::vector<LevelInfo> infos;
407 infos.push_back(info);
408 level_infos_.push_back(infos);
411 TextureDefinition::~TextureDefinition() {
414 Texture* TextureDefinition::CreateTexture() const {
415 if (!image_buffer_.get())
416 return NULL;
418 GLuint texture_id;
419 glGenTextures(1, &texture_id);
421 Texture* texture(new Texture(texture_id));
422 UpdateTexture(texture);
424 return texture;
427 void TextureDefinition::UpdateTexture(Texture* texture) const {
428 gfx::ScopedTextureBinder texture_binder(target_, texture->service_id());
429 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_);
430 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_);
431 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s_);
432 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_);
433 if (image_buffer_.get())
434 image_buffer_->BindToTexture(target_);
435 // We have to make sure the changes are visible to other clients in this share
436 // group. As far as the clients are concerned, the mailbox semantics only
437 // demand a single flush from the client after changes are first made,
438 // and it is not visible to them when another share group boundary is crossed.
439 // We could probably track this and be a bit smarter about when to flush
440 // though.
441 glFlush();
443 texture->level_infos_.resize(1);
444 for (size_t i = 0; i < level_infos_.size(); i++) {
445 const LevelInfo& base_info = level_infos_[i][0];
446 const size_t levels_needed = TextureManager::ComputeMipMapCount(
447 base_info.target, base_info.width, base_info.height, base_info.depth);
448 DCHECK(level_infos_.size() <= levels_needed);
449 texture->level_infos_[0].resize(levels_needed);
450 for (size_t n = 0; n < level_infos_.size(); n++) {
451 const LevelInfo& info = level_infos_[i][n];
452 texture->SetLevelInfo(NULL,
453 info.target,
455 info.internal_format,
456 info.width,
457 info.height,
458 info.depth,
459 info.border,
460 info.format,
461 info.type,
462 info.cleared);
465 if (image_buffer_.get()) {
466 texture->SetLevelImage(
467 NULL,
468 target_,
470 new GLImageSync(
471 image_buffer_,
472 gfx::Size(level_infos_[0][0].width, level_infos_[0][0].height)));
475 texture->target_ = target_;
476 texture->SetImmutable(immutable_);
477 texture->min_filter_ = min_filter_;
478 texture->mag_filter_ = mag_filter_;
479 texture->wrap_s_ = wrap_s_;
480 texture->wrap_t_ = wrap_t_;
481 texture->usage_ = usage_;
484 bool TextureDefinition::Matches(const Texture* texture) const {
485 DCHECK(target_ == texture->target());
486 if (texture->min_filter_ != min_filter_ ||
487 texture->mag_filter_ != mag_filter_ ||
488 texture->wrap_s_ != wrap_s_ ||
489 texture->wrap_t_ != wrap_t_) {
490 return false;
493 // All structural changes should have orphaned the texture.
494 if (image_buffer_.get() && !texture->GetLevelImage(texture->target(), 0))
495 return false;
497 return true;
500 } // namespace gles2
501 } // namespace gpu