Dryad/DryadVertex/VertexHost/system/dprocess/src/vertexfactory.cpp

405 lines
12 KiB
C++

/*
Copyright (c) Microsoft Corporation
All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License
at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions and
limitations under the License.
*/
//
// Includes
//
#include <DrExecution.h>
#include <vertexfactory.h>
#include <dryaderrordef.h>
//
// Create a vertex factory and register it
//
DryadVertexFactoryBase::DryadVertexFactoryBase(const char* name)
{
m_name = name;
VertexFactoryRegistry::RegisterFactory(this);
}
//
// Destructor does nothing
//
DryadVertexFactoryBase::~DryadVertexFactoryBase()
{
}
const char* DryadVertexFactoryBase::GetName()
{
return m_name;
}
//
// The Register method does nothing, but can be used to pull in static
// factories from other compilation units.
//
void DryadVertexFactoryBase::Register()
{
}
//
// Create reference to new program
//
DryadVertexProgramRef DryadVertexFactoryBase::MakeUntyped()
{
DryadVertexProgramRef p;
p.Attach(NewUntyped());
return p;
}
//
// Have factory create new program base
//
DryadVertexProgramBase* DryadVertexFactoryBase::NewUntyped()
{
return NewUntypedInternal();
}
/* this is guaranteed to be set to zero before anyone's constructor is
called */
static VertexFactoryRegistry* s_dryadVertexRegistry;
//
// Create new empty factory registry
//
VertexFactoryRegistry::VertexFactoryRegistry()
{
m_registeredNULL = false;
}
//
// Register a factory
//
void VertexFactoryRegistry::RegisterFactory(DryadVertexFactoryBase* factory)
{
//
// If there is no registry, create one
//
if (s_dryadVertexRegistry == 0)
{
s_dryadVertexRegistry = new VertexFactoryRegistry();
}
VertexFactoryRegistry* self = s_dryadVertexRegistry;
const char* name = factory->GetName();
if (name == NULL)
{
//
// If no factory name, this is an error.
// RegisterFactory gets called during static initializations,
// so just save the errors and log properly in :LookupFactory
// or :ShowAllVertexUsageMessages
//
self->m_registeredNULL = true;
}
else
{
FactoryMap::iterator existing = self->m_factories.find(name);
if (existing != self->m_factories.end())
{
//
// If factory name already in registry, this is an error
// RegisterFactory gets called during static
// initializations, so just save the errors and log
// properly in :LookupFactory or :ShowAllVertexUsageMessages
//
self->m_errorSet.insert(name);
}
else
{
//
// If factory name doesn't exist, add it to list of registered factories (key is name).
//
self->m_factories.insert(std::make_pair(name, factory));
}
}
}
//
// Get Vertex factory from name
//
DryadVertexFactoryBase* VertexFactoryRegistry::LookUpFactory(const char* name)
{
//
// Create a vertex registry if none exist
//
if (s_dryadVertexRegistry == 0)
{
s_dryadVertexRegistry = new VertexFactoryRegistry();
}
VertexFactoryRegistry* self = s_dryadVertexRegistry;
//
// If NULL name was provided to the registry on initialization, log the error
//
if (self->m_registeredNULL)
{
DrLogE("Factory Registered With illegal NULL name");
}
//
// If there are any elements in m_errorSet, multiple factories of the same
// were attempted to be registered. Log this error.
//
if (self->m_errorSet.empty() == false)
{
DuplicateSet::iterator i;
for (i = self->m_errorSet.begin(); i != self->m_errorSet.end(); ++i)
{
DrLogE("Duplicate Factory Registered. Factory name: %s", i->c_str());
}
}
//
// If any errors, report that they exist at the assert level
//
if (self->m_registeredNULL || self->m_errorSet.empty() == false)
{
DrLogA("Factory Registration Errors");
}
//
// Find a factory with the provided name
//
FactoryMap::iterator factory = self->m_factories.find(name);
if (factory != self->m_factories.end())
{
//
// If found factory, return reference to it
//
return factory->second;
}
else
{
//
// If no factory found, return null
//
return NULL;
}
}
//
// Check factory registry and print out any immediate errors and usage instructions
//
void VertexFactoryRegistry::ShowAllVertexUsageMessages(FILE* f)
{
//
// If factory registry not yet initialized, report failure and exit.
// todo: ensure we want to fprintf here and not write to log
//
if (s_dryadVertexRegistry == 0)
{
fprintf(f, "Factory Registry usage called before initialization\n\n");
return;
}
VertexFactoryRegistry* self = s_dryadVertexRegistry;
//
// If NULL name was provided to the registry on initialization, log the error
//
if (self->m_registeredNULL)
{
DrLogE("Factory Registered With illegal NULL name");
}
//
// If there are any elements in m_errorSet, multiple factories of the same
// were attempted to be registered. Log this error.
//
if (self->m_errorSet.empty() == false)
{
DuplicateSet::iterator i;
for (i = self->m_errorSet.begin(); i != self->m_errorSet.end(); ++i)
{
DrLogE("Duplicate Factory Registered. Factory name: %s", i->c_str());
}
}
//
// If any errors, report that they exist at the assert level
//
if (self->m_registeredNULL || self->m_errorSet.empty() == false)
{
DrLogA("Factory Registration Errors");
}
//
// Foreach factory, make sure the argument count is 1 and print out any
// usage information
//
FactoryMap::iterator factory;
for (factory = self->m_factories.begin();
factory != self->m_factories.end(); ++factory)
{
DryadVertexProgramRef program = factory->second->MakeUntyped();
LogAssert(program->GetArgumentCount() == 1);
program->Usage(f);
}
}
//
// Get factory and have it create a vertex program
//
DrError VertexFactoryRegistry::MakeVertex(UInt32 vertexId,
UInt32 vertexVersion,
UInt32 numberOfInputChannels,
UInt32 numberOfOutputChannels,
UInt64* expectedLength,
DryadVertexFactoryBase* factory,
DryadMetaData* metaData,
UInt32 maxInputChannels,
UInt32 maxOutputChannels,
UInt32 argumentCount,
DrStr64* argumentList,
UInt32 serializedBlockLength,
const void* serializedBlock,
DryadMetaDataRef* pErrorData,
DryadVertexProgramRef* pProgram)
{
DryadVertexProgramBase* program;
//
// If factory is not supplied, try to get it from factory registry.
// If still unable, fail with error.
//
if (factory == NULL)
{
//
// If no arguments, return vertex initialization error
//
if (argumentCount == 0)
{
DryadMetaData::Create(pErrorData);
(*pErrorData)->AddErrorWithDescription(DryadError_VertexInitialization,
"Factory Registry called with no arguments");
return DryadError_VertexInitialization;
}
//
// Get vertex factory. If one cannot be found, report initialization error
//
factory = LookUpFactory(argumentList[0]);
if (factory == NULL)
{
DrLogW("Factory Registry called with unknown factory UID %s.", argumentList[0].GetString());
DrStr128 errorString;
errorString.SetF("Factory Registry called with unknown factory UID %s",
argumentList[0].GetString());
DryadMetaData::Create(pErrorData);
(*pErrorData)->AddErrorWithDescription(DryadError_VertexInitialization,
errorString);
return DryadError_VertexInitialization;
}
//
// report new vertex creation
//
DrLogI( "Factory making new vertex. Vertex %s with %u arguments %u inputs %u outputs",
argumentList[0].GetString(), argumentCount,
numberOfInputChannels, numberOfOutputChannels);
//
// Make a program and ensure that program argument is first argument in list
// todo: figure out how first argument in program is specified/what it is
//
*pProgram = factory->MakeUntyped();
program = *pProgram;
LogAssert(program->GetArgumentCount() == 1);
LogAssert(::strcmp(program->GetArgument(0), argumentList[0]) == 0);
//
// adjust the argument count and list to throw away the first
// argument naming which vertex was to be created
//
++argumentList;
--argumentCount;
}
else
{
//
// If a factory exists, then we have been told which factory to use and are
// not going to read it from the argument list
//
*pProgram = factory->MakeUntyped();
program = *pProgram;
LogAssert(program->GetArgumentCount() == 1);
}
//
// Update program with vertext id and version
//
program->SetVertexId(vertexId);
program->SetVertexVersion(vertexVersion);
//
// Let program know how long the input channels are
//
if (expectedLength != NULL)
{
program->SetExpectedInputLength(numberOfInputChannels, expectedLength);
}
//
// Add remaining arguments to arg list
//
UInt32 i;
for (i=0; i<argumentCount; ++i)
{
program->AddArgument(argumentList[i]);
DrLogI( "Factory adding vertex argument. Vertex %s arguments %u=%s",
program->GetArgument(0), i, argumentList[i].GetString());
}
//
// Set max number of channels and other metadata
//
program->SetMaxOpenInputChannelCount(maxInputChannels);
program->SetMaxOpenOutputChannelCount(maxOutputChannels);
program->SetMetaData(metaData);
//
// Copy data into program
//
DrRef<DrMemoryBuffer> buffer;
buffer.Attach(new DrSimpleHeapBuffer());
buffer->Append(serializedBlock, serializedBlockLength);
DrMemoryBufferReader reader(buffer);
program->DeSerialize(&reader);
if (program->GetErrorCode() == DrError_OK)
{
//
// If still ok, initialize the program with the expected number of input and output channels
// todo: this doesn't do anything in base type. Figure out if base type or derived type.
//
program->Initialize(numberOfInputChannels, numberOfOutputChannels);
}
//
// Report any errors
//
*pErrorData = program->GetErrorMetaData();
return program->GetErrorCode();
}