このページでは

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があると仮定している。この例では、通常のメモリーの代わりにビデオメモリーを割り当てるハードウェアAPIがあることを想定しています。

PlatformInterface::MemoryAllocator API で割り当てられたメモリ・バッファに書き込む前に、MemoryAllocator::acquire 関数のオーバーライドが呼び出されます。ハードウェアによっては、メモリ帯域幅が制限されている場合があります。たとえば、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_mallocPlatform::qul_reallocPlatform::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 ライセンスの下で利用可能です。
詳細はこちら。