diff options
Diffstat (limited to 'gpu')
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 27 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.h | 12 | ||||
-rw-r--r-- | gpu/command_buffer/service/gpu_processor_linux.cc | 29 | ||||
-rw-r--r-- | gpu/command_buffer/service/x_utils.cc | 222 | ||||
-rw-r--r-- | gpu/command_buffer/service/x_utils.h | 91 |
5 files changed, 298 insertions, 83 deletions
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index fc44614..63e267d 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -31,7 +31,7 @@ #include "gpu/command_buffer/service/texture_manager.h" #if defined(UNIT_TEST) #elif defined(OS_LINUX) -// XWindowWrapper is stubbed out for unit-tests. +// GLXContextWrapper is stubbed out for unit-tests. #include "gpu/command_buffer/service/x_utils.h" #elif defined(OS_MACOSX) #include "app/surface/accelerated_surface_mac.h" @@ -260,7 +260,7 @@ GLES2Decoder::GLES2Decoder(ContextGroup* group) debug_(false) { #elif defined(OS_LINUX) debug_(false), - window_(NULL) { + context_(NULL) { #elif defined(OS_WIN) debug_(false), hwnd_(NULL) { @@ -1543,7 +1543,7 @@ bool GLES2DecoderImpl::MakeCurrent() { return true; #elif defined(OS_LINUX) // TODO(apatrick): offscreen rendering not yet supported on this platform. - return window()->MakeCurrent(); + return context()->MakeCurrent(); #elif defined(OS_MACOSX) if (gl_context_) { if (CGLGetCurrentContext() != gl_context_) { @@ -1607,7 +1607,7 @@ void GLES2DecoderImpl::UnregisterObjects( } bool GLES2DecoderImpl::InitPlatformSpecific() { -#if !defined(UNIT_TEST) +#if !defined(UNIT_TEST) && !defined(OS_LINUX) bool offscreen = pending_size_.width() > 0 && pending_size_.height() > 0; #endif #if defined(UNIT_TEST) @@ -1672,14 +1672,15 @@ bool GLES2DecoderImpl::InitPlatformSpecific() { } #elif defined(OS_LINUX) - // TODO(apatrick): offscreen rendering not yet supported on this platform. - DCHECK(!offscreen); - // TODO(apatrick): parent contexts not yet supported on this platform. DCHECK(!parent_); - DCHECK(window()); - if (!window()->Initialize()) + DCHECK(context()); + + // Offscreen / onscreen handling done earlier on this platform (in + // GPUProcessor::Initialize). + + if (!context()->Initialize()) return false; #elif defined(OS_MACOSX) // TODO(apatrick): parent contexts not yet supported on this platform. @@ -1971,8 +1972,8 @@ void GLES2DecoderImpl::Destroy() { #if defined(UNIT_TEST) #elif defined(GLES2_GPU_SERVICE_BACKEND_NATIVE_GLES2) #elif defined(OS_LINUX) - DCHECK(window()); - window()->Destroy(); + DCHECK(context()); + context()->Destroy(); #elif defined(OS_MACOSX) surface_.Destroy(); #endif @@ -3677,8 +3678,8 @@ error::Error GLES2DecoderImpl::HandleSwapBuffers( #elif defined(OS_WIN) ::SwapBuffers(gl_device_context_); #elif defined(OS_LINUX) - DCHECK(window()); - window()->SwapBuffers(); + DCHECK(context()); + context()->SwapBuffers(); #elif defined(OS_MACOSX) // TODO(kbr): Need to property hook up and track the OpenGL state and hook // up the notion of the currently bound FBO. diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h index 58e1193..05951a2 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder.h @@ -23,7 +23,7 @@ namespace gpu { // Forward-declared instead of including x_utils.h, because including glx.h // causes havok. -class XWindowWrapper; +class GLXContextWrapper; namespace gles2 { @@ -50,11 +50,11 @@ class GLES2Decoder : public CommonDecoder { } #if defined(OS_LINUX) - void set_window_wrapper(XWindowWrapper *window) { - window_ = window; + void set_context_wrapper(GLXContextWrapper *context) { + context_ = context; } - XWindowWrapper* window() const { - return window_; + GLXContextWrapper* context() const { + return context_; } #elif defined(OS_WIN) void set_hwnd(HWND hwnd) { @@ -108,7 +108,7 @@ class GLES2Decoder : public CommonDecoder { bool debug_; #if defined(OS_LINUX) - XWindowWrapper *window_; + GLXContextWrapper *context_; #elif defined(OS_WIN) // Handle to the GL device. HWND hwnd_; diff --git a/gpu/command_buffer/service/gpu_processor_linux.cc b/gpu/command_buffer/service/gpu_processor_linux.cc index d430933..b477021 100644 --- a/gpu/command_buffer/service/gpu_processor_linux.cc +++ b/gpu/command_buffer/service/gpu_processor_linux.cc @@ -14,10 +14,8 @@ bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle, GPUProcessor* parent, const gfx::Size& size, uint32 parent_texture_id) { - DCHECK(handle); - // Cannot reinitialize. - if (decoder_->window() != NULL) + if (decoder_->context() != NULL) return false; // Map the ring buffer and create the parser. @@ -34,9 +32,18 @@ bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle, decoder_.get())); } - // Initialize GAPI immediately if the window handle is valid. - XWindowWrapper *window = new XWindowWrapper(GDK_DISPLAY(), handle); - decoder_->set_window_wrapper(window); + // Initialize GAPI immediately. + GLXContextWrapper* wrapper = NULL; + if (size.width() > 0 && size.height() > 0) { + // Offscreen code path. + DCHECK(!handle); + wrapper = new GLXPbufferWrapper(GDK_DISPLAY()); + } else { + DCHECK(handle); + // Onscreen code path. + wrapper = new XWindowWrapper(GDK_DISPLAY(), handle); + } + decoder_->set_context_wrapper(wrapper); gles2::GLES2Decoder* parent_decoder = parent ? parent->decoder_.get() : NULL; if (!decoder_->Initialize(parent_decoder, size, @@ -45,15 +52,17 @@ bool GPUProcessor::Initialize(gfx::PluginWindowHandle handle, return false; } - return true;} + return true; +} void GPUProcessor::Destroy() { // Destroy decoder if initialized. + // TODO(gman): simplify cleanup logic. http://crbug.com/39895 if (decoder_.get()) { - XWindowWrapper *window = decoder_->window(); + GLXContextWrapper *context = decoder_->context(); decoder_->Destroy(); - decoder_->set_window_wrapper(NULL); - delete window; + decoder_->set_context_wrapper(NULL); + delete context; decoder_.reset(); } diff --git a/gpu/command_buffer/service/x_utils.cc b/gpu/command_buffer/service/x_utils.cc index 7abdf8c..9c10377 100644 --- a/gpu/command_buffer/service/x_utils.cc +++ b/gpu/command_buffer/service/x_utils.cc @@ -6,21 +6,33 @@ #include <dlfcn.h> +#include "base/scoped_ptr.h" #include "gpu/command_buffer/service/precompile.h" #include "gpu/command_buffer/common/logging.h" #include "gpu/command_buffer/service/x_utils.h" namespace gpu { +// scoped_ptr functor for XFree(). Use as follows: +// scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> foo(...); +// where "XVisualInfo" is any X type that is freed with XFree. +class ScopedPtrXFree { + public: + void operator()(void* x) const { + ::XFree(x); + } +}; + // Some versions of NVIDIA's GL libGL.so include a broken version of // dlopen/dlsym, and so linking it into chrome breaks it. So we dynamically // load it, and use glew to dynamically resolve symbols. // See http://code.google.com/p/chromium/issues/detail?id=16800 +static bool g_glxew_initialized = false; static bool g_glew_initialized = false; -bool XWindowWrapper::Initialize() { - if (!g_glew_initialized) { +static bool InitializeGLXEW() { + if (!g_glxew_initialized) { void* handle = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL); if (!handle) { LOG(ERROR) << "Could not find libGL.so.1"; @@ -29,78 +41,210 @@ bool XWindowWrapper::Initialize() { // Initializes context-independent parts of GLEW if (glxewInit() != GLEW_OK) { - LOG(ERROR) << "GLXEW failed initialization"; + LOG(ERROR) << "glxewInit failed"; + return false; + } + // Hack to work around apparently incorrect assumption in + // glxewContextInit. Documentation indicates that all of the work + // it does is actually context-independent. We require GLX 1.3 + // entry points to be present for successful initialization of the + // off-screen code path in the GLES2Decoder. TODO(kbr): clean this + // up. + if (glxewContextInit() != GLEW_OK) { + LOG(ERROR) << "glxewContextInit failed"; + return false; + } + g_glxew_initialized = true; + } + return true; +} + +// GLEW initialization is extremely expensive because it looks up +// hundreds of function pointers. Realistically we are not going to +// switch between GL implementations on the fly, so for the time being +// we only do the context-dependent GLEW initialization once. +static bool InitializeGLEW() { + if (!g_glew_initialized) { + // Initializes context-dependent parts of GLEW + if (glewInit() != GLEW_OK) { + LOG(ERROR) << "GLEW failed initialization"; + return false; + } + + if (!glewIsSupported("GL_VERSION_2_0")) { + LOG(ERROR) << "GL implementation doesn't support GL version 2.0"; return false; } g_glew_initialized = true; } + return true; +} + +GLXContextWrapper::~GLXContextWrapper() { +} + +bool GLXContextWrapper::Initialize() { + if (!MakeCurrent()) { + Destroy(); + DLOG(ERROR) << "Couldn't make context current for initialization."; + return false; + } + + if (!InitializeGLEW()) { + Destroy(); + return false; + } + + return true; +} + +void GLXContextWrapper::Destroy() { + Bool result = glXMakeCurrent(GetDisplay(), 0, 0); + // glXMakeCurrent isn't supposed to fail when unsetting the context, unless + // we have pending draws on an invalid window - which shouldn't be the case + // here. + DCHECK(result); + if (GetContext()) { + glXDestroyContext(GetDisplay(), GetContext()); + SetContext(NULL); + } +} + +bool XWindowWrapper::Initialize() { + if (!InitializeGLXEW()) + return false; + XWindowAttributes attributes; - XGetWindowAttributes(display_, window_, &attributes); + XGetWindowAttributes(GetDisplay(), window_, &attributes); XVisualInfo visual_info_template; visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); int visual_info_count = 0; - XVisualInfo *visual_info_list = XGetVisualInfo(display_, VisualIDMask, - &visual_info_template, - &visual_info_count); - DCHECK(visual_info_list); + scoped_ptr_malloc<XVisualInfo, ScopedPtrXFree> visual_info_list( + XGetVisualInfo(GetDisplay(), VisualIDMask, + &visual_info_template, + &visual_info_count)); + DCHECK(visual_info_list.get()); DCHECK_GT(visual_info_count, 0); - context_ = 0; + SetContext(NULL); for (int i = 0; i < visual_info_count; ++i) { - context_ = glXCreateContext(display_, visual_info_list + i, 0, - True); - if (context_) break; + SetContext(glXCreateContext(GetDisplay(), visual_info_list.get() + i, 0, + True)); + if (GetContext()) + break; } - XFree(visual_info_list); - if (!context_) { + if (!GetContext()) { DLOG(ERROR) << "Couldn't create GL context."; return false; } - if (!MakeCurrent()) { + return GLXContextWrapper::Initialize(); +} + +bool XWindowWrapper::MakeCurrent() { + if (glXGetCurrentDrawable() == window_ && + glXGetCurrentContext() == GetContext()) { + return true; + } + if (glXMakeCurrent(GetDisplay(), window_, GetContext()) != True) { + glXDestroyContext(GetDisplay(), GetContext()); + SetContext(0); + DLOG(ERROR) << "Couldn't make context current."; return false; } + return true; +} + +bool XWindowWrapper::IsOffscreen() { + return false; +} + +void XWindowWrapper::SwapBuffers() { + glXSwapBuffers(GetDisplay(), window_); +} + +bool GLXPbufferWrapper::Initialize() { + if (!InitializeGLXEW()) + return false; - // Initializes context-dependent parts of GLEW - if (glewInit() != GLEW_OK) { - LOG(ERROR) << "GLEW failed initialization"; + if (!glXChooseFBConfig || + !glXCreateNewContext || + !glXCreatePbuffer || + !glXDestroyPbuffer) { + DLOG(ERROR) << "Pbuffer support not available."; return false; } - if (!glewIsSupported("GL_VERSION_2_0")) { - LOG(ERROR) << "GL implementation doesn't support GL version 2.0"; + static const int config_attributes[] = { + GLX_DRAWABLE_TYPE, + GLX_PBUFFER_BIT, + GLX_RENDER_TYPE, + GLX_RGBA_BIT, + GLX_DOUBLEBUFFER, + 0, + 0 + }; + + int nelements = 0; + // TODO(kbr): figure out whether hardcoding screen to 0 is sufficient. + scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> config( + glXChooseFBConfig(GetDisplay(), 0, config_attributes, &nelements)); + if (!config.get()) { + DLOG(ERROR) << "glXChooseFBConfig failed."; + return false; + } + if (!nelements) { + DLOG(ERROR) << "glXChooseFBConfig returned 0 elements."; + return false; + } + SetContext(glXCreateNewContext(GetDisplay(), + config.get()[0], GLX_RGBA_TYPE, 0, True)); + if (!GetContext()) { + DLOG(ERROR) << "glXCreateNewContext failed."; return false; } + static const int pbuffer_attributes[] = { + GLX_PBUFFER_WIDTH, + 1, + GLX_PBUFFER_HEIGHT, + 1, + 0 + }; + pbuffer_ = glXCreatePbuffer(GetDisplay(), + config.get()[0], pbuffer_attributes); + if (!pbuffer_) { + Destroy(); + DLOG(ERROR) << "glXCreatePbuffer failed."; + return false; + } + return GLXContextWrapper::Initialize(); +} - return true; +void GLXPbufferWrapper::Destroy() { + GLXContextWrapper::Destroy(); + if (pbuffer_) { + glXDestroyPbuffer(GetDisplay(), pbuffer_); + pbuffer_ = NULL; + } } -bool XWindowWrapper::MakeCurrent() { - if (glXGetCurrentDrawable() == window_ && - glXGetCurrentContext() == context_) { +bool GLXPbufferWrapper::MakeCurrent() { + if (glXGetCurrentDrawable() == pbuffer_ && + glXGetCurrentContext() == GetContext()) { return true; } - if (glXMakeCurrent(display_, window_, context_) != True) { - glXDestroyContext(display_, context_); - context_ = 0; + if (glXMakeCurrent(GetDisplay(), pbuffer_, GetContext()) != True) { + glXDestroyContext(GetDisplay(), GetContext()); + SetContext(0); DLOG(ERROR) << "Couldn't make context current."; return false; } return true; } -void XWindowWrapper::Destroy() { - Bool result = glXMakeCurrent(display_, 0, 0); - // glXMakeCurrent isn't supposed to fail when unsetting the context, unless - // we have pending draws on an invalid window - which shouldn't be the case - // here. - DCHECK(result); - if (context_) { - glXDestroyContext(display_, context_); - context_ = 0; - } +bool GLXPbufferWrapper::IsOffscreen() { + return true; } -void XWindowWrapper::SwapBuffers() { - glXSwapBuffers(display_, window_); +void GLXPbufferWrapper::SwapBuffers() { } } // namespace gpu diff --git a/gpu/command_buffer/service/x_utils.h b/gpu/command_buffer/service/x_utils.h index cd601c6..ca88f73 100644 --- a/gpu/command_buffer/service/x_utils.h +++ b/gpu/command_buffer/service/x_utils.h @@ -13,36 +13,97 @@ namespace gpu { +// Abstracts between on-screen and off-screen GLX contexts. +class GLXContextWrapper { + public: + explicit GLXContextWrapper(Display* display) + : display_(display), + context_(NULL) { + DCHECK(display_); + } + + virtual ~GLXContextWrapper(); + + // Initializes the GL context. Subclasses should perform their + // initialization work and then call the superclass implementation. + virtual bool Initialize(); + + // Destroys the GL context. Subclasses may call this before or after + // doing any necessary cleanup work. + virtual void Destroy(); + + // Makes the GL context current on the current thread. + virtual bool MakeCurrent() = 0; + + // Returns true if this context is offscreen. + virtual bool IsOffscreen() = 0; + + // Swaps front and back buffers. This has no effect for off-screen + // contexts. + virtual void SwapBuffers() = 0; + + // Fetches the GLX context for sharing of server-side objects. + GLXContext GetContext() { + return context_; + } + + protected: + Display* GetDisplay() { + return display_; + } + + void SetContext(GLXContext context) { + context_ = context; + } + + private: + Display* display_; + GLXContext context_; + + DISALLOW_COPY_AND_ASSIGN(GLXContextWrapper); +}; + // This class is a wrapper around an X Window and associated GL context. It is // useful to isolate intrusive X headers, since it can be forward declared // (Window and GLXContext can't). -class XWindowWrapper { +class XWindowWrapper : public GLXContextWrapper { public: XWindowWrapper(Display *display, Window window) - : display_(display), + : GLXContextWrapper(display), window_(window) { - DCHECK(display_); DCHECK(window_); } - // Initializes the GL context. - bool Initialize(); - - // Destroys the GL context. - void Destroy(); - - // Makes the GL context current on the current thread. - bool MakeCurrent(); - // Swaps front and back buffers. - void SwapBuffers(); + virtual bool Initialize(); + virtual bool MakeCurrent(); + virtual bool IsOffscreen(); + virtual void SwapBuffers(); private: - Display *display_; Window window_; - GLXContext context_; DISALLOW_COPY_AND_ASSIGN(XWindowWrapper); }; +// This class is a wrapper around a GLX pbuffer and associated GL context. It +// serves the same purpose as the XWindowWrapper for initializing off-screen +// rendering. +class GLXPbufferWrapper : public GLXContextWrapper { + public: + explicit GLXPbufferWrapper(Display* display) + : GLXContextWrapper(display) { + } + + virtual bool Initialize(); + virtual void Destroy(); + virtual bool MakeCurrent(); + virtual bool IsOffscreen(); + virtual void SwapBuffers(); + + private: + GLXPbuffer pbuffer_; + DISALLOW_COPY_AND_ASSIGN(GLXPbufferWrapper); +}; + } // namespace gpu #endif // GPU_COMMAND_BUFFER_SERVICE_X_UTILS_H_ |