[go: nahoru, domu]

blob: b643cfe651c80aa5a915b1ddd2d5bc11cdf722f3 [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.
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_H_
#include <memory>
#include <vector>
#include "base/callback.h"
#include "base/containers/queue.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "components/viz/service/display/overlay_processor_interface.h"
#include "components/viz/service/display/skia_output_surface.h"
#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/src/gpu/GrSemaphore.h"
#include "ui/gfx/swap_result.h"
class GrDirectContext;
class SkSurface;
namespace base {
class SequencedTaskRunner;
}
namespace gfx {
class Rect;
class Size;
struct PresentationFeedback;
} // namespace gfx
namespace gpu {
class MemoryTracker;
class MemoryTypeTracker;
} // namespace gpu
namespace ui {
class LatencyTracker;
}
namespace viz {
class VulkanContextProvider;
class SkiaOutputDevice {
public:
// A helper class for defining a BeginPaint() and EndPaint() scope.
class ScopedPaint {
public:
ScopedPaint(std::vector<GrBackendSemaphore> end_semaphores,
SkiaOutputDevice* device,
SkSurface* sk_surface);
ScopedPaint(const ScopedPaint&) = delete;
ScopedPaint& operator=(const ScopedPaint&) = delete;
~ScopedPaint();
// This can be null.
SkSurface* sk_surface() const { return sk_surface_; }
SkCanvas* GetCanvas();
GrSemaphoresSubmitted Flush(VulkanContextProvider* vulkan_context_provider,
std::vector<GrBackendSemaphore> end_semaphores,
base::OnceClosure on_finished);
bool Wait(int num_semaphores,
const GrBackendSemaphore wait_semaphores[],
bool delete_semaphores_after_wait);
bool Draw(sk_sp<const SkDeferredDisplayList> ddl);
std::vector<GrBackendSemaphore> TakeEndPaintSemaphores() {
std::vector<GrBackendSemaphore> semaphores;
semaphores.swap(end_semaphores_);
return semaphores;
}
private:
std::vector<GrBackendSemaphore> end_semaphores_;
const raw_ptr<SkiaOutputDevice> device_;
// Null when using vulkan secondary command buffer.
const raw_ptr<SkSurface> sk_surface_;
};
using BufferPresentedCallback =
base::OnceCallback<void(const gfx::PresentationFeedback& feedback)>;
using DidSwapBufferCompleteCallback =
base::RepeatingCallback<void(gpu::SwapBuffersCompleteParams,
const gfx::Size& pixel_size,
gfx::GpuFenceHandle release_fence)>;
SkiaOutputDevice(
GrDirectContext* gr_context,
gpu::MemoryTracker* memory_tracker,
DidSwapBufferCompleteCallback did_swap_buffer_complete_callback);
SkiaOutputDevice(const SkiaOutputDevice&) = delete;
SkiaOutputDevice& operator=(const SkiaOutputDevice&) = delete;
virtual ~SkiaOutputDevice();
// Begins a paint scope. The base implementation fails when the SkSurface
// cannot be initialized, but devices that don't draw to a SkSurface (i.e
// |SkiaOutputDeviceVulkanSecondaryCB|) can override this to bypass the
// check.
// `allocate_frame_buffer` indicates a new frame buffer should be allocated
// for this paint. Is set only when `UseDynamicFrameBufferAllocation` is set.
virtual std::unique_ptr<SkiaOutputDevice::ScopedPaint> BeginScopedPaint(
bool allocate_frame_buffer);
// Changes the size of draw surface and invalidates it's contents.
virtual bool Reshape(const SkSurfaceCharacterization& characterization,
const gfx::ColorSpace& color_space,
float device_scale_factor,
gfx::OverlayTransform transform) = 0;
// For devices that supports viewporter.
virtual void SetViewportSize(const gfx::Size& viewport_size);
// Submit the GrContext and run |callback| after. Note most but not all
// implementations will run |callback| in this call stack.
// If the |sync_cpu| flag is true this function will return once the gpu
// has finished with all submitted work.
virtual void Submit(bool sync_cpu, base::OnceClosure callback);
// Presents the back buffer.
virtual void SwapBuffers(BufferPresentedCallback feedback,
OutputSurfaceFrame frame) = 0;
virtual void PostSubBuffer(const gfx::Rect& rect,
BufferPresentedCallback feedback,
OutputSurfaceFrame frame);
virtual void CommitOverlayPlanes(BufferPresentedCallback feedback,
OutputSurfaceFrame frame);
virtual bool AllocateFrameBuffers(size_t n);
// Release one frame buffer. Only called if `UseDynamicFrameBufferAllocation`
// is true.
virtual void ReleaseOneFrameBuffer();
// Set the rectangle that will be drawn into on the surface.
virtual bool SetDrawRectangle(const gfx::Rect& draw_rectangle);
// Enable or disable DC layers. Must be called before DC layers are scheduled.
virtual void SetEnableDCLayers(bool enabled);
virtual void SetGpuVSyncEnabled(bool enabled);
// Whether the output device's primary plane is an overlay. This returns true
// is the SchedulePrimaryPlane function is implemented.
virtual bool IsPrimaryPlaneOverlay() const;
// Schedule the output device's back buffer as an overlay plane. The scheduled
// primary plane will be on screen when SwapBuffers() or PostSubBuffer() is
// called.
virtual void SchedulePrimaryPlane(
const absl::optional<
OverlayProcessorInterface::OutputSurfaceOverlayPlane>& plane);
// Schedule overlays which will be on screen when SwapBuffers() or
// PostSubBuffer() is called.
virtual void ScheduleOverlays(SkiaOutputSurface::OverlayList overlays);
const OutputSurface::Capabilities& capabilities() const {
return capabilities_;
}
// EnsureBackbuffer called when output surface is visible and may be drawn to.
// DiscardBackbuffer called when output surface is hidden and will not be
// drawn to. Default no-op.
virtual void EnsureBackbuffer();
virtual void DiscardBackbuffer();
// Acknowledges a SwapBuffers request without actually attempting to swap.
// This should be called when the GPU thread decides to skip a swap that was
// invoked by the viz thread to ensure that we still run the relevant metrics
// bookkeeping.
virtual void SwapBuffersSkipped(BufferPresentedCallback feedback,
OutputSurfaceFrame frame);
bool is_emulated_rgbx() const { return is_emulated_rgbx_; }
void SetDrawTimings(base::TimeTicks submitted, base::TimeTicks started);
void SetDependencyTimings(base::TimeTicks task_ready);
protected:
// Only valid between StartSwapBuffers and FinishSwapBuffers.
class SwapInfo {
public:
SwapInfo(uint64_t swap_id,
BufferPresentedCallback feedback,
base::TimeTicks viz_scheduled_draw,
base::TimeTicks gpu_started_draw,
base::TimeTicks task_ready);
SwapInfo(SwapInfo&& other);
~SwapInfo();
uint64_t SwapId();
const gpu::SwapBuffersCompleteParams& Complete(
gfx::SwapCompletionResult result,
const absl::optional<gfx::Rect>& damage_area,
std::vector<gpu::Mailbox> released_overlays,
const gpu::Mailbox& primary_plane_mailbox);
void CallFeedback();
private:
BufferPresentedCallback feedback_;
gpu::SwapBuffersCompleteParams params_;
};
// Begin paint the back buffer.
virtual SkSurface* BeginPaint(
bool allocate_frame_buffer,
std::vector<GrBackendSemaphore>* end_semaphores) = 0;
// End paint the back buffer.
virtual void EndPaint() = 0;
// Overridden by SkiaOutputDeviceVulkanSecondaryCB.
virtual SkCanvas* GetCanvas(SkSurface* sk_surface);
virtual GrSemaphoresSubmitted Flush(
SkSurface* sk_surface,
VulkanContextProvider* vulkan_context_provider,
std::vector<GrBackendSemaphore> end_semaphores,
base::OnceClosure on_finished);
virtual bool Wait(SkSurface* sk_surface,
int num_semaphores,
const GrBackendSemaphore wait_semaphores[],
bool delete_semaphores_after_wait);
virtual bool Draw(SkSurface* sk_surface,
sk_sp<const SkDeferredDisplayList> ddl);
// Helper method for SwapBuffers() and PostSubBuffer(). It should be called
// at the beginning of SwapBuffers() and PostSubBuffer() implementations
void StartSwapBuffers(BufferPresentedCallback feedback);
// Helper method for SwapBuffers() and PostSubBuffer(). It should be called
// at the end of SwapBuffers() and PostSubBuffer() implementations
void FinishSwapBuffers(
gfx::SwapCompletionResult result,
const gfx::Size& size,
OutputSurfaceFrame frame,
const absl::optional<gfx::Rect>& damage_area = absl::nullopt,
std::vector<gpu::Mailbox> released_overlays = {},
const gpu::Mailbox& primary_plane_mailbox = gpu::Mailbox());
const raw_ptr<GrDirectContext> gr_context_;
OutputSurface::Capabilities capabilities_;
uint64_t swap_id_ = 0;
DidSwapBufferCompleteCallback did_swap_buffer_complete_callback_;
base::queue<SwapInfo> pending_swaps_;
base::TimeTicks viz_scheduled_draw_;
base::TimeTicks gpu_started_draw_;
base::TimeTicks gpu_task_ready_;
// RGBX format is emulated with RGBA.
bool is_emulated_rgbx_ = false;
std::unique_ptr<gpu::MemoryTypeTracker> memory_type_tracker_;
private:
std::unique_ptr<ui::LatencyTracker> latency_tracker_;
// task runner for latency tracker.
scoped_refptr<base::SequencedTaskRunner> latency_tracker_runner_;
// A mapping from skipped swap ID to its corresponding OutputSurfaceFrame.
base::flat_map<uint64_t, OutputSurfaceFrame> skipped_swap_info_;
};
} // namespace viz
#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_H_