forked from bartvdbraak/blender
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:
parent
a78dca27a2
commit
285a24b3e0
@ -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;
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user