Windows fixes for refactor

This commit is contained in:
Jack Andersen 2019-05-09 18:07:48 -10:00
parent 92e2c03a01
commit f596cbff83
13 changed files with 30 additions and 2644 deletions

View File

@ -15,7 +15,6 @@ endif()
endif()
include(ApplicationTools.cmake)
add_shader(test/test)
configure_file(DataSpecRegistry.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/DataSpecRegistry.hpp @ONLY)
@ -78,6 +77,3 @@ add_subdirectory(lib)
add_subdirectory(blender)
add_subdirectory(driver)
install(DIRECTORY include/hecl DESTINATION include/hecl)
# Runtime test
add_subdirectory(test)

View File

@ -322,6 +322,7 @@ def render_lightmaps(context):
pixel_size = int(area_data.lightmap_resolution)
# Mmm Cycles
context.scene.render.engine = 'CYCLES'
context.scene.render.bake.margin = pixel_size // 256
# Iterate materials and setup cycles
@ -330,6 +331,11 @@ def render_lightmaps(context):
# Set bake target node active
if 'CYCLES_OUT' in mat.node_tree.nodes:
mat.node_tree.nodes.active = mat.node_tree.nodes['CYCLES_OUT']
elif mat.hecl_lightmap and not mat.library:
image_out_node = mat.node_tree.nodes.new('ShaderNodeTexImage')
mat.node_tree.nodes.active = image_out_node
image_out_node.name = 'CYCLES_OUT'
image_out_node.image = make_or_load_cycles_image(mat, area_data)
else:
image_out_node = mat.node_tree.nodes.new('ShaderNodeTexImage')
mat.node_tree.nodes.active = image_out_node
@ -344,11 +350,11 @@ def render_lightmaps(context):
for obj in context.scene.objects:
if obj.type == 'MESH':
if not len(obj.data.uv_textures):
if not len(obj.data.uv_layers):
continue
# Make correct UV layer active
obj.data.uv_textures.active_index = 0
obj.data.uv_layers.active_index = 0
# Make lightmaps
bpy.ops.object.bake('INVOKE_DEFAULT', type='DIFFUSE', pass_filter={'DIRECT', 'INDIRECT'})

View File

@ -2,10 +2,15 @@ import bpy, sys, os, re, struct, traceback
ARGS_PATTERN = re.compile(r'''(?:"([^"]+)"|'([^']+)'|(\S+))''')
# Background mode seems to require quit() in some 2.80 builds
def _quitblender():
bpy.ops.wm.quit_blender()
quit()
# Extract pipe file descriptors from arguments
print('HECL Blender Launch', sys.argv)
if '--' not in sys.argv:
bpy.ops.wm.quit_blender()
_quitblender()
args = sys.argv[sys.argv.index('--')+1:]
readfd = int(args[0])
writefd = int(args[1])
@ -29,7 +34,7 @@ def readpipestr():
read_bytes = os.read(readfd, 4)
if len(read_bytes) != 4:
print('HECL connection lost or desynchronized')
bpy.ops.wm.quit_blender()
_quitblender()
read_len = struct.unpack('I', read_bytes)[0]
return os.read(readfd, read_len)
@ -44,7 +49,7 @@ def writepipebuf(linebytes):
def quitblender():
writepipestr(b'QUITTING')
bpy.ops.wm.quit_blender()
_quitblender()
class PathHasher:
def hashpath32(self, path):
@ -62,6 +67,11 @@ class PathHasher:
return int(read_str[0:16], 16)
return 0
# Ensure Blender 2.8 is being used
if bpy.app.version < (2, 80, 0):
writepipestr(b'NOT280')
_quitblender()
# If there's a third argument, use it as the .zip path containing the addon
did_install = False
if len(args) >= 4 and args[3] != 'SKIPINSTALL':
@ -80,12 +90,12 @@ try:
import hecl
except:
writepipestr(b'NOADDON')
bpy.ops.wm.quit_blender()
_quitblender()
# Quit if just installed
if did_install:
writepipestr(b'ADDONINSTALLED')
bpy.ops.wm.quit_blender()
_quitblender()
# Intro handshake
writepipestr(b'READY')
@ -108,7 +118,7 @@ def read_cmdargs():
cmdline = readpipestr()
if cmdline == b'':
print('HECL connection lost')
bpy.ops.wm.quit_blender()
_quitblender()
cmdargs = []
for match in ARGS_PATTERN.finditer(cmdline.decode()):
cmdargs.append(match.group(match.lastindex))

2
hecl/extern/boo vendored

@ -1 +1 @@
Subproject commit 3ad748f28b5377027c900ded38eeccdfeb7fe7f6
Subproject commit b340a8a42ecf10560891eab65d8c59a6f2640ccc

View File

@ -1,365 +0,0 @@
#include "hecl/Backend/GLSL.hpp"
#include "hecl/Runtime.hpp"
#include "athena/MemoryReader.hpp"
#include "athena/MemoryWriter.hpp"
#include "boo/graphicsdev/GLSLMacros.hpp"
static logvisor::Module Log("hecl::Backend::GLSL");
namespace hecl::Backend {
std::string GLSL::EmitTexGenSource2(TexGenSrc src, int uvIdx) const {
switch (src) {
case TexGenSrc::Position:
return "objPos.xy";
case TexGenSrc::Normal:
return "objNorm.xy";
case TexGenSrc::UV:
return hecl::Format("uvIn[%u]", uvIdx);
default:
break;
}
return std::string();
}
std::string GLSL::EmitTexGenSource4(TexGenSrc src, int uvIdx) const {
switch (src) {
case TexGenSrc::Position:
return "vec4(objPos.xyz, 1.0)";
case TexGenSrc::Normal:
return "vec4(objNorm.xyz, 1.0)";
case TexGenSrc::UV:
return hecl::Format("vec4(uvIn[%u], 0.0, 1.0)", uvIdx);
default:
break;
}
return std::string();
}
std::string GLSL::GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const {
std::string retval =
"layout(location=0) in vec3 posIn;\n"
"layout(location=1) in vec3 normIn;\n";
unsigned idx = 2;
if (col) {
retval += hecl::Format("layout(location=%u) in vec4 colIn[%u];\n", idx, col);
idx += col;
}
if (uv) {
retval += hecl::Format("layout(location=%u) in vec2 uvIn[%u];\n", idx, uv);
idx += uv;
}
if (w) {
retval += hecl::Format("layout(location=%u) in vec4 weightIn[%u];\n", idx, w);
}
return retval;
}
std::string GLSL::GenerateVertToFragStruct(size_t extTexCount, bool reflectionCoords) const {
std::string retval =
"struct VertToFrag\n"
"{\n"
" vec4 mvPos;\n"
" vec4 mvNorm;\n";
if (m_tcgs.size())
retval += hecl::Format(" vec2 tcgs[%u];\n", unsigned(m_tcgs.size()));
if (extTexCount)
retval += hecl::Format(" vec2 extTcgs[%u];\n", unsigned(extTexCount));
if (reflectionCoords)
retval +=
" vec2 reflectTcgs[2];\n"
" float reflectAlpha;\n";
return retval + "};\n";
}
std::string GLSL::GenerateVertUniformStruct(unsigned skinSlots, bool reflectionCoords) const {
std::string retval;
if (skinSlots == 0) {
retval =
"UBINDING0 uniform HECLVertUniform\n"
"{\n"
" mat4 mv;\n"
" mat4 mvInv;\n"
" mat4 proj;\n"
"};\n";
} else {
retval = hecl::Format(
"UBINDING0 uniform HECLVertUniform\n"
"{\n"
" mat4 objs[%u];\n"
" mat4 objsInv[%u];\n"
" mat4 mv;\n"
" mat4 mvInv;\n"
" mat4 proj;\n"
"};\n",
skinSlots, skinSlots);
}
retval +=
"struct HECLTCGMatrix\n"
"{\n"
" mat4 mtx;\n"
" mat4 postMtx;\n"
"};\n"
"UBINDING1 uniform HECLTexMtxUniform\n"
"{\n"
" HECLTCGMatrix texMtxs[8];\n"
"};\n";
if (reflectionCoords)
retval +=
"UBINDING3 uniform HECLReflectMtx\n"
"{\n"
" mat4 indMtx;\n"
" mat4 reflectMtx;\n"
" float reflectAlpha;\n"
"};\n"
"\n";
return retval;
}
std::string GLSL::GenerateAlphaTest() const {
return " if (colorOut.a < 0.25)\n"
" {\n"
" discard;\n"
" }\n";
}
std::string GLSL::GenerateReflectionExpr(ReflectionType type) const {
switch (type) {
case ReflectionType::None:
default:
return "vec3(0.0, 0.0, 0.0)";
case ReflectionType::Simple:
return "texture(reflectionTex, vtf.reflectTcgs[1]).rgb * vtf.reflectAlpha";
case ReflectionType::Indirect:
return "texture(reflectionTex, (texture(reflectionIndTex, vtf.reflectTcgs[0]).ab - "
"vec2(0.5, 0.5)) * vec2(0.5, 0.5) + vtf.reflectTcgs[1]).rgb * vtf.reflectAlpha";
}
}
void GLSL::reset(const IR& ir, Diagnostics& diag) {
/* Common programmable interpretation */
ProgrammableCommon::reset(ir, diag, "GLSL");
}
std::string GLSL::makeVert(unsigned col, unsigned uv, unsigned w, unsigned s, size_t extTexCount,
const TextureInfo* extTexs, ReflectionType reflectionType) const {
extTexCount = std::min(int(extTexCount), BOO_GLSL_MAX_TEXTURE_COUNT - int(m_tcgs.size()));
std::string retval = GenerateVertInStruct(col, uv, w) + "\n" +
GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + "\n" +
GenerateVertUniformStruct(s, reflectionType != ReflectionType::None) +
"SBINDING(0) out VertToFrag vtf;\n\n"
"void main()\n{\n";
if (s) {
/* skinned */
retval +=
" vec4 objPos = vec4(0.0,0.0,0.0,0.0);\n"
" vec4 objNorm = vec4(0.0,0.0,0.0,0.0);\n";
for (size_t i = 0; i < s; ++i)
retval += hecl::Format(" objPos += (objs[%" PRISize "] * vec4(posIn, 1.0)) * weightIn[%" PRISize "][%" PRISize
"];\n"
" objNorm += (objsInv[%" PRISize "] * vec4(normIn, 1.0)) * weightIn[%" PRISize
"][%" PRISize "];\n",
i, i / 4, i % 4, i, i / 4, i % 4);
retval +=
" objPos[3] = 1.0;\n"
" objNorm = vec4(normalize(objNorm.xyz), 0.0);\n"
" vtf.mvPos = mv * objPos;\n"
" vtf.mvNorm = vec4(normalize((mvInv * objNorm).xyz), 0.0);\n"
" gl_Position = proj * vtf.mvPos;\n";
} else {
/* non-skinned */
retval +=
" vec4 objPos = vec4(posIn, 1.0);\n"
" vec4 objNorm = vec4(normIn, 0.0);\n"
" vtf.mvPos = mv * objPos;\n"
" vtf.mvNorm = mvInv * objNorm;\n"
" gl_Position = proj * vtf.mvPos;\n";
}
retval += " vec4 tmpProj;\n";
int tcgIdx = 0;
for (const TexCoordGen& tcg : m_tcgs) {
if (tcg.m_mtx < 0)
retval += hecl::Format(" vtf.tcgs[%u] = %s;\n", tcgIdx, EmitTexGenSource2(tcg.m_src, tcg.m_uvIdx).c_str());
else
retval += hecl::Format(
" tmpProj = texMtxs[%u].postMtx * vec4(%s((texMtxs[%u].mtx * %s).xyz), 1.0);\n"
" vtf.tcgs[%u] = (tmpProj / tmpProj.w).xy;\n",
tcg.m_mtx, tcg.m_norm ? "normalize" : "", tcg.m_mtx, EmitTexGenSource4(tcg.m_src, tcg.m_uvIdx).c_str(),
tcgIdx);
++tcgIdx;
}
for (int i = 0; i < extTexCount; ++i) {
const TextureInfo& extTex = extTexs[i];
if (extTex.mtxIdx < 0)
retval += hecl::Format(" vtf.extTcgs[%u] = %s;\n", i, EmitTexGenSource2(extTex.src, extTex.uvIdx).c_str());
else
retval += hecl::Format(
" tmpProj = texMtxs[%u].postMtx * vec4(%s((texMtxs[%u].mtx * %s).xyz), 1.0);\n"
" vtf.extTcgs[%u] = (tmpProj / tmpProj.w).xy;\n",
extTex.mtxIdx, extTex.normalize ? "normalize" : "", extTex.mtxIdx,
EmitTexGenSource4(extTex.src, extTex.uvIdx).c_str(), i);
}
if (reflectionType != ReflectionType::None)
retval +=
" vtf.reflectTcgs[0] = normalize((indMtx * vec4(posIn, 1.0)).xz) * vec2(0.5, 0.5) + vec2(0.5, 0.5);\n"
" vtf.reflectTcgs[1] = (reflectMtx * vec4(posIn, 1.0)).xy;\n"
" vtf.reflectAlpha = reflectAlpha;\n";
return retval + "}\n";
}
std::string GLSL::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting) const {
std::string lightingSrc;
if (!lighting.m_source.empty())
lightingSrc = lighting.m_source;
else
lightingSrc =
"const vec4 colorReg0 = vec4(1.0);\n"
"const vec4 colorReg1 = vec4(1.0);\n"
"const vec4 colorReg2 = vec4(1.0);\n"
"const vec4 mulColor = vec4(1.0);\n"
"const vec4 addColor = vec4(0.0);\n"
"\n";
std::string texMapDecl;
for (unsigned i = 0; i < m_texMapEnd; ++i)
texMapDecl += hecl::Format("TBINDING%u uniform sampler2D tex%u;\n", i, i);
if (reflectionType == ReflectionType::Indirect)
texMapDecl += hecl::Format(
"TBINDING%u uniform sampler2D reflectionIndTex;\n"
"TBINDING%u uniform sampler2D reflectionTex;\n",
m_texMapEnd, m_texMapEnd + 1);
else if (reflectionType == ReflectionType::Simple)
texMapDecl += hecl::Format("TBINDING%u uniform sampler2D reflectionTex;\n", m_texMapEnd);
std::string retval = std::string("#extension GL_ARB_shader_image_load_store: enable\n") + "#define BLEND_SRC_" +
BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" + "#define BLEND_DST_" +
BlendFactorToDefine(dstFactor, m_blendDst) + "\n" +
GenerateVertToFragStruct(0, reflectionType != ReflectionType::None) +
(!alphaTest ? "#ifdef GL_ARB_shader_image_load_store\n"
"layout(early_fragment_tests) in;\n"
"#endif\n"
: "") +
"layout(location=0) out vec4 colorOut;\n" + texMapDecl + "SBINDING(0) in VertToFrag vtf;\n\n" +
lightingSrc + "\n" + "void main()\n{\n";
if (m_lighting) {
if (!lighting.m_entry.empty())
retval +=
hecl::Format(" vec4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz));\n", lighting.m_entry.data());
else
retval += " vec4 lighting = vec4(1.0,1.0,1.0,1.0);\n";
}
unsigned sampIdx = 0;
for (const TexSampling& sampling : m_texSamplings)
retval += hecl::Format(" vec4 sampling%u = texture(tex%u, vtf.tcgs[%u]);\n", sampIdx++, sampling.mapIdx,
sampling.tcgIdx);
std::string reflectionExpr = GenerateReflectionExpr(reflectionType);
if (m_alphaExpr.size())
retval += " colorOut = vec4(" + m_colorExpr + " + " + reflectionExpr + ", " + m_alphaExpr +
") * mulColor + addColor;\n";
else
retval += " colorOut = vec4(" + m_colorExpr + " + " + reflectionExpr + ", 1.0) * mulColor + addColor;\n";
return retval + (alphaTest ? GenerateAlphaTest() : "") + "}\n";
}
std::string GLSL::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting, const Function& post,
size_t extTexCount, const TextureInfo* extTexs, bool diffuseOnly) const {
std::string lightingSrc;
if (!lighting.m_source.empty())
lightingSrc = lighting.m_source;
else
lightingSrc =
"const vec4 colorReg0 = vec4(1.0);\n"
"const vec4 colorReg1 = vec4(1.0);\n"
"const vec4 colorReg2 = vec4(1.0);\n"
"const vec4 mulColor = vec4(1.0);\n"
"const vec4 addColor = vec4(0.0);\n"
"\n";
std::string postSrc;
if (!post.m_source.empty())
postSrc = post.m_source;
std::string postEntry;
if (!post.m_entry.empty())
postEntry = post.m_entry;
std::string texMapDecl;
for (unsigned i = 0; i < m_texMapEnd; ++i)
texMapDecl += hecl::Format("TBINDING%u uniform sampler2D tex%u;\n", i, i);
if (reflectionType == ReflectionType::Indirect)
texMapDecl += hecl::Format(
"TBINDING%u uniform sampler2D reflectionIndTex;\n"
"TBINDING%u uniform sampler2D reflectionTex;\n",
m_texMapEnd, m_texMapEnd + 1);
else if (reflectionType == ReflectionType::Simple)
texMapDecl += hecl::Format("TBINDING%u uniform sampler2D reflectionTex;\n", m_texMapEnd);
uint32_t extTexBits = 0;
for (int i = 0; i < extTexCount; ++i) {
const TextureInfo& extTex = extTexs[i];
if (!(extTexBits & (1 << extTex.mapIdx))) {
texMapDecl += hecl::Format("TBINDING%u uniform sampler2D extTex%u;\n", extTex.mapIdx, extTex.mapIdx);
extTexBits |= (1 << extTex.mapIdx);
}
}
std::string retval = std::string("#extension GL_ARB_shader_image_load_store: enable\n") + "#define BLEND_SRC_" +
BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" + "#define BLEND_DST_" +
BlendFactorToDefine(dstFactor, m_blendDst) + "\n" +
GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) +
(!alphaTest ? "\n#ifdef GL_ARB_shader_image_load_store\n"
"layout(early_fragment_tests) in;\n"
"#endif\n"
: "") +
"\nlayout(location=0) out vec4 colorOut;\n" + texMapDecl + "SBINDING(0) in VertToFrag vtf;\n\n" +
lightingSrc + "\n" + postSrc + "\nvoid main()\n{\n";
if (m_lighting) {
if (!lighting.m_entry.empty())
retval +=
hecl::Format(" vec4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz));\n", lighting.m_entry.data());
else
retval += " vec4 lighting = vec4(1.0,1.0,1.0,1.0);\n";
}
unsigned sampIdx = 0;
for (const TexSampling& sampling : m_texSamplings)
retval += hecl::Format(" vec4 sampling%u = texture(tex%u, vtf.tcgs[%u]);\n", sampIdx++, sampling.mapIdx,
sampling.tcgIdx);
std::string reflectionExpr = GenerateReflectionExpr(reflectionType);
if (m_alphaExpr.size() && !diffuseOnly)
retval += " colorOut = " + postEntry + "(vec4(" + m_colorExpr + " + " + reflectionExpr + ", " + m_alphaExpr +
")) * mulColor + addColor;\n";
else
retval += " colorOut = " + postEntry + "(vec4(" + (diffuseOnly ? m_diffuseColorExpr : m_colorExpr) + " + " +
reflectionExpr + ", 1.0)) * mulColor + addColor;\n";
return retval + (alphaTest ? GenerateAlphaTest() : "") + "}\n";
}
} // namespace hecl::Backend

