Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "StdAfx.h"
- #include "../Include/MetaShaderImpl.h"
- #include "ed_log.h"
- #include "ed_vfs.hpp"
- #include "Util/Strings.h"
- #include "renderer/BinderFactory.h"
- #include "renderer/ShadingModelFactory.h"
- #include "renderer/IShaderManager.h"
- #include "../Include/MetaShaderManager.h"
- #include "../Include/Preprocessor.h"
- #include "../Include/render.h"
- #include "../Include/MetaShaderCache.h"
- #include <Windows.h>
- #ifndef EDGE
- #define SHADERS_DIR "Bazar/shaders/"
- #else
- #define SHADERS_DIR "graphics/shaders/"
- #endif
- static bool DEBUG_LOG = false;
- namespace render
- {
- namespace
- {
- // для compute
- const int GROUPSIZE = 128;
- class MsgException : public std::exception
- {
- public:
- MsgException(const ed::string& msg)
- : msg(msg)
- {
- }
- virtual ~MsgException() throw ()
- {
- }
- virtual const char* what() const throw ()
- {
- return msg.c_str();
- }
- private:
- ed::string msg;
- };
- struct SortOccurrence
- {
- public:
- MetaShaderImpl::BinderDesc *binderDesc;
- const render::BindVariable *variable;
- size_t pos;
- size_t len;
- render::VariableOccurrenceType occurrenceType;
- SortOccurrence(MetaShaderImpl::BinderDesc *a_binder_desc, const render::BindVariable* a_variable,
- size_t a_pos, size_t a_len, render::VariableOccurrenceType occurrenceType)
- : binderDesc(a_binder_desc),
- variable(a_variable),
- pos(a_pos),
- len(a_len),
- occurrenceType(occurrenceType)
- {
- }
- bool operator<(const SortOccurrence& other) const
- {
- return pos < other.pos;
- /*
- if (pos < other.pos)
- return true;
- else if (pos > other.pos)
- return false;
- if (binderDesc < other.binderDesc)
- return true;
- else if (binderDesc > other.binderDesc)
- return false;
- return len < other.len;
- */
- }
- };
- bool readFile(const ed::string& filePath, ed::string& content)
- {
- // read content of metashader file
- VFS::File file(filePath.c_str(), VFS::OpenRead);
- if (!(VFS_File*)file)
- return false;
- size_t inputFileSize = file.getsize();
- if (inputFileSize == 0)
- return false;
- ed::vector<char> raw_content(inputFileSize, ' ');
- auto code = file.read((void*)&raw_content.front(), inputFileSize);
- content = ed::string(raw_content.begin(), raw_content.end());
- return code != 0;
- }
- uint32_t GetLastErrorCode()
- {
- #ifdef _WINDOWS
- return ::GetLastError();
- #else
- return 1;
- #endif
- }
- uint32_t writeFile(const ed::string& filePath, const ed::string& content)
- {
- ed::string path = filePath;
- #if 0
- //def _WINDOWS
- /*
- * TODO: HACK: fix this in edCore.
- * On Windows if we want to handle path over MAX_PATH length (about 260 symbols), we need
- * to operate with paths, that start with `\\?\` namespace:
- * instead d:\dir\file.txt use \\?\d:\dir\file.txt
- */
- std::replace(path.begin(), path.end(), '/', '\\');
- ed::array<char, MAX_PATH + 1> currentDir;
- ::GetCurrentDirectoryA(currentDir.size(), ¤tDir.front());
- path = ed::string() + "\\\\?\\" + currentDir.data() + "\\" + path;
- #endif
- VFS::File outfile(path.c_str(), VFS::OpenWrite);
- if (outfile.operator VFS_File *() == nullptr)
- return GetLastErrorCode();
- if (content.empty())
- return 0;
- auto written = outfile.write(&content.front(), content.size());
- uint32_t errorCode = written > 0 ? 0 : 1;
- if (errorCode == 1)
- errorCode = GetLastErrorCode();
- return errorCode;
- }
- const ed::string DELIMS = "\r\n";
- const ed::string SHARP_LINE = "#line";
- /*
- * In-place replacer of lines that starts with #line. Such lines will be replaced with empty ones.
- */
- class SharpLineReplacer
- {
- public:
- SharpLineReplacer(ed::string& content)
- : content(content),
- original(content)
- {
- }
- /*
- * Replaces all lines.
- */
- void replace()
- {
- splittedLines = ed::splitStringAndDelims(content, DELIMS);
- content = "";
- size_t sharpLineSize = SHARP_LINE.size();
- for (size_t i = 0; i != splittedLines.size(); ++i)
- {
- ed::string& line = splittedLines[i].second;
- if (!splittedLines[i].first) // line feeds
- {
- content += line;
- continue;
- }
- if (line.size() < sharpLineSize)
- {
- content += line;
- continue;
- }
- ed::string::size_type nonWhiteSpacePos = line.find_first_not_of(" \t");
- if (nonWhiteSpacePos == ed::string::npos ||
- line.size() - nonWhiteSpacePos < sharpLineSize ||
- line.substr(nonWhiteSpacePos, sharpLineSize) != SHARP_LINE)
- {
- content += line;
- }
- }
- }
- /*
- * Reverts to original.
- */
- void undo()
- {
- content = original;
- return;
- #if 0
- size_t goalSize = SHARP_LINE.size();
- for (size_t i = 0; i != splittedLines.size(); ++i)
- {
- ed::string& line = splittedLines[i].second;
- content += line;
- }
- #endif
- }
- private:
- ed::string& content;
- ed::string original;
- ed::vector<std::pair<bool, ed::string>> splittedLines;
- };
- } // namespace
- MetaShaderImpl::BinderDesc::BinderDesc()
- {
- binder = 0;
- subItem = 0;
- }
- MetaShaderImpl::BinderDesc::~BinderDesc()
- {
- if( subItem)
- delete subItem;
- }
- ed::string MetaShaderImpl::getFolderForInterShader()
- {
- return MetaShaderCache::instance().getInterDir();
- }
- ed::string MetaShaderImpl::getFolderForFinalShader()
- {
- return MetaShaderCache::instance().getFinalDir();
- }
- ed::string MetaShaderImpl::getDestShaderPath(const ed::string& suffix, const ed::string& ext, bool inter)
- {
- ed::string transformModifierName = ed::extractFileNameNoExt(ed::extractFileNameNoExt(transformModifier));
- ed::string name = filePath + ";" + transformModifierName + suffix;
- ed::string hex = ed::md5(name.c_str(), name.length()).str();
- ed::string shaderName = ed::extractFileNameNoExt(filePath);
- ed::string dir = inter ? getFolderForInterShader() : getFolderForFinalShader();
- ed::string path = dir + shaderName;
- if (!transformModifierName.empty())
- path += "." + transformModifierName;
- path += "." + hex + "."+ext;
- return path;
- }
- MetaShaderImpl::MetaShaderImpl()
- {
- }
- void MetaShaderImpl::normalizeInput(
- const ed::string& aFilePath,
- const ed::string& aTransformModifier,
- const ed::vector<render::DefinePair>* definitions_
- )
- {
- ed::normalizePath(aFilePath, clearFilePath);
- ed::normalizePath(aTransformModifier, clearTransformModifier);
- ed::string filePath;
- ed::normalizePath(SHADERS_DIR + aFilePath, filePath);
- ed::string transformModifier;
- if (!aTransformModifier.empty())
- {
- ed::normalizePath(SHADERS_DIR + aTransformModifier, transformModifier);
- }
- const ed::vector<render::DefinePair>* definitions = nullptr;
- ed::vector<render::DefinePair> definitionsCopy;
- if (definitions_)
- {
- definitionsCopy = *definitions_;
- definitions = &definitionsCopy;
- MetaShaderCache::normalizeDefinitions(definitionsCopy);
- }
- MetaShaderManager::instance().registerMetaShader(this, aFilePath, aTransformModifier, definitions);
- // fileName
- this->fileName = filePath;
- this->filePath = filePath;
- this->transformModifier = transformModifier;
- if (definitions)
- {
- this->definitions = *definitions;
- for(int i = 0; i < definitions->size(); i++)
- {
- this->fileName += "|";
- const render::DefinePair& dp = (*definitions)[i];
- this->fileName += dp.getName();
- if(dp.getValue() && dp.getValue()[0])
- this->fileName += ed::string("=") + dp.getValue();
- }
- }
- }
- bool MetaShaderImpl::buildMetaShader(
- const ed::string& aFilePath,
- const ed::string& aTransformModifier,
- const ed::vector<render::DefinePair>* definitions_,
- const ed::string& outfx,
- ed::string& cacheKey
- )
- {
- normalizeInput(aFilePath, aTransformModifier, definitions_);
- cacheKey = getCacheKey(&definitions);
- ed::string shaderContent;
- ed::string definitionsString = getDefinitionsString(&definitions);
- ed::vector<ed::string> errors;
- ed::string msg;
- bool buildFailed = false;
- bool criticalError = false;
- BUILD_CODE code = BC_OK;
- try
- {
- code = buildShaderFromMetaShader(filePath, transformModifier, &definitions, shaderContent, definitionsString, errors);
- if (code != BC_OK)
- {
- for (size_t i = 0; i != errors.size(); ++i)
- msg += errors[i] + "\n";
- buildFailed = true;
- if (code == BC_CRITICAL_ERROR)
- criticalError = true;
- }
- }
- catch (const char* e)
- {
- msg += e;
- criticalError = true;
- }
- catch (const ed::string& e)
- {
- msg += e;
- criticalError = true;
- }
- catch(const std::exception& e)
- {
- msg += ed::string() + "std::exception: " + e.what();
- criticalError = true;
- }
- if (!msg.empty())
- ED_ERROR("%s", msg.c_str());
- if (buildFailed || criticalError)
- return false;
- {
- VFS_mkdir(getFolderForFinalShader().c_str());
- auto code = writeFile(outfx, shaderContent);
- if (code != 0)
- ED_ERROR("%s", "Failed to write metashader to \"" + outfx + "\", error code: " + ed::to_string(code));
- return code == 0;
- }
- }
- bool MetaShaderImpl::open(
- const ed::string& aFilePath,
- const ed::string& aTransformModifier,
- const ed::vector<render::DefinePair>* definitions_
- )
- {
- normalizeInput(aFilePath, aTransformModifier, definitions_);
- // для проверки валидности рендерайтемов
- ed::map<ed::string, BinderDesc> prev_bindersDesc = this->bindersDesc;
- // process
- auto prevCompileErrorAction = render::getCompileErrorAction();
- render::setCompileErrorAction(render::CEA_RISE_EXCEPTION);
- for (;;)
- {
- reset();
- ed::string shaderContent;
- ed::string definitionsString = getDefinitionsString(&definitions);
- ed::vector<ed::string> errors;
- ed::string msg;
- bool buildFailed = false;
- bool criticalError = false;
- BUILD_CODE code = BC_OK;
- try
- {
- code = buildShaderFromMetaShader(filePath, transformModifier, &definitions, shaderContent,
- definitionsString, errors);
- if (code != BC_OK)
- {
- for (size_t i = 0; i != errors.size(); ++i)
- msg += errors[i] + "\n";
- buildFailed = true;
- if (code == BC_CRITICAL_ERROR)
- criticalError = true;
- }
- }
- catch (const char* e)
- {
- msg += e;
- criticalError = true;
- }
- catch (const ed::string& e)
- {
- msg += e;
- criticalError = true;
- }
- catch(const std::exception& e)
- {
- msg += ed::string() + "std::exception: " + e.what();
- criticalError = true;
- }
- /*
- catch(...)
- {
- msg += "Unhandled exception";
- criticalError = true;
- }
- */
- if (buildFailed || criticalError)
- {
- ED_ERROR("Failed build metashader: '%s' transform: '%s'", fileName.c_str(), transformModifier.c_str());
- if (!msg.empty())
- ED_ERROR(" Reason: %s", msg.c_str());
- }
- // Не требует показа MB
- if (code == BC_REGULAR_ERROR)
- {
- render::setCompileErrorAction(prevCompileErrorAction);
- return false;
- }
- if (criticalError)
- {
- msg = "Cannot create shader from metashader:\n " + filePath + ".\n Reason: " + msg;
- invalidateCachedShaders(&definitions);
- if (prevCompileErrorAction == render::CEA_RISE_EXCEPTION)
- throw ed::string(msg);
- #ifdef _WINDOWS
- auto choice = MessageBox(0, msg.c_str(), "MetaShader - Shader Creation Error",
- MB_RETRYCANCEL | MB_ICONQUESTION);
- if (choice == IDCANCEL)
- {
- render::setCompileErrorAction(prevCompileErrorAction);
- exit(0);
- return false;
- }
- #endif
- continue;
- }
- if (!compileShader(definitionsString, shaderContent, &definitions, prevCompileErrorAction))
- {
- invalidateCachedShaders(&definitions);
- continue;
- }
- for (auto it = bindersDesc.begin(); it != bindersDesc.end(); )
- {
- auto& binderDesc = (*it).second;
- if (!binderDesc.binder->postprocessing(this, binderDesc.subItem))
- {
- // discard binder
- it = bindersDesc.erase(it);
- }
- else
- {
- ++it;
- }
- }
- break;
- }
- render::setCompileErrorAction(prevCompileErrorAction);
- inited = true;
- // проверить валидность уже созданных рендерайтемов
- if (!prev_bindersDesc.empty())
- {
- ed::string text1, text2;
- for (auto& it : bindersDesc)
- text1 += it.first + ", ";
- for (auto& it : prev_bindersDesc)
- text2 += it.first + ", ";
- if ( text1!= text2)
- {
- inited = false;
- ED_ERROR("Failed to reload metashader, binders is not matched: '%s' transform: '%s'", fileName.c_str(), transformModifier.c_str());
- ED_ERROR("prev binders = '%s'", text2.c_str());
- ED_ERROR(" binders = '%s'", text1.c_str());
- }
- for (auto& it : prev_bindersDesc)
- {
- it.second.binder = nullptr;
- it.second.subItem = nullptr;
- }
- }
- return true;
- }
- // декларация функции
- bool MetaShaderImpl::getFunctionInfo(const ed::string& name, Function& function)
- {
- ed::string clearname = name.substr(1);
- auto found = cachedShader->functions.find(clearname);
- if (found == cachedShader->functions.end())
- return false;
- function = found->second;
- return true;
- }
- bool MetaShaderImpl::bind(
- MetaShaderRenderItem* renderItem,
- render::MetaContext& metaContext)
- {
- if (!inited)
- return false;
- // Так compute не работает
- // if (!geometry->getPrimitives("", renderItem->ib, renderItem->primtype, renderItem->startprim, renderItem->facecount))
- // return false;
- renderItem->subitems.resize(bindersDesc.size(), nullptr);
- int i=0;
- for (auto it = bindersDesc.begin(); it != bindersDesc.end(); ++it, i++)
- {
- auto& binderDesc = (*it).second;
- if (renderItem->subitems[i])
- continue; // already binded
- render::RenderSubItem* rsi = binderDesc.binder->bind(
- this, *renderItem, binderDesc.subItem, metaContext);
- if( !rsi)
- return false;
- if (rsi == DELAYSUBITEM)
- continue;
- if(rsi == EMPTYSUBITEM)
- // сделаем свой делетер, ибо удалять не нужно
- renderItem->subitems[i].reset(rsi, [](render::RenderSubItem*){});
- else
- renderItem->subitems[i].reset(rsi);
- }
- return true;
- }
- // setupParams
- bool MetaShaderImpl::setupParams(
- MetaShaderRenderItem* renderItem,
- render::MetaContext& metaContext
- )
- {
- if (!inited)
- return false;
- int i=0;
- for (auto it = bindersDesc.begin(); it != bindersDesc.end(); ++it, i++)
- {
- auto& binderDesc = (*it).second;
- render::RenderSubItem* pEDTGRenderSubItem = renderItem->subitems[i].get();
- // if (pEDTGRenderSubItem == EMPTYSUBITEM)
- // return false;
- bool res = binderDesc.binder->render(this, binderDesc.subItem, pEDTGRenderSubItem, metaContext);
- if( !res)
- return false;
- }
- if( renderItem->ib)
- shader.bindIndices(*renderItem->ib);
- return true;
- }
- bool MetaShaderImpl::render(
- MetaShaderRenderItem* renderItem,
- render::MetaContext& metaContext,
- int instanceCount
- )
- {
- if (!inited)
- return false;
- // if( !renderItem->ib.isValid())
- // return false;
- shader.begin();
- render::ShaderSubItem* pDrawShaderSubItem = 0;
- render::RenderSubItem* pDrawRenderSubItem = 0;
- int i=0;
- for (auto it = bindersDesc.begin(); it != bindersDesc.end(); ++it, i++)
- {
- auto& binderDesc = (*it).second;
- render::RenderSubItem* pEDTGRenderSubItem = renderItem->subitems[i].get();
- // if (pEDTGRenderSubItem == EMPTYSUBITEM)
- // {
- // shader.end();
- // return false;
- // }
- bool res = binderDesc.binder->render(this, binderDesc.subItem, pEDTGRenderSubItem, metaContext);
- if( !res)
- {
- shader.end();
- return false;
- }
- }
- if (renderItem->ib && renderItem->ib->isValid())
- shader.bindIndices(*renderItem->ib);
- if( instanceCount<=1)
- shader.draw(0, renderItem->primtype, renderItem->startprim, renderItem->facecount);
- else
- shader.drawInstanced(0, renderItem->primtype, renderItem->startprim, renderItem->facecount, instanceCount);
- shader.end();
- return true;
- }
- // render
- bool MetaShaderImpl::compute(
- MetaShaderRenderItem* renderItem,
- render::MetaContext& metaContext
- )
- {
- if (!inited)
- return false;
- if( renderItem->computeElements==0)
- return false;
- shader.begin();
- render::ShaderSubItem* pDrawShaderSubItem = 0;
- render::RenderSubItem* pDrawRenderSubItem = 0;
- int i=0;
- for (auto it = bindersDesc.begin(); it != bindersDesc.end(); ++it, i++)
- {
- auto& binderDesc = (*it).second;
- bool res = binderDesc.binder->render(this, binderDesc.subItem, renderItem->subitems[i].get(), metaContext);
- if( !res)
- {
- shader.end();
- return false;
- }
- }
- int groupCount = (renderItem->computeElements + GROUPSIZE - 1) / GROUPSIZE;
- shader.compute(groupCount, 1, 1);
- shader.end();
- return true;
- }
- // dump
- ed::string MetaShaderImpl::dump(
- MetaShaderRenderItem* renderItem,
- render::MetaContext& metaContext
- )
- {
- ed::string text;
- #ifdef DUMPRENDER
- text += "META: ";
- if( renderItem->primtype!=render::PT_NONE)
- {
- text += render::verbose(renderItem->primtype);
- text.appendf(":%06d startPrim=%d ", renderItem->facecount, renderItem->startprim);
- }
- if( renderItem->computeElements)
- {
- text.appendf("elements: %05d ", renderItem->computeElements);
- }
- text += getName() + " ";
- if (inited)
- {
- text.appendf("binders[%d]: \n", bindersDesc.size());
- int i = 0;
- for (auto it = bindersDesc.begin(); it != bindersDesc.end(); ++it, i++)
- {
- auto& binderDesc = (*it).second;
- text.append(" ");
- text.append(binderDesc.binder->dump(this, binderDesc.subItem, renderItem->subitems[i].get(), metaContext));
- text.append("\n");
- }
- }
- else
- {
- text.appendf(" binders not inited");
- }
- #endif
- return text;
- }
- ed::string MetaShaderImpl::dump()
- {
- ed::string text;
- #ifdef DUMPRENDER
- ed::string definitionsString = getDefinitionsString(&definitions);
- ed::string dstPath = getDestShaderPath(definitionsString, "metafx", false);
- text += "\n" + dstPath;
- if (inited)
- {
- text += ed::string() + "\n\t" + "binders:";
- for (auto it = bindersDesc.begin(); it != bindersDesc.end(); ++it)
- {
- const auto& name = it->first;
- auto& binderDesc = (*it).second;
- text += "\n\t\t" + name + " " + ed::string_format("0x%p", binderDesc.binder);
- }
- }
- else
- {
- text.appendf(" binders not inited");
- }
- #endif
- return text;
- }
- bool MetaShaderImpl::addVertexStream(const render::BindVariable& variable, ed::string& semantic)
- {
- auto entry = vertexStreams.find(variable.name);
- if (entry != vertexStreams.end())
- {
- semantic = entry->second.semantic;
- return true;
- }
- if( variable.name=="VertexID")
- semantic = "SV_VertexID";
- else
- semantic = "TEXCOORD" + ed::to_string(vertexStreams.size());
- vertexStreams[variable.name].handle = render::INVALID_VE_HANDLE;
- vertexStreams[variable.name].semantic = semantic;
- return true;
- }
- MetaShaderImpl::BUILD_CODE MetaShaderImpl::buildShaderFromMetaShader(
- const ed::string& filePath,
- const ed::string& transformModifier,
- const ed::vector<render::DefinePair>* definitions,
- ed::string& shaderContent,
- ed::string& definitionsString,
- ed::vector<ed::string>& errors)
- {
- definitionsString = getDefinitionsString(definitions);
- auto cacheKey = getCacheKey(definitions);
- auto& shaderCache = render::MetaShaderCache::instance();
- auto shader = shaderCache.getShader(cacheKey);
- if (shader == nullptr)
- shader = shaderCache.createShader(cacheKey);
- cachedShader = shader;
- ed::string content;
- auto readFiles = [&]()
- {
- if (!readFile(filePath, content))
- {
- ED_ERROR("Failed to read %s", filePath.c_str());
- return BC_CRITICAL_ERROR;
- }
- // transform modifier
- if (!transformModifier.empty())
- {
- ed::string transformModifierContent;
- if (!readFile(transformModifier, transformModifierContent))
- {
- ED_ERROR("Failed to read %s", transformModifier.c_str());
- return BC_CRITICAL_ERROR;
- }
- content += "\n#line 1 \"" + transformModifier + "\"\n";
- content += transformModifierContent;
- }
- return BC_OK;
- };
- bool isFilesRead = false;
- // Первый прогон, с добавлением шейдинг моделей
- if (shader->sourceAvailable)
- {
- if (shader->preprocessed.needCompilation || shader->preprocessedAfterShadingModels.needCompilation)
- {
- auto code = readFiles();
- if (code != BC_OK)
- return code;
- isFilesRead = true;
- }
- // preprocess metashader
- if (shader->preprocessed.needCompilation)
- {
- if (DEBUG_LOG)
- ED_INFO(" PREP 1 %s", cacheKey.c_str());
- ed::string parsed;
- ed::vector<ed::string> foundIncludes;
- if (!preprocess(filePath, cacheKey,
- definitions, content, parsed, definitionsString,
- errors, getFolderForInterShader(), foundIncludes))
- return BC_CRITICAL_ERROR;
- // parse metashader
- ed::vector<ed::string> includes;
- includes.reserve(foundIncludes.size()+2);
- includes.push_back(this->filePath);
- for (size_t i = 0; i != foundIncludes.size(); ++i)
- includes.push_back(std::move(foundIncludes[i]));
- if (!transformModifier.empty())
- includes.push_back(transformModifier);
- ed::normalizePath(this->filePath, includes.front());
- shaderCache.uploadCacheFirstPass(shader, includes, std::move(parsed));
- // parse functions
- shader->functions.clear();
- SharpLineReplacer sharpLineReplacer(shader->preprocessed.content);
- sharpLineReplacer.replace();
- render::MetaShaderParser parser;
- parser.parseFunctions(shader->preprocessed.content, shader->functions);
- sharpLineReplacer.undo();
- shader->preprocessed.needCompilation = false;
- }
- // shading models
- ed::string shadingModelsText;
- ed::vector<render::IShadingModel*> shadingmodels;
- render::ShadingModelFactory::getInstance().getShadingModels(shadingmodels);
- for (int i = 0; i < shadingmodels.size(); i++)
- {
- shadingModelsText += shadingmodels[i]->Apply(this);
- }
- // detect changes in shading models
- shader->preprocessedAfterShadingModels.needCompilation |= shader->shadingModels != shadingModelsText;
- shader->shadingModels = std::move(shadingModelsText);
- }
- // Основной прогон
- // preprocess metashader
- if (shader->sourceAvailable && shader->preprocessedAfterShadingModels.needCompilation)
- {
- if (!isFilesRead)
- {
- auto code = readFiles();
- if (code != BC_OK)
- return code;
- }
- content += shader->shadingModels;
- // remove "@"
- content.replace_all("@", "");
- // write shadingmodels shader
- ed::string shadingmodelsFilePath = getDestShaderPath(definitionsString, "parse.metafx", true);
- VFS_mkdir(getFolderForInterShader().c_str());
- auto code = writeFile(shadingmodelsFilePath, content);
- if (code != 0)
- throw MsgException("failed to write shading models intermediate metashader to \""
- + shadingmodelsFilePath + "\", error code: " + ed::to_string(code));
- if (DEBUG_LOG)
- ED_INFO(" PREP 2 %s", cacheKey.c_str());
- ed::string parsed;
- ed::vector<ed::string> foundIncludes;
- if (!preprocess(filePath, cacheKey,
- definitions, content, parsed, definitionsString, errors,
- getFolderForInterShader(), foundIncludes))
- return BC_CRITICAL_ERROR;
- ed::string preprocessedFilePath = getDestShaderPath(definitionsString, "prep.metafx", true);
- VFS_mkdir(getFolderForInterShader().c_str());
- code = writeFile(preprocessedFilePath, parsed);
- if (code != 0)
- throw MsgException("failed to write preprocessed intermediate metashader to \""
- + preprocessedFilePath + "\", error code: " + ed::to_string(code));
- render::MetaShaderParser parser;
- // parse metashader
- shader->bindVariables.clear();
- parser.parseMetaShader(parsed, shader->bindVariables);
- ed::vector<ed::string> includes;
- includes.reserve(foundIncludes.size()+2);
- includes.push_back(this->filePath);
- for (size_t i = 0; i != foundIncludes.size(); ++i)
- includes.push_back(std::move(foundIncludes[i]));
- if (!transformModifier.empty())
- includes.push_back(transformModifier);
- ed::normalizePath(this->filePath, includes.front());
- shaderCache.uploadCacheSecondPass(shader, includes, std::move(parsed));
- }
- shaderContent = shader->preprocessedAfterShadingModels.content;
- // const guard for using pointers on map keys
- const auto& bindVariables = shader->bindVariables;
- bindVariablesSet.clear();
- for (auto it = bindVariables.begin(); it != bindVariables.end(); ++it)
- {
- bindVariablesSet.insert(it->first);
- }
- // determining all used binders
- for (auto it = bindVariables.begin(); it != bindVariables.end(); ++it)
- {
- const ed::string& bindType = (*it).first.binder;
- auto found = bindersDesc.find(bindType);
- // add binderDesc if first occurrence
- if (found == bindersDesc.end())
- {
- render::IBinder* binder = render::BinderFactory::getInstance().getBinder(bindType);
- if (binder == NULL)
- {
- #ifndef EDGE
- return BC_REGULAR_ERROR;
- #else
- continue;
- #endif // EDGE
- }
- render::ShaderSubItem* subItem = binder->initSubItem(this);
- if (subItem == NULL)
- {
- ED_ERROR("%s: %s binder sub item is NULL", getName().c_str(), bindType.c_str());
- return BC_REGULAR_ERROR;
- }
- BinderDesc& binderDesc = bindersDesc[bindType];
- binderDesc.binder = binder;
- binderDesc.subItem = subItem;
- }
- }
- // building all occurrences
- ed::vector<SortOccurrence> allOccurrences;
- allOccurrences.reserve(bindVariables.size()*4);
- for (auto it = bindVariables.begin(); it != bindVariables.end(); ++it)
- {
- auto& occurrences = (*it).second;
- // length = bindername + :: + variable name
- const ed::string& binderName = (*it).first.binder;
- if (bindersDesc.find(binderName) == bindersDesc.end())
- continue;
- for (size_t i = 0; i != occurrences.size(); ++i)
- {
- SortOccurrence occurrence(&bindersDesc[binderName], &it->first, occurrences[i].declPos,
- occurrences[i].declLen, occurrences[i].type);
- allOccurrences.push_back(occurrence);
- }
- }
- // sorting all variables occurrences by position
- std::sort(allOccurrences.begin(), allOccurrences.end());
- // Calling all binder->preprocess, replacing "::".
- // Variable declaration occurrences must be passed first and |globalOffset| helps in case if
- // outputted text has different size.
- size_t globalOffset = 0;
- for (size_t i = 0; i != allOccurrences.size(); ++i)
- {
- auto& occurrence = allOccurrences[i];
- size_t offset = occurrence.pos + globalOffset;
- size_t len = occurrence.len;
- ed::string text = shaderContent.substr(offset, len);
- // Removing duplicated uniform definitions which can be appeared from shading models.
- auto& varOccurrences = bindVariables.find(*occurrence.variable)->second;
- if (occurrence.variable->interpolation == render::VT_UNIFORM
- && varOccurrences[0].declPos != occurrence.pos
- && occurrence.occurrenceType != render::VOT_VALUE)
- {
- text.clear();
- // Removing all variable declaration up to ';' symbol. It helps to consider variable
- // with register specification:
- // Texture2DArray varyhouse__decalTexture : register(ps, t[0]);
- while ( offset + len < shaderContent.size() && shaderContent[offset + len] != ';')
- ++len;
- }
- else
- {
- occurrence.binderDesc->binder->preprocessing(this, *occurrence.variable,
- occurrence.occurrenceType,
- text, occurrence.binderDesc->subItem);
- }
- auto globalOffsetChange = text.end() - text.begin() - len;
- shaderContent.replace(shaderContent.begin() + offset, shaderContent.begin() + offset + len,
- text.begin(), text.end());
- globalOffset += globalOffsetChange;
- }
- return BC_OK;
- }
- void MetaShaderImpl::reset()
- {
- cachedShader = nullptr;
- bindersDesc.clear();
- vertexStreams.clear();
- bindVariablesSet.clear();
- inited = false;
- }
- const render::BindVariable* MetaShaderImpl::getBindVariable(const ed::string& binder, const ed::string& name)
- {
- auto found = bindVariablesSet.find(render::BindVariable("", binder, name));
- if (found == bindVariablesSet.end())
- return 0;
- return &(*found);
- }
- bool MetaShaderImpl::compileShader(
- const ed::string& definitionsString,
- const ed::string& shaderContent,
- const ed::vector<render::DefinePair>* definitions,
- render::COMPILEERRORACTION_ENUM globalRenderSetting
- )
- {
- ed::string proceededFilePath = getDestShaderPath(definitionsString, "metafx", false);
- if (!customFinalPath.empty())
- proceededFilePath = customFinalPath;
- ed::string contentOnDisk;
- auto cacheKey = getCacheKey(definitions);
- auto& shaderCache = MetaShaderCache::instance();
- try
- {
- auto shaderEntry = shaderCache.getShader(cacheKey);
- if (!shaderEntry)
- throw ed::string("No cached metashader " + cacheKey);
- if (shaderEntry->sourceAvailable)
- {
- if (!readFile(proceededFilePath, contentOnDisk) || contentOnDisk != shaderContent)
- {
- // write proceeded shader
- VFS_mkdir(getFolderForFinalShader().c_str());
- auto code = writeFile(proceededFilePath, shaderContent);
- if (code != 0)
- throw MsgException("failed to write created intermediate metashader to \""
- + proceededFilePath + "\", error code: " + ed::to_string(code));
- }
- }
- ed::string shaderName = clearFilePath + ":" + clearTransformModifier;
- auto file = shaderEntry->sourceAvailable ? proceededFilePath.c_str() : "no source";
- if (!shader.open(file, definitions, true, false, shaderName.c_str()))
- return false;
- }
- catch (const ed::string& e)
- {
- ED_ERROR("%s", e.c_str());
- if (globalRenderSetting == render::CEA_RISE_EXCEPTION)
- throw ed::string(e);
- #ifdef _WINDOWS
- auto choice = MessageBox(0, e.c_str(), "MetaShader - Compilation Error",
- MB_RETRYCANCEL | MB_ICONQUESTION);
- if (choice == IDCANCEL)
- {
- exit(0);
- return false;
- }
- #endif
- return false;
- }
- return true;
- }
- bool MetaShaderImpl::preprocess(const ed::string& filePath, const ed::string& cacheKey,
- const ed::vector<render::DefinePair>* definitions,
- const ed::string& content, ed::string& parsedContent,
- ed::string& definitionsString, ed::vector<ed::string>& errors,
- const ed::string& destDir, ed::vector<ed::string>& foundIncludes)
- {
- render::Preprocessor preprocessor;
- auto& preprocessorIncludePaths = MetaShaderCache::instance().getPreprocessorIncludePaths();
- for (auto path : preprocessorIncludePaths)
- preprocessor.addIncludeDir(path);
- definitionsString = getDefinitionsString(definitions);
- ed::vector<render::DefinePair> defArray;
- MetaShaderCache::instance().getGlobalDefined(defArray);
- for (int i = 0; i < defArray.size(); i++)
- {
- preprocessor.addMacroDefinition(defArray[i].getName(), defArray[i].getValue());
- }
- if( definitions)
- {
- for (size_t i = 0; i != definitions->size(); ++i)
- {
- preprocessor.addMacroDefinition((*definitions)[i].getName(), (*definitions)[i].getValue());
- }
- }
- ed::string stdParsedContent(parsedContent.c_str());
- if (!preprocessor.preprocess(content.c_str(), filePath.c_str(), stdParsedContent, destDir.c_str()))
- {
- parsedContent = stdParsedContent;
- ED_ERROR("Failed to preprocess shader:\n %s\nreason:", cacheKey.c_str());
- preprocessor.getErrors(errors);
- for (size_t i = 0; i != errors.size(); ++i)
- {
- ED_ERROR("%s", errors[i].c_str());
- }
- return false;
- }
- parsedContent = stdParsedContent;
- {
- const ed::vector<ed::string> &fi = preprocessor.getIncludes();
- foundIncludes.clear();
- foundIncludes.reserve(fi.size());
- for(auto it = fi.begin(); it != fi.end(); ++it){
- foundIncludes.push_back(*it);
- }
- }
- return true;
- }
- ed::string MetaShaderImpl::getDefinitionsString(const ed::vector<render::DefinePair>* definitions)
- const
- {
- return MetaShaderCache::getDefinitionsString(definitions);
- }
- ed::string MetaShaderImpl::getCacheKey(const ed::vector<render::DefinePair>* definitions) const
- {
- return MetaShaderCache::getCacheKey(clearFilePath, clearTransformModifier, definitions);
- }
- void MetaShaderImpl::invalidateCachedShaders(const ed::vector<render::DefinePair>* definitions) const
- {
- auto cacheKey = getCacheKey(definitions);
- auto &shaderCache = render::MetaShaderCache::instance();
- shaderCache.invalidateShader(cacheKey);
- }
- } // namespace render
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement