00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00027
00028 #ifdef WIN32
00029 #include <math.h>
00030 #else
00031 #include <dlfcn.h>
00032 #include <unistd.h>
00033 #include <sys/wait.h>
00034 #endif
00035
00036 #include <iostream>
00037 #include <fstream>
00038
00039 #include "Cc.hpp"
00040 #include "ShDebug.hpp"
00041 #include "ShStream.hpp"
00042 #include "ShVariant.hpp"
00043 #include "ShVariantFactory.hpp"
00044 #include "ShTypeInfo.hpp"
00045 #include "ShOptimizations.hpp"
00046
00047 #ifdef HAVE_CONFIG_H
00048 #include "config.h"
00049 #endif
00050
00051 #ifdef SH_CC_DEBUG
00052 # define SH_CC_DEBUG_PRINT(x) SH_DEBUG_PRINT(x)
00053 #else
00054 # define SH_CC_DEBUG_PRINT(x) do { } while(0)
00055 #endif
00056
00057
00058 namespace ShCc {
00059 using namespace SH;
00060
00061 #include "CcTexturesString.hpp"
00062
00063 std::string encode(const ShVariable& v) {
00064 std::stringstream ret;
00065 if (v.neg()) ret << "-";
00066 ret << v.name();
00067 ret << v.swizzle();
00068 return ret.str();
00069 }
00070
00071
00072 const char* makeVarname(const char* prefix, int suffix) {
00073 static char buffer[128];
00074 sprintf(buffer, "%s%d", prefix, suffix);
00075 return buffer;
00076 }
00077
00078 const char* InputPrefix = "var_i_";
00079 const char* OutputPrefix = "var_o_";
00080 const char* TempPrefix = "var_t_";
00081 const char* ConstPrefix = "var_c_";
00082 const char* TexturePrefix = "var_tex_";
00083 const char* StreamPrefix = "var_s_";
00084 const char* UniformPrefix= "var_u_";
00085
00086 CcVariable::CcVariable(void)
00087 : m_num(-1),
00088 m_size(-1),
00089 m_valueType(SH_VALUETYPE_END)
00090 {}
00091
00092 CcVariable::CcVariable(int num, const std::string& name, int size, ShValueType valueType)
00093 : m_num(num),
00094 m_name(name),
00095 m_size(size),
00096 m_valueType(valueType)
00097 {}
00098
00099 CcBackendCode::LabelFunctor::LabelFunctor(std::map<ShCtrlGraphNodePtr, int>& label_map)
00100 : m_cur_label(0),
00101 m_label_map(label_map)
00102 {}
00103
00104 void CcBackendCode::LabelFunctor::operator()(ShCtrlGraphNode* node)
00105 {
00106 m_label_map[node] = m_cur_label++;
00107 }
00108
00109 CcBackendCode::EmitFunctor::EmitFunctor(CcBackendCode* bec)
00110 : m_bec(bec)
00111 {}
00112
00113 void CcBackendCode::EmitFunctor::operator()(ShCtrlGraphNode* node)
00114 {
00115 m_bec->emit(node);
00116 }
00117
00118 CcBackendCode::CcBackendCode(const ShProgramNodeCPtr& program)
00119 : m_original_program(program),
00120 m_program(0),
00121 #ifdef WIN32
00122 m_hmodule(NULL),
00123 #else
00124 m_handle(NULL),
00125 #endif
00126 m_shader_func(NULL),
00127 m_cur_temp(0),
00128 m_params(NULL)
00129 {
00130 SH_CC_DEBUG_PRINT(__FUNCTION__);
00131
00132
00133 m_convertMap[SH_HALF] = SH_FLOAT;
00134 m_convertMap[SH_FINT] = SH_FLOAT;
00135 m_convertMap[SH_FSHORT] = SH_FLOAT;
00136 m_convertMap[SH_FBYTE] = SH_FLOAT;
00137 m_convertMap[SH_FUINT] = SH_FLOAT;
00138 m_convertMap[SH_FUSHORT] = SH_FLOAT;
00139 m_convertMap[SH_FUBYTE] = SH_FLOAT;
00140 }
00141
00142 CcBackendCode::~CcBackendCode(void)
00143 {
00144 SH_CC_DEBUG_PRINT(__FUNCTION__);
00145 }
00146
00147 bool CcBackendCode::allocateRegister(const ShVariableNodePtr& var)
00148 {
00149 SH_CC_DEBUG_PRINT(__FUNCTION__);
00150 return false;
00151 }
00152
00153 void CcBackendCode::freeRegister(const ShVariableNodePtr& var)
00154 {
00155 SH_CC_DEBUG_PRINT(__FUNCTION__);
00156 }
00157
00158 void CcBackendCode::upload(void)
00159 {
00160 SH_CC_DEBUG_PRINT(__FUNCTION__);
00161 }
00162
00163 void CcBackendCode::bind(void)
00164 {
00165 SH_CC_DEBUG_PRINT(__FUNCTION__);
00166 }
00167
00168 void CcBackendCode::update(void)
00169 {
00170 SH_CC_DEBUG_PRINT(__FUNCTION__);
00171 }
00172
00173 void CcBackendCode::updateUniform(const ShVariableNodePtr& uniform)
00174 {
00175 SH_CC_DEBUG_PRINT(__FUNCTION__);
00176 }
00177
00178 std::ostream& CcBackendCode::print(std::ostream& out)
00179 {
00180 SH_CC_DEBUG_PRINT(__FUNCTION__);
00181 return out;
00182 }
00183
00184 std::ostream& CcBackendCode::describe_interface(std::ostream& out)
00185 {
00186 SH_CC_DEBUG_PRINT(__FUNCTION__);
00187 return out;
00188 }
00189
00190 template<typename T>
00191 void CcBackendCode::allocate_varlist(const std::list<T> &varList, const char* varPrefix, const char* arrayName, const char* typePrefix)
00192 {
00193 int num = 0;
00194
00195 m_code << " // Assigning locals for " << arrayName << std::endl;
00196 for(typename std::list<T>::const_iterator I = varList.begin()
00197 ; I != varList.end(); ++I, ++num) {
00198 ShVariableNodePtr node = *I;
00199
00200 const char* name = makeVarname(varPrefix, num);
00201 const char* type = ctype(node->valueType());
00202 m_code << " " << typePrefix << " " << type << " *" << name
00203 << " = ((" << type << "*) " << arrayName << "[" << num << "]); // "
00204 << node->name() << std::endl;
00205
00206 m_varmap[node] = CcVariable(num, name, node->size(), node->valueType());
00207 }
00208 m_code << std::endl;
00209
00210 SH_CC_DEBUG_PRINT("Found " << num << " " << arrayName << "...");
00211 }
00212
00213 void CcBackendCode::allocate_consts(void)
00214 {
00215 int num = 0;
00216
00217 m_code << " // Declaring constants" << std::endl;
00218 for (ShProgramNode::VarList::const_iterator I = m_program->constants.begin()
00219 ; I != m_program->constants.end(); ++I, ++num) {
00220 ShVariableNodePtr node = (*I);
00221 const char* name = makeVarname(ConstPrefix, num);
00222
00223 m_code << "const " << ctype(node->valueType()) << " " << name << "[" << node->size() << "] = {"
00224 << node->getVariant()->encodeArray() << "}; // " << node->name() << std::endl;
00225
00226 m_varmap[node] = CcVariable(num, name, node->size(), node->valueType());
00227 }
00228 m_code << std::endl;
00229
00230 SH_CC_DEBUG_PRINT("Found " << num << " consts...");
00231 }
00232
00233 void CcBackendCode::allocate_inputs(void) {
00234 allocate_varlist(m_program->inputs, InputPrefix, "inputs");
00235 }
00236
00237 void CcBackendCode::allocate_outputs(void) {
00238 allocate_varlist(m_program->outputs, OutputPrefix, "outputs");
00239 }
00240
00241 void CcBackendCode::allocate_channels(void) {
00242 allocate_varlist(m_program->channels, StreamPrefix, "channels", "const");
00243 }
00244
00245 void CcBackendCode::allocate_textures(void) {
00246 allocate_varlist(m_program->textures, TexturePrefix, "textures", "const");
00247 }
00248
00249 void CcBackendCode::allocate_uniforms(void) {
00250 allocate_varlist(m_program->uniforms, UniformPrefix, "params");
00251
00252 ShProgramNode::VarList &uniforms = m_program->uniforms;
00253 m_params = new void*[uniforms.size()];
00254
00255
00256
00257
00258
00259 ShProgramNode::VarList::iterator I = uniforms.begin();
00260 for (int i = 0; I != m_program->uniforms.end(); ++I, ++i) {
00261 ShVariableNodePtr node = *I;
00262 m_params[i] = node->getVariant()->array();
00263 }
00264 }
00265
00266 void CcBackendCode::allocate_temps()
00267 {
00268 ShProgramNode::VarList::const_iterator I = m_program->temps.begin();
00269 for (; I != m_program->temps.end(); ++I, ++m_cur_temp) {
00270 ShVariableNodePtr node = (*I);
00271 const char* name = makeVarname(TempPrefix, m_cur_temp);
00272
00273 m_code << ctype(node->valueType()) << " " << name << "[" << node->size() << "]"
00274 << "; // " << node->name() << std::endl;
00275 m_varmap[node] = CcVariable(m_cur_temp, name, node->size(), node->valueType());
00276 }
00277
00278 SH_CC_DEBUG_PRINT("Found " << m_cur_temp << " temps...");
00279 }
00280
00281 std::string CcBackendCode::resolve(const ShVariable& v) {
00282 CcVariable &var = m_varmap[v.node()];
00283 SH_DEBUG_ASSERT(var.m_num != -1);
00284
00285 std::stringstream buf;
00286 if (v.neg()) buf << "-";
00287 buf << var.m_name;
00288 return buf.str();
00289 }
00290
00291 std::string CcBackendCode::resolve(const ShVariable& v, int idx) {
00292 CcVariable &var = m_varmap[v.node()];
00293 SH_DEBUG_ASSERT(var.m_num != -1);
00294
00295 std::stringstream buf;
00296 if (v.neg()) buf << "-";
00297 buf << var.m_name << "[" << v.swizzle()[idx] << "]";
00298 return buf.str();
00299 }
00300
00301 const char* CcBackendCode::ctype(ShValueType valueType)
00302 {
00303 switch(valueType) {
00304 case SH_HALF:
00305 case SH_FLOAT:
00306 case SH_FBYTE:
00307 case SH_FSHORT:
00308 case SH_FINT:
00309 case SH_FUBYTE:
00310 case SH_FUSHORT:
00311 case SH_FUINT:
00312 return "float";
00313
00314 case SH_DOUBLE: return "double";
00315 case SH_BYTE: return "char";
00316 case SH_SHORT: return "short";
00317 case SH_INT: return "int";
00318 case SH_UBYTE: return "unsigned char";
00319 case SH_USHORT: return "unsigned short";
00320 case SH_UINT: return "unsigned int";
00321 default:
00322 SH_DEBUG_ASSERT(0 && "Invalid value type");
00323 }
00324 return "unknown";
00325 }
00326
00327 void CcBackendCode::emit(ShBasicBlockPtr block) {
00328 if (!block) {
00329 m_code << " // empty basic block" << std::endl;
00330 }
00331 else {
00332 m_code << " // start basic block" << std::endl;
00333 ShBasicBlock::ShStmtList::const_iterator I = block->begin();
00334 for(;I != block->end(); ++I) {
00335 emit((*I));
00336 }
00337 m_code << " // end basic block" << std::endl;
00338 }
00339 }
00340
00341 void CcBackendCode::emit(ShCtrlGraphNodePtr node) {
00342 m_code << "label_" << m_label_map[node] << ":" << std::endl
00343 << " ;" << std::endl;
00344
00345 if (node->block) {
00346 emit(node->block);
00347 }
00348
00349 std::vector<ShCtrlGraphBranch>::iterator I = node->successors.begin();
00350 for(;I != node->successors.end(); ++I) {
00351
00352 m_code << " if (";
00353 for(int i = 0; i < (*I).cond.size(); i++) {
00354 if (i != 0) {
00355 m_code << " || ";
00356 }
00357
00358 m_code << "(";
00359 m_code << resolve((*I).cond, i) << " > 0";
00360 m_code << ")";
00361 }
00362 m_code << ")";
00363
00364 m_code << " goto label_" << m_label_map[(*I).node] << ";" << std::endl;
00365 }
00366
00367 if (node->follower) {
00368 m_code << " goto label_" << m_label_map[node->follower] << ";" << std::endl;
00369 }
00370
00371 if (node->successors.empty() && !node->follower) {
00372
00373 m_code << " return;" << std::endl;
00374 }
00375 }
00376
00377 bool CcBackendCode::generate(void) {
00378
00379 m_program = m_original_program->clone();
00380 ShContext::current()->enter(m_program);
00381 ShTransformer transform(m_program);
00382
00383 transform.convertToFloat(m_convertMap);
00384 if(transform.changed()) {
00385 optimize(m_program);
00386 m_program->collectVariables();
00387 } else {
00388 m_program = shref_const_cast<ShProgramNode>(m_original_program);
00389 }
00390 ShContext::current()->exit();
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402 SH_CC_DEBUG_PRINT("Creating label map...");
00403 LabelFunctor fl(m_label_map);
00404 m_program->ctrlGraph->dfs(fl);
00405
00406 allocate_consts();
00407 allocate_inputs();
00408 allocate_outputs();
00409 allocate_channels();
00410 allocate_textures();
00411 allocate_uniforms();
00412 allocate_temps();
00413
00414
00415 SH_CC_DEBUG_PRINT("Emitting code...");
00416 EmitFunctor fe(this);
00417 m_program->ctrlGraph->dfs(fe);
00418
00419
00420 std::stringstream prologue;
00421 prologue << "#include <math.h>" << std::endl;
00422 for(int i = 0; cc_texture_string[i][0] != 0; ++i) {
00423 prologue << cc_texture_string[i];
00424 }
00425
00426 prologue << std::endl;
00427 prologue << std::endl;
00428 prologue << "extern \"C\" "
00429 #ifdef WIN32
00430 << " void __declspec(dllexport) cc_shader("
00431 #else
00432 << " void cc_shader("
00433 #endif
00434 << "void** inputs, "
00435 << "void** params, "
00436 << "void** channels, "
00437 << "void** textures, "
00438 << "void** outputs)" << std::endl;
00439 prologue << "{" << std::endl;
00440
00441
00442
00443 std::stringstream epilogue;
00444 epilogue << "}" << std::endl;
00445
00446
00447
00448
00449
00450
00451
00452 SH_CC_DEBUG_PRINT("Outputting generated C++ code to ccstream.cpp");
00453 std::ofstream dbgout("ccstream.cpp");
00454 dbgout << prologue.str();
00455 dbgout << m_code.str();
00456 dbgout << epilogue.str();
00457 dbgout.flush();
00458 dbgout.close();
00459
00460
00461 #ifdef WIN32
00462
00463
00464 char path[1024];
00465 GetTempPath(1024, path);
00466
00467 char prefix[1024];
00468 GetTempFileName(path, "shcc", 0, prefix);
00469
00470 char cppfile[1024];
00471 char dllfile[1024];
00472 sprintf(cppfile, "%s.cpp", prefix);
00473 sprintf(dllfile, "%s.dll", prefix);
00474
00475
00476 std::ofstream fout(cppfile);
00477 fout << prologue.str();
00478 fout << m_code.str();
00479 fout << epilogue.str();
00480 fout.flush();
00481 fout.close();
00482
00483
00484 char cmdline[1024];
00485 sprintf(cmdline, "cl /EHsc /LD /Fe\"%s\" \"%s\"", dllfile, cppfile);
00486
00487 SH_CC_DEBUG_PRINT("cmdline: \"" << cmdline << "\"");
00488
00489 STARTUPINFO si;
00490 PROCESS_INFORMATION pi;
00491 ZeroMemory(&si, sizeof(STARTUPINFO));
00492 ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
00493 si.cb = sizeof(STARTUPINFO);
00494
00495 if (!CreateProcess(NULL, cmdline, NULL, NULL,
00496 TRUE, 0, NULL, NULL, &si, &pi)) {
00497 SH_CC_DEBUG_PRINT("CreateProcess failed!" << GetLastError());
00498 return false;
00499 }
00500
00501
00502 WaitForSingleObject(pi.hProcess, INFINITE);
00503
00504
00505 m_hmodule = LoadLibrary(dllfile);
00506 if (m_hmodule == NULL) {
00507 SH_CC_DEBUG_PRINT("LoadLibrary failed: " << GetLastError());
00508 return false;
00509 } else {
00510 m_shader_func = (CcShaderFunc)GetProcAddress(m_hmodule, "cc_shader");
00511
00512 if (m_shader_func == NULL) {
00513 SH_CC_DEBUG_PRINT("GetProcAddress failed: " << GetLastError());
00514 return false;
00515 }
00516 }
00517
00518 return true;
00519 #else
00520 char name[32];
00521 tmpnam(name);
00522 char ccfile[32];
00523 char sofile[32];
00524 sprintf(ccfile, "%s.cc", name);
00525 sprintf(sofile, "%s.so", name);
00526
00527 std::ofstream fout(ccfile);
00528 fout << prologue.str();
00529 fout << m_code.str();
00530 fout << epilogue.str();
00531 fout.flush();
00532 fout.close();
00533
00534 pid_t pid = fork();
00535 if (pid == 0) {
00536
00537 execlp("cc", "cc", "-O2", "-shared", "-o", sofile, ccfile, NULL);
00538 SH_CC_DEBUG_PRINT("exec failed (" << errno << ")");
00539 exit(-1);
00540 } else if (pid > 0) {
00541 int status;
00542 pid_t ret = waitpid(pid, &status, 0);
00543 if (ret == -1) {
00544 SH_CC_DEBUG_PRINT("wait failed...");
00545 return false;
00546 } else {
00547 SH_CC_DEBUG_PRINT("status = " << status);
00548 }
00549
00550 m_handle = dlopen(sofile, RTLD_NOW);
00551 if (m_handle == NULL) {
00552 SH_CC_DEBUG_PRINT("dlopen failed: " << dlerror());
00553 return false;
00554 } else {
00555 m_shader_func = (CcShaderFunc)dlsym(m_handle, "cc_shader");
00556 if (m_shader_func == NULL) {
00557 SH_CC_DEBUG_PRINT("dlsym failed: " << dlerror());
00558 return false;
00559 }
00560 }
00561 return true;
00562 } else {
00563
00564 SH_CC_DEBUG_PRINT("fork failed...");
00565 return false;
00566 }
00567 #endif
00568 }
00569
00570 bool CcBackendCode::execute(ShStream& dest)
00571 {
00572 if (!m_shader_func) {
00573 if (!generate()) {
00574 SH_CC_DEBUG_PRINT("failed to generate program...");
00575 return false;
00576 }
00577 }
00578
00579 int num_outputs = dest.size();
00580 int num_streams = m_program->channels.size();
00581 int num_textures = m_program->textures.size();
00582 void** inputs = NULL;
00583 void** outputs = new void*[num_outputs];
00584 void** streams = new void*[num_streams];
00585 void** textures = new void*[num_textures];
00586 std::vector<int> output_sizes(num_outputs);
00587 std::vector<int> output_types(num_outputs);
00588 std::vector<int> stream_sizes(num_streams);
00589 std::vector<int> stream_types(num_streams);
00590
00591 int sidx = 0;
00592
00593 SH_CC_DEBUG_PRINT("Assigning input channels to arrays");
00594 for(ShProgramNode::ChannelList::const_iterator I = m_program->channels_begin()
00595 ;I != m_program->channels_end(); ++I, ++sidx) {
00596 ShChannelNodePtr channel = (*I);
00597 ShHostStoragePtr storage = shref_dynamic_cast<ShHostStorage>(channel->memory()->findStorage("host"));
00598
00599 int datasize = shTypeInfo(channel->valueType(), SH_MEM)->datasize();
00600 stream_sizes[sidx] = datasize * channel->size();
00601 stream_types[sidx] = channel->valueType();
00602
00603 if (!storage) {
00604 storage = new ShHostStorage(channel->memory().object(),
00605 datasize * channel->size() * channel->count());
00606 }
00607 storage->dirty();
00608 streams[sidx] = storage->data();
00609 }
00610
00611 int tidx = 0;
00612 for(ShProgramNode::TexList::const_iterator I = m_program->textures_begin()
00613 ;I != m_program->textures_end(); ++I, ++tidx) {
00614 ShTextureNodePtr texture = (*I);
00615
00616 ShHostStoragePtr storage = shref_dynamic_cast<ShHostStorage>(
00617 texture->memory()->findStorage("host"));
00618
00619
00620
00621 textures[tidx] = storage->data();
00622 }
00623
00624
00625
00626 int oidx = 0;
00627 int count = 0;
00628
00629
00630 SH_CC_DEBUG_PRINT("Assigning output channels to arrays");
00631 for(ShStream::NodeList::iterator I = dest.begin()
00632 ;I != dest.end(); ++I, ++oidx) {
00633 ShChannelNodePtr channel = (*I);
00634 ShHostStoragePtr storage = shref_dynamic_cast<ShHostStorage>(
00635 channel->memory()->findStorage("host"));
00636
00637 int datasize = shTypeInfo(channel->valueType(), SH_MEM)->datasize();
00638 output_sizes[oidx] = datasize * channel->size();
00639 output_types[oidx] = channel->valueType();
00640
00641 if (!storage) {
00642 SH_CC_DEBUG_PRINT(" Allocating new storage?");
00643 storage = new ShHostStorage(channel->memory().object(),
00644 datasize * channel->size() * channel->count());
00645 }
00646 storage->dirty();
00647 outputs[oidx] = storage->data();
00648 SH_CC_DEBUG_PRINT(" outputs[" << oidx << "] = " << outputs[oidx]);
00649
00650 if (count == 0) {
00651 count = channel->count();
00652 } else if (count != channel->count()) {
00653 SH_CC_DEBUG_PRINT("channel count discrepancy...");
00654 return false;
00655 }
00656 }
00657
00658
00659 for(int i = 0; i < count; i++) {
00660 SH_CC_DEBUG_PRINT("execution " << i << " of " << count);
00661 m_shader_func(inputs, m_params, streams, textures, outputs);
00662
00663 for(int j = 0; j < num_streams; j++) {
00664 SH_CC_DEBUG_PRINT("advancing input stream "
00665 << j
00666 << " by "
00667 << stream_sizes[j]
00668 << " bytes." );
00669
00670
00671 streams[j] = reinterpret_cast<char*>(streams[j]) + stream_sizes[j];
00672 }
00673 for(int j = 0; j < num_outputs; j++) {
00674 SH_CC_DEBUG_PRINT("advancing output stream "
00675 << j
00676 << " by "
00677 << output_sizes[j]
00678 << " bytes." );
00679 outputs[j] = reinterpret_cast<char*>(outputs[j]) + output_sizes[j];
00680 }
00681 }
00682
00683 return true;
00684 }
00685
00686
00687 CcBackend::CcBackend(void) {
00688 SH_CC_DEBUG_PRINT(__FUNCTION__);
00689 }
00690
00691 CcBackend::~CcBackend(void) {
00692 SH_CC_DEBUG_PRINT(__FUNCTION__);
00693 }
00694
00695 std::string CcBackend::name(void) const {
00696 SH_CC_DEBUG_PRINT(__FUNCTION__);
00697 return "cc";
00698 }
00699
00700 ShBackendCodePtr CcBackend::generateCode(const std::string& target,
00701 const ShProgramNodeCPtr& program) {
00702 SH_CC_DEBUG_PRINT(__FUNCTION__);
00703 CcBackendCodePtr backendcode = new CcBackendCode(program);
00704 backendcode->generate();
00705 return backendcode;
00706 }
00707
00708 void CcBackend::execute(const ShProgramNodeCPtr& program, ShStream& dest) {
00709 SH_CC_DEBUG_PRINT(__FUNCTION__);
00710
00711 ShProgramNodePtr prg = shref_const_cast<ShProgramNode>(program);
00712 ShPointer<ShBackend> b(this);
00713
00714 CcBackendCodePtr backendcode = shref_dynamic_cast<CcBackendCode>(prg->code(b));
00715 backendcode->execute(dest);
00716 }
00717
00718 static CcBackend* backend = new CcBackend();
00719
00720 }
00721