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 "gpu/command_buffer/service/texture_manager.h"
8 #include "ui/gl/gl_image.h"
9 #include "ui/gl/gl_implementation.h"
10 #include "ui/gl/scoped_binders.h"
12 #if !defined(OS_MACOSX)
13 #include "ui/gl/gl_surface_egl.h"
21 class GLImageSync : public gfx::GLImage {
23 explicit GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer,
24 const gfx::Size& size);
27 virtual void Destroy() OVERRIDE;
28 virtual gfx::Size GetSize() OVERRIDE;
29 virtual bool BindTexImage(unsigned target) OVERRIDE;
30 virtual void ReleaseTexImage(unsigned target) OVERRIDE;
31 virtual void WillUseTexImage() OVERRIDE;
32 virtual void WillModifyTexImage() OVERRIDE;
33 virtual void DidModifyTexImage() OVERRIDE;
35 virtual void DidUseTexImage() OVERRIDE;
36 virtual void SetReleaseAfterUse() OVERRIDE;
39 virtual ~GLImageSync();
42 scoped_refptr<NativeImageBuffer> buffer_;
45 DISALLOW_COPY_AND_ASSIGN(GLImageSync);
48 GLImageSync::GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer,
49 const gfx::Size& size)
50 : buffer_(buffer), size_(size) {
52 buffer->AddClient(this);
55 GLImageSync::~GLImageSync() {
57 buffer_->RemoveClient(this);
60 void GLImageSync::Destroy() {}
62 gfx::Size GLImageSync::GetSize() {
66 bool GLImageSync::BindTexImage(unsigned target) {
71 void GLImageSync::ReleaseTexImage(unsigned target) {
75 void GLImageSync::WillUseTexImage() {
77 buffer_->WillRead(this);
80 void GLImageSync::DidUseTexImage() {
82 buffer_->DidRead(this);
85 void GLImageSync::WillModifyTexImage() {
87 buffer_->WillWrite(this);
90 void GLImageSync::DidModifyTexImage() {
92 buffer_->DidWrite(this);
95 void GLImageSync::SetReleaseAfterUse() {
99 #if !defined(OS_MACOSX)
100 class NativeImageBufferEGL : public NativeImageBuffer {
102 static scoped_refptr<NativeImageBufferEGL> Create(GLuint texture_id);
105 NativeImageBufferEGL(scoped_ptr<gfx::GLFence> write_fence,
108 virtual ~NativeImageBufferEGL();
109 virtual void BindToTexture(GLenum target) OVERRIDE;
111 EGLDisplay egl_display_;
112 EGLImageKHR egl_image_;
114 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferEGL);
117 scoped_refptr<NativeImageBufferEGL> NativeImageBufferEGL::Create(
119 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
120 EGLContext egl_context = eglGetCurrentContext();
122 DCHECK_NE(EGL_NO_CONTEXT, egl_context);
123 DCHECK_NE(EGL_NO_DISPLAY, egl_display);
124 DCHECK(glIsTexture(texture_id));
126 DCHECK(gfx::g_driver_egl.ext.b_EGL_KHR_image_base &&
127 gfx::g_driver_egl.ext.b_EGL_KHR_gl_texture_2D_image &&
128 gfx::g_driver_gl.ext.b_GL_OES_EGL_image &&
129 gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync);
131 const EGLint egl_attrib_list[] = {
132 EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
133 EGLClientBuffer egl_buffer = reinterpret_cast<EGLClientBuffer>(texture_id);
134 EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR; // TODO
136 EGLImageKHR egl_image = eglCreateImageKHR(
137 egl_display, egl_context, egl_target, egl_buffer, egl_attrib_list);
139 if (egl_image == EGL_NO_IMAGE_KHR)
142 return new NativeImageBufferEGL(
143 make_scoped_ptr(gfx::GLFence::Create()), egl_display, egl_image);
146 NativeImageBufferEGL::NativeImageBufferEGL(scoped_ptr<gfx::GLFence> write_fence,
149 : NativeImageBuffer(write_fence.Pass()),
150 egl_display_(display),
152 DCHECK(egl_display_ != EGL_NO_DISPLAY);
153 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
156 NativeImageBufferEGL::~NativeImageBufferEGL() {
157 if (egl_image_ != EGL_NO_IMAGE_KHR)
158 eglDestroyImageKHR(egl_display_, egl_image_);
161 void NativeImageBufferEGL::BindToTexture(GLenum target) {
162 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
163 glEGLImageTargetTexture2DOES(target, egl_image_);
164 DCHECK_EQ(static_cast<EGLint>(EGL_SUCCESS), eglGetError());
165 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
169 class NativeImageBufferStub : public NativeImageBuffer {
171 NativeImageBufferStub() : NativeImageBuffer(scoped_ptr<gfx::GLFence>()) {}
174 virtual ~NativeImageBufferStub() {}
175 virtual void BindToTexture(GLenum target) OVERRIDE {}
177 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferStub);
180 } // anonymous namespace
183 scoped_refptr<NativeImageBuffer> NativeImageBuffer::Create(GLuint texture_id) {
184 switch (gfx::GetGLImplementation()) {
185 #if !defined(OS_MACOSX)
186 case gfx::kGLImplementationEGLGLES2:
187 return NativeImageBufferEGL::Create(texture_id);
189 case gfx::kGLImplementationMockGL:
190 return new NativeImageBufferStub;
197 NativeImageBuffer::ClientInfo::ClientInfo(gfx::GLImage* client)
198 : client(client), needs_wait_before_read(true) {}
200 NativeImageBuffer::ClientInfo::~ClientInfo() {}
202 NativeImageBuffer::NativeImageBuffer(scoped_ptr<gfx::GLFence> write_fence)
203 : write_fence_(write_fence.Pass()), write_client_(NULL) {
206 NativeImageBuffer::~NativeImageBuffer() {
207 DCHECK(client_infos_.empty());
210 void NativeImageBuffer::AddClient(gfx::GLImage* client) {
211 base::AutoLock lock(lock_);
212 client_infos_.push_back(ClientInfo(client));
215 void NativeImageBuffer::RemoveClient(gfx::GLImage* client) {
216 base::AutoLock lock(lock_);
217 if (write_client_ == client)
218 write_client_ = NULL;
219 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
220 it != client_infos_.end();
222 if (it->client == client) {
223 client_infos_.erase(it);
230 bool NativeImageBuffer::IsClient(gfx::GLImage* client) {
231 base::AutoLock lock(lock_);
232 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
233 it != client_infos_.end();
235 if (it->client == client)
241 void NativeImageBuffer::WillRead(gfx::GLImage* client) {
242 base::AutoLock lock(lock_);
243 if (!write_fence_.get() || write_client_ == client)
246 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
247 it != client_infos_.end();
249 if (it->client == client) {
250 if (it->needs_wait_before_read) {
251 it->needs_wait_before_read = false;
252 write_fence_->ServerWait();
260 void NativeImageBuffer::WillWrite(gfx::GLImage* client) {
261 base::AutoLock lock(lock_);
262 if (write_client_ != client)
263 write_fence_->ServerWait();
265 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
266 it != client_infos_.end();
268 if (it->read_fence.get() && it->client != client)
269 it->read_fence->ServerWait();
273 void NativeImageBuffer::DidRead(gfx::GLImage* client) {
274 base::AutoLock lock(lock_);
275 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
276 it != client_infos_.end();
278 if (it->client == client) {
279 it->read_fence = make_linked_ptr(gfx::GLFence::Create());
286 void NativeImageBuffer::DidWrite(gfx::GLImage* client) {
287 base::AutoLock lock(lock_);
288 // Sharing semantics require the client to flush in order to make changes
289 // visible to other clients.
290 write_fence_.reset(gfx::GLFence::CreateWithoutFlush());
291 write_client_ = client;
292 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
293 it != client_infos_.end();
295 it->needs_wait_before_read = true;
299 TextureDefinition::LevelInfo::LevelInfo(GLenum target,
300 GLenum internal_format,
309 internal_format(internal_format),
318 TextureDefinition::LevelInfo::~LevelInfo() {}
320 TextureDefinition::TextureDefinition(
323 unsigned int version,
324 const scoped_refptr<NativeImageBuffer>& image_buffer)
327 image_buffer_(image_buffer ? image_buffer : NativeImageBuffer::Create(
328 texture->service_id())),
329 min_filter_(texture->min_filter()),
330 mag_filter_(texture->mag_filter()),
331 wrap_s_(texture->wrap_s()),
332 wrap_t_(texture->wrap_t()),
333 usage_(texture->usage()),
334 immutable_(texture->IsImmutable()) {
337 DCHECK(!texture->level_infos_.empty());
338 DCHECK(!texture->level_infos_[0].empty());
339 DCHECK(!texture->NeedsMips());
340 DCHECK(texture->level_infos_[0][0].width);
341 DCHECK(texture->level_infos_[0][0].height);
343 scoped_refptr<gfx::GLImage> gl_image(
344 new GLImageSync(image_buffer_,
345 gfx::Size(texture->level_infos_[0][0].width,
346 texture->level_infos_[0][0].height)));
347 texture->SetLevelImage(NULL, target, 0, gl_image);
350 level_infos_.clear();
351 const Texture::LevelInfo& level = texture->level_infos_[0][0];
352 LevelInfo info(level.target,
353 level.internal_format,
361 std::vector<LevelInfo> infos;
362 infos.push_back(info);
363 level_infos_.push_back(infos);
366 TextureDefinition::~TextureDefinition() {
369 Texture* TextureDefinition::CreateTexture() const {
374 glGenTextures(1, &texture_id);
376 Texture* texture(new Texture(texture_id));
377 UpdateTexture(texture);
382 void TextureDefinition::UpdateTexture(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 image_buffer_->BindToTexture(target_);
390 // We have to make sure the changes are visible to other clients in this share
391 // group. As far as the clients are concerned, the mailbox semantics only
392 // demand a single flush from the client after changes are first made,
393 // and it is not visible to them when another share group boundary is crossed.
394 // We could probably track this and be a bit smarter about when to flush
398 texture->level_infos_.resize(1);
399 for (size_t i = 0; i < level_infos_.size(); i++) {
400 const LevelInfo& base_info = level_infos_[i][0];
401 const size_t levels_needed = TextureManager::ComputeMipMapCount(
402 base_info.target, base_info.width, base_info.height, base_info.depth);
403 DCHECK(level_infos_.size() <= levels_needed);
404 texture->level_infos_[0].resize(levels_needed);
405 for (size_t n = 0; n < level_infos_.size(); n++) {
406 const LevelInfo& info = level_infos_[i][n];
407 texture->SetLevelInfo(NULL,
410 info.internal_format,
421 texture->SetLevelImage(
427 gfx::Size(level_infos_[0][0].width, level_infos_[0][0].height)));
430 texture->target_ = target_;
431 texture->SetImmutable(immutable_);
432 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->usage_ = usage_;
439 bool TextureDefinition::Matches(const Texture* texture) const {
440 DCHECK(target_ == texture->target());
441 if (texture->min_filter_ != min_filter_ ||
442 texture->mag_filter_ != mag_filter_ ||
443 texture->wrap_s_ != wrap_s_ ||
444 texture->wrap_t_ != wrap_t_) {
448 // All structural changes should have orphaned the texture.
449 if (image_buffer_ && !texture->GetLevelImage(texture->target(), 0))