View File

@ -1,703 +0,0 @@
#include "hecl/Backend/GX.hpp"
namespace hecl::Backend {
template <>
void GX::Color::Enumerate<athena::io::DNA<athena::Big>::Read>(typename Read::StreamT& reader) {
reader.readUBytesToBuf(&num, 4);
}
template <>
void GX::Color::Enumerate<athena::io::DNA<athena::Big>::Write>(typename Write::StreamT& writer) {
writer.writeUBytes(reinterpret_cast<const atUint8*>(&num), 4);
}
template <>
void GX::Color::Enumerate<athena::io::DNA<athena::Big>::BinarySize>(typename BinarySize::StreamT& s) {
s += 4;
}
unsigned GX::addKColor(Diagnostics& diag, const SourceLocation& loc, const Color& color) {
for (unsigned i = 0; i < m_kcolorCount; ++i)
if (m_kcolors[i] == color)
return i;
if (m_kcolorCount >= 4)
diag.reportBackendErr(loc, "GX KColor overflow");
m_kcolors[m_kcolorCount] = color;
m_kcolors[m_kcolorCount].color[3] = 0;
return m_kcolorCount++;
}
unsigned GX::addKAlpha(Diagnostics& diag, const SourceLocation& loc, float alpha) {
uint8_t ai = uint8_t(std::min(std::max(alpha * 255.f, 0.f), 255.f));
for (unsigned i = 0; i < m_kcolorCount; ++i) {
if (m_kcolors[i].color[3] == ai)
return i;
else if (m_kcolors[i].color[3] == 0) {
m_kcolors[i].color[3] = ai;
return i;
}
}
if (m_kcolorCount >= 4)
diag.reportBackendErr(loc, "GX KColor overflow");
m_kcolors[m_kcolorCount] = ai;
return m_kcolorCount++;
}
unsigned GX::addTexCoordGen(Diagnostics& diag, const SourceLocation& loc, TexGenSrc src, TexMtx mtx, bool norm,
PTTexMtx pmtx) {
for (unsigned i = 0; i < m_tcgCount; ++i) {
TexCoordGen& tcg = m_tcgs[i];
if (tcg.m_src == src && tcg.m_mtx == mtx && tcg.m_norm == norm && tcg.m_pmtx == pmtx)
return i;
}
if (m_tcgCount >= 8)
diag.reportBackendErr(loc, "GX TexCoordGen overflow");
GX::TexCoordGen& newTcg = m_tcgs[m_tcgCount];
newTcg.m_src = src;
newTcg.m_mtx = mtx;
newTcg.m_norm = norm;
newTcg.m_pmtx = pmtx;
return m_tcgCount++;
}
GX::TEVStage& GX::addTEVStage(Diagnostics& diag, const SourceLocation& loc) {
if (m_tevCount >= 16)
diag.reportBackendErr(loc, "GX TEV stage overflow");
GX::TEVStage& newTEV = m_tevs[m_tevCount];
newTEV.m_loc = loc;
if (m_tevCount) {
newTEV.m_prev = &m_tevs[m_tevCount - 1];
newTEV.m_prev->m_next = &newTEV;
}
++m_tevCount;
return newTEV;
}
GX::TEVStage& GX::addAlphaTEVStage(Diagnostics& diag, const SourceLocation& loc) {
++m_alphaTraceStage;
while (m_tevCount < m_alphaTraceStage + 1) {
TEVStage& stage = addTEVStage(diag, loc);
stage.m_color[3] = CC_CPREV;
stage.m_alpha[3] = CA_APREV;
}
return m_tevs[m_alphaTraceStage];
}
unsigned GX::RecursiveTraceTexGen(const IR& ir, Diagnostics& diag, const IR::Instruction& inst, TexMtx mtx,
bool normalize, PTTexMtx pmtx) {
if (inst.m_op != IR::OpType::Call)
diag.reportBackendErr(inst.m_loc, "TexCoordGen resolution requires function");
const std::string& tcgName = inst.m_call.m_name;
if (!tcgName.compare("UV")) {
if (inst.getChildCount() < 1)
diag.reportBackendErr(inst.m_loc, "TexCoordGen UV(layerIdx) requires one argument");
const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
auto& idxImm = idxInst.getImmVec();
return addTexCoordGen(diag, inst.m_loc, TexGenSrc(TG_TEX0 + unsigned(idxImm.simd[0])), mtx, normalize, pmtx);
} else if (!tcgName.compare("Normal"))
return addTexCoordGen(diag, inst.m_loc, TG_NRM, mtx, normalize, pmtx);
else if (!tcgName.compare("View"))
return addTexCoordGen(diag, inst.m_loc, TG_POS, mtx, normalize, pmtx);
/* Otherwise treat as game-specific function */
const IR::Instruction& tcgSrcInst = inst.getChildInst(ir, 0);
bool doNorm = normalize || tcgName.back() == 'N';
unsigned idx = RecursiveTraceTexGen(ir, diag, tcgSrcInst, TexMtx(TEXMTX0 + m_texMtxCount * 3), doNorm,
doNorm ? PTTexMtx(PTTEXMTX0 + m_texMtxCount * 3) : PTIDENTITY);
GX::TexCoordGen& tcg = m_tcgs[idx];
m_texMtxRefs[m_texMtxCount] = &tcg;
++m_texMtxCount;
tcg.m_gameFunction = tcgName;
tcg.m_gameArgs.clear();
for (int i = 1; i < inst.getChildCount(); ++i) {
const IR::Instruction& ci = inst.getChildInst(ir, i);
tcg.m_gameArgs.push_back(ci.getImmVec());
}
return idx;
}
GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const IR::Instruction& inst,
bool swizzleAlpha) {
switch (inst.m_op) {
case IR::OpType::Call: {
const std::string& name = inst.m_call.m_name;
bool normalize = false;
if (!name.compare("Texture") || (normalize = true && !name.compare("TextureN"))) {
TEVStage& newStage = addTEVStage(diag, inst.m_loc);
if (inst.getChildCount() < 2)
diag.reportBackendErr(inst.m_loc, "Texture(map, texgen) requires 2 arguments");
const IR::Instruction& mapInst = inst.getChildInst(ir, 0);
auto& mapImm = mapInst.getImmVec();
newStage.m_texMapIdx = unsigned(mapImm.simd[0]);
newStage.m_color[0] = swizzleAlpha ? CC_TEXA : CC_TEXC;
const IR::Instruction& tcgInst = inst.getChildInst(ir, 1);
newStage.m_texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, IDENTITY, normalize, PTIDENTITY);
return TraceResult(&newStage);
} else if (!name.compare("ColorReg")) {
const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
unsigned idx = unsigned(idxInst.getImmVec().simd[0]);
if (swizzleAlpha)
m_aRegMask |= 1 << idx;
else
m_cRegMask |= 1 << idx;
return TraceResult(TevColorArg((swizzleAlpha ? CC_A0 : CC_C0) + idx * 2));
} else if (!name.compare("Lighting")) {
return TraceResult(swizzleAlpha ? CC_RASA : CC_RASC);
} else
diag.reportBackendErr(inst.m_loc, "GX backend unable to interpret '%s'", name.c_str());
break;
}
case IR::OpType::LoadImm: {
const atVec4f& vec = inst.m_loadImm.m_immVec;
if (vec.simd[0] == 0.f && vec.simd[1] == 0.f && vec.simd[2] == 0.f)
return TraceResult(CC_ZERO);
else if (vec.simd[0] == 1.f && vec.simd[1] == 1.f && vec.simd[2] == 1.f)
return TraceResult(CC_ONE);
unsigned idx = addKColor(diag, inst.m_loc, vec);
return TraceResult(TevKColorSel(TEV_KCSEL_K0 + idx));
}
case IR::OpType::Arithmetic: {
ArithmeticOp op = inst.m_arithmetic.m_op;
const IR::Instruction& aInst = inst.getChildInst(ir, 0);
const IR::Instruction& bInst = inst.getChildInst(ir, 1);
TraceResult aTrace;
TraceResult bTrace;
if (aInst.m_op != IR::OpType::Arithmetic && bInst.m_op == IR::OpType::Arithmetic) {
bTrace = RecursiveTraceColor(ir, diag, bInst);
aTrace = RecursiveTraceColor(ir, diag, aInst);
} else {
aTrace = RecursiveTraceColor(ir, diag, aInst);
bTrace = RecursiveTraceColor(ir, diag, bInst);
}
if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage &&
getStageIdx(aTrace.tevStage) > getStageIdx(bTrace.tevStage))
std::swap(aTrace, bTrace);
TevKColorSel newKColor = TEV_KCSEL_1;
if (aTrace.type == TraceResult::Type::TEVKColorSel && bTrace.type == TraceResult::Type::TEVKColorSel)
diag.reportBackendErr(inst.m_loc, "unable to handle 2 KColors in one stage");
else if (aTrace.type == TraceResult::Type::TEVKColorSel) {
newKColor = aTrace.tevKColorSel;
aTrace.type = TraceResult::Type::TEVColorArg;
aTrace.tevColorArg = CC_KONST;
} else if (bTrace.type == TraceResult::Type::TEVKColorSel) {
newKColor = bTrace.tevKColorSel;
bTrace.type = TraceResult::Type::TEVColorArg;
bTrace.tevColorArg = CC_KONST;
}
switch (op) {
case ArithmeticOp::Add: {
if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage) {
TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage;
if (b->m_prev != a) {
a->m_cRegOut = TEVLAZY;
b->m_color[3] = CC_LAZY;
b->m_lazyCInIdx = m_cRegLazy;
a->m_lazyCOutIdx = m_cRegLazy++;
} else if (b == &m_tevs[m_tevCount - 1] && a->m_texMapIdx == b->m_texMapIdx &&
a->m_texGenIdx == b->m_texGenIdx && a->m_color[3] == CC_ZERO && b->m_color[0] != CC_ZERO) {
a->m_color[3] = b->m_color[0];
--m_tevCount;
return TraceResult(a);
} else
b->m_color[3] = CC_CPREV;
return TraceResult(b);
} else if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVColorArg) {
TEVStage* a = aTrace.tevStage;
if (a->m_color[3] != CC_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine");
a->m_color[3] = bTrace.tevColorArg;
a->m_kColor = newKColor;
return TraceResult(a);
} else if (aTrace.type == TraceResult::Type::TEVColorArg && bTrace.type == TraceResult::Type::TEVStage) {
TEVStage* b = bTrace.tevStage;
if (b->m_color[3] != CC_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine");
b->m_color[3] = aTrace.tevColorArg;
b->m_kColor = newKColor;
return TraceResult(b);
} else if (aTrace.type == TraceResult::Type::TEVColorArg && bTrace.type == TraceResult::Type::TEVColorArg) {
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[0] = aTrace.tevColorArg;
stage.m_color[3] = bTrace.tevColorArg;
stage.m_kColor = newKColor;
return TraceResult(&stage);
}
break;
}
case ArithmeticOp::Subtract: {
if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage) {
TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage;
if (b->m_prev != a) {
a->m_cRegOut = TEVLAZY;
b->m_color[3] = CC_LAZY;
b->m_lazyCInIdx = m_cRegLazy;
a->m_lazyCOutIdx = m_cRegLazy++;
} else
b->m_color[3] = CC_CPREV;
b->m_cop = TEV_SUB;
return TraceResult(b);
} else if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVColorArg) {
TEVStage* a = aTrace.tevStage;
if (a->m_color[3] != CC_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for subtract combine");
a->m_color[3] = bTrace.tevColorArg;
a->m_kColor = newKColor;
a->m_cop = TEV_SUB;
return TraceResult(a);
} else if (aTrace.type == TraceResult::Type::TEVColorArg && bTrace.type == TraceResult::Type::TEVColorArg) {
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[0] = aTrace.tevColorArg;
stage.m_color[3] = bTrace.tevColorArg;
stage.m_kColor = newKColor;
stage.m_cop = TEV_SUB;
return TraceResult(&stage);
}
break;
}
case ArithmeticOp::Multiply: {
if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage) {
TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage;
if (b->m_color[2] != CC_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
if (b->m_prev != a) {
a->m_cRegOut = TEVLAZY;
b->m_color[2] = CC_LAZY;
b->m_lazyCInIdx = m_cRegLazy;
a->m_lazyCOutIdx = m_cRegLazy++;
} else
b->m_color[2] = CC_CPREV;
b->m_color[1] = b->m_color[0];
b->m_color[0] = CC_ZERO;
b->m_color[3] = CC_ZERO;
return TraceResult(b);
} else if (aTrace.type == TraceResult::Type::TEVColorArg && bTrace.type == TraceResult::Type::TEVColorArg) {
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[1] = aTrace.tevColorArg;
stage.m_color[2] = bTrace.tevColorArg;
stage.m_kColor = newKColor;
return TraceResult(&stage);
} else if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVColorArg) {
TEVStage* a = aTrace.tevStage;
if (a->m_color[1] != CC_ZERO) {
if (a->m_cRegOut != TEVPREV)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[1] = CC_CPREV;
stage.m_color[2] = bTrace.tevColorArg;
stage.m_kColor = newKColor;
return TraceResult(&stage);
}
a->m_color[1] = a->m_color[0];
a->m_color[0] = CC_ZERO;
a->m_color[2] = bTrace.tevColorArg;
a->m_kColor = newKColor;
return TraceResult(a);
} else if (aTrace.type == TraceResult::Type::TEVColorArg && bTrace.type == TraceResult::Type::TEVStage) {
TEVStage* b = bTrace.tevStage;
if (b->m_color[1] != CC_ZERO) {
if (b->m_cRegOut != TEVPREV)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[1] = aTrace.tevColorArg;
stage.m_color[2] = CC_CPREV;
stage.m_kColor = newKColor;
return TraceResult(&stage);
}
b->m_color[1] = b->m_color[0];
b->m_color[0] = CC_ZERO;
b->m_color[2] = bTrace.tevColorArg;
b->m_kColor = newKColor;
return TraceResult(b);
}
break;
}
default:
diag.reportBackendErr(inst.m_loc, "invalid arithmetic op");
}
diag.reportBackendErr(inst.m_loc, "unable to convert arithmetic to TEV stage");
break;
}
case IR::OpType::Swizzle: {
if (inst.m_swizzle.m_idxs[0] == 3 && inst.m_swizzle.m_idxs[1] == 3 && inst.m_swizzle.m_idxs[2] == 3 &&
inst.m_swizzle.m_idxs[3] == -1) {
const IR::Instruction& cInst = inst.getChildInst(ir, 0);
if (cInst.m_op != IR::OpType::Call)
diag.reportBackendErr(inst.m_loc, "only functions accepted for alpha swizzle");
return RecursiveTraceColor(ir, diag, cInst, true);
} else
diag.reportBackendErr(inst.m_loc, "only alpha extract may be performed with swizzle operation");
break;
}
default:
diag.reportBackendErr(inst.m_loc, "invalid color op");
}
return TraceResult();
}
GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const IR::Instruction& inst) {
switch (inst.m_op) {
case IR::OpType::Call: {
const std::string& name = inst.m_call.m_name;
bool normalize = false;
if (!name.compare("Texture") || (normalize = true && !name.compare("TextureN"))) {
if (inst.getChildCount() < 2)
diag.reportBackendErr(inst.m_loc, "Texture(map, texgen) requires 2 arguments");
const IR::Instruction& mapInst = inst.getChildInst(ir, 0);
const atVec4f& mapImm = mapInst.getImmVec();
unsigned mapIdx = unsigned(mapImm.simd[0]);
int foundStage = -1;
for (int i = m_alphaTraceStage + 1; i < int(m_tevCount); ++i) {
TEVStage& testStage = m_tevs[i];
if (testStage.m_texMapIdx == mapIdx) {
foundStage = i;
break;
}
}
if (foundStage >= 0) {
m_alphaTraceStage = foundStage;
TEVStage& stage = m_tevs[foundStage];
stage.m_alpha[0] = CA_TEXA;
return TraceResult(&stage);
}
TEVStage& newStage = addAlphaTEVStage(diag, inst.m_loc);
newStage.m_color[3] = CC_CPREV;
newStage.m_texMapIdx = mapIdx;
newStage.m_alpha[0] = CA_TEXA;
const IR::Instruction& tcgInst = inst.getChildInst(ir, 1);
newStage.m_texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, IDENTITY, normalize, PTIDENTITY);
return TraceResult(&newStage);
} else if (!name.compare("ColorReg")) {
const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
unsigned idx = unsigned(idxInst.getImmVec().simd[0]);
m_aRegMask |= 1 << idx;
return TraceResult(TevAlphaArg(CA_A0 + idx));
} else if (!name.compare("Lighting")) {
return TraceResult(CA_RASA);
} else
diag.reportBackendErr(inst.m_loc, "GX backend unable to interpret '%s'", name.c_str());
break;
}
case IR::OpType::LoadImm: {
const atVec4f& vec = inst.m_loadImm.m_immVec;
if (vec.simd[0] == 0.f)
return TraceResult(CA_ZERO);
else if (vec.simd[0] == 1.f)
return TraceResult(TEV_KASEL_1);
unsigned idx = addKAlpha(diag, inst.m_loc, vec.simd[0]);
return TraceResult(TevKAlphaSel(TEV_KASEL_K0_A + idx));
}
case IR::OpType::Arithmetic: {
ArithmeticOp op = inst.m_arithmetic.m_op;
const IR::Instruction& aInst = inst.getChildInst(ir, 0);
const IR::Instruction& bInst = inst.getChildInst(ir, 1);
TraceResult aTrace;
TraceResult bTrace;
if (aInst.m_op != IR::OpType::Arithmetic && bInst.m_op == IR::OpType::Arithmetic) {
bTrace = RecursiveTraceAlpha(ir, diag, bInst);
aTrace = RecursiveTraceAlpha(ir, diag, aInst);
} else {
aTrace = RecursiveTraceAlpha(ir, diag, aInst);
bTrace = RecursiveTraceAlpha(ir, diag, bInst);
}
if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage &&
getStageIdx(aTrace.tevStage) > getStageIdx(bTrace.tevStage))
std::swap(aTrace, bTrace);
TevKAlphaSel newKAlpha = TEV_KASEL_1;
if (aTrace.type == TraceResult::Type::TEVKAlphaSel && bTrace.type == TraceResult::Type::TEVKAlphaSel)
diag.reportBackendErr(inst.m_loc, "unable to handle 2 KAlphas in one stage");
else if (aTrace.type == TraceResult::Type::TEVKAlphaSel) {
newKAlpha = aTrace.tevKAlphaSel;
aTrace.type = TraceResult::Type::TEVAlphaArg;
aTrace.tevAlphaArg = CA_KONST;
} else if (bTrace.type == TraceResult::Type::TEVKAlphaSel) {
newKAlpha = bTrace.tevKAlphaSel;
bTrace.type = TraceResult::Type::TEVAlphaArg;
bTrace.tevAlphaArg = CA_KONST;
}
switch (op) {
case ArithmeticOp::Add: {
if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage) {
TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage;
if (b->m_prev != a) {
a->m_aRegOut = TEVLAZY;
b->m_alpha[3] = CA_LAZY;
if (a->m_lazyAOutIdx != -1)
b->m_lazyAInIdx = a->m_lazyAOutIdx;
else {
b->m_lazyAInIdx = m_aRegLazy;
a->m_lazyAOutIdx = m_aRegLazy++;
}
} else
b->m_alpha[3] = CA_APREV;
return TraceResult(b);
} else if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVAlphaArg) {
TEVStage* a = aTrace.tevStage;
if (a->m_alpha[3] != CA_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine");
a->m_alpha[3] = bTrace.tevAlphaArg;
a->m_kAlpha = newKAlpha;
return TraceResult(a);
} else if (aTrace.type == TraceResult::Type::TEVAlphaArg && bTrace.type == TraceResult::Type::TEVStage) {
TEVStage* b = bTrace.tevStage;
if (b->m_alpha[3] != CA_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine");
b->m_alpha[3] = aTrace.tevAlphaArg;
b->m_kAlpha = newKAlpha;
return TraceResult(b);
} else if (aTrace.type == TraceResult::Type::TEVAlphaArg && bTrace.type == TraceResult::Type::TEVAlphaArg) {
TEVStage& stage = addAlphaTEVStage(diag, inst.m_loc);
stage.m_alpha[0] = aTrace.tevAlphaArg;
stage.m_alpha[3] = bTrace.tevAlphaArg;
stage.m_kAlpha = newKAlpha;
return TraceResult(&stage);
}
break;
}
case ArithmeticOp::Subtract: {
if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage) {
TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage;
if (b->m_aop != TEV_SUB)
diag.reportBackendErr(inst.m_loc, "unable to integrate alpha subtraction into stage chain");
if (b->m_prev != a) {
a->m_aRegOut = TEVLAZY;
b->m_alpha[3] = CA_LAZY;
if (a->m_lazyAOutIdx != -1)
b->m_lazyAInIdx = a->m_lazyAOutIdx;
else {
b->m_lazyAInIdx = m_aRegLazy;
a->m_lazyAOutIdx = m_aRegLazy++;
}
} else
b->m_alpha[3] = CA_APREV;
return TraceResult(b);
} else if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVAlphaArg) {
TEVStage* a = aTrace.tevStage;
if (a->m_aop != TEV_SUB)
diag.reportBackendErr(inst.m_loc, "unable to integrate alpha subtraction into stage chain");
if (a->m_alpha[3] != CA_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for add combine");
a->m_alpha[3] = bTrace.tevAlphaArg;
a->m_kAlpha = newKAlpha;
return TraceResult(a);
} else if (aTrace.type == TraceResult::Type::TEVAlphaArg && bTrace.type == TraceResult::Type::TEVAlphaArg) {
TEVStage& stage = addAlphaTEVStage(diag, inst.m_loc);
stage.m_alpha[0] = aTrace.tevAlphaArg;
stage.m_alpha[3] = bTrace.tevAlphaArg;
stage.m_kAlpha = newKAlpha;
stage.m_aop = TEV_SUB;
return TraceResult(&stage);
}
break;
}
case ArithmeticOp::Multiply: {
if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVStage) {
TEVStage* a = aTrace.tevStage;
TEVStage* b = bTrace.tevStage;
if (b->m_alpha[2] != CA_ZERO)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
if (b->m_prev != a) {
a->m_aRegOut = TEVLAZY;
b->m_alpha[2] = CA_LAZY;
b->m_lazyAInIdx = m_aRegLazy;
a->m_lazyAOutIdx = m_aRegLazy++;
} else
b->m_alpha[2] = CA_APREV;
b->m_alpha[1] = b->m_alpha[0];
b->m_alpha[0] = CA_ZERO;
b->m_alpha[3] = CA_ZERO;
return TraceResult(b);
} else if (aTrace.type == TraceResult::Type::TEVAlphaArg && bTrace.type == TraceResult::Type::TEVAlphaArg) {
TEVStage& stage = addAlphaTEVStage(diag, inst.m_loc);
stage.m_color[3] = CC_CPREV;
stage.m_alpha[1] = aTrace.tevAlphaArg;
stage.m_alpha[2] = bTrace.tevAlphaArg;
stage.m_kAlpha = newKAlpha;
return TraceResult(&stage);
} else if (aTrace.type == TraceResult::Type::TEVStage && bTrace.type == TraceResult::Type::TEVAlphaArg) {
TEVStage* a = aTrace.tevStage;
if (a->m_alpha[1] != CA_ZERO) {
if (a->m_aRegOut != TEVPREV)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
TEVStage& stage = addAlphaTEVStage(diag, inst.m_loc);
stage.m_alpha[1] = CA_APREV;
stage.m_alpha[2] = bTrace.tevAlphaArg;
stage.m_kAlpha = newKAlpha;
return TraceResult(&stage);
}
a->m_alpha[1] = a->m_alpha[0];
a->m_alpha[0] = CA_ZERO;
a->m_alpha[2] = bTrace.tevAlphaArg;
a->m_kAlpha = newKAlpha;
return TraceResult(a);
} else if (aTrace.type == TraceResult::Type::TEVAlphaArg && bTrace.type == TraceResult::Type::TEVStage) {
TEVStage* b = bTrace.tevStage;
if (b->m_alpha[1] != CA_ZERO) {
if (b->m_aRegOut != TEVPREV)
diag.reportBackendErr(inst.m_loc, "unable to modify TEV stage for multiply combine");
TEVStage& stage = addAlphaTEVStage(diag, inst.m_loc);
stage.m_alpha[1] = aTrace.tevAlphaArg;
stage.m_alpha[2] = CA_APREV;
stage.m_kAlpha = newKAlpha;
return TraceResult(&stage);
}
b->m_alpha[1] = b->m_alpha[0];
b->m_alpha[0] = CA_ZERO;
b->m_alpha[2] = bTrace.tevAlphaArg;
b->m_kAlpha = newKAlpha;
return TraceResult(b);
}
break;
}
default:
diag.reportBackendErr(inst.m_loc, "invalid arithmetic op");
}
diag.reportBackendErr(inst.m_loc, "unable to convert arithmetic to TEV stage");
break;
}
case IR::OpType::Swizzle: {
if (inst.m_swizzle.m_idxs[0] == 3 && inst.m_swizzle.m_idxs[1] == 3 && inst.m_swizzle.m_idxs[2] == 3 &&
inst.m_swizzle.m_idxs[3] == -1) {
const IR::Instruction& cInst = inst.getChildInst(ir, 0);
if (cInst.m_op != IR::OpType::Call)
diag.reportBackendErr(inst.m_loc, "only functions accepted for alpha swizzle");
return RecursiveTraceAlpha(ir, diag, cInst);
} else
diag.reportBackendErr(inst.m_loc, "only alpha extract may be performed with swizzle operation");
break;
}
default:
diag.reportBackendErr(inst.m_loc, "invalid alpha op");
}
return TraceResult();
}
void GX::reset(const IR& ir, Diagnostics& diag) {
diag.setBackend("GX");
m_tevCount = 0;
m_tcgCount = 0;
m_texMtxCount = 0;
m_kcolorCount = 0;
m_cRegMask = 0;
m_cRegLazy = 0;
m_aRegMask = 0;
m_aRegLazy = 0;
m_alphaTraceStage = -1;
/* Final instruction is the root call by hecl convention */
const IR::Instruction& rootCall = ir.m_instructions.back();
if (!rootCall.m_call.m_name.compare("HECLOpaque")) {
m_blendSrc = BL_ONE;
m_blendDst = BL_ZERO;
} else if (!rootCall.m_call.m_name.compare("HECLAlpha")) {
m_blendSrc = BL_SRCALPHA;
m_blendDst = BL_INVSRCALPHA;
} else if (!rootCall.m_call.m_name.compare("HECLAdditive")) {
m_blendSrc = BL_SRCALPHA;
m_blendDst = BL_ONE;
} else {
diag.reportBackendErr(rootCall.m_loc, "GX backend doesn't handle '%s' root", rootCall.m_call.m_name.c_str());
return;
}
/* Follow Color Chain */
const IR::Instruction& colorRoot = ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(0));
TraceResult result = RecursiveTraceColor(ir, diag, colorRoot);
switch (result.type) {
case TraceResult::Type::TEVColorArg: {
TEVStage& stage = addTEVStage(diag, colorRoot.m_loc);
stage.m_color[3] = result.tevColorArg;
break;
}
case TraceResult::Type::TEVKColorSel: {
TEVStage& stage = addTEVStage(diag, colorRoot.m_loc);
stage.m_color[3] = CC_KONST;
stage.m_kColor = result.tevKColorSel;
break;
}
default:
break;
}
/* Follow Alpha Chain */
if (rootCall.m_call.m_argInstIdxs.size() > 1) {
const IR::Instruction& alphaRoot = ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(1));
TraceResult result = RecursiveTraceAlpha(ir, diag, alphaRoot);
switch (result.type) {
case TraceResult::Type::TEVAlphaArg: {
TEVStage& stage = addAlphaTEVStage(diag, alphaRoot.m_loc);
stage.m_alpha[3] = result.tevAlphaArg;
break;
}
case TraceResult::Type::TEVKAlphaSel: {
TEVStage& stage = addAlphaTEVStage(diag, alphaRoot.m_loc);
stage.m_alpha[3] = CA_KONST;
stage.m_kAlpha = result.tevKAlphaSel;
break;
}
default:
break;
}
/* Ensure Alpha reaches end of chain */
if (m_alphaTraceStage >= 0)
for (unsigned i = m_alphaTraceStage + 1; i < m_tevCount; ++i)
m_tevs[i].m_alpha[3] = CA_APREV;
}
/* Resolve lazy color/alpha regs */
if (m_cRegLazy) {
for (int i = 0; i < int(m_tevCount); ++i) {
TEVStage& stage = m_tevs[i];
if (stage.m_cRegOut == TEVLAZY) {
int picked = pickCLazy(diag, stage.m_loc, i);
stage.m_cRegOut = TevRegID(TEVREG0 + picked);
for (int j = i + 1; j < int(m_tevCount); ++j) {
TEVStage& nstage = m_tevs[j];
if (nstage.m_lazyCInIdx == stage.m_lazyCOutIdx)
for (int c = 0; c < 4; ++c)
if (nstage.m_color[c] == CC_LAZY)
nstage.m_color[c] = TevColorArg(CC_C0 + picked * 2);
}
}
if (stage.m_aRegOut == TEVLAZY) {
int picked = pickALazy(diag, stage.m_loc, i);
stage.m_aRegOut = TevRegID(TEVREG0 + picked);
for (int j = i + 1; j < int(m_tevCount); ++j) {
TEVStage& nstage = m_tevs[j];
if (nstage.m_lazyAInIdx == stage.m_lazyAOutIdx)
for (int c = 0; c < 4; ++c)
if (nstage.m_alpha[c] == CA_LAZY)
nstage.m_alpha[c] = TevAlphaArg(CA_A0 + picked);
}
}
}
}
}
} // namespace hecl::Backend

