C
Qt Quick におけるメモリ割り当てUltraliteプラットフォームの抽象化
Qt Quick Ultralite コアライブラリは、大規模なメモリ割り当てにメモリアロケーター API を使用します。この API により、さまざまな目的に合わせて、メモリをどのように、どこに割り当てるかをより細かく制御できます。たとえば、一部のプラットフォームでは、画像データを VRAM に格納するのが合理的である場合があります。 また、このAPIでは、Qt Quick Ultraliteコアライブラリに対し、メモリへの書き込み前後に明示的にメモリの取得と解放を行うことを要求しており、これによりプラットフォーム側で必要な同期処理が行われるようになっています。
メモリアロケータの例
以下に、メモリアロケーターの例を示します。
class ExampleMemoryAllocator : public PlatformInterface::MemoryAllocator { public: void *allocate(std::size_t size, UsagePattern) QUL_DECL_OVERRIDE { void *ptr = NULL; // ptr = HW_VideoMemAlloc(size); return ptr; } void *reallocate(void *ptr, std::size_t size) QUL_DECL_OVERRIDE { void *new_ptr = NULL; // new_ptr = HW_VideoMemRealloc(ptr, size); return new_ptr; } void free(void *ptr) QUL_DECL_OVERRIDE { // HW_VideoMemFree(ptr); } void acquire(void * /* ptr */, std::size_t /* offset */, std::size_t /* size */) QUL_DECL_OVERRIDE { // WaitForLcdUpdateComplete(); } };
この例では、通常のメモリではなくビデオメモリを割り当てるためのハードウェアAPIが利用可能であることを前提としています。ただし、カスタムプラットフォームへの移植では、他のメモリ領域を使用することも考えられます。
`MemoryAllocator::acquire `関数のオーバーライドは、PlatformInterface::MemoryAllocator APIで割り当てられたメモリバッファへの書き込み前に呼び出されます。一部のハードウェアではメモリ帯域幅が制限されている場合があります。例えば、LCDディスプレイコントローラがフレームバッファをスキャンしている間はSDRAMへの書き込みができないといったケースです。その場合、プラットフォームはLCDの更新が完了するまで待機し、その後でSDRAMへの書き込みを許可するように選択できます。
次に、PlatformContext::memoryAllocator 関数の実装例を示します。
PlatformInterface::MemoryAllocator *ExamplePlatform::memoryAllocator( PlatformInterface::MemoryAllocator::AllocationType type) { static ExampleMemoryAllocator exampleMemoryAllocator; static ExampleReversePreloadAllocator<4> examplePreloadAllocator(preloadSdramEnd, preloadSdramStart); static PlatformInterface::MemoryAllocator defaultMemoryAllocator; switch (type) { case PlatformInterface::MemoryAllocator::Image: return &exampleMemoryAllocator; case PlatformInterface::MemoryAllocator::DefaultPreload: return &examplePreloadAllocator; default: return &defaultMemoryAllocator; } }
ここでは、画像の割り当てには前述のメモリアロケータの例を使用しますが、その他の割り当てについてはデフォルトの実装にフォールバックします。デフォルトの実装は、制御をPlatform::qul_malloc 、Platform::qul_realloc 、およびPlatform::qul_free 関数に委譲します。
リバースプリロードアロケータの例
プリロード可能なリソースはプラットフォームの初期化時に一度だけ読み込まれるため、この目的にはよりシンプルなアロケータを使用できます。 たとえば、メモリの再割り当てや解放は不要であるため、これらをサポートする必要はありません。リバースアロケータを使用すると、プリロードメモリはセクションの末尾から始まり、セクションの先頭に向かって拡大していきます。これは、たとえば、プリロードメモリがヒープメモリが存在する方向と同じ方向に拡大するのを避ける場合に役立ちます。
以下に、逆プリロードアロケータの例を示します:
template<std::size_t ALIGNMENT> class ExampleReversePreloadAllocator : public PlatformInterface::MemoryAllocator { public: ExampleReversePreloadAllocator(void *endAddress, void *startAddress = NULL) : m_currentAddress(endAddress) , m_startAddress(startAddress) {} void *allocate(std::size_t size, UsagePattern) QUL_DECL_OVERRIDE { m_currentAddress = static_cast<char *>(m_currentAddress) - size; m_currentAddress = static_cast<char *>(m_currentAddress) - (reinterpret_cast<uintptr_t>(m_currentAddress) % ALIGNMENT); if (m_startAddress && m_currentAddress < m_startAddress) return NULL; return m_currentAddress; } // Reallocating is not supported in preloading void *reallocate(void *, std::size_t) QUL_DECL_OVERRIDE { QUL_ASSERT(false, QulError_PreloadAllocator_UnsupportedOperation); return NULL; }; // Preallocated assets are not freed void free(void *) QUL_DECL_OVERRIDE { QUL_ASSERT(false, QulError_PreloadAllocator_UnsupportedOperation); }; void acquire(void *, std::size_t, std::size_t) QUL_DECL_OVERRIDE { QUL_ASSERT(false, QulError_PreloadAllocator_UnsupportedOperation); }; void release(void *, std::size_t, std::size_t) QUL_DECL_OVERRIDE { QUL_ASSERT(false, QulError_PreloadAllocator_UnsupportedOperation); }; private: void *m_currentAddress; const void *m_startAddress; };
高速なメモリ割り当て
Platform::StackAllocator を使用すると、通常の割り当てよりも高速に短期メモリを割り当てることができます。使用例はits class documentation に掲載されています。
アロケーターを準備するために、静的メモリを事前に割り当てます。これは、固定量のメモリを確保し、l{Qul::Platform::}{StackAllocator} の静的メンバーを初期化することで行われます。
static char qul_scratch_buffer[16 * 1024]; char *StackAllocator::m_buffer = qul_scratch_buffer; char *StackAllocator::m_top = StackAllocator::m_buffer; int32_t StackAllocator::m_size = sizeof(qul_scratch_buffer);
前述の例のコードでは、16kBのバッファを確保し、そのポインタとサイズをStackAllocator に設定しています。
注: Qt Quick Ultralite コアライブラリがスタックアロケータを使用できるようにするには、スタックアロケータを 初期化する必要があります。
特定の Qt ライセンスで利用可能です。
詳細はこちらをご覧ください。