mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-02 01:24:11 +01:00
[dxbc] Basic geometry shader (sm4) support
This commit is contained in:
parent
c44b50ae4d
commit
6cc3ff4ad8
@ -17,7 +17,6 @@ namespace dxvk {
|
||||
BytecodeLength);
|
||||
|
||||
DxbcModule module(reader);
|
||||
m_shader = module.compile();
|
||||
|
||||
// If requested by the user, dump both the raw DXBC
|
||||
// shader and the compiled SPIR-V module to a file.
|
||||
@ -31,12 +30,20 @@ namespace dxvk {
|
||||
|
||||
reader.store(std::ofstream(str::format(baseName, ".dxbc"),
|
||||
std::ios_base::binary | std::ios_base::trunc));
|
||||
}
|
||||
|
||||
|
||||
m_shader = module.compile();
|
||||
|
||||
if (dumpPath.size() != 0) {
|
||||
const std::string baseName = str::format(dumpPath, "/",
|
||||
ConstructFileName(ComputeShaderHash(pShaderBytecode, BytecodeLength),
|
||||
module.version().type()));
|
||||
|
||||
m_shader->dump(std::ofstream(str::format(baseName, ".spv"),
|
||||
std::ios_base::binary | std::ios_base::trunc));
|
||||
}
|
||||
|
||||
|
||||
// If requested by the user, replace
|
||||
// the shader with another file.
|
||||
const std::string readPath
|
||||
|
@ -35,8 +35,9 @@ namespace dxvk {
|
||||
// Initialize the shader module with capabilities
|
||||
// etc. Each shader type has its own peculiarities.
|
||||
switch (m_version.type()) {
|
||||
case DxbcProgramType::VertexShader: this->emitVsInit(); break;
|
||||
case DxbcProgramType::PixelShader: this->emitPsInit(); break;
|
||||
case DxbcProgramType::VertexShader: this->emitVsInit(); break;
|
||||
case DxbcProgramType::GeometryShader: this->emitGsInit(); break;
|
||||
case DxbcProgramType::PixelShader: this->emitPsInit(); break;
|
||||
default: throw DxvkError("DxbcCompiler: Unsupported program type");
|
||||
}
|
||||
}
|
||||
@ -55,6 +56,9 @@ namespace dxvk {
|
||||
case DxbcInstClass::ControlFlow:
|
||||
return this->emitControlFlow(ins);
|
||||
|
||||
case DxbcInstClass::GeometryEmit:
|
||||
return this->emitGeometryEmit(ins);
|
||||
|
||||
case DxbcInstClass::TextureSample:
|
||||
return this->emitSample(ins);
|
||||
|
||||
@ -70,6 +74,9 @@ namespace dxvk {
|
||||
case DxbcInstClass::VectorDot:
|
||||
return this->emitVectorDot(ins);
|
||||
|
||||
case DxbcInstClass::VectorIdiv:
|
||||
return this->emitVectorIdiv(ins);
|
||||
|
||||
case DxbcInstClass::VectorImul:
|
||||
return this->emitVectorImul(ins);
|
||||
|
||||
@ -98,8 +105,9 @@ namespace dxvk {
|
||||
// input registers, call various shader functions
|
||||
// and write back the output registers.
|
||||
switch (m_version.type()) {
|
||||
case DxbcProgramType::VertexShader: this->emitVsFinalize(); break;
|
||||
case DxbcProgramType::PixelShader: this->emitPsFinalize(); break;
|
||||
case DxbcProgramType::VertexShader: this->emitVsFinalize(); break;
|
||||
case DxbcProgramType::GeometryShader: this->emitGsFinalize(); break;
|
||||
case DxbcProgramType::PixelShader: this->emitPsFinalize(); break;
|
||||
default: throw DxvkError("DxbcCompiler: Unsupported program type");
|
||||
}
|
||||
|
||||
@ -152,6 +160,15 @@ namespace dxvk {
|
||||
case DxbcOpcode::DclResource:
|
||||
return this->emitDclResource(ins);
|
||||
|
||||
case DxbcOpcode::DclGsInputPrimitive:
|
||||
return this->emitDclGsInputPrimitive(ins);
|
||||
|
||||
case DxbcOpcode::DclGsOutputPrimitiveTopology:
|
||||
return this->emitDclGsOutputTopology(ins);
|
||||
|
||||
case DxbcOpcode::DclMaxOutputVertexCount:
|
||||
return this->emitDclMaxOutputVertexCount(ins);
|
||||
|
||||
default:
|
||||
Logger::warn(
|
||||
str::format("DxbcCompiler: Unhandled opcode: ",
|
||||
@ -175,9 +192,10 @@ namespace dxvk {
|
||||
m_rRegs.resize(newCount);
|
||||
|
||||
DxbcRegisterInfo info;
|
||||
info.type.ctype = DxbcScalarType::Float32;
|
||||
info.type.ccount = 4;
|
||||
info.sclass = spv::StorageClassPrivate;
|
||||
info.type.ctype = DxbcScalarType::Float32;
|
||||
info.type.ccount = 4;
|
||||
info.type.alength = 0;
|
||||
info.sclass = spv::StorageClassPrivate;
|
||||
|
||||
for (uint32_t i = oldCount; i < newCount; i++) {
|
||||
const uint32_t varId = this->emitNewVariable(info);
|
||||
@ -274,21 +292,17 @@ namespace dxvk {
|
||||
DxbcRegMask regMask,
|
||||
DxbcSystemValue sv,
|
||||
DxbcInterpolationMode im) {
|
||||
if (regDim != 0) {
|
||||
Logger::err("DxbcCompiler: Input arrays not yet supported");
|
||||
return;
|
||||
}
|
||||
|
||||
// Avoid declaring the same variable multiple times.
|
||||
// This may happen when multiple system values are
|
||||
// mapped to different parts of the same register.
|
||||
if (m_vRegs.at(regIdx) == 0) {
|
||||
DxbcRegisterInfo info;
|
||||
info.type.ctype = DxbcScalarType::Float32;
|
||||
info.type.ccount = 4;
|
||||
info.type.ctype = DxbcScalarType::Float32;
|
||||
info.type.ccount = 4;
|
||||
info.type.alength = regDim;
|
||||
info.sclass = spv::StorageClassInput;
|
||||
|
||||
const uint32_t varId = this->emitNewVariable(info);
|
||||
uint32_t varId = this->emitNewVariable(info);
|
||||
|
||||
m_module.decorateLocation(varId, regIdx);
|
||||
m_module.setDebugName(varId, str::format("v", regIdx).c_str());
|
||||
@ -327,18 +341,14 @@ namespace dxvk {
|
||||
DxbcRegMask regMask,
|
||||
DxbcSystemValue sv,
|
||||
DxbcInterpolationMode im) {
|
||||
if (regDim != 0) {
|
||||
Logger::err("DxbcCompiler: Output arrays not yet supported");
|
||||
return;
|
||||
}
|
||||
|
||||
// Avoid declaring the same variable multiple times.
|
||||
// This may happen when multiple system values are
|
||||
// mapped to different parts of the same register.
|
||||
if (m_oRegs.at(regIdx) == 0) {
|
||||
DxbcRegisterInfo info;
|
||||
info.type.ctype = DxbcScalarType::Float32;
|
||||
info.type.ccount = 4;
|
||||
info.type.ctype = DxbcScalarType::Float32;
|
||||
info.type.ccount = 4;
|
||||
info.type.alength = regDim;
|
||||
info.sclass = spv::StorageClassOutput;
|
||||
|
||||
const uint32_t varId = this->emitNewVariable(info);
|
||||
@ -555,6 +565,50 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitDclGsInputPrimitive(const DxbcShaderInstruction& ins) {
|
||||
// The input primitive type is stored within in the
|
||||
// control bits of the opcode token. In SPIR-V, we
|
||||
// have to define an execution mode.
|
||||
const spv::ExecutionMode mode = [&] {
|
||||
switch (ins.controls.primitive) {
|
||||
case DxbcPrimitive::Point: return spv::ExecutionModeInputPoints;
|
||||
case DxbcPrimitive::Line: return spv::ExecutionModeInputLines;
|
||||
case DxbcPrimitive::Triangle: return spv::ExecutionModeTriangles;
|
||||
case DxbcPrimitive::LineAdj: return spv::ExecutionModeInputLinesAdjacency;
|
||||
case DxbcPrimitive::TriangleAdj: return spv::ExecutionModeInputTrianglesAdjacency;
|
||||
default: throw DxvkError("DxbcCompiler: Unsupported primitive type");
|
||||
}
|
||||
}();
|
||||
|
||||
m_module.setExecutionMode(m_entryPointId, mode);
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitDclGsOutputTopology(const DxbcShaderInstruction& ins) {
|
||||
// The input primitive topology is stored within in the
|
||||
// control bits of the opcode token. In SPIR-V, we have
|
||||
// to define an execution mode.
|
||||
const spv::ExecutionMode mode = [&] {
|
||||
switch (ins.controls.primitiveTopology) {
|
||||
case DxbcPrimitiveTopology::PointList: return spv::ExecutionModeOutputPoints;
|
||||
case DxbcPrimitiveTopology::LineStrip: return spv::ExecutionModeOutputLineStrip;
|
||||
case DxbcPrimitiveTopology::TriangleStrip: return spv::ExecutionModeOutputTriangleStrip;
|
||||
default: throw DxvkError("DxbcCompiler: Unsupported primitive topology");
|
||||
}
|
||||
}();
|
||||
|
||||
m_module.setExecutionMode(m_entryPointId, mode);
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitDclMaxOutputVertexCount(const DxbcShaderInstruction& ins) {
|
||||
// dcl_max_output_vertex_count has one operand:
|
||||
// (imm0) The maximum number of vertices
|
||||
m_gs.outputVertexCount = ins.imm[0].u32;
|
||||
m_module.setOutputVertices(m_entryPointId, m_gs.outputVertexCount);
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitVectorAlu(const DxbcShaderInstruction& ins) {
|
||||
std::array<DxbcRegisterValue, DxbcMaxOperandCount> src;
|
||||
|
||||
@ -824,6 +878,66 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitVectorIdiv(const DxbcShaderInstruction& ins) {
|
||||
// udiv has four operands:
|
||||
// (dst0) Quotient destination register
|
||||
// (dst1) Remainder destination register
|
||||
// (src0) The first vector to compare
|
||||
// (src1) The second vector to compare
|
||||
if (ins.dst[0].type == DxbcOperandType::Null
|
||||
&& ins.dst[1].type == DxbcOperandType::Null)
|
||||
return;
|
||||
|
||||
// FIXME support this if applications require it
|
||||
if (ins.dst[0].type != DxbcOperandType::Null
|
||||
&& ins.dst[1].type != DxbcOperandType::Null
|
||||
&& ins.dst[0].mask != ins.dst[1].mask) {
|
||||
Logger::warn("DxbcCompiler: Umul with different destination masks not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
// Load source operands as integers with the
|
||||
// mask of one non-NULL destination operand
|
||||
const DxbcRegMask srcMask =
|
||||
ins.dst[0].type != DxbcOperandType::Null
|
||||
? ins.dst[0].mask
|
||||
: ins.dst[1].mask;
|
||||
|
||||
const std::array<DxbcRegisterValue, 2> src = {
|
||||
emitRegisterLoad(ins.src[0], srcMask),
|
||||
emitRegisterLoad(ins.src[1], srcMask),
|
||||
};
|
||||
|
||||
// Compute results only if the destination
|
||||
// operands are not NULL.
|
||||
if (ins.dst[0].type != DxbcOperandType::Null) {
|
||||
DxbcRegisterValue quotient;
|
||||
quotient.type.ctype = ins.dst[0].dataType;
|
||||
quotient.type.ccount = ins.dst[0].mask.setCount();
|
||||
|
||||
quotient.id = m_module.opUDiv(
|
||||
getVectorTypeId(quotient.type),
|
||||
src.at(0).id, src.at(1).id);
|
||||
|
||||
quotient = emitDstOperandModifiers(quotient, ins.modifiers);
|
||||
emitRegisterStore(ins.dst[0], quotient);
|
||||
}
|
||||
|
||||
if (ins.dst[1].type != DxbcOperandType::Null) {
|
||||
DxbcRegisterValue remainder;
|
||||
remainder.type.ctype = ins.dst[1].dataType;
|
||||
remainder.type.ccount = ins.dst[1].mask.setCount();
|
||||
|
||||
remainder.id = m_module.opUMod(
|
||||
getVectorTypeId(remainder.type),
|
||||
src.at(0).id, src.at(1).id);
|
||||
|
||||
remainder = emitDstOperandModifiers(remainder, ins.modifiers);
|
||||
emitRegisterStore(ins.dst[1], remainder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitVectorImul(const DxbcShaderInstruction& ins) {
|
||||
// imul and umul have four operands:
|
||||
// (dst0) High destination register
|
||||
@ -835,7 +949,7 @@ namespace dxvk {
|
||||
return;
|
||||
|
||||
// If dst0 is NULL, this instruction behaves just
|
||||
// like any other three -operand ALU instruction
|
||||
// like any other three-operand ALU instruction
|
||||
const std::array<DxbcRegisterValue, 2> src = {
|
||||
emitRegisterLoad(ins.src[0], ins.dst[1].mask),
|
||||
emitRegisterLoad(ins.src[1], ins.dst[1].mask),
|
||||
@ -897,8 +1011,26 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitSample(
|
||||
const DxbcShaderInstruction& ins) {
|
||||
void DxbcCompiler::emitGeometryEmit(const DxbcShaderInstruction& ins) {
|
||||
switch (ins.op) {
|
||||
case DxbcOpcode::Emit: {
|
||||
emitGsOutputSetup();
|
||||
m_module.opEmitVertex();
|
||||
} break;
|
||||
|
||||
case DxbcOpcode::Cut: {
|
||||
m_module.opEndPrimitive();
|
||||
} break;
|
||||
|
||||
default:
|
||||
Logger::warn(str::format(
|
||||
"DxbcCompiler: Unhandled instruction: ",
|
||||
ins.op));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitSample(const DxbcShaderInstruction& ins) {
|
||||
// TODO support address offset
|
||||
// TODO support more sample ops
|
||||
|
||||
@ -1106,6 +1238,33 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitControlFlowDiscard(const DxbcShaderInstruction& ins) {
|
||||
// Discard actually has an operand that determines
|
||||
// whether or not the fragment should be discarded
|
||||
const DxbcRegisterValue condition = emitRegisterLoad(
|
||||
ins.src[0], DxbcRegMask(true, false, false, false));
|
||||
|
||||
const DxbcRegisterValue zeroTest = emitRegisterZeroTest(
|
||||
condition, ins.controls.zeroTest);
|
||||
|
||||
// Insert a Pseudo-'If' block
|
||||
const uint32_t discardBlock = m_module.allocateId();
|
||||
const uint32_t mergeBlock = m_module.allocateId();
|
||||
|
||||
m_module.opSelectionMerge(mergeBlock,
|
||||
spv::SelectionControlMaskNone);
|
||||
|
||||
m_module.opBranchConditional(
|
||||
zeroTest.id, discardBlock, mergeBlock);
|
||||
|
||||
// OpKill terminates the block
|
||||
m_module.opLabel(discardBlock);
|
||||
m_module.opKill();
|
||||
|
||||
m_module.opLabel(mergeBlock);
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitControlFlow(const DxbcShaderInstruction& ins) {
|
||||
switch (ins.op) {
|
||||
case DxbcOpcode::If:
|
||||
@ -1128,6 +1287,9 @@ namespace dxvk {
|
||||
|
||||
case DxbcOpcode::Ret:
|
||||
return this->emitControlFlowRet(ins);
|
||||
|
||||
case DxbcOpcode::Discard:
|
||||
return this->emitControlFlowDiscard(ins);
|
||||
|
||||
default:
|
||||
Logger::warn(str::format(
|
||||
@ -1368,16 +1530,30 @@ namespace dxvk {
|
||||
// stages, the index has two dimensions:
|
||||
// (0) vertex index (relative)
|
||||
// (1) register index (relative)
|
||||
if (operand.idxDim != 1)
|
||||
throw DxvkError("DxbcCompiler: 2D index for v# not yet supported");
|
||||
|
||||
// We don't support two-dimensional indices yet
|
||||
const uint32_t registerId = operand.idx[0].offset;
|
||||
|
||||
DxbcRegisterPointer result;
|
||||
result.type.ctype = DxbcScalarType::Float32;
|
||||
result.type.ccount = 4;
|
||||
result.id = m_vRegs.at(registerId);
|
||||
|
||||
if (operand.idxDim == 1) {
|
||||
// TODO add support for relative register index
|
||||
result.id = m_vRegs.at(operand.idx[0].offset);
|
||||
return result;
|
||||
} else {
|
||||
// TODO add support for relative register index
|
||||
const DxbcRegisterValue vertexId = emitIndexLoad(operand.idx[0]);
|
||||
|
||||
DxbcRegisterInfo info;
|
||||
info.type.ctype = result.type.ctype;
|
||||
info.type.ccount = result.type.ccount;
|
||||
info.type.alength = 0;
|
||||
info.sclass = spv::StorageClassInput;
|
||||
|
||||
result.id = m_module.opAccessChain(
|
||||
getPointerTypeId(info),
|
||||
m_vRegs.at(operand.idx[1].offset),
|
||||
1, &vertexId.id);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1415,8 +1591,9 @@ namespace dxvk {
|
||||
// (0) register index (immediate)
|
||||
// (1) constant offset (relative)
|
||||
DxbcRegisterInfo info;
|
||||
info.type.ctype = DxbcScalarType::Float32;
|
||||
info.type.ccount = 4;
|
||||
info.type.ctype = DxbcScalarType::Float32;
|
||||
info.type.ccount = 4;
|
||||
info.type.alength = 0;
|
||||
info.sclass = spv::StorageClassUniform;
|
||||
|
||||
const uint32_t regId = operand.idx[0].offset;
|
||||
@ -1429,7 +1606,8 @@ namespace dxvk {
|
||||
};
|
||||
|
||||
DxbcRegisterPointer result;
|
||||
result.type = info.type;
|
||||
result.type.ctype = info.type.ctype;
|
||||
result.type.ccount = info.type.ccount;
|
||||
result.id = m_module.opAccessChain(ptrTypeId,
|
||||
m_constantBuffers.at(regId).varId,
|
||||
indices.size(), indices.data());
|
||||
@ -1585,6 +1763,11 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitGsInputSetup() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitPsInputSetup() {
|
||||
|
||||
}
|
||||
@ -1595,21 +1778,61 @@ namespace dxvk {
|
||||
switch (svMapping.sv) {
|
||||
case DxbcSystemValue::Position: {
|
||||
DxbcRegisterInfo info;
|
||||
info.type.ctype = DxbcScalarType::Float32;
|
||||
info.type.ccount = 4;
|
||||
info.type.ctype = DxbcScalarType::Float32;
|
||||
info.type.ccount = 4;
|
||||
info.type.alength = 0;
|
||||
info.sclass = spv::StorageClassOutput;
|
||||
|
||||
const uint32_t ptrTypeId = getPointerTypeId(info);
|
||||
const uint32_t memberId = m_module.constu32(PerVertex_Position);
|
||||
|
||||
DxbcRegisterPointer dstPtr;
|
||||
dstPtr.type = info.type;
|
||||
dstPtr.id = m_module.opAccessChain(
|
||||
dstPtr.type.ctype = info.type.ctype;
|
||||
dstPtr.type.ccount = info.type.ccount;
|
||||
dstPtr.id = m_module.opAccessChain(
|
||||
ptrTypeId, m_perVertexOut, 1, &memberId);
|
||||
|
||||
DxbcRegisterPointer srcPtr;
|
||||
srcPtr.type = info.type;
|
||||
srcPtr.id = m_oRegs.at(svMapping.regId);
|
||||
srcPtr.type.ctype = info.type.ctype;
|
||||
srcPtr.type.ccount = info.type.ccount;
|
||||
srcPtr.id = m_oRegs.at(svMapping.regId);
|
||||
|
||||
emitValueStore(dstPtr, emitValueLoad(srcPtr),
|
||||
DxbcRegMask(true, true, true, true));
|
||||
} break;
|
||||
|
||||
default:
|
||||
Logger::warn(str::format(
|
||||
"DxbcCompiler: Unhandled vertex sv output: ",
|
||||
svMapping.sv));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitGsOutputSetup() {
|
||||
for (const DxbcSvMapping& svMapping : m_oMappings) {
|
||||
switch (svMapping.sv) {
|
||||
case DxbcSystemValue::Position: {
|
||||
DxbcRegisterInfo info;
|
||||
info.type.ctype = DxbcScalarType::Float32;
|
||||
info.type.ccount = 4;
|
||||
info.type.alength = 0;
|
||||
info.sclass = spv::StorageClassOutput;
|
||||
|
||||
const uint32_t ptrTypeId = getPointerTypeId(info);
|
||||
const uint32_t memberId = m_module.constu32(PerVertex_Position);
|
||||
|
||||
DxbcRegisterPointer dstPtr;
|
||||
dstPtr.type.ctype = info.type.ctype;
|
||||
dstPtr.type.ccount = info.type.ccount;
|
||||
dstPtr.id = m_module.opAccessChain(
|
||||
ptrTypeId, m_perVertexOut, 1, &memberId);
|
||||
|
||||
DxbcRegisterPointer srcPtr;
|
||||
srcPtr.type.ctype = info.type.ctype;
|
||||
srcPtr.type.ccount = info.type.ccount;
|
||||
srcPtr.id = m_oRegs.at(svMapping.regId);
|
||||
|
||||
emitValueStore(dstPtr, emitValueLoad(srcPtr),
|
||||
DxbcRegMask(true, true, true, true));
|
||||
@ -1659,9 +1882,41 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitGsInit() {
|
||||
m_module.enableCapability(spv::CapabilityGeometry);
|
||||
m_module.enableCapability(spv::CapabilityClipDistance);
|
||||
m_module.enableCapability(spv::CapabilityCullDistance);
|
||||
|
||||
// Declare the per-vertex output block. Outputs are not
|
||||
// declared as arrays, instead they will be flushed when
|
||||
// calling EmitVertex.
|
||||
const uint32_t perVertexStruct = this->getPerVertexBlockId();
|
||||
const uint32_t perVertexPointer = m_module.defPointerType(
|
||||
perVertexStruct, spv::StorageClassOutput);
|
||||
|
||||
m_perVertexOut = m_module.newVar(
|
||||
perVertexPointer, spv::StorageClassOutput);
|
||||
m_entryPointInterfaces.push_back(m_perVertexOut);
|
||||
m_module.setDebugName(m_perVertexOut, "gs_vertex_out");
|
||||
|
||||
// Main function of the vertex shader
|
||||
m_gs.functionId = m_module.allocateId();
|
||||
m_module.setDebugName(m_gs.functionId, "gs_main");
|
||||
|
||||
m_module.functionBegin(
|
||||
m_module.defVoidType(),
|
||||
m_gs.functionId,
|
||||
m_module.defFunctionType(
|
||||
m_module.defVoidType(), 0, nullptr),
|
||||
spv::FunctionControlMaskNone);
|
||||
m_module.opLabel(m_module.allocateId());
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitPsInit() {
|
||||
m_module.enableCapability(spv::CapabilityShader);
|
||||
m_module.setOriginUpperLeft(m_entryPointId);
|
||||
m_module.setExecutionMode(m_entryPointId,
|
||||
spv::ExecutionModeOriginUpperLeft);
|
||||
|
||||
// Declare pixel shader outputs. According to the Vulkan
|
||||
// documentation, they are required to match the type of
|
||||
@ -1669,8 +1924,9 @@ namespace dxvk {
|
||||
for (auto e = m_osgn->begin(); e != m_osgn->end(); e++) {
|
||||
if (e->systemValue == DxbcSystemValue::None) {
|
||||
DxbcRegisterInfo info;
|
||||
info.type.ctype = e->componentType;
|
||||
info.type.ccount = e->componentMask.setCount();
|
||||
info.type.ctype = e->componentType;
|
||||
info.type.ccount = e->componentMask.setCount();
|
||||
info.type.alength = 0;
|
||||
info.sclass = spv::StorageClassOutput;
|
||||
|
||||
const uint32_t varId = emitNewVariable(info);
|
||||
@ -1680,7 +1936,8 @@ namespace dxvk {
|
||||
m_entryPointInterfaces.push_back(varId);
|
||||
|
||||
m_oRegs.at(e->registerId) = varId;
|
||||
m_ps.oTypes.at(e->registerId) = info.type;
|
||||
m_ps.oTypes.at(e->registerId).ctype = info.type.ctype;
|
||||
m_ps.oTypes.at(e->registerId).ccount = info.type.ccount;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1707,6 +1964,16 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitGsFinalize() {
|
||||
this->emitGsInputSetup();
|
||||
m_module.opFunctionCall(
|
||||
m_module.defVoidType(),
|
||||
m_gs.functionId, 0, nullptr);
|
||||
// No output setup at this point as that was
|
||||
// already done during the EmitVertex step
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitPsFinalize() {
|
||||
this->emitPsInputSetup();
|
||||
m_module.opFunctionCall(
|
||||
@ -1758,9 +2025,25 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxbcCompiler::getArrayTypeId(const DxbcArrayType& type) {
|
||||
DxbcVectorType vtype;
|
||||
vtype.ctype = type.ctype;
|
||||
vtype.ccount = type.ccount;
|
||||
|
||||
uint32_t typeId = this->getVectorTypeId(vtype);
|
||||
|
||||
if (type.alength != 0) {
|
||||
typeId = m_module.defArrayType(typeId,
|
||||
m_module.constu32(type.alength));
|
||||
}
|
||||
|
||||
return typeId;
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxbcCompiler::getPointerTypeId(const DxbcRegisterInfo& type) {
|
||||
return m_module.defPointerType(
|
||||
this->getVectorTypeId(type.type),
|
||||
this->getArrayTypeId(type.type),
|
||||
type.sclass);
|
||||
}
|
||||
|
||||
|
@ -26,15 +26,30 @@ namespace dxvk {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Array type
|
||||
*
|
||||
* Convenience struct that stores a scalar type, a
|
||||
* component count and an array size. An array of
|
||||
* length 0 will be evaluated to a vector type. The
|
||||
* compiler can use this to generate SPIR-V types.
|
||||
*/
|
||||
struct DxbcArrayType {
|
||||
DxbcScalarType ctype;
|
||||
uint32_t ccount;
|
||||
uint32_t alength;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Register info
|
||||
*
|
||||
* Stores the vector type of a register and
|
||||
* Stores the array type of a register and
|
||||
* its storage class. The compiler can use
|
||||
* this to generate SPIR-V pointer types.
|
||||
*/
|
||||
struct DxbcRegisterInfo {
|
||||
DxbcVectorType type;
|
||||
DxbcArrayType type;
|
||||
spv::StorageClass sclass;
|
||||
};
|
||||
|
||||
@ -69,7 +84,18 @@ namespace dxvk {
|
||||
* \brief Vertex shader-specific structure
|
||||
*/
|
||||
struct DxbcCompilerVsPart {
|
||||
uint32_t functionId;
|
||||
uint32_t functionId = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Geometry shader-specific structure
|
||||
*/
|
||||
struct DxbcCompilerGsPart {
|
||||
DxbcPrimitive inputPrimitive = DxbcPrimitive::Undefined;
|
||||
DxbcPrimitiveTopology outputTopology = DxbcPrimitiveTopology::Undefined;
|
||||
uint32_t outputVertexCount = 0;
|
||||
uint32_t functionId = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -77,7 +103,8 @@ namespace dxvk {
|
||||
* \brief Pixel shader-specific structure
|
||||
*/
|
||||
struct DxbcCompilerPsPart {
|
||||
uint32_t functionId;
|
||||
uint32_t functionId = 0;
|
||||
|
||||
std::array<DxbcVectorType, DxbcMaxInterfaceRegs> oTypes;
|
||||
};
|
||||
|
||||
@ -205,6 +232,7 @@ namespace dxvk {
|
||||
///////////////////////////////////
|
||||
// Shader-specific data structures
|
||||
DxbcCompilerVsPart m_vs;
|
||||
DxbcCompilerGsPart m_gs;
|
||||
DxbcCompilerPsPart m_ps;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
@ -244,6 +272,15 @@ namespace dxvk {
|
||||
void emitDclResource(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
void emitDclGsInputPrimitive(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
void emitDclGsOutputTopology(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
void emitDclMaxOutputVertexCount(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
//////////////////////////////
|
||||
// Instruction class handlers
|
||||
void emitVectorAlu(
|
||||
@ -258,12 +295,18 @@ namespace dxvk {
|
||||
void emitVectorDot(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
void emitVectorIdiv(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
void emitVectorImul(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
void emitVectorSinCos(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
void emitGeometryEmit(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
void emitSample(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
@ -290,6 +333,9 @@ namespace dxvk {
|
||||
void emitControlFlowRet(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
void emitControlFlowDiscard(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
void emitControlFlow(
|
||||
const DxbcShaderInstruction& ins);
|
||||
|
||||
@ -376,21 +422,25 @@ namespace dxvk {
|
||||
/////////////////////////////
|
||||
// Input preparation methods
|
||||
void emitVsInputSetup();
|
||||
void emitGsInputSetup();
|
||||
void emitPsInputSetup();
|
||||
|
||||
//////////////////////////////
|
||||
// Output preparation methods
|
||||
void emitVsOutputSetup();
|
||||
void emitGsOutputSetup();
|
||||
void emitPsOutputSetup();
|
||||
|
||||
/////////////////////////////////
|
||||
// Shader initialization methods
|
||||
void emitVsInit();
|
||||
void emitGsInit();
|
||||
void emitPsInit();
|
||||
|
||||
///////////////////////////////
|
||||
// Shader finalization methods
|
||||
void emitVsFinalize();
|
||||
void emitGsFinalize();
|
||||
void emitPsFinalize();
|
||||
|
||||
///////////////////////////////
|
||||
@ -410,6 +460,9 @@ namespace dxvk {
|
||||
uint32_t getVectorTypeId(
|
||||
const DxbcVectorType& type);
|
||||
|
||||
uint32_t getArrayTypeId(
|
||||
const DxbcArrayType& type);
|
||||
|
||||
uint32_t getPointerTypeId(
|
||||
const DxbcRegisterInfo& type);
|
||||
|
||||
|
@ -80,11 +80,22 @@ namespace dxvk {
|
||||
m_instruction.modifiers.precise = !!bit::extract(token, 19, 22);
|
||||
|
||||
// Opcode controls. It will depend on the opcode itself which ones are valid.
|
||||
m_instruction.controls.zeroTest = static_cast<DxbcZeroTest> (bit::extract(token, 18, 18));
|
||||
m_instruction.controls.syncFlags = static_cast<DxbcSyncFlags> (bit::extract(token, 11, 14));
|
||||
m_instruction.controls.resourceDim = static_cast<DxbcResourceDim> (bit::extract(token, 11, 15));
|
||||
m_instruction.controls.resinfoType = static_cast<DxbcResinfoType> (bit::extract(token, 11, 12));
|
||||
m_instruction.controls.interpolation = static_cast<DxbcInterpolationMode>(bit::extract(token, 11, 14));
|
||||
m_instruction.controls.zeroTest =
|
||||
static_cast<DxbcZeroTest>(bit::extract(token, 18, 18));
|
||||
m_instruction.controls.syncFlags =
|
||||
static_cast<DxbcSyncFlags>(bit::extract(token, 11, 14));
|
||||
m_instruction.controls.resourceDim =
|
||||
static_cast<DxbcResourceDim>(bit::extract(token, 11, 15));
|
||||
m_instruction.controls.resinfoType =
|
||||
static_cast<DxbcResinfoType>(bit::extract(token, 11, 12));
|
||||
m_instruction.controls.interpolation =
|
||||
static_cast<DxbcInterpolationMode>(bit::extract(token, 11, 14));
|
||||
m_instruction.controls.samplerMode =
|
||||
static_cast<DxbcSamplerMode>(bit::extract(token, 11, 14));
|
||||
m_instruction.controls.primitiveTopology =
|
||||
static_cast<DxbcPrimitiveTopology>(bit::extract(token, 11, 17));
|
||||
m_instruction.controls.primitive =
|
||||
static_cast<DxbcPrimitive>(bit::extract(token, 11, 16));
|
||||
|
||||
// Process extended opcode tokens
|
||||
while (bit::extract(token, 31, 31)) {
|
||||
|
@ -75,15 +75,18 @@ namespace dxvk {
|
||||
|
||||
DxbcRegSwizzle() { }
|
||||
DxbcRegSwizzle(uint32_t x, uint32_t y, uint32_t z, uint32_t w)
|
||||
: m_data((x << 0) | (y << 2) | (z << 4) | (w << 6)) { }
|
||||
: m_mask((x << 0) | (y << 2) | (z << 4) | (w << 6)) { }
|
||||
|
||||
uint32_t operator [] (uint32_t id) const {
|
||||
return (m_data >> (id + id)) & 0x3;
|
||||
return (m_mask >> (id + id)) & 0x3;
|
||||
}
|
||||
|
||||
bool operator == (const DxbcRegSwizzle& other) const { return m_mask == other.m_mask; }
|
||||
bool operator != (const DxbcRegSwizzle& other) const { return m_mask != other.m_mask; }
|
||||
|
||||
private:
|
||||
|
||||
uint8_t m_data = 0;
|
||||
uint8_t m_mask = 0;
|
||||
|
||||
};
|
||||
|
||||
@ -99,30 +102,33 @@ namespace dxvk {
|
||||
public:
|
||||
|
||||
DxbcRegMask() { }
|
||||
DxbcRegMask(uint32_t mask) : m_data(mask) { }
|
||||
DxbcRegMask(uint32_t mask) : m_mask(mask) { }
|
||||
DxbcRegMask(bool x, bool y, bool z, bool w)
|
||||
: m_data((x ? 0x1 : 0) | (y ? 0x2 : 0)
|
||||
: m_mask((x ? 0x1 : 0) | (y ? 0x2 : 0)
|
||||
| (z ? 0x4 : 0) | (w ? 0x8 : 0)) { }
|
||||
|
||||
bool operator [] (uint32_t id) const {
|
||||
return (m_data >> id) & 1;
|
||||
return (m_mask >> id) & 1;
|
||||
}
|
||||
|
||||
uint32_t setCount() const {
|
||||
const uint8_t n[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
|
||||
1, 2, 2, 3, 2, 3, 3, 4 };
|
||||
return n[m_data & 0xF];
|
||||
return n[m_mask & 0xF];
|
||||
}
|
||||
|
||||
uint32_t firstSet() const {
|
||||
const uint8_t n[16] = { 4, 0, 1, 0, 2, 0, 1, 0,
|
||||
3, 0, 1, 0, 2, 0, 1, 0 };
|
||||
return n[m_data & 0xF];
|
||||
return n[m_mask & 0xF];
|
||||
}
|
||||
|
||||
bool operator == (const DxbcRegMask& other) const { return m_mask == other.m_mask; }
|
||||
bool operator != (const DxbcRegMask& other) const { return m_mask != other.m_mask; }
|
||||
|
||||
private:
|
||||
|
||||
uint8_t m_data = 0;
|
||||
uint8_t m_mask = 0;
|
||||
|
||||
};
|
||||
|
||||
@ -194,6 +200,9 @@ namespace dxvk {
|
||||
DxbcResourceDim resourceDim;
|
||||
DxbcResinfoType resinfoType;
|
||||
DxbcInterpolationMode interpolation;
|
||||
DxbcSamplerMode samplerMode;
|
||||
DxbcPrimitiveTopology primitiveTopology;
|
||||
DxbcPrimitive primitive;
|
||||
};
|
||||
|
||||
|
||||
|
@ -34,7 +34,7 @@ namespace dxvk {
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
|
||||
} },
|
||||
/* Cut */
|
||||
{ },
|
||||
{ 0, DxbcInstClass::GeometryEmit },
|
||||
/* Default */
|
||||
{ },
|
||||
/* DerivRtx */
|
||||
@ -42,7 +42,9 @@ namespace dxvk {
|
||||
/* DerivRty */
|
||||
{ },
|
||||
/* Discard */
|
||||
{ },
|
||||
{ 1, DxbcInstClass::ControlFlow, {
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* Div */
|
||||
{ 3, DxbcInstClass::VectorAlu, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
@ -70,7 +72,7 @@ namespace dxvk {
|
||||
/* Else */
|
||||
{ 0, DxbcInstClass::ControlFlow },
|
||||
/* Emit */
|
||||
{ },
|
||||
{ 0, DxbcInstClass::GeometryEmit },
|
||||
/* EmitThenCut */
|
||||
{ },
|
||||
/* EndIf */
|
||||
@ -295,13 +297,23 @@ namespace dxvk {
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* UDiv */
|
||||
{ },
|
||||
{ 4, DxbcInstClass::VectorIdiv, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
|
||||
} },
|
||||
/* ULt */
|
||||
{ },
|
||||
/* UGe */
|
||||
{ },
|
||||
/* UMul */
|
||||
{ },
|
||||
{ 4, DxbcInstClass::VectorImul, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* UMad */
|
||||
{ },
|
||||
/* UMax */
|
||||
@ -330,11 +342,13 @@ namespace dxvk {
|
||||
/* DclIndexRange */
|
||||
{ },
|
||||
/* DclGsOutputPrimitiveTopology */
|
||||
{ },
|
||||
{ 0, DxbcInstClass::Declaration },
|
||||
/* DclGsInputPrimitive */
|
||||
{ },
|
||||
{ 0, DxbcInstClass::Declaration },
|
||||
/* DclMaxOutputVertexCount */
|
||||
{ },
|
||||
{ 1, DxbcInstClass::Declaration, {
|
||||
{ DxbcOperandKind::Imm32, DxbcScalarType::Uint32 },
|
||||
} },
|
||||
/* DclInput */
|
||||
{ 1, DxbcInstClass::Declaration, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
|
@ -30,11 +30,13 @@ namespace dxvk {
|
||||
enum class DxbcInstClass {
|
||||
Declaration, ///< Interface or resource declaration
|
||||
ControlFlow, ///< Control flow instructions
|
||||
GeometryEmit, ///< Special geometry shader instructions
|
||||
TextureSample, ///< Texture sampling instruction
|
||||
VectorAlu, ///< Component-wise vector instructions
|
||||
VectorCmov, ///< Component-wise conditional move
|
||||
VectorCmp, ///< Component-wise vector comparison
|
||||
VectorDot, ///< Dot product instruction
|
||||
VectorIdiv, ///< Component-wise integer division
|
||||
VectorImul, ///< Component-wise integer multiplication
|
||||
VectorSinCos, ///< Sine and Cosine instruction
|
||||
Undefined, ///< Instruction code not defined
|
||||
|
@ -456,6 +456,79 @@ namespace dxvk {
|
||||
|
||||
using DxbcSyncFlags = Flags<DxbcSyncFlag>;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Geometry shader input primitive
|
||||
*/
|
||||
enum class DxbcPrimitive : uint32_t {
|
||||
Undefined = 0,
|
||||
Point = 1,
|
||||
Line = 2,
|
||||
Triangle = 3,
|
||||
LineAdj = 6,
|
||||
TriangleAdj = 7,
|
||||
Patch1 = 8,
|
||||
Patch2 = 9,
|
||||
Patch3 = 10,
|
||||
Patch4 = 11,
|
||||
Patch5 = 12,
|
||||
Patch6 = 13,
|
||||
Patch7 = 14,
|
||||
Patch8 = 15,
|
||||
Patch9 = 16,
|
||||
Patch10 = 17,
|
||||
Patch11 = 18,
|
||||
Patch12 = 19,
|
||||
Patch13 = 20,
|
||||
Patch14 = 21,
|
||||
Patch15 = 22,
|
||||
Patch16 = 23,
|
||||
Patch17 = 24,
|
||||
Patch18 = 25,
|
||||
Patch19 = 26,
|
||||
Patch20 = 27,
|
||||
Patch21 = 28,
|
||||
Patch22 = 29,
|
||||
Patch23 = 30,
|
||||
Patch24 = 31,
|
||||
Patch25 = 32,
|
||||
Patch26 = 33,
|
||||
Patch27 = 34,
|
||||
Patch28 = 35,
|
||||
Patch29 = 36,
|
||||
Patch30 = 37,
|
||||
Patch31 = 38,
|
||||
Patch32 = 39,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Geometry shader output topology
|
||||
*/
|
||||
enum class DxbcPrimitiveTopology : uint32_t {
|
||||
Undefined = 0,
|
||||
PointList = 1,
|
||||
LineList = 2,
|
||||
LineStrip = 3,
|
||||
TriangleList = 4,
|
||||
TriangleStrip = 5,
|
||||
LineListAdj = 10,
|
||||
LineStripAdj = 11,
|
||||
TriangleListAdj = 12,
|
||||
TriangleStripAdj = 13,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Sampler operation mode
|
||||
*/
|
||||
enum class DxbcSamplerMode : uint32_t {
|
||||
Default = 0,
|
||||
Comparison = 1,
|
||||
Mono = 2,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Scalar value type
|
||||
*
|
||||
|
@ -41,4 +41,25 @@ namespace dxvk {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t primitiveVertexCount(DxbcPrimitive primitive) {
|
||||
static const std::array<uint32_t, 8> s_vertexCounts = {
|
||||
0, // Undefined
|
||||
1, // Point
|
||||
2, // Line
|
||||
3, // Triangle
|
||||
0, // Undefined
|
||||
0, // Undefined
|
||||
4, // Line with adjacency
|
||||
6, // Triangle with adjacency
|
||||
};
|
||||
|
||||
if (primitive >= DxbcPrimitive::Patch1) {
|
||||
return static_cast<uint32_t>(primitive)
|
||||
- static_cast<uint32_t>(DxbcPrimitive::Patch1);
|
||||
} else {
|
||||
return s_vertexCounts.at(
|
||||
static_cast<uint32_t>(primitive));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxbc_common.h"
|
||||
#include "dxbc_enums.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
@ -32,4 +33,13 @@ namespace dxvk {
|
||||
DxbcBindingType bindingType,
|
||||
uint32_t bindingIndex);
|
||||
|
||||
/**
|
||||
* \brief Primitive vertex count
|
||||
*
|
||||
* Calculates the number of vertices
|
||||
* for a given primitive type.
|
||||
*/
|
||||
uint32_t primitiveVertexCount(
|
||||
DxbcPrimitive primitive);
|
||||
|
||||
}
|
@ -72,12 +72,13 @@ namespace dxvk {
|
||||
m_memoryModel.putWord (memoryModel);
|
||||
}
|
||||
|
||||
|
||||
void SpirvModule::enableEarlyFragmentTests(
|
||||
uint32_t entryPointId) {
|
||||
|
||||
void SpirvModule::setExecutionMode(
|
||||
uint32_t entryPointId,
|
||||
spv::ExecutionMode executionMode) {
|
||||
m_execModeInfo.putIns (spv::OpExecutionMode, 3);
|
||||
m_execModeInfo.putWord(entryPointId);
|
||||
m_execModeInfo.putWord(spv::ExecutionModeEarlyFragmentTests);
|
||||
m_execModeInfo.putWord(executionMode);
|
||||
}
|
||||
|
||||
|
||||
@ -95,11 +96,13 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void SpirvModule::setOriginUpperLeft(
|
||||
uint32_t entryPointId) {
|
||||
m_execModeInfo.putIns (spv::OpExecutionMode, 3);
|
||||
void SpirvModule::setOutputVertices(
|
||||
uint32_t entryPointId,
|
||||
uint32_t vertexCount) {
|
||||
m_execModeInfo.putIns (spv::OpExecutionMode, 4);
|
||||
m_execModeInfo.putWord(entryPointId);
|
||||
m_execModeInfo.putWord(spv::ExecutionModeOriginUpperLeft);
|
||||
m_execModeInfo.putWord(spv::ExecutionModeOutputVertices);
|
||||
m_execModeInfo.putWord(vertexCount);
|
||||
}
|
||||
|
||||
|
||||
@ -738,6 +741,66 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvModule::opSDiv(
|
||||
uint32_t resultType,
|
||||
uint32_t a,
|
||||
uint32_t b) {
|
||||
uint32_t resultId = this->allocateId();
|
||||
|
||||
m_code.putIns (spv::OpSDiv, 5);
|
||||
m_code.putWord(resultType);
|
||||
m_code.putWord(resultId);
|
||||
m_code.putWord(a);
|
||||
m_code.putWord(b);
|
||||
return resultId;
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvModule::opUDiv(
|
||||
uint32_t resultType,
|
||||
uint32_t a,
|
||||
uint32_t b) {
|
||||
uint32_t resultId = this->allocateId();
|
||||
|
||||
m_code.putIns (spv::OpUDiv, 5);
|
||||
m_code.putWord(resultType);
|
||||
m_code.putWord(resultId);
|
||||
m_code.putWord(a);
|
||||
m_code.putWord(b);
|
||||
return resultId;
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvModule::opSRem(
|
||||
uint32_t resultType,
|
||||
uint32_t a,
|
||||
uint32_t b) {
|
||||
uint32_t resultId = this->allocateId();
|
||||
|
||||
m_code.putIns (spv::OpSRem, 5);
|
||||
m_code.putWord(resultType);
|
||||
m_code.putWord(resultId);
|
||||
m_code.putWord(a);
|
||||
m_code.putWord(b);
|
||||
return resultId;
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvModule::opUMod(
|
||||
uint32_t resultType,
|
||||
uint32_t a,
|
||||
uint32_t b) {
|
||||
uint32_t resultId = this->allocateId();
|
||||
|
||||
m_code.putIns (spv::OpUMod, 5);
|
||||
m_code.putWord(resultType);
|
||||
m_code.putWord(resultId);
|
||||
m_code.putWord(a);
|
||||
m_code.putWord(b);
|
||||
return resultId;
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvModule::opFDiv(
|
||||
uint32_t resultType,
|
||||
uint32_t a,
|
||||
@ -1310,6 +1373,21 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void SpirvModule::opKill() {
|
||||
m_code.putIns (spv::OpKill, 1);
|
||||
}
|
||||
|
||||
|
||||
void SpirvModule::opEmitVertex() {
|
||||
m_code.putIns (spv::OpEmitVertex, 1);
|
||||
}
|
||||
|
||||
|
||||
void SpirvModule::opEndPrimitive() {
|
||||
m_code.putIns (spv::OpEndPrimitive, 1);
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvModule::defType(
|
||||
spv::Op op,
|
||||
uint32_t argCount,
|
||||
|
@ -37,8 +37,9 @@ namespace dxvk {
|
||||
spv::AddressingModel addressModel,
|
||||
spv::MemoryModel memoryModel);
|
||||
|
||||
void enableEarlyFragmentTests(
|
||||
uint32_t entryPointId);
|
||||
void setExecutionMode(
|
||||
uint32_t entryPointId,
|
||||
spv::ExecutionMode executionMode);
|
||||
|
||||
void setLocalSize(
|
||||
uint32_t entryPointId,
|
||||
@ -46,8 +47,9 @@ namespace dxvk {
|
||||
uint32_t y,
|
||||
uint32_t z);
|
||||
|
||||
void setOriginUpperLeft(
|
||||
uint32_t entryPointId);
|
||||
void setOutputVertices(
|
||||
uint32_t entryPointId,
|
||||
uint32_t vertexCount);
|
||||
|
||||
void setDebugName(
|
||||
uint32_t expressionId,
|
||||
@ -265,6 +267,26 @@ namespace dxvk {
|
||||
uint32_t a,
|
||||
uint32_t b);
|
||||
|
||||
uint32_t opSDiv(
|
||||
uint32_t resultType,
|
||||
uint32_t a,
|
||||
uint32_t b);
|
||||
|
||||
uint32_t opUDiv(
|
||||
uint32_t resultType,
|
||||
uint32_t a,
|
||||
uint32_t b);
|
||||
|
||||
uint32_t opSRem(
|
||||
uint32_t resultType,
|
||||
uint32_t a,
|
||||
uint32_t b);
|
||||
|
||||
uint32_t opUMod(
|
||||
uint32_t resultType,
|
||||
uint32_t a,
|
||||
uint32_t b);
|
||||
|
||||
uint32_t opFDiv(
|
||||
uint32_t resultType,
|
||||
uint32_t a,
|
||||
@ -453,6 +475,12 @@ namespace dxvk {
|
||||
|
||||
void opReturn();
|
||||
|
||||
void opKill();
|
||||
|
||||
void opEmitVertex();
|
||||
|
||||
void opEndPrimitive();
|
||||
|
||||
private:
|
||||
|
||||
uint32_t m_id = 1;
|
||||
|
Loading…
Reference in New Issue
Block a user