mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
[dxbc] Implemented gather instructions and pixel shader SVs
This commit is contained in:
parent
ce129d4172
commit
596541ed02
@ -101,6 +101,9 @@ namespace dxvk {
|
|||||||
case DxbcInstClass::TextureFetch:
|
case DxbcInstClass::TextureFetch:
|
||||||
return this->emitTextureFetch(ins);
|
return this->emitTextureFetch(ins);
|
||||||
|
|
||||||
|
case DxbcInstClass::TextureGather:
|
||||||
|
return this->emitTextureGather(ins);
|
||||||
|
|
||||||
case DxbcInstClass::TextureSample:
|
case DxbcInstClass::TextureSample:
|
||||||
return this->emitTextureSample(ins);
|
return this->emitTextureSample(ins);
|
||||||
|
|
||||||
@ -418,6 +421,16 @@ namespace dxvk {
|
|||||||
"vThreadIndexInGroup");
|
"vThreadIndexInGroup");
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case DxbcOperandType::OutputDepth: {
|
||||||
|
m_module.setExecutionMode(m_entryPointId,
|
||||||
|
spv::ExecutionModeDepthReplacing);
|
||||||
|
m_ps.builtinDepth = emitNewBuiltinVariable({
|
||||||
|
{ DxbcScalarType::Float32, 1, 0 },
|
||||||
|
spv::StorageClassOutput },
|
||||||
|
spv::BuiltInFragDepth,
|
||||||
|
"oDepth");
|
||||||
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Logger::err(str::format(
|
Logger::err(str::format(
|
||||||
"DxbcCompiler: Unsupported operand type declaration: ",
|
"DxbcCompiler: Unsupported operand type declaration: ",
|
||||||
@ -2388,6 +2401,159 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxbcCompiler::emitTextureGather(const DxbcShaderInstruction& ins) {
|
||||||
|
// Gather4 takes the following operands:
|
||||||
|
// (dst0) The destination register
|
||||||
|
// (src0) Texture coordinates
|
||||||
|
// (src1) The texture itself
|
||||||
|
// (src2) The sampler, with a component selector
|
||||||
|
// Gather4C takes the following additional operand:
|
||||||
|
// (src3) The depth reference value
|
||||||
|
// TODO reduce code duplication by moving some common code
|
||||||
|
// in both sample() and gather() into separate methods
|
||||||
|
const DxbcRegister& texCoordReg = ins.src[0];
|
||||||
|
const DxbcRegister& textureReg = ins.src[1];
|
||||||
|
const DxbcRegister& samplerReg = ins.src[2];
|
||||||
|
|
||||||
|
// Texture and sampler register IDs
|
||||||
|
const uint32_t textureId = textureReg.idx[0].offset;
|
||||||
|
const uint32_t samplerId = samplerReg.idx[0].offset;
|
||||||
|
|
||||||
|
// Image type, which stores the image dimensions etc.
|
||||||
|
const DxbcImageInfo imageType = m_textures.at(textureId).imageInfo;
|
||||||
|
|
||||||
|
const uint32_t imageLayerDim = getTexLayerDim(imageType);
|
||||||
|
const uint32_t imageCoordDim = getTexCoordDim(imageType);
|
||||||
|
|
||||||
|
const DxbcRegMask coordArrayMask = DxbcRegMask::firstN(imageCoordDim);
|
||||||
|
|
||||||
|
// Load the texture coordinates. SPIR-V allows these
|
||||||
|
// to be float4 even if not all components are used.
|
||||||
|
DxbcRegisterValue coord = emitRegisterLoad(texCoordReg, coordArrayMask);
|
||||||
|
|
||||||
|
// Load reference value for depth-compare operations
|
||||||
|
const bool isDepthCompare = ins.op == DxbcOpcode::Gather4C;
|
||||||
|
|
||||||
|
const DxbcRegisterValue referenceValue = isDepthCompare
|
||||||
|
? emitRegisterLoad(ins.src[3], DxbcRegMask(true, false, false, false))
|
||||||
|
: DxbcRegisterValue();
|
||||||
|
|
||||||
|
if (isDepthCompare && m_options.packDrefValueIntoCoordinates) {
|
||||||
|
const std::array<uint32_t, 2> packedCoordIds
|
||||||
|
= {{ coord.id, referenceValue.id }};
|
||||||
|
|
||||||
|
coord.type.ccount += 1;
|
||||||
|
coord.id = m_module.opCompositeConstruct(
|
||||||
|
getVectorTypeId(coord.type),
|
||||||
|
packedCoordIds.size(),
|
||||||
|
packedCoordIds.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the sampled image type based on the opcode.
|
||||||
|
const uint32_t sampledImageType = isDepthCompare
|
||||||
|
? m_module.defSampledImageType(m_textures.at(textureId).depthTypeId)
|
||||||
|
: m_module.defSampledImageType(m_textures.at(textureId).colorTypeId);
|
||||||
|
|
||||||
|
// Accumulate additional image operands.
|
||||||
|
SpirvImageOperands imageOperands;
|
||||||
|
|
||||||
|
if (ins.sampleControls.u != 0 || ins.sampleControls.v != 0 || ins.sampleControls.w != 0) {
|
||||||
|
const std::array<uint32_t, 3> offsetIds = {
|
||||||
|
imageLayerDim >= 1 ? m_module.consti32(ins.sampleControls.u) : 0,
|
||||||
|
imageLayerDim >= 2 ? m_module.consti32(ins.sampleControls.v) : 0,
|
||||||
|
imageLayerDim >= 3 ? m_module.consti32(ins.sampleControls.w) : 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
imageOperands.flags |= spv::ImageOperandsConstOffsetMask;
|
||||||
|
imageOperands.sConstOffset = m_module.constComposite(
|
||||||
|
getVectorTypeId({ DxbcScalarType::Sint32, imageLayerDim }),
|
||||||
|
imageLayerDim, offsetIds.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only execute the gather operation if the resource is bound
|
||||||
|
const uint32_t labelMerge = m_module.allocateId();
|
||||||
|
const uint32_t labelBound = m_module.allocateId();
|
||||||
|
const uint32_t labelUnbound = m_module.allocateId();
|
||||||
|
|
||||||
|
m_module.opSelectionMerge(labelMerge, spv::SelectionControlMaskNone);
|
||||||
|
m_module.opBranchConditional(m_textures.at(textureId).specId, labelBound, labelUnbound);
|
||||||
|
m_module.opLabel(labelBound);
|
||||||
|
|
||||||
|
// Combine the texture and the sampler into a sampled image
|
||||||
|
const uint32_t sampledImageId = m_module.opSampledImage(
|
||||||
|
sampledImageType,
|
||||||
|
m_module.opLoad(
|
||||||
|
m_textures.at(textureId).imageTypeId,
|
||||||
|
m_textures.at(textureId).varId),
|
||||||
|
m_module.opLoad(
|
||||||
|
m_samplers.at(samplerId).typeId,
|
||||||
|
m_samplers.at(samplerId).varId));
|
||||||
|
|
||||||
|
// Gathering texels always returns a four-component
|
||||||
|
// vector, even for the depth-compare variants.
|
||||||
|
DxbcRegisterValue result;
|
||||||
|
result.type.ctype = m_textures.at(textureId).sampledType;
|
||||||
|
result.type.ccount = 4;
|
||||||
|
switch (ins.op) {
|
||||||
|
// Simple image gather operation
|
||||||
|
case DxbcOpcode::Gather4: {
|
||||||
|
result.id = m_module.opImageGather(
|
||||||
|
getVectorTypeId(result.type), sampledImageId, coord.id,
|
||||||
|
m_module.constu32(samplerReg.swizzle[0]),
|
||||||
|
imageOperands);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
// Depth-compare operation
|
||||||
|
case DxbcOpcode::Gather4C: {
|
||||||
|
result.id = m_module.opImageDrefGather(
|
||||||
|
getVectorTypeId(result.type), sampledImageId, coord.id,
|
||||||
|
referenceValue.id, imageOperands);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Logger::warn(str::format(
|
||||||
|
"DxbcCompiler: Unhandled instruction: ",
|
||||||
|
ins.op));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swizzle components using the texture swizzle
|
||||||
|
// and the destination operand's write mask
|
||||||
|
result = emitRegisterSwizzle(result,
|
||||||
|
textureReg.swizzle, ins.dst[0].mask);
|
||||||
|
|
||||||
|
// If the texture is not bound, return zeroes
|
||||||
|
m_module.opBranch(labelMerge);
|
||||||
|
m_module.opLabel(labelUnbound);
|
||||||
|
|
||||||
|
DxbcRegisterValue zeroes = [&] {
|
||||||
|
switch (result.type.ctype) {
|
||||||
|
case DxbcScalarType::Float32: return emitBuildConstVecf32(0.0f, 0.0f, 0.0f, 0.0f, ins.dst[0].mask);
|
||||||
|
case DxbcScalarType::Uint32: return emitBuildConstVecu32(0u, 0u, 0u, 0u, ins.dst[0].mask);
|
||||||
|
case DxbcScalarType::Sint32: return emitBuildConstVeci32(0, 0, 0, 0, ins.dst[0].mask);
|
||||||
|
default: throw DxvkError("DxbcCompiler: Invalid scalar type");
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
m_module.opBranch(labelMerge);
|
||||||
|
m_module.opLabel(labelMerge);
|
||||||
|
|
||||||
|
// Merge the result with a phi function
|
||||||
|
const std::array<SpirvPhiLabel, 2> phiLabels = {{
|
||||||
|
{ result.id, labelBound },
|
||||||
|
{ zeroes.id, labelUnbound },
|
||||||
|
}};
|
||||||
|
|
||||||
|
DxbcRegisterValue mergedResult;
|
||||||
|
mergedResult.type = result.type;
|
||||||
|
mergedResult.id = m_module.opPhi(
|
||||||
|
getVectorTypeId(mergedResult.type),
|
||||||
|
phiLabels.size(), phiLabels.data());
|
||||||
|
|
||||||
|
emitRegisterStore(ins.dst[0], mergedResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxbcCompiler::emitTextureSample(const DxbcShaderInstruction& ins) {
|
void DxbcCompiler::emitTextureSample(const DxbcShaderInstruction& ins) {
|
||||||
// TODO support remaining sample ops
|
// TODO support remaining sample ops
|
||||||
|
|
||||||
@ -2407,22 +2573,11 @@ namespace dxvk {
|
|||||||
// Image type, which stores the image dimensions etc.
|
// Image type, which stores the image dimensions etc.
|
||||||
const DxbcImageInfo imageType = m_textures.at(textureId).imageInfo;
|
const DxbcImageInfo imageType = m_textures.at(textureId).imageInfo;
|
||||||
|
|
||||||
const uint32_t imageLayerDim = [&] {
|
const uint32_t imageLayerDim = getTexLayerDim(imageType);
|
||||||
switch (imageType.dim) {
|
const uint32_t imageCoordDim = getTexCoordDim(imageType);
|
||||||
case spv::DimBuffer: return 1;
|
|
||||||
case spv::Dim1D: return 1;
|
|
||||||
case spv::Dim2D: return 2;
|
|
||||||
case spv::Dim3D: return 3;
|
|
||||||
case spv::DimCube: return 3;
|
|
||||||
default: throw DxvkError("DxbcCompiler: Unsupported image dim");
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
|
|
||||||
const DxbcRegMask coordArrayMask =
|
const DxbcRegMask coordArrayMask = DxbcRegMask::firstN(imageCoordDim);
|
||||||
DxbcRegMask::firstN(imageLayerDim + imageType.array);
|
const DxbcRegMask coordLayerMask = DxbcRegMask::firstN(imageLayerDim);
|
||||||
|
|
||||||
const DxbcRegMask coordLayerMask =
|
|
||||||
DxbcRegMask::firstN(imageLayerDim);
|
|
||||||
|
|
||||||
// Load the texture coordinates. SPIR-V allows these
|
// Load the texture coordinates. SPIR-V allows these
|
||||||
// to be float4 even if not all components are used.
|
// to be float4 even if not all components are used.
|
||||||
@ -3562,6 +3717,11 @@ namespace dxvk {
|
|||||||
return DxbcRegisterPointer {
|
return DxbcRegisterPointer {
|
||||||
{ DxbcScalarType::Uint32, 1 },
|
{ DxbcScalarType::Uint32, 1 },
|
||||||
m_cs.builtinLocalInvocationIndex };
|
m_cs.builtinLocalInvocationIndex };
|
||||||
|
|
||||||
|
case DxbcOperandType::OutputDepth:
|
||||||
|
return DxbcRegisterPointer {
|
||||||
|
{ DxbcScalarType::Float32, 1 },
|
||||||
|
m_ps.builtinDepth };
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw DxvkError(str::format(
|
throw DxvkError(str::format(
|
||||||
@ -4224,6 +4384,20 @@ namespace dxvk {
|
|||||||
emitValueLoad(ptrIn), mask);
|
emitValueLoad(ptrIn), mask);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case DxbcSystemValue::IsFrontFace: {
|
||||||
|
DxbcRegisterValue result;
|
||||||
|
result.type.ctype = DxbcScalarType::Uint32;
|
||||||
|
result.type.ccount = 1;
|
||||||
|
result.id = m_module.opSelect(
|
||||||
|
getVectorTypeId(result.type),
|
||||||
|
m_module.opLoad(
|
||||||
|
m_module.defBoolType(),
|
||||||
|
m_ps.builtinIsFrontFace),
|
||||||
|
m_module.constu32(0xFFFFFFFF),
|
||||||
|
m_module.constu32(0x00000000));
|
||||||
|
return result;
|
||||||
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw DxvkError(str::format(
|
throw DxvkError(str::format(
|
||||||
"DxbcCompiler: Unhandled PS SV input: ", sv));
|
"DxbcCompiler: Unhandled PS SV input: ", sv));
|
||||||
@ -4326,6 +4500,12 @@ namespace dxvk {
|
|||||||
spv::StorageClassInput },
|
spv::StorageClassInput },
|
||||||
spv::BuiltInFragCoord,
|
spv::BuiltInFragCoord,
|
||||||
"ps_frag_coord");
|
"ps_frag_coord");
|
||||||
|
|
||||||
|
m_ps.builtinIsFrontFace = emitNewBuiltinVariable({
|
||||||
|
{ DxbcScalarType::Bool, 1, 0 },
|
||||||
|
spv::StorageClassInput },
|
||||||
|
spv::BuiltInFrontFacing,
|
||||||
|
"ps_is_front_face");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,8 +125,9 @@ namespace dxvk {
|
|||||||
struct DxbcCompilerPsPart {
|
struct DxbcCompilerPsPart {
|
||||||
uint32_t functionId = 0;
|
uint32_t functionId = 0;
|
||||||
|
|
||||||
uint32_t builtinFragCoord = 0;
|
uint32_t builtinFragCoord = 0;
|
||||||
uint32_t builtinDepth = 0;
|
uint32_t builtinDepth = 0;
|
||||||
|
uint32_t builtinIsFrontFace = 0;
|
||||||
|
|
||||||
std::array<DxbcVectorType, DxbcMaxInterfaceRegs> oTypes;
|
std::array<DxbcVectorType, DxbcMaxInterfaceRegs> oTypes;
|
||||||
};
|
};
|
||||||
@ -457,6 +458,9 @@ namespace dxvk {
|
|||||||
void emitTextureFetch(
|
void emitTextureFetch(
|
||||||
const DxbcShaderInstruction& ins);
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
|
void emitTextureGather(
|
||||||
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
void emitTextureSample(
|
void emitTextureSample(
|
||||||
const DxbcShaderInstruction& ins);
|
const DxbcShaderInstruction& ins);
|
||||||
|
|
||||||
|
@ -532,7 +532,12 @@ namespace dxvk {
|
|||||||
/* Lod */
|
/* Lod */
|
||||||
{ },
|
{ },
|
||||||
/* Gather4 */
|
/* Gather4 */
|
||||||
{ },
|
{ 4, DxbcInstClass::TextureGather, {
|
||||||
|
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||||
|
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||||
|
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||||
|
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||||
|
} },
|
||||||
/* SamplePos */
|
/* SamplePos */
|
||||||
{ },
|
{ },
|
||||||
/* SampleInfo */
|
/* SampleInfo */
|
||||||
@ -581,7 +586,13 @@ namespace dxvk {
|
|||||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||||
} },
|
} },
|
||||||
/* Gather4C */
|
/* Gather4C */
|
||||||
{ },
|
{ 5, DxbcInstClass::TextureGather, {
|
||||||
|
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||||
|
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||||
|
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||||
|
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||||
|
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||||
|
} },
|
||||||
/* Gather4Po */
|
/* Gather4Po */
|
||||||
{ },
|
{ },
|
||||||
/* Gather4PoC */
|
/* Gather4PoC */
|
||||||
|
@ -43,6 +43,7 @@ namespace dxvk {
|
|||||||
ConvertFloat16, ///< 16-bit float packing/unpacking
|
ConvertFloat16, ///< 16-bit float packing/unpacking
|
||||||
TextureQuery, ///< Texture query instruction
|
TextureQuery, ///< Texture query instruction
|
||||||
TextureFetch, ///< Texture fetch instruction
|
TextureFetch, ///< Texture fetch instruction
|
||||||
|
TextureGather, ///< Texture gather instruction
|
||||||
TextureSample, ///< Texture sampling instruction
|
TextureSample, ///< Texture sampling instruction
|
||||||
TypedUavLoad, ///< Typed UAV load
|
TypedUavLoad, ///< Typed UAV load
|
||||||
TypedUavStore, ///< Typed UAV store
|
TypedUavStore, ///< Typed UAV store
|
||||||
|
@ -2360,6 +2360,48 @@ namespace dxvk {
|
|||||||
return resultId;
|
return resultId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t SpirvModule::opImageGather(
|
||||||
|
uint32_t resultType,
|
||||||
|
uint32_t sampledImage,
|
||||||
|
uint32_t coordinates,
|
||||||
|
uint32_t component,
|
||||||
|
const SpirvImageOperands& operands) {
|
||||||
|
uint32_t resultId = this->allocateId();
|
||||||
|
|
||||||
|
m_code.putIns(spv::OpImageGather,
|
||||||
|
6 + getImageOperandWordCount(operands));
|
||||||
|
m_code.putWord(resultType);
|
||||||
|
m_code.putWord(resultId);
|
||||||
|
m_code.putWord(sampledImage);
|
||||||
|
m_code.putWord(coordinates);
|
||||||
|
m_code.putWord(component);
|
||||||
|
|
||||||
|
putImageOperands(operands);
|
||||||
|
return resultId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t SpirvModule::opImageDrefGather(
|
||||||
|
uint32_t resultType,
|
||||||
|
uint32_t sampledImage,
|
||||||
|
uint32_t coordinates,
|
||||||
|
uint32_t reference,
|
||||||
|
const SpirvImageOperands& operands) {
|
||||||
|
uint32_t resultId = this->allocateId();
|
||||||
|
|
||||||
|
m_code.putIns(spv::OpImageDrefGather,
|
||||||
|
6 + getImageOperandWordCount(operands));
|
||||||
|
m_code.putWord(resultType);
|
||||||
|
m_code.putWord(resultId);
|
||||||
|
m_code.putWord(sampledImage);
|
||||||
|
m_code.putWord(coordinates);
|
||||||
|
m_code.putWord(reference);
|
||||||
|
|
||||||
|
putImageOperands(operands);
|
||||||
|
return resultId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t SpirvModule::opImageSampleImplicitLod(
|
uint32_t SpirvModule::opImageSampleImplicitLod(
|
||||||
uint32_t resultType,
|
uint32_t resultType,
|
||||||
|
@ -830,6 +830,20 @@ namespace dxvk {
|
|||||||
uint32_t coordinates,
|
uint32_t coordinates,
|
||||||
const SpirvImageOperands& operands);
|
const SpirvImageOperands& operands);
|
||||||
|
|
||||||
|
uint32_t opImageGather(
|
||||||
|
uint32_t resultType,
|
||||||
|
uint32_t sampledImage,
|
||||||
|
uint32_t coordinates,
|
||||||
|
uint32_t component,
|
||||||
|
const SpirvImageOperands& operands);
|
||||||
|
|
||||||
|
uint32_t opImageDrefGather(
|
||||||
|
uint32_t resultType,
|
||||||
|
uint32_t sampledImage,
|
||||||
|
uint32_t coordinates,
|
||||||
|
uint32_t reference,
|
||||||
|
const SpirvImageOperands& operands);
|
||||||
|
|
||||||
uint32_t opImageSampleImplicitLod(
|
uint32_t opImageSampleImplicitLod(
|
||||||
uint32_t resultType,
|
uint32_t resultType,
|
||||||
uint32_t sampledImage,
|
uint32_t sampledImage,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user