View File

@ -1,359 +0,0 @@
#include "hecl/Backend/HLSL.hpp"
#include "hecl/Runtime.hpp"
#include <athena/MemoryReader.hpp>
#include <athena/MemoryWriter.hpp>
#include <boo/graphicsdev/D3D.hpp>
static logvisor::Module Log("hecl::Backend::HLSL");
namespace hecl::Backend {
std::string HLSL::EmitTexGenSource2(TexGenSrc src, int uvIdx) const {
switch (src) {
case TexGenSrc::Position:
return "objPos.xy\n";
case TexGenSrc::Normal:
return "objNorm.xy\n";
case TexGenSrc::UV:
return hecl::Format("v.uvIn[%u]", uvIdx);
default:
break;
}
return std::string();
}
std::string HLSL::EmitTexGenSource4(TexGenSrc src, int uvIdx) const {
switch (src) {
case TexGenSrc::Position:
return "float4(objPos.xyz, 1.0)\n";
case TexGenSrc::Normal:
return "float4(objNorm.xyz, 1.0)\n";
case TexGenSrc::UV:
return hecl::Format("float4(v.uvIn[%u], 0.0, 1.0)", uvIdx);
default:
break;
}
return std::string();
}
std::string HLSL::GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const {
std::string retval =
"struct VertData\n"
"{\n"
" float3 posIn : POSITION;\n"
" float3 normIn : NORMAL;\n";
if (col)
retval += hecl::Format(" float4 colIn[%u] : COLOR;\n", col);
if (uv)
retval += hecl::Format(" float2 uvIn[%u] : UV;\n", uv);
if (w)
retval += hecl::Format(" float4 weightIn[%u] : WEIGHT;\n", w);
return retval + "};\n";
}
std::string HLSL::GenerateVertToFragStruct(size_t extTexCount, bool reflectionCoords) const {
std::string retval =
"struct VertToFrag\n"
"{\n"
" float4 mvpPos : SV_Position;\n"
" float4 mvPos : POSITION;\n"
" float4 mvNorm : NORMAL;\n";
if (m_tcgs.size())
retval += hecl::Format(" float2 tcgs[%u] : UV;\n", unsigned(m_tcgs.size()));
if (extTexCount)
retval += hecl::Format(" float2 extTcgs[%u] : EXTUV;\n", unsigned(extTexCount));
if (reflectionCoords)
retval +=
" float2 reflectTcgs[2] : REFLECTUV;\n"
" float reflectAlpha : REFLECTALPHA;\n";
return retval + "};\n";
}
std::string HLSL::GenerateVertUniformStruct(unsigned skinSlots, bool reflectionCoords) const {
std::string retval;
if (skinSlots == 0) {
retval =
"cbuffer HECLVertUniform : register(b0)\n"
"{\n"
" float4x4 mv;\n"
" float4x4 mvInv;\n"
" float4x4 proj;\n"
"};\n";
} else {
retval = hecl::Format(
"cbuffer HECLVertUniform : register(b0)\n"
"{\n"
" float4x4 objs[%u];\n"
" float4x4 objsInv[%u];\n"
" float4x4 mv;\n"
" float4x4 mvInv;\n"
" float4x4 proj;\n"
"};\n",
skinSlots, skinSlots);
}
retval +=
"struct TCGMtx\n"
"{\n"
" float4x4 mtx;\n"
" float4x4 postMtx;\n"
"};\n"
"cbuffer HECLTCGMatrix : register(b1)\n"
"{\n"
" TCGMtx texMtxs[8];\n"
"};\n";
if (reflectionCoords)
retval +=
"cbuffer HECLReflectMtx : register(b3)\n"
"{\n"
" float4x4 indMtx;\n"
" float4x4 reflectMtx;\n"
" float reflectAlpha;\n"
"};\n"
"\n";
return retval;
}
std::string HLSL::GenerateAlphaTest() const {
return " if (colorOut.a < 0.25)\n"
" {\n"
" discard;\n"
" }\n";
}
std::string HLSL::GenerateReflectionExpr(ReflectionType type) const {
switch (type) {
case ReflectionType::None:
default:
return "float3(0.0, 0.0, 0.0)";
case ReflectionType::Simple:
return "reflectionTex.Sample(reflectSamp, vtf.reflectTcgs[1]).rgb * vtf.reflectAlpha";
case ReflectionType::Indirect:
return "reflectionTex.Sample(reflectSamp, (reflectionIndTex.Sample(samp, vtf.reflectTcgs[0]).ab - "
"float2(0.5, 0.5)) * float2(0.5, 0.5) + vtf.reflectTcgs[1]).rgb * vtf.reflectAlpha";
}
}
void HLSL::reset(const IR& ir, Diagnostics& diag) {
/* Common programmable interpretation */
ProgrammableCommon::reset(ir, diag, "HLSL");
}
std::string HLSL::makeVert(unsigned col, unsigned uv, unsigned w, unsigned s, size_t extTexCount,
const TextureInfo* extTexs, ReflectionType reflectionType) const {
std::string retval = GenerateVertInStruct(col, uv, w) + "\n" +
GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + "\n" +
GenerateVertUniformStruct(s, reflectionType != ReflectionType::None) + "\n" +
"VertToFrag main(in VertData v)\n"
"{\n"
" VertToFrag vtf;\n";
if (s) {
/* skinned */
retval +=
" float4 objPos = float4(0.0,0.0,0.0,0.0);\n"
" float4 objNorm = float4(0.0,0.0,0.0,0.0);\n";
for (size_t i = 0; i < s; ++i)
retval += hecl::Format(
" objPos += mul(objs[%" PRISize "], float4(v.posIn, 1.0)) * v.weightIn[%" PRISize "][%" PRISize
"];\n"
" objNorm += mul(objsInv[%" PRISize "], float4(v.normIn, 1.0)) * v.weightIn[%" PRISize "][%" PRISize "];\n",
i, i / 4, i % 4, i, i / 4, i % 4);
retval +=
" objPos[3] = 1.0;\n"
" objNorm = float4(normalize(objNorm.xyz), 0.0);\n"
" vtf.mvPos = mul(mv, objPos);\n"
" vtf.mvNorm = float4(normalize(mul(mvInv, objNorm).xyz), 0.0);\n"
" vtf.mvpPos = mul(proj, vtf.mvPos);\n";
} else {
/* non-skinned */
retval +=
" float4 objPos = float4(v.posIn, 1.0);\n"
" float4 objNorm = float4(v.normIn, 0.0);\n"
" vtf.mvPos = mul(mv, objPos);\n"
" vtf.mvNorm = mul(mvInv, objNorm);\n"
" vtf.mvpPos = mul(proj, vtf.mvPos);\n";
}
retval += " float4 tmpProj;\n";
int tcgIdx = 0;
for (const TexCoordGen& tcg : m_tcgs) {
if (tcg.m_mtx < 0)
retval += hecl::Format(" vtf.tcgs[%u] = %s;\n", tcgIdx, EmitTexGenSource2(tcg.m_src, tcg.m_uvIdx).c_str());
else
retval += hecl::Format(
" tmpProj = mul(texMtxs[%u].postMtx, float4(%s(mul(texMtxs[%u].mtx, %s).xyz), 1.0));\n"
" vtf.tcgs[%u] = (tmpProj / tmpProj.w).xy;\n",
tcg.m_mtx, tcg.m_norm ? "normalize" : "", tcg.m_mtx, EmitTexGenSource4(tcg.m_src, tcg.m_uvIdx).c_str(),
tcgIdx);
++tcgIdx;
}
for (int i = 0; i < extTexCount; ++i) {
const TextureInfo& extTex = extTexs[i];
if (extTex.mtxIdx < 0)
retval += hecl::Format(" vtf.extTcgs[%u] = %s;\n", i, EmitTexGenSource2(extTex.src, extTex.uvIdx).c_str());
else
retval += hecl::Format(
" tmpProj = mul(texMtxs[%u].postMtx, float4(%s(mul(texMtxs[%u].mtx, %s).xyz), 1.0));\n"
" vtf.extTcgs[%u] = (tmpProj / tmpProj.w).xy;\n",
extTex.mtxIdx, extTex.normalize ? "normalize" : "", extTex.mtxIdx,
EmitTexGenSource4(extTex.src, extTex.uvIdx).c_str(), i);
}
if (reflectionType != ReflectionType::None)
retval +=
" vtf.reflectTcgs[0] = normalize(mul(indMtx, float4(v.posIn, 1.0)).xz) * float2(0.5, 0.5) + float2(0.5, "
"0.5);\n"
" vtf.reflectTcgs[1] = mul(reflectMtx, float4(v.posIn, 1.0)).xy;\n"
" vtf.reflectAlpha = reflectAlpha;\n";
return retval +
" return vtf;\n"
"}\n";
}
std::string HLSL::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting) const {
std::string lightingSrc;
if (!lighting.m_source.empty())
lightingSrc = lighting.m_source;
else
lightingSrc =
"static const float4 colorReg0 = float4(1.0, 1.0, 1.0, 1.0);\n"
"static const float4 colorReg1 = float4(1.0, 1.0, 1.0, 1.0);\n"
"static const float4 colorReg2 = float4(1.0, 1.0, 1.0, 1.0);\n"
"static const float4 mulColor = float4(1.0, 1.0, 1.0, 1.0);\n"
"static const float4 addColor = float4(0.0, 0.0, 0.0, 0.0);\n";
std::string texMapDecl;
if (m_texMapEnd)
texMapDecl = hecl::Format("Texture2D texs[%u] : register(t0);\n", m_texMapEnd);
if (reflectionType == ReflectionType::Indirect)
texMapDecl += hecl::Format(
"Texture2D reflectionIndTex : register(t%u);\n"
"Texture2D reflectionTex : register(t%u);\n",
m_texMapEnd, m_texMapEnd + 1);
else if (reflectionType == ReflectionType::Simple)
texMapDecl += hecl::Format("Texture2D reflectionTex : register(t%u);\n", m_texMapEnd);
std::string retval = std::string("#define BLEND_SRC_") + BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" +
"#define BLEND_DST_" + BlendFactorToDefine(dstFactor, m_blendDst) + "\n" +
"SamplerState samp : register(s0);\n"
"SamplerState clampSamp : register(s1);\n"
"SamplerState reflectSamp : register(s2);\n" +
GenerateVertToFragStruct(0, reflectionType != ReflectionType::None) + texMapDecl + "\n" +
lightingSrc + "\n" + (!alphaTest ? "\n[earlydepthstencil]\n" : "\n") +
"float4 main(in VertToFrag vtf) : SV_Target0\n{\n";
if (m_lighting) {
if (!lighting.m_entry.empty())
retval += hecl::Format(" float4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf);\n",
lighting.m_entry.data());
else
retval += " float4 lighting = float4(1.0,1.0,1.0,1.0);\n";
}
unsigned sampIdx = 0;
for (const TexSampling& sampling : m_texSamplings)
retval += hecl::Format(" float4 sampling%u = texs[%u].Sample(samp, vtf.tcgs[%u]);\n", sampIdx++, sampling.mapIdx,
sampling.tcgIdx);
std::string reflectionExpr = GenerateReflectionExpr(reflectionType);
retval += " float4 colorOut;\n";
if (m_alphaExpr.size())
retval += " colorOut = float4(" + m_colorExpr + " + " + reflectionExpr + ", " + m_alphaExpr +
") * mulColor + addColor;\n";
else
retval += " colorOut = float4(" + m_colorExpr + " + " + reflectionExpr + ", 1.0) * mulColor + addColor;\n";
return retval + (alphaTest ? GenerateAlphaTest() : "") + " return colorOut;\n}\n";
}
std::string HLSL::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting, const Function& post,
size_t extTexCount, const TextureInfo* extTexs, bool diffuseOnly) const {
std::string lightingSrc;
if (!lighting.m_source.empty())
lightingSrc = lighting.m_source;
else
lightingSrc =
"static const float4 colorReg0 = float4(1.0, 1.0, 1.0, 1.0);\n"
"static const float4 colorReg1 = float4(1.0, 1.0, 1.0, 1.0);\n"
"static const float4 colorReg2 = float4(1.0, 1.0, 1.0, 1.0);\n"
"static const float4 mulColor = float4(1.0, 1.0, 1.0, 1.0);\n"
"static const float4 addColor = float4(0.0, 0.0, 0.0, 0.0);\n";
std::string postSrc;
if (!post.m_source.empty())
postSrc = post.m_source;
std::string postEntry;
if (!post.m_entry.empty())
postEntry = post.m_entry;
std::string texMapDecl;
if (m_texMapEnd)
texMapDecl = hecl::Format("Texture2D texs[%u] : register(t0);\n", m_texMapEnd);
if (reflectionType == ReflectionType::Indirect)
texMapDecl += hecl::Format(
"Texture2D reflectionIndTex : register(t%u);\n"
"Texture2D reflectionTex : register(t%u);\n",
m_texMapEnd, m_texMapEnd + 1);
else if (reflectionType == ReflectionType::Simple)
texMapDecl += hecl::Format("Texture2D reflectionTex : register(t%u);\n", m_texMapEnd);
uint32_t extTexBits = 0;
for (int i = 0; i < extTexCount; ++i) {
const TextureInfo& extTex = extTexs[i];
if (!(extTexBits & (1 << extTex.mapIdx))) {
texMapDecl += hecl::Format("Texture2D extTex%u : register(t%u);\n", extTex.mapIdx, extTex.mapIdx);
extTexBits |= (1 << extTex.mapIdx);
}
}
std::string retval = std::string("#define BLEND_SRC_") + BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" +
"#define BLEND_DST_" + BlendFactorToDefine(dstFactor, m_blendDst) + "\n" +
"SamplerState samp : register(s0);\n"
"SamplerState clampSamp : register(s1);\n"
"SamplerState reflectSamp : register(s2);\n" +
GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + texMapDecl +
"\n" + lightingSrc + "\n" + postSrc + (!alphaTest ? "\n[earlydepthstencil]\n" : "\n") +
"float4 main(in VertToFrag vtf) : SV_Target0\n{\n";
if (m_lighting) {
if (!lighting.m_entry.empty())
retval += hecl::Format(" float4 lighting = %s(vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf);\n",
lighting.m_entry.data());
else
retval += " float4 lighting = float4(1.0,1.0,1.0,1.0);\n";
}
unsigned sampIdx = 0;
for (const TexSampling& sampling : m_texSamplings)
retval += hecl::Format(" float4 sampling%u = texs[%u].Sample(samp, vtf.tcgs[%u]);\n", sampIdx++, sampling.mapIdx,
sampling.tcgIdx);
std::string reflectionExpr = GenerateReflectionExpr(reflectionType);
retval += " float4 colorOut;\n";
if (m_alphaExpr.size() && !diffuseOnly)
retval += " colorOut = " + postEntry + "(" + (postEntry.size() ? "vtf, " : "") + "float4(" + m_colorExpr +
" + " + reflectionExpr + ", " + m_alphaExpr + ")) * mulColor + addColor;\n";
else
retval += " colorOut = " + postEntry + "(" + (postEntry.size() ? "vtf, " : "") + "float4(" +
(diffuseOnly ? m_diffuseColorExpr : m_colorExpr) + " + " + reflectionExpr + ", 1.0)) * mulColor + addColor;\n";
return retval + (alphaTest ? GenerateAlphaTest() : "") + " return colorOut;\n}\n";
}
} // namespace hecl::Backend

