#pragma once #include "ffmpegbuffer.h" #include #include #include #include #include #include #include EMSCRIPTEN_DECLARE_VAL_TYPE(AsyncWaitResult); EMSCRIPTEN_DECLARE_VAL_TYPE(MipMapOutputBuffers); class AsyncWaitPolyfill { bool hasWaitAsync; emscripten::val atomics; emscripten::val getGrowableHeapI32; public: AsyncWaitPolyfill(); AsyncWaitResult waitAsync(uintptr_t address, uint32_t expectedValue, double timeout) const; }; class MipMapRequest { // arguments std::shared_ptr buffer; int mipMapLevel; int start; int end; // results int blocksProduced; std::optional continueFrom; std::array, 2> outputs; // synchronization uint32_t status; // 0: queued, 1: completed, 2: cancelled void finalize(int finalStatus); static std::vector makeSharedMinMaxArray(int blockCount); AsyncWaitPolyfill asyncWaitPolyfill; public: MipMapRequest(std::shared_ptr &&buffer, int mipMapLevel, int start, int end); ~MipMapRequest(); MipMapRequest(const MipMapRequest &) = delete; MipMapRequest(MipMapRequest &&) = delete; MipMapRequest &operator=(const MipMapRequest &) = delete; MipMapRequest &operator=(MipMapRequest &&) = delete; int getStatus() const; int getBlocksProduced() const; std::optional getContinueFrom() const; MipMapOutputBuffers getOutputBuffers() const; void cancel(); AsyncWaitResult waitAsync() const; void run(); }; class MipMapWorker { constexpr static const int QUEUE_LIMIT = 100; std::unordered_map> bufferCache; emscripten_lock_t bufferCacheLock; emscripten_lock_t lock; emscripten_condvar_t condvar; std::deque> workQueue; static void mipMapWorkerStart(int payloadPtr); std::shared_ptr getBufferCached(const std::string &uuid); std::shared_ptr waitForWork(); void workerEntrypoint(); public: MipMapWorker(); ~MipMapWorker(); MipMapWorker(const MipMapWorker &) = delete; MipMapWorker(MipMapWorker &&) = delete; MipMapWorker &operator=(const MipMapWorker &) = delete; MipMapWorker &operator=(MipMapWorker &&) = delete; std::shared_ptr createRequest(const std::string &uuid, int mipMapLevel, int start, int end); };