Revert "Reland c91b178b07b0d - Delete dead signin code (SigninGlobalError)"
[chromium-blink-merge.git] / gpu / command_buffer / service / texture_definition.cc
blob466536bb5250e9f8078d2e922511a027b6f51d36
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 #if DCHECK_IS_ON()
269 base::LazyInstance<base::ThreadLocalBoolean> g_inside_scoped_update_texture;
270 #endif
272 } // anonymous namespace
274 // static
275 scoped_refptr<NativeImageBuffer> NativeImageBuffer::Create(GLuint texture_id) {
276 switch (gfx::GetGLImplementation()) {
277 #if !defined(OS_MACOSX)
278 case gfx::kGLImplementationEGLGLES2:
279 return NativeImageBufferEGL::Create(texture_id);
280 #endif
281 case gfx::kGLImplementationMockGL:
282 return new NativeImageBufferStub;
283 default:
284 NOTREACHED();
285 return NULL;
289 // static
290 void TextureDefinition::AvoidEGLTargetTextureReuse() {
291 g_avoid_egl_target_texture_reuse = true;
294 ScopedUpdateTexture::ScopedUpdateTexture() {
295 #if DCHECK_IS_ON()
296 DCHECK(!g_inside_scoped_update_texture.Get().Get());
297 g_inside_scoped_update_texture.Get().Set(true);
298 #endif
301 ScopedUpdateTexture::~ScopedUpdateTexture() {
302 #if DCHECK_IS_ON()
303 DCHECK(g_inside_scoped_update_texture.Get().Get());
304 g_inside_scoped_update_texture.Get().Set(false);
305 #endif
306 // We have to make sure the changes are visible to other clients in this share
307 // group. As far as the clients are concerned, the mailbox semantics only
308 // demand a single flush from the client after changes are first made,
309 // and it is not visible to them when another share group boundary is crossed.
310 // We could probably track this and be a bit smarter about when to flush
311 // though.
312 glFlush();
315 TextureDefinition::LevelInfo::LevelInfo()
316 : target(0),
317 internal_format(0),
318 width(0),
319 height(0),
320 depth(0),
321 border(0),
322 format(0),
323 type(0) {
326 TextureDefinition::LevelInfo::LevelInfo(GLenum target,
327 GLenum internal_format,
328 GLsizei width,
329 GLsizei height,
330 GLsizei depth,
331 GLint border,
332 GLenum format,
333 GLenum type,
334 const gfx::Rect& cleared_rect)
335 : target(target),
336 internal_format(internal_format),
337 width(width),
338 height(height),
339 depth(depth),
340 border(border),
341 format(format),
342 type(type),
343 cleared_rect(cleared_rect) {
346 TextureDefinition::LevelInfo::~LevelInfo() {}
348 TextureDefinition::TextureDefinition()
349 : version_(0),
350 target_(0),
351 min_filter_(0),
352 mag_filter_(0),
353 wrap_s_(0),
354 wrap_t_(0),
355 usage_(0),
356 immutable_(true) {
359 TextureDefinition::TextureDefinition(
360 Texture* texture,
361 unsigned int version,
362 const scoped_refptr<NativeImageBuffer>& image_buffer)
363 : version_(version),
364 target_(texture->target()),
365 image_buffer_(image_buffer),
366 min_filter_(texture->min_filter()),
367 mag_filter_(texture->mag_filter()),
368 wrap_s_(texture->wrap_s()),
369 wrap_t_(texture->wrap_t()),
370 usage_(texture->usage()),
371 immutable_(texture->IsImmutable()),
372 defined_(texture->IsDefined()) {
373 DCHECK_IMPLIES(image_buffer_.get(), defined_);
374 if (!image_buffer_.get() && defined_) {
375 image_buffer_ = NativeImageBuffer::Create(texture->service_id());
376 DCHECK(image_buffer_.get());
379 const Texture::FaceInfo& first_face = texture->face_infos_[0];
380 if (image_buffer_.get()) {
381 scoped_refptr<gfx::GLImage> gl_image(
382 new GLImageSync(image_buffer_,
383 gfx::Size(first_face.level_infos[0].width,
384 first_face.level_infos[0].height)));
385 texture->SetLevelImage(NULL, target_, 0, gl_image.get());
388 const Texture::LevelInfo& level = first_face.level_infos[0];
389 level_info_ = LevelInfo(level.target, level.internal_format, level.width,
390 level.height, level.depth, level.border, level.format,
391 level.type, level.cleared_rect);
394 TextureDefinition::~TextureDefinition() {
397 Texture* TextureDefinition::CreateTexture() const {
398 GLuint texture_id;
399 glGenTextures(1, &texture_id);
401 Texture* texture(new Texture(texture_id));
402 ScopedUpdateTexture scoped_update_texture;
403 UpdateTextureInternal(texture);
405 return texture;
408 void TextureDefinition::UpdateTextureInternal(Texture* texture) const {
409 #if DCHECK_IS_ON()
410 DCHECK(g_inside_scoped_update_texture.Get().Get());
411 #endif
412 gfx::ScopedTextureBinder texture_binder(target_, texture->service_id());
413 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_);
414 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_);
415 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s_);
416 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_);
418 if (image_buffer_.get()) {
419 gfx::GLImage* existing_image = texture->GetLevelImage(target_, 0);
420 // Don't need to re-bind if already bound before.
421 if (!existing_image || !image_buffer_->IsClient(existing_image)) {
422 image_buffer_->BindToTexture(target_);
426 if (defined_) {
427 texture->face_infos_.resize(1);
428 texture->face_infos_[0].level_infos.resize(1);
429 texture->SetLevelInfo(NULL, level_info_.target, 0,
430 level_info_.internal_format, level_info_.width,
431 level_info_.height, level_info_.depth,
432 level_info_.border, level_info_.format,
433 level_info_.type, level_info_.cleared_rect);
436 if (image_buffer_.get()) {
437 texture->SetLevelImage(
438 NULL,
439 target_,
441 new GLImageSync(
442 image_buffer_,
443 gfx::Size(level_info_.width, level_info_.height)));
446 texture->target_ = target_;
447 texture->SetImmutable(immutable_);
448 texture->min_filter_ = min_filter_;
449 texture->mag_filter_ = mag_filter_;
450 texture->wrap_s_ = wrap_s_;
451 texture->wrap_t_ = wrap_t_;
452 texture->usage_ = usage_;
455 void TextureDefinition::UpdateTexture(Texture* texture) const {
456 GLuint old_service_id = 0u;
457 if (image_buffer_.get() && g_avoid_egl_target_texture_reuse) {
458 GLuint service_id = 0u;
459 glGenTextures(1, &service_id);
460 old_service_id = texture->service_id();
461 texture->SetServiceId(service_id);
463 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), target_);
464 GLint bound_id = 0;
465 glGetIntegerv(GL_TEXTURE_BINDING_2D, &bound_id);
466 if (bound_id == static_cast<GLint>(old_service_id)) {
467 glBindTexture(target_, service_id);
469 texture->SetLevelImage(NULL, target_, 0, NULL);
472 UpdateTextureInternal(texture);
474 if (old_service_id) {
475 glDeleteTextures(1, &old_service_id);
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 texture->SafeToRenderFrom() != SafeToRenderFrom()) {
486 return false;
489 // Texture became defined.
490 if (!image_buffer_.get() && texture->IsDefined())
491 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 bool TextureDefinition::SafeToRenderFrom() const {
501 return level_info_.cleared_rect.Contains(
502 gfx::Rect(level_info_.width, level_info_.height));
505 } // namespace gles2
506 } // namespace gpu