View File

@ -1,442 +0,0 @@
#include "hecl/Backend/Metal.hpp"
#include <athena/MemoryReader.hpp>
#include <athena/MemoryWriter.hpp>
#include <boo/graphicsdev/Metal.hpp>
static logvisor::Module Log("hecl::Backend::Metal");
namespace hecl::Backend {
std::string Metal::EmitTexGenSource2(TexGenSrc src, int uvIdx) const {
switch (src) {
case TexGenSrc::Position:
return "objPos.xy\n";
case TexGenSrc::Normal:
return "objNorm.xy\n";
case TexGenSrc::UV:
return hecl::Format("v.uvIn%u", uvIdx);
default:
break;
}
return std::string();
}
std::string Metal::EmitTexGenSource4(TexGenSrc src, int uvIdx) const {
switch (src) {
case TexGenSrc::Position:
return "float4(objPos.xyz, 1.0)\n";
case TexGenSrc::Normal:
return "float4(objNorm.xyz, 1.0)\n";
case TexGenSrc::UV:
return hecl::Format("float4(v.uvIn%u, 0.0, 1.0)", uvIdx);
default:
break;
}
return std::string();
}
std::string Metal::GenerateVertInStruct(unsigned col, unsigned uv, unsigned w) const {
std::string retval =
"struct VertData\n"
"{\n"
" float3 posIn [[ attribute(0) ]];\n"
" float3 normIn [[ attribute(1) ]];\n";
unsigned idx = 2;
if (col) {
for (unsigned i = 0; i < col; ++i, ++idx)
retval += hecl::Format(" float4 colIn%u [[ attribute(%u) ]];\n", i, idx);
}
if (uv) {
for (unsigned i = 0; i < uv; ++i, ++idx)
retval += hecl::Format(" float2 uvIn%u [[ attribute(%u) ]];\n", i, idx);
}
if (w) {
for (unsigned i = 0; i < w; ++i, ++idx)
retval += hecl::Format(" float4 weightIn%u [[ attribute(%u) ]];\n", i, idx);
}
return retval + "};\n";
}
std::string Metal::GenerateVertToFragStruct(size_t extTexCount, bool reflectionCoords) const {
std::string retval =
"struct VertToFrag\n"
"{\n"
" float4 mvpPos [[ position ]];\n"
" float4 mvPos;\n"
" float4 mvNorm;\n";
if (m_tcgs.size())
for (size_t i = 0; i < m_tcgs.size(); ++i)
retval += hecl::Format(" float2 tcgs%" PRISize ";\n", i);
if (extTexCount)
for (size_t i = 0; i < extTexCount; ++i)
retval += hecl::Format(" float2 extTcgs%" PRISize ";\n", i);
if (reflectionCoords)
retval +=
" float2 reflectTcgs0;\n"
" float2 reflectTcgs1;\n"
" float reflectAlpha;\n";
return retval + "};\n";
}
std::string Metal::GenerateVertUniformStruct(unsigned skinSlots) const {
std::string retval;
if (skinSlots == 0) {
retval =
"struct HECLVertUniform\n"
"{\n"
" float4x4 mv;\n"
" float4x4 mvInv;\n"
" float4x4 proj;\n"
"};\n"
"struct TexMtxs {float4x4 mtx; float4x4 postMtx;};\n"
"struct ReflectTexMtxs {float4x4 indMtx; float4x4 reflectMtx; float reflectAlpha;};\n";
} else {
retval = hecl::Format(
"struct HECLVertUniform\n"
"{\n"
" float4x4 objs[%u];\n"
" float4x4 objsInv[%u];\n"
" float4x4 mv;\n"
" float4x4 mvInv;\n"
" float4x4 proj;\n"
"};\n"
"struct TexMtxs {float4x4 mtx; float4x4 postMtx;};\n"
"struct ReflectTexMtxs {float4x4 indMtx; float4x4 reflectMtx; float reflectAlpha;};\n",
skinSlots, skinSlots);
}
return retval;
}
std::string Metal::GenerateFragOutStruct() const {
return "struct FragOut\n"
"{\n"
" float4 color [[ color(0) ]];\n"
" //float depth [[ depth(less) ]];\n"
"};\n";
}
std::string Metal::GenerateAlphaTest() const {
return " if (out.color.a < 0.25)\n"
" {\n"
" discard_fragment();\n"
" }\n";
}
std::string Metal::GenerateReflectionExpr(ReflectionType type) const {
switch (type) {
case ReflectionType::None:
default:
return "float3(0.0, 0.0, 0.0)";
case ReflectionType::Simple:
return "reflectionTex.sample(reflectSamp, vtf.reflectTcgs1).rgb * vtf.reflectAlpha";
case ReflectionType::Indirect:
return "reflectionTex.sample(reflectSamp, (reflectionIndTex.sample(samp, vtf.reflectTcgs0).ab - "
"float2(0.5, 0.5)) * float2(0.5, 0.5) + vtf.reflectTcgs1).rgb * vtf.reflectAlpha";
}
}
void Metal::reset(const IR& ir, Diagnostics& diag) {
/* Common programmable interpretation */
ProgrammableCommon::reset(ir, diag, "Metal");
}
std::string Metal::makeVert(unsigned col, unsigned uv, unsigned w, unsigned s, size_t extTexCount,
const TextureInfo* extTexs, ReflectionType reflectionType) const {
std::string tmStr = ",\nconstant TexMtxs* texMtxs [[ buffer(3) ]]";
if (reflectionType != ReflectionType::None)
tmStr += ",\nconstant ReflectTexMtxs& reflectMtxs [[ buffer(5) ]]";
std::string retval = "#include <metal_stdlib>\nusing namespace metal;\n" + GenerateVertInStruct(col, uv, w) + "\n" +
GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + "\n" +
GenerateVertUniformStruct(s) +
"\nvertex VertToFrag vmain(VertData v [[ stage_in ]],\n"
" constant HECLVertUniform& vu [[ buffer(2) ]]" +
tmStr +
")\n"
"{\n"
" VertToFrag vtf;\n";
if (s) {
/* skinned */
retval +=
" float4 objPos = float4(0.0,0.0,0.0,0.0);\n"
" float4 objNorm = float4(0.0,0.0,0.0,0.0);\n";
for (size_t i = 0; i < s; ++i)
retval += hecl::Format(
" objPos += (vu.objs[%" PRISize "] * float4(v.posIn, 1.0)) * v.weightIn%" PRISize "[%" PRISize
"];\n"
" objNorm += (vu.objsInv[%" PRISize "] * float4(v.normIn, 1.0)) * v.weightIn%" PRISize "[%" PRISize "];\n",
i, i / 4, i % 4, i, i / 4, i % 4);
retval +=
" objPos[3] = 1.0;\n"
" objNorm = float4(normalize(objNorm.xyz), 0.0);\n"
" vtf.mvPos = vu.mv * objPos;\n"
" vtf.mvNorm = float4(normalize((vu.mvInv * objNorm).xyz), 0.0);\n"
" vtf.mvpPos = vu.proj * vtf.mvPos;\n";
} else {
/* non-skinned */
retval +=
" float4 objPos = float4(v.posIn, 1.0);\n"
" float4 objNorm = float4(v.normIn, 0.0);\n"
" vtf.mvPos = vu.mv * objPos;\n"
" vtf.mvNorm = vu.mvInv * objNorm;\n"
" vtf.mvpPos = vu.proj * vtf.mvPos;\n";
}
retval += " float4 tmpProj;\n";
int tcgIdx = 0;
for (const TexCoordGen& tcg : m_tcgs) {
if (tcg.m_mtx < 0)
retval += hecl::Format(" vtf.tcgs%u = %s;\n", tcgIdx, EmitTexGenSource2(tcg.m_src, tcg.m_uvIdx).c_str());
else
retval += hecl::Format(
" tmpProj = texMtxs[%u].postMtx * float4(%s((texMtxs[%u].mtx * %s).xyz), 1.0);\n"
" vtf.tcgs%u = (tmpProj / tmpProj.w).xy;\n",
tcg.m_mtx, tcg.m_norm ? "normalize" : "", tcg.m_mtx, EmitTexGenSource4(tcg.m_src, tcg.m_uvIdx).c_str(),
tcgIdx);
++tcgIdx;
}
for (int i = 0; i < extTexCount; ++i) {
const TextureInfo& extTex = extTexs[i];
if (extTex.mtxIdx < 0)
retval += hecl::Format(" vtf.extTcgs%u = %s;\n", i, EmitTexGenSource2(extTex.src, extTex.uvIdx).c_str());
else
retval += hecl::Format(
" tmpProj = texMtxs[%u].postMtx * float4(%s((texMtxs[%u].mtx * %s).xyz), 1.0);\n"
" vtf.extTcgs%u = (tmpProj / tmpProj.w).xy;\n",
extTex.mtxIdx, extTex.normalize ? "normalize" : "", extTex.mtxIdx,
EmitTexGenSource4(extTex.src, extTex.uvIdx).c_str(), i);
}
if (reflectionType != ReflectionType::None)
retval +=
" vtf.reflectTcgs0 = normalize((reflectMtxs.indMtx * float4(v.posIn, 1.0)).xz) * float2(0.5, 0.5) + "
"float2(0.5, 0.5);\n"
" vtf.reflectTcgs1 = (reflectMtxs.reflectMtx * float4(v.posIn, 1.0)).xy;\n"
" vtf.reflectAlpha = reflectMtxs.reflectAlpha;\n";
return retval + " return vtf;\n}\n";
}
std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting) const {
std::string lightingSrc;
if (!lighting.m_source.empty())
lightingSrc = lighting.m_source;
std::string texMapDecl;
if (m_texMapEnd)
for (int i = 0; i < m_texMapEnd; ++i)
texMapDecl += hecl::Format(",\ntexture2d<float> tex%u [[ texture(%u) ]]", i, i);
if (reflectionType == ReflectionType::Indirect)
texMapDecl += hecl::Format(
",\ntexture2d<float> reflectionIndTex [[ texture(%u) ]]\n"
",\ntexture2d<float> reflectionTex [[ texture(%u) ]]\n",
m_texMapEnd, m_texMapEnd + 1);
else if (reflectionType == ReflectionType::Simple)
texMapDecl += hecl::Format(",\ntexture2d<float> reflectionTex [[ texture(%u) ]]\n", m_texMapEnd);
std::string blockCall;
for (size_t i = 0; i < blockCount; ++i) {
texMapDecl += hecl::Format(",\nconstant %s& block%" PRISize " [[ buffer(%" PRISize ") ]]", blockNames[i], i, i + 4);
if (blockCall.size())
blockCall += ", ";
blockCall += hecl::Format("block%" PRISize, i);
}
std::string retval =
std::string("#include <metal_stdlib>\nusing namespace metal;\n") + "#define BLEND_SRC_" +
BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" + "#define BLEND_DST_" +
BlendFactorToDefine(dstFactor, m_blendDst) + "\n" +
GenerateVertToFragStruct(0, reflectionType != ReflectionType::None) + "\n" + GenerateFragOutStruct() + "\n" +
lightingSrc + "\n" +
"fragment FragOut fmain(VertToFrag vtf [[ stage_in ]],\n"
"sampler samp [[ sampler(0) ]], sampler clampSamp [[ sampler(1) ]], sampler reflectSamp [[ sampler(2) ]]" +
texMapDecl +
")\n"
"{\n"
" FragOut out;\n";
if (!lighting.m_source.empty()) {
retval +=
" float4 colorReg0 = block0.colorReg0;\n"
" float4 colorReg1 = block0.colorReg1;\n"
" float4 colorReg2 = block0.colorReg2;\n"
" float4 mulColor = block0.mulColor;\n"
" float4 addColor = block0.addColor;\n";
} else {
retval +=
" float4 colorReg0 = float4(1.0, 1.0, 1.0, 1.0);\n"
" float4 colorReg1 = float4(1.0, 1.0, 1.0, 1.0);\n"
" float4 colorReg2 = float4(1.0, 1.0, 1.0, 1.0);\n"
" float4 mulColor = float4(1.0, 1.0, 1.0, 1.0);\n"
" float4 addColor = float4(0.0, 0.0, 0.0, 0.0);\n";
}
if (m_lighting) {
if (!lighting.m_entry.empty())
retval += hecl::Format(" float4 lighting = %s(%s, vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf);\n",
lighting.m_entry.data(), blockCall.c_str());
else
retval += " float4 lighting = float4(1.0,1.0,1.0,1.0);\n";
}
unsigned sampIdx = 0;
for (const TexSampling& sampling : m_texSamplings)
retval += hecl::Format(" float4 sampling%u = tex%u.sample(samp, vtf.tcgs%u);\n", sampIdx++, sampling.mapIdx,
sampling.tcgIdx);
std::string reflectionExpr = GenerateReflectionExpr(reflectionType);
if (m_alphaExpr.size())
retval += " out.color = float4(" + m_colorExpr + " + " + reflectionExpr + ", " + m_alphaExpr +
") * mulColor + addColor;\n";
else
retval += " out.color = float4(" + m_colorExpr + " + " + reflectionExpr + ", 1.0) * mulColor + addColor;\n";
return retval + (alphaTest ? GenerateAlphaTest() : "") +
" return out;\n"
"}\n";
}
std::string Metal::makeFrag(size_t blockCount, const char** blockNames, bool alphaTest, ReflectionType reflectionType,
BlendFactor srcFactor, BlendFactor dstFactor, const Function& lighting,
const Function& post, size_t extTexCount, const TextureInfo* extTexs,
bool diffuseOnly) const {
std::string lightingSrc;
if (!lighting.m_source.empty())
lightingSrc = lighting.m_source;
std::string postSrc;
if (!post.m_source.empty())
postSrc = post.m_source;
std::string lightingEntry;
if (!lighting.m_entry.empty())
lightingEntry = lighting.m_entry;
std::string postEntry;
if (!post.m_entry.empty())
postEntry = post.m_entry;
int extTexBits = 0;
for (int i = 0; i < extTexCount; ++i) {
const TextureInfo& extTex = extTexs[i];
extTexBits |= 1 << extTex.mapIdx;
}
std::string texMapDecl;
if (m_texMapEnd)
for (int i = 0; i < m_texMapEnd; ++i)
if (!(extTexBits & (1 << i)))
texMapDecl += hecl::Format(",\ntexture2d<float> tex%u [[ texture(%u) ]]", i, i);
if (reflectionType == ReflectionType::Indirect)
texMapDecl += hecl::Format(
",\ntexture2d<float> reflectionIndTex [[ texture(%u) ]]\n"
",\ntexture2d<float> reflectionTex [[ texture(%u) ]]\n",
m_texMapEnd, m_texMapEnd + 1);
else if (reflectionType == ReflectionType::Simple)
texMapDecl += hecl::Format(",\ntexture2d<float> reflectionTex [[ texture(%u) ]]\n", m_texMapEnd);
std::string extTexCall;
int extTexBits2 = 0;
for (int i = 0; i < extTexCount; ++i) {
const TextureInfo& extTex = extTexs[i];
if (!(extTexBits2 & (1 << extTex.mapIdx))) {
if (extTexCall.size())
extTexCall += ", ";
extTexCall += hecl::Format("tex%u", extTex.mapIdx);
texMapDecl += hecl::Format(",\ntexture2d<float> tex%u [[ texture(%u) ]]", extTex.mapIdx, extTex.mapIdx);
extTexBits2 |= 1 << extTex.mapIdx;
}
}
std::string blockCall;
for (size_t i = 0; i < blockCount; ++i) {
texMapDecl += hecl::Format(",\nconstant %s& block%" PRISize " [[ buffer(%" PRISize ") ]]", blockNames[i], i, i + 4);
if (blockCall.size())
blockCall += ", ";
blockCall += hecl::Format("block%" PRISize, i);
}
std::string retval =
std::string("#include <metal_stdlib>\nusing namespace metal;\n") + "#define BLEND_SRC_" +
BlendFactorToDefine(srcFactor, m_blendSrc) + "\n" + "#define BLEND_DST_" +
BlendFactorToDefine(dstFactor, m_blendDst) + "\n" +
GenerateVertToFragStruct(extTexCount, reflectionType != ReflectionType::None) + "\n" + GenerateFragOutStruct() +
"\n" + lightingSrc + "\n" + postSrc + "\n" +
"fragment FragOut fmain(VertToFrag vtf [[ stage_in ]],\n"
"sampler samp [[ sampler(0) ]], sampler clampSamp [[ sampler(1) ]], sampler reflectSamp [[ sampler(2) ]]" +
texMapDecl +
")\n"
"{\n"
" FragOut out;\n";
if (!lighting.m_source.empty()) {
retval +=
" float4 colorReg0 = block0.colorReg0;\n"
" float4 colorReg1 = block0.colorReg1;\n"
" float4 colorReg2 = block0.colorReg2;\n"
" float4 mulColor = block0.mulColor;\n"
" float4 addColor = block0.addColor;\n";
} else {
retval +=
" float4 colorReg0 = float4(1.0, 1.0, 1.0, 1.0);\n"
" float4 colorReg1 = float4(1.0, 1.0, 1.0, 1.0);\n"
" float4 colorReg2 = float4(1.0, 1.0, 1.0, 1.0);\n"
" float4 mulColor = float4(1.0, 1.0, 1.0, 1.0);\n"
" float4 addColor = float4(0.0, 0.0, 0.0, 0.0);\n";
}
if (m_lighting) {
if (!lighting.m_entry.empty()) {
retval +=
" float4 lighting = " + lightingEntry + "(" + blockCall +
", vtf.mvPos.xyz, normalize(vtf.mvNorm.xyz), vtf" +
(!strncmp(lighting.m_entry.data(), "EXT", 3) ? (extTexCall.size() ? (", samp, clampSamp," + extTexCall) : "")
: "") +
");\n";
} else
retval += " float4 lighting = float4(1.0,1.0,1.0,1.0);\n";
}
unsigned sampIdx = 0;
for (const TexSampling& sampling : m_texSamplings)
retval += hecl::Format(" float4 sampling%u = tex%u.sample(samp, vtf.tcgs%u);\n", sampIdx++, sampling.mapIdx,
sampling.tcgIdx);
std::string reflectionExpr = GenerateReflectionExpr(reflectionType);
if (m_alphaExpr.size() && !diffuseOnly) {
retval += " out.color = " + postEntry + "(" +
(postEntry.size() ? ("vtf, " + (blockCall.size() ? (blockCall + ", ") : "") +
(!strncmp(post.m_entry.data(), "EXT", 3)
? (extTexCall.size() ? ("samp, clampSamp," + extTexCall + ", ") : "")
: ""))
: "") +
"float4(" + m_colorExpr + " + " + reflectionExpr + ", " + m_alphaExpr + ")) * mulColor + addColor;\n";
} else {
retval += " out.color = " + postEntry + "(" +
(postEntry.size() ? ("vtf, " + (blockCall.size() ? (blockCall + ", ") : "") +
(!strncmp(post.m_entry.data(), "EXT", 3)
? (extTexCall.size() ? ("samp, clampSamp," + extTexCall + ", ") : "")
: ""))
: "") +
"float4(" + (diffuseOnly ? m_diffuseColorExpr : m_colorExpr) + " + " + reflectionExpr +
", 1.0)) * mulColor + addColor;\n";
}
return retval + (alphaTest ? GenerateAlphaTest() : "") +
" return out;\n"
"}\n";
}
} // namespace hecl::Backend

