2014-08-21 20:12:42 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2014 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2014-11-04 16:11:07 +00:00
|
|
|
// Need to include something before #if SK_SUPPORT_GPU so that the Android
|
|
|
|
// framework build, which gets its defines from SkTypes rather than a makefile,
|
|
|
|
// has the definition before checking it.
|
2014-08-21 20:12:42 +00:00
|
|
|
#include "SkCanvas.h"
|
2014-11-24 17:49:17 +00:00
|
|
|
#include "SkCanvasPriv.h"
|
2014-08-21 20:12:42 +00:00
|
|
|
#include "SkMultiPictureDraw.h"
|
|
|
|
#include "SkPicture.h"
|
2014-10-29 19:36:45 +00:00
|
|
|
#include "SkTaskGroup.h"
|
|
|
|
|
2014-11-04 16:11:07 +00:00
|
|
|
#if SK_SUPPORT_GPU
|
2014-12-03 15:33:57 +00:00
|
|
|
#include "GrContext.h"
|
2014-11-04 16:11:07 +00:00
|
|
|
#include "GrLayerHoister.h"
|
|
|
|
#include "GrRecordReplaceDraw.h"
|
2014-11-10 16:10:42 +00:00
|
|
|
#include "GrRenderTarget.h"
|
2014-11-04 16:11:07 +00:00
|
|
|
#endif
|
|
|
|
|
2014-10-29 19:36:45 +00:00
|
|
|
void SkMultiPictureDraw::DrawData::draw() {
|
|
|
|
fCanvas->drawPicture(fPicture, &fMatrix, fPaint);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SkMultiPictureDraw::DrawData::init(SkCanvas* canvas, const SkPicture* picture,
|
|
|
|
const SkMatrix* matrix, const SkPaint* paint) {
|
|
|
|
fPicture = SkRef(picture);
|
|
|
|
fCanvas = SkRef(canvas);
|
|
|
|
if (matrix) {
|
|
|
|
fMatrix = *matrix;
|
|
|
|
} else {
|
|
|
|
fMatrix.setIdentity();
|
|
|
|
}
|
|
|
|
if (paint) {
|
|
|
|
fPaint = SkNEW_ARGS(SkPaint, (*paint));
|
|
|
|
} else {
|
|
|
|
fPaint = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SkMultiPictureDraw::DrawData::Reset(SkTDArray<DrawData>& data) {
|
|
|
|
for (int i = 0; i < data.count(); ++i) {
|
|
|
|
data[i].fPicture->unref();
|
|
|
|
data[i].fCanvas->unref();
|
|
|
|
SkDELETE(data[i].fPaint);
|
|
|
|
}
|
|
|
|
data.rewind();
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
2014-08-21 20:12:42 +00:00
|
|
|
|
|
|
|
SkMultiPictureDraw::SkMultiPictureDraw(int reserve) {
|
|
|
|
if (reserve > 0) {
|
2014-10-29 19:36:45 +00:00
|
|
|
fGPUDrawData.setReserve(reserve);
|
|
|
|
fThreadSafeDrawData.setReserve(reserve);
|
2014-08-21 20:12:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SkMultiPictureDraw::reset() {
|
2014-10-29 19:36:45 +00:00
|
|
|
DrawData::Reset(fGPUDrawData);
|
|
|
|
DrawData::Reset(fThreadSafeDrawData);
|
2014-08-21 20:12:42 +00:00
|
|
|
}
|
|
|
|
|
2014-10-29 21:17:13 +00:00
|
|
|
void SkMultiPictureDraw::add(SkCanvas* canvas,
|
2014-08-21 20:12:42 +00:00
|
|
|
const SkPicture* picture,
|
2014-10-29 21:17:13 +00:00
|
|
|
const SkMatrix* matrix,
|
2014-08-21 20:12:42 +00:00
|
|
|
const SkPaint* paint) {
|
|
|
|
if (NULL == canvas || NULL == picture) {
|
|
|
|
SkDEBUGFAIL("parameters to SkMultiPictureDraw::add should be non-NULL");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-10-29 19:36:45 +00:00
|
|
|
SkTDArray<DrawData>& array = canvas->getGrContext() ? fGPUDrawData : fThreadSafeDrawData;
|
|
|
|
array.append()->init(canvas, picture, matrix, paint);
|
2014-08-21 20:12:42 +00:00
|
|
|
}
|
|
|
|
|
2014-10-29 19:36:45 +00:00
|
|
|
class AutoMPDReset : SkNoncopyable {
|
|
|
|
SkMultiPictureDraw* fMPD;
|
|
|
|
public:
|
|
|
|
AutoMPDReset(SkMultiPictureDraw* mpd) : fMPD(mpd) {}
|
|
|
|
~AutoMPDReset() { fMPD->reset(); }
|
|
|
|
};
|
|
|
|
|
2014-08-21 20:12:42 +00:00
|
|
|
void SkMultiPictureDraw::draw() {
|
2014-10-29 19:36:45 +00:00
|
|
|
AutoMPDReset mpdreset(this);
|
|
|
|
// we place the taskgroup after the MPDReset, to ensure that we don't delete the DrawData
|
|
|
|
// objects until after we're finished the tasks (which have pointers to the data).
|
|
|
|
|
|
|
|
SkTaskGroup group;
|
2014-10-29 22:44:25 +00:00
|
|
|
group.batch(DrawData::Draw, fThreadSafeDrawData.begin(), fThreadSafeDrawData.count());
|
2014-10-29 19:36:45 +00:00
|
|
|
// we deliberately don't call wait() here, since the destructor will do that, this allows us
|
|
|
|
// to continue processing gpu-data without having to wait on the cpu tasks.
|
|
|
|
|
|
|
|
const int count = fGPUDrawData.count();
|
|
|
|
if (0 == count) {
|
|
|
|
return;
|
|
|
|
}
|
2014-10-08 12:17:02 +00:00
|
|
|
|
2014-11-03 15:19:30 +00:00
|
|
|
#if !defined(SK_IGNORE_GPU_LAYER_HOISTING) && SK_SUPPORT_GPU
|
2014-10-29 19:36:45 +00:00
|
|
|
GrContext* context = fGPUDrawData[0].fCanvas->getGrContext();
|
|
|
|
SkASSERT(context);
|
2014-10-08 12:17:02 +00:00
|
|
|
|
2014-10-29 19:36:45 +00:00
|
|
|
// Start by collecting all the layers that are going to be atlased and render
|
2014-10-28 14:21:44 +00:00
|
|
|
// them (if necessary). Hoisting the free floating layers is deferred until
|
|
|
|
// drawing the canvas that requires them.
|
|
|
|
SkTDArray<GrHoistedLayer> atlasedNeedRendering, atlasedRecycled;
|
2014-10-08 12:17:02 +00:00
|
|
|
|
2014-10-29 19:36:45 +00:00
|
|
|
for (int i = 0; i < count; ++i) {
|
|
|
|
const DrawData& data = fGPUDrawData[i];
|
|
|
|
// we only expect 1 context for all the canvases
|
2014-10-30 18:49:37 +00:00
|
|
|
SkASSERT(data.fCanvas->getGrContext() == context);
|
2014-10-08 12:17:02 +00:00
|
|
|
|
2014-11-24 17:49:17 +00:00
|
|
|
if (!data.fPaint) {
|
2014-10-08 12:17:02 +00:00
|
|
|
SkRect clipBounds;
|
2014-10-29 19:36:45 +00:00
|
|
|
if (!data.fCanvas->getClipBounds(&clipBounds)) {
|
2014-10-08 12:17:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-11-24 17:49:17 +00:00
|
|
|
SkMatrix initialMatrix = data.fCanvas->getTotalMatrix();
|
|
|
|
initialMatrix.preConcat(data.fMatrix);
|
|
|
|
|
2014-11-10 16:10:42 +00:00
|
|
|
GrRenderTarget* rt = data.fCanvas->internal_private_accessTopLayerRenderTarget();
|
|
|
|
SkASSERT(rt);
|
|
|
|
|
2014-10-28 14:21:44 +00:00
|
|
|
// TODO: sorting the cacheable layers from smallest to largest
|
|
|
|
// would improve the packing and reduce the number of swaps
|
|
|
|
// TODO: another optimization would be to make a first pass to
|
|
|
|
// lock any required layer that is already in the atlas
|
2014-11-24 17:49:17 +00:00
|
|
|
GrLayerHoister::FindLayersToAtlas(context, data.fPicture, initialMatrix,
|
2014-10-29 21:17:13 +00:00
|
|
|
clipBounds,
|
2014-11-10 16:10:42 +00:00
|
|
|
&atlasedNeedRendering, &atlasedRecycled,
|
|
|
|
rt->numSamples());
|
2014-10-08 12:17:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-29 19:36:45 +00:00
|
|
|
GrLayerHoister::DrawLayersToAtlas(context, atlasedNeedRendering);
|
2014-10-28 14:21:44 +00:00
|
|
|
|
|
|
|
SkTDArray<GrHoistedLayer> needRendering, recycled;
|
2014-10-08 12:17:02 +00:00
|
|
|
#endif
|
|
|
|
|
2014-10-29 19:36:45 +00:00
|
|
|
for (int i = 0; i < count; ++i) {
|
|
|
|
const DrawData& data = fGPUDrawData[i];
|
|
|
|
SkCanvas* canvas = data.fCanvas;
|
|
|
|
const SkPicture* picture = data.fPicture;
|
|
|
|
|
2014-11-03 15:19:30 +00:00
|
|
|
#if !defined(SK_IGNORE_GPU_LAYER_HOISTING) && SK_SUPPORT_GPU
|
2014-11-24 17:49:17 +00:00
|
|
|
if (!data.fPaint) {
|
2014-10-28 14:21:44 +00:00
|
|
|
|
|
|
|
SkRect clipBounds;
|
2014-10-29 19:36:45 +00:00
|
|
|
if (!canvas->getClipBounds(&clipBounds)) {
|
2014-10-28 14:21:44 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-11-24 17:49:17 +00:00
|
|
|
SkAutoCanvasMatrixPaint acmp(canvas, &data.fMatrix, data.fPaint, picture->cullRect());
|
|
|
|
|
|
|
|
const SkMatrix initialMatrix = canvas->getTotalMatrix();
|
|
|
|
|
2014-11-10 16:10:42 +00:00
|
|
|
GrRenderTarget* rt = data.fCanvas->internal_private_accessTopLayerRenderTarget();
|
|
|
|
SkASSERT(rt);
|
|
|
|
|
2014-10-28 14:21:44 +00:00
|
|
|
// Find the layers required by this canvas. It will return atlased
|
|
|
|
// layers in the 'recycled' list since they have already been drawn.
|
2014-11-24 17:49:17 +00:00
|
|
|
GrLayerHoister::FindLayersToHoist(context, picture, initialMatrix,
|
2014-11-10 16:10:42 +00:00
|
|
|
clipBounds, &needRendering, &recycled,
|
|
|
|
rt->numSamples());
|
2014-10-28 14:21:44 +00:00
|
|
|
|
|
|
|
GrLayerHoister::DrawLayers(context, needRendering);
|
|
|
|
|
|
|
|
// Render the entire picture using new layers
|
2014-12-03 15:33:57 +00:00
|
|
|
GrRecordReplaceDraw(picture, canvas, context->getLayerCache(),
|
|
|
|
initialMatrix, NULL);
|
2014-10-28 14:21:44 +00:00
|
|
|
|
|
|
|
GrLayerHoister::UnlockLayers(context, needRendering);
|
|
|
|
GrLayerHoister::UnlockLayers(context, recycled);
|
|
|
|
|
|
|
|
needRendering.rewind();
|
|
|
|
recycled.rewind();
|
|
|
|
} else
|
2014-10-08 12:17:02 +00:00
|
|
|
#endif
|
|
|
|
{
|
2014-10-29 19:36:45 +00:00
|
|
|
canvas->drawPicture(picture, &data.fMatrix, data.fPaint);
|
2014-10-08 12:17:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-03 15:19:30 +00:00
|
|
|
#if !defined(SK_IGNORE_GPU_LAYER_HOISTING) && SK_SUPPORT_GPU
|
2014-10-29 19:36:45 +00:00
|
|
|
GrLayerHoister::UnlockLayers(context, atlasedNeedRendering);
|
|
|
|
GrLayerHoister::UnlockLayers(context, atlasedRecycled);
|
2014-10-29 20:56:02 +00:00
|
|
|
#if !GR_CACHE_HOISTED_LAYERS
|
|
|
|
GrLayerHoister::PurgeCache(context);
|
|
|
|
#endif
|
2014-10-08 12:17:02 +00:00
|
|
|
#endif
|
2014-08-21 20:12:42 +00:00
|
|
|
}
|
|
|
|
|