blob: ef12cc71bfaedc03ea6ca37e48be57861c8d7806 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebEngine module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "display_gl_output_surface.h"
#include "chromium_gpu_helper.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/viz/service/display/display.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/service/mailbox_manager.h"
#include "gpu/command_buffer/service/texture_base.h"
#include "gpu/ipc/in_process_command_buffer.h"
#include "ui/gl/color_space_utils.h"
namespace QtWebEngineCore {
DisplayGLOutputSurface::DisplayGLOutputSurface(scoped_refptr<viz::VizProcessContextProvider> contextProvider)
: OutputSurface(contextProvider)
, m_commandBuffer(contextProvider->command_buffer())
, m_gl(contextProvider->ContextGL())
, m_vizContextProvider(contextProvider)
{
capabilities_.uses_default_gl_framebuffer = false;
m_gl->GenFramebuffers(1, &m_fboId);
}
DisplayGLOutputSurface::~DisplayGLOutputSurface()
{
m_vizContextProvider->SetUpdateVSyncParametersCallback(viz::UpdateVSyncParametersCallback());
m_gl->DeleteFramebuffers(1, &m_fboId);
if (m_sink)
m_sink->disconnect(this);
}
// Called from viz::Display::Initialize.
void DisplayGLOutputSurface::BindToClient(viz::OutputSurfaceClient *client)
{
m_display = static_cast<viz::Display *>(client);
m_sink = DisplayFrameSink::findOrCreate(m_display->frame_sink_id());
m_sink->connect(this);
}
// Triggered by ui::Compositor::SetVisible(true).
void DisplayGLOutputSurface::EnsureBackbuffer()
{
}
// Triggered by ui::Compositor::SetVisible(false). Framebuffer must be cleared.
void DisplayGLOutputSurface::DiscardBackbuffer()
{
NOTIMPLEMENTED();
// m_gl->DiscardBackbufferCHROMIUM();
}
// Called from viz::DirectRenderer::DrawFrame before rendering starts, but only
// if the parameters differ from the previous Reshape call.
//
// Parameters:
//
// - sizeInPixels comes from ui::Compositor::SetScaleAndSize via
// viz::HostContextFactoryPrivate::ResizeDisplay.
//
// - devicePixelRatio comes from viz::CompositorFrame::device_scale_factor()
// via viz::RootCompositorFrameSinkImpl::SubmitCompositorFrame and
// viz::Display::SetLocalSurfaceId.
//
// - colorSpace and hasAlpha correspond to the color_space and
// has_transparent_background properties of the root viz::RenderPass.
//
// - useStencil should create a stencil buffer, but this is only needed for
// overdraw feedback (--show-overdraw-feedback), so it's safe to ignore.
// Accordingly, capabilities_.supports_stencil should be set to false.
//
void DisplayGLOutputSurface::Reshape(const gfx::Size &sizeInPixels,
float devicePixelRatio,
const gfx::ColorSpace &colorSpace,
bool hasAlpha,
bool /*useStencil*/)
{
m_currentShape = Shape{sizeInPixels, devicePixelRatio, colorSpace, hasAlpha};
m_gl->ResizeCHROMIUM(sizeInPixels.width(), sizeInPixels.height(), devicePixelRatio,
gl::ColorSpaceUtils::GetGLColorSpace(colorSpace), hasAlpha);
}
std::unique_ptr<DisplayGLOutputSurface::Buffer> DisplayGLOutputSurface::makeBuffer(const Shape &shape)
{
std::unique_ptr<Buffer> buffer = std::make_unique<Buffer>(this);
buffer->shape = shape;
m_gl->GenTextures(1, &buffer->clientId);
m_gl->BindTexture(GL_TEXTURE_2D, buffer->clientId);
m_gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
m_gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
m_gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
m_gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
uint32_t width = shape.sizeInPixels.width();
uint32_t height = shape.sizeInPixels.height();
uint32_t format = shape.hasAlpha ? GL_RGBA : GL_RGB;
m_gl->TexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr);
return buffer;
}
void DisplayGLOutputSurface::deleteBufferResources(Buffer *buffer)
{
m_gl->DeleteTextures(1, &buffer->clientId);
}
// Called by viz::GLRenderer during rendering whenever it switches to the root
// render pass.
void DisplayGLOutputSurface::BindFramebuffer()
{
if (!m_backBuffer || m_backBuffer->shape != m_currentShape)
m_backBuffer = makeBuffer(m_currentShape);
m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fboId);
m_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_backBuffer->clientId, 0);
}
// Called from viz::Display::DrawAndSwap after rendering.
//
// Parameters:
//
// - frame.size is the same as the size given to Reshape.
//
// - frame.sub_buffer_rect and frame.content_bounds are never used since these
// are only enabled if gl::GLSurface::SupportsPostSubBuffer() or
// gl::GLSurface::SupportsSwapBuffersWithBounds() are true, respectively,
// but this not the case for any offscreen gl::GLSurface.
//
// - frame.latency_info is viz::CompositorFrame::metadata.latency_info.
void DisplayGLOutputSurface::SwapBuffers(viz::OutputSurfaceFrame frame)
{
DCHECK(frame.size == m_currentShape.sizeInPixels);
DCHECK(!frame.sub_buffer_rect.has_value());
DCHECK(frame.content_bounds.empty());
DCHECK(m_backBuffer);
m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fboId);
m_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
gpu::SyncToken syncToken;
m_gl->GenSyncTokenCHROMIUM(syncToken.GetData());
unsigned int clientId = m_backBuffer->clientId;
// Now some thread-hopping:
//
// - We start here on the viz thread (client side of command buffer).
//
// - Then we'll jump to the gpu thread (service side of command buffer) to
// get the real OpenGL texture id.
//
// - Then we'll get a call from the Qt Quick Scene Graph thread (could be
// a separate thread or the main thread).
//
// - Finally we'll return to the viz thread to acknowledge the swap.
{
QMutexLocker locker(&m_mutex);
m_taskRunner = base::ThreadTaskRunnerHandle::Get();
m_middleBuffer = std::move(m_backBuffer);
m_middleBuffer->serviceId = 0;
}
m_commandBuffer->GetTextureQt(
clientId,
base::BindOnce(&DisplayGLOutputSurface::swapBuffersOnGpuThread, base::Unretained(this)),
std::vector<gpu::SyncToken>{syncToken});
}
void DisplayGLOutputSurface::swapBuffersOnGpuThread(unsigned int id, std::unique_ptr<gl::GLFence> fence)
{
{
QMutexLocker locker(&m_mutex);
m_middleBuffer->serviceId = id;
m_middleBuffer->fence = CompositorResourceFence::create(std::move(fence));
}
m_sink->scheduleUpdate();
}
void DisplayGLOutputSurface::swapBuffersOnVizThread()
{
{
QMutexLocker locker(&m_mutex);
m_backBuffer = std::move(m_middleBuffer);
}
const auto now = base::TimeTicks::Now();
m_display->DidReceiveSwapBuffersAck(gfx::SwapTimings{now, now});
m_display->DidReceivePresentationFeedback(
gfx::PresentationFeedback(now, base::TimeDelta(),
gfx::PresentationFeedback::Flags::kVSync));
}
void DisplayGLOutputSurface::SetDrawRectangle(const gfx::Rect &)
{
}
// Returning true here will cause viz::GLRenderer to try to render the output
// surface as an overlay plane (see viz::DirectRenderer::DrawFrame and
// viz::GLRenderer::ScheduleOverlays).
bool DisplayGLOutputSurface::IsDisplayedAsOverlayPlane() const
{
return false;
}
// Only used if IsDisplayedAsOverlayPlane was true (called from
// viz::GLRenderer::ScheduleOverlays).
unsigned DisplayGLOutputSurface::GetOverlayTextureId() const
{
return 0;
}
// Only used if IsDisplayedAsOverlayPlane was true (called from
// viz::DirectRender::DrawFrame).
gfx::BufferFormat DisplayGLOutputSurface::GetOverlayBufferFormat() const
{
return gfx::BufferFormat();
}
// Called by viz::GLRenderer but always false in all implementations except for
// android_webview::ParentOutputSurface.
bool DisplayGLOutputSurface::HasExternalStencilTest() const
{
return false;
}
// Only called if HasExternalStencilTest was true. Dead code?
void DisplayGLOutputSurface::ApplyExternalStencil()
{
NOTREACHED();
}
// Called from GLRenderer::GetFramebufferCopyTextureFormat when using
// glCopyTexSubImage2D on our framebuffer.
uint32_t DisplayGLOutputSurface::GetFramebufferCopyTextureFormat()
{
return m_currentShape.hasAlpha ? GL_RGBA : GL_RGB;
}
// Called from viz::DirectRenderer::DrawFrame, only used for overlays.
unsigned DisplayGLOutputSurface::UpdateGpuFence()
{
NOTREACHED();
return 0;
}
void DisplayGLOutputSurface::SetUpdateVSyncParametersCallback(viz::UpdateVSyncParametersCallback callback)
{
m_vizContextProvider->SetUpdateVSyncParametersCallback(std::move(callback));
}
void DisplayGLOutputSurface::SetDisplayTransformHint(gfx::OverlayTransform)
{
}
gfx::OverlayTransform DisplayGLOutputSurface::GetDisplayTransform()
{
return gfx::OVERLAY_TRANSFORM_NONE;
}
} // namespace QtWebEngineCore