mirror of
https://github.com/RGBCube/serenity
synced 2025-05-23 22:25:08 +00:00

The main advantage of this change is that heavy-weight filters do not lock up the GUI anymore. This first cut has several flaws: - We do not account for modification of the referenced images while the filter is running. Depending on the exact filter behavior this might have all sorts of weird effects. A simple fix would be to show a progress dialog to the user, preventing them from performing other modifications in the meantime. - We do not use the image processor for previews. Preview behavior has a couple of other considerations that are intentionally not addressed in this commit or pull request.
69 lines
2.1 KiB
C++
69 lines
2.1 KiB
C++
/*
|
|
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>.
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include "ImageProcessor.h"
|
|
|
|
namespace PixelPaint {
|
|
|
|
FilterApplicationCommand::FilterApplicationCommand(NonnullRefPtr<Filter> filter, NonnullRefPtr<Layer> target_layer)
|
|
: m_filter(move(filter))
|
|
, m_target_layer(move(target_layer))
|
|
{
|
|
}
|
|
|
|
void FilterApplicationCommand::execute()
|
|
{
|
|
m_filter->apply(m_target_layer->content_bitmap(), m_target_layer->content_bitmap());
|
|
m_filter->m_editor->gui_event_loop().deferred_invoke([strong_this = NonnullRefPtr(*this)]() {
|
|
// HACK: we can't tell strong_this to not be const
|
|
(*const_cast<NonnullRefPtr<Layer>*>(&strong_this->m_target_layer))->did_modify_bitmap(strong_this->m_target_layer->rect());
|
|
strong_this->m_filter->m_editor->did_complete_action(String::formatted("Filter {}", strong_this->m_filter->filter_name()));
|
|
});
|
|
}
|
|
|
|
static Singleton<ImageProcessor> s_image_processor;
|
|
|
|
ImageProcessor::ImageProcessor()
|
|
: m_command_queue(MUST(Queue::try_create()))
|
|
, m_processor_thread(Threading::Thread::construct([this]() {
|
|
while (true) {
|
|
if (auto next_command = m_command_queue.try_dequeue(); !next_command.is_error()) {
|
|
next_command.value()->execute();
|
|
} else {
|
|
Threading::MutexLocker locker { m_wakeup_mutex };
|
|
m_wakeup_variable.wait_while([this]() { return m_command_queue.weak_used() == 0; });
|
|
}
|
|
}
|
|
return 0;
|
|
},
|
|
"Image Processor"sv))
|
|
, m_wakeup_variable(m_wakeup_mutex)
|
|
{
|
|
}
|
|
|
|
ImageProcessor* ImageProcessor::the()
|
|
{
|
|
return s_image_processor;
|
|
}
|
|
|
|
ErrorOr<void> ImageProcessor::enqueue_command(NonnullRefPtr<ImageProcessingCommand> command)
|
|
{
|
|
if (auto queue_status = m_command_queue.try_enqueue(move(command)); queue_status.is_error())
|
|
return ENOSPC;
|
|
|
|
if (!m_processor_thread->is_started()) {
|
|
m_processor_thread->start();
|
|
m_processor_thread->detach();
|
|
}
|
|
|
|
m_wakeup_mutex.lock();
|
|
m_wakeup_variable.signal();
|
|
m_wakeup_mutex.unlock();
|
|
|
|
return {};
|
|
}
|
|
|
|
}
|