View File

@ -1,376 +0,0 @@
#include "hecl/Backend/ProgrammableCommon.hpp"
#include <map>
namespace hecl::Backend {
const char* ProgrammableCommon::BlendFactorToDefine(BlendFactor factor, BlendFactor defaultFactor) {
switch (factor) {
case BlendFactor::Zero:
return "ZERO";
case BlendFactor::One:
return "ONE";
case BlendFactor::SrcColor:
return "SRCCOLOR";
case BlendFactor::InvSrcColor:
return "INVSRCCOLOR";
case BlendFactor::DstColor:
return "DSTCOLOR";
case BlendFactor::InvDstColor:
return "INVDSTCOLOR";
case BlendFactor::SrcAlpha:
return "SRCALPHA";
case BlendFactor::InvSrcAlpha:
return "INVSRCALPHA";
case BlendFactor::DstAlpha:
return "DSTALPHA";
case BlendFactor::InvDstAlpha:
return "INVDSTALPHA";
case BlendFactor::SrcColor1:
return "SRCCOLOR1";
case BlendFactor::InvSrcColor1:
return "INVSRCCOLOR1";
default:
return BlendFactorToDefine(defaultFactor, BlendFactor::Zero);
}
}
unsigned ProgrammableCommon::addTexCoordGen(TexGenSrc src, int uvIdx, int mtx, bool normalize) {
for (unsigned i = 0; i < m_tcgs.size(); ++i) {
TexCoordGen& tcg = m_tcgs[i];
if (tcg.m_src == src && tcg.m_uvIdx == uvIdx && tcg.m_mtx == mtx && tcg.m_norm == normalize)
return i;
}
m_tcgs.emplace_back();
TexCoordGen& newTcg = m_tcgs.back();
newTcg.m_src = src;
newTcg.m_uvIdx = uvIdx;
newTcg.m_mtx = mtx;
newTcg.m_norm = normalize;
return m_tcgs.size() - 1;
}
unsigned ProgrammableCommon::addTexSampling(unsigned mapIdx, unsigned tcgIdx) {
for (unsigned i = 0; i < m_texSamplings.size(); ++i) {
TexSampling& samp = m_texSamplings[i];
if (samp.mapIdx == mapIdx && samp.tcgIdx == tcgIdx)
return i;
}
m_texSamplings.emplace_back();
TexSampling& samp = m_texSamplings.back();
samp.mapIdx = mapIdx;
samp.tcgIdx = tcgIdx;
if (m_texMapEnd < mapIdx + 1)
m_texMapEnd = mapIdx + 1;
return m_texSamplings.size() - 1;
}
unsigned ProgrammableCommon::RecursiveTraceTexGen(const IR& ir, Diagnostics& diag, const IR::Instruction& inst, int mtx,
bool normalize) {
if (inst.m_op != IR::OpType::Call)
diag.reportBackendErr(inst.m_loc, "TexCoordGen resolution requires function");
const std::string& tcgName = inst.m_call.m_name;
if (!tcgName.compare("UV")) {
if (inst.getChildCount() < 1)
diag.reportBackendErr(inst.m_loc, "TexCoordGen UV(layerIdx) requires one argument");
const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
auto& idxImm = idxInst.getImmVec();
return addTexCoordGen(TexGenSrc::UV, int(idxImm.simd[0]), mtx, normalize);
} else if (!tcgName.compare("Normal"))
return addTexCoordGen(TexGenSrc::Normal, -1, mtx, normalize);
else if (!tcgName.compare("View"))
return addTexCoordGen(TexGenSrc::Position, -1, mtx, normalize);
/* Otherwise treat as game-specific function */
const IR::Instruction& tcgSrcInst = inst.getChildInst(ir, 0);
unsigned idx = RecursiveTraceTexGen(ir, diag, tcgSrcInst, m_texMtxRefs.size(), normalize || tcgName.back() == 'N');
TexCoordGen& tcg = m_tcgs[idx];
m_texMtxRefs.push_back(idx);
tcg.m_gameFunction = tcgName;
tcg.m_gameArgs.clear();
for (int i = 1; i < inst.getChildCount(); ++i) {
const IR::Instruction& ci = inst.getChildInst(ir, i);
tcg.m_gameArgs.push_back(ci.getImmVec());
}
return idx;
}
std::string ProgrammableCommon::RecursiveTraceDiffuseColor(const IR& ir, Diagnostics& diag, const IR::Instruction& inst,
bool toSwizzle, bool fallback) {
switch (inst.m_op) {
case IR::OpType::Call: {
const std::string& name = inst.m_call.m_name;
bool normalize = false;
if (!name.compare("TextureD") ||
(fallback && !name.compare("Texture")) ||
((normalize = true) && !name.compare("TextureDN")) ||
((normalize = true) && fallback && !name.compare("TextureN"))) {
if (inst.getChildCount() < 2)
diag.reportBackendErr(inst.m_loc, "Texture(map, texgen) requires 2 arguments");
const IR::Instruction& mapInst = inst.getChildInst(ir, 0);
auto& mapImm = mapInst.getImmVec();
unsigned mapIdx = unsigned(mapImm.simd[0]);
const IR::Instruction& tcgInst = inst.getChildInst(ir, 1);
unsigned texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, -1, normalize);
return toSwizzle ? EmitSamplingUseRaw(addTexSampling(mapIdx, texGenIdx))
: EmitSamplingUseRGB(addTexSampling(mapIdx, texGenIdx));
} else
return std::string();
}
case IR::OpType::LoadImm: {
const atVec4f& vec = inst.m_loadImm.m_immVec;
return EmitVec3(vec);
}
case IR::OpType::Arithmetic: {
const IR::Instruction& aInst = inst.getChildInst(ir, 0);
const IR::Instruction& bInst = inst.getChildInst(ir, 1);
std::string aTrace = RecursiveTraceDiffuseColor(ir, diag, aInst, false, fallback);
std::string bTrace = RecursiveTraceDiffuseColor(ir, diag, bInst, false, fallback);
return (!aTrace.empty()) ? aTrace : bTrace;
}
case IR::OpType::Swizzle: {
const IR::Instruction& aInst = inst.getChildInst(ir, 0);
std::string aTrace = RecursiveTraceDiffuseColor(ir, diag, aInst, true, fallback);
if (!aTrace.empty())
return EmitSwizzle3(diag, inst.m_loc, aTrace, inst.m_swizzle.m_idxs);
return std::string();
}
default:
diag.reportBackendErr(inst.m_loc, "invalid color op");
}
return std::string();
}
std::string ProgrammableCommon::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const IR::Instruction& inst,
bool toSwizzle) {
switch (inst.m_op) {
case IR::OpType::Call: {
const std::string& name = inst.m_call.m_name;
bool normalize = false;
if (!name.compare("Texture") || !name.compare("TextureD") ||
((normalize = true) && !name.compare("TextureN")) ||
((normalize = true) && !name.compare("TextureDN"))) {
if (inst.getChildCount() < 2)
diag.reportBackendErr(inst.m_loc, "Texture(map, texgen) requires 2 arguments");
const IR::Instruction& mapInst = inst.getChildInst(ir, 0);
auto& mapImm = mapInst.getImmVec();
unsigned mapIdx = unsigned(mapImm.simd[0]);
const IR::Instruction& tcgInst = inst.getChildInst(ir, 1);
unsigned texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, -1, normalize);
return toSwizzle ? EmitSamplingUseRaw(addTexSampling(mapIdx, texGenIdx))
: EmitSamplingUseRGB(addTexSampling(mapIdx, texGenIdx));
} else if (!name.compare("ColorReg")) {
const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
unsigned idx = unsigned(idxInst.getImmVec().simd[0]);
return toSwizzle ? EmitColorRegUseRaw(idx) : EmitColorRegUseRGB(idx);
} else if (!name.compare("Lighting")) {
m_lighting = true;
return toSwizzle ? EmitLightingRaw() : EmitLightingRGB();
} else if (!name.compare("vec3")) {
if (inst.getChildCount() < 3)
diag.reportBackendErr(inst.m_loc, "vec3(r,g,b) requires 3 arguments");
const IR::Instruction& aInst = inst.getChildInst(ir, 0);
const IR::Instruction& bInst = inst.getChildInst(ir, 1);
const IR::Instruction& cInst = inst.getChildInst(ir, 2);
return EmitVec3(RecursiveTraceAlpha(ir, diag, aInst, false), RecursiveTraceAlpha(ir, diag, bInst, false),
RecursiveTraceAlpha(ir, diag, cInst, false));
} else
diag.reportBackendErr(inst.m_loc, "unable to interpret '%s'", name.c_str());
break;
}
case IR::OpType::LoadImm: {
const atVec4f& vec = inst.m_loadImm.m_immVec;
return EmitVec3(vec);
}
case IR::OpType::Arithmetic: {
ArithmeticOp op = inst.m_arithmetic.m_op;
const IR::Instruction& aInst = inst.getChildInst(ir, 0);
const IR::Instruction& bInst = inst.getChildInst(ir, 1);
std::string aTrace = RecursiveTraceColor(ir, diag, aInst, false);
std::string bTrace = RecursiveTraceColor(ir, diag, bInst, false);
switch (op) {
case ArithmeticOp::Add: {
return EmitAdd(aTrace, bTrace);
}
case ArithmeticOp::Subtract: {
return EmitSub(aTrace, bTrace);
}
case ArithmeticOp::Multiply: {
return EmitMult(aTrace, bTrace);
}
case ArithmeticOp::Divide: {
return EmitDiv(aTrace, bTrace);
}
default:
diag.reportBackendErr(inst.m_loc, "invalid arithmetic op");
}
break;
}
case IR::OpType::Swizzle: {
const IR::Instruction& aInst = inst.getChildInst(ir, 0);
std::string aTrace = RecursiveTraceColor(ir, diag, aInst, true);
return EmitSwizzle3(diag, inst.m_loc, aTrace, inst.m_swizzle.m_idxs);
}
default:
diag.reportBackendErr(inst.m_loc, "invalid color op");
}
return std::string();
}
std::string ProgrammableCommon::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const IR::Instruction& inst,
bool toSwizzle) {
switch (inst.m_op) {
case IR::OpType::Call: {
const std::string& name = inst.m_call.m_name;
bool normalize = false;
if (!name.compare("Texture") || !name.compare("TextureD") ||
((normalize = true) && !name.compare("TextureN")) ||
((normalize = true) && !name.compare("TextureDN"))) {
if (inst.getChildCount() < 2)
diag.reportBackendErr(inst.m_loc, "Texture(map, texgen) requires 2 arguments");
const IR::Instruction& mapInst = inst.getChildInst(ir, 0);
const atVec4f& mapImm = mapInst.getImmVec();
unsigned mapIdx = unsigned(mapImm.simd[0]);
const IR::Instruction& tcgInst = inst.getChildInst(ir, 1);
unsigned texGenIdx = RecursiveTraceTexGen(ir, diag, tcgInst, -1, normalize);
return toSwizzle ? EmitSamplingUseRaw(addTexSampling(mapIdx, texGenIdx))
: EmitSamplingUseAlpha(addTexSampling(mapIdx, texGenIdx));
} else if (!name.compare("ColorReg")) {
const IR::Instruction& idxInst = inst.getChildInst(ir, 0);
unsigned idx = unsigned(idxInst.getImmVec().simd[0]);
return toSwizzle ? EmitColorRegUseRaw(idx) : EmitColorRegUseAlpha(idx);
} else if (!name.compare("Lighting")) {
m_lighting = true;
return toSwizzle ? EmitLightingRaw() : EmitLightingAlpha();
} else
diag.reportBackendErr(inst.m_loc, "unable to interpret '%s'", name.c_str());
break;
}
case IR::OpType::LoadImm: {
const atVec4f& vec = inst.m_loadImm.m_immVec;
return EmitVal(vec.simd[0]);
}
case IR::OpType::Arithmetic: {
ArithmeticOp op = inst.m_arithmetic.m_op;
const IR::Instruction& aInst = inst.getChildInst(ir, 0);
const IR::Instruction& bInst = inst.getChildInst(ir, 1);
std::string aTrace = RecursiveTraceAlpha(ir, diag, aInst, false);
std::string bTrace = RecursiveTraceAlpha(ir, diag, bInst, false);
switch (op) {
case ArithmeticOp::Add: {
return EmitAdd(aTrace, bTrace);
}
case ArithmeticOp::Subtract: {
return EmitSub(aTrace, bTrace);
}
case ArithmeticOp::Multiply: {
return EmitMult(aTrace, bTrace);
}
case ArithmeticOp::Divide: {
return EmitDiv(aTrace, bTrace);
}
default:
diag.reportBackendErr(inst.m_loc, "invalid arithmetic op");
}
break;
}
case IR::OpType::Swizzle: {
const IR::Instruction& aInst = inst.getChildInst(ir, 0);
std::string aTrace = RecursiveTraceAlpha(ir, diag, aInst, true);
return EmitSwizzle1(diag, inst.m_loc, aTrace, inst.m_swizzle.m_idxs);
}
default:
diag.reportBackendErr(inst.m_loc, "invalid alpha op");
}
return std::string();
}
void ProgrammableCommon::resetResourceAccumulators() {
m_texSamplings.clear();
m_texMapEnd = 0;
m_tcgs.clear();
m_texMtxRefs.clear();
}
void ProgrammableCommon::reset(const IR& ir, Diagnostics& diag, const char* backendName) {
m_lighting = false;
m_texSamplings.clear();
m_texMapEnd = 0;
m_tcgs.clear();
m_texMtxRefs.clear();
m_colorExpr.clear();
m_alphaExpr.clear();
diag.setBackend(backendName);
/* Final instruction is the root call by hecl convention */
const IR::Instruction& rootCall = ir.m_instructions.back();
if (!rootCall.m_call.m_name.compare("HECLOpaque")) {
m_blendSrc = BlendFactor::One;
m_blendDst = BlendFactor::Zero;
} else if (!rootCall.m_call.m_name.compare("HECLAlpha")) {
m_blendSrc = BlendFactor::SrcAlpha;
m_blendDst = BlendFactor::InvSrcAlpha;
} else if (!rootCall.m_call.m_name.compare("HECLAdditive")) {
m_blendSrc = BlendFactor::SrcAlpha;
m_blendDst = BlendFactor::One;
} else {
diag.reportBackendErr(rootCall.m_loc, "%s backend doesn't handle '%s' root", backendName,
rootCall.m_call.m_name.c_str());
return;
}
/* Follow Color Chain */
const IR::Instruction& colorRoot = ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(0));
m_diffuseColorExpr = RecursiveTraceDiffuseColor(ir, diag, colorRoot, false, false);
resetResourceAccumulators();
if (m_diffuseColorExpr.empty()) {
m_diffuseColorExpr = RecursiveTraceDiffuseColor(ir, diag, colorRoot, false, true);
resetResourceAccumulators();
}
m_colorExpr = RecursiveTraceColor(ir, diag, colorRoot, false);
/* Follow Alpha Chain */
if (rootCall.m_call.m_argInstIdxs.size() > 1) {
const IR::Instruction& alphaRoot = ir.m_instructions.at(rootCall.m_call.m_argInstIdxs.at(1));
m_alphaExpr = RecursiveTraceAlpha(ir, diag, alphaRoot, false);
}
}
static const char SWIZZLE_CHARS[] = "rgba";
std::string ProgrammableCommon::EmitSwizzle3(Diagnostics& diag, const SourceLocation& loc, const std::string& a,
const atInt8 swiz[4]) const {
std::string retval = a + '.';
for (int i = 0; i < 3; ++i) {
if (swiz[i] < 0 || swiz[i] > 3)
diag.reportBackendErr(loc, "unable to use swizzle as RGB value");
retval += SWIZZLE_CHARS[swiz[i]];
}
return retval;
}
std::string ProgrammableCommon::EmitSwizzle1(Diagnostics& diag, const SourceLocation& loc, const std::string& a,
const atInt8 swiz[4]) const {
std::string retval = a + '.';
if (swiz[0] < 0 || swiz[0] > 3)
diag.reportBackendErr(loc, "unable to use swizzle as Alpha value");
retval += SWIZZLE_CHARS[swiz[0]];
return retval;
}
} // namespace hecl::Backend

