@@ -14,19 +14,6 @@
namespace inl::gxeng {


//struct MaterialShaderParameter {
// enum eType {
// COLOR = 0,
// VALUE = 1,
// MAP_COLOR_2D = 2,
// MAP_VALUE_2D = 3,
// UNKNOWN = 1000,
// };
//
// eType type;
// int index;
//};

enum class eMaterialShaderParamType {
COLOR = 0,
VALUE = 1,
@@ -39,13 +26,28 @@ enum class eMaterialShaderParamType {

class MaterialShader {
public:
MaterialShader(ShaderManager* shaderManager) : m_shaderManager(shaderManager) {}
virtual ~MaterialShader() {};
virtual std::string GetShaderCode(ShaderManager& shaderManager) const = 0;

public:
static std::string RemoveComments(std::string code);
static std::string FindFunctionSignature(std::string code, const std::string& functionName);
static void SplitFunctionSignature(std::string signature, std::string& returnType, std::vector<std::pair<std::string, std::string>>& parameters);
static std::string GetParameterString(eMaterialShaderParamType type);
static eMaterialShaderParamType GetParameterType(std::string typeString);
static void ExtractShaderParameters(std::string code, const std::string& functionName, eMaterialShaderParamType& returnType, std::vector<eMaterialShaderParamType>& parameters);
protected:
std::string LoadShaderSource(std::string name) const;
private:
ShaderManager* m_shaderManager;
};


class MaterialShaderEquation : public MaterialShader {
public:
MaterialShaderEquation(ShaderManager* shaderManager) : MaterialShader(shaderManager) {}

std::string GetShaderCode(ShaderManager& shaderManager) const override;

void SetSourceName(const std::string& name);
@@ -84,6 +86,8 @@ class MaterialShaderGraph : public MaterialShader {
};

public:
MaterialShaderGraph(ShaderManager* shaderManager) : MaterialShader(shaderManager) {}

std::string GetShaderCode(ShaderManager& shaderManager) const override;

void SetGraph(std::vector<std::unique_ptr<MaterialShader>> nodes, std::vector<Link> links);
@@ -94,171 +98,13 @@ class MaterialShaderGraph : public MaterialShader {



inline std::string RemoveComments(std::string code) {
std::stringstream ss(code);

// remove single line comments by trimming commented-out tails, line-by-line
std::string noSingleLine;
std::string singleLine;
while (std::getline(ss, singleLine)) {
size_t idx = singleLine.find_first_of("//");
if (idx != singleLine.npos) {
singleLine = singleLine.substr(0, idx - 1);
}
noSingleLine += singleLine;
}

// remove multiline comments by replacing regex template " /*anything*/ " to empty string
std::stringstream noComment;
std::regex multilinePattern(R"(/\*.*\*/)");
std::regex_replace(std::ostreambuf_iterator<char>(noComment), noSingleLine.begin(), noSingleLine.end(), multilinePattern, "");

std::string ret = noComment.str();
return ret;
}


inline std::string FindFunctionSignature(std::string code, const std::string& functionName) {
// regex to match " functionName ( anything ) { "
std::regex signaturePattern(functionName + R"(\s*\(.*\)\s*\{)");

// find matches
std::smatch matches;
if (!std::regex_search(code, matches, signaturePattern)) {
throw std::invalid_argument("No main function found in material shader.");
}

// march back towards return type over whitespaces
intptr_t matchIdx = matches[0].first - code.cbegin();
matchIdx -= 1;
while (matchIdx >= 0 && isspace(code[matchIdx])) {
--matchIdx;
}

// march back over return type's characters
intptr_t returnIdx = matchIdx;
while (returnIdx >= 0 && !isspace(code[returnIdx])) {
--returnIdx;
}
returnIdx = std::max(intptr_t(0), returnIdx);

// return type spans across range [returnIdx, matchIdx], it being empty range means failure
if (matchIdx == returnIdx) {
throw std::invalid_argument("Main function has no return type.");
}

// walk back from match's end until ')'
intptr_t matchEndIdx = matches[0].second - code.begin();
while (code[matchEndIdx] != ')') {
matchEndIdx--;
}

return code.substr(returnIdx, matchEndIdx - returnIdx);
}

inline void SplitFunctionSignature(std::string signature, std::string& returnType, std::vector<std::pair<std::string, std::string>>& parameters) {
// extract part between the parentheses
size_t opening = signature.find_first_of('(');
size_t closing = signature.find_first_of(')');
std::stringstream paramString(signature.substr(opening + 1, closing - opening - 1));

// split the parameters string to individual parameters, and process them
std::string param;
while (getline(paramString, param, ',')) {
if (param.size() == 0) {
throw std::invalid_argument("Parameter of main has zero characters.");
}
// trim leading and trailing whitespaces
intptr_t firstChar = 0;
while (firstChar < param.size() && isspace(param[firstChar])) {
++firstChar;
}
intptr_t lastChar = param.size() - 1;
while (lastChar >= firstChar && isspace(param[lastChar])) {
--lastChar;
}
if (firstChar >= lastChar) {
throw std::invalid_argument("Parameter of main has no type specifier or declaration name.");
}
param = param.substr(firstChar, lastChar);

// split param to type and name
firstChar = 0;
while (!isspace(param[firstChar])) {
++firstChar;
}
lastChar = param.size() - 1;
while (!isspace(param[lastChar])) {
--lastChar;
}

parameters.push_back({ param.substr(0, firstChar), param.substr(lastChar+1, param.npos) });
}

// get return type
intptr_t lastChar = 0;
while (!isspace(signature[lastChar])) {
++lastChar;
}
returnType = signature.substr(0, lastChar);
}

inline std::string GetParameterString(eMaterialShaderParamType type) {
switch (type) {
case eMaterialShaderParamType::COLOR: return "float4";
case eMaterialShaderParamType::MAP_COLOR_2D: return "MapColor2D";
case eMaterialShaderParamType::MAP_VALUE_2D: return "MapValue2D";
case eMaterialShaderParamType::UNKNOWN: return "anyád";
case eMaterialShaderParamType::VALUE: return "float";
}
}
inline eMaterialShaderParamType GetParameterType(std::string typeString) {
if (typeString == "float4") {
return eMaterialShaderParamType::COLOR;
}
else if (typeString == "float") {
return eMaterialShaderParamType::VALUE;
}
else if (typeString == "MapColor2D") {
return eMaterialShaderParamType::MAP_COLOR_2D;
}
else if (typeString == "MapValue2D") {
return eMaterialShaderParamType::MAP_VALUE_2D;
}
else {
return eMaterialShaderParamType::UNKNOWN;
}
}

inline void ExtractShaderParameters(std::string code, eMaterialShaderParamType& returnType, std::vector<eMaterialShaderParamType>& parameters) {
code = RemoveComments(code);
std::string signature = FindFunctionSignature(code, "main");

std::string returnTypeStr;
std::vector<std::pair<std::string, std::string>> paramList;
SplitFunctionSignature(signature, returnTypeStr, paramList);

returnType = GetParameterType(returnTypeStr);

// collect results
std::vector<eMaterialShaderParamType> params;
for (const auto& p : paramList) {
eMaterialShaderParamType type = GetParameterType(p.first);
params.push_back(type);
}

parameters = std::move(params);
}




// TEST IMPLEMENTATION
inline std::string MaterialGenPixelShader(std::string shadingFunction) {
// get material shading function's HLSL code
eMaterialShaderParamType returnType;
std::vector<eMaterialShaderParamType> params;
ExtractShaderParameters(shadingFunction, returnType, params);
MaterialShader::ExtractShaderParameters(shadingFunction, "main", returnType, params);

// rename "main" to something else
std::stringstream renameMain;
@@ -162,12 +162,10 @@ Task ForwardRender::GetTask() {

if (entities) {
GraphicsCommandList cmdList = context.GetGraphicsCommandList();
CopyCommandList cpyCmdList = context.GetCopyCommandList();

pipeline::RenderTexture2D depthTarget = depthStencil.QueryWrite(cpyCmdList, m_graphicsContext);
assert(depthTarget.type == pipeline::RenderTextureType::DEPTH_STENCIL);
DepthStencilView2D dsv = depthStencil.QueryDepthStencil(cmdList, m_graphicsContext);

RenderScene(depthTarget.dsv, *entities, camera, sun, cmdList);
RenderScene(dsv, *entities, camera, sun, cmdList);
result.AddCommandList(std::move(cmdList));
}

@@ -8,37 +8,11 @@ namespace inl::gxeng::pipeline {
Texture2D::Texture2D() {}


Texture2D::Texture2D(TextureView2D srv)
: Texture2D(srv, RenderTargetView2D())
{}


Texture2D::Texture2D(RenderTargetView2D rtv)
: Texture2D({}, rtv)
{}


Texture2D::Texture2D(TextureView2D srv, RenderTargetView2D rtv)
: m_srv(std::move(srv)),
m_renderTexture({RenderTextureType::RENDER_TARGET, rtv, {}}),
m_beenCopied(false),
m_beenUsed(false),
m_usageCount(std::make_shared<std::atomic_size_t>(1))
{}


Texture2D::Texture2D(TextureView2D srv, DepthStencilView2D dsv)
: m_srv(std::move(srv)),
m_renderTexture({ RenderTextureType::DEPTH_STENCIL, {}, dsv }),
m_beenCopied(false),
m_beenUsed(false),
m_usageCount(std::make_shared<std::atomic_size_t>(1))
{}


Texture2D::Texture2D(const Texture2D& rhs)
Texture2D::Texture2D(const Texture2D& rhs)
: m_srv(rhs.m_srv),
m_renderTexture(rhs.m_renderTexture),
m_rtv(rhs.m_rtv),
m_dsv(rhs.m_dsv),
m_uav(rhs.m_uav),
m_beenCopied(false),
m_beenUsed(false),
m_usageCount(rhs.m_usageCount)
@@ -51,10 +25,12 @@ Texture2D::Texture2D(const Texture2D& rhs)

Texture2D::Texture2D(Texture2D&& rhs)
: m_srv(std::move(rhs.m_srv)),
m_renderTexture(std::move(rhs.m_renderTexture)),
m_rtv(std::move(rhs.m_rtv)),
m_dsv(std::move(rhs.m_dsv)),
m_uav(std::move(rhs.m_uav)),
m_beenCopied(rhs.m_beenCopied),
m_beenUsed(rhs.m_beenUsed),
m_usageCount(std::move(rhs.m_usageCount))
m_usageCount(std::move(rhs.m_usageCount))
{
rhs.m_beenUsed = false;
rhs.m_beenCopied = false;
@@ -65,7 +41,9 @@ Texture2D& Texture2D::operator=(const Texture2D& rhs) {
Clean();

m_srv = rhs.m_srv;
m_renderTexture = rhs.m_renderTexture;
m_rtv = rhs.m_rtv;
m_dsv = rhs.m_dsv;
m_uav = rhs.m_uav;
m_usageCount = rhs.m_usageCount;
m_beenUsed = false;
m_beenCopied = false;
@@ -81,7 +59,9 @@ Texture2D& Texture2D::operator=(Texture2D&& rhs) {
Clean();

m_srv = std::move(rhs.m_srv);
m_renderTexture = std::move(rhs.m_renderTexture);
m_rtv = std::move(rhs.m_rtv);
m_dsv = std::move(rhs.m_dsv);
m_uav = std::move(rhs.m_uav);
m_usageCount = std::move(rhs.m_usageCount);
m_beenUsed = rhs.m_beenUsed;
m_beenCopied = rhs.m_beenCopied;
@@ -105,20 +85,32 @@ void Texture2D::Clean() {
}


void Texture2D::AddView(TextureView2D srv) {
m_srv = std::move(srv);
}
void Texture2D::AddView(RenderTargetView2D rtv) {
m_rtv = std::move(rtv);
}
void Texture2D::AddView(DepthStencilView2D dsv) {
m_dsv = std::move(dsv);
}
void Texture2D::AddView(RWTextureView2D uav) {
m_uav = std::move(uav);
}


bool Texture2D::Readable() const {
return (bool)m_srv;
}
bool Texture2D::Writable() const {
switch (m_renderTexture.type) {
case RenderTextureType::RENDER_TARGET:
return (bool)m_renderTexture.rtv;
case RenderTextureType::DEPTH_STENCIL:
return (bool)m_renderTexture.dsv;
default:
assert(false);
}
return false;

bool Texture2D::WritableRenderTarget() const {
return (bool)m_rtv;
}
bool Texture2D::WritableDepthStencil() const {
return (bool)m_dsv;
}
bool Texture2D::WritableRW() const {
return (bool)m_uav;
}


@@ -128,22 +120,39 @@ const TextureView2D& Texture2D::QueryRead() const {
}


const RenderTexture2D& Texture2D::QueryWrite(CopyCommandList& copyMaker, GraphicsContext& graphicsContext) {
const RenderTargetView2D& Texture2D::QueryRenderTarget(CopyCommandList& copyMaker, GraphicsContext& graphicsContext) {
CopyIfNeeded(copyMaker, graphicsContext);

return m_rtv;
}

const DepthStencilView2D& Texture2D::QueryDepthStencil(CopyCommandList& copyMaker, GraphicsContext& graphicsContext) {
CopyIfNeeded(copyMaker, graphicsContext);

return m_dsv;
}

const RWTextureView2D& Texture2D::QueryRW(CopyCommandList& copyMaker, GraphicsContext& graphicsContext) {
CopyIfNeeded(copyMaker, graphicsContext);

return m_uav;
}


void Texture2D::CopyIfNeeded(CopyCommandList& copyMaker, GraphicsContext& graphicsContext) {
if (!m_beenCopied) {
m_beenUsed = true;
m_beenCopied = true;

// determine if copy is needed
bool needCopy = *m_usageCount > 1;
if (!needCopy) {
return m_renderTexture;
}

// copy the whole texture
throw std::logic_error("Channeling a single texture to multiple nodes for writing is not supported yet.");
if (needCopy) {
throw std::logic_error("Channeling a single texture to multiple nodes for writing is not supported yet.");
}
}
}



}
@@ -17,48 +17,83 @@ namespace inl::gxeng::pipeline {

enum class RenderTextureType { RENDER_TARGET, DEPTH_STENCIL };

struct RenderTexture2D {
RenderTextureType type;

// Could be a union but would need to explicitly define the
// constructors and destructor for this struct
// which is too much boilerplate for so little performance gain.
RenderTargetView2D rtv;
DepthStencilView2D dsv;
template <class T, class... List>
struct is_any_of;

template <class T>
struct is_any_of<T> {
static constexpr bool value = false;
};

template <class T, class U, class... List>
struct is_any_of<T, U, List...> {
static constexpr bool value = std::is_same<T, U>::value || is_any_of<T, List...>::value;
};



class Texture2D {
public:
Texture2D();
Texture2D(TextureView2D srv);
Texture2D(RenderTargetView2D rtv);
Texture2D(TextureView2D srv, RenderTargetView2D rtv);
Texture2D(TextureView2D srv, DepthStencilView2D dsv);

template <class ViewHeadT, class... ViewT, class = std::enable_if_t<is_any_of<std::decay_t<ViewHeadT>, TextureView2D, RenderTargetView2D, DepthStencilView2D, RWTextureView2D>::value, void>>
Texture2D(ViewHeadT&& view, ViewT&&... views);

Texture2D(const Texture2D&);
Texture2D(Texture2D&&);
Texture2D& operator=(const Texture2D&);
Texture2D& operator=(Texture2D&&);
~Texture2D();

void AddView(TextureView2D srv);
void AddView(RenderTargetView2D rtv);
void AddView(DepthStencilView2D dsv);
void AddView(RWTextureView2D uav);

bool Readable() const;
bool Writable() const;
bool WritableRenderTarget() const;
bool WritableDepthStencil() const;
bool WritableRW() const;

// TODO(Artur) Nodes must be able to modify texture state even if reading only
// eg. set the texture to pixel shader resource
const TextureView2D& QueryRead() const;
const RenderTexture2D& QueryWrite(CopyCommandList& copyMaker, GraphicsContext& graphicsContext);
const RenderTargetView2D& QueryRenderTarget(CopyCommandList& copyMaker, GraphicsContext& graphicsContext);
const DepthStencilView2D& QueryDepthStencil(CopyCommandList& copyMaker, GraphicsContext& graphicsContext);
const RWTextureView2D& QueryRW(CopyCommandList& copyMaker, GraphicsContext& graphicsContext);
private:
void Clean();
void CopyIfNeeded(CopyCommandList& copyMaker, GraphicsContext& graphicsContext);

template <class ViewHeadT, class... ViewTailT>
void AddViews(ViewHeadT&& head, ViewTailT&&... tail);
void AddViews() {};
private:
TextureView2D m_srv;
RenderTexture2D m_renderTexture;
RenderTargetView2D m_rtv;
DepthStencilView2D m_dsv;
RWTextureView2D m_uav;
mutable bool m_beenCopied;
mutable bool m_beenUsed;
std::shared_ptr<std::atomic_size_t> m_usageCount;
};


template <class ViewHeadT, class... ViewT, class = std::enable_if_t<is_any_of<std::decay_t<ViewHeadT>, TextureView2D, RenderTargetView2D, DepthStencilView2D, RWTextureView2D>::value, void>>
Texture2D::Texture2D(ViewHeadT&& view, ViewT&&... views) :
m_beenCopied(false),
m_beenUsed(false),
m_usageCount(std::make_shared<std::atomic_size_t>(1))
{
AddViews(std::forward<ViewHeadT>(view), std::forward<ViewT>(views)...);
}


template <class ViewHeadT, class... ViewTailT>
void Texture2D::AddViews(ViewHeadT&& head, ViewTailT&&... tail) {
AddView(std::forward<ViewHeadT>(head));
AddViews(std::forward<ViewTailT>(tail)...);
}


}
@@ -45,9 +45,9 @@ int TestMaterialShader::Run() {
" return color*0.4f; \n"
"}";

MaterialShaderEquation shaderNode;
MaterialShaderEquation darkenNode;
MaterialShaderEquation mapNode;
MaterialShaderEquation shaderNode(nullptr);
MaterialShaderEquation darkenNode(nullptr);
MaterialShaderEquation mapNode(nullptr);
shaderNode.SetSourceCode(simpleShader);
darkenNode.SetSourceCode(darken);
mapNode.SetSourceCode(mapColor2D);
@@ -65,7 +65,7 @@ int TestMaterialShader::Run() {
{ 2, 3, 1 },
};

MaterialShaderGraph graph;
MaterialShaderGraph graph(nullptr);
graph.SetGraph(std::move(nodes), std::move(links));
std::string shaderCode = graph.GetShaderCode(*(ShaderManager*)nullptr);
cout << shaderCode << endl;