Optimization: SkDebugCanvas is capable of pausing and drawing incrementally instead of redrawing all commands.

Review URL: https://codereview.appspot.com/6458056

git-svn-id: http://skia.googlecode.com/svn/trunk@4891 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
chudy@google.com 2012-08-01 15:57:52 +00:00
Родитель 6385314686
Коммит 830b8793bb
7 изменённых файлов: 94 добавлений и 80 удалений

Просмотреть файл

@ -25,8 +25,8 @@ SkCanvasWidget::SkCanvasWidget() : QWidget()
fIndex = 0; fIndex = 0;
fPreviousPoint.set(0,0); fPreviousPoint.set(0,0);
fTransform.set(0,0); fUserOffset.set(0,0);
fScaleFactor = 1.0; fUserScaleFactor = 1.0;
setWidgetVisibility(kGPU_WidgetType, true); setWidgetVisibility(kGPU_WidgetType, true);
this->setDisabled(true); this->setDisabled(true);
@ -58,42 +58,37 @@ void SkCanvasWidget::loadPicture(QString filename) {
fDebugCanvas = new SkDebugCanvas(picture->width(), picture->height()); fDebugCanvas = new SkDebugCanvas(picture->width(), picture->height());
picture->draw(fDebugCanvas); picture->draw(fDebugCanvas);
fIndex = fDebugCanvas->getSize(); fIndex = fDebugCanvas->getSize() - 1;
fRasterWidget.setDebugCanvas(fDebugCanvas); fRasterWidget.setDebugCanvas(fDebugCanvas);
fGLWidget.setDebugCanvas(fDebugCanvas); fGLWidget.setDebugCanvas(fDebugCanvas);
// TODO(chudy): Remove bounds from debug canvas storage.
fDebugCanvas->setBounds(this->width(), this->height()); fDebugCanvas->setBounds(this->width(), this->height());
} }
void SkCanvasWidget::mouseMoveEvent(QMouseEvent* event) { void SkCanvasWidget::mouseMoveEvent(QMouseEvent* event) {
SkIPoint eventPoint = SkIPoint::Make(event->globalX(), event->globalY()); SkIPoint eventPoint = SkIPoint::Make(event->globalX(), event->globalY());
fTransform += eventPoint - fPreviousPoint; fUserOffset += eventPoint - fPreviousPoint;
fPreviousPoint = eventPoint; fPreviousPoint = eventPoint;
updateWidgetTransform(kTranslate); fDebugCanvas->setUserOffset(fUserOffset);
drawTo(fIndex); drawTo(fIndex);
} }
void SkCanvasWidget::mousePressEvent(QMouseEvent* event) { void SkCanvasWidget::mousePressEvent(QMouseEvent* event) {
fPreviousPoint.set(event->globalX(), event->globalY()); fPreviousPoint.set(event->globalX(), event->globalY());
emit hitChanged(fDebugCanvas->getCommandAtPoint(event->x(), event->y(), emit hitChanged(fDebugCanvas->getCommandAtPoint(event->x(), event->y(),
fIndex, fTransform, fScaleFactor)); fIndex));
} }
void SkCanvasWidget::mouseDoubleClickEvent(QMouseEvent* event) { void SkCanvasWidget::mouseDoubleClickEvent(QMouseEvent* event) {
fTransform.set(0,0);
fScaleFactor = 1.0;
emit scaleFactorChanged(fScaleFactor);
// TODO(chudy): Change to signal / slot mechanism.
resetWidgetTransform(); resetWidgetTransform();
drawTo(fIndex);
} }
void SkCanvasWidget::resetWidgetTransform() { void SkCanvasWidget::resetWidgetTransform() {
fTransform.set(0,0); fUserOffset.set(0,0);
fScaleFactor = 1.0; fUserScaleFactor = 1.0;
updateWidgetTransform(kTranslate); fDebugCanvas->setUserOffset(fUserOffset);
updateWidgetTransform(kScale); fDebugCanvas->setUserScale(fUserScaleFactor);
emit scaleFactorChanged(fUserScaleFactor);
drawTo(fIndex);
} }
void SkCanvasWidget::setWidgetVisibility(WidgetType type, bool isHidden) { void SkCanvasWidget::setWidgetVisibility(WidgetType type, bool isHidden) {
@ -104,27 +99,17 @@ void SkCanvasWidget::setWidgetVisibility(WidgetType type, bool isHidden) {
} }
} }
void SkCanvasWidget::updateWidgetTransform(TransformType type) {
if (type == kTranslate) {
fRasterWidget.setTranslate(fTransform);
fGLWidget.setTranslate(fTransform);
} else if (type == kScale) {
fRasterWidget.setScale(fScaleFactor);
fGLWidget.setScale(fScaleFactor);
}
}
void SkCanvasWidget::zoom(float zoomIncrement) { void SkCanvasWidget::zoom(float zoomIncrement) {
fScaleFactor += zoomIncrement; fUserScaleFactor += zoomIncrement;
/* The range of the fScaleFactor crosses over the range -1,0,1 frequently. /* The range of the fUserScaleFactor crosses over the range -1,0,1 frequently.
* Based on the code below, -1 and 1 both scale the image to it's original * Based on the code below, -1 and 1 both scale the image to it's original
* size we do the following to never have a registered wheel scroll * size we do the following to never have a registered wheel scroll
* not effect the fScaleFactor. */ * not effect the fUserScaleFactor. */
if (fScaleFactor == 0) { if (fUserScaleFactor == 0) {
fScaleFactor = 2 * zoomIncrement; fUserScaleFactor = 2 * zoomIncrement;
} }
emit scaleFactorChanged(fScaleFactor); emit scaleFactorChanged(fUserScaleFactor);
updateWidgetTransform(kScale); fDebugCanvas->setUserScale(fUserScaleFactor);
drawTo(fIndex); drawTo(fIndex);
} }

