| // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/gpu/gpu_backing_store_glx_context.h" |
| |
| #include "app/gfx/gl/gl_bindings.h" |
| #include "app/x11_util.h" |
| #include "base/scoped_ptr.h" |
| #include "chrome/gpu/gpu_thread.h" |
| |
| // Must be last. |
| #include <X11/Xutil.h> |
| |
| GpuBackingStoreGLXContext::GpuBackingStoreGLXContext(GpuThread* gpu_thread) |
| : gpu_thread_(gpu_thread), |
| tried_to_init_(false), |
| context_(NULL), |
| previous_window_id_(0), |
| frame_buffer_for_scrolling_(0), |
| is_frame_buffer_bound_(false), |
| temp_scroll_texture_id_(0) { |
| } |
| |
| GpuBackingStoreGLXContext::~GpuBackingStoreGLXContext() { |
| if (temp_scroll_texture_id_) { |
| glDeleteTextures(1, &temp_scroll_texture_id_); |
| temp_scroll_texture_id_ = 0; |
| } |
| |
| if (frame_buffer_for_scrolling_) |
| glDeleteFramebuffersEXT(1, &frame_buffer_for_scrolling_); |
| |
| if (context_) |
| glXDestroyContext(gpu_thread_->display(), context_); |
| } |
| |
| GLXContext GpuBackingStoreGLXContext::BindContext(XID window_id) { |
| DCHECK(!is_frame_buffer_bound_); |
| |
| if (tried_to_init_) { |
| if (!context_) |
| return NULL; |
| if (!previous_window_id_ || previous_window_id_ != window_id) { |
| bool success = glXMakeCurrent(gpu_thread_->display(), window_id, |
| context_); |
| DCHECK(success); |
| } |
| previous_window_id_ = window_id; |
| return context_; |
| } |
| tried_to_init_ = true; |
| |
| int attrib_list[] = { GLX_RGBA, GLX_DOUBLEBUFFER, 0 }; |
| scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info( |
| glXChooseVisual(gpu_thread_->display(), 0, attrib_list)); |
| if (!visual_info.get()) |
| return NULL; |
| |
| context_ = glXCreateContext(gpu_thread_->display(), visual_info.get(), |
| NULL, True); |
| bool success = glXMakeCurrent(gpu_thread_->display(), window_id, context_); |
| DCHECK(success); |
| return context_; |
| } |
| |
| bool GpuBackingStoreGLXContext::BindTextureForScrolling( |
| XID window_id, |
| const gfx::Size& size) { |
| DCHECK(!is_frame_buffer_bound_); |
| BindContext(window_id); |
| |
| // Create a new destination texture if the old one isn't properly sized. |
| // This means we try to re-use old ones without re-creating all the texture |
| // to save work in the common case of scrolling a window repeatedly that |
| // doesn't change size. |
| if (temp_scroll_texture_id_ == 0 || |
| size != temp_scroll_texture_size_) { |
| if (!temp_scroll_texture_id_) { |
| // There may be no temporary one created yet. |
| glGenTextures(1, &temp_scroll_texture_id_); |
| } |
| |
| // Create a new texture in the context with random garbage in it large |
| // enough to fit the required size. |
| glBindTexture(GL_TEXTURE_2D, temp_scroll_texture_id_); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), |
| 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); |
| glBindTexture(GL_TEXTURE_2D, 0); |
| } |
| |
| if (!frame_buffer_for_scrolling_) |
| glGenFramebuffersEXT(1, &frame_buffer_for_scrolling_); |
| glBindFramebufferEXT(GL_FRAMEBUFFER, frame_buffer_for_scrolling_); |
| is_frame_buffer_bound_ = true; |
| |
| // Release our color attachment. |
| glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| temp_scroll_texture_id_, 0); |
| |
| DCHECK(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == |
| GL_FRAMEBUFFER_COMPLETE_EXT); |
| return true; |
| } |
| |
| unsigned int GpuBackingStoreGLXContext::SwapTextureForScrolling( |
| unsigned int old_texture, |
| const gfx::Size& old_size) { |
| // Unbind the framebuffer, which we expect to be bound. |
| DCHECK(is_frame_buffer_bound_); |
| glBindFramebufferEXT(GL_FRAMEBUFFER, 0); |
| is_frame_buffer_bound_ = false; |
| |
| DCHECK(temp_scroll_texture_id_); |
| unsigned int new_texture = temp_scroll_texture_id_; |
| |
| temp_scroll_texture_id_ = old_texture; |
| temp_scroll_texture_size_ = old_size; |
| |
| return new_texture; |
| } |