Dev:Source/Architecture/Module Blender

提供: wiki
移動先: 案内検索

Module Blender Home Page

Introduction

Module Blender (ModBlender) is a blender tree that has a much more sophisticated plugin system than the current blender version (both BF and evil blender). Giving the developer a much cleaner interface that is less likly to change over time (even if the underlying codebase changes).

Each module is contained in a BMX or a Blender Module eXtension which is a native binary that contains callbacks and/or functionality ready to be exported to other modules (and also blender itself). If a given BMX is written in a special way (which isnt that difficult) then the BMX runtime can swap unused modules out to disk, saving on resources and keeping in line with Blenders low resource philosophy.

Features / Design Considerations

This is a list of the current features for the current implementation:

  • Each module can be hot swappable (very easy to implement to a BMX);
  • Uses message passing (similar to the current version of Blender);
  • Uses a very clean C API;
  • All modules have their data stored in the client side (if hot swappable);
  • Module instances can be swapped to disk if memory resources are exausted;
  • On loadup a splash screen shows a little status bar showing the module loading progress;
  • Memory allocation is tracked per binary, making it visable as to where all of the resources are going;
  • All of blenders internal API is wrapped in bundles of function pointers located in structs;
  • The hop swappable nature of the message passing API is transpearant, i.e. if a message is send to a binary that has been unloaded, the binary is then reloaded back into memory and the message is processed as it usually would be and
  • The system uses GUIDs to identify modules and prevent name clashes.

Module Workflow

Blender Initalisation

When Blender boots up its splash() function is called which draws a splash screen on the screen area. In ModBlender this is replaced with MOD_InitSplash(), which accepts the same parameters but initalises the module sybsystem.

