Update Polymer and pull in iron-list
[chromium-blink-merge.git] / gpu / command_buffer / service / texture_definition.cc
blob1f1372a711be8fb85ae9044508c5aa5e96915238
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/lazy_instance.h"
10 #include "base/memory/linked_ptr.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/synchronization/lock.h"
13 #include "base/threading/thread_local.h"
14 #include "gpu/command_buffer/service/texture_manager.h"
15 #include "ui/gl/gl_image.h"
16 #include "ui/gl/gl_implementation.h"
17 #include "ui/gl/scoped_binders.h"
19 #if !defined(OS_MACOSX)
20 #include "ui/gl/gl_surface_egl.h"
21 #endif
23 namespace gpu {
24 namespace gles2 {
26 namespace {
28 class GLImageSync : public gfx::GLImage {
29 public:
30 explicit GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer,
31 const gfx::Size& size);
33 // Implement GLImage.
34 void Destroy(bool have_context) override;
35 gfx::Size GetSize() override;
36 unsigned GetInternalFormat() override;
37 bool BindTexImage(unsigned target) override;
38 void ReleaseTexImage(unsigned target) override;
39 bool CopyTexSubImage(unsigned target,
40 const gfx::Point& offset,
41 const gfx::Rect& rect) override;
42 void WillUseTexImage() override;
43 void WillModifyTexImage() override;
44 void DidModifyTexImage() override;
45 void DidUseTexImage() override;
46 bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
47 int z_order,
48 gfx::OverlayTransform transform,
49 const gfx::Rect& bounds_rect,
50 const gfx::RectF& crop_rect) override;
51 void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
52 uint64_t process_tracing_id,
53 const std::string& dump_name) override;
55 protected:
56 ~GLImageSync() override;
58 private:
59 scoped_refptr<NativeImageBuffer> buffer_;
60 gfx::Size size_;
62 DISALLOW_COPY_AND_ASSIGN(GLImageSync);
65 GLImageSync::GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer,
66 const gfx::Size& size)
67 : buffer_(buffer), size_(size) {
68 if (buffer.get())
69 buffer->AddClient(this);
72 GLImageSync::~GLImageSync() {
73 if (buffer_.get())
74 buffer_->RemoveClient(this);
77 void GLImageSync::Destroy(bool have_context) {
80 gfx::Size GLImageSync::GetSize() {
81 return size_;
84 unsigned GLImageSync::GetInternalFormat() {
85 return GL_RGBA;
88 bool GLImageSync::BindTexImage(unsigned target) {
89 NOTREACHED();
90 return false;
93 void GLImageSync::ReleaseTexImage(unsigned target) {
94 NOTREACHED();
97 bool GLImageSync::CopyTexSubImage(unsigned target,
98 const gfx::Point& offset,
99 const gfx::Rect& rect) {
100 return false;
103 void GLImageSync::WillUseTexImage() {
106 void GLImageSync::DidUseTexImage() {
109 void GLImageSync::WillModifyTexImage() {
112 void GLImageSync::DidModifyTexImage() {
115 bool GLImageSync::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
116 int z_order,
117 gfx::OverlayTransform transform,
118 const gfx::Rect& bounds_rect,
119 const gfx::RectF& crop_rect) {
120 NOTREACHED();
121 return false;
124 void GLImageSync::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
125 uint64_t process_tracing_id,
126 const std::string& dump_name) {
127 // TODO(ericrk): Implement GLImage OnMemoryDump. crbug.com/514914
130 #if !defined(OS_MACOSX)
131 class NativeImageBufferEGL : public NativeImageBuffer {
132 public:
133 static scoped_refptr<NativeImageBufferEGL> Create(GLuint texture_id);
135 private:
136 NativeImageBufferEGL(EGLDisplay display, EGLImageKHR image);
137 ~NativeImageBufferEGL() override;
138 void AddClient(gfx::GLImage* client) override;
139 void RemoveClient(gfx::GLImage* client) override;
140 bool IsClient(gfx::GLImage* client) override;
141 void BindToTexture(GLenum target) const override;
143 const EGLDisplay egl_display_;
144 const EGLImageKHR egl_image_;
146 base::Lock lock_;
148 struct ClientInfo {
149 explicit ClientInfo(gfx::GLImage* client);
150 ~ClientInfo();
152 gfx::GLImage* client;
153 bool needs_wait_before_read;
155 std::list<ClientInfo> client_infos_;
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);
174 const EGLint egl_attrib_list[] = {
175 EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
176 EGLClientBuffer egl_buffer = reinterpret_cast<EGLClientBuffer>(texture_id);
177 EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR;
179 EGLImageKHR egl_image = eglCreateImageKHR(
180 egl_display, egl_context, egl_target, egl_buffer, egl_attrib_list);
182 if (egl_image == EGL_NO_IMAGE_KHR) {
183 LOG(ERROR) << "eglCreateImageKHR for cross-thread sharing failed: 0x"
184 << std::hex << eglGetError();
185 return NULL;
188 return new NativeImageBufferEGL(egl_display, egl_image);
191 NativeImageBufferEGL::ClientInfo::ClientInfo(gfx::GLImage* client)
192 : client(client), needs_wait_before_read(true) {}
194 NativeImageBufferEGL::ClientInfo::~ClientInfo() {}
196 NativeImageBufferEGL::NativeImageBufferEGL(EGLDisplay display,
197 EGLImageKHR image)
198 : NativeImageBuffer(),
199 egl_display_(display),
200 egl_image_(image),
201 write_client_(NULL) {
202 DCHECK(egl_display_ != EGL_NO_DISPLAY);
203 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
206 NativeImageBufferEGL::~NativeImageBufferEGL() {
207 DCHECK(client_infos_.empty());
208 if (egl_image_ != EGL_NO_IMAGE_KHR)
209 eglDestroyImageKHR(egl_display_, egl_image_);
212 void NativeImageBufferEGL::AddClient(gfx::GLImage* client) {
213 base::AutoLock lock(lock_);
214 client_infos_.push_back(ClientInfo(client));
217 void NativeImageBufferEGL::RemoveClient(gfx::GLImage* client) {
218 base::AutoLock lock(lock_);
219 if (write_client_ == client)
220 write_client_ = NULL;
221 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
222 it != client_infos_.end();
223 it++) {
224 if (it->client == client) {
225 client_infos_.erase(it);
226 return;
229 NOTREACHED();
232 bool NativeImageBufferEGL::IsClient(gfx::GLImage* client) {
233 base::AutoLock lock(lock_);
234 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
235 it != client_infos_.end();
236 it++) {
237 if (it->client == client)
238 return true;
240 return false;
243 void NativeImageBufferEGL::BindToTexture(GLenum target) const {
244 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
245 glEGLImageTargetTexture2DOES(target, egl_image_);
246 DCHECK_EQ(static_cast<EGLint>(EGL_SUCCESS), eglGetError());
247 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
250 #endif
252 class NativeImageBufferStub : public NativeImageBuffer {
253 public:
254 NativeImageBufferStub() : NativeImageBuffer() {}
256 private:
257 ~NativeImageBufferStub() override {}
258 void AddClient(gfx::GLImage* client) override {}
259 void RemoveClient(gfx::GLImage* client) override {}
260 bool IsClient(gfx::GLImage* client) override { return true; }
261 void BindToTexture(GLenum target) const override {}
263 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferStub);
266 bool g_avoid_egl_target_texture_reuse = false;
268 } // anonymous namespace
270 // static
271 scoped_refptr<NativeImageBuffer> NativeImageBuffer::Create(GLuint texture_id) {
272 switch (gfx::GetGLImplementation()) {
273 #if !defined(OS_MACOSX)
274 case gfx::kGLImplementationEGLGLES2:
275 return NativeImageBufferEGL::Create(texture_id);
276 #endif
277 case gfx::kGLImplementationMockGL:
278 return new NativeImageBufferStub;
279 default:
280 NOTREACHED();
281 return NULL;
285 // static
286 void TextureDefinition::AvoidEGLTargetTextureReuse() {
287 g_avoid_egl_target_texture_reuse = true;
290 TextureDefinition::LevelInfo::LevelInfo()
291 : target(0),
292 internal_format(0),
293 width(0),
294 height(0),
295 depth(0),
296 border(0),
297 format(0),
298 type(0) {
301 TextureDefinition::LevelInfo::LevelInfo(GLenum target,
302 GLenum internal_format,
303 GLsizei width,
304 GLsizei height,
305 GLsizei depth,
306 GLint border,
307 GLenum format,
308 GLenum type,
309 const gfx::Rect& cleared_rect)
310 : target(target),
311 internal_format(internal_format),
312 width(width),
313 height(height),
314 depth(depth),
315 border(border),
316 format(format),
317 type(type),
318 cleared_rect(cleared_rect) {
321 TextureDefinition::LevelInfo::~LevelInfo() {}
323 TextureDefinition::TextureDefinition()
324 : version_(0),
325 target_(0),
326 min_filter_(0),
327 mag_filter_(0),
328 wrap_s_(0),
329 wrap_t_(0),
330 usage_(0),
331 immutable_(true) {
334 TextureDefinition::TextureDefinition(
335 Texture* texture,
336 unsigned int version,
337 const scoped_refptr<NativeImageBuffer>& image_buffer)
338 : version_(version),
339 target_(texture->target()),
340 image_buffer_(image_buffer),
341 min_filter_(texture->min_filter()),
342 mag_filter_(texture->mag_filter()),
343 wrap_s_(texture->wrap_s()),
344 wrap_t_(texture->wrap_t()),
345 usage_(texture->usage()),
346 immutable_(texture->IsImmutable()),
347 defined_(texture->IsDefined()) {
348 DCHECK_IMPLIES(image_buffer_.get(), defined_);
349 if (!image_buffer_.get() && defined_) {
350 image_buffer_ = NativeImageBuffer::Create(texture->service_id());
351 DCHECK(image_buffer_.get());
354 const Texture::FaceInfo& first_face = texture->face_infos_[0];
355 if (image_buffer_.get()) {
356 scoped_refptr<gfx::GLImage> gl_image(
357 new GLImageSync(image_buffer_,
358 gfx::Size(first_face.level_infos[0].width,
359 first_face.level_infos[0].height)));
360 texture->SetLevelImage(NULL, target_, 0, gl_image.get());
363 const Texture::LevelInfo& level = first_face.level_infos[0];
364 level_info_ = LevelInfo(level.target, level.internal_format, level.width,
365 level.height, level.depth, level.border, level.format,
366 level.type, level.cleared_rect);
369 TextureDefinition::~TextureDefinition() {
372 Texture* TextureDefinition::CreateTexture() const {
373 GLuint texture_id;
374 glGenTextures(1, &texture_id);
376 Texture* texture(new Texture(texture_id));
377 UpdateTextureInternal(texture);
379 return texture;
382 void TextureDefinition::UpdateTextureInternal(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_);
389 if (image_buffer_.get()) {
390 gfx::GLImage* existing_image = texture->GetLevelImage(target_, 0);
391 // Don't need to re-bind if already bound before.
392 if (!existing_image || !image_buffer_->IsClient(existing_image)) {
393 image_buffer_->BindToTexture(target_);
397 if (defined_) {
398 texture->face_infos_.resize(1);
399 texture->face_infos_[0].level_infos.resize(1);
400 texture->SetLevelInfo(NULL, level_info_.target, 0,
401 level_info_.internal_format, level_info_.width,
402 level_info_.height, level_info_.depth,
403 level_info_.border, level_info_.format,
404 level_info_.type, level_info_.cleared_rect);
407 if (image_buffer_.get()) {
408 texture->SetLevelImage(
409 NULL,
410 target_,
412 new GLImageSync(
413 image_buffer_,
414 gfx::Size(level_info_.width, level_info_.height)));
417 texture->target_ = target_;
418 texture->SetImmutable(immutable_);
419 texture->min_filter_ = min_filter_;
420 texture->mag_filter_ = mag_filter_;
421 texture->wrap_s_ = wrap_s_;
422 texture->wrap_t_ = wrap_t_;
423 texture->usage_ = usage_;
426 void TextureDefinition::UpdateTexture(Texture* texture) const {
427 GLuint old_service_id = 0u;
428 if (image_buffer_.get() && g_avoid_egl_target_texture_reuse) {
429 GLuint service_id = 0u;
430 glGenTextures(1, &service_id);
431 old_service_id = texture->service_id();
432 texture->SetServiceId(service_id);
434 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), target_);
435 GLint bound_id = 0;
436 glGetIntegerv(GL_TEXTURE_BINDING_2D, &bound_id);
437 if (bound_id == static_cast<GLint>(old_service_id)) {
438 glBindTexture(target_, service_id);
440 texture->SetLevelImage(NULL, target_, 0, NULL);
443 UpdateTextureInternal(texture);
445 if (old_service_id) {
446 glDeleteTextures(1, &old_service_id);
450 bool TextureDefinition::Matches(const Texture* texture) const {
451 DCHECK(target_ == texture->target());
452 if (texture->min_filter_ != min_filter_ ||
453 texture->mag_filter_ != mag_filter_ ||
454 texture->wrap_s_ != wrap_s_ ||
455 texture->wrap_t_ != wrap_t_ ||
456 texture->SafeToRenderFrom() != SafeToRenderFrom()) {
457 return false;
460 // Texture became defined.
461 if (!image_buffer_.get() && texture->IsDefined())
462 return false;
464 // All structural changes should have orphaned the texture.
465 if (image_buffer_.get() && !texture->GetLevelImage(texture->target(), 0))
466 return false;
468 return true;
471 bool TextureDefinition::SafeToRenderFrom() const {
472 return level_info_.cleared_rect.Contains(
473 gfx::Rect(level_info_.width, level_info_.height));
476 } // namespace gles2
477 } // namespace gpu