Просмотреть файл

@ -118,19 +118,12 @@ private:
SkGLWidget fGLWidget; SkGLWidget fGLWidget;
SkDebugCanvas* fDebugCanvas; SkDebugCanvas* fDebugCanvas;
SkIPoint fPreviousPoint; SkIPoint fPreviousPoint;
SkIPoint fTransform; SkIPoint fUserOffset;
float fScaleFactor; float fUserScaleFactor;
int fIndex; int fIndex;
enum TransformType {
kTranslate = 1 << 0,
kScale = 1 << 1,
};
void resetWidgetTransform(); void resetWidgetTransform();
void updateWidgetTransform(TransformType type);
void mouseMoveEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event);
void mousePressEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event);

Просмотреть файл

@ -18,12 +18,14 @@ SkGLWidget::SkGLWidget() : QGLWidget() {
fCurIntf = NULL; fCurIntf = NULL;
fCurContext = NULL; fCurContext = NULL;
fGpuDevice = NULL; fGpuDevice = NULL;
fCanvas = NULL;
} }
SkGLWidget::~SkGLWidget() { SkGLWidget::~SkGLWidget() {
SkSafeUnref(fCurIntf); SkSafeUnref(fCurIntf);
SkSafeUnref(fCurContext); SkSafeUnref(fCurContext);
SkSafeUnref(fGpuDevice); SkSafeUnref(fGpuDevice);
SkSafeUnref(fCanvas);
} }
void SkGLWidget::initializeGL() { void SkGLWidget::initializeGL() {
@ -31,6 +33,7 @@ void SkGLWidget::initializeGL() {
fCurContext = GrContext::Create(kOpenGL_Shaders_GrEngine, (GrPlatform3DContext) fCurIntf); fCurContext = GrContext::Create(kOpenGL_Shaders_GrEngine, (GrPlatform3DContext) fCurIntf);
GrRenderTarget* curRenderTarget = fCurContext->createPlatformRenderTarget(getDesc(this->width(), this->height())); GrRenderTarget* curRenderTarget = fCurContext->createPlatformRenderTarget(getDesc(this->width(), this->height()));
fGpuDevice = new SkGpuDevice(fCurContext, curRenderTarget); fGpuDevice = new SkGpuDevice(fCurContext, curRenderTarget);
fCanvas = new SkCanvas(fGpuDevice);
curRenderTarget->unref(); curRenderTarget->unref();
glClearColor(1, 1, 1, 0); glClearColor(1, 1, 1, 0);
@ -41,21 +44,17 @@ void SkGLWidget::initializeGL() {
void SkGLWidget::resizeGL(int w, int h) { void SkGLWidget::resizeGL(int w, int h) {
GrRenderTarget* curRenderTarget = fCurContext->createPlatformRenderTarget(getDesc(w,h)); GrRenderTarget* curRenderTarget = fCurContext->createPlatformRenderTarget(getDesc(w,h));
SkSafeUnref(fGpuDevice); SkSafeUnref(fGpuDevice);
SkSafeUnref(fCanvas);
fGpuDevice = new SkGpuDevice(fCurContext, curRenderTarget); fGpuDevice = new SkGpuDevice(fCurContext, curRenderTarget);
fCanvas = new SkCanvas(fGpuDevice);
drawTo(fIndex); drawTo(fIndex);
} }
void SkGLWidget::paintGL() { void SkGLWidget::paintGL() {
glClearColor(1, 1, 1, 0); glClearColor(1, 1, 1, 0);
SkCanvas canvas(fGpuDevice); fDebugCanvas->drawTo(fCanvas, fIndex);
canvas.translate(fTransform.fX, fTransform.fY); // TODO(chudy): Implement an optional flush button in Gui.
if(fScaleFactor < 0) { fCanvas->flush();
canvas.scale((1.0 / -fScaleFactor),(1.0 / -fScaleFactor));
} else if (fScaleFactor > 0) {
canvas.scale(fScaleFactor, fScaleFactor);
}
fDebugCanvas->drawTo(&canvas, fIndex);
canvas.flush();
} }
GrPlatformRenderTargetDesc SkGLWidget::getDesc(int w, int h) { GrPlatformRenderTargetDesc SkGLWidget::getDesc(int w, int h) {

Просмотреть файл

@ -9,44 +9,40 @@
#include "SkRasterWidget.h" #include "SkRasterWidget.h"
SkRasterWidget::SkRasterWidget(QWidget* parent) : QWidget(parent) { SkRasterWidget::SkRasterWidget() : QWidget() {
fBitmap.setConfig(SkBitmap::kARGB_8888_Config, 800, 800); fBitmap.setConfig(SkBitmap::kARGB_8888_Config, 800, 800);
fBitmap.allocPixels(); fBitmap.allocPixels();
fBitmap.eraseColor(0); fBitmap.eraseColor(0);
fTransform.set(0,0); fTransform.set(0,0);
fScaleFactor = 1.0; fScaleFactor = 1.0;
fIndex = 0; fIndex = 0;
fDevice = NULL; fDevice = new SkDevice(fBitmap);
fDebugCanvas = NULL; fDebugCanvas = NULL;
fCanvas = new SkCanvas(fDevice);
this->setStyleSheet("QWidget {background-color: white; border: 1px solid #cccccc;}"); this->setStyleSheet("QWidget {background-color: white; border: 1px solid #cccccc;}");
} }
SkRasterWidget::~SkRasterWidget() { SkRasterWidget::~SkRasterWidget() {
delete fDevice; SkSafeUnref(fCanvas);
SkSafeUnref(fDevice);
} }
void SkRasterWidget::resizeEvent(QResizeEvent* event) { void SkRasterWidget::resizeEvent(QResizeEvent* event) {
fBitmap.setConfig(SkBitmap::kARGB_8888_Config, event->size().width(), event->size().height()); fBitmap.setConfig(SkBitmap::kARGB_8888_Config, event->size().width(), event->size().height());
fBitmap.allocPixels(); fBitmap.allocPixels();
delete fDevice; SkSafeUnref(fCanvas);
SkSafeUnref(fDevice);
fDevice = new SkDevice(fBitmap); fDevice = new SkDevice(fBitmap);
fCanvas = new SkCanvas(fDevice);
this->update(); this->update();
} }
void SkRasterWidget::paintEvent(QPaintEvent* event) { void SkRasterWidget::paintEvent(QPaintEvent* event) {
if (fDebugCanvas) { if (fDebugCanvas) {
fBitmap.eraseColor(0); fDebugCanvas->drawTo(fCanvas, fIndex);
SkCanvas canvas(fDevice); // TODO(chudy): Refactor into SkDebugCanvas.
canvas.translate(fTransform.fX, fTransform.fY); fMatrix = fCanvas->getTotalMatrix();
if (fScaleFactor < 0) { fClip = fCanvas->getTotalClip().getBounds();
canvas.scale((1.0 / -fScaleFactor), (1.0 / -fScaleFactor));
} else if (fScaleFactor > 0) {
canvas.scale(fScaleFactor, fScaleFactor);
}
fMatrix = canvas.getTotalMatrix();
fClip = canvas.getTotalClip().getBounds();
fDebugCanvas->drawTo(&canvas, fIndex);
QPainter painter(this); QPainter painter(this);
QStyleOption opt; QStyleOption opt;

Просмотреть файл

@ -20,7 +20,7 @@
class SkRasterWidget : public QWidget { class SkRasterWidget : public QWidget {
public: public:
SkRasterWidget(QWidget* parent = NULL); SkRasterWidget();
~SkRasterWidget(); ~SkRasterWidget();
@ -67,6 +67,7 @@ protected:
private: private:
SkBitmap fBitmap; SkBitmap fBitmap;
SkDebugCanvas* fDebugCanvas; SkDebugCanvas* fDebugCanvas;
SkCanvas* fCanvas;
SkDevice* fDevice; SkDevice* fDevice;
SkMatrix fMatrix; SkMatrix fMatrix;

Просмотреть файл

@ -18,6 +18,9 @@ SkDebugCanvas::SkDebugCanvas(int width, int height) {
fBm.setConfig(SkBitmap::kNo_Config, fWidth, fHeight); fBm.setConfig(SkBitmap::kNo_Config, fWidth, fHeight);
this->setBitmapDevice(fBm); this->setBitmapDevice(fBm);
fFilter = false; fFilter = false;
fIndex = 0;
fUserOffset.set(0,0);
fUserScale = 1.0;
} }
SkDebugCanvas::~SkDebugCanvas() {} SkDebugCanvas::~SkDebugCanvas() {}
@ -34,21 +37,26 @@ void SkDebugCanvas::draw(SkCanvas* canvas) {
} }
} }
} }
fIndex = commandVector.size() - 1;
} }
int SkDebugCanvas::getCommandAtPoint(int x, int y, int index, void SkDebugCanvas::applyUserTransform(SkCanvas* canvas) {
SkIPoint transform, float scale) { canvas->translate(fUserOffset.fX, fUserOffset.fY);
if (fUserScale < 0) {
canvas->scale((1.0 / -fUserScale), (1.0 / -fUserScale));
} else if (fUserScale > 0) {
canvas->scale(fUserScale, fUserScale);
}
}
int SkDebugCanvas::getCommandAtPoint(int x, int y, int index) {
SkBitmap bitmap; SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1); bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
bitmap.allocPixels(); bitmap.allocPixels();
SkCanvas canvas(bitmap); SkCanvas canvas(bitmap);
canvas.translate(transform.fX - x, transform.fY - y); canvas.translate(-x, -y);
if (scale < 0) { applyUserTransform(&canvas);
canvas.scale((1.0 / -scale), (1.0 / -scale));
} else if (scale > 0) {
canvas.scale(scale, scale);
}
int layer = 0; int layer = 0;
SkColor prev = bitmap.getColor(0,0); SkColor prev = bitmap.getColor(0,0);
@ -68,7 +76,21 @@ void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
int counter = 0; int counter = 0;
SkASSERT(!commandVector.empty()); SkASSERT(!commandVector.empty());
SkASSERT(index < (int)commandVector.size()); SkASSERT(index < (int)commandVector.size());
for (int i = 0; i <= index; i++) { int i;
// This only works assuming the canvas and device are the same ones that
// were previously drawn into because they need to preserve all saves
// and restores.
if (fIndex < index) {
i = fIndex + 1;
} else {
i = 0;
canvas->clear(0);
canvas->resetMatrix();
applyUserTransform(canvas);
}
for (; i <= index; i++) {
if (i == index && fFilter) { if (i == index && fFilter) {
SkPaint p; SkPaint p;
p.setColor(0xAAFFFFFF); p.setColor(0xAAFFFFFF);
@ -87,6 +109,8 @@ void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
commandVector[i]->execute(canvas); commandVector[i]->execute(canvas);
} }
} }
fIndex = index;
} }
SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) { SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) {

Просмотреть файл

@ -47,8 +47,7 @@ public:
/** /**
Returns the index of the last draw command to write to the pixel at (x,y) Returns the index of the last draw command to write to the pixel at (x,y)
*/ */
int getCommandAtPoint(int x, int y, int index, int getCommandAtPoint(int x, int y, int index);
SkIPoint transform, float scale);
/** /**
Returns the draw command at the given index. Returns the draw command at the given index.
@ -96,6 +95,14 @@ public:
fHeight = height; fHeight = height;
} }
void setUserOffset(SkIPoint offset) {
fUserOffset = offset;
}
void setUserScale(float scale) {
fUserScale = scale;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Inherited from SkCanvas // Inherited from SkCanvas
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -181,12 +188,21 @@ private:
int fWidth; int fWidth;
SkBitmap fBm; SkBitmap fBm;
bool fFilter; bool fFilter;
int fIndex;
SkIPoint fUserOffset;
float fUserScale;
/** /**
Adds the command to the classes vector of commands. Adds the command to the classes vector of commands.
@param command The draw command for execution @param command The draw command for execution
*/ */
void addDrawCommand(SkDrawCommand* command); void addDrawCommand(SkDrawCommand* command);
/**
Applies any panning and zooming the user has specified before
drawing anything else into the canvas.
*/
void applyUserTransform(SkCanvas* canvas);
}; };
#endif #endif