| // Copyright 2014 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 "ui/gl/gl_surface.h" |
| |
| #include <memory> |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_vector.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/threading/worker_pool.h" |
| #include "ui/gfx/native_widget_types.h" |
| #include "ui/gl/gl_context.h" |
| #include "ui/gl/gl_image.h" |
| #include "ui/gl/gl_image_linux_dma_buffer.h" |
| #include "ui/gl/gl_implementation.h" |
| #include "ui/gl/gl_surface_egl.h" |
| #include "ui/gl/gl_surface_osmesa.h" |
| #include "ui/gl/gl_surface_stub.h" |
| #include "ui/gl/scoped_binders.h" |
| #include "ui/gl/scoped_make_current.h" |
| #include "ui/ozone/public/native_pixmap.h" |
| #include "ui/ozone/public/ozone_platform.h" |
| #include "ui/ozone/public/surface_factory_ozone.h" |
| #include "ui/ozone/public/surface_ozone_egl.h" |
| |
| namespace gfx { |
| |
| namespace { |
| |
| void WaitForFence(EGLDisplay display, EGLSyncKHR fence) { |
| eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, |
| EGL_FOREVER_KHR); |
| } |
| |
| // A thin wrapper around GLSurfaceEGL that owns the EGLNativeWindow |
| class GL_EXPORT GLSurfaceOzoneEGL : public NativeViewGLSurfaceEGL { |
| public: |
| GLSurfaceOzoneEGL(scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface, |
| AcceleratedWidget widget, |
| const gfx::SurfaceConfiguration& requested_configuration); |
| |
| // GLSurface: |
| bool Initialize() override; |
| bool Resize(const gfx::Size& size) override; |
| gfx::SwapResult SwapBuffers() override; |
| bool ScheduleOverlayPlane(int z_order, |
| OverlayTransform transform, |
| GLImage* image, |
| const Rect& bounds_rect, |
| const RectF& crop_rect) override; |
| |
| private: |
| using NativeViewGLSurfaceEGL::Initialize; |
| |
| ~GLSurfaceOzoneEGL() override; |
| |
| bool ReinitializeNativeSurface(); |
| |
| // The native surface. Deleting this is allowed to free the EGLNativeWindow. |
| scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface_; |
| AcceleratedWidget widget_; |
| |
| DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneEGL); |
| }; |
| |
| GLSurfaceOzoneEGL::GLSurfaceOzoneEGL( |
| scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface, |
| AcceleratedWidget widget, |
| const gfx::SurfaceConfiguration& requested_configuration) |
| : NativeViewGLSurfaceEGL(ozone_surface->GetNativeWindow(), |
| requested_configuration), |
| ozone_surface_(ozone_surface.Pass()), |
| widget_(widget) { |
| } |
| |
| bool GLSurfaceOzoneEGL::Initialize() { |
| return Initialize(ozone_surface_->CreateVSyncProvider()); |
| } |
| |
| bool GLSurfaceOzoneEGL::Resize(const gfx::Size& size) { |
| if (!ozone_surface_->ResizeNativeWindow(size)) { |
| if (!ReinitializeNativeSurface() || |
| !ozone_surface_->ResizeNativeWindow(size)) |
| return false; |
| } |
| |
| return NativeViewGLSurfaceEGL::Resize(size); |
| } |
| |
| gfx::SwapResult GLSurfaceOzoneEGL::SwapBuffers() { |
| gfx::SwapResult result = NativeViewGLSurfaceEGL::SwapBuffers(); |
| if (result != gfx::SwapResult::SWAP_ACK) |
| return result; |
| |
| return ozone_surface_->OnSwapBuffers() ? gfx::SwapResult::SWAP_ACK |
| : gfx::SwapResult::SWAP_FAILED; |
| } |
| |
| bool GLSurfaceOzoneEGL::ScheduleOverlayPlane(int z_order, |
| OverlayTransform transform, |
| GLImage* image, |
| const Rect& bounds_rect, |
| const RectF& crop_rect) { |
| return image->ScheduleOverlayPlane(widget_, z_order, transform, bounds_rect, |
| crop_rect); |
| } |
| |
| GLSurfaceOzoneEGL::~GLSurfaceOzoneEGL() { |
| Destroy(); // EGL surface must be destroyed before SurfaceOzone |
| } |
| |
| bool GLSurfaceOzoneEGL::ReinitializeNativeSurface() { |
| scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current; |
| GLContext* current_context = GLContext::GetCurrent(); |
| bool was_current = current_context && current_context->IsCurrent(this); |
| if (was_current) { |
| scoped_make_current.reset(new ui::ScopedMakeCurrent(current_context, this)); |
| } |
| |
| Destroy(); |
| ozone_surface_ = ui::OzonePlatform::GetInstance() |
| ->GetSurfaceFactoryOzone() |
| ->CreateEGLSurfaceForWidget(widget_) |
| .Pass(); |
| if (!ozone_surface_) { |
| LOG(ERROR) << "Failed to create native surface."; |
| return false; |
| } |
| |
| window_ = ozone_surface_->GetNativeWindow(); |
| if (!Initialize()) { |
| LOG(ERROR) << "Failed to initialize."; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL { |
| public: |
| GLSurfaceOzoneSurfaceless( |
| scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface, |
| AcceleratedWidget widget, |
| const gfx::SurfaceConfiguration& requested_configuration); |
| |
| // GLSurface: |
| bool Initialize() override; |
| bool Resize(const gfx::Size& size) override; |
| gfx::SwapResult SwapBuffers() override; |
| bool ScheduleOverlayPlane(int z_order, |
| OverlayTransform transform, |
| GLImage* image, |
| const Rect& bounds_rect, |
| const RectF& crop_rect) override; |
| bool IsOffscreen() override; |
| VSyncProvider* GetVSyncProvider() override; |
| bool SupportsPostSubBuffer() override; |
| gfx::SwapResult PostSubBuffer(int x, int y, int width, int height) override; |
| bool SwapBuffersAsync(const SwapCompletionCallback& callback) override; |
| bool PostSubBufferAsync(int x, |
| int y, |
| int width, |
| int height, |
| const SwapCompletionCallback& callback) override; |
| |
| protected: |
| struct Overlay { |
| Overlay(int z_order, |
| OverlayTransform transform, |
| GLImage* image, |
| const Rect& bounds_rect, |
| const RectF& crop_rect); |
| |
| bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget) const; |
| |
| int z_order; |
| OverlayTransform transform; |
| scoped_refptr<GLImage> image; |
| Rect bounds_rect; |
| RectF crop_rect; |
| }; |
| |
| struct PendingFrame { |
| PendingFrame(); |
| |
| bool ScheduleOverlayPlanes(gfx::AcceleratedWidget widget); |
| |
| bool ready; |
| std::vector<Overlay> overlays; |
| SwapCompletionCallback callback; |
| }; |
| |
| ~GLSurfaceOzoneSurfaceless() override; |
| |
| void SubmitFrame(); |
| |
| EGLSyncKHR InsertFence(); |
| void FenceRetired(EGLSyncKHR fence, PendingFrame* frame); |
| |
| void SwapCompleted(const SwapCompletionCallback& callback, |
| gfx::SwapResult result); |
| |
| // The native surface. Deleting this is allowed to free the EGLNativeWindow. |
| scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface_; |
| AcceleratedWidget widget_; |
| scoped_ptr<VSyncProvider> vsync_provider_; |
| ScopedVector<PendingFrame> unsubmitted_frames_; |
| bool has_implicit_external_sync_; |
| bool last_swap_buffers_result_; |
| bool swap_buffers_pending_; |
| |
| base::WeakPtrFactory<GLSurfaceOzoneSurfaceless> weak_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfaceless); |
| }; |
| |
| GLSurfaceOzoneSurfaceless::Overlay::Overlay(int z_order, |
| OverlayTransform transform, |
| GLImage* image, |
| const Rect& bounds_rect, |
| const RectF& crop_rect) |
| : z_order(z_order), |
| transform(transform), |
| image(image), |
| bounds_rect(bounds_rect), |
| crop_rect(crop_rect) { |
| } |
| |
| bool GLSurfaceOzoneSurfaceless::Overlay::ScheduleOverlayPlane( |
| gfx::AcceleratedWidget widget) const { |
| return image->ScheduleOverlayPlane(widget, z_order, transform, bounds_rect, |
| crop_rect); |
| } |
| |
| GLSurfaceOzoneSurfaceless::PendingFrame::PendingFrame() : ready(false) { |
| } |
| |
| bool GLSurfaceOzoneSurfaceless::PendingFrame::ScheduleOverlayPlanes( |
| gfx::AcceleratedWidget widget) { |
| for (const auto& overlay : overlays) |
| if (!overlay.ScheduleOverlayPlane(widget)) |
| return false; |
| return true; |
| } |
| |
| GLSurfaceOzoneSurfaceless::GLSurfaceOzoneSurfaceless( |
| scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface, |
| AcceleratedWidget widget, |
| const gfx::SurfaceConfiguration& requested_configuration) |
| : SurfacelessEGL(ozone_surface->GetSize(), |
| requested_configuration), |
| ozone_surface_(ozone_surface.Pass()), |
| widget_(widget), |
| has_implicit_external_sync_( |
| HasEGLExtension("EGL_ARM_implicit_external_sync")), |
| last_swap_buffers_result_(true), |
| swap_buffers_pending_(false), |
| weak_factory_(this) { |
| unsubmitted_frames_.push_back(new PendingFrame()); |
| } |
| |
| bool GLSurfaceOzoneSurfaceless::Initialize() { |
| if (!SurfacelessEGL::Initialize()) |
| return false; |
| vsync_provider_ = ozone_surface_->CreateVSyncProvider(); |
| if (!vsync_provider_) |
| return false; |
| return true; |
| } |
| bool GLSurfaceOzoneSurfaceless::Resize(const gfx::Size& size) { |
| if (!ozone_surface_->ResizeNativeWindow(size)) |
| return false; |
| |
| return SurfacelessEGL::Resize(size); |
| } |
| gfx::SwapResult GLSurfaceOzoneSurfaceless::SwapBuffers() { |
| glFlush(); |
| // TODO: the following should be replaced by a per surface flush as it gets |
| // implemented in GL drivers. |
| if (has_implicit_external_sync_) { |
| EGLSyncKHR fence = InsertFence(); |
| if (!fence) |
| return SwapResult::SWAP_FAILED; |
| |
| EGLDisplay display = GetDisplay(); |
| WaitForFence(display, fence); |
| eglDestroySyncKHR(display, fence); |
| } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) { |
| glFinish(); |
| } |
| |
| unsubmitted_frames_.back()->ScheduleOverlayPlanes(widget_); |
| unsubmitted_frames_.back()->overlays.clear(); |
| |
| return ozone_surface_->OnSwapBuffers() ? gfx::SwapResult::SWAP_ACK |
| : gfx::SwapResult::SWAP_FAILED; |
| } |
| bool GLSurfaceOzoneSurfaceless::ScheduleOverlayPlane(int z_order, |
| OverlayTransform transform, |
| GLImage* image, |
| const Rect& bounds_rect, |
| const RectF& crop_rect) { |
| unsubmitted_frames_.back()->overlays.push_back( |
| Overlay(z_order, transform, image, bounds_rect, crop_rect)); |
| return true; |
| } |
| bool GLSurfaceOzoneSurfaceless::IsOffscreen() { |
| return false; |
| } |
| VSyncProvider* GLSurfaceOzoneSurfaceless::GetVSyncProvider() { |
| return vsync_provider_.get(); |
| } |
| bool GLSurfaceOzoneSurfaceless::SupportsPostSubBuffer() { |
| return true; |
| } |
| gfx::SwapResult GLSurfaceOzoneSurfaceless::PostSubBuffer(int x, |
| int y, |
| int width, |
| int height) { |
| // The actual sub buffer handling is handled at higher layers. |
| SwapBuffers(); |
| return gfx::SwapResult::SWAP_ACK; |
| } |
| bool GLSurfaceOzoneSurfaceless::SwapBuffersAsync( |
| const SwapCompletionCallback& callback) { |
| // If last swap failed, don't try to schedule new ones. |
| if (!last_swap_buffers_result_) |
| return false; |
| |
| glFlush(); |
| |
| SwapCompletionCallback surface_swap_callback = |
| base::Bind(&GLSurfaceOzoneSurfaceless::SwapCompleted, |
| weak_factory_.GetWeakPtr(), callback); |
| |
| PendingFrame* frame = unsubmitted_frames_.back(); |
| frame->callback = surface_swap_callback; |
| unsubmitted_frames_.push_back(new PendingFrame()); |
| |
| // TODO: the following should be replaced by a per surface flush as it gets |
| // implemented in GL drivers. |
| if (has_implicit_external_sync_) { |
| EGLSyncKHR fence = InsertFence(); |
| if (!fence) |
| return false; |
| |
| base::Closure fence_wait_task = |
| base::Bind(&WaitForFence, GetDisplay(), fence); |
| |
| base::Closure fence_retired_callback = |
| base::Bind(&GLSurfaceOzoneSurfaceless::FenceRetired, |
| weak_factory_.GetWeakPtr(), fence, frame); |
| |
| base::WorkerPool::PostTaskAndReply(FROM_HERE, fence_wait_task, |
| fence_retired_callback, false); |
| return true; |
| } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) { |
| glFinish(); |
| } |
| |
| frame->ready = true; |
| SubmitFrame(); |
| return last_swap_buffers_result_; |
| } |
| bool GLSurfaceOzoneSurfaceless::PostSubBufferAsync( |
| int x, |
| int y, |
| int width, |
| int height, |
| const SwapCompletionCallback& callback) { |
| return SwapBuffersAsync(callback); |
| } |
| |
| GLSurfaceOzoneSurfaceless::~GLSurfaceOzoneSurfaceless() { |
| Destroy(); // EGL surface must be destroyed before SurfaceOzone |
| } |
| |
| void GLSurfaceOzoneSurfaceless::SubmitFrame() { |
| DCHECK(!unsubmitted_frames_.empty()); |
| |
| if (unsubmitted_frames_.front()->ready && !swap_buffers_pending_) { |
| scoped_ptr<PendingFrame> frame(unsubmitted_frames_.front()); |
| unsubmitted_frames_.weak_erase(unsubmitted_frames_.begin()); |
| swap_buffers_pending_ = true; |
| |
| last_swap_buffers_result_ = |
| frame->ScheduleOverlayPlanes(widget_) && |
| ozone_surface_->OnSwapBuffersAsync(frame->callback); |
| } |
| } |
| |
| EGLSyncKHR GLSurfaceOzoneSurfaceless::InsertFence() { |
| const EGLint attrib_list[] = {EGL_SYNC_CONDITION_KHR, |
| EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM, |
| EGL_NONE}; |
| return eglCreateSyncKHR(GetDisplay(), EGL_SYNC_FENCE_KHR, attrib_list); |
| } |
| |
| void GLSurfaceOzoneSurfaceless::FenceRetired(EGLSyncKHR fence, |
| PendingFrame* frame) { |
| eglDestroySyncKHR(GetDisplay(), fence); |
| frame->ready = true; |
| SubmitFrame(); |
| } |
| |
| void GLSurfaceOzoneSurfaceless::SwapCompleted( |
| const SwapCompletionCallback& callback, |
| gfx::SwapResult result) { |
| callback.Run(result); |
| swap_buffers_pending_ = false; |
| |
| SubmitFrame(); |
| } |
| |
| // This provides surface-like semantics implemented through surfaceless. |
| // A framebuffer is bound automatically. |
| class GL_EXPORT GLSurfaceOzoneSurfacelessSurfaceImpl |
| : public GLSurfaceOzoneSurfaceless { |
| public: |
| GLSurfaceOzoneSurfacelessSurfaceImpl( |
| scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface, |
| AcceleratedWidget widget, |
| const gfx::SurfaceConfiguration& requested_configuration); |
| |
| // GLSurface: |
| unsigned int GetBackingFrameBufferObject() override; |
| bool OnMakeCurrent(GLContext* context) override; |
| bool Resize(const gfx::Size& size) override; |
| bool SupportsPostSubBuffer() override; |
| gfx::SwapResult SwapBuffers() override; |
| bool SwapBuffersAsync(const SwapCompletionCallback& callback) override; |
| void Destroy() override; |
| bool IsSurfaceless() const override { return false; } |
| |
| private: |
| class SurfaceImage : public GLImageLinuxDMABuffer { |
| public: |
| SurfaceImage(const gfx::Size& size, unsigned internalformat); |
| |
| bool Initialize(scoped_refptr<ui::NativePixmap> pixmap, |
| gfx::GpuMemoryBuffer::Format format); |
| bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget, |
| int z_order, |
| gfx::OverlayTransform transform, |
| const gfx::Rect& bounds_rect, |
| const gfx::RectF& crop_rect) override; |
| |
| private: |
| ~SurfaceImage() override; |
| |
| scoped_refptr<ui::NativePixmap> pixmap_; |
| }; |
| |
| ~GLSurfaceOzoneSurfacelessSurfaceImpl() override; |
| |
| void BindFramebuffer(); |
| bool CreatePixmaps(); |
| |
| static const int kBuffers = 2; |
| GLuint fbo_; |
| GLuint textures_[kBuffers]; |
| std::unique_ptr<GLuint[]> rb_depth_; |
| scoped_refptr<GLImage> images_[2]; |
| int current_surface_; |
| DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfacelessSurfaceImpl); |
| }; |
| |
| GLSurfaceOzoneSurfacelessSurfaceImpl::SurfaceImage::SurfaceImage( |
| const gfx::Size& size, |
| unsigned internalformat) |
| : GLImageLinuxDMABuffer(size, internalformat) { |
| } |
| |
| bool GLSurfaceOzoneSurfacelessSurfaceImpl::SurfaceImage::Initialize( |
| scoped_refptr<ui::NativePixmap> pixmap, |
| gfx::GpuMemoryBuffer::Format format) { |
| base::FileDescriptor handle(pixmap->GetDmaBufFd(), false); |
| if (!GLImageLinuxDMABuffer::Initialize(handle, format, |
| pixmap->GetDmaBufPitch())) |
| return false; |
| pixmap_ = pixmap; |
| return true; |
| } |
| bool GLSurfaceOzoneSurfacelessSurfaceImpl::SurfaceImage::ScheduleOverlayPlane( |
| gfx::AcceleratedWidget widget, |
| int z_order, |
| gfx::OverlayTransform transform, |
| const gfx::Rect& bounds_rect, |
| const gfx::RectF& crop_rect) { |
| return pixmap_->ScheduleOverlayPlane(widget, z_order, transform, bounds_rect, |
| crop_rect); |
| } |
| |
| GLSurfaceOzoneSurfacelessSurfaceImpl::SurfaceImage::~SurfaceImage() { |
| } |
| |
| GLSurfaceOzoneSurfacelessSurfaceImpl::GLSurfaceOzoneSurfacelessSurfaceImpl( |
| scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface, |
| AcceleratedWidget widget, |
| const gfx::SurfaceConfiguration& requested_configuration) |
| : GLSurfaceOzoneSurfaceless( |
| ozone_surface.Pass(), widget, requested_configuration), |
| fbo_(0), |
| current_surface_(0) { |
| for (auto& texture : textures_) |
| texture = 0; |
| } |
| |
| unsigned int |
| GLSurfaceOzoneSurfacelessSurfaceImpl::GetBackingFrameBufferObject() { |
| return fbo_; |
| } |
| |
| bool GLSurfaceOzoneSurfacelessSurfaceImpl::OnMakeCurrent(GLContext* context) { |
| if (!fbo_) { |
| glGenFramebuffersEXT(1, &fbo_); |
| if (!fbo_) |
| return false; |
| glGenTextures(arraysize(textures_), textures_); |
| if (get_surface_configuration().depth_bits <= 16) { |
| rb_depth_.reset(new GLuint[kBuffers]); |
| glGenRenderbuffersEXT(kBuffers, rb_depth_.get()); |
| } |
| if (!CreatePixmaps()) |
| return false; |
| } |
| BindFramebuffer(); |
| glBindFramebufferEXT(GL_FRAMEBUFFER, fbo_); |
| return SurfacelessEGL::OnMakeCurrent(context); |
| } |
| |
| bool GLSurfaceOzoneSurfacelessSurfaceImpl::Resize(const gfx::Size& size) { |
| if (size == GetSize()) |
| return true; |
| return GLSurfaceOzoneSurfaceless::Resize(size) && CreatePixmaps(); |
| } |
| |
| bool GLSurfaceOzoneSurfacelessSurfaceImpl::SupportsPostSubBuffer() { |
| return false; |
| } |
| |
| gfx::SwapResult GLSurfaceOzoneSurfacelessSurfaceImpl::SwapBuffers() { |
| if (!images_[current_surface_]->ScheduleOverlayPlane( |
| widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE, |
| gfx::Rect(GetSize()), gfx::RectF(1, 1))) |
| return gfx::SwapResult::SWAP_FAILED; |
| gfx::SwapResult result = GLSurfaceOzoneSurfaceless::SwapBuffers(); |
| if (result != gfx::SwapResult::SWAP_ACK) |
| return result; |
| current_surface_ ^= 1; |
| BindFramebuffer(); |
| return gfx::SwapResult::SWAP_ACK; |
| } |
| |
| bool GLSurfaceOzoneSurfacelessSurfaceImpl::SwapBuffersAsync( |
| const SwapCompletionCallback& callback) { |
| if (!images_[current_surface_]->ScheduleOverlayPlane( |
| widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE, |
| gfx::Rect(GetSize()), gfx::RectF(1, 1))) |
| return false; |
| if (!GLSurfaceOzoneSurfaceless::SwapBuffersAsync(callback)) |
| return false; |
| current_surface_ ^= 1; |
| BindFramebuffer(); |
| return true; |
| } |
| |
| void GLSurfaceOzoneSurfacelessSurfaceImpl::Destroy() { |
| GLContext* current_context = GLContext::GetCurrent(); |
| DCHECK(current_context && current_context->IsCurrent(this)); |
| glBindFramebufferEXT(GL_FRAMEBUFFER, 0); |
| if (fbo_) { |
| glDeleteTextures(arraysize(textures_), textures_); |
| for (auto& texture : textures_) |
| texture = 0; |
| if (rb_depth_) { |
| glDeleteRenderbuffersEXT(kBuffers, rb_depth_.get()); |
| rb_depth_.reset(); |
| } |
| glDeleteFramebuffersEXT(1, &fbo_); |
| fbo_ = 0; |
| } |
| for (auto image : images_) { |
| if (image) |
| image->Destroy(true); |
| } |
| } |
| |
| GLSurfaceOzoneSurfacelessSurfaceImpl::~GLSurfaceOzoneSurfacelessSurfaceImpl() { |
| DCHECK(!fbo_); |
| for (size_t i = 0; i < arraysize(textures_); i++) |
| DCHECK(!textures_[i]) << "texture " << i << " not released"; |
| DCHECK(!rb_depth_); |
| } |
| |
| void GLSurfaceOzoneSurfacelessSurfaceImpl::BindFramebuffer() { |
| ScopedFrameBufferBinder fb(fbo_); |
| glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| textures_[current_surface_], 0); |
| if (rb_depth_) { |
| glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, |
| GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rb_depth_[current_surface_]); |
| } |
| } |
| |
| bool GLSurfaceOzoneSurfacelessSurfaceImpl::CreatePixmaps() { |
| if (!fbo_) |
| return true; |
| for (size_t i = 0; i < arraysize(textures_); i++) { |
| scoped_refptr<ui::NativePixmap> pixmap = |
| ui::OzonePlatform::GetInstance() |
| ->GetSurfaceFactoryOzone() |
| ->CreateNativePixmap(widget_, GetSize(), |
| ui::SurfaceFactoryOzone::BGRA_8888, |
| ui::SurfaceFactoryOzone::SCANOUT); |
| if (!pixmap) |
| return false; |
| scoped_refptr<SurfaceImage> image = |
| new SurfaceImage(GetSize(), GL_BGRA_EXT); |
| if (!image->Initialize(pixmap, gfx::GpuMemoryBuffer::Format::BGRA_8888)) |
| return false; |
| if (images_[i]) |
| images_[i]->Destroy(true); |
| images_[i] = image; |
| // Bind image to texture. |
| ScopedTextureBinder binder(GL_TEXTURE_2D, textures_[i]); |
| |
| if (!images_[i]->BindTexImage(GL_TEXTURE_2D)) |
| return false; |
| } |
| if (rb_depth_) { |
| for (size_t i = 0; i < kBuffers; i++) { |
| glBindRenderbufferEXT(GL_RENDERBUFFER, rb_depth_[i]); |
| glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, |
| GetSize().width(), GetSize().height()); |
| } |
| } |
| return true; |
| } |
| |
| } // namespace |
| |
| // static |
| bool GLSurface::InitializeOneOffInternal() { |
| switch (GetGLImplementation()) { |
| case kGLImplementationEGLGLES2: |
| if (!GLSurfaceEGL::InitializeOneOff()) { |
| LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed."; |
| return false; |
| } |
| |
| return true; |
| case kGLImplementationOSMesaGL: |
| case kGLImplementationMockGL: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| // static |
| scoped_refptr<GLSurface> GLSurface::CreateSurfacelessViewGLSurface( |
| gfx::AcceleratedWidget window, |
| const gfx::SurfaceConfiguration& requested_configuration) { |
| if (GetGLImplementation() == kGLImplementationEGLGLES2 && |
| window != kNullAcceleratedWidget && |
| GLSurfaceEGL::IsEGLSurfacelessContextSupported() && |
| ui::OzonePlatform::GetInstance() |
| ->GetSurfaceFactoryOzone() |
| ->CanShowPrimaryPlaneAsOverlay()) { |
| scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone = |
| ui::OzonePlatform::GetInstance() |
| ->GetSurfaceFactoryOzone() |
| ->CreateSurfacelessEGLSurfaceForWidget(window); |
| if (!surface_ozone) |
| return nullptr; |
| scoped_refptr<GLSurface> surface; |
| surface = new GLSurfaceOzoneSurfaceless(surface_ozone.Pass(), |
| window, |
| requested_configuration); |
| if (surface->Initialize()) |
| return surface; |
| } |
| |
| return nullptr; |
| } |
| |
| // static |
| scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface( |
| gfx::AcceleratedWidget window, |
| const gfx::SurfaceConfiguration& requested_configuration) { |
| if (GetGLImplementation() == kGLImplementationOSMesaGL) { |
| scoped_refptr<GLSurface> surface( |
| new GLSurfaceOSMesaHeadless(requested_configuration)); |
| if (!surface->Initialize()) |
| return NULL; |
| return surface; |
| } |
| DCHECK(GetGLImplementation() == kGLImplementationEGLGLES2); |
| if (window != kNullAcceleratedWidget) { |
| scoped_refptr<GLSurface> surface; |
| if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() && |
| ui::OzonePlatform::GetInstance() |
| ->GetSurfaceFactoryOzone() |
| ->CanShowPrimaryPlaneAsOverlay()) { |
| scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone = |
| ui::OzonePlatform::GetInstance() |
| ->GetSurfaceFactoryOzone() |
| ->CreateSurfacelessEGLSurfaceForWidget(window); |
| if (!surface_ozone) |
| return NULL; |
| surface = new GLSurfaceOzoneSurfacelessSurfaceImpl( |
| surface_ozone.Pass(), window, requested_configuration); |
| } else { |
| scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone = |
| ui::OzonePlatform::GetInstance() |
| ->GetSurfaceFactoryOzone() |
| ->CreateEGLSurfaceForWidget(window); |
| if (!surface_ozone) |
| return NULL; |
| |
| surface = new GLSurfaceOzoneEGL( |
| surface_ozone.Pass(), window, requested_configuration); |
| } |
| if (!surface->Initialize()) |
| return NULL; |
| return surface; |
| } else { |
| scoped_refptr<GLSurface> surface = new GLSurfaceStub( |
| requested_configuration); |
| if (surface->Initialize()) |
| return surface; |
| } |
| return NULL; |
| } |
| |
| // static |
| scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface( |
| const gfx::Size& size, |
| const gfx::SurfaceConfiguration& requested_configuration) { |
| switch (GetGLImplementation()) { |
| case kGLImplementationOSMesaGL: { |
| scoped_refptr<GLSurface> surface(new GLSurfaceOSMesa( |
| OSMesaSurfaceFormatBGRA, size, requested_configuration)); |
| if (!surface->Initialize()) |
| return NULL; |
| |
| return surface; |
| } |
| case kGLImplementationEGLGLES2: { |
| scoped_refptr<GLSurface> surface; |
| if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() && |
| (size.width() == 0 && size.height() == 0)) { |
| surface = new SurfacelessEGL(size, requested_configuration); |
| } else |
| surface = new PbufferGLSurfaceEGL(size, requested_configuration); |
| |
| if (!surface->Initialize()) |
| return NULL; |
| return surface; |
| } |
| case kGLImplementationMockGL: |
| return new GLSurfaceStub(requested_configuration); |
| default: |
| NOTREACHED(); |
| return NULL; |
| } |
| } |
| |
| EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() { |
| return ui::OzonePlatform::GetInstance() |
| ->GetSurfaceFactoryOzone() |
| ->GetNativeDisplay(); |
| } |
| |
| } // namespace gfx |