2017-10-16 17:50:09 +02:00
|
|
|
#include "dxbc_compiler.h"
|
|
|
|
|
|
|
|
namespace dxvk {
|
|
|
|
|
2017-11-01 00:01:40 +01:00
|
|
|
DxbcCompiler::DxbcCompiler(
|
|
|
|
DxbcProgramVersion version,
|
|
|
|
const Rc<DxbcIsgn>& inputSig,
|
|
|
|
const Rc<DxbcIsgn>& outputSig)
|
|
|
|
: m_version (version),
|
|
|
|
m_inputSig (inputSig),
|
|
|
|
m_outputSig (outputSig) {
|
2017-10-26 15:40:39 +02:00
|
|
|
m_entryPointId = m_module.allocateId();
|
2017-10-21 17:58:58 +02:00
|
|
|
|
2017-10-18 09:50:30 +02:00
|
|
|
this->declareCapabilities();
|
|
|
|
this->declareMemoryModel();
|
2017-10-26 16:32:10 +02:00
|
|
|
|
|
|
|
m_typeVoid = m_module.defVoidType();
|
|
|
|
m_typeFunction = m_module.defFunctionType(m_typeVoid, 0, nullptr);
|
|
|
|
|
|
|
|
m_module.functionBegin(m_typeVoid,
|
|
|
|
m_entryPointId, m_typeFunction,
|
|
|
|
spv::FunctionControlMaskNone);
|
2017-11-01 00:01:40 +01:00
|
|
|
|
|
|
|
// TODO implement proper control flow
|
|
|
|
m_module.opLabel(m_module.allocateId());
|
2017-10-16 17:50:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DxbcCompiler::~DxbcCompiler() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-01 00:01:40 +01:00
|
|
|
void DxbcCompiler::processInstruction(const DxbcInstruction& ins) {
|
2017-10-25 13:49:13 +02:00
|
|
|
const DxbcOpcodeToken token = ins.token();
|
2017-10-22 23:13:29 +02:00
|
|
|
|
2017-10-25 13:49:13 +02:00
|
|
|
switch (token.opcode()) {
|
2017-10-29 02:35:16 +02:00
|
|
|
case DxbcOpcode::DclGlobalFlags:
|
2017-11-01 00:01:40 +01:00
|
|
|
return this->dclGlobalFlags(ins);
|
|
|
|
|
2017-10-29 02:35:16 +02:00
|
|
|
case DxbcOpcode::DclInput:
|
|
|
|
return this->dclInput(ins);
|
|
|
|
|
2017-11-01 00:01:40 +01:00
|
|
|
case DxbcOpcode::DclOutputSiv:
|
|
|
|
return this->dclOutputSiv(ins);
|
|
|
|
|
2017-10-29 02:35:16 +02:00
|
|
|
case DxbcOpcode::DclTemps:
|
2017-11-01 00:01:40 +01:00
|
|
|
return this->dclTemps(ins);
|
2017-10-26 16:32:10 +02:00
|
|
|
|
2017-11-01 00:01:40 +01:00
|
|
|
case DxbcOpcode::DclThreadGroup:
|
|
|
|
return this->dclThreadGroup(ins);
|
|
|
|
|
|
|
|
case DxbcOpcode::Mov:
|
|
|
|
return this->opMov(ins);
|
|
|
|
|
|
|
|
case DxbcOpcode::Ret:
|
|
|
|
return this->opRet(ins);
|
2017-10-25 13:49:13 +02:00
|
|
|
|
|
|
|
default:
|
2017-11-01 00:01:40 +01:00
|
|
|
throw DxvkError(str::format("DXBC: Unhandled instruction: ", ins.token().opcode()));
|
2017-10-25 13:49:13 +02:00
|
|
|
}
|
2017-10-16 17:50:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Rc<DxvkShader> DxbcCompiler::finalize() {
|
2017-10-26 16:32:10 +02:00
|
|
|
m_module.functionEnd();
|
|
|
|
|
2017-10-29 02:35:16 +02:00
|
|
|
m_module.addEntryPoint(m_entryPointId,
|
|
|
|
m_version.executionModel(), "main",
|
|
|
|
m_interfaces.size(),
|
|
|
|
m_interfaces.data());
|
|
|
|
|
2017-10-17 13:02:57 +02:00
|
|
|
return new DxvkShader(m_version.shaderStage(),
|
2017-10-26 15:40:39 +02:00
|
|
|
m_module.compile(), 0, nullptr);
|
2017-10-16 19:53:17 +02:00
|
|
|
}
|
|
|
|
|
2017-10-18 09:50:30 +02:00
|
|
|
|
|
|
|
void DxbcCompiler::declareCapabilities() {
|
2017-10-26 15:40:39 +02:00
|
|
|
m_module.enableCapability(spv::CapabilityShader);
|
2017-10-18 09:50:30 +02:00
|
|
|
|
|
|
|
switch (m_version.type()) {
|
|
|
|
case DxbcProgramType::GeometryShader:
|
2017-10-26 15:40:39 +02:00
|
|
|
m_module.enableCapability(spv::CapabilityGeometry);
|
2017-10-18 09:50:30 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DxbcProgramType::HullShader:
|
|
|
|
case DxbcProgramType::DomainShader:
|
2017-10-26 15:40:39 +02:00
|
|
|
m_module.enableCapability(spv::CapabilityTessellation);
|
2017-10-18 09:50:30 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxbcCompiler::declareMemoryModel() {
|
2017-10-26 15:40:39 +02:00
|
|
|
m_module.setMemoryModel(
|
2017-10-18 09:50:30 +02:00
|
|
|
spv::AddressingModelLogical,
|
|
|
|
spv::MemoryModelGLSL450);
|
|
|
|
}
|
|
|
|
|
2017-10-29 02:35:16 +02:00
|
|
|
|
2017-11-01 00:01:40 +01:00
|
|
|
void DxbcCompiler::dclGlobalFlags(const DxbcInstruction& ins) {
|
|
|
|
const DxbcGlobalFlags flags(ins.token().control());
|
|
|
|
|
2017-10-29 02:35:16 +02:00
|
|
|
if (!flags.test(DxbcGlobalFlag::RefactoringAllowed))
|
|
|
|
m_useRestrictedMath = true;
|
|
|
|
|
|
|
|
if (flags.test(DxbcGlobalFlag::DoublePrecision))
|
|
|
|
m_module.enableCapability(spv::CapabilityFloat64);
|
|
|
|
|
|
|
|
if (flags.test(DxbcGlobalFlag::EarlyFragmentTests))
|
|
|
|
m_module.enableEarlyFragmentTests(m_entryPointId);
|
|
|
|
|
|
|
|
// Raw and structured buffers are supported regardless
|
|
|
|
// of whether the corresponding flag is set or not.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-01 00:01:40 +01:00
|
|
|
void DxbcCompiler::dclInput(const DxbcInstruction& ins) {
|
|
|
|
const DxbcOperand operand = ins.operand(0);
|
|
|
|
const DxbcOperandToken token = operand.token();
|
2017-10-29 02:35:16 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-01 00:01:40 +01:00
|
|
|
void DxbcCompiler::dclOutputSiv(const DxbcInstruction& ins) {
|
|
|
|
Logger::err("DXBC: dclOutputSiv: Not implemented yet");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxbcCompiler::dclTemps(const DxbcInstruction& ins) {
|
2017-10-26 16:32:10 +02:00
|
|
|
// Temporaries are treated as untyped 4x32-bit vectors.
|
2017-11-01 00:01:40 +01:00
|
|
|
const DxbcValueType regType(DxbcScalarType::Uint32, 4);
|
|
|
|
const DxbcPointerType ptrType(regType, spv::StorageClassPrivate);
|
|
|
|
const uint32_t ptrTypeId = this->getPointerTypeId(ptrType);
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < ins.arg(0); i++) {
|
|
|
|
DxbcPointer reg;
|
|
|
|
reg.type = ptrType;
|
|
|
|
reg.typeId = ptrTypeId;
|
|
|
|
reg.valueId = m_module.newVar(ptrTypeId, spv::StorageClassPrivate);
|
2017-10-26 16:32:10 +02:00
|
|
|
m_rRegs.push_back(reg);
|
|
|
|
|
2017-11-01 00:01:40 +01:00
|
|
|
m_module.setDebugName(reg.valueId,
|
2017-10-26 16:32:10 +02:00
|
|
|
str::format("r", i).c_str());
|
|
|
|
}
|
2017-11-01 00:01:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxbcCompiler::dclThreadGroup(const DxbcInstruction& ins) {
|
|
|
|
m_module.setLocalSize(m_entryPointId,
|
|
|
|
ins.arg(0), ins.arg(1), ins.arg(2));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxbcCompiler::opMov(const DxbcInstruction& ins) {
|
|
|
|
const DxbcOperand dstOp = ins.operand(0);
|
|
|
|
const DxbcOperand srcOp = ins.operand(dstOp.length());
|
|
|
|
|
|
|
|
DxbcValueType dstType(DxbcScalarType::Uint32, 1);
|
|
|
|
this->loadOperand(srcOp, dstType);
|
|
|
|
|
|
|
|
Logger::err("DXBC: mov: Not implemented yet");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxbcCompiler::opRet(const DxbcInstruction& ins) {
|
|
|
|
// TODO implement proper control flow
|
|
|
|
m_module.opReturn();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t DxbcCompiler::getScalarTypeId(const DxbcScalarType& type) {
|
|
|
|
switch (type) {
|
|
|
|
case DxbcScalarType::Uint32 : return m_module.defIntType(32, 0);
|
|
|
|
case DxbcScalarType::Uint64 : return m_module.defIntType(64, 0);
|
|
|
|
case DxbcScalarType::Sint32 : return m_module.defIntType(32, 1);
|
|
|
|
case DxbcScalarType::Sint64 : return m_module.defIntType(64, 1);
|
|
|
|
case DxbcScalarType::Float32: return m_module.defFloatType(32);
|
|
|
|
case DxbcScalarType::Float64: return m_module.defFloatType(64);
|
|
|
|
}
|
|
|
|
|
|
|
|
throw DxvkError("DXBC: Invalid scalar type");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t DxbcCompiler::getValueTypeId(const DxbcValueType& type) {
|
|
|
|
const uint32_t scalarTypeId = this->getScalarTypeId(type.componentType);
|
|
|
|
|
|
|
|
return type.componentCount > 1
|
|
|
|
? m_module.defVectorType(scalarTypeId, type.componentCount)
|
|
|
|
: scalarTypeId;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t DxbcCompiler::getPointerTypeId(const DxbcPointerType& type) {
|
|
|
|
return m_module.defPointerType(
|
|
|
|
this->getValueTypeId(type.valueType),
|
|
|
|
type.storageClass);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DxbcValue DxbcCompiler::loadPointer(const DxbcPointer& pointer) {
|
|
|
|
DxbcValue result;
|
|
|
|
result.type = pointer.type.valueType;
|
|
|
|
result.typeId = this->getValueTypeId(result.type);
|
|
|
|
result.valueId = m_module.opLoad(result.typeId, pointer.valueId);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DxbcValue DxbcCompiler::loadOperand(
|
|
|
|
const DxbcOperand& operand,
|
|
|
|
const DxbcValueType& type) {
|
|
|
|
const DxbcOperandToken token = operand.token();
|
|
|
|
|
|
|
|
DxbcValue result;
|
|
|
|
|
|
|
|
switch (token.type()) {
|
|
|
|
|
|
|
|
case DxbcOperandType::Imm32: {
|
|
|
|
const uint32_t componentCount = token.numComponents();
|
|
|
|
|
|
|
|
result.type = DxbcValueType(DxbcScalarType::Uint32, componentCount);
|
|
|
|
result.typeId = this->getValueTypeId(result.type);
|
|
|
|
|
|
|
|
if (componentCount == 1) {
|
|
|
|
result.valueId = m_module.constu32(operand.imm32(0));
|
|
|
|
} else {
|
|
|
|
std::array<uint32_t, 4> constIds;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < componentCount; i++)
|
|
|
|
constIds.at(i) = m_module.constu32(operand.imm32(i));
|
|
|
|
|
|
|
|
result.valueId = m_module.constComposite(
|
|
|
|
result.typeId, componentCount, constIds.data());
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case DxbcOperandType::Temp: {
|
|
|
|
const DxbcOperandIndex index = operand.index(0);
|
|
|
|
result = this->loadPointer(m_rRegs.at(index.immPart()));
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
throw DxvkError(str::format(
|
|
|
|
"DxbcCompiler::loadOperandRegister: Unhandled operand type: ",
|
|
|
|
token.type()));
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxbcCompiler::storePointer(
|
|
|
|
const DxbcPointer& pointer,
|
|
|
|
const DxbcValue& value) {
|
|
|
|
m_module.opStore(pointer.valueId, value.valueId);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxbcCompiler::storeOperand(
|
|
|
|
const DxbcOperand& operand,
|
|
|
|
const DxbcValueType& srcType,
|
|
|
|
uint32_t srcValue) {
|
2017-10-29 02:35:16 +02:00
|
|
|
|
2017-10-26 16:32:10 +02:00
|
|
|
}
|
|
|
|
|
2017-10-16 17:50:09 +02:00
|
|
|
}
|