Commit 5928aa99 authored by David Reid's avatar David Reid

Add support for pre-allocation to engine nodes.

parent bf1b5183
...@@ -1878,8 +1878,14 @@ typedef struct ...@@ -1878,8 +1878,14 @@ typedef struct
MA_ATOMIC ma_bool8 isPitchDisabled; /* When set to true, pitching will be disabled which will allow the resampler to be bypassed to save some computation. */ MA_ATOMIC ma_bool8 isPitchDisabled; /* When set to true, pitching will be disabled which will allow the resampler to be bypassed to save some computation. */
MA_ATOMIC ma_bool8 isSpatializationDisabled; /* Set to false by default. When set to false, will not have spatialisation applied. */ MA_ATOMIC ma_bool8 isSpatializationDisabled; /* Set to false by default. When set to false, will not have spatialisation applied. */
MA_ATOMIC ma_uint8 pinnedListenerIndex; /* The index of the listener this node should always use for spatialization. If set to (ma_uint8)-1 the engine will use the closest listener. */ MA_ATOMIC ma_uint8 pinnedListenerIndex; /* The index of the listener this node should always use for spatialization. If set to (ma_uint8)-1 the engine will use the closest listener. */
/* Memory management. */
void* _pHeap;
ma_bool32 _ownsHeap;
} ma_engine_node; } ma_engine_node;
MA_API ma_result ma_engine_node_get_heap_size(const ma_engine_node_config* pConfig, size_t* pHeapSizeInBytes);
MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* pConfig, void* pHeap, ma_engine_node* pEngineNode);
MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_engine_node* pEngineNode); MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_engine_node* pEngineNode);
MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocation_callbacks* pAllocationCallbacks); MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocation_callbacks* pAllocationCallbacks);
...@@ -12329,60 +12335,139 @@ static ma_node_vtable g_ma_engine_node_vtable__group = ...@@ -12329,60 +12335,139 @@ static ma_node_vtable g_ma_engine_node_vtable__group =
MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES /* The engine node does resampling so should let miniaudio know about it. */ MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES /* The engine node does resampling so should let miniaudio know about it. */
}; };
MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_engine_node* pEngineNode)
static ma_node_config ma_engine_node_base_node_config_init(const ma_engine_node_config* pConfig)
{
ma_node_config baseNodeConfig;
if (pConfig->type == ma_engine_node_type_sound) {
/* Sound. */
baseNodeConfig = ma_node_config_init();
baseNodeConfig.vtable = &g_ma_engine_node_vtable__sound;
baseNodeConfig.initialState = ma_node_state_stopped; /* Sounds are stopped by default. */
} else {
/* Group. */
baseNodeConfig = ma_node_config_init();
baseNodeConfig.vtable = &g_ma_engine_node_vtable__group;
baseNodeConfig.initialState = ma_node_state_started; /* Groups are started by default. */
}
return baseNodeConfig;
}
static ma_spatializer_config ma_engine_node_spatializer_config_init(const ma_node_config* pBaseNodeConfig)
{
return ma_spatializer_config_init(pBaseNodeConfig->pInputChannels[0], pBaseNodeConfig->pOutputChannels[0]);
}
typedef struct
{
size_t sizeInBytes;
size_t baseNodeOffset;
size_t spatializerOffset;
} ma_engine_node_heap_layout;
static ma_result ma_engine_node_get_heap_layout(const ma_engine_node_config* pConfig, ma_engine_node_heap_layout* pHeapLayout)
{ {
ma_result result; ma_result result;
size_t tempHeapSize;
ma_node_config baseNodeConfig; ma_node_config baseNodeConfig;
ma_resampler_config resamplerConfig;
ma_fader_config faderConfig;
ma_spatializer_config spatializerConfig; ma_spatializer_config spatializerConfig;
ma_panner_config pannerConfig;
ma_uint32 channelsIn; ma_uint32 channelsIn;
ma_uint32 channelsOut; ma_uint32 channelsOut;
if (pEngineNode == NULL) { MA_ASSERT(pHeapLayout);
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pEngineNode); MA_ZERO_OBJECT(pHeapLayout);
if (pConfig == NULL) { if (pConfig == NULL) {
return MA_INVALID_ARGS; /* Config must be specified. */ return MA_INVALID_ARGS;
} }
if (pConfig->pEngine == NULL) { if (pConfig->pEngine == NULL) {
return MA_INVALID_ARGS; /* An engine must be specified. */ return MA_INVALID_ARGS; /* An engine must be specified. */
} }
if (pConfig->pinnedListenerIndex != (ma_uint8)-1 && pConfig->pinnedListenerIndex >= ma_engine_get_listener_count(pConfig->pEngine)) { pHeapLayout->sizeInBytes = 0;
return MA_INVALID_ARGS; /* Invalid listener. */
}
/* Assume the engine channel count if no channels were specified. */
channelsIn = (pConfig->channelsIn != 0) ? pConfig->channelsIn : ma_engine_get_channels(pConfig->pEngine); channelsIn = (pConfig->channelsIn != 0) ? pConfig->channelsIn : ma_engine_get_channels(pConfig->pEngine);
channelsOut = (pConfig->channelsOut != 0) ? pConfig->channelsOut : ma_engine_get_channels(pConfig->pEngine); channelsOut = (pConfig->channelsOut != 0) ? pConfig->channelsOut : ma_engine_get_channels(pConfig->pEngine);
if (pConfig->type == ma_engine_node_type_sound) {
/* Sound. */ /* Base node. */
baseNodeConfig = ma_node_config_init(); baseNodeConfig = ma_engine_node_base_node_config_init(pConfig);
baseNodeConfig.vtable = &g_ma_engine_node_vtable__sound; baseNodeConfig.pInputChannels = &channelsIn;
baseNodeConfig.pInputChannels = &channelsIn; baseNodeConfig.pOutputChannels = &channelsOut;
baseNodeConfig.pOutputChannels = &channelsOut;
baseNodeConfig.initialState = ma_node_state_stopped; /* Sounds are stopped by default. */ pHeapLayout->baseNodeOffset = pHeapLayout->sizeInBytes;
} else { pHeapLayout->sizeInBytes += 0; /* TODO: Implement pre-allocation for nodes. */
/* Group. */
baseNodeConfig = ma_node_config_init();
baseNodeConfig.vtable = &g_ma_engine_node_vtable__group; /* Spatializer. */
baseNodeConfig.pInputChannels = &channelsIn; spatializerConfig = ma_engine_node_spatializer_config_init(&baseNodeConfig);
baseNodeConfig.pOutputChannels = &channelsOut;
baseNodeConfig.initialState = ma_node_state_started; /* Groups are started by default. */ result = ma_spatializer_get_heap_size(&spatializerConfig, &tempHeapSize);
if (result != MA_SUCCESS) {
return result; /* Failed to retrieve the size of the heap for the spatializer. */
} }
result = ma_node_init(&pConfig->pEngine->nodeGraph, &baseNodeConfig, pAllocationCallbacks, &pEngineNode->baseNode); pHeapLayout->spatializerOffset = pHeapLayout->sizeInBytes;
pHeapLayout->sizeInBytes += tempHeapSize;
return MA_SUCCESS;
}
MA_API ma_result ma_engine_node_get_heap_size(const ma_engine_node_config* pConfig, size_t* pHeapSizeInBytes)
{
ma_result result;
ma_engine_node_heap_layout heapLayout;
if (pHeapSizeInBytes == NULL) {
return MA_INVALID_ARGS;
}
*pHeapSizeInBytes = 0;
result = ma_engine_node_get_heap_layout(pConfig, &heapLayout);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
goto error0; return result;
}
*pHeapSizeInBytes = heapLayout.sizeInBytes;
return MA_SUCCESS;
}
MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* pConfig, void* pHeap, ma_engine_node* pEngineNode)
{
ma_result result;
ma_engine_node_heap_layout heapLayout;
ma_node_config baseNodeConfig;
ma_resampler_config resamplerConfig;
ma_fader_config faderConfig;
ma_spatializer_config spatializerConfig;
ma_panner_config pannerConfig;
ma_uint32 channelsIn;
ma_uint32 channelsOut;
if (pEngineNode == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pEngineNode);
result = ma_engine_node_get_heap_layout(pConfig, &heapLayout);
if (result != MA_SUCCESS) {
return result;
}
if (pConfig->pinnedListenerIndex != (ma_uint8)-1 && pConfig->pinnedListenerIndex >= ma_engine_get_listener_count(pConfig->pEngine)) {
return MA_INVALID_ARGS; /* Invalid listener. */
} }
pEngineNode->_pHeap = pHeap;
pEngineNode->pEngine = pConfig->pEngine; pEngineNode->pEngine = pConfig->pEngine;
pEngineNode->sampleRate = (pConfig->sampleRate > 0) ? pConfig->sampleRate : ma_engine_get_sample_rate(pEngineNode->pEngine); pEngineNode->sampleRate = (pConfig->sampleRate > 0) ? pConfig->sampleRate : ma_engine_get_sample_rate(pEngineNode->pEngine);
pEngineNode->pitch = 1; pEngineNode->pitch = 1;
...@@ -12392,6 +12477,22 @@ MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ...@@ -12392,6 +12477,22 @@ MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const
pEngineNode->isSpatializationDisabled = pConfig->isSpatializationDisabled; pEngineNode->isSpatializationDisabled = pConfig->isSpatializationDisabled;
pEngineNode->pinnedListenerIndex = pConfig->pinnedListenerIndex; pEngineNode->pinnedListenerIndex = pConfig->pinnedListenerIndex;
channelsIn = (pConfig->channelsIn != 0) ? pConfig->channelsIn : ma_engine_get_channels(pConfig->pEngine);
channelsOut = (pConfig->channelsOut != 0) ? pConfig->channelsOut : ma_engine_get_channels(pConfig->pEngine);
/* Base node. */
baseNodeConfig = ma_engine_node_base_node_config_init(pConfig);
baseNodeConfig.pInputChannels = &channelsIn;
baseNodeConfig.pOutputChannels = &channelsOut;
result = ma_node_init(&pConfig->pEngine->nodeGraph, &baseNodeConfig, &pEngineNode->pEngine->allocationCallbacks, &pEngineNode->baseNode); /* TODO: Implement pre-allocation for nodes. */
if (result != MA_SUCCESS) {
goto error0;
}
/* /*
We can now initialize the effects we need in order to implement the engine node. There's a We can now initialize the effects we need in order to implement the engine node. There's a
defined order of operations here, mainly centered around when we convert our channels from the defined order of operations here, mainly centered around when we convert our channels from the
...@@ -12423,10 +12524,10 @@ MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ...@@ -12423,10 +12524,10 @@ MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const
Spatialization comes next. We spatialize based ont he node's output channel count. It's up the caller to Spatialization comes next. We spatialize based ont he node's output channel count. It's up the caller to
ensure channels counts link up correctly in the node graph. ensure channels counts link up correctly in the node graph.
*/ */
spatializerConfig = ma_spatializer_config_init(baseNodeConfig.pInputChannels[0], baseNodeConfig.pOutputChannels[0]); spatializerConfig = ma_engine_node_spatializer_config_init(&baseNodeConfig);
spatializerConfig.gainSmoothTimeInFrames = pEngineNode->pEngine->gainSmoothTimeInFrames; spatializerConfig.gainSmoothTimeInFrames = pEngineNode->pEngine->gainSmoothTimeInFrames;
result = ma_spatializer_init(&spatializerConfig, pAllocationCallbacks, &pEngineNode->spatializer); /* TODO: Use a preallocated heap for this. */ result = ma_spatializer_init_preallocated(&spatializerConfig, ma_offset_ptr(pHeap, heapLayout.spatializerOffset), &pEngineNode->spatializer);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
goto error2; goto error2;
} }
...@@ -12440,16 +12541,47 @@ MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ...@@ -12440,16 +12541,47 @@ MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const
result = ma_panner_init(&pannerConfig, &pEngineNode->panner); result = ma_panner_init(&pannerConfig, &pEngineNode->panner);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
goto error2; goto error3;
} }
return MA_SUCCESS; return MA_SUCCESS;
error3: ma_spatializer_uninit(&pEngineNode->spatializer, NULL); /* <-- No need for allocation callbacks here because we use a preallocated heap. */
error2: ma_resampler_uninit(&pEngineNode->resampler); error2: ma_resampler_uninit(&pEngineNode->resampler);
error1: ma_node_uninit(&pEngineNode->baseNode, pAllocationCallbacks); error1: ma_node_uninit(&pEngineNode->baseNode, NULL); /* <-- No need for allocation callbacks here because we use a preallocated heap. */
error0: return result; error0: return result;
} }
MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_engine_node* pEngineNode)
{
ma_result result;
size_t heapSizeInBytes;
void* pHeap;
result = ma_engine_node_get_heap_size(pConfig, &heapSizeInBytes);
if (result != MA_SUCCESS) {
return result;
}
if (heapSizeInBytes > 0) {
pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
if (pHeap == NULL) {
return MA_OUT_OF_MEMORY;
}
} else {
pHeap = NULL;
}
result = ma_engine_node_init_preallocated(pConfig, pHeap, pEngineNode);
if (result != MA_SUCCESS) {
ma_free(pHeap, pAllocationCallbacks);
return result;
}
pEngineNode->_ownsHeap = MA_TRUE;
return MA_SUCCESS;
}
MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocation_callbacks* pAllocationCallbacks) MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocation_callbacks* pAllocationCallbacks)
{ {
/* /*
...@@ -12459,7 +12591,13 @@ MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocati ...@@ -12459,7 +12591,13 @@ MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocati
ma_node_uninit(&pEngineNode->baseNode, pAllocationCallbacks); ma_node_uninit(&pEngineNode->baseNode, pAllocationCallbacks);
/* Now that the node has been uninitialized we can safely uninitialize the rest. */ /* Now that the node has been uninitialized we can safely uninitialize the rest. */
ma_spatializer_uninit(&pEngineNode->spatializer, NULL);
ma_resampler_uninit(&pEngineNode->resampler); ma_resampler_uninit(&pEngineNode->resampler);
/* Free the heap last. */
if (pEngineNode->_pHeap != NULL && pEngineNode->_ownsHeap) {
ma_free(pEngineNode->_pHeap, pAllocationCallbacks);
}
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment