00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "renderserver.h"
00024 #include "api.h"
00025 #include "context.h"
00026 #include "paramset.h"
00027 #include "error.h"
00028 #include "include/asio.hpp"
00029
00030 #include <fstream>
00031 #include <boost/thread/xtime.hpp>
00032 #include <boost/archive/text_oarchive.hpp>
00033 #include <boost/archive/text_iarchive.hpp>
00034 #include <boost/iostreams/filtering_stream.hpp>
00035 #include <boost/date_time/posix_time/posix_time.hpp>
00036
00037 using namespace lux;
00038 using namespace boost::iostreams;
00039 using namespace std;
00040 using asio::ip::tcp;
00041
00042
00043
00044
00045
00046 RenderServer::RenderServer(int threadCount, int tcpPort) : threadCount(threadCount),
00047 tcpPort(tcpPort), state(UNSTARTED), serverThread(NULL) {
00048 }
00049
00050 RenderServer::~RenderServer() {
00051 if ((state == READY) && (state == BUSY))
00052 stop();
00053 }
00054
00055 void RenderServer::start() {
00056 if (state != UNSTARTED) {
00057 stringstream ss;
00058 ss << "Can not start a rendering server in state: " << state;
00059 luxError(LUX_SYSTEM, LUX_ERROR, ss.str().c_str());
00060
00061 return;
00062 }
00063
00064
00065 serverThread = new NetworkRenderServerThread(this);
00066 serverThread->serverThread = new boost::thread(boost::bind(
00067 NetworkRenderServerThread::run, serverThread));
00068
00069 state = READY;
00070 }
00071
00072 void RenderServer::join() {
00073 if ((state != READY) && (state != BUSY)) {
00074 stringstream ss;
00075 ss << "Can not join a rendering server in state: " << state;
00076 luxError(LUX_SYSTEM, LUX_ERROR, ss.str().c_str());
00077
00078 return;
00079 }
00080
00081 serverThread->join();
00082 }
00083
00084 void RenderServer::stop() {
00085 if ((state != READY) && (state != BUSY)) {
00086 stringstream ss;
00087 ss << "Can not stop a rendering server in state: " << state;
00088 luxError(LUX_SYSTEM, LUX_ERROR, ss.str().c_str());
00089
00090 return;
00091 }
00092
00093 serverThread->interrupt();
00094 serverThread->join();
00095
00096 state = STOPPED;
00097 }
00098
00099
00100
00101
00102
00103 static void printInfoThread() {
00104 while (true) {
00105 boost::xtime xt;
00106 boost::xtime_get(&xt, boost::TIME_UTC);
00107 xt.sec += 5;
00108 boost::thread::sleep(xt);
00109
00110 boost::posix_time::time_duration td(0, 0,
00111 (int) luxStatistics("secElapsed"), 0);
00112
00113 int sampleSec = (int)luxStatistics("samplesSec");
00114
00115 if (sampleSec > 0) {
00116 stringstream ss;
00117 ss << td << " " << sampleSec << " samples/sec " << " "
00118 << (float) luxStatistics("samplesPx") << " samples/pix";
00119 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00120 }
00121 }
00122 }
00123
00124 static void processCommandFilm(void (&f)(const string &, const ParamSet &), basic_istream<char> &stream) {
00125 string type;
00126 ParamSet params;
00127 stream >> type;
00128
00129 if((type != "fleximage") && (type != "multiimage")) {
00130 stringstream ss;
00131 ss << "Unsupported film type for server rendering: " << type;
00132 luxError(LUX_SYSTEM, LUX_ERROR, ss.str().c_str());
00133
00134 return;
00135 }
00136
00137 boost::archive::text_iarchive ia(stream);
00138 ia >> params;
00139
00140
00141
00142 params.EraseBool("write_tonemapped_exr");
00143 params.EraseBool("write_untonemapped_exr");
00144 params.EraseBool("write_untonemapped_igi");
00145 params.EraseBool("write_tonemapped_igi");
00146 params.EraseBool("write_tonemapped_tga");
00147 params.EraseBool("write_resume_flm");
00148
00149 params.AddBool("write_tonemapped_exr", new bool(false));
00150 params.AddBool("write_untonemapped_exr", new bool(false));
00151 params.AddBool("write_untonemapped_igi", new bool(false));
00152 params.AddBool("write_tonemapped_igi", new bool(false));
00153 params.AddBool("write_tonemapped_tga", new bool(false));
00154 params.AddBool("write_resume_flm", new bool(false));
00155
00156 f(type.c_str(), params);
00157 }
00158
00159 static void processCommand(void (&f)(const string &, const ParamSet &), basic_istream<char> &stream) {
00160 string type;
00161 ParamSet params;
00162 stream >> type;
00163 boost::archive::text_iarchive ia(stream);
00164 ia >> params;
00165 f(type.c_str(), params);
00166 }
00167
00168 static void processCommand(void (&f)(const string &), basic_istream<char> &stream) {
00169 string type;
00170 stream >> type;
00171 f(type.c_str());
00172 }
00173
00174 static void processCommand(void (&f)(float, float, float), basic_istream<char> &stream) {
00175 float ax, ay, az;
00176 stream >> ax;
00177 stream >> ay;
00178 stream >> az;
00179 f(ax, ay, az);
00180 }
00181
00182 static void processCommand(void (&f)(float[16]), basic_istream<char> &stream) {
00183 float t[16];
00184 for (int i = 0; i < 16; i++)
00185 stream >> t[i];
00186 f(t);
00187 }
00188
00189
00190 void NetworkRenderServerThread::run(NetworkRenderServerThread *serverThread) {
00191
00192
00193 static const unsigned int CMD_LUXINIT = 2531407474U, CMD_LUXTRANSLATE = 2039302476U, CMD_LUXROTATE = 3982485453U, CMD_LUXSCALE = 1943523046U,
00194 CMD_LUXLOOKAT = 3747502632U, CMD_LUXCONCATTRANSFORM = 449663410U, CMD_LUXTRANSFORM = 2039102042U, CMD_LUXIDENTITY = 97907816U,
00195 CMD_LUXCOORDINATESYSTEM = 1707244427U, CMD_LUXCOORDSYSTRANSFORM = 2024449520U, CMD_LUXPIXELFILTER = 2384561510U,
00196 CMD_LUXFILM = 2531294310U, CMD_LUXSAMPLER = 3308802546U, CMD_LUXACCELERATOR = 1613429731U, CMD_LUXSURFACEINTEGRATOR = 4011931910U,
00197 CMD_LUXVOLUMEINTEGRATOR = 2954204437U, CMD_LUXCAMERA = 3378604391U, CMD_LUXWORLDBEGIN = 1247285547U,
00198 CMD_LUXATTRIBUTEBEGIN = 684297207U, CMD_LUXATTRIBUTEEND = 3427929065U, CMD_LUXTRANSFORMBEGIN = 567425599U,
00199 CMD_LUXTRANSFORMEND = 2773125169U, CMD_LUXTEXTURE = 475043887U, CMD_LUXMATERIAL = 4064803661U,
00200 CMD_LUXMAKENAMEDMATERIAL = 2355625968U, CMD_LUXNAMEDMATERIAL = 922480690U, CMD_LUXLIGHTSOURCE = 130489799U,
00201 CMD_LUXAREALIGHTSOURCE = 515057184U, CMD_LUXPORTALSHAPE = 3416559329U, CMD_LUXSHAPE = 1943702863U,
00202 CMD_LUXREVERSEORIENTATION = 2027239206U, CMD_LUXVOLUME = 4138761078U, CMD_LUXOBJECTBEGIN = 1097337658U,
00203 CMD_LUXOBJECTEND = 229760620U, CMD_LUXOBJECTINSTANCE = 4125664042U, CMD_LUXWORLDEND = 1582674973U, CMD_LUXGETFILM = 859419430U,
00204 CMD_SERVER_DISCONNECT = 2500584742U, CMD_SERVER_CONNECT = 332355398U,
00205 CMD_VOID = 5381U, CMD_SPACE = 177605U;
00206
00207 int listenPort = serverThread->renderServer->tcpPort;
00208 stringstream ss;
00209 ss << "Launching server [" << serverThread->renderServer->threadCount <<
00210 " threads] mode on port '" << listenPort << "'.";
00211 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00212
00213 try {
00214 asio::io_service io_service;
00215 tcp::endpoint endpoint(tcp::v4(), listenPort);
00216 tcp::acceptor acceptor(io_service, endpoint);
00217
00218 for (;;) {
00219 tcp::iostream stream;
00220 acceptor.accept(*stream.rdbuf());
00221 stream.setf(ios::scientific, ios::floatfield);
00222 stream.precision(16);
00223
00224
00225 string command;
00226 while (getline(stream, command)) {
00227 unsigned int hash = DJBHash(command);
00228
00229 if ((command != "") && (command != " ")) {
00230 ss.str("");
00231 ss << "Server processing command: '" << command <<
00232 "' (hash: " << hash << ")";
00233 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00234 }
00235
00236
00237 switch (hash) {
00238 case CMD_VOID:
00239 case CMD_SPACE:
00240 break;
00241 case CMD_SERVER_DISCONNECT:
00242
00243 luxExit();
00244 luxWait();
00245 luxCleanup();
00246 serverThread->renderServer->state = RenderServer::READY;
00247 break;
00248 case CMD_SERVER_CONNECT:
00249 if (serverThread->renderServer->state == RenderServer::READY) {
00250 serverThread->renderServer->state = RenderServer::BUSY;
00251 stream << "OK" <<endl;
00252 } else
00253 stream << "BUSY" <<endl;
00254 break;
00255 case CMD_LUXINIT:
00256 luxError(LUX_BUG, LUX_SEVERE, "Server already initialized");
00257 break;
00258 case CMD_LUXTRANSLATE: processCommand(Context::luxTranslate, stream);
00259 break;
00260 case CMD_LUXROTATE:
00261 {
00262 float angle, ax, ay, az;
00263 stream >> angle;
00264 stream >> ax;
00265 stream >> ay;
00266 stream >> az;
00267
00268 luxRotate(angle, ax, ay, az);
00269 }
00270 break;
00271 case CMD_LUXSCALE: processCommand(Context::luxScale, stream);
00272 break;
00273 case CMD_LUXLOOKAT:
00274 {
00275 float ex, ey, ez, lx, ly, lz, ux, uy, uz;
00276 stream >> ex;
00277 stream >> ey;
00278 stream >> ez;
00279 stream >> lx;
00280 stream >> ly;
00281 stream >> lz;
00282 stream >> ux;
00283 stream >> uy;
00284 stream >> uz;
00285
00286 luxLookAt(ex, ey, ez, lx, ly, lz, ux, uy, uz);
00287 }
00288 break;
00289 case CMD_LUXCONCATTRANSFORM: processCommand(Context::luxConcatTransform, stream);
00290 break;
00291 case CMD_LUXTRANSFORM: processCommand(Context::luxTransform, stream);
00292 break;
00293 case CMD_LUXIDENTITY: Context::luxIdentity();
00294 break;
00295 case CMD_LUXCOORDINATESYSTEM: processCommand(Context::luxCoordinateSystem, stream);
00296 break;
00297 case CMD_LUXCOORDSYSTRANSFORM: processCommand(Context::luxCoordSysTransform, stream);
00298 break;
00299 case CMD_LUXPIXELFILTER: processCommand(Context::luxPixelFilter, stream);
00300 break;
00301 case CMD_LUXFILM:
00302 {
00303
00304
00305
00306 processCommandFilm(Context::luxFilm, stream);
00307 }
00308 break;
00309 case CMD_LUXSAMPLER: processCommand(Context::luxSampler, stream);
00310 break;
00311 case CMD_LUXACCELERATOR: processCommand(Context::luxAccelerator, stream);
00312 break;
00313 case CMD_LUXSURFACEINTEGRATOR: processCommand(Context::luxSurfaceIntegrator, stream);
00314 break;
00315 case CMD_LUXVOLUMEINTEGRATOR: processCommand(Context::luxVolumeIntegrator, stream);
00316 break;
00317 case CMD_LUXCAMERA: processCommand(Context::luxCamera, stream);
00318 break;
00319 case CMD_LUXWORLDBEGIN: Context::luxWorldBegin();
00320 break;
00321 case CMD_LUXATTRIBUTEBEGIN: Context::luxAttributeBegin();
00322 break;
00323 case CMD_LUXATTRIBUTEEND: Context::luxAttributeEnd();
00324 break;
00325 case CMD_LUXTRANSFORMBEGIN: Context::luxTransformBegin();
00326 break;
00327 case CMD_LUXTRANSFORMEND: Context::luxTransformEnd();
00328 break;
00329 case CMD_LUXTEXTURE:
00330 {
00331 string name, type, texname;
00332 ParamSet params;
00333 stream >> name;
00334 stream >> type;
00335 stream >> texname;
00336 boost::archive::text_iarchive ia(stream);
00337 ia >> params;
00338
00339
00340 string file = "";
00341 file = params.FindOneString(string("filename"), file);
00342 if (file.size()) {
00343
00344 {
00345 stringstream ss;
00346 ss << "Receiving file: '" << file << "'";
00347 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00348 }
00349
00350 bool first = true;
00351 string s;
00352 ofstream out(file.c_str(), ios::out | ios::binary);
00353 while (getline(stream, s) && s != "LUX_END_FILE") {
00354 if (!first)out << "\n";
00355 first = false;
00356 out << s;
00357 }
00358 out.flush();
00359 }
00360
00361 Context::luxTexture(name.c_str(), type.c_str(), texname.c_str(), params);
00362 }
00363 break;
00364 case CMD_LUXMATERIAL: processCommand(Context::luxMaterial, stream);
00365 break;
00366 case CMD_LUXMAKENAMEDMATERIAL: processCommand(Context::luxMakeNamedMaterial, stream);
00367 break;
00368 case CMD_LUXNAMEDMATERIAL: processCommand(Context::luxNamedMaterial, stream);
00369 break;
00370 case CMD_LUXLIGHTSOURCE: processCommand(Context::luxLightSource, stream);
00371 break;
00372 case CMD_LUXAREALIGHTSOURCE: processCommand(Context::luxAreaLightSource, stream);
00373 break;
00374 case CMD_LUXPORTALSHAPE: processCommand(Context::luxPortalShape, stream);
00375 break;
00376 case CMD_LUXSHAPE: processCommand(Context::luxShape, stream);
00377 break;
00378 case CMD_LUXREVERSEORIENTATION: Context::luxReverseOrientation();
00379 break;
00380 case CMD_LUXVOLUME: processCommand(Context::luxVolume, stream);
00381 break;
00382 case CMD_LUXOBJECTBEGIN: processCommand(Context::luxObjectBegin, stream);
00383 break;
00384 case CMD_LUXOBJECTEND: Context::luxObjectEnd();
00385 break;
00386 case CMD_LUXOBJECTINSTANCE: processCommand(Context::luxObjectInstance, stream);
00387 break;
00388 case CMD_LUXWORLDEND:
00389 {
00390 serverThread->engineThread = new boost::thread(&luxWorldEnd);
00391
00392
00393 while (!luxStatistics("sceneIsReady")) {
00394 boost::xtime xt;
00395 boost::xtime_get(&xt, boost::TIME_UTC);
00396 xt.sec += 1;
00397 boost::thread::sleep(xt);
00398 }
00399
00400
00401 if(!serverThread->infoThread)
00402 serverThread->infoThread = new boost::thread(&printInfoThread);
00403
00404
00405 int threadsToAdd = serverThread->renderServer->threadCount;
00406 while (--threadsToAdd)
00407 Context::luxAddThread();
00408 }
00409 break;
00410 case CMD_LUXGETFILM:
00411 {
00412
00413
00414 if (serverThread->renderServer->state == RenderServer::BUSY) {
00415 luxError(LUX_NOERROR, LUX_INFO, "Transmitting film samples");
00416
00417 Context::luxTransmitFilm(stream);
00418 stream.close();
00419
00420 luxError(LUX_NOERROR, LUX_INFO, "Finished film samples transmission");
00421 } else {
00422 luxError(LUX_SYSTEM, LUX_ERROR, "Received a GetFilm command after a ServerDisconnect");
00423 stream.close();
00424 }
00425 }
00426 break;
00427 default:
00428 ss.str("");
00429 ss << "Unknown command '" << command << "'. Ignoring";
00430 luxError(LUX_BUG, LUX_SEVERE, ss.str().c_str());
00431 break;
00432 }
00433
00434
00435 }
00436 }
00437 } catch (exception& e) {
00438 luxError(LUX_BUG, LUX_ERROR, e.what());
00439 }
00440 }