Add an interface abstraction to the WebP worker thread implementation

This allows custom implementations of threading mecanism.

Patch by Leonhard Gruenschloss.

Change-Id: Id8ea5917acd2f24fa8bce79748d1747de2751614
This commit is contained in:
skal
2014-06-12 11:35:44 +02:00
parent d6cd6358ff
commit 24e3080571
6 changed files with 165 additions and 103 deletions

View File

@ -362,7 +362,7 @@ void VP8EncInitAlpha(VP8Encoder* const enc) {
enc->alpha_data_size_ = 0;
if (enc->thread_level_ > 0) {
WebPWorker* const worker = &enc->alpha_worker_;
WebPWorkerInit(worker);
WebPGetWorkerInterface()->Init(worker);
worker->data1 = enc;
worker->data2 = NULL;
worker->hook = (WebPWorkerHook)CompressAlphaJob;
@ -373,10 +373,11 @@ int VP8EncStartAlpha(VP8Encoder* const enc) {
if (enc->has_alpha_) {
if (enc->thread_level_ > 0) {
WebPWorker* const worker = &enc->alpha_worker_;
if (!WebPWorkerReset(worker)) { // Makes sure worker is good to go.
// Makes sure worker is good to go.
if (!WebPGetWorkerInterface()->Reset(worker)) {
return 0;
}
WebPWorkerLaunch(worker);
WebPGetWorkerInterface()->Launch(worker);
return 1;
} else {
return CompressAlphaJob(enc, NULL); // just do the job right away
@ -389,7 +390,7 @@ int VP8EncFinishAlpha(VP8Encoder* const enc) {
if (enc->has_alpha_) {
if (enc->thread_level_ > 0) {
WebPWorker* const worker = &enc->alpha_worker_;
if (!WebPWorkerSync(worker)) return 0; // error
if (!WebPGetWorkerInterface()->Sync(worker)) return 0; // error
}
}
return WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_);
@ -399,8 +400,10 @@ int VP8EncDeleteAlpha(VP8Encoder* const enc) {
int ok = 1;
if (enc->thread_level_ > 0) {
WebPWorker* const worker = &enc->alpha_worker_;
ok = WebPWorkerSync(worker); // finish anything left in flight
WebPWorkerEnd(worker); // still need to end the worker, even if !ok
// finish anything left in flight
ok = WebPGetWorkerInterface()->Sync(worker);
// still need to end the worker, even if !ok
WebPGetWorkerInterface()->End(worker);
}
WebPSafeFree(enc->alpha_data_);
enc->alpha_data_ = NULL;

View File

@ -420,7 +420,7 @@ static void MergeJobs(const SegmentJob* const src, SegmentJob* const dst) {
// initialize the job struct with some TODOs
static void InitSegmentJob(VP8Encoder* const enc, SegmentJob* const job,
int start_row, int end_row) {
WebPWorkerInit(&job->worker);
WebPGetWorkerInterface()->Init(&job->worker);
job->worker.data1 = job;
job->worker.data2 = &job->it;
job->worker.hook = (WebPWorkerHook)DoSegmentsJob;
@ -453,6 +453,8 @@ int VP8EncAnalyze(VP8Encoder* const enc) {
#else
const int do_mt = 0;
#endif
const WebPWorkerInterface* const worker_interface =
WebPGetWorkerInterface();
SegmentJob main_job;
if (do_mt) {
SegmentJob side_job;
@ -462,23 +464,23 @@ int VP8EncAnalyze(VP8Encoder* const enc) {
InitSegmentJob(enc, &side_job, split_row, last_row);
// we don't need to call Reset() on main_job.worker, since we're calling
// WebPWorkerExecute() on it
ok &= WebPWorkerReset(&side_job.worker);
ok &= worker_interface->Reset(&side_job.worker);
// launch the two jobs in parallel
if (ok) {
WebPWorkerLaunch(&side_job.worker);
WebPWorkerExecute(&main_job.worker);
ok &= WebPWorkerSync(&side_job.worker);
ok &= WebPWorkerSync(&main_job.worker);
worker_interface->Launch(&side_job.worker);
worker_interface->Execute(&main_job.worker);
ok &= worker_interface->Sync(&side_job.worker);
ok &= worker_interface->Sync(&main_job.worker);
}
WebPWorkerEnd(&side_job.worker);
worker_interface->End(&side_job.worker);
if (ok) MergeJobs(&side_job, &main_job); // merge results together
} else {
// Even for single-thread case, we use the generic Worker tools.
InitSegmentJob(enc, &main_job, 0, last_row);
WebPWorkerExecute(&main_job.worker);
ok &= WebPWorkerSync(&main_job.worker);
worker_interface->Execute(&main_job.worker);
ok &= worker_interface->Sync(&main_job.worker);
}
WebPWorkerEnd(&main_job.worker);
worker_interface->End(&main_job.worker);
if (ok) {
enc->alpha_ = main_job.alpha / total_mb;
enc->uv_alpha_ = main_job.uv_alpha / total_mb;