Implemented power of two tiling.
Review URL: https://codereview.appspot.com/6485056 git-svn-id: http://skia.googlecode.com/svn/trunk@5274 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
ac4b86cdcf
commit
f4959ab118
@ -336,6 +336,12 @@ static inline SkScalar SkScalarInterp(SkScalar A, SkScalar B, SkScalar t) {
|
||||
return A + SkScalarMul(B - A, t);
|
||||
}
|
||||
|
||||
static inline SkScalar SkScalarLog2(SkScalar x) {
|
||||
static const SkScalar log2_conversion_factor = SkScalarDiv(1, SkScalarLog(2));
|
||||
|
||||
return SkScalarMul(SkScalarLog(x), log2_conversion_factor);
|
||||
}
|
||||
|
||||
/** Interpolate along the function described by (keys[length], values[length])
|
||||
for the passed searchKey. SearchKeys outside the range keys[0]-keys[Length]
|
||||
clamp to the min or max value. This function was inspired by a desire
|
||||
|
@ -189,8 +189,14 @@ void TiledPictureBenchmark::run(SkPicture* pict) {
|
||||
}
|
||||
|
||||
SkString result;
|
||||
result.printf("%i_tiles_%ix%i: msecs = %6.2f", fRenderer.numTiles(), fRenderer.getTileWidth(),
|
||||
fRenderer.getTileHeight(), wall_time / fRepeats);
|
||||
if (fRenderer.getTileMinPowerOf2Width() > 0) {
|
||||
result.printf("%i_pow2tiles_%iminx%i: msecs = %6.2f", fRenderer.numTiles(),
|
||||
fRenderer.getTileMinPowerOf2Width(), fRenderer.getTileHeight(),
|
||||
wall_time / fRepeats);
|
||||
} else {
|
||||
result.printf("%i_tiles_%ix%i: msecs = %6.2f", fRenderer.numTiles(),
|
||||
fRenderer.getTileWidth(), fRenderer.getTileHeight(), wall_time / fRepeats);
|
||||
}
|
||||
#if SK_SUPPORT_GPU
|
||||
if (fRenderer.isUsingGpuDevice()) {
|
||||
result.appendf(" gmsecs = %6.2f", gpu_time / fRepeats);
|
||||
|
@ -117,6 +117,14 @@ public:
|
||||
return fRenderer.getTileHeightPercentage();
|
||||
}
|
||||
|
||||
void setTileMinPowerOf2Width(int width) {
|
||||
fRenderer.setTileMinPowerOf2Width(width);
|
||||
}
|
||||
|
||||
int getTileMinPowerOf2Width() {
|
||||
return fRenderer.getTileMinPowerOf2Width();
|
||||
}
|
||||
|
||||
private:
|
||||
TiledPictureRenderer fRenderer;
|
||||
typedef PictureBenchmark INHERITED;
|
||||
|
@ -175,7 +175,11 @@ void TiledPictureRenderer::init(SkPicture* pict) {
|
||||
fTileHeight = sk_float_ceil2int(float(fTileHeightPercentage * fPicture->height() / 100));
|
||||
}
|
||||
|
||||
this->setupTiles();
|
||||
if (fTileMinPowerOf2Width > 0) {
|
||||
this->setupPowerOf2Tiles();
|
||||
} else {
|
||||
this->setupTiles();
|
||||
}
|
||||
}
|
||||
|
||||
void TiledPictureRenderer::render() {
|
||||
@ -205,8 +209,8 @@ void TiledPictureRenderer::clipTile(SkCanvas* tile) {
|
||||
tile->clipRect(clip);
|
||||
}
|
||||
|
||||
void TiledPictureRenderer::addTile(int tile_x_start, int tile_y_start) {
|
||||
SkCanvas* tile = this->setupCanvas(fTileWidth, fTileHeight);
|
||||
void TiledPictureRenderer::addTile(int tile_x_start, int tile_y_start, int width, int height) {
|
||||
SkCanvas* tile = this->setupCanvas(width, height);
|
||||
|
||||
tile->translate(SkIntToScalar(-tile_x_start), SkIntToScalar(-tile_y_start));
|
||||
this->clipTile(tile);
|
||||
@ -219,7 +223,43 @@ void TiledPictureRenderer::setupTiles() {
|
||||
tile_y_start += fTileHeight) {
|
||||
for (int tile_x_start = 0; tile_x_start < fPicture->width();
|
||||
tile_x_start += fTileWidth) {
|
||||
this->addTile(tile_x_start, tile_y_start);
|
||||
this->addTile(tile_x_start, tile_y_start, fTileWidth, fTileHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The goal of the powers of two tiles is to minimize the amount of wasted tile
|
||||
// space in the width-wise direction and then minimize the number of tiles. The
|
||||
// constraints are that every tile must have a pixel width that is a power of
|
||||
// two and also be of some minimal width (that is also a power of two).
|
||||
//
|
||||
// This is sovled by first taking our picture size and rounding it up to the
|
||||
// multiple of the minimal width. The binary representation of this rounded
|
||||
// value gives us the tiles we need: a bit of value one means we need a tile of
|
||||
// that size.
|
||||
void TiledPictureRenderer::setupPowerOf2Tiles() {
|
||||
int rounded_value = fPicture->width();
|
||||
if (fPicture->width() % fTileMinPowerOf2Width != 0) {
|
||||
rounded_value = fPicture->width() - (fPicture->width() % fTileMinPowerOf2Width)
|
||||
+ fTileMinPowerOf2Width;
|
||||
}
|
||||
|
||||
int num_bits = SkScalarCeilToInt(SkScalarLog2(fPicture->width()));
|
||||
int largest_possible_tile_size = 1 << num_bits;
|
||||
|
||||
// The tile height is constant for a particular picture.
|
||||
for (int tile_y_start = 0; tile_y_start < fPicture->height(); tile_y_start += fTileHeight) {
|
||||
int tile_x_start = 0;
|
||||
int current_width = largest_possible_tile_size;
|
||||
|
||||
while (current_width >= fTileMinPowerOf2Width) {
|
||||
// It is very important this is a bitwise AND.
|
||||
if (current_width & rounded_value) {
|
||||
this->addTile(tile_x_start, tile_y_start, current_width, fTileHeight);
|
||||
tile_x_start += current_width;
|
||||
}
|
||||
|
||||
current_width >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#ifndef PictureRenderer_DEFINED
|
||||
#define PictureRenderer_DEFINED
|
||||
#include "SkMath.h"
|
||||
#include "SkTypes.h"
|
||||
#include "SkTDArray.h"
|
||||
#include "SkRefCnt.h"
|
||||
@ -145,6 +146,19 @@ public:
|
||||
return fTileHeightPercentage;
|
||||
}
|
||||
|
||||
void setTileMinPowerOf2Width(int width) {
|
||||
SkASSERT(SkIsPow2(width) && width > 0);
|
||||
if (!SkIsPow2(width) || width <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
fTileMinPowerOf2Width = width;
|
||||
}
|
||||
|
||||
int getTileMinPowerOf2Width() const {
|
||||
return fTileMinPowerOf2Width;
|
||||
}
|
||||
|
||||
int numTiles() const {
|
||||
return fTiles.count();
|
||||
}
|
||||
@ -159,6 +173,7 @@ private:
|
||||
int fTileHeight;
|
||||
double fTileWidthPercentage;
|
||||
double fTileHeightPercentage;
|
||||
int fTileMinPowerOf2Width;
|
||||
|
||||
SkTDArray<SkCanvas*> fTiles;
|
||||
|
||||
@ -167,8 +182,9 @@ private:
|
||||
// as they may go over this area and the picture may have some commands that
|
||||
// draw outside of this area and so should not actually be written.
|
||||
void clipTile(SkCanvas* tile);
|
||||
void addTile(int tile_x_start, int tile_y_start);
|
||||
void addTile(int tile_x_start, int tile_y_start, int width, int height);
|
||||
void setupTiles();
|
||||
void setupPowerOf2Tiles();
|
||||
void deleteTiles();
|
||||
void copyTilesToCanvas();
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "BenchTimer.h"
|
||||
#include "PictureBenchmark.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkMath.h"
|
||||
#include "SkOSFile.h"
|
||||
#include "SkPicture.h"
|
||||
#include "SkStream.h"
|
||||
@ -22,7 +23,8 @@ static void usage(const char* argv0) {
|
||||
"Usage: \n"
|
||||
" %s <inputDir>...\n"
|
||||
" [--repeat] \n"
|
||||
" [--mode pipe | record | simple | tile width[%] height[%] | unflatten]\n"
|
||||
" [--mode pipe | pow2tile minWidth height[%] | record | simple\n"
|
||||
" | tile width[%] height[%] | unflatten]\n"
|
||||
" [--device bitmap"
|
||||
#if SK_SUPPORT_GPU
|
||||
" | gpu"
|
||||
@ -34,11 +36,22 @@ static void usage(const char* argv0) {
|
||||
" inputDir: A list of directories and files to use as input. Files are\n"
|
||||
" expected to have the .skp extension.\n\n");
|
||||
SkDebugf(
|
||||
" --mode pipe | record | simple | tile width[%] height[%] | unflatten: Run\n"
|
||||
" in the corresponding mode. Default is simple.\n");
|
||||
" --mode pipe | pow2tile minWidht height[%] | record | simple\n"
|
||||
" | tile width[%] height[%] | unflatten: Run in the corresponding mode.\n"
|
||||
" Default is simple.\n");
|
||||
SkDebugf(
|
||||
" pipe, Benchmark SkGPipe rendering.\n");
|
||||
SkDebugf(
|
||||
" pow2tile minWidth height[%], Creates tiles with widths\n"
|
||||
" that are all a power of two\n"
|
||||
" such that they minimize the\n"
|
||||
" amount of wasted tile space.\n"
|
||||
" minWidth is the minimum width\n"
|
||||
" of these tiles and must be a\n"
|
||||
" power of two. Simple\n"
|
||||
" rendering using these tiles\n"
|
||||
" is benchmarked.\n");
|
||||
SkDebugf(
|
||||
" record, Benchmark picture to picture recording.\n");
|
||||
SkDebugf(
|
||||
" simple, Benchmark a simple rendering.\n");
|
||||
@ -131,29 +144,47 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
|
||||
benchmark = SkNEW(sk_tools::RecordPictureBenchmark);
|
||||
} else if (0 == strcmp(*argv, "simple")) {
|
||||
benchmark = SkNEW(sk_tools::SimplePictureBenchmark);
|
||||
} else if (0 == strcmp(*argv, "tile")) {
|
||||
} else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))) {
|
||||
char* mode = *argv;
|
||||
bool isPowerOf2Mode = false;
|
||||
|
||||
if (0 == strcmp(*argv, "pow2tile")) {
|
||||
isPowerOf2Mode = true;
|
||||
}
|
||||
|
||||
sk_tools::TiledPictureBenchmark* tileBenchmark =
|
||||
SkNEW(sk_tools::TiledPictureBenchmark);
|
||||
++argv;
|
||||
if (argv >= stop) {
|
||||
SkDELETE(tileBenchmark);
|
||||
SkDebugf("Missing width for --mode tile\n");
|
||||
SkDebugf("Missing width for --mode %s\n", mode);
|
||||
usage(argv0);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (sk_tools::is_percentage(*argv)) {
|
||||
if (isPowerOf2Mode) {
|
||||
int minWidth = atoi(*argv);
|
||||
|
||||
if (!SkIsPow2(minWidth) || minWidth <= 0) {
|
||||
SkDELETE(tileBenchmark);
|
||||
SkDebugf("--mode %s must be given a width"
|
||||
" value that is a power of two\n", mode);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
tileBenchmark->setTileMinPowerOf2Width(minWidth);
|
||||
} else if (sk_tools::is_percentage(*argv)) {
|
||||
tileBenchmark->setTileWidthPercentage(atof(*argv));
|
||||
if (!(tileBenchmark->getTileWidthPercentage() > 0)) {
|
||||
SkDELETE(tileBenchmark);
|
||||
SkDebugf("--mode tile must be given a width percentage > 0\n");
|
||||
SkDebugf("--mode %s must be given a width percentage > 0\n", mode);
|
||||
exit(-1);
|
||||
}
|
||||
} else {
|
||||
tileBenchmark->setTileWidth(atoi(*argv));
|
||||
if (!(tileBenchmark->getTileWidth() > 0)) {
|
||||
SkDELETE(tileBenchmark);
|
||||
SkDebugf("--mode tile must be given a width > 0\n");
|
||||
SkDebugf("--mode %s must be given a width > 0\n", mode);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
@ -161,7 +192,7 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
|
||||
++argv;
|
||||
if (argv >= stop) {
|
||||
SkDELETE(tileBenchmark);
|
||||
SkDebugf("Missing height for --mode tile\n");
|
||||
SkDebugf("Missing height for --mode %s\n", mode);
|
||||
usage(argv0);
|
||||
exit(-1);
|
||||
}
|
||||
@ -170,14 +201,14 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
|
||||
tileBenchmark->setTileHeightPercentage(atof(*argv));
|
||||
if (!(tileBenchmark->getTileHeightPercentage() > 0)) {
|
||||
SkDELETE(tileBenchmark);
|
||||
SkDebugf("--mode tile must be given a height percentage > 0\n");
|
||||
SkDebugf("--mode %s must be given a height percentage > 0\n", mode);
|
||||
exit(-1);
|
||||
}
|
||||
} else {
|
||||
tileBenchmark->setTileHeight(atoi(*argv));
|
||||
if (!(tileBenchmark->getTileHeight() > 0)) {
|
||||
SkDELETE(tileBenchmark);
|
||||
SkDebugf("--mode tile must be given a height > 0\n");
|
||||
SkDebugf("--mode %s must be given a height > 0\n", mode);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "SkBitmap.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkDevice.h"
|
||||
#include "SkMath.h"
|
||||
#include "SkOSFile.h"
|
||||
#include "SkPicture.h"
|
||||
#include "SkStream.h"
|
||||
@ -21,7 +22,8 @@ static void usage(const char* argv0) {
|
||||
SkDebugf("\n"
|
||||
"Usage: \n"
|
||||
" %s <input>... <outputDir> \n"
|
||||
" [--mode pipe | simple | tile width[%] height[%]]\n"
|
||||
" [--mode pipe | pow2tile minWidth height[%] | simple\n"
|
||||
" | tile width[%] height[%]]\n"
|
||||
" [--device bitmap"
|
||||
#if SK_SUPPORT_GPU
|
||||
" | gpu"
|
||||
@ -35,11 +37,21 @@ static void usage(const char* argv0) {
|
||||
SkDebugf(
|
||||
" outputDir: directory to write the rendered images.\n\n");
|
||||
SkDebugf(
|
||||
" --mode pipe | simple | tile width[%] height[%]: Run in the\n"
|
||||
" corresponding mode. Default is simple.\n");
|
||||
" --mode pipe | pow2tile minWidth height[%] | simple\n"
|
||||
" | tile width[%] height[%]: Run in the corresponding mode.\n"
|
||||
" Default is simple.\n");
|
||||
SkDebugf(
|
||||
" pipe, Render using a SkGPipe.\n");
|
||||
SkDebugf(
|
||||
" pow2tile minWidth height[%], Creates tiles with widths\n"
|
||||
" that are all a power of two\n"
|
||||
" such that they minimize the\n"
|
||||
" amount of wasted tile space.\n"
|
||||
" minWidth is the minimum width\n"
|
||||
" of these tiles and must be a\n"
|
||||
" power of two. A simple render\n"
|
||||
" is done with these tiles.\n");
|
||||
SkDebugf(
|
||||
" simple, Render using the default rendering method.\n");
|
||||
SkDebugf(
|
||||
" tile width[%] height[%], Do a simple render using tiles\n"
|
||||
@ -139,29 +151,47 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
|
||||
renderer = SkNEW(sk_tools::PipePictureRenderer);
|
||||
} else if (0 == strcmp(*argv, "simple")) {
|
||||
renderer = SkNEW(sk_tools::SimplePictureRenderer);
|
||||
} else if (0 == strcmp(*argv, "tile")) {
|
||||
} else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))) {
|
||||
char* mode = *argv;
|
||||
bool isPowerOf2Mode = false;
|
||||
|
||||
if (0 == strcmp(*argv, "pow2tile")) {
|
||||
isPowerOf2Mode = true;
|
||||
}
|
||||
|
||||
sk_tools::TiledPictureRenderer* tileRenderer =
|
||||
SkNEW(sk_tools::TiledPictureRenderer);
|
||||
++argv;
|
||||
if (argv >= stop) {
|
||||
SkDELETE(tileRenderer);
|
||||
SkDebugf("Missing width for --mode tile\n");
|
||||
SkDebugf("Missing width for --mode %s\n", mode);
|
||||
usage(argv0);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (sk_tools::is_percentage(*argv)) {
|
||||
if (isPowerOf2Mode) {
|
||||
int minWidth = atoi(*argv);
|
||||
|
||||
if (!SkIsPow2(minWidth) || minWidth <= 0) {
|
||||
SkDELETE(tileRenderer);
|
||||
SkDebugf("--mode %s must be given a width"
|
||||
" value that is a power of two\n", mode);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
tileRenderer->setTileMinPowerOf2Width(minWidth);
|
||||
} else if (sk_tools::is_percentage(*argv)) {
|
||||
tileRenderer->setTileWidthPercentage(atof(*argv));
|
||||
if (!(tileRenderer->getTileWidthPercentage() > 0)) {
|
||||
SkDELETE(tileRenderer);
|
||||
SkDebugf("--mode tile must be given a width percentage > 0\n");
|
||||
SkDebugf("--mode %s must be given a width percentage > 0\n", mode);
|
||||
exit(-1);
|
||||
}
|
||||
} else {
|
||||
tileRenderer->setTileWidth(atoi(*argv));
|
||||
if (!(tileRenderer->getTileWidth() > 0)) {
|
||||
SkDELETE(tileRenderer);
|
||||
SkDebugf("--mode tile must be given a width > 0\n");
|
||||
SkDebugf("--mode %s must be given a width > 0\n", mode);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
@ -169,7 +199,7 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
|
||||
++argv;
|
||||
if (argv >= stop) {
|
||||
SkDELETE(tileRenderer);
|
||||
SkDebugf("Missing height for --mode tile\n");
|
||||
SkDebugf("Missing height for --mode %s\n", mode);
|
||||
usage(argv0);
|
||||
exit(-1);
|
||||
}
|
||||
@ -179,14 +209,14 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
|
||||
if (!(tileRenderer->getTileHeightPercentage() > 0)) {
|
||||
SkDELETE(tileRenderer);
|
||||
SkDebugf(
|
||||
"--mode tile must be given a height percentage > 0\n");
|
||||
"--mode %s must be given a height percentage > 0\n", mode);
|
||||
exit(-1);
|
||||
}
|
||||
} else {
|
||||
tileRenderer->setTileHeight(atoi(*argv));
|
||||
if (!(tileRenderer->getTileHeight() > 0)) {
|
||||
SkDELETE(tileRenderer);
|
||||
SkDebugf("--mode tile must be given a height > 0\n");
|
||||
SkDebugf("--mode %s must be given a height > 0\n", mode);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user