View File

@ -275,7 +275,7 @@ Connection::Connection(int verbosityLevel) {
SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
HANDLE consoleOutReadTmp, consoleOutWrite, consoleErrWrite, consoleOutRead;
if (!CreatePipe(&consoleOutReadTmp, &consoleOutWrite, &sattrs, 0))
if (!CreatePipe(&consoleOutReadTmp, &consoleOutWrite, &sattrs, 1024))
BlenderLog.report(logvisor::Fatal, "Error with CreatePipe");
if (!DuplicateHandle(GetCurrentProcess(), consoleOutWrite, GetCurrentProcess(), &consoleErrWrite, 0, TRUE,
@ -362,7 +362,7 @@ Connection::Connection(int verbosityLevel) {
m_consoleThreadRunning = true;
m_consoleThread = std::thread([=]() {
CHAR lpBuffer[256];
CHAR lpBuffer[1024];
DWORD nBytesRead;
DWORD nCharsWritten;
@ -482,6 +482,9 @@ Connection::Connection(int verbosityLevel) {
DEFAULT_BLENDER_BIN);
else
BlenderLog.report(logvisor::Fatal, _SYS_STR("Unable to find blender at '%s'"), DEFAULT_BLENDER_BIN);
} else if (!strcmp(lineBuf, "NOT280")) {
_closePipe();
BlenderLog.report(logvisor::Fatal, _SYS_STR("Installed blender version must be >= 2.80"));
} else if (!strcmp(lineBuf, "NOADDON")) {
_closePipe();
if (blenderAddonPath != _SYS_STR("SKIPINSTALL"))

View File

@ -1,9 +0,0 @@
add_executable(heclTest WIN32 main.cpp)
target_link_libraries(heclTest
${HECL_APPLICATION_REPS_TARGETS_LIST}
hecl-full hecl-blender-addon
athena-core athena-libyaml xxhash logvisor boo
${ZLIB_LIBRARIES} lzokay ${BOO_SYS_LIBS})
if(COMMAND add_sanitizers)
add_sanitizers(heclTest)
endif()

View File

@ -1,282 +0,0 @@
#include <boo/boo.hpp>
#include "logvisor/logvisor.hpp"
#include "hecl/Console.hpp"
#include "hecl/CVarManager.hpp"
#include "athena/MemoryWriter.hpp"
#include "hecl/Runtime.hpp"
#include "hecl/Backend/Backend.hpp"
#include "hecl/HMDLMeta.hpp"
#include "hecl/Pipeline.hpp"
#include <cmath>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std::literals;
struct HECLWindowCallback : boo::IWindowCallback {
bool m_sizeDirty = false;
boo::SWindowRect m_latestSize;
virtual ~HECLWindowCallback();
void resized(const boo::SWindowRect& rect, bool /*sync*/) {
m_sizeDirty = true;
m_latestSize = rect;
}
bool m_destroyed = false;
void destroyed() { m_destroyed = true; }
void charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat) {
hecl::Console::instance()->handleCharCode(charCode, mods, isRepeat);
}
void specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods, bool isRepeat) {
hecl::Console::instance()->handleSpecialKeyDown(key, mods, isRepeat);
}
void specialKeyUp(boo::ESpecialKey key, boo::EModifierKey mods) {
hecl::Console::instance()->hecl::Console::handleSpecialKeyUp(key, mods);
}
};
HECLWindowCallback::~HECLWindowCallback() {}
struct HECLApplicationCallback : boo::IApplicationCallback {
HECLWindowCallback m_windowCb;
hecl::Runtime::FileStoreManager m_fileStoreMgr;
hecl::CVarManager m_cvarManager;
hecl::Console m_console;
std::shared_ptr<boo::IWindow> m_mainWindow;
bool m_running = true;
HECLApplicationCallback()
: m_fileStoreMgr(_SYS_STR("heclTest")), m_cvarManager(m_fileStoreMgr), m_console(&m_cvarManager) {
m_console.registerCommand(
"quit"sv, "Quits application"sv, "",
std::bind(&HECLApplicationCallback::quit, this, std::placeholders::_1, std::placeholders::_2));
}
virtual ~HECLApplicationCallback();
int appMain(boo::IApplication* app) {
hecl::VerbosityLevel = 2;
/* Setup boo window */
m_mainWindow = app->newWindow(_SYS_STR("HECL Test"));
m_mainWindow->setCallback(&m_windowCb);
boo::ObjToken<boo::ITextureR> renderTex;
boo::ObjToken<boo::IGraphicsBuffer> vubo;
boo::ObjToken<boo::IShaderPipeline> pipeline, pipeline2;
boo::ObjToken<boo::IShaderDataBinding> binding, binding2;
struct VertexUBO {
float modelview[4][4] = {};
float modelviewInv[4][4] = {};
float projection[4][4] = {};
VertexUBO() {
modelview[0][0] = 1.0;
modelview[1][1] = 1.0;
modelview[2][2] = 1.0;
modelview[3][3] = 1.0;
modelviewInv[0][0] = 1.0;
modelviewInv[1][1] = 1.0;
modelviewInv[2][2] = 1.0;
modelviewInv[3][3] = 1.0;
projection[0][0] = 1.0;
projection[1][1] = 1.0;
projection[2][2] = 1.0;
projection[3][3] = 1.0;
}
} vuboData;
/* Make ramp texture */
using Pixel = uint8_t[4];
static Pixel tex[256][256];
for (int i = 0; i < 256; ++i)
for (int j = 0; j < 256; ++j) {
tex[i][j][0] = uint8_t(i);
tex[i][j][1] = uint8_t(j);
tex[i][j][2] = 0;
tex[i][j][3] = 0xff;
}
boo::IGraphicsDataFactory* gfxF = m_mainWindow->getMainContextDataFactory();
if (gfxF->platform() == boo::IGraphicsDataFactory::Platform::Vulkan)
vuboData.modelview[1][1] = -1.f;
/* Pipeline converter */
std::unique_ptr<hecl::PipelineConverterBase> conv = hecl::NewPipelineConverter(gfxF);
/* Compile HECL shader */
static std::string testShader = "HECLOpaque(Texture(0, UV(0)))";
// static std::string testShader = "HECLOpaque(vec3(1.0,1.0,1.0),1.0)";
hecl::Backend::ShaderTag testShaderTag(testShader, 0, 1, 0, 0, boo::Primitive::TriStrips,
hecl::Backend::ReflectionType::None, false, false, false, false);
hecl::Frontend::Frontend FE;
hecl::Frontend::IR ir = FE.compileSource(testShader, "booTest");
hecl::HECLIR irObj(ir, testShaderTag, 0);
gfxF->commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) {
pipeline = conv->convert(ctx, irObj);
pipeline2 = conv->convert(ctx, Shader_test{});
boo::SWindowRect mainWindowRect = m_mainWindow->getWindowFrame();
renderTex = ctx.newRenderTexture(size_t(mainWindowRect.size[0]), size_t(mainWindowRect.size[1]),
boo::TextureClampMode::Repeat, 1, 0);
/* Generate meta structure (usually statically serialized) */
hecl::HMDLMeta testMeta;
testMeta.topology = hecl::HMDLTopology::TriStrips;
testMeta.vertStride = 32;
testMeta.vertCount = 4;
testMeta.indexCount = 4;
testMeta.colorCount = 0;
testMeta.uvCount = 1;
testMeta.weightCount = 0;
testMeta.bankCount = 0;
/* Binary form of meta structure */
atUint8 testMetaBuf[HECL_HMDL_META_SZ];
athena::io::MemoryWriter testMetaWriter(testMetaBuf, HECL_HMDL_META_SZ);
testMeta.write(testMetaWriter);
/* Make Tri-strip VBO */
struct Vert {
float pos[3];
float norm[3];
float uv[2];
};
static const Vert quad[4] = {{{0.5, 0.5}, {}, {1.0, 1.0}},
{{-0.5, 0.5}, {}, {0.0, 1.0}},
{{0.5, -0.5}, {}, {1.0, 0.0}},
{{-0.5, -0.5}, {}, {0.0, 0.0}}};
/* Now simple IBO */
static const uint32_t ibo[4] = {0, 1, 2, 3};
/* Construct quad mesh against boo factory */
hecl::Runtime::HMDLData testData(ctx, testMetaBuf, quad, ibo);
boo::ObjToken<boo::ITexture> texture = ctx.newStaticTexture(256, 256, 1, boo::TextureFormat::RGBA8,
boo::TextureClampMode::Repeat, tex, 256 * 256 * 4)
.get();
/* Make vertex uniform buffer */
vubo = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(VertexUBO), 1).get();
/* Assemble data binding */
binding = testData.newShaderDataBindng(ctx, pipeline, 1, &vubo, nullptr, 1, &texture);
binding2 = testData.newShaderDataBindng(ctx, pipeline2, 1, &vubo, nullptr, 1, &texture);
return true;
} BooTrace);
m_mainWindow->showWindow();
m_windowCb.m_latestSize = m_mainWindow->getWindowFrame();
boo::IGraphicsCommandQueue* gfxQ = m_mainWindow->getCommandQueue();
size_t frameIdx = 0;
while (m_running) {
m_mainWindow->waitForRetrace();
if (m_windowCb.m_destroyed) {
m_running = false;
break;
}
if (m_windowCb.m_sizeDirty) {
gfxQ->resizeRenderTexture(renderTex, size_t(m_windowCb.m_latestSize.size[0]),
size_t(m_windowCb.m_latestSize.size[1]));
m_windowCb.m_sizeDirty = false;
}
m_console.proc();
gfxQ->setRenderTarget(renderTex);
boo::SWindowRect r = m_windowCb.m_latestSize;
r.location[0] = 0;
r.location[1] = 0;
gfxQ->setViewport(r);
gfxQ->setScissor(r);
float rgba[] = {sinf(frameIdx / 60.0f), cosf(frameIdx / 60.0f), 0.0f, 1.0f};
gfxQ->setClearColor(rgba);
gfxQ->clearTarget();
vuboData.modelview[3][0] = sinf(frameIdx / 60.0f) * 0.5f;
vuboData.modelview[3][1] = cosf(frameIdx / 60.0f) * 0.5f;
vubo.cast<boo::IGraphicsBufferD>()->load(&vuboData, sizeof(vuboData));
gfxQ->setShaderDataBinding(binding2);
gfxQ->drawIndexed(0, 4);
gfxQ->resolveDisplay(renderTex);
m_console.draw(gfxQ);
gfxQ->execute();
++frameIdx;
}
m_cvarManager.serialize();
gfxQ->stopRenderer();
return 0;
}
void appQuitting(boo::IApplication* /*app*/) { m_running = false; }
void quit(hecl::Console* /*con*/, const std::vector<std::string>& /*args*/) { m_running = false; }
};
void AthenaExcHandler(athena::error::Level level, const char* file, const char* /*function*/, int line, const char* fmt,
...) {
static logvisor::Module Log("heclTest::AthenaExcHandler");
va_list ap;
va_start(ap, fmt);
Log.reportSource(logvisor::Level(level), file, uint32_t(line), fmt, ap);
va_end(ap);
}
#if !WINDOWS_STORE
#if _WIN32
int wmain(int argc, const boo::SystemChar** argv)
#else
int main(int argc, const boo::SystemChar** argv)
#endif
{
atSetExceptionHandler(AthenaExcHandler);
logvisor::RegisterStandardExceptions();
logvisor::RegisterConsoleLogger();
HECLApplicationCallback appCb;
int ret = boo::ApplicationRun(boo::IApplication::EPlatformType::Auto, appCb, _SYS_STR("heclTest"),
_SYS_STR("HECL Test"), argc, argv);
printf("IM DYING!!\n");
return ret;
}
#else
using namespace Windows::ApplicationModel::Core;
[Platform::MTAThread] int WINAPIV main(Platform::Array<Platform::String ^> ^ params) {
logvisor::RegisterStandardExceptions();
logvisor::RegisterConsoleLogger();
HECLApplicationCallback appCb;
boo::ViewProvider ^ viewProvider = ref new boo::ViewProvider(appCb, _SYS_STR("heclTest"), _SYS_STR("HECL Test"),
_SYS_STR("heclTest"), params, false);
CoreApplication::Run(viewProvider);
return 0;
}
#endif
#if _WIN32 && !WINDOWS_STORE
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int) {
int argc = 0;
const boo::SystemChar** argv;
if (lpCmdLine[0])
argv = (const wchar_t**)(CommandLineToArgvW(lpCmdLine, &argc));
static boo::SystemChar selfPath[1024];
GetModuleFileNameW(nullptr, selfPath, 1024);
static const boo::SystemChar* booArgv[32] = {};
booArgv[0] = selfPath;
for (int i = 0; i < argc; ++i)
booArgv[i + 1] = argv[i];
logvisor::CreateWin32Console();
return wmain(argc + 1, booArgv);
}
#endif
HECLApplicationCallback::~HECLApplicationCallback() {}

