remove SkThreadedBMPDevice and friends
It is unused, is becoming a maintainence burden and source of bugs, and takes up a lot of time on the *SAN bots. Change-Id: If383eb6e4838ca23140f9e16d518b1bfc655fa12 Reviewed-on: https://skia-review.googlesource.com/143307 Auto-Submit: Mike Klein <mtklein@google.com> Commit-Queue: Herb Derby <herb@google.com> Reviewed-by: Herb Derby <herb@google.com>
This commit is contained in:
parent
1c94a8fabe
commit
48b649060c
@ -906,7 +906,6 @@ static Sink* create_sink(const GrContextOptions& grCtxOptions, const SkCommandLi
|
||||
SINK("rgbx", RasterSink, kRGB_888x_SkColorType);
|
||||
SINK("1010102", RasterSink, kRGBA_1010102_SkColorType);
|
||||
SINK("101010x", RasterSink, kRGB_101010x_SkColorType);
|
||||
SINK("t8888", ThreadedSink, kN32_SkColorType);
|
||||
SINK("pdf", PDFSink, false, SK_ScalarDefaultRasterDPI);
|
||||
SINK("skp", SKPSink);
|
||||
SINK("pipe", PipeSink);
|
||||
|
@ -56,11 +56,11 @@
|
||||
#include "SkRecordDraw.h"
|
||||
#include "SkRecorder.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkSurface.h"
|
||||
#include "SkSurfaceCharacterization.h"
|
||||
#include "SkSwizzler.h"
|
||||
#include "SkTLogic.h"
|
||||
#include "SkTaskGroup.h"
|
||||
#include "SkThreadedBMPDevice.h"
|
||||
#if defined(SK_BUILD_FOR_WIN)
|
||||
#include "SkAutoCoInitialize.h"
|
||||
#include "SkHRESULT.h"
|
||||
@ -1804,7 +1804,7 @@ RasterSink::RasterSink(SkColorType colorType, sk_sp<SkColorSpace> colorSpace)
|
||||
: fColorType(colorType)
|
||||
, fColorSpace(std::move(colorSpace)) {}
|
||||
|
||||
void RasterSink::allocPixels(const Src& src, SkBitmap* dst) const {
|
||||
Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
|
||||
const SkISize size = src.size();
|
||||
// If there's an appropriate alpha type for this color type, use it, otherwise use premul.
|
||||
SkAlphaType alphaType = kPremul_SkAlphaType;
|
||||
@ -1813,42 +1813,13 @@ void RasterSink::allocPixels(const Src& src, SkBitmap* dst) const {
|
||||
dst->allocPixelsFlags(SkImageInfo::Make(size.width(), size.height(),
|
||||
fColorType, alphaType, fColorSpace),
|
||||
SkBitmap::kZeroPixels_AllocFlag);
|
||||
}
|
||||
|
||||
Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
|
||||
this->allocPixels(src, dst);
|
||||
SkCanvas canvas(*dst);
|
||||
return src.draw(&canvas);
|
||||
}
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
ThreadedSink::ThreadedSink(SkColorType colorType, sk_sp<SkColorSpace> colorSpace)
|
||||
: RasterSink(colorType, colorSpace) {}
|
||||
|
||||
Error ThreadedSink::draw(const Src& src, SkBitmap* dst, SkWStream* stream, SkString* str) const {
|
||||
this->allocPixels(src, dst);
|
||||
|
||||
auto canvas = skstd::make_unique<SkCanvas>(
|
||||
sk_make_sp<SkThreadedBMPDevice>(
|
||||
*dst, FLAGS_backendTiles, FLAGS_backendThreads));
|
||||
Error result = src.draw(canvas.get());
|
||||
canvas->flush();
|
||||
return result;
|
||||
|
||||
// ??? yuqian: why does the following give me segmentation fault while the above one works?
|
||||
// The seg fault occurs right in the beginning of ThreadedSink::draw with invalid
|
||||
// memory address (it would crash without even calling this->allocPixels).
|
||||
|
||||
// SkThreadedBMPDevice device(*dst, tileCnt, FLAGS_cpuThreads, fExecutor.get());
|
||||
// SkCanvas canvas(&device);
|
||||
// Error result = src.draw(&canvas);
|
||||
// canvas.flush();
|
||||
// return result;
|
||||
}
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
// Handy for front-patching a Src. Do whatever up-front work you need, then call draw_to_canvas(),
|
||||
// passing the Sink draw() arguments, a size, and a function draws into an SkCanvas.
|
||||
// Several examples below.
|
||||
|
@ -441,9 +441,8 @@ public:
|
||||
Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
|
||||
const char* fileExtension() const override { return "png"; }
|
||||
SinkFlags flags() const override { return SinkFlags{ SinkFlags::kRaster, SinkFlags::kDirect }; }
|
||||
protected:
|
||||
void allocPixels(const Src& src, SkBitmap*) const;
|
||||
|
||||
private:
|
||||
SkColorType fColorType;
|
||||
sk_sp<SkColorSpace> fColorSpace;
|
||||
};
|
||||
|
@ -311,8 +311,6 @@ skia_core_sources = [
|
||||
"$_src/core/SkSRGB.cpp",
|
||||
"$_src/core/SkTaskGroup.cpp",
|
||||
"$_src/core/SkTaskGroup.h",
|
||||
"$_src/core/SkTaskGroup2D.cpp",
|
||||
"$_src/core/SkTaskGroup2D.h",
|
||||
"$_src/core/SkTDPQueue.h",
|
||||
"$_src/core/SkTDynamicHash.h",
|
||||
"$_src/core/SkTextBlob.cpp",
|
||||
@ -322,9 +320,6 @@ skia_core_sources = [
|
||||
"$_src/core/SkTextToPathIter.h",
|
||||
"$_src/core/SkTime.cpp",
|
||||
|
||||
# The Clang's false positive thread warnings have been resolved in SkTaskGroup2D.cpp
|
||||
"$_src/core/SkThreadedBMPDevice.cpp",
|
||||
"$_src/core/SkThreadedBMPDevice.h",
|
||||
"$_src/core/SkThreadID.cpp",
|
||||
"$_src/core/SkTLList.h",
|
||||
"$_src/core/SkTLS.cpp",
|
||||
|
@ -404,7 +404,6 @@
|
||||
"Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-NativeFonts",
|
||||
"Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-SK_USE_DISCARDABLE_SCALEDIMAGECACHE",
|
||||
"Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-SafeStack",
|
||||
"Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-T8888",
|
||||
"Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-Shard_12-Coverage",
|
||||
"Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Release-All",
|
||||
"Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Release-All-ASAN",
|
||||
|
@ -1,278 +0,0 @@
|
||||
[
|
||||
{
|
||||
"cmd": [
|
||||
"python",
|
||||
"-u",
|
||||
"RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
|
||||
"--json-output",
|
||||
"/path/to/tmp/json",
|
||||
"ensure-directory",
|
||||
"--mode",
|
||||
"0777",
|
||||
"[START_DIR]/tmp"
|
||||
],
|
||||
"infra_step": true,
|
||||
"name": "makedirs tmp_dir"
|
||||
},
|
||||
{
|
||||
"cmd": [
|
||||
"python",
|
||||
"-u",
|
||||
"RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
|
||||
"--json-output",
|
||||
"/path/to/tmp/json",
|
||||
"copy",
|
||||
"[START_DIR]/skia/infra/bots/assets/skp/VERSION",
|
||||
"/path/to/tmp/"
|
||||
],
|
||||
"infra_step": true,
|
||||
"name": "Get skp VERSION"
|
||||
},
|
||||
{
|
||||
"cmd": [
|
||||
"python",
|
||||
"-u",
|
||||
"RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
|
||||
"--json-output",
|
||||
"/path/to/tmp/json",
|
||||
"copy",
|
||||
"42",
|
||||
"[START_DIR]/tmp/SKP_VERSION"
|
||||
],
|
||||
"infra_step": true,
|
||||
"name": "write SKP_VERSION"
|
||||
},
|
||||
{
|
||||
"cmd": [
|
||||
"python",
|
||||
"-u",
|
||||
"RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
|
||||
"--json-output",
|
||||
"/path/to/tmp/json",
|
||||
"copy",
|
||||
"[START_DIR]/skia/infra/bots/assets/skimage/VERSION",
|
||||
"/path/to/tmp/"
|
||||
],
|
||||
"infra_step": true,
|
||||
"name": "Get skimage VERSION"
|
||||
},
|
||||
{
|
||||
"cmd": [
|
||||
"python",
|
||||
"-u",
|
||||
"RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
|
||||
"--json-output",
|
||||
"/path/to/tmp/json",
|
||||
"copy",
|
||||
"42",
|
||||
"[START_DIR]/tmp/SK_IMAGE_VERSION"
|
||||
],
|
||||
"infra_step": true,
|
||||
"name": "write SK_IMAGE_VERSION"
|
||||
},
|
||||
{
|
||||
"cmd": [
|
||||
"python",
|
||||
"-u",
|
||||
"RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
|
||||
"--json-output",
|
||||
"/path/to/tmp/json",
|
||||
"copy",
|
||||
"[START_DIR]/skia/infra/bots/assets/svg/VERSION",
|
||||
"/path/to/tmp/"
|
||||
],
|
||||
"infra_step": true,
|
||||
"name": "Get svg VERSION"
|
||||
},
|
||||
{
|
||||
"cmd": [
|
||||
"python",
|
||||
"-u",
|
||||
"RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
|
||||
"--json-output",
|
||||
"/path/to/tmp/json",
|
||||
"copy",
|
||||
"42",
|
||||
"[START_DIR]/tmp/SVG_VERSION"
|
||||
],
|
||||
"infra_step": true,
|
||||
"name": "write SVG_VERSION"
|
||||
},
|
||||
{
|
||||
"cmd": [
|
||||
"python",
|
||||
"-u",
|
||||
"RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
|
||||
"--json-output",
|
||||
"/path/to/tmp/json",
|
||||
"rmtree",
|
||||
"[START_DIR]/test"
|
||||
],
|
||||
"infra_step": true,
|
||||
"name": "rmtree test"
|
||||
},
|
||||
{
|
||||
"cmd": [
|
||||
"python",
|
||||
"-u",
|
||||
"RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
|
||||
"--json-output",
|
||||
"/path/to/tmp/json",
|
||||
"ensure-directory",
|
||||
"--mode",
|
||||
"0777",
|
||||
"[START_DIR]/test"
|
||||
],
|
||||
"infra_step": true,
|
||||
"name": "makedirs test"
|
||||
},
|
||||
{
|
||||
"cmd": [
|
||||
"python",
|
||||
"-u",
|
||||
"\nimport contextlib\nimport math\nimport socket\nimport sys\nimport time\nimport urllib2\n\nHASHES_URL = 'https://storage.googleapis.com/skia-infra-gm/hash_files/gold-prod-hashes.txt'\nRETRIES = 5\nTIMEOUT = 60\nWAIT_BASE = 15\n\nsocket.setdefaulttimeout(TIMEOUT)\nfor retry in range(RETRIES):\n try:\n with contextlib.closing(\n urllib2.urlopen(HASHES_URL, timeout=TIMEOUT)) as w:\n hashes = w.read()\n with open(sys.argv[1], 'w') as f:\n f.write(hashes)\n break\n except Exception as e:\n print 'Failed to get uninteresting hashes from %s:' % HASHES_URL\n print e\n if retry == RETRIES:\n raise\n waittime = WAIT_BASE * math.pow(2, retry)\n print 'Retry in %d seconds.' % waittime\n time.sleep(waittime)\n",
|
||||
"[START_DIR]/tmp/uninteresting_hashes.txt"
|
||||
],
|
||||
"env": {
|
||||
"CHROME_HEADLESS": "1",
|
||||
"PATH": "<PATH>:RECIPE_PACKAGE_REPO[depot_tools]"
|
||||
},
|
||||
"infra_step": true,
|
||||
"name": "get uninteresting hashes",
|
||||
"~followup_annotations": [
|
||||
"@@@STEP_LOG_LINE@python.inline@@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@import contextlib@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@import math@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@import socket@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@import sys@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@import time@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@import urllib2@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@HASHES_URL = 'https://storage.googleapis.com/skia-infra-gm/hash_files/gold-prod-hashes.txt'@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@RETRIES = 5@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@TIMEOUT = 60@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@WAIT_BASE = 15@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@socket.setdefaulttimeout(TIMEOUT)@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@for retry in range(RETRIES):@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@ try:@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@ with contextlib.closing(@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@ urllib2.urlopen(HASHES_URL, timeout=TIMEOUT)) as w:@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@ hashes = w.read()@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@ with open(sys.argv[1], 'w') as f:@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@ f.write(hashes)@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@ break@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@ except Exception as e:@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@ print 'Failed to get uninteresting hashes from %s:' % HASHES_URL@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@ print e@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@ if retry == RETRIES:@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@ raise@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@ waittime = WAIT_BASE * math.pow(2, retry)@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@ print 'Retry in %d seconds.' % waittime@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@ time.sleep(waittime)@@@",
|
||||
"@@@STEP_LOG_END@python.inline@@@"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cmd": [
|
||||
"python",
|
||||
"-u",
|
||||
"import os\nprint os.environ.get('SWARMING_BOT_ID', '')\n"
|
||||
],
|
||||
"name": "get swarming bot id",
|
||||
"stdout": "/path/to/tmp/",
|
||||
"~followup_annotations": [
|
||||
"@@@STEP_LOG_LINE@python.inline@import os@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@print os.environ.get('SWARMING_BOT_ID', '')@@@",
|
||||
"@@@STEP_LOG_END@python.inline@@@"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cmd": [
|
||||
"python",
|
||||
"-u",
|
||||
"import os\nprint os.environ.get('SWARMING_TASK_ID', '')\n"
|
||||
],
|
||||
"name": "get swarming task id",
|
||||
"stdout": "/path/to/tmp/",
|
||||
"~followup_annotations": [
|
||||
"@@@STEP_LOG_LINE@python.inline@import os@@@",
|
||||
"@@@STEP_LOG_LINE@python.inline@print os.environ.get('SWARMING_TASK_ID', '')@@@",
|
||||
"@@@STEP_LOG_END@python.inline@@@"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cmd": [
|
||||
"python",
|
||||
"-u",
|
||||
"RECIPE_MODULE[skia::flavor]/resources/symbolize_stack_trace.py",
|
||||
"[START_DIR]",
|
||||
"catchsegv",
|
||||
"[START_DIR]/build/dm",
|
||||
"--resourcePath",
|
||||
"[START_DIR]/skia/resources",
|
||||
"--skps",
|
||||
"[START_DIR]/skp",
|
||||
"--images",
|
||||
"[START_DIR]/skimage/dm",
|
||||
"--colorImages",
|
||||
"[START_DIR]/skimage/colorspace",
|
||||
"--nameByHash",
|
||||
"--properties",
|
||||
"gitHash",
|
||||
"abc123",
|
||||
"builder",
|
||||
"Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-T8888",
|
||||
"buildbucket_build_id",
|
||||
"123454321",
|
||||
"swarming_bot_id",
|
||||
"skia-bot-123",
|
||||
"swarming_task_id",
|
||||
"123456",
|
||||
"--svgs",
|
||||
"[START_DIR]/svg",
|
||||
"--key",
|
||||
"arch",
|
||||
"x86_64",
|
||||
"compiler",
|
||||
"Clang",
|
||||
"configuration",
|
||||
"Debug",
|
||||
"cpu_or_gpu",
|
||||
"CPU",
|
||||
"cpu_or_gpu_value",
|
||||
"AVX2",
|
||||
"extra_config",
|
||||
"T8888",
|
||||
"model",
|
||||
"GCE",
|
||||
"os",
|
||||
"Debian9",
|
||||
"--uninterestingHashesFile",
|
||||
"[START_DIR]/tmp/uninteresting_hashes.txt",
|
||||
"--writePath",
|
||||
"[START_DIR]/[SWARM_OUT_DIR]",
|
||||
"--dont_write",
|
||||
"pdf",
|
||||
"--randomProcessorTest",
|
||||
"--nogpu",
|
||||
"--config",
|
||||
"t8888",
|
||||
"--src",
|
||||
"gm",
|
||||
"--nonativeFonts",
|
||||
"--verbose"
|
||||
],
|
||||
"cwd": "[START_DIR]/skia",
|
||||
"env": {
|
||||
"CHROME_HEADLESS": "1",
|
||||
"PATH": "<PATH>:RECIPE_PACKAGE_REPO[depot_tools]"
|
||||
},
|
||||
"name": "symbolized dm"
|
||||
},
|
||||
{
|
||||
"name": "$result",
|
||||
"recipe_result": null,
|
||||
"status_code": 0
|
||||
}
|
||||
]
|
@ -126,15 +126,8 @@ def dm_flags(api, bot):
|
||||
configs.extend(['narrow'])
|
||||
configs.extend(['enarrow'])
|
||||
|
||||
# Temporarily disabled while debugging.
|
||||
#if 'SAN' in bot:
|
||||
# configs.extend(['t8888'])
|
||||
|
||||
configs.extend(mode + '-8888' for mode in ['serialize', 'tiles_rt', 'pic'])
|
||||
|
||||
if 'T8888' in bot:
|
||||
configs = ['t8888']
|
||||
|
||||
# This bot only differs from vanilla CPU bots in 8888 config.
|
||||
if 'SK_FORCE_RASTER_PIPELINE_BLITTER' in bot:
|
||||
configs = ['8888']
|
||||
@ -329,11 +322,6 @@ def dm_flags(api, bot):
|
||||
args.remove('image')
|
||||
args.remove('colorImage')
|
||||
|
||||
if 'T8888' in bot:
|
||||
args.remove('tests')
|
||||
args.remove('image')
|
||||
args.remove('colorImage')
|
||||
|
||||
def remove_from_args(arg):
|
||||
if arg in args:
|
||||
args.remove(arg)
|
||||
@ -1045,7 +1033,6 @@ TEST_BUILDERS = [
|
||||
'Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-MSAN',
|
||||
('Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All'
|
||||
'-SK_USE_DISCARDABLE_SCALEDIMAGECACHE'),
|
||||
'Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-T8888',
|
||||
'Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Release-All-Lottie',
|
||||
('Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Release-All'
|
||||
'-SK_FORCE_RASTER_PIPELINE_BLITTER'),
|
||||
|
@ -2038,11 +2038,6 @@
|
||||
"Upload-Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-SafeStack"
|
||||
]
|
||||
},
|
||||
"Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-T8888": {
|
||||
"tasks": [
|
||||
"Upload-Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-T8888"
|
||||
]
|
||||
},
|
||||
"Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-Shard_12-Coverage": {
|
||||
"tasks": [
|
||||
"Upload-Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-Shard_12-Coverage"
|
||||
@ -48294,118 +48289,6 @@
|
||||
"test"
|
||||
]
|
||||
},
|
||||
"Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-T8888": {
|
||||
"caches": [
|
||||
{
|
||||
"name": "vpython",
|
||||
"path": "cache/vpython"
|
||||
}
|
||||
],
|
||||
"cipd_packages": [
|
||||
{
|
||||
"name": "infra/tools/luci/kitchen/${platform}",
|
||||
"path": ".",
|
||||
"version": "git_revision:546aae39f1fb9dce9add528e2011afa574535ecd"
|
||||
},
|
||||
{
|
||||
"name": "infra/tools/luci-auth/${platform}",
|
||||
"path": "cipd_bin_packages",
|
||||
"version": "git_revision:e1abc57be62d198b5c2f487bfb2fa2d2eb0e867c"
|
||||
},
|
||||
{
|
||||
"name": "infra/tools/luci/vpython/${platform}",
|
||||
"path": "cipd_bin_packages",
|
||||
"version": "git_revision:b9c4670197dcefd8762d6e509302acd3efc6e303"
|
||||
},
|
||||
{
|
||||
"name": "skia/bots/skimage",
|
||||
"path": "skimage",
|
||||
"version": "version:34"
|
||||
},
|
||||
{
|
||||
"name": "skia/bots/skp",
|
||||
"path": "skp",
|
||||
"version": "version:135"
|
||||
},
|
||||
{
|
||||
"name": "skia/bots/svg",
|
||||
"path": "svg",
|
||||
"version": "version:9"
|
||||
}
|
||||
],
|
||||
"command": [
|
||||
"./kitchen${EXECUTABLE_SUFFIX}",
|
||||
"cook",
|
||||
"-checkout-dir",
|
||||
"recipe_bundle",
|
||||
"-mode",
|
||||
"swarming",
|
||||
"-luci-system-account",
|
||||
"system",
|
||||
"-cache-dir",
|
||||
"cache",
|
||||
"-temp-dir",
|
||||
"tmp",
|
||||
"-known-gerrit-host",
|
||||
"android.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"boringssl.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"chromium.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"dart.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"fuchsia.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"go.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"llvm.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"skia.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"webrtc.googlesource.com",
|
||||
"-output-result-json",
|
||||
"${ISOLATED_OUTDIR}/build_result_filename",
|
||||
"-workdir",
|
||||
".",
|
||||
"-recipe",
|
||||
"test",
|
||||
"-properties",
|
||||
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-T8888\",\"patch_issue\":\"<(ISSUE)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"revision\":\"<(REVISION)\",\"swarm_out_dir\":\"test\"}",
|
||||
"-logdog-annotation-url",
|
||||
"logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations"
|
||||
],
|
||||
"dependencies": [
|
||||
"Housekeeper-PerCommit-BundleRecipes",
|
||||
"Build-Debian9-Clang-x86_64-Debug"
|
||||
],
|
||||
"dimensions": [
|
||||
"cpu:x86-64-Haswell_GCE",
|
||||
"machine_type:n1-standard-16",
|
||||
"os:Debian-9.4",
|
||||
"pool:Skia"
|
||||
],
|
||||
"env_prefixes": {
|
||||
"PATH": [
|
||||
"cipd_bin_packages",
|
||||
"cipd_bin_packages/bin"
|
||||
],
|
||||
"VPYTHON_VIRTUALENV_ROOT": [
|
||||
"${cache_dir}/vpython"
|
||||
]
|
||||
},
|
||||
"execution_timeout_ns": 14400000000000,
|
||||
"expiration_ns": 72000000000000,
|
||||
"extra_tags": {
|
||||
"log_location": "logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations"
|
||||
},
|
||||
"io_timeout_ns": 14400000000000,
|
||||
"isolate": "test_skia_bundled.isolate",
|
||||
"max_attempts": 1,
|
||||
"outputs": [
|
||||
"test"
|
||||
]
|
||||
},
|
||||
"Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-shard_00_12-Coverage": {
|
||||
"caches": [
|
||||
{
|
||||
@ -87690,105 +87573,6 @@
|
||||
"isolate": "swarm_recipe.isolate",
|
||||
"service_account": "skia-external-gm-uploader@skia-swarming-bots.iam.gserviceaccount.com"
|
||||
},
|
||||
"Upload-Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-T8888": {
|
||||
"caches": [
|
||||
{
|
||||
"name": "vpython",
|
||||
"path": "cache/vpython"
|
||||
}
|
||||
],
|
||||
"cipd_packages": [
|
||||
{
|
||||
"name": "infra/tools/luci/kitchen/${platform}",
|
||||
"path": ".",
|
||||
"version": "git_revision:546aae39f1fb9dce9add528e2011afa574535ecd"
|
||||
},
|
||||
{
|
||||
"name": "infra/tools/luci-auth/${platform}",
|
||||
"path": "cipd_bin_packages",
|
||||
"version": "git_revision:e1abc57be62d198b5c2f487bfb2fa2d2eb0e867c"
|
||||
},
|
||||
{
|
||||
"name": "infra/tools/luci/vpython/${platform}",
|
||||
"path": "cipd_bin_packages",
|
||||
"version": "git_revision:b9c4670197dcefd8762d6e509302acd3efc6e303"
|
||||
},
|
||||
{
|
||||
"name": "infra/gsutil",
|
||||
"path": "cipd_bin_packages",
|
||||
"version": "version:4.28"
|
||||
}
|
||||
],
|
||||
"command": [
|
||||
"./kitchen${EXECUTABLE_SUFFIX}",
|
||||
"cook",
|
||||
"-checkout-dir",
|
||||
"recipe_bundle",
|
||||
"-mode",
|
||||
"swarming",
|
||||
"-luci-system-account",
|
||||
"system",
|
||||
"-cache-dir",
|
||||
"cache",
|
||||
"-temp-dir",
|
||||
"tmp",
|
||||
"-known-gerrit-host",
|
||||
"android.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"boringssl.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"chromium.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"dart.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"fuchsia.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"go.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"llvm.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"skia.googlesource.com",
|
||||
"-known-gerrit-host",
|
||||
"webrtc.googlesource.com",
|
||||
"-output-result-json",
|
||||
"${ISOLATED_OUTDIR}/build_result_filename",
|
||||
"-workdir",
|
||||
".",
|
||||
"-recipe",
|
||||
"upload_dm_results",
|
||||
"-properties",
|
||||
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-T8888\",\"gs_bucket\":\"skia-infra-gm\",\"patch_issue\":\"<(ISSUE)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"revision\":\"<(REVISION)\",\"swarm_out_dir\":\"output_ignored\"}",
|
||||
"-logdog-annotation-url",
|
||||
"logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations"
|
||||
],
|
||||
"dependencies": [
|
||||
"Housekeeper-PerCommit-BundleRecipes",
|
||||
"Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-T8888"
|
||||
],
|
||||
"dimensions": [
|
||||
"cpu:x86-64-Haswell_GCE",
|
||||
"gpu:none",
|
||||
"machine_type:n1-highmem-2",
|
||||
"os:Debian-9.4",
|
||||
"pool:Skia"
|
||||
],
|
||||
"env_prefixes": {
|
||||
"PATH": [
|
||||
"cipd_bin_packages",
|
||||
"cipd_bin_packages/bin"
|
||||
],
|
||||
"VPYTHON_VIRTUALENV_ROOT": [
|
||||
"${cache_dir}/vpython"
|
||||
]
|
||||
},
|
||||
"execution_timeout_ns": 3600000000000,
|
||||
"extra_tags": {
|
||||
"log_location": "logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations"
|
||||
},
|
||||
"io_timeout_ns": 3600000000000,
|
||||
"isolate": "swarm_recipe.isolate",
|
||||
"service_account": "skia-external-gm-uploader@skia-swarming-bots.iam.gserviceaccount.com"
|
||||
},
|
||||
"Upload-Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-Shard_12-Coverage": {
|
||||
"caches": [
|
||||
{
|
||||
|
@ -155,7 +155,6 @@ private:
|
||||
friend class SkDrawTiler;
|
||||
friend class SkDeviceFilteredPaint;
|
||||
friend class SkSurface_Raster;
|
||||
friend class SkThreadedBMPDevice; // to copy fRCStack
|
||||
|
||||
class BDDraw;
|
||||
|
||||
|
@ -35,7 +35,6 @@
|
||||
#include "SkTLazy.h"
|
||||
#include "SkTemplates.h"
|
||||
#include "SkTextMapStateProc.h"
|
||||
#include "SkThreadedBMPDevice.h"
|
||||
#include "SkTo.h"
|
||||
#include "SkUtils.h"
|
||||
|
||||
@ -957,11 +956,8 @@ SkScalar SkDraw::ComputeResScaleForStroking(const SkMatrix& matrix) {
|
||||
}
|
||||
|
||||
void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage,
|
||||
SkBlitter* customBlitter, bool doFill, SkInitOnceData* iData) const {
|
||||
SkBlitter* customBlitter, bool doFill) const {
|
||||
if (SkPathPriv::TooBigForMath(devPath)) {
|
||||
if (iData) {
|
||||
iData->setEmptyDrawFn();
|
||||
}
|
||||
return;
|
||||
}
|
||||
SkBlitter* blitter = nullptr;
|
||||
@ -976,9 +972,6 @@ void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawC
|
||||
SkStrokeRec::InitStyle style = doFill ? SkStrokeRec::kFill_InitStyle
|
||||
: SkStrokeRec::kHairline_InitStyle;
|
||||
if (as_MFB(paint.getMaskFilter())->filterPath(devPath, *fMatrix, *fRC, blitter, style)) {
|
||||
if (iData) {
|
||||
iData->setEmptyDrawFn();
|
||||
}
|
||||
return; // filterPath() called the blitter, so we're done
|
||||
}
|
||||
}
|
||||
@ -1024,48 +1017,16 @@ void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawC
|
||||
}
|
||||
}
|
||||
|
||||
if (iData == nullptr) {
|
||||
proc(devPath, *fRC, blitter); // proceed directly if we're not in threaded init-once
|
||||
} else if (!doFill || !paint.isAntiAlias()) {
|
||||
// We're in threaded init-once but we can't use DAA. Hence we'll stop here and hand all the
|
||||
// remaining work to draw phase. This is a simple example of how to add init-once to
|
||||
// existing drawXXX commands: simply send in SkInitOnceData, do as much init work as
|
||||
// possible, and finally wrap the remaining work into iData->fElement->fDrawFn.
|
||||
SkASSERT(customBlitter == nullptr);
|
||||
devPath.updateBoundsCache(); // make it thread safe
|
||||
iData->fElement->setDrawFn([proc, devPath, paint, drawCoverage](SkArenaAlloc* alloc,
|
||||
const SkThreadedBMPDevice::DrawState& ds, const SkIRect& tileBounds) {
|
||||
SkThreadedBMPDevice::TileDraw tileDraw(ds, tileBounds);
|
||||
SkAutoBlitterChoose blitterStorage(tileDraw, nullptr, paint, drawCoverage);
|
||||
proc(devPath, *tileDraw.fRC, blitterStorage.get());
|
||||
});
|
||||
} else {
|
||||
// We can use DAA to do scan conversion in the init-once phase.
|
||||
SkDAARecord* record = iData->fAlloc->make<SkDAARecord>(iData->fAlloc);
|
||||
SkNullBlitter nullBlitter; // We don't want to blit anything during the init phase
|
||||
SkScan::AntiFillPath(devPath, *fRC, &nullBlitter, record);
|
||||
SkASSERT(customBlitter == nullptr);
|
||||
iData->fElement->setDrawFn([record, devPath, paint, drawCoverage](SkArenaAlloc* alloc,
|
||||
const SkThreadedBMPDevice::DrawState& ds, const SkIRect& tileBounds) {
|
||||
SkASSERT(record->fType != SkDAARecord::Type::kToBeComputed);
|
||||
SkThreadedBMPDevice::TileDraw tileDraw(ds, tileBounds);
|
||||
SkAutoBlitterChoose blitterStorage(tileDraw, nullptr, paint, drawCoverage);
|
||||
SkScan::AntiFillPath(devPath, *tileDraw.fRC, blitterStorage.get(), record);
|
||||
});
|
||||
}
|
||||
proc(devPath, *fRC, blitter);
|
||||
}
|
||||
|
||||
void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
|
||||
const SkMatrix* prePathMatrix, bool pathIsMutable,
|
||||
bool drawCoverage, SkBlitter* customBlitter,
|
||||
SkInitOnceData* iData) const {
|
||||
bool drawCoverage, SkBlitter* customBlitter) const {
|
||||
SkDEBUGCODE(this->validate();)
|
||||
|
||||
// nothing to draw
|
||||
if (fRC->isEmpty()) {
|
||||
if (iData) {
|
||||
iData->setEmptyDrawFn();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1075,9 +1036,6 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
|
||||
SkPath* tmpPath = &tmpPathStorage;
|
||||
SkMatrix tmpMatrix;
|
||||
const SkMatrix* matrix = fMatrix;
|
||||
if (iData) {
|
||||
tmpPath = iData->fAlloc->make<SkPath>();
|
||||
}
|
||||
tmpPath->setIsVolatile(true);
|
||||
SkPathPriv::SetIsBadForDAA(*tmpPath, SkPathPriv::IsBadForDAA(origSrcPath));
|
||||
|
||||
@ -1142,7 +1100,7 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
|
||||
// transform the path into device space
|
||||
pathPtr->transform(*matrix, devPathPtr);
|
||||
|
||||
this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill, iData);
|
||||
this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill);
|
||||
}
|
||||
|
||||
void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkPaint& paint) const {
|
||||
|
@ -31,7 +31,6 @@ class SkRasterClip;
|
||||
struct SkDrawProcs;
|
||||
struct SkRect;
|
||||
class SkRRect;
|
||||
struct SkInitOnceData;
|
||||
|
||||
class SkDraw {
|
||||
public:
|
||||
@ -137,11 +136,11 @@ private:
|
||||
|
||||
void drawPath(const SkPath&, const SkPaint&, const SkMatrix* preMatrix,
|
||||
bool pathIsMutable, bool drawCoverage,
|
||||
SkBlitter* customBlitter = nullptr, SkInitOnceData* iData = nullptr) const;
|
||||
SkBlitter* customBlitter = nullptr) const;
|
||||
|
||||
void drawLine(const SkPoint[2], const SkPaint&) const;
|
||||
void drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage,
|
||||
SkBlitter* customBlitter, bool doFill, SkInitOnceData* iData = nullptr) const;
|
||||
SkBlitter* customBlitter, bool doFill) const;
|
||||
/**
|
||||
* Return the current clip bounds, in local coordinates, with slop to account
|
||||
* for antialiasing or hairlines (i.e. device-bounds outset by 1, and then
|
||||
@ -169,8 +168,6 @@ public:
|
||||
#else
|
||||
void validate() const {}
|
||||
#endif
|
||||
|
||||
friend class SkThreadedBMPDevice; // to access private method drawPath
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkTaskGroup2D.h"
|
||||
|
||||
void SkTaskGroup2D::start() {
|
||||
fThreadsGroup->batch(fThreadCnt, [this](int threadId){
|
||||
this->work(threadId);
|
||||
});
|
||||
}
|
||||
|
||||
void SkTaskGroup2D::addColumn() {
|
||||
SkASSERT(!fIsFinishing); // we're not supposed to add more work after the calling of finish
|
||||
fWidth++;
|
||||
}
|
||||
|
||||
void SkTaskGroup2D::finish() {
|
||||
fIsFinishing = true;
|
||||
fThreadsGroup->wait();
|
||||
}
|
||||
|
||||
void SkSpinningTaskGroup2D::work(int threadId) {
|
||||
int workCol = 0;
|
||||
int initCol = 0;
|
||||
|
||||
while (true) {
|
||||
SkASSERT(workCol <= fWidth);
|
||||
if (this->isFinishing() && workCol >= fWidth) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note that row = threadId
|
||||
if (workCol < fWidth && fKernel->work2D(threadId, workCol, threadId)) {
|
||||
workCol++;
|
||||
} else {
|
||||
// Initialize something if we can't work
|
||||
this->initAnUninitializedColumn(initCol, threadId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkFlexibleTaskGroup2D::work(int threadId) {
|
||||
int row = threadId;
|
||||
int initCol = 0;
|
||||
int numRowsCompleted = 0;
|
||||
std::vector<bool> completedRows(fHeight, false);
|
||||
|
||||
// Only keep fHeight - numRowsCompleted number of threads looping. When rows are about to
|
||||
// complete, this strategy keeps the contention low.
|
||||
while (threadId < fHeight - numRowsCompleted) {
|
||||
RowData& rowData = fRowData[row];
|
||||
|
||||
// The Android roller somehow gets a false-positive compile warning/error about the try-lock
|
||||
// and unlock process. Hence we disable -Wthread-safety-analysis to bypass it.
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wthread-safety-analysis"
|
||||
#endif
|
||||
if (rowData.fMutex.try_lock()) {
|
||||
while (rowData.fNextColumn < fWidth &&
|
||||
fKernel->work2D(row, rowData.fNextColumn, threadId)) {
|
||||
rowData.fNextColumn++;
|
||||
}
|
||||
// isFinishing can never go from true to false. Once it's true, we count how many rows
|
||||
// are completed (out of work). If that count reaches fHeight, then we're out of work
|
||||
// for the whole group and we can stop.
|
||||
if (rowData.fNextColumn == fWidth && this->isFinishing()) {
|
||||
numRowsCompleted += (completedRows[row] == false);
|
||||
completedRows[row] = true; // so we won't count this row twice
|
||||
}
|
||||
rowData.fMutex.unlock();
|
||||
}
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
// By reaching here, we're either unable to acquire the row, or out of work, or blocked by
|
||||
// initialization
|
||||
row = (row + 1) % fHeight; // Move to the next row
|
||||
this->initAnUninitializedColumn(initCol, threadId); // Initialize something
|
||||
}
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkTaskGroup2D_DEFINED
|
||||
#define SkTaskGroup2D_DEFINED
|
||||
|
||||
#include "SkTaskGroup.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
// The interface for doing work on a 2D grid with possible initialization on columns.
|
||||
class SkWorkKernel2D {
|
||||
public:
|
||||
// Return false iff the column needs initialization and such initialization is not finished yet.
|
||||
virtual bool work2D(int row, int column, int thread) = 0;
|
||||
|
||||
// Return false if no initialization is done for this colum (e.g., it's already initialized; or
|
||||
// maybe some other thread is initializing the column).
|
||||
virtual bool initColumn(int column, int thread) = 0;
|
||||
|
||||
virtual ~SkWorkKernel2D() {}
|
||||
};
|
||||
|
||||
// A 2D grid (height rows x width columns) of tasks to be executed on a given executor with
|
||||
// threadCnt number of threads.
|
||||
//
|
||||
// The height (number of rows) is fixed. The width (number of columns) may be dynamically expanded.
|
||||
//
|
||||
// The task on row i and column j is abstracted as work2D(i, j, t). Parameter t is the thread id and
|
||||
// it shouldn't affect the work to be done. It's only used to allow some variables that are not
|
||||
// thread safe and should be used exclusively by one thread (e.g., thread allocators). We guarantee
|
||||
// that the task on the same row will be executed in order (i.e., work2D(1, 1, t) is guaranteed to
|
||||
// finish before calling work2D(1, 2, t)). Tasks in different rows can happen in any order.
|
||||
//
|
||||
// There are also width number of init calls, one per column. work2D(i, j, t) may return false if
|
||||
// column j requires initialization but it's not initialized yet. In that case, a thread t needs to
|
||||
// call initColumn(j, t) once to unblock all rows that depend on the initialization of column j.
|
||||
// (Again, t shouldn't affect the init work to be done; it's just for some non-thread-safe
|
||||
// variables). The init calls have no order requirement so we can call them in any order.
|
||||
//
|
||||
// Multiple therads may try to init the same column j at the same time. InitFn is expected to handle
|
||||
// this gracefully (e.g., let only one thread do the init and return immediately for other threads).
|
||||
class SkTaskGroup2D {
|
||||
public:
|
||||
SkTaskGroup2D(SkWorkKernel2D* kernel, int height, SkExecutor* executor, int threadCnt)
|
||||
: fKernel(kernel), fHeight(height), fThreadCnt(threadCnt), fIsFinishing(false)
|
||||
, fWidth(0), fThreadsGroup(new SkTaskGroup(*executor)) {}
|
||||
|
||||
virtual ~SkTaskGroup2D() {}
|
||||
|
||||
virtual void addColumn(); // Add a new column of tasks.
|
||||
|
||||
void start(); // start threads to execute tasks
|
||||
void finish(); // wait and finish all tasks (no more tasks can be added after calling this)
|
||||
|
||||
SK_ALWAYS_INLINE bool isFinishing() const {
|
||||
return fIsFinishing;
|
||||
}
|
||||
|
||||
protected:
|
||||
static constexpr int MAX_CACHE_LINE = 64;
|
||||
|
||||
// Finish all tasks on the threadId and then return.
|
||||
virtual void work(int threadId) = 0;
|
||||
|
||||
// Initialize a column that needs to be initialized. The parameter initCol is not thread safe
|
||||
// and should only be exclusively accessed by the working thread which will modify it to the
|
||||
// column that may need to be initialized next.
|
||||
void initAnUninitializedColumn(int& initCol, int threadId) {
|
||||
bool didSomeInit = false;
|
||||
while (initCol < fWidth && !didSomeInit) {
|
||||
didSomeInit = fKernel->initColumn(initCol++, threadId);
|
||||
}
|
||||
}
|
||||
|
||||
SkWorkKernel2D* fKernel;
|
||||
const int fHeight;
|
||||
const int fThreadCnt;
|
||||
|
||||
std::atomic<bool> fIsFinishing;
|
||||
std::atomic<int> fWidth;
|
||||
|
||||
std::unique_ptr<SkTaskGroup> fThreadsGroup;
|
||||
};
|
||||
|
||||
// A simple spinning task group that assumes height equals threadCnt.
|
||||
class SkSpinningTaskGroup2D final : public SkTaskGroup2D {
|
||||
public:
|
||||
SkSpinningTaskGroup2D(SkWorkKernel2D* kernel, int h, SkExecutor* x, int t)
|
||||
: SkTaskGroup2D(kernel, h, x, t) {
|
||||
SkASSERT(h == t); // height must be equal to threadCnt
|
||||
}
|
||||
|
||||
protected:
|
||||
void work(int threadId) override;
|
||||
};
|
||||
|
||||
class SkFlexibleTaskGroup2D final : public SkTaskGroup2D {
|
||||
public:
|
||||
SkFlexibleTaskGroup2D(SkWorkKernel2D* kernel, int h, SkExecutor* x, int t)
|
||||
: SkTaskGroup2D(kernel, h, x, t), fRowData(h) {}
|
||||
|
||||
protected:
|
||||
void work(int threadId) override;
|
||||
|
||||
private:
|
||||
// alignas(MAX_CACHE_LINE) to avoid false sharing by cache lines
|
||||
struct alignas(MAX_CACHE_LINE) RowData {
|
||||
RowData() : fNextColumn(0) {}
|
||||
|
||||
int fNextColumn; // next column index to work
|
||||
std::mutex fMutex; // the mutex for the thread to acquire
|
||||
};
|
||||
|
||||
std::vector<RowData> fRowData;
|
||||
};
|
||||
|
||||
#endif//SkTaskGroup2D_DEFINED
|
@ -1,250 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkThreadedBMPDevice.h"
|
||||
|
||||
#include "SkPath.h"
|
||||
#include "SkSpecialImage.h"
|
||||
#include "SkTaskGroup.h"
|
||||
#include "SkVertices.h"
|
||||
|
||||
// Calling init(j, k) would initialize the j-th element on k-th thread. It returns false if it's
|
||||
// already initiailized.
|
||||
bool SkThreadedBMPDevice::DrawQueue::initColumn(int column, int thread) {
|
||||
return fElements[column].tryInitOnce(&fThreadAllocs[thread]);
|
||||
}
|
||||
|
||||
// Calling work(i, j, k) would draw j-th element the i-th tile on k-th thead. If the element still
|
||||
// needs to be initialized, drawFn will return false without drawing.
|
||||
bool SkThreadedBMPDevice::DrawQueue::work2D(int row, int column, int thread) {
|
||||
return fElements[column].tryDraw(fDevice->fTileBounds[row], &fThreadAllocs[thread]);
|
||||
}
|
||||
|
||||
void SkThreadedBMPDevice::DrawQueue::reset() {
|
||||
if (fTasks) {
|
||||
fTasks->finish();
|
||||
}
|
||||
|
||||
fThreadAllocs.reset(fDevice->fThreadCnt);
|
||||
fSize = 0;
|
||||
|
||||
// using TaskGroup2D = SkSpinningTaskGroup2D;
|
||||
using TaskGroup2D = SkFlexibleTaskGroup2D;
|
||||
|
||||
fTasks.reset(new TaskGroup2D(this, fDevice->fTileCnt, fDevice->fExecutor,
|
||||
fDevice->fThreadCnt));
|
||||
fTasks->start();
|
||||
}
|
||||
|
||||
SkThreadedBMPDevice::SkThreadedBMPDevice(const SkBitmap& bitmap,
|
||||
int tiles,
|
||||
int threads,
|
||||
SkExecutor* executor)
|
||||
: INHERITED(bitmap)
|
||||
, fTileCnt(tiles)
|
||||
, fThreadCnt(threads <= 0 ? tiles : threads)
|
||||
, fQueue(this)
|
||||
{
|
||||
if (executor == nullptr) {
|
||||
fInternalExecutor = SkExecutor::MakeFIFOThreadPool(fThreadCnt);
|
||||
executor = fInternalExecutor.get();
|
||||
}
|
||||
fExecutor = executor;
|
||||
|
||||
// Tiling using stripes for now; we'll explore better tiling in the future.
|
||||
int h = (bitmap.height() + fTileCnt - 1) / SkTMax(fTileCnt, 1);
|
||||
int w = bitmap.width();
|
||||
int top = 0;
|
||||
for(int tid = 0; tid < fTileCnt; ++tid, top += h) {
|
||||
fTileBounds.push_back(SkIRect::MakeLTRB(0, top, w, top + h));
|
||||
}
|
||||
fQueue.reset();
|
||||
}
|
||||
|
||||
void SkThreadedBMPDevice::flush() {
|
||||
fQueue.reset();
|
||||
fAlloc.reset();
|
||||
}
|
||||
|
||||
SkThreadedBMPDevice::DrawState::DrawState(SkThreadedBMPDevice* dev) {
|
||||
// we need fDst to be set, and if we're actually drawing, to dirty the genID
|
||||
if (!dev->accessPixels(&fDst)) {
|
||||
// NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
|
||||
fDst.reset(dev->imageInfo(), nullptr, 0);
|
||||
}
|
||||
fMatrix = dev->ctm();
|
||||
fMatrix.getType(); // make it thread safe
|
||||
fRC = dev->fRCStack.rc();
|
||||
}
|
||||
|
||||
SkDraw SkThreadedBMPDevice::DrawState::getDraw() const {
|
||||
SkDraw draw;
|
||||
draw.fDst = fDst;
|
||||
draw.fMatrix = &fMatrix;
|
||||
draw.fRC = &fRC;
|
||||
return draw;
|
||||
}
|
||||
|
||||
SkThreadedBMPDevice::TileDraw::TileDraw(const DrawState& ds, const SkIRect& tileBounds)
|
||||
: fTileRC(ds.fRC) {
|
||||
fDst = ds.fDst;
|
||||
fMatrix = &ds.fMatrix;
|
||||
fTileRC.op(tileBounds, SkRegion::kIntersect_Op);
|
||||
fRC = &fTileRC;
|
||||
}
|
||||
|
||||
static inline SkRect get_fast_bounds(const SkRect& r, const SkPaint& p) {
|
||||
SkRect result;
|
||||
if (p.canComputeFastBounds()) {
|
||||
result = p.computeFastBounds(r, &result);
|
||||
} else {
|
||||
result = SkRectPriv::MakeLargest();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void SkThreadedBMPDevice::drawPaint(const SkPaint& paint) {
|
||||
SkRect drawBounds = SkRectPriv::MakeLargest();
|
||||
fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
|
||||
TileDraw(ds, tileBounds).drawPaint(paint);
|
||||
});
|
||||
}
|
||||
|
||||
void SkThreadedBMPDevice::drawPoints(SkCanvas::PointMode mode, size_t count,
|
||||
const SkPoint pts[], const SkPaint& paint) {
|
||||
SkPoint* clonedPts = this->cloneArray(pts, count);
|
||||
SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
|
||||
fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
|
||||
TileDraw(ds, tileBounds).drawPoints(mode, count, clonedPts, paint, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
void SkThreadedBMPDevice::drawRect(const SkRect& r, const SkPaint& paint) {
|
||||
SkRect drawBounds = get_fast_bounds(r, paint);
|
||||
fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
|
||||
TileDraw(ds, tileBounds).drawRect(r, paint);
|
||||
});
|
||||
}
|
||||
|
||||
void SkThreadedBMPDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
|
||||
#ifdef SK_IGNORE_BLURRED_RRECT_OPT
|
||||
SkPath path;
|
||||
|
||||
path.addRRect(rrect);
|
||||
// call the VIRTUAL version, so any subclasses who do handle drawPath aren't
|
||||
// required to override drawRRect.
|
||||
this->drawPath(path, paint, nullptr, false);
|
||||
#else
|
||||
SkRect drawBounds = get_fast_bounds(rrect.getBounds(), paint);
|
||||
fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
|
||||
TileDraw(ds, tileBounds).drawRRect(rrect, paint);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void SkThreadedBMPDevice::drawPath(const SkPath& path, const SkPaint& paint,
|
||||
const SkMatrix* prePathMatrix, bool pathIsMutable) {
|
||||
SkRect drawBounds = path.isInverseFillType() ? SkRectPriv::MakeLargest()
|
||||
: get_fast_bounds(path.getBounds(), paint);
|
||||
// when path is small, init-once has too much overhead; init-once also can't handle mask filter
|
||||
if (path.countVerbs() < 4 || paint.getMaskFilter()) {
|
||||
fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds) {
|
||||
TileDraw(ds, tileBounds).drawPath(path, paint, prePathMatrix, false);
|
||||
});
|
||||
} else {
|
||||
fQueue.push(drawBounds, [=](SkArenaAlloc* alloc, DrawElement* elem) {
|
||||
SkInitOnceData data = {alloc, elem};
|
||||
elem->getDraw().drawPath(path, paint, prePathMatrix, false, false, nullptr, &data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
SkBitmap SkThreadedBMPDevice::snapBitmap(const SkBitmap& bitmap) {
|
||||
// We can't use bitmap.isImmutable() because it could be temporarily immutable
|
||||
// TODO(liyuqian): use genID to reduce the copy frequency
|
||||
SkBitmap snap;
|
||||
snap.allocPixels(bitmap.info());
|
||||
bitmap.readPixels(snap.pixmap());
|
||||
return snap;
|
||||
}
|
||||
|
||||
void SkThreadedBMPDevice::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
|
||||
const SkRect* dstOrNull, const SkPaint& paint) {
|
||||
SkRect drawBounds;
|
||||
SkRect* clonedDstOrNull = nullptr;
|
||||
if (dstOrNull == nullptr) {
|
||||
drawBounds = SkRect::MakeWH(bitmap.width(), bitmap.height());
|
||||
matrix.mapRect(&drawBounds);
|
||||
} else {
|
||||
drawBounds = *dstOrNull;
|
||||
clonedDstOrNull = fAlloc.make<SkRect>(*dstOrNull);
|
||||
}
|
||||
|
||||
SkBitmap snap = this->snapBitmap(bitmap);
|
||||
fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
|
||||
SkBitmap local = snap; // bitmap is not thread safe; copy a local one.
|
||||
TileDraw(ds, tileBounds).drawBitmap(local, matrix, clonedDstOrNull, paint);
|
||||
});
|
||||
}
|
||||
|
||||
void SkThreadedBMPDevice::drawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
|
||||
const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) {
|
||||
// SkBitmapDevice::drawBitmapRect may use shader and drawRect. In that case, we need to snap
|
||||
// the bitmap here because we won't go into SkThreadedBMPDevice::drawBitmap.
|
||||
SkBitmap snap = this->snapBitmap(bitmap);
|
||||
this->SkBitmapDevice::drawBitmapRect(snap, src, dst, paint, constraint);
|
||||
}
|
||||
|
||||
|
||||
void SkThreadedBMPDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) {
|
||||
SkRect drawBounds = SkRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
|
||||
SkBitmap snap = this->snapBitmap(bitmap);
|
||||
fQueue.push<false>(drawBounds, [=](SkArenaAlloc*, const DrawState& ds,
|
||||
const SkIRect& tileBounds){
|
||||
SkBitmap local = snap; // bitmap is not thread safe; copy a local one.
|
||||
TileDraw(ds, tileBounds).drawSprite(local, x, y, paint);
|
||||
});
|
||||
}
|
||||
|
||||
void SkThreadedBMPDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[],
|
||||
int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) {
|
||||
char* clonedText = this->cloneArray((const char*)text, len);
|
||||
SkScalar* clonedXpos = this->cloneArray(xpos, paint.countText(text, len) * scalarsPerPos);
|
||||
SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
|
||||
SkSurfaceProps prop(SkBitmapDeviceFilteredSurfaceProps(fBitmap, paint, this->surfaceProps())());
|
||||
fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
|
||||
TileDraw(ds, tileBounds).drawPosText(clonedText, len, clonedXpos, scalarsPerPos, offset,
|
||||
paint, &prop);
|
||||
});
|
||||
}
|
||||
|
||||
void SkThreadedBMPDevice::drawVertices(const SkVertices* vertices, const SkMatrix* bones,
|
||||
int boneCount, SkBlendMode bmode, const SkPaint& paint) {
|
||||
const sk_sp<SkVertices> verts = sk_ref_sp(vertices); // retain vertices until flush
|
||||
SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
|
||||
|
||||
// Make a copy of the bone matrices.
|
||||
SkMatrix* clonedBones = bones ? this->cloneArray(bones, boneCount) : nullptr;
|
||||
|
||||
// Make the bone matrices thread-safe.
|
||||
for (int i = 0; i < boneCount; i ++) {
|
||||
clonedBones[i].getType();
|
||||
}
|
||||
|
||||
fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
|
||||
TileDraw(ds, tileBounds).drawVertices(verts->mode(), verts->vertexCount(),
|
||||
verts->positions(), verts->texCoords(),
|
||||
verts->colors(), verts->boneIndices(),
|
||||
verts->boneWeights(), bmode, verts->indices(),
|
||||
verts->indexCount(), paint, clonedBones, boneCount);
|
||||
});
|
||||
}
|
||||
|
||||
sk_sp<SkSpecialImage> SkThreadedBMPDevice::snapSpecial() {
|
||||
this->flush();
|
||||
return this->makeSpecial(fBitmap);
|
||||
}
|
@ -1,225 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkThreadedBMPDevice_DEFINED
|
||||
#define SkThreadedBMPDevice_DEFINED
|
||||
|
||||
#include "SkBitmapDevice.h"
|
||||
#include "SkDraw.h"
|
||||
#include "SkRectPriv.h"
|
||||
#include "SkTaskGroup2D.h"
|
||||
#include <new>
|
||||
|
||||
class SkThreadedBMPDevice : public SkBitmapDevice {
|
||||
public:
|
||||
// When threads = 0, we make fThreadCnt = tiles. Otherwise fThreadCnt = threads.
|
||||
// When executor = nullptr, we manages the thread pool. Otherwise, the caller manages it.
|
||||
SkThreadedBMPDevice(const SkBitmap& bitmap, int tiles, int threads = 0,
|
||||
SkExecutor* executor = nullptr);
|
||||
|
||||
~SkThreadedBMPDevice() override { fQueue.finish(); }
|
||||
|
||||
protected:
|
||||
void drawPaint(const SkPaint& paint) override;
|
||||
void drawPoints(SkCanvas::PointMode mode, size_t count,
|
||||
const SkPoint[], const SkPaint& paint) override;
|
||||
void drawRect(const SkRect& r, const SkPaint& paint) override;
|
||||
void drawRRect(const SkRRect& rr, const SkPaint& paint) override;
|
||||
|
||||
void drawPath(const SkPath&, const SkPaint&, const SkMatrix* prePathMatrix,
|
||||
bool pathIsMutable) override;
|
||||
void drawSprite(const SkBitmap&, int x, int y, const SkPaint&) override;
|
||||
void drawPosText(const void* text, size_t len, const SkScalar pos[],
|
||||
int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) override;
|
||||
void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode,
|
||||
const SkPaint&) override;
|
||||
|
||||
void drawBitmap(const SkBitmap&, const SkMatrix&, const SkRect* dstOrNull,
|
||||
const SkPaint&) override;
|
||||
void drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
|
||||
const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) override;
|
||||
|
||||
sk_sp<SkSpecialImage> snapSpecial() override;
|
||||
|
||||
void flush() override;
|
||||
|
||||
private:
|
||||
// We store DrawState inside DrawElement because inifFn and drawFn both want to use it
|
||||
struct DrawState {
|
||||
SkPixmap fDst;
|
||||
SkMatrix fMatrix;
|
||||
SkRasterClip fRC;
|
||||
|
||||
DrawState() {}
|
||||
explicit DrawState(SkThreadedBMPDevice* dev);
|
||||
|
||||
SkDraw getDraw() const;
|
||||
};
|
||||
|
||||
class TileDraw : public SkDraw {
|
||||
public: TileDraw(const DrawState& ds, const SkIRect& tileBounds);
|
||||
private: SkRasterClip fTileRC;
|
||||
};
|
||||
|
||||
class DrawElement {
|
||||
public:
|
||||
using InitFn = std::function<void(SkArenaAlloc* threadAlloc, DrawElement* element)>;
|
||||
using DrawFn = std::function<void(SkArenaAlloc* threadAlloc, const DrawState& ds,
|
||||
const SkIRect& tileBounds)>;
|
||||
|
||||
DrawElement() {}
|
||||
DrawElement(SkThreadedBMPDevice* device, DrawFn&& drawFn, const SkIRect& drawBounds)
|
||||
: fInitialized(true)
|
||||
, fDrawFn(std::move(drawFn))
|
||||
, fDS(device)
|
||||
, fDrawBounds(drawBounds) {}
|
||||
DrawElement(SkThreadedBMPDevice* device, InitFn&& initFn, const SkIRect& drawBounds)
|
||||
: fInitialized(false)
|
||||
, fNeedInit(true)
|
||||
, fInitFn(std::move(initFn))
|
||||
, fDS(device)
|
||||
, fDrawBounds(drawBounds) {}
|
||||
|
||||
SK_ALWAYS_INLINE bool tryInitOnce(SkArenaAlloc* alloc) {
|
||||
bool t = true;
|
||||
// If there are multiple threads reaching this point simutaneously,
|
||||
// compare_exchange_strong ensures that only one thread can enter the if condition and
|
||||
// do the initialization.
|
||||
if (!fInitialized && fNeedInit && fNeedInit.compare_exchange_strong(t, false)) {
|
||||
#ifdef SK_DEBUG
|
||||
fDrawFn = 0; // Invalidate fDrawFn
|
||||
#endif
|
||||
fInitFn(alloc, this);
|
||||
fInitialized = true;
|
||||
SkASSERT(fDrawFn != 0); // Ensure that fInitFn does populate fDrawFn
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SK_ALWAYS_INLINE bool tryDraw(const SkIRect& tileBounds, SkArenaAlloc* alloc) {
|
||||
if (!SkIRect::Intersects(tileBounds, fDrawBounds)) {
|
||||
return true;
|
||||
}
|
||||
if (fInitialized) {
|
||||
fDrawFn(alloc, fDS, tileBounds);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SkDraw getDraw() const { return fDS.getDraw(); }
|
||||
void setDrawFn(DrawFn&& fn) { fDrawFn = std::move(fn); }
|
||||
|
||||
private:
|
||||
std::atomic<bool> fInitialized;
|
||||
std::atomic<bool> fNeedInit;
|
||||
InitFn fInitFn;
|
||||
DrawFn fDrawFn;
|
||||
DrawState fDS;
|
||||
SkIRect fDrawBounds;
|
||||
};
|
||||
|
||||
class DrawQueue : public SkWorkKernel2D {
|
||||
public:
|
||||
static constexpr int MAX_QUEUE_SIZE = 100000;
|
||||
|
||||
DrawQueue(SkThreadedBMPDevice* device) : fDevice(device) {}
|
||||
void reset();
|
||||
|
||||
// For ~SkThreadedBMPDevice() to shutdown tasks, we use this instead of reset because reset
|
||||
// will start new tasks.
|
||||
void finish() { fTasks->finish(); }
|
||||
|
||||
// Push a draw command into the queue. If Fn is DrawFn, we're pushing an element without
|
||||
// the need of initialization. If Fn is InitFn, we're pushing an element with init-once
|
||||
// and the InitFn will generate the DrawFn during initialization.
|
||||
template<bool useCTM = true, typename Fn>
|
||||
SK_ALWAYS_INLINE void push(const SkRect& rawDrawBounds, Fn&& fn) {
|
||||
if (fSize == MAX_QUEUE_SIZE) {
|
||||
this->reset();
|
||||
}
|
||||
SkASSERT(fSize < MAX_QUEUE_SIZE);
|
||||
SkIRect drawBounds = fDevice->transformDrawBounds<useCTM>(rawDrawBounds);
|
||||
fElements[fSize].~DrawElement(); // release previous resources to prevent memory leak
|
||||
new (&fElements[fSize++]) DrawElement(fDevice, std::move(fn), drawBounds);
|
||||
fTasks->addColumn();
|
||||
}
|
||||
|
||||
// SkWorkKernel2D
|
||||
bool initColumn(int column, int thread) override;
|
||||
bool work2D(int row, int column, int thread) override;
|
||||
|
||||
private:
|
||||
SkThreadedBMPDevice* fDevice;
|
||||
std::unique_ptr<SkTaskGroup2D> fTasks;
|
||||
SkTArray<SkSTArenaAlloc<8 << 10>> fThreadAllocs; // 8k stack size
|
||||
DrawElement fElements[MAX_QUEUE_SIZE];
|
||||
int fSize;
|
||||
};
|
||||
|
||||
template<bool useCTM = true>
|
||||
SkIRect transformDrawBounds(const SkRect& drawBounds) const {
|
||||
if (drawBounds == SkRectPriv::MakeLargest()) {
|
||||
return SkRectPriv::MakeILarge();
|
||||
}
|
||||
SkRect transformedBounds;
|
||||
if (useCTM) {
|
||||
this->ctm().mapRect(&transformedBounds, drawBounds);
|
||||
} else {
|
||||
transformedBounds = drawBounds;
|
||||
}
|
||||
return transformedBounds.roundOut();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
T* cloneArray(const T* array, int count) {
|
||||
T* clone = fAlloc.makeArrayDefault<T>(count);
|
||||
memcpy(clone, array, sizeof(T) * count);
|
||||
return clone;
|
||||
}
|
||||
|
||||
SkBitmap snapBitmap(const SkBitmap& bitmap);
|
||||
|
||||
const int fTileCnt;
|
||||
const int fThreadCnt;
|
||||
SkTArray<SkIRect> fTileBounds;
|
||||
|
||||
/**
|
||||
* This can either be
|
||||
* 1. fInternalExecutor.get() which means that we're managing the thread pool's life cycle.
|
||||
* 2. provided by our caller which means that our caller is managing the threads' life cycle.
|
||||
* In the 2nd case, fInternalExecutor == nullptr.
|
||||
*/
|
||||
SkExecutor* fExecutor = nullptr;
|
||||
std::unique_ptr<SkExecutor> fInternalExecutor;
|
||||
|
||||
SkSTArenaAlloc<8 << 10> fAlloc; // so we can allocate memory that lives until flush
|
||||
|
||||
DrawQueue fQueue;
|
||||
|
||||
friend struct SkInitOnceData; // to access DrawElement and DrawState
|
||||
friend class SkDraw; // to access DrawState
|
||||
|
||||
typedef SkBitmapDevice INHERITED;
|
||||
};
|
||||
|
||||
// Passed to SkDraw::drawXXX to enable threaded draw with init-once. The goal is to reuse as much
|
||||
// code as possible from SkDraw. (See SkDraw::drawPath and SkDraw::drawDevPath for an example.)
|
||||
struct SkInitOnceData {
|
||||
SkArenaAlloc* fAlloc;
|
||||
SkThreadedBMPDevice::DrawElement* fElement;
|
||||
|
||||
void setEmptyDrawFn() {
|
||||
fElement->setDrawFn([](SkArenaAlloc* threadAlloc, const SkThreadedBMPDevice::DrawState& ds,
|
||||
const SkIRect& tileBounds){});
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SkThreadedBMPDevice_DEFINED
|
@ -34,7 +34,6 @@
|
||||
#include "SkSurface.h"
|
||||
#include "SkTaskGroup.h"
|
||||
#include "SkTestFontMgr.h"
|
||||
#include "SkThreadedBMPDevice.h"
|
||||
#include "SkTo.h"
|
||||
#include "SvgSlide.h"
|
||||
#include "Viewer.h"
|
||||
@ -194,8 +193,6 @@ Viewer::Viewer(int argc, char** argv, void* platformData)
|
||||
, fOffset{0.0f, 0.0f}
|
||||
, fGestureDevice(GestureDevice::kNone)
|
||||
, fPerspectiveMode(kPerspective_Off)
|
||||
, fTileCnt(0)
|
||||
, fThreadCnt(0)
|
||||
{
|
||||
SkGraphics::Init();
|
||||
|
||||
@ -326,40 +323,6 @@ Viewer::Viewer(int argc, char** argv, void* platformData)
|
||||
#endif
|
||||
this->setBackend(newBackend);
|
||||
});
|
||||
fCommands.addCommand('+', "Threaded Backend", "Increase tile count", [this]() {
|
||||
fTileCnt++;
|
||||
if (fThreadCnt == 0) {
|
||||
this->resetExecutor();
|
||||
}
|
||||
this->updateTitle();
|
||||
fWindow->inval();
|
||||
});
|
||||
fCommands.addCommand('-', "Threaded Backend", "Decrease tile count", [this]() {
|
||||
fTileCnt = SkTMax(0, fTileCnt - 1);
|
||||
if (fThreadCnt == 0) {
|
||||
this->resetExecutor();
|
||||
}
|
||||
this->updateTitle();
|
||||
fWindow->inval();
|
||||
});
|
||||
fCommands.addCommand('>', "Threaded Backend", "Increase thread count", [this]() {
|
||||
if (fTileCnt == 0) {
|
||||
return;
|
||||
}
|
||||
fThreadCnt = (fThreadCnt + 1) % fTileCnt;
|
||||
this->resetExecutor();
|
||||
this->updateTitle();
|
||||
fWindow->inval();
|
||||
});
|
||||
fCommands.addCommand('<', "Threaded Backend", "Decrease thread count", [this]() {
|
||||
if (fTileCnt == 0) {
|
||||
return;
|
||||
}
|
||||
fThreadCnt = (fThreadCnt + fTileCnt - 1) % fTileCnt;
|
||||
this->resetExecutor();
|
||||
this->updateTitle();
|
||||
fWindow->inval();
|
||||
});
|
||||
fCommands.addCommand('K', "IO", "Save slide to SKP", [this]() {
|
||||
fSaveToSKP = true;
|
||||
fWindow->inval();
|
||||
@ -768,13 +731,6 @@ void Viewer::updateTitle() {
|
||||
}
|
||||
paintTitle.done();
|
||||
|
||||
if (fTileCnt > 0) {
|
||||
title.appendf(" T%d", fTileCnt);
|
||||
if (fThreadCnt > 0) {
|
||||
title.appendf("/%d", fThreadCnt);
|
||||
}
|
||||
}
|
||||
|
||||
switch (fColorMode) {
|
||||
case ColorMode::kLegacy:
|
||||
title.append(" Legacy 8888");
|
||||
@ -1140,17 +1096,7 @@ void Viewer::drawSlide(SkCanvas* canvas) {
|
||||
? SkSurface::MakeRaster(info, &props)
|
||||
: canvas->makeSurface(info);
|
||||
SkPixmap offscreenPixmap;
|
||||
if (fTileCnt > 0 && offscreenSurface->peekPixels(&offscreenPixmap)) {
|
||||
SkBitmap offscreenBitmap;
|
||||
offscreenBitmap.installPixels(offscreenPixmap);
|
||||
threadedCanvas =
|
||||
skstd::make_unique<SkCanvas>(
|
||||
sk_make_sp<SkThreadedBMPDevice>(
|
||||
offscreenBitmap, fTileCnt, fThreadCnt, fExecutor.get()));
|
||||
slideCanvas = threadedCanvas.get();
|
||||
} else {
|
||||
slideCanvas = offscreenSurface->getCanvas();
|
||||
}
|
||||
slideCanvas = offscreenSurface->getCanvas();
|
||||
}
|
||||
|
||||
std::unique_ptr<SkCanvas> xformCanvas = nullptr;
|
||||
|
@ -106,10 +106,6 @@ private:
|
||||
SkMatrix computeMatrix();
|
||||
SkPoint mapEvent(float x, float y);
|
||||
|
||||
void resetExecutor() {
|
||||
fExecutor = SkExecutor::MakeFIFOThreadPool(fThreadCnt == 0 ? fTileCnt : fThreadCnt);
|
||||
}
|
||||
|
||||
sk_app::Window* fWindow;
|
||||
|
||||
StatsLayer fStatsLayer;
|
||||
@ -172,10 +168,6 @@ private:
|
||||
|
||||
SkTArray<std::function<void(void)>> fDeferredActions;
|
||||
|
||||
int fTileCnt;
|
||||
int fThreadCnt;
|
||||
std::unique_ptr<SkExecutor> fExecutor;
|
||||
|
||||
SkPaint fPaint;
|
||||
SkPaintFields fPaintOverrides;
|
||||
bool fPixelGeometryOverrides = false;
|
||||
|
Loading…
Reference in New Issue
Block a user