The $BLENDER$/bmx/ directory is scanned (much like what happens in the Python script initalisation) where DLLs are read in. If they contain a HRESULT module_init(BAPI * api) function, it is called with the toplevel API. The toplevel API contains the following functions:

  • getBlenderVersion(): Return the current Blender version in integer form, ie. v2.34 == 234;
  • setVersion(): Set the version of that particular BMX, also in integer form;
  • getAPI(): Get a pointer to a structure containing API functionality;
  • setAPI(): Register an API with the API registry;
  • registerModule(): Register a module with the module registry, included in the parameter list is the name and GUID of the module, as well as a brief deccription so users may know what is installed on their system;
  • print(): A wrapper for printf(), this should be used in the future just in case its output is to be directed to withing the main Blender window itself;
  • error(): Print an error message to the console and also to an error log (just in case the Blender application crashes);
  • debug(): Print a debugging message to the console, this isnt a straight printf wrapper - sophisticated filtering can be used to determing what messages get printed based on a "level" integer that is passed along with the string;
  • debugPolicy(): Determine what messages get printed to the console with debug();
  • setLastError(): Set both an error message (in string form) as well as an error code (integer form), I have taken the error codes from the Wine project (http://www.winehq.com/) which includes every conceivable error under the sun.
  • getLastError(): Retreive the last error, this function returns an error code, the string is returned via a pointer passed as a parameter and
  • makeReloadable(): Using this API with either a GUID (for a module) or a string ID (for an API) will allow that particular Module/API to become reloadable. However ALL resources in a given BMX have to be declared as reloadable with makeReloadable() before the given BMX gan be swapped out to disk.

It is everything that is needed to initalise the BMX. The function of the module_init() function is to:

  • Determine whether the Blender application supports the functionality that the BMX requires;
  • Register any modules and API interfaces and
  • Obtain API interfaces that are provided by the Blender application itself.

It is not used to obtain interfaces or module instances from other BMX files since these modules (even though present) may not actually have been registered with their respective registeries, this is saved until the CLASS_INIT and MODULE_INIT messages which are sent to the class instances after each module_init() functions have been called.

Once the modules have all been initalised all swappable BMX's are swapped to disk to converve resources.

Module Instances

Each module contains one class instance and if the modules is allowed to have multiple instances - module instances. Both class and module instances have their own unique data area and module instance ID. They both share the same module callback, where the two differ is that the class have the CLASS_ specific messages and the module instances have the MODULE_ messages. The callback is shown below:

MAPI HRESULT callback(unsigned long msg, void * pointer, long value) { MyModuleDataAreaStruct *data;
 switch(msg) { case TEXTURE_SAMPLE: data = mod->getDataArea(); /* Do cool texturing stuff here */  return S_OK;
 case MODULE_INIT: /* Preform Module instance initalisation stuff here */ mod->createDataArea(sizeof(MyModuleDataAreaStruct));
 return S_OK;   
 case MODULE_RESTORE: /* The module is being reloaded after being saved, sort that out here */ data = mod->createDataArea(sizeof(MyModuleDataAreaStruct)); /* Restore our 1 demo entry */ dna->entry("windX", &data->windX, DNA_FLOAT, 1, DNA_RETREIVE);
 return S_OK; } return mod->unimpl(msg, pointer, value);
}

Hopefully there will be some things that you have noticed:

  • There is no module handle, the module system is heavily reliant on its internal state, this allows us to monitor memory usage as well as where the current error messages are comming from (as examples);
  • All of the API functionality is comming from the BMODULE API struct that has the functionality to deal with the semi complicated callback procedures;
  • If the callback dosent process a message it calls unimpl() which allows the blender runtime to process the message - if it needs to and
  • Because the modules data is constrained to its data area you are forced into data encapsulation - a good programming practice.

Other methods for data storage and retreival are getBinaryData() - which gets the allocated data assioacated to the current binary and getClassData which gets the data from a modules registered class, either through a GUID (passed as a parameter) or as the class of the current module (if the GUID pointer is NULL).

State

ModBlender Keeps internally the current Blender Module, and (indirectly) the current Blender binary. Currently the design is such that you cannot execute code within a BMX without having an active module receiving and transmitting messages. Internally the module runtime has a module stack that is incremented and decremented when ever the MOD_SendMessage() API is used, This is the only API that allows you to access functionality with a BMX.

Message Passing

The module runtime uses:
HRESULT MOD_SendMessage(BlenderModule module, unsigned long msg, void pointer, long value, unsigned int flags);
To invoke code with a BMX. Internally it manages the module stack (see above) and also checks to make sure that the given module and module's binary are in memory, if any one of the two arnt, then they are loaded and the message is send as usual.

Message Allocation

Since messages are just symbolic repersentations of numbers it is critical that different messages do not use the same number. In order to get rid of this conflict a macro was developed, this is as shown below:

#define MAKE_MESSAGE(klass, off) (2^16 * (klass) + (off))

klass: The message class is a symbolically defined integer that repersents a group of similar messages, i.e.
off: the message offset, This is unique to that particular message class.

Some examples for some messages and their classes are:

#define SYSTEM_CLASS  0
#define MODULE_CLASS  1
#define TEXTURE_CLASS 2
#define STORAGE_CLASS 3

#define MODULE_INIT     MAKE_MESSAGE( MODULE_CLASS, 0)
#define MODULE_RESTORE  MAKE_MESSAGE( MODULE_CLASS, 1)
#define MODULE_DELETE   MAKE_MESSAGE( MODULE_CLASS, 2)

#define TEXTURE_SAMPLE  MAKE_MESSAGE( TEXTURE_CLASS, 0)
#define TEXTURE_GUI     MAKE_MESSAGE( TEXTURE_CLASS, 1)

As you can see this system makes it possible to group message definitions together allowing for easy manitenence. [more will be added to this when time permits]

Bugs and TODO

Here is a list of the bugs and features that need to be added:

  • I am still adding code but this should be compilable in the next few weeks;
  • A much more sophisticated resource algorithm needs to be added so as not to swap out the modules that are under heavy use.

Files

  • module-core.c: Contains MOD_InitSplash() which is used to initalise the module system. It also contains all of the core module APIs , data and internal state;
  • module-internal.c: Contains the function used to initalise the other parts of blender that use the BMX framework;
  • module.h: The main module header file to be included for every BMX. It contains the messages and structures exported from parts of Blender and
  • MOD_intern.h: Contains prototypes used for other parts of blender (internally).

Links

Coders forum where I publish news regarding this project: http://blender.org/modules.php?op=modload&name=phpBB2&file=viewtopic&t=4222

You have to keep in mind that I am currently doing this in my spare time so development is slow, and also the design needs to be looked at by the other Blender Developers, so don't be surprised to see any major changes.

Kind Regards
DeveloperWikiSimonHarvey
30 Jun 2005


Comments

For thoes with access to this Wiki please post your comments at the above forum address which gets checked daily (I only check the Wiki when I am updating it).