From 3d0aad705d581ec3b0be50fbd42e0197eb2580a0 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Mon, 12 Mar 2018 12:25:10 +0100 Subject: [PATCH] [dxbc] Implemented samplepos instruction Required by Fallout 4, among other games. --- src/dxbc/dxbc_compiler.cpp | 171 +++++++++++++++++++++++++++---------- src/dxbc/dxbc_compiler.h | 16 ++-- src/dxbc/dxbc_defs.cpp | 6 +- src/dxbc/dxbc_defs.h | 1 + src/spirv/spirv_module.cpp | 169 +++++++++++++++++++++++++++++++++--- src/spirv/spirv_module.h | 42 +++++++++ 6 files changed, 342 insertions(+), 63 deletions(-) diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index 810b1a30a..ae6bbfc26 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -103,6 +103,9 @@ namespace dxvk { case DxbcInstClass::TextureQueryMs: return this->emitTextureQueryMs(ins); + case DxbcInstClass::TextureQueryMsPos: + return this->emitTextureQueryMsPos(ins); + case DxbcInstClass::TextureFetch: return this->emitTextureFetch(ins); @@ -2546,14 +2549,9 @@ namespace dxvk { } if (resinfoType == DxbcResinfoType::RcpFloat) { - const uint32_t typeId = getVectorTypeId(imageSize.type); - - const uint32_t one = m_module.constf32(1.0f); - std::array constIds = { one, one, one, one }; - - imageSize.id = m_module.opFDiv(typeId, - m_module.constComposite(typeId, - imageSize.type.ccount, constIds.data()), + imageSize.id = m_module.opFDiv( + getVectorTypeId(imageSize.type), + m_module.constvec4f32(1.0f, 1.0f, 1.0f, 1.0f), imageSize.id); } @@ -2657,6 +2655,66 @@ namespace dxvk { } + void DxbcCompiler::emitTextureQueryMsPos(const DxbcShaderInstruction& ins) { + // samplepos has three operands: + // (dst0) The destination register + // (src0) Resource to query + // (src1) Sample index + // TODO Check if resource is bound + if (m_samplePositions == 0) + m_samplePositions = emitSamplePosArray(); + + // The lookup index is qual to the sample count plus the + // sample index, or 0 if the resource cannot be queried. + DxbcRegisterValue sampleCount = emitQueryTextureSamples(ins.src[0]); + DxbcRegisterValue sampleIndex = emitRegisterLoad( + ins.src[1], DxbcRegMask(true, false, false, false)); + + uint32_t lookupIndex = m_module.opIAdd( + getVectorTypeId(sampleCount.type), + sampleCount.id, sampleIndex.id); + + // Validate the parameters + uint32_t sampleCountValid = m_module.opULessThanEqual( + m_module.defBoolType(), + sampleCount.id, + m_module.constu32(16)); + + uint32_t sampleIndexValid = m_module.opULessThan( + m_module.defBoolType(), + sampleIndex.id, + sampleCount.id); + + // If the lookup cannot be performed, set the lookup + // index to zero, which will return a zero vector. + lookupIndex = m_module.opSelect( + getVectorTypeId(sampleCount.type), + m_module.opLogicalAnd( + m_module.defBoolType(), + sampleCountValid, + sampleIndexValid), + lookupIndex, + m_module.constu32(0)); + + // Load sample pos vector and write the masked + // components to the destination register. + DxbcRegisterPointer samplePos; + samplePos.type.ctype = DxbcScalarType::Float32; + samplePos.type.ccount = 4; + samplePos.id = m_module.opAccessChain( + m_module.defPointerType( + getVectorTypeId(samplePos.type), + spv::StorageClassPrivate), + m_samplePositions, 1, &lookupIndex); + + emitRegisterStore(ins.dst[0], + emitRegisterSwizzle( + emitValueLoad(samplePos), + ins.src[0].swizzle, + ins.dst[0].mask)); + } + + void DxbcCompiler::emitTextureFetch(const DxbcShaderInstruction& ins) { // ld has three operands: // (dst0) The destination register @@ -3608,43 +3666,6 @@ namespace dxvk { } - DxbcRegisterValue DxbcCompiler::emitBuildZero( - DxbcScalarType type) { - DxbcRegisterValue result; - result.type.ctype = type; - result.type.ccount = 1; - - switch (type) { - case DxbcScalarType::Float32: result.id = m_module.constf32(0.0f); break; - case DxbcScalarType::Uint32: result.id = m_module.constu32(0); break; - case DxbcScalarType::Sint32: result.id = m_module.consti32(0); break; - default: throw DxvkError("DxbcCompiler: Invalid scalar type"); - } - - return result; - } - - - DxbcRegisterValue DxbcCompiler::emitBuildZeroVec( - DxbcVectorType type) { - const DxbcRegisterValue scalar = emitBuildZero(type.ctype); - - if (type.ccount == 1) - return scalar; - - const std::array zeroIds = {{ - scalar.id, scalar.id, scalar.id, scalar.id, - }}; - - DxbcRegisterValue result; - result.type = type; - result.id = m_module.constComposite( - getVectorTypeId(result.type), - zeroIds.size(), zeroIds.data()); - return result; - } - - DxbcRegisterValue DxbcCompiler::emitRegisterBitcast( DxbcRegisterValue srcValue, DxbcScalarType dstType) { @@ -5688,7 +5709,67 @@ namespace dxvk { return varId; } + + uint32_t DxbcCompiler::emitSamplePosArray() { + const std::array samplePosVectors = {{ + // Invalid sample count / unbound resource + m_module.constvec4f32(0.0f, 0.0f, 0.0f, 0.0f), + // VK_SAMPLE_COUNT_1_BIT + m_module.constvec4f32(0.5f, 0.5f, 0.0f, 0.0f), + // VK_SAMPLE_COUNT_2_BIT + m_module.constvec4f32(0.25f, 0.25f, 0.0f, 0.0f), + m_module.constvec4f32(0.75f, 0.75f, 0.0f, 0.0f), + // VK_SAMPLE_COUNT_4_BIT + m_module.constvec4f32(0.375f, 0.125f, 0.0f, 0.0f), + m_module.constvec4f32(0.785f, 0.375f, 0.0f, 0.0f), + m_module.constvec4f32(0.125f, 0.625f, 0.0f, 0.0f), + m_module.constvec4f32(0.625f, 0.875f, 0.0f, 0.0f), + // VK_SAMPLE_COUNT_8_BIT + m_module.constvec4f32(0.5625f, 0.3125f, 0.0f, 0.0f), + m_module.constvec4f32(0.4375f, 0.6875f, 0.0f, 0.0f), + m_module.constvec4f32(0.8125f, 0.5625f, 0.0f, 0.0f), + m_module.constvec4f32(0.3125f, 0.1875f, 0.0f, 0.0f), + m_module.constvec4f32(0.1875f, 0.8125f, 0.0f, 0.0f), + m_module.constvec4f32(0.0625f, 0.4375f, 0.0f, 0.0f), + m_module.constvec4f32(0.6875f, 0.9375f, 0.0f, 0.0f), + m_module.constvec4f32(0.9375f, 0.0625f, 0.0f, 0.0f), + // VK_SAMPLE_COUNT_16_BIT + m_module.constvec4f32(0.5625f, 0.5625f, 0.0f, 0.0f), + m_module.constvec4f32(0.4375f, 0.3125f, 0.0f, 0.0f), + m_module.constvec4f32(0.3125f, 0.6250f, 0.0f, 0.0f), + m_module.constvec4f32(0.7500f, 0.4375f, 0.0f, 0.0f), + m_module.constvec4f32(0.1875f, 0.3750f, 0.0f, 0.0f), + m_module.constvec4f32(0.6250f, 0.8125f, 0.0f, 0.0f), + m_module.constvec4f32(0.8125f, 0.6875f, 0.0f, 0.0f), + m_module.constvec4f32(0.6875f, 0.1875f, 0.0f, 0.0f), + m_module.constvec4f32(0.3750f, 0.8750f, 0.0f, 0.0f), + m_module.constvec4f32(0.5000f, 0.0625f, 0.0f, 0.0f), + m_module.constvec4f32(0.2500f, 0.1250f, 0.0f, 0.0f), + m_module.constvec4f32(0.1250f, 0.7500f, 0.0f, 0.0f), + m_module.constvec4f32(0.0000f, 0.5000f, 0.0f, 0.0f), + m_module.constvec4f32(0.9375f, 0.2500f, 0.0f, 0.0f), + m_module.constvec4f32(0.8750f, 0.9375f, 0.0f, 0.0f), + m_module.constvec4f32(0.0625f, 0.0000f, 0.0f, 0.0f), + }}; + uint32_t arrayTypeId = getArrayTypeId({ + DxbcScalarType::Float32, 4, + samplePosVectors.size() }); + + uint32_t samplePosArray = m_module.constComposite( + arrayTypeId, + samplePosVectors.size(), + samplePosVectors.data()); + + uint32_t varId = m_module.newVarInit( + m_module.defPointerType(arrayTypeId, spv::StorageClassPrivate), + spv::StorageClassPrivate, samplePosArray); + + m_module.setDebugName(varId, "g_sample_pos"); + return varId; + } + + uint32_t DxbcCompiler::emitNewVariable(const DxbcRegisterInfo& info) { const uint32_t ptrTypeId = this->getPointerTypeId(info); return m_module.newVar(ptrTypeId, info.sclass); diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index f4aab3c81..a74c92f7f 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -393,6 +393,11 @@ namespace dxvk { // an array of four-component uint32 vectors. uint32_t m_immConstBuf = 0; + /////////////////////////////////////////////////// + // Sample pos array. If defined, this iis an array + // of 32 four-component float vectors. + uint32_t m_samplePositions = 0; + //////////////////////////////////////////// // Struct type used for UAV counter buffers uint32_t m_uavCtrStructType = 0; @@ -589,6 +594,9 @@ namespace dxvk { void emitTextureQueryMs( const DxbcShaderInstruction& ins); + void emitTextureQueryMsPos( + const DxbcShaderInstruction& ins); + void emitTextureFetch( const DxbcShaderInstruction& ins); @@ -676,12 +684,6 @@ namespace dxvk { int32_t w, const DxbcRegMask& writeMask); - DxbcRegisterValue emitBuildZero( - DxbcScalarType type); - - DxbcRegisterValue emitBuildZeroVec( - DxbcVectorType type); - ///////////////////////////////////////// // Generic register manipulation methods DxbcRegisterValue emitRegisterBitcast( @@ -934,6 +936,8 @@ namespace dxvk { DxbcCompilerHsForkJoinPhase emitNewHullShaderForkJoinPhase(); + uint32_t emitSamplePosArray(); + /////////////////////////////// // Variable definition methods uint32_t emitNewVariable( diff --git a/src/dxbc/dxbc_defs.cpp b/src/dxbc/dxbc_defs.cpp index f5ca554be..3e1ed31b2 100644 --- a/src/dxbc/dxbc_defs.cpp +++ b/src/dxbc/dxbc_defs.cpp @@ -553,7 +553,11 @@ namespace dxvk { { DxbcOperandKind::SrcReg, DxbcScalarType::Float32 }, } }, /* SamplePos */ - { }, + { 3, DxbcInstClass::TextureQueryMsPos, { + { DxbcOperandKind::DstReg, DxbcScalarType::Float32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 }, + { DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 }, + } }, /* SampleInfo */ { 2, DxbcInstClass::TextureQueryMs, { { DxbcOperandKind::DstReg, DxbcScalarType::Uint32 }, diff --git a/src/dxbc/dxbc_defs.h b/src/dxbc/dxbc_defs.h index c1155c9a7..16a38334e 100644 --- a/src/dxbc/dxbc_defs.h +++ b/src/dxbc/dxbc_defs.h @@ -47,6 +47,7 @@ namespace dxvk { TextureQuery, ///< Texture query instruction TextureQueryLod, ///< Texture LOD query instruction TextureQueryMs, ///< Multisample texture query + TextureQueryMsPos, ///< Sample position query TextureFetch, ///< Texture fetch instruction TextureGather, ///< Texture gather instruction TextureSample, ///< Texture sampling instruction diff --git a/src/spirv/spirv_module.cpp b/src/spirv/spirv_module.cpp index b5ba7ed65..b0fd813e4 100644 --- a/src/spirv/spirv_module.cpp +++ b/src/spirv/spirv_module.cpp @@ -224,6 +224,84 @@ namespace dxvk { } + uint32_t SpirvModule::constvec4i32( + int32_t x, + int32_t y, + int32_t z, + int32_t w) { + uint32_t scalarTypeId = this->defIntType(32, 1); + uint32_t vectorTypeId = this->defVectorType(scalarTypeId, 4); + + uint32_t resultId = this->allocateId(); + + uint32_t xConst = this->consti32(x); + uint32_t yConst = this->consti32(y); + uint32_t zConst = this->consti32(z); + uint32_t wConst = this->consti32(w); + + m_typeConstDefs.putIns (spv::OpConstantComposite, 7); + m_typeConstDefs.putWord (vectorTypeId); + m_typeConstDefs.putWord (resultId); + m_typeConstDefs.putWord (xConst); + m_typeConstDefs.putWord (yConst); + m_typeConstDefs.putWord (zConst); + m_typeConstDefs.putWord (wConst); + return resultId; + } + + + uint32_t SpirvModule::constvec4u32( + uint32_t x, + uint32_t y, + uint32_t z, + uint32_t w) { + uint32_t scalarTypeId = this->defIntType(32, 0); + uint32_t vectorTypeId = this->defVectorType(scalarTypeId, 4); + + uint32_t resultId = this->allocateId(); + + uint32_t xConst = this->constu32(x); + uint32_t yConst = this->constu32(y); + uint32_t zConst = this->constu32(z); + uint32_t wConst = this->constu32(w); + + m_typeConstDefs.putIns (spv::OpConstantComposite, 7); + m_typeConstDefs.putWord (vectorTypeId); + m_typeConstDefs.putWord (resultId); + m_typeConstDefs.putWord (xConst); + m_typeConstDefs.putWord (yConst); + m_typeConstDefs.putWord (zConst); + m_typeConstDefs.putWord (wConst); + return resultId; + } + + + uint32_t SpirvModule::constvec4f32( + float x, + float y, + float z, + float w) { + uint32_t scalarTypeId = this->defFloatType(32); + uint32_t vectorTypeId = this->defVectorType(scalarTypeId, 4); + + uint32_t resultId = this->allocateId(); + + uint32_t xConst = this->constf32(x); + uint32_t yConst = this->constf32(y); + uint32_t zConst = this->constf32(z); + uint32_t wConst = this->constf32(w); + + m_typeConstDefs.putIns (spv::OpConstantComposite, 7); + m_typeConstDefs.putWord (vectorTypeId); + m_typeConstDefs.putWord (resultId); + m_typeConstDefs.putWord (xConst); + m_typeConstDefs.putWord (yConst); + m_typeConstDefs.putWord (zConst); + m_typeConstDefs.putWord (wConst); + return resultId; + } + + uint32_t SpirvModule::constComposite( uint32_t typeId, uint32_t constCount, @@ -379,7 +457,7 @@ namespace dxvk { uint32_t SpirvModule::defIntType( uint32_t width, uint32_t isSigned) { - std::array args = { width, isSigned }; + std::array args = {{ width, isSigned }}; return this->defType(spv::OpTypeInt, args.size(), args.data()); } @@ -387,7 +465,7 @@ namespace dxvk { uint32_t SpirvModule::defFloatType( uint32_t width) { - std::array args = { width }; + std::array args = {{ width }}; return this->defType(spv::OpTypeFloat, args.size(), args.data()); } @@ -396,10 +474,8 @@ namespace dxvk { uint32_t SpirvModule::defVectorType( uint32_t elementType, uint32_t elementCount) { - std::array args = { - elementType, - elementCount - }; + std::array args = + {{ elementType, elementCount }}; return this->defType(spv::OpTypeVector, args.size(), args.data()); @@ -409,10 +485,8 @@ namespace dxvk { uint32_t SpirvModule::defMatrixType( uint32_t columnType, uint32_t columnCount) { - std::array args = { - columnType, - columnCount - }; + std::array args = + {{ columnType, columnCount }}; return this->defType(spv::OpTypeMatrix, args.size(), args.data()); @@ -422,7 +496,7 @@ namespace dxvk { uint32_t SpirvModule::defArrayType( uint32_t typeId, uint32_t length) { - std::array args = { typeId, length }; + std::array args = {{ typeId, length }}; return this->defType(spv::OpTypeArray, args.size(), args.data()); @@ -2024,6 +2098,79 @@ namespace dxvk { } + uint32_t SpirvModule::opLogicalEqual( + uint32_t resultType, + uint32_t operand1, + uint32_t operand2) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpLogicalEqual, 5); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(operand1); + m_code.putWord(operand2); + return resultId; + } + + + uint32_t SpirvModule::opLogicalNotEqual( + uint32_t resultType, + uint32_t operand1, + uint32_t operand2) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpLogicalNotEqual, 5); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(operand1); + m_code.putWord(operand2); + return resultId; + } + + + uint32_t SpirvModule::opLogicalAnd( + uint32_t resultType, + uint32_t operand1, + uint32_t operand2) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpLogicalAnd, 5); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(operand1); + m_code.putWord(operand2); + return resultId; + } + + + uint32_t SpirvModule::opLogicalOr( + uint32_t resultType, + uint32_t operand1, + uint32_t operand2) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpLogicalOr, 5); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(operand1); + m_code.putWord(operand2); + return resultId; + } + + + uint32_t SpirvModule::opLogicalNot( + uint32_t resultType, + uint32_t operand) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpLogicalNot, 4); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(operand); + return resultId; + } + + uint32_t SpirvModule::opDot( uint32_t resultType, uint32_t vector1, diff --git a/src/spirv/spirv_module.h b/src/spirv/spirv_module.h index 660949f95..041b60128 100644 --- a/src/spirv/spirv_module.h +++ b/src/spirv/spirv_module.h @@ -119,6 +119,24 @@ namespace dxvk { uint32_t constf64( double v); + uint32_t constvec4i32( + int32_t x, + int32_t y, + int32_t z, + int32_t w); + + uint32_t constvec4u32( + uint32_t x, + uint32_t y, + uint32_t z, + uint32_t w); + + uint32_t constvec4f32( + float x, + float y, + float z, + float w); + uint32_t constComposite( uint32_t typeId, uint32_t constCount, @@ -724,6 +742,30 @@ namespace dxvk { uint32_t vector1, uint32_t vector2); + uint32_t opLogicalEqual( + uint32_t resultType, + uint32_t operand1, + uint32_t operand2); + + uint32_t opLogicalNotEqual( + uint32_t resultType, + uint32_t operand1, + uint32_t operand2); + + uint32_t opLogicalAnd( + uint32_t resultType, + uint32_t operand1, + uint32_t operand2); + + uint32_t opLogicalOr( + uint32_t resultType, + uint32_t operand1, + uint32_t operand2); + + uint32_t opLogicalNot( + uint32_t resultType, + uint32_t operand); + uint32_t opDot( uint32_t resultType, uint32_t vector1,