// SPDX-License-Identifier: Apache-2.0 // ---------------------------------------------------------------------------- // Copyright 2011-2024 Arm Limited // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy // of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. // ---------------------------------------------------------------------------- /** * @brief Functions and data declarations for the outer context. * * The outer context includes thread-pool management, which is slower to * compile due to increased use of C++ stdlib. The inner context used in the * majority of the codec library does not include this. */ #ifndef ASTCENC_INTERNAL_ENTRY_INCLUDED #define ASTCENC_INTERNAL_ENTRY_INCLUDED #include <atomic> #include <condition_variable> #include <functional> #include <mutex> #include "astcenc_internal.h" /* ============================================================================ Parallel execution control ============================================================================ */ /** * @brief A simple counter-based manager for parallel task execution. * * The task processing execution consists of: * * * A single-threaded init stage. * * A multi-threaded processing stage. * * A condition variable so threads can wait for processing completion. * * The init stage will be executed by the first thread to arrive in the critical section, there is * no main thread in the thread pool. * * The processing stage uses dynamic dispatch to assign task tickets to threads on an on-demand * basis. Threads may each therefore executed different numbers of tasks, depending on their * processing complexity. The task queue and the task tickets are just counters; the caller must map * these integers to an actual processing partition in a specific problem domain. * * The exit wait condition is needed to ensure processing has finished before a worker thread can * progress to the next stage of the pipeline. Specifically a worker may exit the processing stage * because there are no new tasks to assign to it while other worker threads are still processing. * Calling @c wait() will ensure that all other worker have finished before the thread can proceed. * * The basic usage model: * * // --------- From single-threaded code --------- * * // Reset the tracker state * manager->reset() * * // --------- From multi-threaded code --------- * * // Run the stage init; only first thread actually runs the lambda * manager->init(<lambda>) * * do * { * // Request a task assignment * uint task_count; * uint base_index = manager->get_tasks(<granule>, task_count); * * // Process any tasks we were given (task_count <= granule size) * if (task_count) * { * // Run the user task processing code for N tasks here * ... * * // Flag these tasks as complete * manager->complete_tasks(task_count); * } * } while (task_count); * * // Wait for all threads to complete tasks before progressing * manager->wait() * * // Run the stage term; only first thread actually runs the lambda * manager->term(<lambda>) */ class ParallelManager { … }; /** * @brief The astcenc compression context. */ struct astcenc_context { … }; #endif