blob: 0e3489c8ddfdd76f66972ab3cb53ba6ea9a9d9dc [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_SCRATCH_SURFACE_CACHE_H_
#define COBALT_RENDERER_RASTERIZER_SKIA_SCRATCH_SURFACE_CACHE_H_
#include <vector>
#include "base/callback.h"
#include "base/logging.h"
#include "cobalt/math/size.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/core/SkSurfaceProps.h"
namespace cobalt {
namespace renderer {
namespace rasterizer {
namespace skia {
// The ScratchSurfaceCache manages a set of Skia SkSurface objects that can
// be used for offscreen rendering (mainly by SkiaRenderTreeNodeVisitor).
// In order to acquire surfaces from ScratchSurfaceCache, one should construct
// a CachedScratchSurface object, from which they can get a pointer to the
// SkSurface object.
// It is unique because it caters to SkiaRenderTreeNodeVisitor's scratch
// surface allocation pattern. In particular, we don't mind handing out very
// large scratch surfaces when very small surfaces are requested, because
// typically only one surface is ever needed at a time. When multiple surfaces
// are necessary, the subsequent ones tend to be smaller than the previous
// (because rendering is now happening within the previous ones), and so handing
// out textures in large to small order makes sense.
class ScratchSurfaceCache {
public:
typedef base::Callback<SkSurface*(const math::Size&)> CreateSkSurfaceFunction;
ScratchSurfaceCache(
const CreateSkSurfaceFunction& create_sk_surface_function);
~ScratchSurfaceCache();
private:
// Acquire (either via cache lookup or by creation if that fails) a scratch
// surface.
SkSurface* AcquireScratchSurface(const math::Size& size);
void ReleaseScratchSurface(SkSurface* surface);
// Searches through |unused_surfaces_| for one the one that best matches the
// requested size, among all those cached surfaces that have at least the
// requested size.
SkSurface* FindBestCachedSurface(const math::Size& size);
// Removes elements from the cache until we are below the cache limit.
void Purge();
// Allocate a new SkSurface and return it.
SkSurface* CreateScratchSurface(const math::Size& size);
// Called to allocate new SkSurfaces.
CreateSkSurfaceFunction create_sk_surface_function_;
// We keep track of all surfaces we've handed out using |surface_stack_|.
// This is mostly for debug checks to verify that surfaces returned to us
// actually did come from us, and that they are returned in the expected
// order.
std::vector<SkSurface*> surface_stack_;
// |unused_surfaces_| is the heart of the cache, as it stores the surfaces
// that are unused but allocated and available to be handed out upon request.
// Most recently used surfaces are found at the end of this vector.
std::vector<SkSurface*> unused_surfaces_;
// Tracks how much total memory we've allocated towards surfaces.
size_t surface_memory_;
friend class CachedScratchSurface;
};
// The primary interface to ScratchSurfaceCache is through CachedScratchSurface
// objects. These effectively scope the acquisition of a cached surface, RAII
// style.
class CachedScratchSurface {
public:
CachedScratchSurface(ScratchSurfaceCache* cache, const math::Size& size)
: cache_(cache) {
surface_ = cache_->AcquireScratchSurface(size);
}
~CachedScratchSurface() {
if (surface_) {
cache_->ReleaseScratchSurface(surface_);
}
}
// Returns a pointer to the Skia SkSurface.
SkSurface* GetSurface() { return surface_; }
private:
ScratchSurfaceCache* cache_;
SkSurface* surface_;
};
} // namespace skia
} // namespace rasterizer
} // namespace renderer
} // namespace cobalt
#endif // COBALT_RENDERER_RASTERIZER_SKIA_SCRATCH_SURFACE_CACHE_H_