Commit 477b16c4 authored by xlai's avatar xlai Committed by Commit bot

Change to idle-task implementations in toBlob

This is a combined revert of
https://codereview.chromium.org/1491653002
and https://codereview.chromium.org/1614173002. One more
additional edit is the addition of
"testRunner.dumpAsText();" in canvas-toBlob-defaultpng.html
and canvas-toBlob-toDataURL-race.js.

Reason for this revert is that we found out idle-task
performs much better (has less negative impacts on other
activities) than threaded implementation on majority of
machines.

BUG=581574

Review URL: https://codereview.chromium.org/1637163002

Cr-Commit-Position: refs/heads/master@{#371806}
parent 5194bd77
...@@ -10,6 +10,11 @@ ...@@ -10,6 +10,11 @@
"base": "fast/canvas", "base": "fast/canvas",
"args": ["--force-display-list-2d-canvas"] "args": ["--force-display-list-2d-canvas"]
}, },
{
"prefix": "threaded",
"base": "fast/canvas/toBlob",
"args": ["--enable-threaded-compositing"]
},
{ {
"prefix": "threaded", "prefix": "threaded",
"base": "compositing/visibility", "base": "compositing/visibility",
......
<script src = "../../resources/js-test.js"></script> <script src = "../../../resources/js-test.js"></script>
<script type = 'text/javascript'> <script type = 'text/javascript'>
jsTestIsAsync = true; jsTestIsAsync = true;
description("Test that verifies whether the image data survives the toBlob process after async image encoding"); description("Test that verifies whether the image data survives the toBlob process after async image encoding");
......
<script src = "../../resources/js-test.js"></script> <script src = "../../../resources/js-test.js"></script>
<script src = "script-tests/canvas-toBlob-toDataURL-race.js"></script> <script src = "../script-tests/canvas-toBlob-toDataURL-race.js"></script>
<script type = 'text/javascript'> <script type = 'text/javascript'>
description("Verifies if synchronous PNG image encoding (toDataURL) conflicts with asynchronous image encoding (toBlob)"); description("Verifies if synchronous PNG image encoding (toDataURL) conflicts with asynchronous image encoding (toBlob)");
......
...@@ -611,7 +611,11 @@ void HTMLCanvasElement::toBlob(ScriptState* scriptState, BlobCallback* callback, ...@@ -611,7 +611,11 @@ void HTMLCanvasElement::toBlob(ScriptState* scriptState, BlobCallback* callback,
RefPtr<CanvasAsyncBlobCreator> asyncCreatorRef = CanvasAsyncBlobCreator::create(imageDataRef.release(), encodingMimeType, imageData->size(), callback, scriptState->executionContext()); RefPtr<CanvasAsyncBlobCreator> asyncCreatorRef = CanvasAsyncBlobCreator::create(imageDataRef.release(), encodingMimeType, imageData->size(), callback, scriptState->executionContext());
asyncCreatorRef->scheduleAsyncBlobCreation(quality); if (Platform::current()->isThreadedCompositingEnabled() && (encodingMimeType == DefaultMimeType)) {
asyncCreatorRef->scheduleAsyncBlobCreation(true);
} else {
asyncCreatorRef->scheduleAsyncBlobCreation(false, quality);
}
} }
void HTMLCanvasElement::addListener(CanvasDrawListener* listener) void HTMLCanvasElement::addListener(CanvasDrawListener* listener)
......
...@@ -13,15 +13,27 @@ ...@@ -13,15 +13,27 @@
#include "platform/image-encoders/skia/PNGImageEncoder.h" #include "platform/image-encoders/skia/PNGImageEncoder.h"
#include "platform/threading/BackgroundTaskRunner.h" #include "platform/threading/BackgroundTaskRunner.h"
#include "public/platform/Platform.h" #include "public/platform/Platform.h"
#include "public/platform/WebScheduler.h"
#include "public/platform/WebTaskRunner.h"
#include "public/platform/WebThread.h" #include "public/platform/WebThread.h"
#include "public/platform/WebTraceLocation.h" #include "public/platform/WebTraceLocation.h"
#include "wtf/Functional.h" #include "wtf/Functional.h"
namespace blink { namespace blink {
namespace {
const double SlackBeforeDeadline = 0.001; // a small slack period between deadline and current time for safety
const int NumChannelsPng = 4; const int NumChannelsPng = 4;
const int LongTaskImageSizeThreshold = 1000 * 1000; // The max image size we expect to encode in 14ms on Linux in PNG format const int LongTaskImageSizeThreshold = 1000 * 1000; // The max image size we expect to encode in 14ms on Linux in PNG format
bool isDeadlineNearOrPassed(double deadlineSeconds)
{
return (deadlineSeconds - SlackBeforeDeadline - Platform::current()->monotonicallyIncreasingTimeSeconds() <= 0);
}
} // anonymous namespace
class CanvasAsyncBlobCreator::ContextObserver final : public NoBaseWillBeGarbageCollected<CanvasAsyncBlobCreator::ContextObserver>, public ContextLifecycleObserver { class CanvasAsyncBlobCreator::ContextObserver final : public NoBaseWillBeGarbageCollected<CanvasAsyncBlobCreator::ContextObserver>, public ContextLifecycleObserver {
WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(CanvasAsyncBlobCreator::ContextObserver); WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(CanvasAsyncBlobCreator::ContextObserver);
public: public:
...@@ -88,7 +100,7 @@ DEFINE_TRACE(CanvasAsyncBlobCreator::ContextObserver) ...@@ -88,7 +100,7 @@ DEFINE_TRACE(CanvasAsyncBlobCreator::ContextObserver)
ContextLifecycleObserver::trace(visitor); ContextLifecycleObserver::trace(visitor);
} }
void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation(double quality) void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation(bool canUseIdlePeriodScheduling, double quality)
{ {
// TODO: async blob creation should be supported in worker_pool threads as well. but right now blink does not have that // TODO: async blob creation should be supported in worker_pool threads as well. but right now blink does not have that
ASSERT(isMainThread()); ASSERT(isMainThread());
...@@ -96,8 +108,52 @@ void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation(double quality) ...@@ -96,8 +108,52 @@ void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation(double quality)
// Make self-reference to keep this object alive until the final task completes // Make self-reference to keep this object alive until the final task completes
m_selfRef = this; m_selfRef = this;
BackgroundTaskRunner::TaskSize taskSize = (m_size.height() * m_size.width() >= LongTaskImageSizeThreshold) ? BackgroundTaskRunner::TaskSizeLongRunningTask : BackgroundTaskRunner::TaskSizeShortRunningTask; if (canUseIdlePeriodScheduling) {
BackgroundTaskRunner::postOnBackgroundThread(BLINK_FROM_HERE, threadSafeBind(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, AllowCrossThreadAccess(this), quality), taskSize); ASSERT(m_mimeType == "image/png");
Platform::current()->mainThread()->scheduler()->postIdleTask(BLINK_FROM_HERE, WTF::bind<double>(&CanvasAsyncBlobCreator::initiatePngEncoding, this));
} else {
BackgroundTaskRunner::TaskSize taskSize = (m_size.height() * m_size.width() >= LongTaskImageSizeThreshold) ? BackgroundTaskRunner::TaskSizeLongRunningTask : BackgroundTaskRunner::TaskSizeShortRunningTask;
BackgroundTaskRunner::postOnBackgroundThread(BLINK_FROM_HERE, threadSafeBind(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, AllowCrossThreadAccess(this), quality), taskSize);
}
}
void CanvasAsyncBlobCreator::initiatePngEncoding(double deadlineSeconds)
{
m_encoderState = PNGImageEncoderState::create(m_size, m_encodedImage.get());
if (!m_encoderState) {
Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HERE, bind(&BlobCallback::handleEvent, m_callback, nullptr));
m_selfRef.clear();
return;
}
CanvasAsyncBlobCreator::idleEncodeRowsPng(deadlineSeconds);
}
void CanvasAsyncBlobCreator::scheduleIdleEncodeRowsPng()
{
Platform::current()->currentThread()->scheduler()->postIdleTask(BLINK_FROM_HERE, WTF::bind<double>(&CanvasAsyncBlobCreator::idleEncodeRowsPng, this));
}
void CanvasAsyncBlobCreator::idleEncodeRowsPng(double deadlineSeconds)
{
unsigned char* inputPixels = m_data->data() + m_pixelRowStride * m_numRowsCompleted;
for (int y = m_numRowsCompleted; y < m_size.height(); ++y) {
if (isDeadlineNearOrPassed(deadlineSeconds)) {
m_numRowsCompleted = y;
CanvasAsyncBlobCreator::scheduleIdleEncodeRowsPng();
return;
}
PNGImageEncoder::writeOneRowToPng(inputPixels, m_encoderState.get());
inputPixels += m_pixelRowStride;
}
m_numRowsCompleted = m_size.height();
PNGImageEncoder::finalizePng(m_encoderState.get());
if (isDeadlineNearOrPassed(deadlineSeconds)) {
Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HERE, bind(&CanvasAsyncBlobCreator::createBlobAndCall, this));
} else {
this->createBlobAndCall();
}
} }
void CanvasAsyncBlobCreator::createBlobAndCall() void CanvasAsyncBlobCreator::createBlobAndCall()
......
...@@ -21,7 +21,7 @@ class CORE_EXPORT CanvasAsyncBlobCreator ...@@ -21,7 +21,7 @@ class CORE_EXPORT CanvasAsyncBlobCreator
: public RefCounted<CanvasAsyncBlobCreator> { : public RefCounted<CanvasAsyncBlobCreator> {
public: public:
static PassRefPtr<CanvasAsyncBlobCreator> create(PassRefPtr<DOMUint8ClampedArray> unpremultipliedRGBAImageData, const String& mimeType, const IntSize&, BlobCallback*, ExecutionContext*); static PassRefPtr<CanvasAsyncBlobCreator> create(PassRefPtr<DOMUint8ClampedArray> unpremultipliedRGBAImageData, const String& mimeType, const IntSize&, BlobCallback*, ExecutionContext*);
void scheduleAsyncBlobCreation(double quality = 0.0); void scheduleAsyncBlobCreation(bool canUseIdlePeriodScheduling, double quality = 0.0);
virtual ~CanvasAsyncBlobCreator(); virtual ~CanvasAsyncBlobCreator();
protected: protected:
...@@ -47,6 +47,10 @@ private: ...@@ -47,6 +47,10 @@ private:
RefPtr<CanvasAsyncBlobCreator> m_selfRef; RefPtr<CanvasAsyncBlobCreator> m_selfRef;
void clearSelfReference(); void clearSelfReference();
void initiatePngEncoding(double deadlineSeconds);
void scheduleIdleEncodeRowsPng();
void idleEncodeRowsPng(double deadlineSeconds);
void createBlobAndCall(); void createBlobAndCall();
void encodeImageOnEncoderThread(double quality); void encodeImageOnEncoderThread(double quality);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment