Replaced tile based memory manager with a single aligned buffer

- should increase speed with large node setups
 - enables caching of buffers in the node editor (in the future)
 - OpenCL part still needs some work
This commit is contained in:
Monique Dewanchand 2012-06-01 10:20:24 +00:00
parent a78dca27a2
commit 285a24b3e0
16 changed files with 92 additions and 474 deletions

@ -79,10 +79,6 @@ set(SRC
intern/COM_MemoryProxy.h
intern/COM_MemoryBuffer.cpp
intern/COM_MemoryBuffer.h
intern/COM_MemoryManager.cpp
intern/COM_MemoryManager.h
intern/COM_MemoryManagerState.cpp
intern/COM_MemoryManagerState.h
intern/COM_WorkScheduler.cpp
intern/COM_WorkScheduler.h
intern/COM_WorkPackage.cpp

@ -29,14 +29,10 @@ void CPUDevice::execute(WorkPackage *work)
rcti rect;
executionGroup->determineChunkRect(&rect, chunkNumber);
MemoryBuffer ** inputBuffers = executionGroup->getInputBuffers(chunkNumber);
MemoryBuffer * outputBuffer = executionGroup->allocateOutputBuffer(chunkNumber, &rect);
MemoryBuffer ** inputBuffers = executionGroup->getInputBuffersCPU();
executionGroup->getOutputNodeOperation()->executeRegion(&rect, chunkNumber, inputBuffers);
executionGroup->finalizeChunkExecution(chunkNumber, inputBuffers);
if (outputBuffer != NULL) {
outputBuffer->setCreatedState();
}
}

@ -34,7 +34,6 @@
#include "COM_ViewerOperation.h"
#include <stdlib.h>
#include "BLI_math.h"
#include "COM_MemoryManager.h"
#include "PIL_time.h"
#include "COM_ChunkOrder.h"
#include <algorithm>
@ -362,7 +361,24 @@ void ExecutionGroup::execute(ExecutionSystem *graph)
delete[] chunkOrder;
}
MemoryBuffer** ExecutionGroup::getInputBuffers(int chunkNumber)
MemoryBuffer** ExecutionGroup::getInputBuffersCPU()
{
vector<MemoryProxy*> memoryproxies;
unsigned int index;
this->determineDependingMemoryProxies(&memoryproxies);
MemoryBuffer **memoryBuffers = new MemoryBuffer*[this->cachedMaxReadBufferOffset];
for (index = 0 ; index < this->cachedMaxReadBufferOffset ; index ++) {
memoryBuffers[index] = NULL;
}
for (index = 0 ; index < this->cachedReadOperations.size(); index ++) {
ReadBufferOperation *readOperation = (ReadBufferOperation*)this->cachedReadOperations[index];
memoryBuffers[readOperation->getOffset()] = readOperation->getMemoryProxy()->getBuffer();
}
return memoryBuffers;
}
MemoryBuffer** ExecutionGroup::getInputBuffersOpenCL(int chunkNumber)
{
rcti rect;
vector<MemoryProxy*> memoryproxies;
@ -385,6 +401,8 @@ MemoryBuffer** ExecutionGroup::getInputBuffers(int chunkNumber)
return memoryBuffers;
}
// @todo: for opencl the memory buffers size needs to be same as the needed size
// currently this method is not called, but will be when opencl nodes are created
MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *memoryProxy, rcti *rect)
{
// find all chunks inside the rect
@ -399,8 +417,7 @@ MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *mem
const int maxychunk = ceil((rect->ymax-1)/chunkSizef);
if (maxxchunk== minxchunk+1 && maxychunk == minychunk+1) {
const int chunkNumber = minxchunk+minychunk*numberOfXChunks;
MemoryBuffer *result = MemoryManager::getMemoryBuffer(memoryProxy, chunkNumber);
MemoryBuffer *result =memoryProxy->getBuffer();
return result;
}
@ -420,7 +437,7 @@ MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *mem
for (indexx = max(minxchunk, 0); indexx<min((int)this->numberOfXChunks, maxxchunk) ; indexx++) {
for (indexy = max(minychunk, 0); indexy<min((int)this->numberOfYChunks, maxychunk) ; indexy++) {
int chunkNumber = indexx+indexy*this->numberOfXChunks;
MemoryBuffer *chunkBuffer = MemoryManager::getMemoryBuffer(memoryProxy, chunkNumber);
MemoryBuffer *chunkBuffer = memoryProxy->getBuffer();
result->copyContentFrom(chunkBuffer);
}
}
@ -432,8 +449,6 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer** memo
{
if (this->chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED)
this->chunkExecutionStates[chunkNumber] = COM_ES_EXECUTED;
else
throw "Threading inconsistency";
this->chunksFinished++;
if (memoryBuffers) {
@ -477,7 +492,7 @@ MemoryBuffer *ExecutionGroup::allocateOutputBuffer(int chunkNumber, rcti *rect)
NodeOperation * operation = this->getOutputNodeOperation();
if (operation->isWriteBufferOperation()) {
WriteBufferOperation *writeOperation = (WriteBufferOperation*)operation;
outputBuffer = MemoryManager::allocateMemoryBuffer(writeOperation->getMemoryProxy(), chunkNumber, rect);
// @todo outputBuffer = MemoryManager::allocateMemoryBuffer(writeOperation->getMemoryProxy(), chunkNumber, rect);
}
return outputBuffer;
}

@ -334,8 +334,16 @@ public:
* @param chunkNumber the chunk to be calculated
* @return MemoryBuffer** the inputbuffers
*/
MemoryBuffer** getInputBuffers(int chunkNumber);
MemoryBuffer** getInputBuffersCPU();
/**
* @brief get all inputbuffers needed to calculate an chunk
* @note all inputbuffers must be executed
* @param chunkNumber the chunk to be calculated
* @return MemoryBuffer** the inputbuffers
*/
MemoryBuffer** getInputBuffersOpenCL(int chunkNumber);
/**
* @brief allocate the outputbuffer of a chunk
* @param chunkNumber the number of the chunk in the ExecutionGroup

@ -31,7 +31,6 @@
#include "COM_NodeBase.h"
#include "COM_WorkScheduler.h"
#include "COM_ReadBufferOperation.h"
#include "COM_MemoryManager.h"
#include "stdio.h"
#include "COM_GroupNode.h"
#include "COM_WriteBufferOperation.h"
@ -114,8 +113,6 @@ void ExecutionSystem::execute()
order ++;
}
}
MemoryManager::initialize();
unsigned int index;
for (index = 0 ; index < this->operations.size() ; index ++) {
@ -156,7 +153,6 @@ void ExecutionSystem::execute()
ExecutionGroup * executionGroup = this->groups[index];
executionGroup->deinitExecution();
}
MemoryManager::clear();
}
void ExecutionSystem::addOperation(NodeOperation *operation)

@ -31,7 +31,6 @@
#include "COM_NodeBase.h"
#include "COM_WorkScheduler.h"
#include "COM_ReadBufferOperation.h"
#include "COM_MemoryManager.h"
#include "stdio.h"
#include "COM_GroupNode.h"
#include "COM_WriteBufferOperation.h"

@ -44,7 +44,7 @@ MemoryBuffer::MemoryBuffer(MemoryProxy * memoryProxy, unsigned int chunkNumber,
BLI_init_rcti(&this->rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax);
this->memoryProxy = memoryProxy;
this->chunkNumber = chunkNumber;
this->buffer = (float*)MEM_mallocN(sizeof(float)*determineBufferSize()*4, "COM_MemoryBuffer");
this->buffer = (float*)MEM_mallocN(sizeof(float)*determineBufferSize()*COM_NUMBER_OF_CHANNELS, "COM_MemoryBuffer");
this->state = COM_MB_ALLOCATED;
this->datatype = COM_DT_COLOR;
this->chunkWidth = this->rect.xmax - this->rect.xmin;
@ -55,7 +55,7 @@ MemoryBuffer::MemoryBuffer(MemoryProxy * memoryProxy, rcti *rect)
BLI_init_rcti(&this->rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax);
this->memoryProxy = memoryProxy;
this->chunkNumber = -1;
this->buffer = (float*)MEM_mallocN(sizeof(float)*determineBufferSize()*4, "COM_MemoryBuffer");
this->buffer = (float*)MEM_mallocN(sizeof(float)*determineBufferSize()*COM_NUMBER_OF_CHANNELS, "COM_MemoryBuffer");
this->state = COM_MB_TEMPORARILY;
this->datatype = COM_DT_COLOR;
this->chunkWidth = this->rect.xmax - this->rect.xmin;
@ -63,12 +63,12 @@ MemoryBuffer::MemoryBuffer(MemoryProxy * memoryProxy, rcti *rect)
MemoryBuffer *MemoryBuffer::duplicate()
{
MemoryBuffer *result = new MemoryBuffer(this->memoryProxy, &this->rect);
memcpy(result->buffer, this->buffer, this->determineBufferSize()*4*sizeof(float));
memcpy(result->buffer, this->buffer, this->determineBufferSize()*COM_NUMBER_OF_CHANNELS*sizeof(float));
return result;
}
void MemoryBuffer::clear()
{
memset(this->buffer, 0, this->determineBufferSize()*4*sizeof(float));
memset(this->buffer, 0, this->determineBufferSize()*COM_NUMBER_OF_CHANNELS*sizeof(float));
}
float *MemoryBuffer::convertToValueBuffer()
@ -77,7 +77,7 @@ float *MemoryBuffer::convertToValueBuffer()
int i;
int offset4;
float *result = new float[size];
for (i = 0, offset4 = 0 ; i < size ; i ++, offset4 +=4) {
for (i = 0, offset4 = 0 ; i < size ; i ++, offset4 +=COM_NUMBER_OF_CHANNELS) {
result[i] = this->buffer[offset4];
}
@ -107,9 +107,9 @@ void MemoryBuffer::copyContentFrom(MemoryBuffer *otherBuffer)
for (otherY = minY ; otherY<maxY ; otherY ++) {
otherOffset = ((otherY-otherBuffer->rect.ymin) * otherBuffer->chunkWidth + minX-otherBuffer->rect.xmin)*4;
offset = ((otherY - this->rect.ymin) * this->chunkWidth + minX-this->rect.xmin)*4;
memcpy(&this->buffer[offset], &otherBuffer->buffer[otherOffset], (maxX-minX) * 4*sizeof(float));
otherOffset = ((otherY-otherBuffer->rect.ymin) * otherBuffer->chunkWidth + minX-otherBuffer->rect.xmin)*COM_NUMBER_OF_CHANNELS;
offset = ((otherY - this->rect.ymin) * this->chunkWidth + minX-this->rect.xmin)*COM_NUMBER_OF_CHANNELS;
memcpy(&this->buffer[offset], &otherBuffer->buffer[otherOffset], (maxX-minX) * COM_NUMBER_OF_CHANNELS*sizeof(float));
}
}
@ -119,7 +119,7 @@ void MemoryBuffer::read(float *result, int x, int y)
y>=this->rect.ymin && y < this->rect.ymax) {
int dx = x-this->rect.xmin;
int dy = y-this->rect.ymin;
int offset = (this->chunkWidth*dy+dx)*4;
int offset = (this->chunkWidth*dy+dx)*COM_NUMBER_OF_CHANNELS;
result[0] = this->buffer[offset];
result[1] = this->buffer[offset+1];
result[2] = this->buffer[offset+2];
@ -136,7 +136,7 @@ void MemoryBuffer::writePixel(int x, int y, float color[4])
{
if (x>=this->rect.xmin && x < this->rect.xmax &&
y>=this->rect.ymin && y < this->rect.ymax) {
int offset = (this->chunkWidth*y+x)*4;
int offset = (this->chunkWidth*y+x)*COM_NUMBER_OF_CHANNELS;
this->buffer[offset] = color[0];
this->buffer[offset+1] = color[1];
this->buffer[offset+2] = color[2];

@ -1,74 +0,0 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor:
* Jeroen Bakker
* Monique Dewanchand
*/
#include "COM_MemoryManager.h"
#include "BLI_threads.h"
#include <stdio.h>
#include "COM_defines.h"
vector<MemoryBuffer*> buffers;
ThreadMutex mutex;
MemoryBuffer *MemoryManager::allocateMemoryBuffer(MemoryProxy *id, unsigned int chunkNumber, rcti *rect)
{
MemoryBuffer *result = new MemoryBuffer(id, chunkNumber, rect);
MemoryManagerState * state = MemoryManager::getState(id);
state->addMemoryBuffer(result);
BLI_mutex_lock(&mutex);
buffers.push_back(result);
BLI_mutex_unlock(&mutex);
return result;
}
void MemoryManager::addMemoryProxy(MemoryProxy *memoryProxy)
{
MemoryManagerState * state = MemoryManager::getState(memoryProxy);
if (!state) {
state = new MemoryManagerState(memoryProxy);
memoryProxy->setState(state);
}
}
MemoryBuffer *MemoryManager::getMemoryBuffer(MemoryProxy *id, unsigned int chunkNumber)
{
MemoryManagerState * state = MemoryManager::getState(id);
if (!state) {
return NULL;
}
MemoryBuffer *buffer = state->getMemoryBuffer(chunkNumber);
if (!buffer) return NULL;
return buffer;
}
MemoryManagerState *MemoryManager::getState(MemoryProxy *memoryProxy)
{
return memoryProxy->getState();
}
void MemoryManager::initialize()
{
BLI_mutex_init(&mutex);
}
void MemoryManager::clear()
{
buffers.clear();
BLI_mutex_end(&mutex);
}

@ -1,146 +0,0 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor:
* Jeroen Bakker
* Monique Dewanchand
*/
#ifndef _COM_MemoryManager_h_
#define _COM_MemoryManager_h_
#include "COM_MemoryBuffer.h"
#include "COM_MemoryProxy.h"
#include "COM_ExecutionGroup.h"
#include "COM_MemoryManagerState.h"
/**
* @page memorymanager The Memory Manager
* The compositor has its own MemoryManager. The goal of the MemoryManager is to manage the memory allocated by chunks.
* During execution new chunks will be created [MemoryManager.allocateMemoryBuffer] When calculation is finished the MemoryBuffer will get the state [MemoryBufferState.COM_MB_AVAILABLE].
* From now on other ExecutionGroup and NodeOperations may read from the MemoryBuffer.
* The MemoryManager also has the capability to save MemoryBuffer's to disk in order to free some memory.
*
* @section S_MEM Memory manager
* The memory manager synchronize and optimize data across devices.
* Only one NodeOperation running on a device is able to write to a MemoryBuffer. This MemoryBuffer is only allocated on the main-device memory (CPU).
* The MemoryBuffer.state will be [MemoryBufferState.COM_MB_ALLOCATED]. As soon as the chunk has been executed the state changes to [MemoryBufferState.COM_MB_AVAILABLE]. This MemoryBuffer can now be used as inputBuffer of ExecutionGroup's.
* When needed the MemoryBuffer will be stored to a file. This will save memory that can be used by other tiles.
* @subsection S_MEM_1 Step one
* When a chunk of an ExecutionGroup is being executed by a device, the MemoryBuffer is allocated on the CPU.
* <pre>
* Allocation of the output MemoryBuffer
* +----------------------------------------+
* | Main device (CPU) |
* | +----------------+ +--------------+ |
* | | ExecutionGroup | | MemoryBuffer | |
* | | | | Chunk a | |
* | +----------------+ +--------------+ |
* | |
* +----------------------------------------+
* </pre>
* @see MemoryManager.allocateMemoryBuffer
*
* @subsection S_MEM_2 Step two
* The Device will execute the ExecutionGroup. This differs per type of Device. CPUDevice will call the NodeOperation.executeRegion method of the outputnode of the ExecutionGroup.
* The [NodeOperation.executeRegion] writes the result to the allocated MemoryBuffer. When finished the state of the MemoryBuffer will be set to [MemoryBufferState.COM_MB_AVAILABLE].
* <pre>
* Execute a chunk and store result to the MemoryBuffer
* +----------------------------------------+
* | Main device (CPU) |
* | +----------------+ +--------------+ |
* | | ExecutionGroup | | MemoryBuffer | |
* | | | | Chunk a | |
* | +----------------+ +--------------+ |
* | | ^ |
* | +----------------+ | |
* | | NodeOperation |--------+ |
* | | | Write result |
* | +----------------+ |
* | |
* +----------------------------------------+
* </pre>
* @subsection S_MEM_3 Step 3
* Other Chunks that depend on the MemoryBuffer can now use it.
* When a MemoryBuffer is being used its number of users are increased. When a 'user' is finished the number of users are decreased, If a MemoryBuffer has no users, the system can decide to store the data to disk and free some memory.
* @see MemoryBuffer.numberOfUsers
* @see MemoryBuffer.saveToDisk
*
* @subsection S_MEM_CON Temporarily MemoryBuffers
* Nodes like blur nodes can depend on multiple MemoryBuffer of the same MemoryProxy. These multiple buffers will be consolidated temporarily to a new MemoryBuffer.
* When execution is finished this temporarily memory buffer is deallicated.
* <pre>
* Original MemoryBuffer's Temporarily
* +-------+ +-------+ MemoryBuffer
* | MB A | | MB B | +-------+-------+
* +-------+ +-------+ | MB A | MB B |
* ==> +-------+-------+
* +-------+ +-------+ | MB C | MB D |
* | MB C | | MB D | +-------+-------+
* +-------+ +-------+
* </pre>
* @see ExecutionGroup.constructConsolidatedMemoryBuffer constructs the temporarily MemoryBuffer
* @see MemoryBuffer.state state is MemoryManagerState.COM_MB_TEMPORARILY
* @see ExecutionGroup.finalizeChunkExecution deallocate the temporarily MemoryBuffer
* @note this MemoryBuffer is not managed by the MemoryManager
*/
/**
* @brief the memory manager for the compostor
* @ingroup Memory
*/
class MemoryManager {
private:
/**
* @brief retrieve the state of a certain MemoryProxy;
* @param memoryProxy the MemoryProxy to retrieve the state from
*/
static MemoryManagerState *getState(MemoryProxy *memoryProxy);
public:
/**
* @brief allocate a memory buffer
* @param memoryProxy the MemoryProxy to get a chunk from
* @param chunkNumber number of the chunk to receive
* @param rect size + position of the chunk
*/
static MemoryBuffer *allocateMemoryBuffer(MemoryProxy *memoryProxy, unsigned int chunkNumber, rcti *rect);
/**
* @brief get a memory buffer
* @param memoryProxy the MemoryProxy to get a chunk from
* @param chunkNumber number of the chunk to receive
* @param addUser must we add a user to the chunk.
*/
static MemoryBuffer *getMemoryBuffer(MemoryProxy *memoryProxy, unsigned int chunkNumber);
/**
* @brief add a MemoryProxy to the scope of the memory manager
* @param memoryProxy the MemoryProxy to add
*/
static void addMemoryProxy(MemoryProxy *memoryProxy);
/**
* @brief clear the memory manager
*/
static void clear();
/**
* @brief initialize the memory manager.
*/
static void initialize();
};
#endif

@ -1,100 +0,0 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor:
* Jeroen Bakker
* Monique Dewanchand
*/
#include "COM_MemoryManagerState.h"
MemoryManagerState::MemoryManagerState(MemoryProxy *memoryProxy)
{
this->memoryProxy = memoryProxy;
this->currentSize = 0;
this->chunkBuffers = NULL;
BLI_mutex_init(&this->mutex);
}
MemoryProxy * MemoryManagerState::getMemoryProxy()
{
return this->memoryProxy;
}
MemoryManagerState::~MemoryManagerState()
{
this->memoryProxy = NULL;
unsigned int index;
for (index = 0 ; index < this->currentSize; index ++) {
MemoryBuffer *buffer = this->chunkBuffers[index];
if (buffer) {
delete buffer;
}
}
delete [] this->chunkBuffers;
BLI_mutex_end(&this->mutex);
}
void MemoryManagerState::addMemoryBuffer(MemoryBuffer *buffer)
{
BLI_mutex_lock(&this->mutex);
unsigned int chunkNumber = buffer->getChunkNumber();
unsigned int index;
while (this->currentSize <= chunkNumber) {
unsigned int newSize = this->currentSize + 1000;
MemoryBuffer** newbuffer = new MemoryBuffer*[newSize];
MemoryBuffer** oldbuffer = this->chunkBuffers;
for (index = 0 ; index < this->currentSize ; index++) {
newbuffer[index] = oldbuffer[index];
}
for (index = currentSize ; index < newSize; index++) {
newbuffer[index] = NULL;
}
this->chunkBuffers = newbuffer;
this->currentSize = newSize;
if (oldbuffer) delete oldbuffer;
}
if (this->chunkBuffers[chunkNumber] == NULL) {
this->chunkBuffers[chunkNumber] = buffer;
}
else {
throw "ALREADY ALLOCATED!";
}
BLI_mutex_unlock(&this->mutex);
}
MemoryBuffer *MemoryManagerState::getMemoryBuffer(unsigned int chunkNumber)
{
MemoryBuffer *result = NULL;
if (chunkNumber< this->currentSize) {
result = this->chunkBuffers[chunkNumber];
if (result) {
return result;
}
}
BLI_mutex_lock(&this->mutex);
if (chunkNumber< this->currentSize) {
result = this->chunkBuffers[chunkNumber];
}
BLI_mutex_unlock(&this->mutex);
return result;
}

@ -1,87 +0,0 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor:
* Jeroen Bakker
* Monique Dewanchand
*/
class MemoryManagerState;
#ifndef _COM_MemoryManagerState_h_
#define _COM_MemoryManagerState_h_
#include "COM_MemoryProxy.h"
#include "COM_MemoryBuffer.h"
#include <vector>
extern "C" {
#include "BLI_threads.h"
}
/**
* @brief State of a MemoryProxy in the MemoryManager.
* @ingroup Memory
*/
class MemoryManagerState {
private:
/**
* @brief reference to the MemoryProxy of this state
*/
MemoryProxy *memoryProxy;
/**
* @brief list of all chunkbuffers
*/
MemoryBuffer** chunkBuffers;
/**
* @brief size of the chunkBuffers
*/
unsigned int currentSize;
/**
* @brief lock to this memory for multithreading
*/
ThreadMutex mutex;
public:
/**
* @brief creates a new MemoryManagerState for a certain MemoryProxy.
*/
MemoryManagerState(MemoryProxy * memoryProxy);
/**
* @brief destructor
*/
~MemoryManagerState();
/**
* @brief get the reference to the MemoryProxy this state belongs to.
*/
MemoryProxy *getMemoryProxy();
/**
* @brief add a new memorybuffer to the state
*/
void addMemoryBuffer(MemoryBuffer *buffer);
/**
* @brief get the MemoryBuffer assiciated to a chunk.
* @param chunkNumber the chunknumber
*/
MemoryBuffer *getMemoryBuffer(unsigned int chunkNumber);
};
#endif

@ -25,15 +25,26 @@
MemoryProxy::MemoryProxy()
{
this->state = NULL;
this->writeBufferOperation = NULL;
this->executor = NULL;
}
MemoryProxy::~MemoryProxy()
void MemoryProxy::allocate(unsigned int width, unsigned int height)
{
if (this->state) {
delete this->state;
this->state = NULL;
rcti result;
result.xmin = 0;
result.xmax = width;
result.ymin = 0;
result.ymax = height;
buffer = new MemoryBuffer(this, &result);
}
void MemoryProxy::free()
{
if (buffer) {
delete buffer;
buffer = NULL;
}
}

@ -26,7 +26,6 @@ class MemoryProxy;
#ifndef _COM_MemoryProxy_h
#define _COM_MemoryProxy_h
#include "COM_ExecutionGroup.h"
#include "COM_MemoryManagerState.h"
class ExecutionGroup;
@ -48,12 +47,6 @@ private:
*/
ExecutionGroup *executor;
/**
* @brief data of the different chunks.
* @note state is part of this class due to optimization in the MemoryManager
*/
MemoryManagerState * state;
/**
* @brief datatype of this MemoryProxy
*/
@ -63,9 +56,14 @@ private:
* @brief channel information of this buffer
*/
ChannelInfo channelInfo[COM_NUMBER_OF_CHANNELS];
/**
* @brief the allocated memory
*/
MemoryBuffer* buffer;
public:
MemoryProxy();
~MemoryProxy();
/**
* @brief set the ExecutionGroup that can be scheduled to calculate a certain chunk.
@ -89,18 +87,21 @@ public:
* @return WriteBufferOperation
*/
WriteBufferOperation *getWriteBufferOperation() {return this->writeBufferOperation;}
/**
* @brief set the memorymanager state of this MemoryProxy, this is set from the MemoryManager
* @param state the state to set
* @brief allocate memory of size widht x height
*/
void setState(MemoryManagerState *state) {this->state = state;}
void allocate(unsigned int width, unsigned int height);
/**
* @brief get the state of this MemoryProxy
* @return MemoryManagerState reference to the state of this MemoryProxy.
* @brief free the allocated memory
*/
MemoryManagerState *getState() {return this->state;}
void free();
/**
* @brief get the allocated memory
*/
inline MemoryBuffer* getBuffer() {return this->buffer;}
};
#endif

@ -33,6 +33,7 @@ class NodeOperation;
#include "COM_SocketReader.h"
#include "OCL_opencl.h"
#include "list"
#include "BLI_threads.h"
class ReadBufferOperation;

@ -53,7 +53,7 @@ void OpenCLDevice::execute(WorkPackage *work)
rcti rect;
executionGroup->determineChunkRect(&rect, chunkNumber);
MemoryBuffer ** inputBuffers = executionGroup->getInputBuffers(chunkNumber);
MemoryBuffer ** inputBuffers = executionGroup->getInputBuffersOpenCL(chunkNumber);
MemoryBuffer * outputBuffer = executionGroup->allocateOutputBuffer(chunkNumber, &rect);
executionGroup->getOutputNodeOperation()->executeOpenCLRegion(this->context, this->program, this->queue, &rect, chunkNumber, inputBuffers);

@ -22,10 +22,8 @@
#include "COM_WriteBufferOperation.h"
#include "COM_defines.h"
#include "COM_MemoryManager.h"
#include <stdio.h>
/// @TODO: writebuffers don't have an actual data type set.
WriteBufferOperation::WriteBufferOperation() :NodeOperation()
{
this->addInputSocket(COM_DT_COLOR);
@ -46,20 +44,23 @@ void WriteBufferOperation::executePixel(float *color, float x, float y, PixelSam
{
input->read(color, x, y, sampler, inputBuffers);
}
void WriteBufferOperation::initExecution()
{
this->input = this->getInputOperation(0);
MemoryManager::addMemoryProxy(this->memoryProxy);
this->input = this->getInputOperation(0);
this->memoryProxy->allocate(this->width, this->height);
}
void WriteBufferOperation::deinitExecution()
{
this->input = NULL;
this->memoryProxy->free();
}
void WriteBufferOperation::executeRegion(rcti *rect, unsigned int tileNumber, MemoryBuffer** memoryBuffers)
{
MemoryBuffer *memoryBuffer = MemoryManager::getMemoryBuffer(this->getMemoryProxy(), tileNumber);
//MemoryBuffer *memoryBuffer = MemoryManager::getMemoryBuffer(this->getMemoryProxy(), tileNumber);
MemoryBuffer *memoryBuffer = this->memoryProxy->getBuffer();
float *buffer = memoryBuffer->getBuffer();
if (this->input->isComplex()) {
void *data = this->input->initializeTileData(rect, memoryBuffers);
@ -67,14 +68,14 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int tileNumber, Me
int y1 = rect->ymin;
int x2 = rect->xmax;
int y2 = rect->ymax;
int offset4 = 0;
int x;
int y;
bool breaked = false;
for (y = y1 ; y < y2 && (!breaked) ; y++) {
int offset4 = (y*memoryBuffer->getWidth()+x1)*COM_NUMBER_OF_CHANNELS;
for (x = x1 ; x < x2; x++) {
input->read(&(buffer[offset4]), x, y, memoryBuffers, data);
offset4 +=4;
offset4 +=COM_NUMBER_OF_CHANNELS;
}
if (tree->test_break && tree->test_break(tree->tbh)) {
@ -92,14 +93,15 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int tileNumber, Me
int y1 = rect->ymin;
int x2 = rect->xmax;
int y2 = rect->ymax;
int offset4 = 0;
int x;
int y;
bool breaked = false;
for (y = y1 ; y < y2 && (!breaked) ; y++) {
int offset4 = (y*memoryBuffer->getWidth()+x1)*COM_NUMBER_OF_CHANNELS;
for (x = x1 ; x < x2 ; x++) {
input->read(&(buffer[offset4]), x, y, COM_PS_NEAREST, memoryBuffers);
offset4 +=4;
offset4 +=COM_NUMBER_OF_CHANNELS;
}
if (tree->test_break && tree->test_break(tree->tbh)) {
breaked = true;
@ -111,7 +113,7 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int tileNumber, Me
void WriteBufferOperation::executeOpenCLRegion(cl_context context, cl_program program, cl_command_queue queue, rcti *rect, unsigned int chunkNumber, MemoryBuffer** inputMemoryBuffers)
{
MemoryBuffer *outputMemoryBuffer = MemoryManager::getMemoryBuffer(this->getMemoryProxy(), chunkNumber);
MemoryBuffer *outputMemoryBuffer = this->getMemoryProxy()->getBuffer();// @todo wrong implementation needs revision
float *outputFloatBuffer = outputMemoryBuffer->getBuffer();
cl_int error;
/*