Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WGSL] [WASM] Add reflection endpoints + Fix bit manipulation operations #5499

Merged
merged 10 commits into from
Nov 8, 2024
33 changes: 33 additions & 0 deletions source/slang-wasm/slang-wasm-bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,44 @@ EMSCRIPTEN_BINDINGS(slang)
.function("getEntryPointCodeBlob", &slang::wgsl::ComponentType::getEntryPointCodeBlob)
.function("getTargetCodeBlob", &slang::wgsl::ComponentType::getTargetCodeBlob)
.function("getTargetCode", &slang::wgsl::ComponentType::getTargetCode)
.function("getLayout", &slang::wgsl::ComponentType::getLayout, allow_raw_pointers())
.function(
"loadStrings",
&slang::wgsl::ComponentType::loadStrings,
return_value_policy::take_ownership());

class_<slang::wgsl::TypeLayoutReflection>("TypeLayoutReflection")
.function(
"getDescriptorSetDescriptorRangeType",
&slang::wgsl::TypeLayoutReflection::getDescriptorSetDescriptorRangeType);

class_<slang::wgsl::VariableLayoutReflection>("VariableLayoutReflection")
.function("getName", &slang::wgsl::VariableLayoutReflection::getName)
.function(
"getTypeLayout",
&slang::wgsl::VariableLayoutReflection::getTypeLayout,
allow_raw_pointers())
.function("getBindingIndex", &slang::wgsl::VariableLayoutReflection::getBindingIndex);

class_<slang::wgsl::ProgramLayout>("ProgramLayout")
.function("getParameterCount", &slang::wgsl::ProgramLayout::getParameterCount)
.function(
"getParameterByIndex",
&slang::wgsl::ProgramLayout::getParameterByIndex,
allow_raw_pointers())
.function(
"getGlobalParamsTypeLayout",
&slang::wgsl::ProgramLayout::getGlobalParamsTypeLayout,
allow_raw_pointers());

enum_<slang::BindingType>("BindingType")
.value("Unknown", slang::BindingType::Unknown)
.value("Texture", slang::BindingType::Texture)
.value("ConstantBuffer", slang::BindingType::ConstantBuffer)
.value("MutableRawBuffer", slang::BindingType::MutableRawBuffer)
.value("MutableTypedBuffer", slang::BindingType::MutableTypedBuffer)
.value("MutableTexture", slang::BindingType::MutableTexture);

class_<slang::wgsl::Module, base<slang::wgsl::ComponentType>>("Module")
.function(
"findEntryPointByName",
Expand Down
43 changes: 43 additions & 0 deletions source/slang-wasm/slang-wasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,49 @@ HashedString* ComponentType::loadStrings()
return hashedStrings;
}

ProgramLayout* ComponentType::getLayout(unsigned int targetIndex)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to making really hard in javascript to ensure all these reflection objects are explicitly delete()'d when they are no longer in use.

We should instead just return a raw pointer to the layout without allocating a fresh object on the heap, and use allow_raw_pointers in emscripten bind, to free the javascript side from the responsibility of manually calling delete().

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, let me see if I can change up the wasm bindings

{
return (slang::wgsl::ProgramLayout*)interface()->getLayout(targetIndex);
}

unsigned int ProgramLayout::getParameterCount()
{
return interface()->getParameterCount();
}

VariableLayoutReflection* ProgramLayout::getParameterByIndex(unsigned int index)
{
return (slang::wgsl::VariableLayoutReflection*)(interface()->getParameterByIndex(index));
}

TypeLayoutReflection* ProgramLayout::getGlobalParamsTypeLayout()
{
return (slang::wgsl::TypeLayoutReflection*)(interface()->getGlobalParamsTypeLayout());
}

BindingType TypeLayoutReflection::getDescriptorSetDescriptorRangeType(
unsigned int setIndex,
unsigned int rangeIndex)
{
return interface()->getDescriptorSetDescriptorRangeType(setIndex, rangeIndex);
}

std::string VariableLayoutReflection::getName()
{
return interface()->getName();
}

TypeLayoutReflection* VariableLayoutReflection::getTypeLayout()
{
return (slang::wgsl::TypeLayoutReflection*)(interface()->getTypeLayout());
}

unsigned int VariableLayoutReflection::getBindingIndex()
{
return interface()->getBindingIndex();
}