View File

@ -1,93 +0,0 @@
#shader test
#culling none
#attribute position3
#attribute normal3
#attribute uv2
#vertex glsl
layout(location=0) in vec3 in_pos;
layout(location=1) in vec3 in_norm;
layout(location=2) in vec2 in_uv;
SBINDING(0) out vec2 out_uv;
void main()
{
gl_Position = vec4(in_pos, 1.0);
out_uv = in_uv;
}
#fragment glsl
precision highp float;
TBINDING0 uniform sampler2D texs[1];
layout(location=0) out vec4 out_frag;
SBINDING(0) in vec2 out_uv;
void main()
{
out_frag = texture(texs[0], out_uv);
}
#vertex hlsl
struct VertData
{
float3 in_pos : POSITION;
float3 in_norm : NORMAL;
float2 in_uv : UV;
};
struct VertToFrag
{
float4 position : SV_Position;
float2 out_uv : UV;
};
VertToFrag main(in VertData v)
{
VertToFrag ret;
ret.position = float4(v.in_pos, 1.0);
ret.out_uv = v.in_uv;
return ret;
}
#fragment hlsl
struct VertToFrag
{
float4 position : SV_Position;
float2 out_uv : UV;
};
Texture2D texs : register(t0);
SamplerState samp : register(s0);
float4 main(in VertToFrag vtf) : SV_Target0
{
return texs.Sample(samp, vtf.out_uv);
}
#vertex metal
struct VertData
{
float3 in_pos [[ attribute(0) ]];
float3 in_norm [[ attribute(1) ]];
float2 in_uv [[ attribute(2) ]];
};
struct VertToFrag
{
float4 position [[ position ]];
float2 out_uv;
};
vertex VertToFrag vmain(VertData v [[ stage_in ]])
{
VertToFrag ret;
ret.position = float4(v.in_pos, 1.0);
ret.out_uv = v.in_uv;
return ret;
}
#fragment metal
struct VertToFrag
{
float4 position [[ position ]];
float2 out_uv;
};
fragment float4 fmain(VertToFrag vtf [[ stage_in ]],
sampler samp [[ sampler(0) ]],
texture2d<float> tex [[ texture(0) ]])
{
return tex.sample(samp, vtf.out_uv);
}