Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / gpu / command_buffer / service / texture_definition.cc
blobd81d2583b39b650f5c27b97d41b034d26e0cd73c
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_surface_egl.h"
19 #endif
21 namespace gpu {
22 namespace gles2 {
24 namespace {
26 class GLImageSync : public gfx::GLImage {
27 public:
28 explicit GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer,
29 const gfx::Size& size);
31 // Implement GLImage.
32 void Destroy(bool have_context) override;
33 gfx::Size GetSize() override;
34 bool BindTexImage(unsigned target) override;
35 void ReleaseTexImage(unsigned target) override;
36 bool CopyTexImage(unsigned target) override;
37 void WillUseTexImage() override;
38 void WillModifyTexImage() override;
39 void DidModifyTexImage() override;
40 void DidUseTexImage() override;
41 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;
47 protected:
48 ~GLImageSync() override;
50 private:
51 scoped_refptr<NativeImageBuffer> buffer_;
52 gfx::Size size_;
54 DISALLOW_COPY_AND_ASSIGN(GLImageSync);
57 GLImageSync::GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer,
58 const gfx::Size& size)
59 : buffer_(buffer), size_(size) {
60 if (buffer.get())
61 buffer->AddClient(this);
64 GLImageSync::~GLImageSync() {
65 if (buffer_.get())
66 buffer_->RemoveClient(this);
69 void GLImageSync::Destroy(bool have_context) {
72 gfx::Size GLImageSync::GetSize() {
73 return size_;
76 bool GLImageSync::BindTexImage(unsigned target) {
77 NOTREACHED();
78 return false;
81 void GLImageSync::ReleaseTexImage(unsigned target) {
82 NOTREACHED();
85 bool GLImageSync::CopyTexImage(unsigned target) {
86 return false;
89 void GLImageSync::WillUseTexImage() {
92 void GLImageSync::DidUseTexImage() {
95 void GLImageSync::WillModifyTexImage() {
98 void GLImageSync::DidModifyTexImage() {
101 bool GLImageSync::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
102 int z_order,
103 gfx::OverlayTransform transform,
104 const gfx::Rect& bounds_rect,
105 const gfx::RectF& crop_rect) {
106 NOTREACHED();
107 return false;
110 #if !defined(OS_MACOSX)
111 class NativeImageBufferEGL : public NativeImageBuffer {
112 public:
113 static scoped_refptr<NativeImageBufferEGL> Create(GLuint texture_id);
115 private:
116 NativeImageBufferEGL(EGLDisplay display, EGLImageKHR image);
117 ~NativeImageBufferEGL() override;
118 void AddClient(gfx::GLImage* client) override;
119 void RemoveClient(gfx::GLImage* client) override;
120 bool IsClient(gfx::GLImage* client) override;
121 void BindToTexture(GLenum target) override;
123 EGLDisplay egl_display_;
124 EGLImageKHR egl_image_;
126 base::Lock lock_;
128 struct ClientInfo {
129 explicit ClientInfo(gfx::GLImage* client);
130 ~ClientInfo();
132 gfx::GLImage* client;
133 bool needs_wait_before_read;
135 std::list<ClientInfo> client_infos_;
136 gfx::GLImage* write_client_;
138 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferEGL);
141 scoped_refptr<NativeImageBufferEGL> NativeImageBufferEGL::Create(
142 GLuint texture_id) {
143 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
144 EGLContext egl_context = eglGetCurrentContext();
146 DCHECK_NE(EGL_NO_CONTEXT, egl_context);
147 DCHECK_NE(EGL_NO_DISPLAY, egl_display);
148 DCHECK(glIsTexture(texture_id));
150 DCHECK(gfx::g_driver_egl.ext.b_EGL_KHR_image_base &&
151 gfx::g_driver_egl.ext.b_EGL_KHR_gl_texture_2D_image &&
152 gfx::g_driver_gl.ext.b_GL_OES_EGL_image);
154 const EGLint egl_attrib_list[] = {
155 EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
156 EGLClientBuffer egl_buffer = reinterpret_cast<EGLClientBuffer>(texture_id);
157 EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR;
159 EGLImageKHR egl_image = eglCreateImageKHR(
160 egl_display, egl_context, egl_target, egl_buffer, egl_attrib_list);
162 if (egl_image == EGL_NO_IMAGE_KHR) {
163 LOG(ERROR) << "eglCreateImageKHR for cross-thread sharing failed: 0x"
164 << std::hex << eglGetError();
165 return NULL;
168 return new NativeImageBufferEGL(egl_display, egl_image);
171 NativeImageBufferEGL::ClientInfo::ClientInfo(gfx::GLImage* client)
172 : client(client), needs_wait_before_read(true) {}
174 NativeImageBufferEGL::ClientInfo::~ClientInfo() {}
176 NativeImageBufferEGL::NativeImageBufferEGL(EGLDisplay display,
177 EGLImageKHR image)
178 : NativeImageBuffer(),
179 egl_display_(display),
180 egl_image_(image),
181 write_client_(NULL) {
182 DCHECK(egl_display_ != EGL_NO_DISPLAY);
183 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
186 NativeImageBufferEGL::~NativeImageBufferEGL() {
187 DCHECK(client_infos_.empty());
188 if (egl_image_ != EGL_NO_IMAGE_KHR)
189 eglDestroyImageKHR(egl_display_, egl_image_);
192 void NativeImageBufferEGL::AddClient(gfx::GLImage* client) {
193 base::AutoLock lock(lock_);
194 client_infos_.push_back(ClientInfo(client));
197 void NativeImageBufferEGL::RemoveClient(gfx::GLImage* client) {
198 base::AutoLock lock(lock_);
199 if (write_client_ == client)
200 write_client_ = NULL;
201 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
202 it != client_infos_.end();
203 it++) {
204 if (it->client == client) {
205 client_infos_.erase(it);
206 return;
209 NOTREACHED();
212 bool NativeImageBufferEGL::IsClient(gfx::GLImage* client) {
213 base::AutoLock lock(lock_);
214 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
215 it != client_infos_.end();
216 it++) {
217 if (it->client == client)
218 return true;
220 return false;
223 void NativeImageBufferEGL::BindToTexture(GLenum target) {
224 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
225 glEGLImageTargetTexture2DOES(target, egl_image_);
226 DCHECK_EQ(static_cast<EGLint>(EGL_SUCCESS), eglGetError());
227 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
230 #endif
232 class NativeImageBufferStub : public NativeImageBuffer {
233 public:
234 NativeImageBufferStub() : NativeImageBuffer() {}
236 private:
237 ~NativeImageBufferStub() override {}
238 void AddClient(gfx::GLImage* client) override {}
239 void RemoveClient(gfx::GLImage* client) override {}
240 bool IsClient(gfx::GLImage* client) override { return true; }
241 void BindToTexture(GLenum target) override {}
243 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferStub);
246 bool g_avoid_egl_target_texture_reuse = false;
248 } // anonymous namespace
250 // static
251 scoped_refptr<NativeImageBuffer> NativeImageBuffer::Create(GLuint texture_id) {
252 switch (gfx::GetGLImplementation()) {
253 #if !defined(OS_MACOSX)
254 case gfx::kGLImplementationEGLGLES2:
255 return NativeImageBufferEGL::Create(texture_id);
256 #endif
257 case gfx::kGLImplementationMockGL:
258 return new NativeImageBufferStub;
259 default:
260 NOTREACHED();
261 return NULL;
265 // static
266 void TextureDefinition::AvoidEGLTargetTextureReuse() {
267 g_avoid_egl_target_texture_reuse = true;
270 TextureDefinition::LevelInfo::LevelInfo()
271 : target(0),
272 internal_format(0),
273 width(0),
274 height(0),
275 depth(0),
276 border(0),
277 format(0),
278 type(0),
279 cleared(false) {
282 TextureDefinition::LevelInfo::LevelInfo(GLenum target,
283 GLenum internal_format,
284 GLsizei width,
285 GLsizei height,
286 GLsizei depth,
287 GLint border,
288 GLenum format,
289 GLenum type,
290 bool cleared)
291 : target(target),
292 internal_format(internal_format),
293 width(width),
294 height(height),
295 depth(depth),
296 border(border),
297 format(format),
298 type(type),
299 cleared(cleared) {}
301 TextureDefinition::LevelInfo::~LevelInfo() {}
303 TextureDefinition::TextureDefinition()
304 : version_(0),
305 target_(0),
306 min_filter_(0),
307 mag_filter_(0),
308 wrap_s_(0),
309 wrap_t_(0),
310 usage_(0),
311 immutable_(true) {
314 TextureDefinition::TextureDefinition(
315 Texture* texture,
316 unsigned int version,
317 const scoped_refptr<NativeImageBuffer>& image_buffer)
318 : version_(version),
319 target_(texture->target()),
320 image_buffer_(image_buffer),
321 min_filter_(texture->min_filter()),
322 mag_filter_(texture->mag_filter()),
323 wrap_s_(texture->wrap_s()),
324 wrap_t_(texture->wrap_t()),
325 usage_(texture->usage()),
326 immutable_(texture->IsImmutable()),
327 defined_(texture->IsDefined()) {
328 DCHECK_IMPLIES(image_buffer_.get(), defined_);
329 if (!image_buffer_.get() && defined_) {
330 image_buffer_ = NativeImageBuffer::Create(texture->service_id());
331 DCHECK(image_buffer_.get());
334 const Texture::FaceInfo& first_face = texture->face_infos_[0];
335 if (image_buffer_.get()) {
336 scoped_refptr<gfx::GLImage> gl_image(
337 new GLImageSync(image_buffer_,
338 gfx::Size(first_face.level_infos[0].width,
339 first_face.level_infos[0].height)));
340 texture->SetLevelImage(NULL, target_, 0, gl_image.get());
343 const Texture::LevelInfo& level = first_face.level_infos[0];
344 level_info_ = LevelInfo(level.target, level.internal_format, level.width,
345 level.height, level.depth, level.border, level.format,
346 level.type, level.cleared);
349 TextureDefinition::~TextureDefinition() {
352 Texture* TextureDefinition::CreateTexture() const {
353 GLuint texture_id;
354 glGenTextures(1, &texture_id);
356 Texture* texture(new Texture(texture_id));
357 UpdateTextureInternal(texture);
359 return texture;
362 void TextureDefinition::UpdateTextureInternal(Texture* texture) const {
363 gfx::ScopedTextureBinder texture_binder(target_, texture->service_id());
364 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_);
365 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_);
366 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s_);
367 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_);
368 if (image_buffer_.get())
369 image_buffer_->BindToTexture(target_);
370 // We have to make sure the changes are visible to other clients in this share
371 // group. As far as the clients are concerned, the mailbox semantics only
372 // demand a single flush from the client after changes are first made,
373 // and it is not visible to them when another share group boundary is crossed.
374 // We could probably track this and be a bit smarter about when to flush
375 // though.
376 glFlush();
378 if (defined_) {
379 texture->face_infos_.resize(1);
380 texture->face_infos_[0].level_infos.resize(1);
381 texture->SetLevelInfo(NULL, level_info_.target, 0,
382 level_info_.internal_format, level_info_.width,
383 level_info_.height, level_info_.depth,
384 level_info_.border, level_info_.format,
385 level_info_.type, level_info_.cleared);
388 if (image_buffer_.get()) {
389 texture->SetLevelImage(
390 NULL,
391 target_,
393 new GLImageSync(
394 image_buffer_,
395 gfx::Size(level_info_.width, level_info_.height)));
398 texture->target_ = target_;
399 texture->SetImmutable(immutable_);
400 texture->min_filter_ = min_filter_;
401 texture->mag_filter_ = mag_filter_;
402 texture->wrap_s_ = wrap_s_;
403 texture->wrap_t_ = wrap_t_;
404 texture->usage_ = usage_;
407 void TextureDefinition::UpdateTexture(Texture* texture) const {
408 GLuint old_service_id = 0u;
409 if (image_buffer_.get() && g_avoid_egl_target_texture_reuse) {
410 GLuint service_id = 0u;
411 glGenTextures(1, &service_id);
412 old_service_id = texture->service_id();
413 texture->SetServiceId(service_id);
415 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), target_);
416 GLint bound_id = 0;
417 glGetIntegerv(GL_TEXTURE_BINDING_2D, &bound_id);
418 if (bound_id == static_cast<GLint>(old_service_id)) {
419 glBindTexture(target_, service_id);
423 UpdateTextureInternal(texture);
425 if (old_service_id) {
426 glDeleteTextures(1, &old_service_id);
430 bool TextureDefinition::Matches(const Texture* texture) const {
431 DCHECK(target_ == texture->target());
432 if (texture->min_filter_ != min_filter_ ||
433 texture->mag_filter_ != mag_filter_ ||
434 texture->wrap_s_ != wrap_s_ ||
435 texture->wrap_t_ != wrap_t_ ||
436 texture->SafeToRenderFrom() != SafeToRenderFrom()) {
437 return false;
440 // Texture became defined.
441 if (!image_buffer_.get() && texture->IsDefined())
442 return false;
444 // All structural changes should have orphaned the texture.
445 if (image_buffer_.get() && !texture->GetLevelImage(texture->target(), 0))
446 return false;
448 return true;
451 bool TextureDefinition::SafeToRenderFrom() const {
452 return level_info_.cleared;
455 } // namespace gles2
456 } // namespace gpu