blob: 7b52259cedd90db69145ef7b69e93c320a359b87 [file] [log] [blame]
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef COBALT_RENDERER_RASTERIZER_SKIA_SURFACE_CACHE_DELEGATE_H_
#define COBALT_RENDERER_RASTERIZER_SKIA_SURFACE_CACHE_DELEGATE_H_
#include <string>
#include "base/callback.h"
#include "base/optional.h"
#if defined(ENABLE_DEBUG_CONSOLE)
#include "cobalt/base/console_commands.h"
#endif
#include "cobalt/renderer/rasterizer/common/offscreen_render_coordinate_mapping.h"
#include "cobalt/renderer/rasterizer/common/surface_cache.h"
#include "cobalt/renderer/rasterizer/skia/render_tree_node_visitor_draw_state.h"
#include "third_party/skia/include/core/SkSurface.h"
namespace cobalt {
namespace renderer {
namespace rasterizer {
namespace skia {
// Implements skia-specific cache recording and playback surface management
// in order to provide skia-support for the render tree surface caching system.
class SurfaceCacheDelegate : public common::SurfaceCache::Delegate {
private:
class CachedSurface : public common::SurfaceCache::CachedSurface {
public:
CachedSurface(SkSurface* surface, const math::Vector2dF& output_post_scale,
const math::Vector2dF& output_pre_translate,
const math::Rect& output_bounds)
: surface_(surface),
image_(surface_ ? surface_->newImageSnapshot() : NULL),
output_post_scale_(output_post_scale),
output_pre_translate_(output_pre_translate),
output_bounds_(output_bounds) {}
~CachedSurface() OVERRIDE {}
SkImage* image() const { return image_.get(); }
const math::Vector2dF& output_post_scale() const {
return output_post_scale_;
}
const math::Vector2dF& output_pre_translate() const {
return output_pre_translate_;
}
const math::Rect& output_bounds() const { return output_bounds_; }
private:
// The actual skia surface representing the cached render tree.
SkAutoTUnref<SkSurface> surface_;
// For convenience, we save the image snapshot associated with |surface_|
// above.
SkAutoTUnref<SkImage> image_;
// When applying |surface_| to another render target, the current
// transformation should be post-multiplied by |output_post_scale_|, and
// pre-multiplied by |output_pre_translate_|.
math::Vector2dF output_post_scale_;
math::Vector2dF output_pre_translate_;
// The rectangle coordinates into which |surface_| should be rendered.
math::Rect output_bounds_;
};
public:
typedef base::Callback<SkSurface*(const math::Size&)> CreateSkSurfaceFunction;
// Creating a ScopedContext object declares a render tree visitor context,
// and so there should be one ScopedContext per render tree visitor. Since
// it is typical to recursively create sub render tree visitors, this class
// is designed to be instantiated multiple times on the same
// SurfaceCacheDelegate object.
class ScopedContext {
public:
ScopedContext(SurfaceCacheDelegate* delegate,
RenderTreeNodeVisitorDrawState* draw_state)
: delegate_(delegate), old_draw_state_(delegate_->draw_state_) {
// Setup our new draw state (including render target) to the provided one.
delegate_->draw_state_ = draw_state;
// A new canvas may mean a new total matrix, so inform our delegate to
// refresh its scale.
delegate_->UpdateCanvasScale();
}
~ScopedContext() {
// Restore the draw state to the old setting.
delegate_->draw_state_ = old_draw_state_;
if (delegate_->draw_state_) {
delegate_->UpdateCanvasScale();
}
}
private:
SurfaceCacheDelegate* delegate_;
RenderTreeNodeVisitorDrawState* old_draw_state_;
};
SurfaceCacheDelegate(
const CreateSkSurfaceFunction& create_sk_surface_function,
const math::Size& max_surface_size);
// Must be called every time our client changes the current scale on us, e.g.
// when visiting a MatrixTransformNode.
void UpdateCanvasScale();
void ApplySurface(common::SurfaceCache::CachedSurface* surface) OVERRIDE;
void StartRecording(const math::RectF& local_bounds) OVERRIDE;
common::SurfaceCache::CachedSurface* EndRecording() OVERRIDE;
void ReleaseSurface(common::SurfaceCache::CachedSurface* surface) OVERRIDE;
math::Size GetRenderSize(const math::SizeF& local_size) OVERRIDE;
math::Size MaximumSurfaceSize() OVERRIDE;
private:
// Defines a set of data that is relevant only while recording.
struct RecordingData {
RecordingData(const RenderTreeNodeVisitorDrawState& original_draw_state,
const common::OffscreenRenderCoordinateMapping& coord_mapping,
SkSurface* surface)
: original_draw_state(original_draw_state),
coord_mapping(coord_mapping),
surface(surface) {}
// The original draw state (including render target/canvas) that the
// recorded draw calls would have otherwise targeted if we were not
// recording.
RenderTreeNodeVisitorDrawState original_draw_state;
// Information about how to map the offscreen cached surface to the main
// render target.
common::OffscreenRenderCoordinateMapping coord_mapping;
// The offscreen cached surface that we are recording to.
SkSurface* surface;
};
#if defined(ENABLE_DEBUG_CONSOLE)
void OnToggleCacheHighlights(const std::string& message);
#endif
// A function that will return a fresh SkSurface object when we need to cache
// something new.
CreateSkSurfaceFunction create_sk_surface_function_;
// The maximum size of an SkSurface.
math::Size max_surface_size_;
// The current draw state (including the SkCanvas) that is being targeted,
// whether its the main onscreen surface or a cached surface.
RenderTreeNodeVisitorDrawState* draw_state_;
// If we are currently recording, this will contain all of the data relevant
// to that recording.
base::optional<RecordingData> recording_data_;
// The current scale of draw_state_->render_target->getTotalMatrix(). This
// lets us quickly check if the scale of a render node changes from the last
// time we observed it, which may happen if an animation is targeting a
// MatrixTransformNode render tree node.
math::Vector2dF scale_;
#if defined(ENABLE_DEBUG_CONSOLE)
// Debug command to toggle cache highlights to help visualize which nodes
// are being cached.
bool toggle_cache_highlights_;
base::ConsoleCommandManager::CommandHandler
toggle_cache_highlights_command_handler_;
#endif
};
} // namespace skia
} // namespace rasterizer
} // namespace renderer
} // namespace cobalt
#endif // COBALT_RENDERER_RASTERIZER_SKIA_SURFACE_CACHE_DELEGATE_H_