namespace lsp
{
Position translate(Slang::LanguageServerProtocol::Position p)
Expand Down
36 changes: 36 additions & 0 deletions source/slang-wasm/slang-wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,40 @@ class HashedString

CompileTargets* getCompileTargets();


class TypeLayoutReflection
{
public:
BindingType getDescriptorSetDescriptorRangeType(unsigned int setIndex, unsigned int rangeIndex);

slang::TypeLayoutReflection* interface() const { return (slang::TypeLayoutReflection*)this; }
};

class VariableLayoutReflection
{
public:
std::string getName();
slang::wgsl::TypeLayoutReflection* getTypeLayout();
unsigned int getBindingIndex();

slang::VariableLayoutReflection* interface() const
{
return (slang::VariableLayoutReflection*)this;
}
};


class ProgramLayout
{
public:
unsigned int getParameterCount();
slang::wgsl::VariableLayoutReflection* getParameterByIndex(unsigned int index);

slang::wgsl::TypeLayoutReflection* getGlobalParamsTypeLayout();

slang::ProgramLayout* interface() const { return (slang::ProgramLayout*)this; }
};

class ComponentType
{
public:
Expand All @@ -65,6 +99,8 @@ class ComponentType
std::string getTargetCode(int targetIndex);
emscripten::val getTargetCodeBlob(int targetIndex);

slang::wgsl::ProgramLayout* getLayout(unsigned int targetIndex);

slang::IComponentType* interface() const { return m_interface; }

HashedString* loadStrings();
Expand Down
7 changes: 7 additions & 0 deletions source/slang/slang-emit-c-like.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,13 @@ bool CLikeSourceEmitter::maybeEmitParens(EmitOpInfo& outerPrec, const EmitOpInfo
{
needParens = true;
}
// a ^ b * c => (a ^ b) * c
else if (
prec.rightPrecedence == EPrecedence::kEPrecedence_BitXor_Right &&
outerPrec.rightPrecedence == EPrecedence::kEPrecedence_Multiplicative_Left)
{
needParens = true;
}

if (needParens)
{
Expand Down
66 changes: 51 additions & 15 deletions source/slang/slang-emit-wgsl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1304,28 +1304,64 @@ bool WGSLSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOu
// https://www.w3.org/TR/WGSL/#bit-expr
IRInst* const shiftAmount = inst->getOperand(1);
IRType* const shiftAmountType = shiftAmount->getDataType();
if (shiftAmountType->getOp() == kIROp_IntType)
{
// Dawn complains about "mixing '<<' and '|' requires parenthesis", so let's
// add parenthesis.
m_writer->emit("(");

const auto emitOp = getEmitOpForOp(inst->getOp());
const auto info = getInfo(emitOp);
// Dawn complains about mixing '<<' and '|', '^' and a bunch of other bit operators
// without a paranthesis, so we'll always emit paranthesis around the shift amount.
//

const bool needClose = maybeEmitParens(outerPrec, info);
emitOperand(inst->getOperand(0), leftSide(outerPrec, info));
m_writer->emit(" ");
m_writer->emit(info.op);
m_writer->emit(" ");
m_writer->emit("(");

const auto emitOp = getEmitOpForOp(inst->getOp());
const auto info = getInfo(emitOp);

const bool needClose = maybeEmitParens(outerPrec, info);
emitOperand(inst->getOperand(0), leftSide(outerPrec, info));
m_writer->emit(" ");
m_writer->emit(info.op);
m_writer->emit(" ");

if (shiftAmountType->getOp() == kIROp_IntType)
{
m_writer->emit("bitcast<u32>(");
emitOperand(inst->getOperand(1), rightSide(outerPrec, info));
m_writer->emit(")");
maybeCloseParens(needClose);

}
else
{
m_writer->emit("(");
emitOperand(inst->getOperand(1), rightSide(outerPrec, info));
m_writer->emit(")");
return true;
}

maybeCloseParens(needClose);

m_writer->emit(")");

return true;
}
case kIROp_BitXor:
case kIROp_BitOr:
{
// Emit bitwise operators with paranthesis to avoid precedence issues
const auto emitOp = getEmitOpForOp(inst->getOp());
const auto info = getInfo(emitOp);

m_writer->emit("(");

const bool needClose = maybeEmitParens(outerPrec, info);
emitOperand(inst->getOperand(0), leftSide(outerPrec, info));
m_writer->emit(" ");

m_writer->emit(info.op);

m_writer->emit(" (");
emitOperand(inst->getOperand(1), rightSide(outerPrec, info));
m_writer->emit(")");

maybeCloseParens(needClose);

m_writer->emit(")");
return true;
}
break;

Expand Down
Loading