Add GLOB_MEASURE_TIME configuration option to profile the runtime of the postprocessing steps.
Start new documentation page for Performance/Profiling questions. Migrate existing notes on multithreading to a new doc page, add more details. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@772 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
7f2f5e7555
commit
aae8637666
|
@ -0,0 +1,72 @@
|
||||||
|
// boost timer.hpp header file ---------------------------------------------//
|
||||||
|
|
||||||
|
// Copyright Beman Dawes 1994-99. Distributed under the Boost
|
||||||
|
// Software License, Version 1.0. (See accompanying file
|
||||||
|
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// See http://www.boost.org/libs/timer for documentation.
|
||||||
|
|
||||||
|
// Revision History
|
||||||
|
// 01 Apr 01 Modified to use new <boost/limits.hpp> header. (JMaddock)
|
||||||
|
// 12 Jan 01 Change to inline implementation to allow use without library
|
||||||
|
// builds. See docs for more rationale. (Beman Dawes)
|
||||||
|
// 25 Sep 99 elapsed_max() and elapsed_min() added (John Maddock)
|
||||||
|
// 16 Jul 99 Second beta
|
||||||
|
// 6 Jul 99 Initial boost version
|
||||||
|
|
||||||
|
#ifndef BOOST_TIMER_HPP
|
||||||
|
#define BOOST_TIMER_HPP
|
||||||
|
|
||||||
|
//#include <boost/config.hpp>
|
||||||
|
#include <ctime>
|
||||||
|
//#include <boost/limits.hpp>
|
||||||
|
|
||||||
|
# ifdef BOOST_NO_STDC_NAMESPACE
|
||||||
|
namespace std { using ::clock_t; using ::clock; }
|
||||||
|
# endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
// timer -------------------------------------------------------------------//
|
||||||
|
|
||||||
|
// A timer object measures elapsed time.
|
||||||
|
|
||||||
|
// It is recommended that implementations measure wall clock rather than CPU
|
||||||
|
// time since the intended use is performance measurement on systems where
|
||||||
|
// total elapsed time is more important than just process or CPU time.
|
||||||
|
|
||||||
|
// Warnings: The maximum measurable elapsed time may well be only 596.5+ hours
|
||||||
|
// due to implementation limitations. The accuracy of timings depends on the
|
||||||
|
// accuracy of timing information provided by the underlying platform, and
|
||||||
|
// this varies a great deal from platform to platform.
|
||||||
|
|
||||||
|
class timer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
timer() { _start_time = std::clock(); } // postcondition: elapsed()==0
|
||||||
|
// timer( const timer& src ); // post: elapsed()==src.elapsed()
|
||||||
|
// ~timer(){}
|
||||||
|
// timer& operator=( const timer& src ); // post: elapsed()==src.elapsed()
|
||||||
|
void restart() { _start_time = std::clock(); } // post: elapsed()==0
|
||||||
|
double elapsed() const // return elapsed time in seconds
|
||||||
|
{ return double(std::clock() - _start_time) / CLOCKS_PER_SEC; }
|
||||||
|
|
||||||
|
double elapsed_max() const // return estimated maximum value for elapsed()
|
||||||
|
// Portability warning: elapsed_max() may return too high a value on systems
|
||||||
|
// where std::clock_t overflows or resets at surprising values.
|
||||||
|
{
|
||||||
|
return (double((std::numeric_limits<std::clock_t>::max)())
|
||||||
|
- double(_start_time)) / double(CLOCKS_PER_SEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
double elapsed_min() const // return minimum value for elapsed()
|
||||||
|
{ return double(1)/double(CLOCKS_PER_SEC); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::clock_t _start_time;
|
||||||
|
}; // timer
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_TIMER_HPP
|
|
@ -141,6 +141,7 @@ SOURCE_GROUP( Common FILES
|
||||||
Vertex.h
|
Vertex.h
|
||||||
LineSplitter.h
|
LineSplitter.h
|
||||||
TinyFormatter.h
|
TinyFormatter.h
|
||||||
|
Profiler.h
|
||||||
)
|
)
|
||||||
|
|
||||||
SOURCE_GROUP( 3DS FILES
|
SOURCE_GROUP( 3DS FILES
|
||||||
|
@ -720,6 +721,7 @@ ADD_LIBRARY( assimp SHARED
|
||||||
BlenderIntermediate.h
|
BlenderIntermediate.h
|
||||||
BlenderModifier.h
|
BlenderModifier.h
|
||||||
BlenderModifier.cpp
|
BlenderModifier.cpp
|
||||||
|
Profiler.h
|
||||||
|
|
||||||
# Necessary to show the headers in the project when using the VC++ generator:
|
# Necessary to show the headers in the project when using the VC++ generator:
|
||||||
BoostWorkaround/boost/math/common_factor_rt.hpp
|
BoostWorkaround/boost/math/common_factor_rt.hpp
|
||||||
|
|
|
@ -67,6 +67,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "ProcessHelper.h"
|
#include "ProcessHelper.h"
|
||||||
#include "ScenePreprocessor.h"
|
#include "ScenePreprocessor.h"
|
||||||
#include "MemoryIOWrapper.h"
|
#include "MemoryIOWrapper.h"
|
||||||
|
#include "Profiler.h"
|
||||||
|
|
||||||
|
using namespace Assimp::Profiling;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Importers
|
// Importers
|
||||||
|
@ -837,20 +840,25 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
|
||||||
{
|
{
|
||||||
// Check whether this Importer instance has already loaded
|
// Check whether this Importer instance has already loaded
|
||||||
// a scene. In this case we need to delete the old one
|
// a scene. In this case we need to delete the old one
|
||||||
if (pimpl->mScene)
|
if (pimpl->mScene) {
|
||||||
{
|
|
||||||
DefaultLogger::get()->debug("Deleting previous scene");
|
DefaultLogger::get()->debug("(Deleting previous scene)");
|
||||||
FreeScene();
|
FreeScene();
|
||||||
}
|
}
|
||||||
|
|
||||||
// First check if the file is accessable at all
|
// First check if the file is accessable at all
|
||||||
if( !pimpl->mIOHandler->Exists( pFile))
|
if( !pimpl->mIOHandler->Exists( pFile)) {
|
||||||
{
|
|
||||||
pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
|
pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
|
||||||
DefaultLogger::get()->error(pimpl->mErrorString);
|
DefaultLogger::get()->error(pimpl->mErrorString);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::scoped_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL);
|
||||||
|
if (profiler) {
|
||||||
|
profiler->BeginRegion("total");
|
||||||
|
}
|
||||||
|
|
||||||
// Find an worker class which can handle the file
|
// Find an worker class which can handle the file
|
||||||
BaseImporter* imp = NULL;
|
BaseImporter* imp = NULL;
|
||||||
for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
|
for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
|
||||||
|
@ -861,10 +869,9 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!imp)
|
if (!imp) {
|
||||||
{
|
|
||||||
// not so bad yet ... try format auto detection.
|
// not so bad yet ... try format auto detection.
|
||||||
std::string::size_type s = pFile.find_last_of('.');
|
const std::string::size_type s = pFile.find_last_of('.');
|
||||||
if (s != std::string::npos) {
|
if (s != std::string::npos) {
|
||||||
DefaultLogger::get()->info("File extension now known, trying signature-based detection");
|
DefaultLogger::get()->info("File extension now known, trying signature-based detection");
|
||||||
for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
|
for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
|
||||||
|
@ -885,9 +892,18 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
|
||||||
|
|
||||||
// Dispatch the reading to the worker class for this format
|
// Dispatch the reading to the worker class for this format
|
||||||
DefaultLogger::get()->info("Found a matching importer for this file format");
|
DefaultLogger::get()->info("Found a matching importer for this file format");
|
||||||
|
|
||||||
|
if (profiler) {
|
||||||
|
profiler->BeginRegion("import");
|
||||||
|
}
|
||||||
|
|
||||||
imp->SetupProperties( this );
|
imp->SetupProperties( this );
|
||||||
pimpl->mScene = imp->ReadFile( pFile, pimpl->mIOHandler);
|
pimpl->mScene = imp->ReadFile( pFile, pimpl->mIOHandler);
|
||||||
|
|
||||||
|
if (profiler) {
|
||||||
|
profiler->EndRegion("import");
|
||||||
|
}
|
||||||
|
|
||||||
// If successful, apply all active post processing steps to the imported data
|
// If successful, apply all active post processing steps to the imported data
|
||||||
if( pimpl->mScene) {
|
if( pimpl->mScene) {
|
||||||
|
|
||||||
|
@ -904,9 +920,17 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
|
||||||
#endif // no validation
|
#endif // no validation
|
||||||
|
|
||||||
// Preprocess the scene and prepare it for post-processing
|
// Preprocess the scene and prepare it for post-processing
|
||||||
|
if (profiler) {
|
||||||
|
profiler->BeginRegion("preprocess");
|
||||||
|
}
|
||||||
|
|
||||||
ScenePreprocessor pre(pimpl->mScene);
|
ScenePreprocessor pre(pimpl->mScene);
|
||||||
pre.ProcessScene();
|
pre.ProcessScene();
|
||||||
|
|
||||||
|
if (profiler) {
|
||||||
|
profiler->EndRegion("preprocess");
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure that the validation process won't be called twice
|
// Ensure that the validation process won't be called twice
|
||||||
ApplyPostProcessing(pFlags & (~aiProcess_ValidateDataStructure));
|
ApplyPostProcessing(pFlags & (~aiProcess_ValidateDataStructure));
|
||||||
}
|
}
|
||||||
|
@ -917,6 +941,10 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
|
||||||
|
|
||||||
// clear any data allocated by post-process steps
|
// clear any data allocated by post-process steps
|
||||||
pimpl->mPPShared->Clean();
|
pimpl->mPPShared->Clean();
|
||||||
|
|
||||||
|
if (profiler) {
|
||||||
|
profiler->EndRegion("total");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
|
#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
|
||||||
catch (std::exception &e)
|
catch (std::exception &e)
|
||||||
|
@ -979,16 +1007,27 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
|
||||||
pFlags |= aiProcess_ValidateDataStructure;
|
pFlags |= aiProcess_ValidateDataStructure;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (pimpl->bExtraVerbose)
|
if (pimpl->bExtraVerbose) {
|
||||||
DefaultLogger::get()->warn("Not a debug build, ignoring extra verbose setting");
|
DefaultLogger::get()->warn("Not a debug build, ignoring extra verbose setting");
|
||||||
|
}
|
||||||
#endif // ! DEBUG
|
#endif // ! DEBUG
|
||||||
|
|
||||||
|
boost::scoped_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL);
|
||||||
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
|
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
|
||||||
|
|
||||||
BaseProcess* process = pimpl->mPostProcessingSteps[a];
|
BaseProcess* process = pimpl->mPostProcessingSteps[a];
|
||||||
if( process->IsActive( pFlags)) {
|
if( process->IsActive( pFlags)) {
|
||||||
|
|
||||||
|
if (profiler) {
|
||||||
|
profiler->BeginRegion("postprocess");
|
||||||
|
}
|
||||||
|
|
||||||
process->SetupProperties( this );
|
process->SetupProperties( this );
|
||||||
process->ExecuteOnScene ( this );
|
process->ExecuteOnScene ( this );
|
||||||
|
|
||||||
|
if (profiler) {
|
||||||
|
profiler->EndRegion("postprocess");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if( !pimpl->mScene) {
|
if( !pimpl->mScene) {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (ASSIMP)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2010, ASSIMP Development Team
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the ASSIMP team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the ASSIMP Development Team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file Profiler.h
|
||||||
|
* @brief Utility to measure the respective runtime of each import step
|
||||||
|
*/
|
||||||
|
#ifndef INCLUDED_PROFILER_H
|
||||||
|
#define INCLUDED_PROFILER_H
|
||||||
|
|
||||||
|
#include "boost/timer.hpp"
|
||||||
|
|
||||||
|
#include "../include/DefaultLogger.h"
|
||||||
|
#include "TinyFormatter.h"
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
namespace Profiling {
|
||||||
|
|
||||||
|
using namespace Formatter;
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
/** Simple wrapper around boost::timer to simplify reporting. Timings are automatically
|
||||||
|
* dumped to the log file.
|
||||||
|
*/
|
||||||
|
class Profiler
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Profiler() {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** Start a named timer */
|
||||||
|
void BeginRegion(const std::string& region) {
|
||||||
|
regions[region] = boost::timer();
|
||||||
|
DefaultLogger::get()->debug((format("START `"),region,"`"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** End a specific named timer and write its end time to the log */
|
||||||
|
void EndRegion(const std::string& region) {
|
||||||
|
RegionMap::const_iterator it = regions.find(region);
|
||||||
|
if (it == regions.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultLogger::get()->debug((format("END `"),region,"`, dt= ",(*it).second.elapsed()," s"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef std::map<std::string,boost::timer> RegionMap;
|
||||||
|
RegionMap regions;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Binary file not shown.
150
doc/dox.h
150
doc/dox.h
|
@ -461,23 +461,6 @@ surely enough for almost any purpose. The process is simple:
|
||||||
<li> .. and pass it as last parameter to #aiImportFileEx
|
<li> .. and pass it as last parameter to #aiImportFileEx
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@section threadsafety Thread-safety and internal multi-threading
|
|
||||||
|
|
||||||
The ASSIMP library can be accessed by multiple threads simultaneously, as long as the
|
|
||||||
following prerequisites are fulfilled:
|
|
||||||
<ul>
|
|
||||||
<li> When using the C++-API make sure you create a new Importer instance for each thread.
|
|
||||||
Constructing instances of Importer is expensive, so it might be a good idea to
|
|
||||||
let every thread maintain its own thread-local instance (use it to
|
|
||||||
load as many models as you want).</li>
|
|
||||||
<li> The C-API is threadsafe as long as AI_C_THREADSAFE is defined. That's the default. </li>
|
|
||||||
<li> When supplying custom IO logic, make sure your underyling implementation is thead-safe.</li>
|
|
||||||
<li> Custom log streams or logger replacements have to be thread-safe, too.</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
See the @ref assimp_st section @endlink to learn how to build a lightweight variant
|
|
||||||
of ASSIMP which is not thread-safe and does not utilize multiple threads for loading.
|
|
||||||
|
|
||||||
@section logging Logging
|
@section logging Logging
|
||||||
|
|
||||||
The ASSIMP library provides an easy mechanism to log messages. For instance if you want to check the state of your
|
The ASSIMP library provides an easy mechanism to log messages. For instance if you want to check the state of your
|
||||||
|
@ -1264,7 +1247,7 @@ mat->Get(AI_MATKEY_COLOR_DIFFUSE,color);
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
<b>Note:</b> Get() is actually a template with explicit specializations for aiColor3D, aiColor4D, aiString, float, int and some others.
|
<b>Note:</b> Get() is actually a template with explicit specializations for aiColor3D, aiColor4D, aiString, float, int and some others.
|
||||||
Make sure that the type of the second parameter is matching the expected data type of the material property (no compile-time check yet!).
|
Make sure that the type of the second parameter matches the expected data type of the material property (no compile-time check yet!).
|
||||||
Don't follow this advice if you wish to encounter very strange results.
|
Don't follow this advice if you wish to encounter very strange results.
|
||||||
|
|
||||||
@section C C-API
|
@section C C-API
|
||||||
|
@ -1466,16 +1449,139 @@ Build: alles von CustomBuild + DirectX + MFC?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@page perf Performance
|
||||||
|
|
||||||
|
@section perf_overview Overview
|
||||||
|
|
||||||
|
This page discusses Assimps general performance and some ways to finetune and profile it. You will see that an
|
||||||
|
intelligent choice of postprocessing steps is essential for quick loading.
|
||||||
|
|
||||||
|
@section perf_profile Profiling
|
||||||
|
|
||||||
|
Assimp has builtin support for basic profiling and reporting. To turn it on, set the <tt>GLOB_MEASURE_TIME</tt>
|
||||||
|
configuration switch to <tt>true</tt> (nonzero). Results are dumped to the logfile, so you need to setup
|
||||||
|
an appropriate logger implementation with at least one output stream first. See the @link logging Logging Page @endlink
|
||||||
|
for the details.
|
||||||
|
|
||||||
|
A sample report looks like this (some unrelated log messages omitted, grouped entries for clarity):
|
||||||
|
|
||||||
|
@verbatim
|
||||||
|
Debug, T5488: START `total`
|
||||||
|
Info, T5488: Found a matching importer for this file format
|
||||||
|
|
||||||
|
Debug, T5488: START `import`
|
||||||
|
Info, T5488: BlendModifier: Applied the `Subdivision` modifier to `OBMonkey`
|
||||||
|
Debug, T5488: END `import`, dt= 3.516 s
|
||||||
|
|
||||||
|
|
||||||
|
Debug, T5488: START `preprocess`
|
||||||
|
Debug, T5488: END `preprocess`, dt= 0.001 s
|
||||||
|
Info, T5488: Entering post processing pipeline
|
||||||
|
|
||||||
|
Debug, T5488: START `postprocess`
|
||||||
|
Debug, T5488: RemoveRedundantMatsProcess begin
|
||||||
|
Debug, T5488: RemoveRedundantMatsProcess finished
|
||||||
|
Debug, T5488: END `postprocess`, dt= 0.001 s
|
||||||
|
|
||||||
|
Debug, T5488: START `postprocess`
|
||||||
|
Debug, T5488: TriangulateProcess begin
|
||||||
|
Info, T5488: TriangulateProcess finished. All polygons have been triangulated.
|
||||||
|
Debug, T5488: END `postprocess`, dt= 3.415 s
|
||||||
|
|
||||||
|
Debug, T5488: START `postprocess`
|
||||||
|
Debug, T5488: SortByPTypeProcess begin
|
||||||
|
Info, T5488: Points: 0, Lines: 0, Triangles: 1, Polygons: 0 (Meshes, X = removed)
|
||||||
|
Debug, T5488: SortByPTypeProcess finished
|
||||||
|
Debug, T5488: START `postprocess`
|
||||||
|
Debug, T5488: JoinVerticesProcess begin
|
||||||
|
Debug, T5488: Mesh 0 (unnamed) | Verts in: 503808 out: 126345 | ~74.922
|
||||||
|
Info, T5488: JoinVerticesProcess finished | Verts in: 503808 out: 126345 | ~74.9
|
||||||
|
Debug, T5488: END `postprocess`, dt= 2.052 s
|
||||||
|
Debug, T5488: START `postprocess`
|
||||||
|
Debug, T5488: FlipWindingOrderProcess begin
|
||||||
|
Debug, T5488: FlipWindingOrderProcess finished
|
||||||
|
Debug, T5488: END `postprocess`, dt= 0.006 s
|
||||||
|
|
||||||
|
Debug, T5488: START `postprocess`
|
||||||
|
Debug, T5488: LimitBoneWeightsProcess begin
|
||||||
|
Debug, T5488: LimitBoneWeightsProcess end
|
||||||
|
Debug, T5488: END `postprocess`, dt= 0.001 s
|
||||||
|
|
||||||
|
Debug, T5488: START `postprocess`
|
||||||
|
Debug, T5488: ImproveCacheLocalityProcess begin
|
||||||
|
Debug, T5488: Mesh 0 | ACMR in: 0.851622 out: 0.718139 | ~15.7
|
||||||
|
Info, T5488: Cache relevant are 1 meshes (251904 faces). Average output ACMR is 0.718139
|
||||||
|
Debug, T5488: ImproveCacheLocalityProcess finished.
|
||||||
|
Debug, T5488: END `postprocess`, dt= 1.903 s
|
||||||
|
|
||||||
|
Info, T5488: Leaving post processing pipeline
|
||||||
|
Debug, T5488: END `total`, dt= 11.269 s
|
||||||
|
@endverbatim
|
||||||
|
|
||||||
|
So, only one fourth of the total import time was used for the actual model import, while the rest of the
|
||||||
|
time was consumed by the #aiProcess_Triangulate, #aiProcess_JoinIdenticalVertices and #aiProcess_ImproveCacheLocality
|
||||||
|
postprocessing steps. It is therefore not a good idea to specify *all* postprocessing flags just because they
|
||||||
|
sound so nice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@page threading Threading
|
||||||
|
|
||||||
|
@section overview Overview
|
||||||
|
|
||||||
|
This page discusses both Assimps scalability in threaded environments, the precautions to be taken in order to
|
||||||
|
use it from multiple threads concurrently and finally its own ability to parallelize certain tasks internally.
|
||||||
|
|
||||||
|
@section threadsafety Thread-safety / Using Assimp concurrently from several threads
|
||||||
|
|
||||||
|
The library can be accessed by multiple threads simultaneously, as long as the
|
||||||
|
following prerequisites are fulfilled:
|
||||||
|
<ul>
|
||||||
|
<li> When using the C++-API make sure you create a new Importer instance for each thread.
|
||||||
|
Constructing instances of Importer is expensive, so it might be a good idea to
|
||||||
|
let every thread maintain its own thread-local instance (use it to
|
||||||
|
load as many models as you want).</li>
|
||||||
|
<li> The C-API is threadsafe as long as AI_C_THREADSAFE is defined. That's the default. </li>
|
||||||
|
<li> When supplying custom IO logic, make sure your underyling implementation is thead-safe.</li>
|
||||||
|
<li> Custom log streams or logger replacements have to be thread-safe, too.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Multiple concurrent imports may or may not be beneficial, however. For certain file formats in conjunction with
|
||||||
|
little postprocessing IO times tend to be the performance bottleneck, using multiple threads does therefore not
|
||||||
|
help. Intense postprocessing (especially the O(nlogn) steps #aiProcess_JoinIdenticalVertices,
|
||||||
|
#aiProcess_GenSmoothNormals and #aiProcess_CalcTangentSpace) together with file formats like X or Collada,
|
||||||
|
which are slow to parse, might scale well with multiple concurrent imports.
|
||||||
|
|
||||||
|
|
||||||
|
@section automt Internal threading
|
||||||
|
|
||||||
|
Automatic multi-threading is not currently implemented.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@page importer_notes Importer Notes
|
@page importer_notes Importer Notes
|
||||||
|
|
||||||
|
@section blender Blender
|
||||||
|
@subsection bl_overview Overview
|
||||||
|
|
||||||
|
Assimp provides a self-contained reimplementation of Blender's so called SDNA system (http://www.blender.org/development/architecture/notes-on-sdna/).
|
||||||
|
SDNA allows Blender to be fully backward AND forward compatible and to exchange
|
||||||
|
files created on any of the various platforms blender runs on with any other. Quick processing is another design goal -
|
||||||
|
BLEND is a fully-fledged binary monster and Assimp tries to read the most of it. Naturally, if Blender is the only modelling tool
|
||||||
|
in your asset work flow, consider writing a custom exporter from Blender if Assimp's format coverage does not meet your requirements.
|
||||||
|
|
||||||
|
@subsection bl_status Current status
|
||||||
|
|
||||||
|
@subsection bl_notes Notes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@section ogre Ogre
|
@section ogre Ogre
|
||||||
|
|
||||||
@subsection overview Overview
|
@subsection overview Overview
|
||||||
Ogre importer is currently optimized for the Blender Ogre exporter, because thats the only one that i use.
|
Ogre importer is currently optimized for the Blender Ogre exporter, because thats the only one that i use. You can find the Blender Ogre exporter at: http://www.ogre3d.org/forums/viewtopic.php?f=8&t=45922
|
||||||
|
|
||||||
You can find the Blender Ogre exporter at: http://www.ogre3d.org/forums/viewtopic.php?f=8&t=45922
|
|
||||||
|
|
||||||
@subsection what What will be loaded?
|
@subsection what What will be loaded?
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,44 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#define INCLUDED_AI_CONFIG_H
|
#define INCLUDED_AI_CONFIG_H
|
||||||
|
|
||||||
|
|
||||||
|
// ###########################################################################
|
||||||
|
// LIBRARY SETTINGS
|
||||||
|
// General, global settings
|
||||||
|
// ###########################################################################
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** @brief Enables time measurements.
|
||||||
|
*
|
||||||
|
* If enabled, measures the time needed for each part of the loading
|
||||||
|
* process (i.e. IO time, importing, postprocessing, ..) and dumps
|
||||||
|
* these timings to the DefaultLogger. See the @link perf Performance
|
||||||
|
* Page@endlink for more information on this topic.
|
||||||
|
*
|
||||||
|
* Property type: bool. Default value: false.
|
||||||
|
*/
|
||||||
|
#define AI_CONFIG_GLOB_MEASURE_TIME \
|
||||||
|
"GLOB_MEASURE_TIME"
|
||||||
|
|
||||||
|
# if 0 // not implemented yet
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** @brief Set Assimp's multithreading policy.
|
||||||
|
*
|
||||||
|
* This setting is ignored if Assimp was built without boost.thread
|
||||||
|
* support (ASSIMP_BUILD_NO_THREADING, which is implied by ASSIMP_BUILD_BOOST_WORKAROUND).
|
||||||
|
* Possible values are: -1 to let Assimp decide what to do, 0 to disable
|
||||||
|
* multithreading entirely and any number larger than 0 to force a specific
|
||||||
|
* number of threads. Assimp is always free to ignore this settings, which is
|
||||||
|
* merely a hint. Usually, the default value (-1) will be fine. However, if
|
||||||
|
* Assimp is used concurrently from multiple user threads, it might be useful
|
||||||
|
* to limit each Importer instance to a specific number of cores.
|
||||||
|
*
|
||||||
|
* For more information, see the @link threading Threading page@endlink.
|
||||||
|
* Property type: int, default value: -1.
|
||||||
|
*/
|
||||||
|
#define AI_CONFIG_GLOB_MULTITHREADING \
|
||||||
|
"GLOB_MULTITHREADING"
|
||||||
|
#endif
|
||||||
|
|
||||||
// ###########################################################################
|
// ###########################################################################
|
||||||
// POST PROCESSING SETTINGS
|
// POST PROCESSING SETTINGS
|
||||||
// Various stuff to fine-tune the behavior of a specific post processing step.
|
// Various stuff to fine-tune the behavior of a specific post processing step.
|
||||||
|
@ -136,7 +174,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* important additional information which you intend to parse.
|
* important additional information which you intend to parse.
|
||||||
* For rendering, you can still render all meshes in the scene without
|
* For rendering, you can still render all meshes in the scene without
|
||||||
* any transformations.
|
* any transformations.
|
||||||
* Property type: integer (0: false; !0: true). Default value: false.
|
* Property type: bool. Default value: false.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_PP_PTV_KEEP_HIERARCHY \
|
#define AI_CONFIG_PP_PTV_KEEP_HIERARCHY \
|
||||||
"PP_PTV_KEEP_HIERARCHY"
|
"PP_PTV_KEEP_HIERARCHY"
|
||||||
|
@ -159,7 +197,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* degenerated lines to points. See the documentation to the
|
* degenerated lines to points. See the documentation to the
|
||||||
* #aiProcess_FindDegenerates step for a detailed example of the various ways
|
* #aiProcess_FindDegenerates step for a detailed example of the various ways
|
||||||
* to get rid of these lines and points if you don't want them.
|
* to get rid of these lines and points if you don't want them.
|
||||||
* Property type: integer (0: false; !0: true). Default value: false.
|
* Property type: bool. Default value: false.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_PP_FD_REMOVE \
|
#define AI_CONFIG_PP_FD_REMOVE \
|
||||||
"PP_FD_REMOVE"
|
"PP_FD_REMOVE"
|
||||||
|
@ -402,7 +440,7 @@ enum aiComponent
|
||||||
|
|
||||||
// ###########################################################################
|
// ###########################################################################
|
||||||
// IMPORTER SETTINGS
|
// IMPORTER SETTINGS
|
||||||
// Various stuff to fine-tune the behaviour of a specific importer plugin.
|
// Various stuff to fine-tune the behaviour of specific importer plugins.
|
||||||
// ###########################################################################
|
// ###########################################################################
|
||||||
|
|
||||||
|
|
||||||
|
@ -433,7 +471,7 @@ enum aiComponent
|
||||||
/** @brief Configures the AC loader to collect all surfaces which have the
|
/** @brief Configures the AC loader to collect all surfaces which have the
|
||||||
* "Backface cull" flag set in separate meshes.
|
* "Backface cull" flag set in separate meshes.
|
||||||
*
|
*
|
||||||
* Property type: integer (0: false; !0: true). Default value: true.
|
* Property type: bool. Default value: true.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL \
|
#define AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL \
|
||||||
"IMPORT_AC_SEPARATE_BFCULL"
|
"IMPORT_AC_SEPARATE_BFCULL"
|
||||||
|
@ -444,7 +482,7 @@ enum aiComponent
|
||||||
* default, Assimp performs the subdivision using the standard
|
* default, Assimp performs the subdivision using the standard
|
||||||
* Catmull-Clark algorithm
|
* Catmull-Clark algorithm
|
||||||
*
|
*
|
||||||
* Property type: integer (0: false; !0: true). Default value: true.
|
* * Property type: bool. Default value: true.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION \
|
#define AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION \
|
||||||
"IMPORT_AC_EVAL_SUBDIVISION"
|
"IMPORT_AC_EVAL_SUBDIVISION"
|
||||||
|
@ -453,7 +491,7 @@ enum aiComponent
|
||||||
/** @brief Configures the UNREAL 3D loader to separate faces with different
|
/** @brief Configures the UNREAL 3D loader to separate faces with different
|
||||||
* surface flags (e.g. two-sided vs. single-sided).
|
* surface flags (e.g. two-sided vs. single-sided).
|
||||||
*
|
*
|
||||||
* Property type: integer (0: false; !0: true). Default value: true.
|
* * Property type: bool. Default value: true.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS \
|
#define AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS \
|
||||||
"UNREAL_HANDLE_FLAGS"
|
"UNREAL_HANDLE_FLAGS"
|
||||||
|
@ -466,7 +504,7 @@ enum aiComponent
|
||||||
* want to compute them on your own, if you need them. This option is intended
|
* want to compute them on your own, if you need them. This option is intended
|
||||||
* for model viewers which want to offer an easy way to apply textures to
|
* for model viewers which want to offer an easy way to apply textures to
|
||||||
* terrains.
|
* terrains.
|
||||||
* Property type: integer (0: false; !0: true). Default value: false.
|
* * Property type: bool. Default value: false.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_IMPORT_TER_MAKE_UVS \
|
#define AI_CONFIG_IMPORT_TER_MAKE_UVS \
|
||||||
"IMPORT_TER_MAKE_UVS"
|
"IMPORT_TER_MAKE_UVS"
|
||||||
|
@ -475,19 +513,20 @@ enum aiComponent
|
||||||
/** @brief Configures the ASE loader to always reconstruct normal vectors
|
/** @brief Configures the ASE loader to always reconstruct normal vectors
|
||||||
* basing on the smoothing groups loaded from the file.
|
* basing on the smoothing groups loaded from the file.
|
||||||
*
|
*
|
||||||
* Many ASE files have invalid normals (they're not orthonormal).
|
* Some ASE files have carry invalid normals, other don't.
|
||||||
* Property type: integer (0: false; !0: true). Default value: true.
|
* * Property type: bool. Default value: true.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS \
|
#define AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS \
|
||||||
"IMPORT_ASE_RECONSTRUCT_NORMALS"
|
"IMPORT_ASE_RECONSTRUCT_NORMALS"
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** @brief Configures the M3D loader to process multi-part player models.
|
/** @brief Configures the M3D loader to detect and process multi-part
|
||||||
|
* Quake player models.
|
||||||
*
|
*
|
||||||
* These models usually consist of 3 files, lower.md3, upper.md3 and
|
* These models usually consist of 3 files, lower.md3, upper.md3 and
|
||||||
* head.md3. If this property is set to true, Assimp will try to load and
|
* head.md3. If this property is set to true, Assimp will try to load and
|
||||||
* combine all three files if one of them is loaded.
|
* combine all three files if one of them is loaded.
|
||||||
* Property type: integer (0: false; !0: true). Default value: true.
|
* Property type: bool. Default value: true.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_IMPORT_MD3_HANDLE_MULTIPART \
|
#define AI_CONFIG_IMPORT_MD3_HANDLE_MULTIPART \
|
||||||
"IMPORT_MD3_HANDLE_MULTIPART"
|
"IMPORT_MD3_HANDLE_MULTIPART"
|
||||||
|
@ -545,7 +584,7 @@ enum aiComponent
|
||||||
* and combined with the MD5MESH file. This configuration option can be
|
* and combined with the MD5MESH file. This configuration option can be
|
||||||
* used to disable this behaviour.
|
* used to disable this behaviour.
|
||||||
*
|
*
|
||||||
* Property type: integer (0: false; !0: true). Default value: false.
|
* * Property type: bool. Default value: false.
|
||||||
*/
|
*/
|
||||||
#define AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD \
|
#define AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD \
|
||||||
"IMPORT_MD5_NO_ANIM_AUTOLOAD"
|
"IMPORT_MD5_NO_ANIM_AUTOLOAD"
|
||||||
|
|
Binary file not shown.
|
@ -151,7 +151,7 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter)
|
||||||
aiSetImportPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,g_smoothAngle);
|
aiSetImportPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,g_smoothAngle);
|
||||||
aiSetImportPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,nopointslines ? aiPrimitiveType_LINE | aiPrimitiveType_POINT : 0 );
|
aiSetImportPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,nopointslines ? aiPrimitiveType_LINE | aiPrimitiveType_POINT : 0 );
|
||||||
|
|
||||||
//aiSetImportPropertyInteger(AI_CONFIG_PP_FD_REMOVE,1);
|
aiSetImportPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,1);
|
||||||
//aiSetImportPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY,1);
|
//aiSetImportPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY,1);
|
||||||
|
|
||||||
// Call ASSIMPs C-API to load the file
|
// Call ASSIMPs C-API to load the file
|
||||||
|
|
|
@ -2425,6 +2425,10 @@
|
||||||
RelativePath="..\..\code\ParsingUtils.h"
|
RelativePath="..\..\code\ParsingUtils.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\code\Profiler.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\code\qnan.h"
|
RelativePath="..\..\code\qnan.h"
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in New Issue