Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / gpu / command_buffer / service / texture_definition.cc
blobc19b5d3d47cf03c76182a07143059209c2585d1f
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;
52 protected:
53 ~GLImageSync() override;
55 private:
56 scoped_refptr<NativeImageBuffer> buffer_;
57 gfx::Size size_;
59 DISALLOW_COPY_AND_ASSIGN(GLImageSync);
62 GLImageSync::GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer,
63 const gfx::Size& size)
64 : buffer_(buffer), size_(size) {
65 if (buffer.get())
66 buffer->AddClient(this);
69 GLImageSync::~GLImageSync() {
70 if (buffer_.get())
71 buffer_->RemoveClient(this);
74 void GLImageSync::Destroy(bool have_context) {
77 gfx::Size GLImageSync::GetSize() {
78 return size_;
81 unsigned GLImageSync::GetInternalFormat() {
82 return GL_RGBA;
85 bool GLImageSync::BindTexImage(unsigned target) {
86 NOTREACHED();
87 return false;
90 void GLImageSync::ReleaseTexImage(unsigned target) {
91 NOTREACHED();
94 bool GLImageSync::CopyTexSubImage(unsigned target,
95 const gfx::Point& offset,
96 const gfx::Rect& rect) {
97 return false;
100 void GLImageSync::WillUseTexImage() {
103 void GLImageSync::DidUseTexImage() {
106 void GLImageSync::WillModifyTexImage() {
109 void GLImageSync::DidModifyTexImage() {
112 bool GLImageSync::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
113 int z_order,
114 gfx::OverlayTransform transform,
115 const gfx::Rect& bounds_rect,
116 const gfx::RectF& crop_rect) {
117 NOTREACHED();
118 return false;
121 #if !defined(OS_MACOSX)
122 class NativeImageBufferEGL : public NativeImageBuffer {
123 public:
124 static scoped_refptr<NativeImageBufferEGL> Create(GLuint texture_id);
126 private:
127 NativeImageBufferEGL(EGLDisplay display, EGLImageKHR image);
128 ~NativeImageBufferEGL() override;
129 void AddClient(gfx::GLImage* client) override;
130 void RemoveClient(gfx::GLImage* client) override;
131 bool IsClient(gfx::GLImage* client) override;
132 void BindToTexture(GLenum target) const override;
134 const EGLDisplay egl_display_;
135 const EGLImageKHR egl_image_;
137 base::Lock lock_;
139 struct ClientInfo {
140 explicit ClientInfo(gfx::GLImage* client);
141 ~ClientInfo();
143 gfx::GLImage* client;
144 bool needs_wait_before_read;
146 std::list<ClientInfo> client_infos_;
147 gfx::GLImage* write_client_;
149 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferEGL);
152 scoped_refptr<NativeImageBufferEGL> NativeImageBufferEGL::Create(
153 GLuint texture_id) {
154 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
155 EGLContext egl_context = eglGetCurrentContext();
157 DCHECK_NE(EGL_NO_CONTEXT, egl_context);
158 DCHECK_NE(EGL_NO_DISPLAY, egl_display);
159 DCHECK(glIsTexture(texture_id));
161 DCHECK(gfx::g_driver_egl.ext.b_EGL_KHR_image_base &&
162 gfx::g_driver_egl.ext.b_EGL_KHR_gl_texture_2D_image &&
163 gfx::g_driver_gl.ext.b_GL_OES_EGL_image);
165 const EGLint egl_attrib_list[] = {
166 EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
167 EGLClientBuffer egl_buffer = reinterpret_cast<EGLClientBuffer>(texture_id);
168 EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR;
170 EGLImageKHR egl_image = eglCreateImageKHR(
171 egl_display, egl_context, egl_target, egl_buffer, egl_attrib_list);
173 if (egl_image == EGL_NO_IMAGE_KHR) {
174 LOG(ERROR) << "eglCreateImageKHR for cross-thread sharing failed: 0x"
175 << std::hex << eglGetError();
176 return NULL;
179 return new NativeImageBufferEGL(egl_display, egl_image);
182 NativeImageBufferEGL::ClientInfo::ClientInfo(gfx::GLImage* client)
183 : client(client), needs_wait_before_read(true) {}
185 NativeImageBufferEGL::ClientInfo::~ClientInfo() {}
187 NativeImageBufferEGL::NativeImageBufferEGL(EGLDisplay display,
188 EGLImageKHR image)
189 : NativeImageBuffer(),
190 egl_display_(display),
191 egl_image_(image),
192 write_client_(NULL) {
193 DCHECK(egl_display_ != EGL_NO_DISPLAY);
194 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
197 NativeImageBufferEGL::~NativeImageBufferEGL() {
198 DCHECK(client_infos_.empty());
199 if (egl_image_ != EGL_NO_IMAGE_KHR)
200 eglDestroyImageKHR(egl_display_, egl_image_);
203 void NativeImageBufferEGL::AddClient(gfx::GLImage* client) {
204 base::AutoLock lock(lock_);
205 client_infos_.push_back(ClientInfo(client));
208 void NativeImageBufferEGL::RemoveClient(gfx::GLImage* client) {
209 base::AutoLock lock(lock_);
210 if (write_client_ == client)
211 write_client_ = NULL;
212 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
213 it != client_infos_.end();
214 it++) {
215 if (it->client == client) {
216 client_infos_.erase(it);
217 return;
220 NOTREACHED();
223 bool NativeImageBufferEGL::IsClient(gfx::GLImage* client) {
224 base::AutoLock lock(lock_);
225 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
226 it != client_infos_.end();
227 it++) {
228 if (it->client == client)
229 return true;
231 return false;
234 void NativeImageBufferEGL::BindToTexture(GLenum target) const {
235 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
236 glEGLImageTargetTexture2DOES(target, egl_image_);
237 DCHECK_EQ(static_cast<EGLint>(EGL_SUCCESS), eglGetError());
238 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
241 #endif
243 class NativeImageBufferStub : public NativeImageBuffer {
244 public:
245 NativeImageBufferStub() : NativeImageBuffer() {}
247 private:
248 ~NativeImageBufferStub() override {}
249 void AddClient(gfx::GLImage* client) override {}
250 void RemoveClient(gfx::GLImage* client) override {}
251 bool IsClient(gfx::GLImage* client) override { return true; }
252 void BindToTexture(GLenum target) const override {}
254 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferStub);
257 bool g_avoid_egl_target_texture_reuse = false;
259 #if DCHECK_IS_ON()
260 base::LazyInstance<base::ThreadLocalBoolean> g_inside_scoped_update_texture;
261 #endif
263 } // anonymous namespace
265 // static
266 scoped_refptr<NativeImageBuffer> NativeImageBuffer::Create(GLuint texture_id) {
267 switch (gfx::GetGLImplementation()) {
268 #if !defined(OS_MACOSX)
269 case gfx::kGLImplementationEGLGLES2:
270 return NativeImageBufferEGL::Create(texture_id);
271 #endif
272 case gfx::kGLImplementationMockGL:
273 return new NativeImageBufferStub;
274 default:
275 NOTREACHED();
276 return NULL;
280 // static
281 void TextureDefinition::AvoidEGLTargetTextureReuse() {
282 g_avoid_egl_target_texture_reuse = true;
285 ScopedUpdateTexture::ScopedUpdateTexture() {
286 #if DCHECK_IS_ON()
287 DCHECK(!g_inside_scoped_update_texture.Get().Get());
288 g_inside_scoped_update_texture.Get().Set(true);
289 #endif
292 ScopedUpdateTexture::~ScopedUpdateTexture() {
293 #if DCHECK_IS_ON()
294 DCHECK(g_inside_scoped_update_texture.Get().Get());
295 g_inside_scoped_update_texture.Get().Set(false);
296 #endif
297 // We have to make sure the changes are visible to other clients in this share
298 // group. As far as the clients are concerned, the mailbox semantics only
299 // demand a single flush from the client after changes are first made,
300 // and it is not visible to them when another share group boundary is crossed.
301 // We could probably track this and be a bit smarter about when to flush
302 // though.
303 glFlush();
306 TextureDefinition::LevelInfo::LevelInfo()
307 : target(0),
308 internal_format(0),
309 width(0),
310 height(0),
311 depth(0),
312 border(0),
313 format(0),
314 type(0) {
317 TextureDefinition::LevelInfo::LevelInfo(GLenum target,
318 GLenum internal_format,
319 GLsizei width,
320 GLsizei height,
321 GLsizei depth,
322 GLint border,
323 GLenum format,
324 GLenum type,
325 const gfx::Rect& cleared_rect)
326 : target(target),
327 internal_format(internal_format),
328 width(width),
329 height(height),
330 depth(depth),
331 border(border),
332 format(format),
333 type(type),
334 cleared_rect(cleared_rect) {
337 TextureDefinition::LevelInfo::~LevelInfo() {}
339 TextureDefinition::TextureDefinition()
340 : version_(0),
341 target_(0),
342 min_filter_(0),
343 mag_filter_(0),
344 wrap_s_(0),
345 wrap_t_(0),
346 usage_(0),
347 immutable_(true) {
350 TextureDefinition::TextureDefinition(
351 Texture* texture,
352 unsigned int version,
353 const scoped_refptr<NativeImageBuffer>& image_buffer)
354 : version_(version),
355 target_(texture->target()),
356 image_buffer_(image_buffer),
357 min_filter_(texture->min_filter()),
358 mag_filter_(texture->mag_filter()),
359 wrap_s_(texture->wrap_s()),
360 wrap_t_(texture->wrap_t()),
361 usage_(texture->usage()),
362 immutable_(texture->IsImmutable()),
363 defined_(texture->IsDefined()) {
364 DCHECK_IMPLIES(image_buffer_.get(), defined_);
365 if (!image_buffer_.get() && defined_) {
366 image_buffer_ = NativeImageBuffer::Create(texture->service_id());
367 DCHECK(image_buffer_.get());
370 const Texture::FaceInfo& first_face = texture->face_infos_[0];
371 if (image_buffer_.get()) {
372 scoped_refptr<gfx::GLImage> gl_image(
373 new GLImageSync(image_buffer_,
374 gfx::Size(first_face.level_infos[0].width,
375 first_face.level_infos[0].height)));
376 texture->SetLevelImage(NULL, target_, 0, gl_image.get());
379 const Texture::LevelInfo& level = first_face.level_infos[0];
380 level_info_ = LevelInfo(level.target, level.internal_format, level.width,
381 level.height, level.depth, level.border, level.format,
382 level.type, level.cleared_rect);
385 TextureDefinition::~TextureDefinition() {
388 Texture* TextureDefinition::CreateTexture() const {
389 GLuint texture_id;
390 glGenTextures(1, &texture_id);
392 Texture* texture(new Texture(texture_id));
393 ScopedUpdateTexture scoped_update_texture;
394 UpdateTextureInternal(texture);
396 return texture;
399 void TextureDefinition::UpdateTextureInternal(Texture* texture) const {
400 #if DCHECK_IS_ON()
401 DCHECK(g_inside_scoped_update_texture.Get().Get());
402 #endif
403 gfx::ScopedTextureBinder texture_binder(target_, texture->service_id());
404 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_);
405 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_);
406 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s_);
407 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_);
409 if (image_buffer_.get()) {
410 gfx::GLImage* existing_image = texture->GetLevelImage(target_, 0);
411 // Don't need to re-bind if already bound before.
412 if (!existing_image || !image_buffer_->IsClient(existing_image)) {
413 image_buffer_->BindToTexture(target_);
417 if (defined_) {
418 texture->face_infos_.resize(1);
419 texture->face_infos_[0].level_infos.resize(1);
420 texture->SetLevelInfo(NULL, level_info_.target, 0,
421 level_info_.internal_format, level_info_.width,
422 level_info_.height, level_info_.depth,
423 level_info_.border, level_info_.format,
424 level_info_.type, level_info_.cleared_rect);
427 if (image_buffer_.get()) {
428 texture->SetLevelImage(
429 NULL,
430 target_,
432 new GLImageSync(
433 image_buffer_,
434 gfx::Size(level_info_.width, level_info_.height)));
437 texture->target_ = target_;
438 texture->SetImmutable(immutable_);
439 texture->min_filter_ = min_filter_;
440 texture->mag_filter_ = mag_filter_;
441 texture->wrap_s_ = wrap_s_;
442 texture->wrap_t_ = wrap_t_;
443 texture->usage_ = usage_;
446 void TextureDefinition::UpdateTexture(Texture* texture) const {
447 GLuint old_service_id = 0u;
448 if (image_buffer_.get() && g_avoid_egl_target_texture_reuse) {
449 GLuint service_id = 0u;
450 glGenTextures(1, &service_id);
451 old_service_id = texture->service_id();
452 texture->SetServiceId(service_id);
454 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), target_);
455 GLint bound_id = 0;
456 glGetIntegerv(GL_TEXTURE_BINDING_2D, &bound_id);
457 if (bound_id == static_cast<GLint>(old_service_id)) {
458 glBindTexture(target_, service_id);
460 texture->SetLevelImage(NULL, target_, 0, NULL);
463 UpdateTextureInternal(texture);
465 if (old_service_id) {
466 glDeleteTextures(1, &old_service_id);
470 bool TextureDefinition::Matches(const Texture* texture) const {
471 DCHECK(target_ == texture->target());
472 if (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->SafeToRenderFrom() != SafeToRenderFrom()) {
477 return false;
480 // Texture became defined.
481 if (!image_buffer_.get() && texture->IsDefined())
482 return false;
484 // All structural changes should have orphaned the texture.
485 if (image_buffer_.get() && !texture->GetLevelImage(texture->target(), 0))
486 return false;
488 return true;
491 bool TextureDefinition::SafeToRenderFrom() const {
492 return level_info_.cleared_rect.Contains(
493 gfx::Rect(level_info_.width, level_info_.height));
496 } // namespace gles2
497 } // namespace gpu