[dxbc] Implemented append/consume functionality

Nier will now render the bullets properly.
This commit is contained in:
Philip Rebohle 2018-01-11 17:11:51 +01:00
parent f5bfaac4b3
commit 69c5af4455
5 changed files with 131 additions and 12 deletions

View File

@ -65,6 +65,9 @@ namespace dxvk {
case DxbcInstClass::Atomic:
return this->emitAtomic(ins);
case DxbcInstClass::AtomicCounter:
return this->emitAtomicCounter(ins);
case DxbcInstClass::Barrier:
return this->emitBarrier(ins);
@ -718,6 +721,7 @@ namespace dxvk {
uav.type = DxbcResourceType::Typed;
uav.imageInfo = typeInfo;
uav.varId = varId;
uav.ctrId = 0;
uav.specId = specConstId;
uav.sampledType = sampledType;
uav.sampledTypeId = sampledTypeId;
@ -828,6 +832,7 @@ namespace dxvk {
uav.type = resType;
uav.imageInfo = typeInfo;
uav.varId = varId;
uav.ctrId = 0;
uav.specId = specConstId;
uav.sampledType = sampledType;
uav.sampledTypeId = sampledTypeId;
@ -958,7 +963,49 @@ namespace dxvk {
m_module.setLocalSize(m_entryPointId,
ins.imm[0].u32, ins.imm[1].u32, ins.imm[2].u32);
}
uint32_t DxbcCompiler::emitDclUavCounter(uint32_t regId) {
// Declare a structure type which holds the UAV counter
if (m_uavCtrStructType == 0) {
const uint32_t t_u32 = m_module.defIntType(32, 0);
const uint32_t t_struct = m_module.defStructTypeUnique(1, &t_u32);
m_module.decorate(t_struct, spv::DecorationBufferBlock);
m_module.memberDecorateOffset(t_struct, 0, 0);
m_module.setDebugName (t_struct, "uav_meta");
m_module.setDebugMemberName(t_struct, 0, "ctr");
m_uavCtrStructType = t_struct;
m_uavCtrPointerType = m_module.defPointerType(
t_struct, spv::StorageClassUniform);
}
// Declare the buffer variable
const uint32_t varId = m_module.newVar(
m_uavCtrPointerType, spv::StorageClassUniform);
m_module.setDebugName(varId,
str::format("u", regId, "_meta").c_str());
const uint32_t bindingId = computeResourceSlotId(
m_version.type(), DxbcBindingType::UavCounter,
regId);
m_module.decorateDescriptorSet(varId, 0);
m_module.decorateBinding(varId, bindingId);
// Declare the storage buffer binding
DxvkResourceSlot resource;
resource.slot = bindingId;
resource.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
resource.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
m_resourceSlots.push_back(resource);
return varId;
}
void DxbcCompiler::emitDclImmediateConstantBuffer(const DxbcShaderInstruction& ins) {
if (m_immConstBuf != 0)
@ -1543,16 +1590,8 @@ namespace dxvk {
// (dst0) The destination register
// (src0) The register to shift
// (src1) The shift amount (scalar)
const DxbcRegisterValue shiftReg = emitRegisterLoad(
ins.src[0], ins.dst[0].mask);
DxbcRegisterValue countReg = emitRegisterLoad(
ins.src[1], DxbcRegMask(true, false, false, false));
// Unlike in DXBC, SPIR-V shift operations allow different
// shift amounts per component, so we'll extend the count
// register to a vector.
countReg = emitRegisterExtend(countReg, shiftReg.type.ccount);
const DxbcRegisterValue shiftReg = emitRegisterLoad(ins.src[0], ins.dst[0].mask);
const DxbcRegisterValue countReg = emitRegisterLoad(ins.src[1], ins.dst[0].mask);
DxbcRegisterValue result;
result.type.ctype = ins.dst[0].dataType;
@ -1756,6 +1795,67 @@ namespace dxvk {
}
void DxbcCompiler::emitAtomicCounter(const DxbcShaderInstruction& ins) {
// imm_atomic_alloc and imm_atomic_consume have the following operands:
// (dst0) The register that will hold the old counter value
// (dst1) The UAV whose counter is going to be modified
// TODO check if the corresponding UAV is bound
const uint32_t registerId = ins.dst[1].idx[0].offset;
if (m_uavs.at(registerId).ctrId == 0)
m_uavs.at(registerId).ctrId = emitDclUavCounter(registerId);
// Get a pointer to the atomic counter in question
DxbcRegisterInfo ptrType;
ptrType.type.ctype = DxbcScalarType::Uint32;
ptrType.type.ccount = 1;
ptrType.type.alength = 0;
ptrType.sclass = spv::StorageClassUniform;
const uint32_t zeroId = m_module.consti32(0);
const uint32_t ptrId = m_module.opAccessChain(
getPointerTypeId(ptrType),
m_uavs.at(registerId).ctrId,
1, &zeroId);
// Define memory scope and semantics based on the operands
uint32_t scope = spv::ScopeDevice;
uint32_t semantics = spv::MemorySemanticsUniformMemoryMask
| spv::MemorySemanticsAcquireReleaseMask;
const uint32_t scopeId = m_module.constu32(scope);
const uint32_t semanticsId = m_module.constu32(semantics);
// Compute the result value
DxbcRegisterValue value;
value.type.ctype = DxbcScalarType::Uint32;
value.type.ccount = 1;
const uint32_t typeId = getVectorTypeId(value.type);
switch (ins.op) {
case DxbcOpcode::ImmAtomicAlloc:
value.id = m_module.opAtomicIAdd(typeId, ptrId,
scopeId, semanticsId, m_module.constu32(1));
break;
case DxbcOpcode::ImmAtomicConsume:
value.id = m_module.opAtomicISub(typeId, ptrId,
scopeId, semanticsId, m_module.constu32(1));
break;
default:
Logger::warn(str::format(
"DxbcCompiler: Unhandled instruction: ",
ins.op));
return;
}
// Store the result
emitRegisterStore(ins.dst[0], value);
}
void DxbcCompiler::emitBarrier(const DxbcShaderInstruction& ins) {
// sync takes no operands. Instead, the synchronization
// scope is defined by the operand control bits.

View File

@ -300,6 +300,11 @@ namespace dxvk {
// an array of four-component uint32 vectors.
uint32_t m_immConstBuf = 0;
////////////////////////////////////////////
// Struct type used for UAV counter buffers
uint32_t m_uavCtrStructType = 0;
uint32_t m_uavCtrPointerType = 0;
///////////////////////////////////////////////////
// Entry point description - we'll need to declare
// the function ID and all input/output variables.
@ -371,6 +376,9 @@ namespace dxvk {
void emitDclThreadGroup(
const DxbcShaderInstruction& ins);
uint32_t emitDclUavCounter(
uint32_t regId);
////////////////////////
// Custom data handlers
void emitDclImmediateConstantBuffer(
@ -414,6 +422,9 @@ namespace dxvk {
void emitAtomic(
const DxbcShaderInstruction& ins);
void emitAtomicCounter(
const DxbcShaderInstruction& ins);
void emitBarrier(
const DxbcShaderInstruction& ins);

View File

@ -93,6 +93,7 @@ namespace dxvk {
DxbcResourceType type = DxbcResourceType::Typed;
DxbcImageInfo imageInfo;
uint32_t varId = 0;
uint32_t ctrId = 0;
uint32_t specId = 0;
DxbcScalarType sampledType = DxbcScalarType::Float32;
uint32_t sampledTypeId = 0;

View File

@ -792,9 +792,15 @@ namespace dxvk {
{ DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
} },
/* ImmAtomicAlloc */
{ },
{ 2, DxbcInstClass::AtomicCounter, {
{ DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
{ DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
} },
/* ImmAtomicConsume */
{ },
{ 2, DxbcInstClass::AtomicCounter, {
{ DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
{ DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },
} },
/* ImmAtomicIAdd */
{ 4, DxbcInstClass::Atomic, {
{ DxbcOperandKind::DstReg, DxbcScalarType::Uint32 },

View File

@ -33,6 +33,7 @@ namespace dxvk {
ControlFlow, ///< Control flow instructions
GeometryEmit, ///< Special geometry shader instructions
Atomic, ///< Atomic operations
AtomicCounter, ///< Atomic counter operations
Barrier, ///< Execution or memory barrier
BitExtract, ///< Bit field extract operations
BitInsert, ///< Bit field insert operations