blob: ad4d1cfb78435cafc194f5acffcc2a3babeb8f15 [file] [log] [blame]
// Copyright 2019 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 "components/viz/service/display_embedder/skia_output_device_gl.h"
#include <utility>
#include "base/bind_helpers.h"
#include "components/viz/service/display_embedder/skia_output_surface_dependency.h"
#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/gl_utils.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/core/SkSurfaceProps.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrContext.h"
#include "third_party/skia/include/gpu/gl/GrGLTypes.h"
#include "ui/gl/color_space_utils.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_version_info.h"
namespace viz {
SkiaOutputDeviceGL::SkiaOutputDeviceGL(
SkiaOutputSurfaceDependency* deps,
scoped_refptr<gpu::gles2::FeatureInfo> feature_info,
const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback)
: SkiaOutputDevice(false /*need_swap_semaphore */,
did_swap_buffer_complete_callback),
dependency_(deps),
feature_info_(feature_info) {
gl_surface_ = dependency_->CreateGLSurface(weak_ptr_factory_.GetWeakPtr());
}
void SkiaOutputDeviceGL::Initialize(GrContext* gr_context,
gl::GLContext* gl_context) {
DCHECK(gr_context);
DCHECK(gl_context);
gr_context_ = gr_context;
gl::CurrentGL* current_gl = gl_context->GetCurrentGL();
DCHECK(current_gl);
// Get alpha bits from the default frame buffer.
glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
gr_context_->resetContext(kRenderTarget_GrGLBackendState);
const auto* version = current_gl->Version;
GLint alpha_bits = 0;
if (version->is_desktop_core_profile) {
glGetFramebufferAttachmentParameterivEXT(
GL_FRAMEBUFFER, GL_BACK_LEFT, GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
&alpha_bits);
} else {
glGetIntegerv(GL_ALPHA_BITS, &alpha_bits);
}
CHECK_GL_ERROR();
supports_alpha_ = alpha_bits > 0;
capabilities_.flipped_output_surface = gl_surface_->FlipsVertically();
capabilities_.supports_post_sub_buffer = gl_surface_->SupportsPostSubBuffer();
if (feature_info_->workarounds()
.disable_post_sub_buffers_for_onscreen_surfaces)
capabilities_.supports_post_sub_buffer = false;
}
SkiaOutputDeviceGL::~SkiaOutputDeviceGL() {}
scoped_refptr<gl::GLSurface> SkiaOutputDeviceGL::gl_surface() {
return gl_surface_;
}
void SkiaOutputDeviceGL::Reshape(const gfx::Size& size,
float device_scale_factor,
const gfx::ColorSpace& color_space,
bool has_alpha) {
gl::GLSurface::ColorSpace surface_color_space =
gl::ColorSpaceUtils::GetGLSurfaceColorSpace(color_space);
if (!gl_surface_->Resize(size, device_scale_factor, surface_color_space,
has_alpha)) {
LOG(FATAL) << "Failed to resize.";
// TODO(penghuang): Handle the failure.
}
SkSurfaceProps surface_props =
SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType);
GrGLFramebufferInfo framebuffer_info;
framebuffer_info.fFBOID = gl_surface_->GetBackingFramebufferObject();
framebuffer_info.fFormat = supports_alpha_ ? GL_RGBA8 : GL_RGB8_OES;
GrBackendRenderTarget render_target(size.width(), size.height(), 0, 8,
framebuffer_info);
auto origin = gl_surface_->FlipsVertically() ? kTopLeft_GrSurfaceOrigin
: kBottomLeft_GrSurfaceOrigin;
auto color_type =
supports_alpha_ ? kRGBA_8888_SkColorType : kRGB_888x_SkColorType;
draw_surface_ = SkSurface::MakeFromBackendRenderTarget(
gr_context_, render_target, origin, color_type,
color_space.ToSkColorSpace(), &surface_props);
DCHECK(draw_surface_);
}
gfx::SwapResponse SkiaOutputDeviceGL::SwapBuffers(
const GrBackendSemaphore& semaphore,
BufferPresentedCallback feedback) {
// TODO(backer): Support SwapBuffersAsync
StartSwapBuffers({});
return FinishSwapBuffers(gl_surface_->SwapBuffers(std::move(feedback)));
}
gfx::SwapResponse SkiaOutputDeviceGL::PostSubBuffer(
const gfx::Rect& rect,
const GrBackendSemaphore& semaphore,
BufferPresentedCallback feedback) {
// TODO(backer): Support PostSubBufferAsync
StartSwapBuffers({});
return FinishSwapBuffers(gl_surface_->PostSubBuffer(
rect.x(), rect.y(), rect.width(), rect.height(), std::move(feedback)));
}
void SkiaOutputDeviceGL::SetDrawRectangle(const gfx::Rect& draw_rectangle) {
gl_surface_->SetDrawRectangle(draw_rectangle);
}
void SkiaOutputDeviceGL::EnsureBackbuffer() {
gl_surface_->SetBackbufferAllocation(true);
}
void SkiaOutputDeviceGL::DiscardBackbuffer() {
gl_surface_->SetBackbufferAllocation(false);
}
#if defined(OS_WIN)
void SkiaOutputDeviceGL::DidCreateAcceleratedSurfaceChildWindow(
gpu::SurfaceHandle parent_window,
gpu::SurfaceHandle child_window) {
dependency_->DidCreateAcceleratedSurfaceChildWindow(parent_window,
child_window);
}
#endif
const gpu::gles2::FeatureInfo* SkiaOutputDeviceGL::GetFeatureInfo() const {
return feature_info_.get();
}
const gpu::GpuPreferences& SkiaOutputDeviceGL::GetGpuPreferences() const {
return gpu_preferences_;
}
void SkiaOutputDeviceGL::DidSwapBuffersComplete(
gpu::SwapBuffersCompleteParams params) {
// TODO(kylechar): Check if this is necessary.
}
void SkiaOutputDeviceGL::BufferPresented(
const gfx::PresentationFeedback& feedback) {
// TODO(kylechar): Check if this is necessary.
}
GpuVSyncCallback SkiaOutputDeviceGL::GetGpuVSyncCallback() {
// TODO(sunnyps): Implement GpuVSync with SkiaRenderer.
NOTIMPLEMENTED();
return base::DoNothing::Repeatedly<base::TimeTicks, base::TimeDelta>();
}
} // namespace viz