[dxbc] Added immediate constant buffer support

This commit is contained in:
Philip Rebohle 2017-12-19 17:41:23 +01:00
parent 2c5b1c151f
commit 95bc4b5826
11 changed files with 199 additions and 3 deletions

View File

@ -52,6 +52,9 @@ namespace dxvk {
switch (ins.opClass) {
case DxbcInstClass::Declaration:
return this->emitDcl(ins);
case DxbcInstClass::CustomData:
return this->emitCustomData(ins);
case DxbcInstClass::ControlFlow:
return this->emitControlFlow(ins);
@ -620,6 +623,70 @@ namespace dxvk {
}
void DxbcCompiler::emitDclImmediateConstantBuffer(const DxbcShaderInstruction& ins) {
if (m_immConstBuf != 0)
throw DxvkError("DxbcCompiler: Immediate constant buffer already declared");
if ((ins.customDataSize & 0x3) != 0)
throw DxvkError("DxbcCompiler: Immediate constant buffer size not a multiple of four DWORDs");
// Declare individual vector constants as 4x32-bit vectors
std::array<uint32_t, 4096> vectorIds;
DxbcVectorType vecType;
vecType.ctype = DxbcScalarType::Uint32;
vecType.ccount = 4;
const uint32_t vectorTypeId = getVectorTypeId(vecType);
const uint32_t vectorCount = ins.customDataSize / 4;
for (uint32_t i = 0; i < vectorCount; i++) {
std::array<uint32_t, 4> scalarIds = {
m_module.constu32(ins.customData[4 * i + 0]),
m_module.constu32(ins.customData[4 * i + 1]),
m_module.constu32(ins.customData[4 * i + 2]),
m_module.constu32(ins.customData[4 * i + 3]),
};
vectorIds.at(i) = m_module.constComposite(
vectorTypeId, scalarIds.size(), scalarIds.data());
}
// Declare the array that contains all the vectors
DxbcArrayType arrInfo;
arrInfo.ctype = DxbcScalarType::Uint32;
arrInfo.ccount = 4;
arrInfo.alength = vectorCount;
const uint32_t arrayTypeId = getArrayTypeId(arrInfo);
const uint32_t arrayId = m_module.constComposite(
arrayTypeId, vectorCount, vectorIds.data());
// Declare the variable that will hold the constant
// data and initialize it with the constant array.
const uint32_t pointerTypeId = m_module.defPointerType(
arrayTypeId, spv::StorageClassPrivate);
m_immConstBuf = m_module.newVarInit(
pointerTypeId, spv::StorageClassPrivate,
arrayId);
m_module.setDebugName(m_immConstBuf, "icb");
}
void DxbcCompiler::emitCustomData(const DxbcShaderInstruction& ins) {
switch (ins.customDataType) {
case DxbcCustomDataClass::ImmConstBuf:
return emitDclImmediateConstantBuffer(ins);
default:
Logger::warn(str::format(
"DxbcCompiler: Unsupported custom data block: ",
ins.customDataType));
}
}
void DxbcCompiler::emitVectorAlu(const DxbcShaderInstruction& ins) {
std::array<DxbcRegisterValue, DxbcMaxOperandCount> src;
@ -1654,6 +1721,30 @@ namespace dxvk {
}
DxbcRegisterPointer DxbcCompiler::emitGetImmConstBufPtr(
const DxbcRegister& operand) {
if (m_immConstBuf == 0)
throw DxvkError("DxbcCompiler: Immediate constant buffer not defined");
const DxbcRegisterValue constId
= emitIndexLoad(operand.idx[0]);
DxbcRegisterInfo ptrInfo;
ptrInfo.type.ctype = DxbcScalarType::Uint32;
ptrInfo.type.ccount = 4;
ptrInfo.type.alength = 0;
ptrInfo.sclass = spv::StorageClassPrivate;
DxbcRegisterPointer result;
result.type.ctype = ptrInfo.type.ctype;
result.type.ccount = ptrInfo.type.ccount;
result.id = m_module.opAccessChain(
getPointerTypeId(ptrInfo),
m_immConstBuf, 1, &constId.id);
return result;
}
DxbcRegisterPointer DxbcCompiler::emitGetOperandPtr(
const DxbcRegister& operand) {
switch (operand.type) {
@ -1669,6 +1760,9 @@ namespace dxvk {
case DxbcOperandType::ConstantBuffer:
return emitGetConstBufPtr(operand);
case DxbcOperandType::ImmediateConstantBuffer:
return emitGetImmConstBufPtr(operand);
default:
throw DxvkError(str::format(
"DxbcCompiler: Unhandled operand type: ",

View File

@ -223,6 +223,11 @@ namespace dxvk {
uint32_t m_perVertexIn = 0;
uint32_t m_perVertexOut = 0;
//////////////////////////////////////////////////
// Immediate constant buffer. If defined, this is
// an array of four-component uint32 vectors.
uint32_t m_immConstBuf = 0;
///////////////////////////////////////////////////
// Entry point description - we'll need to declare
// the function ID and all input/output variables.
@ -281,6 +286,14 @@ namespace dxvk {
void emitDclMaxOutputVertexCount(
const DxbcShaderInstruction& ins);
////////////////////////
// Custom data handlers
void emitDclImmediateConstantBuffer(
const DxbcShaderInstruction& ins);
void emitCustomData(
const DxbcShaderInstruction& ins);
//////////////////////////////
// Instruction class handlers
void emitVectorAlu(
@ -395,6 +408,9 @@ namespace dxvk {
DxbcRegisterPointer emitGetConstBufPtr(
const DxbcRegister& operand);
DxbcRegisterPointer emitGetImmConstBufPtr(
const DxbcRegister& operand);
DxbcRegisterPointer emitGetOperandPtr(
const DxbcRegister& operand);

View File

@ -2,6 +2,13 @@
namespace dxvk {
const uint32_t* DxbcCodeSlice::ptrAt(uint32_t id) const {
if (m_ptr + id >= m_end)
throw DxvkError("DxbcCodeSlice: End of stream");
return m_ptr + id;
}
uint32_t DxbcCodeSlice::at(uint32_t id) const {
if (m_ptr + id >= m_end)
throw DxvkError("DxbcCodeSlice: End of stream");
@ -37,6 +44,7 @@ namespace dxvk {
// Initialize the instruction structure. Some of these values
// may not get written otherwise while decoding the instruction.
m_instruction.op = static_cast<DxbcOpcode>(bit::extract(token0, 0, 10));
m_instruction.opClass = DxbcInstClass::Undefined;
m_instruction.sampleControls = { 0, 0, 0 };
m_instruction.dstCount = 0;
m_instruction.srcCount = 0;
@ -44,6 +52,9 @@ namespace dxvk {
m_instruction.dst = m_dstOperands.data();
m_instruction.src = m_srcOperands.data();
m_instruction.imm = m_immOperands.data();
m_instruction.customDataType = DxbcCustomDataClass::Comment;
m_instruction.customDataSize = 0;
m_instruction.customData = nullptr;
// Reset the index pointer, which may still contain
// a non-zero value from the previous iteration
@ -68,7 +79,22 @@ namespace dxvk {
void DxbcDecodeContext::decodeCustomData(DxbcCodeSlice code) {
Logger::warn("DxbcDecodeContext::decodeCustomData: Not implemented");
const uint32_t blockLength = code.at(1);
if (blockLength < 2) {
Logger::err("DxbcDecodeContext: Invalid custom data block");
return;
}
// Custom data blocks have their own instruction class
m_instruction.op = DxbcOpcode::CustomData;
m_instruction.opClass = DxbcInstClass::CustomData;
// We'll point into the code buffer rather than making a copy
m_instruction.customDataType = static_cast<DxbcCustomDataClass>(
bit::extract(code.at(0), 11, 31));
m_instruction.customDataSize = blockLength - 2;
m_instruction.customData = code.ptrAt(2);
}

View File

@ -231,6 +231,14 @@ namespace dxvk {
/**
* \brief Shader instruction
*
* Note that this structure may store pointer to
* external structures, such as the original code
* buffer. This is safe to use if and only if:
* - The \ref DxbcDecodeContext that created it
* still exists and was not moved
* - The code buffer that was being decoded
* still exists and was not moved.
*/
struct DxbcShaderInstruction {
DxbcOpcode op;
@ -246,6 +254,10 @@ namespace dxvk {
const DxbcRegister* dst;
const DxbcRegister* src;
const DxbcImmediate* imm;
DxbcCustomDataClass customDataType;
uint32_t customDataSize;
const uint32_t* customData;
};
@ -264,6 +276,8 @@ namespace dxvk {
const uint32_t* end)
: m_ptr(ptr), m_end(end) { }
const uint32_t* ptrAt(uint32_t id) const;
uint32_t at(uint32_t id) const;
uint32_t read();

View File

@ -218,7 +218,7 @@ namespace dxvk {
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
} },
/* CustomData */
{ },
{ 0, DxbcInstClass::CustomData },
/* Mov */
{ 2, DxbcInstClass::VectorAlu, {
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },

View File

@ -29,6 +29,7 @@ namespace dxvk {
*/
enum class DxbcInstClass {
Declaration, ///< Interface or resource declaration
CustomData, ///< Immediate constant buffer
ControlFlow, ///< Control flow instructions
GeometryEmit, ///< Special geometry shader instructions
TextureSample, ///< Texture sampling instruction

View File

@ -536,7 +536,7 @@ namespace dxvk {
* types. Scalar types are represented as
* a one-component vector type.
*/
enum class DxbcScalarType {
enum class DxbcScalarType : uint32_t {
Uint32 = 0,
Uint64 = 1,
Sint32 = 2,
@ -546,4 +546,18 @@ namespace dxvk {
Bool = 6,
};
/**
* \brief Custom data class
*
* Stores which type of custom data is
* referenced by the instruction.
*/
enum class DxbcCustomDataClass : uint32_t {
Comment = 0,
DebugInfo = 1,
Opaque = 2,
ImmConstBuf = 3,
};
}

View File

@ -411,3 +411,13 @@ std::ostream& operator << (std::ostream& os, dxvk::DxbcProgramType e) {
ENUM_DEFAULT(e);
}
}
std::ostream& operator << (std::ostream& os, dxvk::DxbcCustomDataClass e) {
switch (e) {
ENUM_NAME(DxbcCustomDataClass::Comment);
ENUM_NAME(DxbcCustomDataClass::DebugInfo);
ENUM_NAME(DxbcCustomDataClass::Opaque);
ENUM_NAME(DxbcCustomDataClass::ImmConstBuf);
ENUM_DEFAULT(e);
}
}

View File

@ -18,3 +18,4 @@ std::ostream& operator << (std::ostream& os, dxvk::DxbcRegisterComponentType e);
std::ostream& operator << (std::ostream& os, dxvk::DxbcInstructionReturnType e);
std::ostream& operator << (std::ostream& os, dxvk::DxbcSystemValue e);
std::ostream& operator << (std::ostream& os, dxvk::DxbcProgramType e);
std::ostream& operator << (std::ostream& os, dxvk::DxbcCustomDataClass e);

View File

@ -521,6 +521,21 @@ namespace dxvk {
}
uint32_t SpirvModule::newVarInit(
uint32_t pointerType,
spv::StorageClass storageClass,
uint32_t initialValue) {
uint32_t resultId = this->allocateId();
m_variables.putIns (spv::OpVariable, 5);
m_variables.putWord (pointerType);
m_variables.putWord (resultId);
m_variables.putWord (storageClass);
m_variables.putWord (initialValue);
return resultId;
}
void SpirvModule::functionBegin(
uint32_t returnType,
uint32_t functionId,

View File

@ -195,6 +195,11 @@ namespace dxvk {
uint32_t pointerType,
spv::StorageClass storageClass);
uint32_t newVarInit(
uint32_t pointerType,
spv::StorageClass storageClass,
uint32_t initialValue);
void functionBegin(
uint32_t returnType,
uint32_t functionId,