[dxbc] Implemented operand modifiers and load/store stuff

This commit is contained in:
Philip Rebohle 2017-11-16 01:30:17 +01:00
parent 901abe4356
commit 5d26f0fb0c
13 changed files with 1017 additions and 77 deletions

View File

@ -0,0 +1,135 @@
/*
** Copyright (c) 2014-2016 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and/or associated documentation files (the "Materials"),
** to deal in the Materials without restriction, including without limitation
** the rights to use, copy, modify, merge, publish, distribute, sublicense,
** and/or sell copies of the Materials, and to permit persons to whom the
** Materials are furnished to do so, subject to the following conditions:
**
** The above copyright notice and this permission notice shall be included in
** all copies or substantial portions of the Materials.
**
** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
** IN THE MATERIALS.
*/
#ifndef GLSLstd450_HPP
#define GLSLstd450_HPP
namespace spv {
static const int GLSLstd450Version = 100;
static const int GLSLstd450Revision = 3;
enum GLSLstd450 {
GLSLstd450Bad = 0, // Don't use
GLSLstd450Round = 1,
GLSLstd450RoundEven = 2,
GLSLstd450Trunc = 3,
GLSLstd450FAbs = 4,
GLSLstd450SAbs = 5,
GLSLstd450FSign = 6,
GLSLstd450SSign = 7,
GLSLstd450Floor = 8,
GLSLstd450Ceil = 9,
GLSLstd450Fract = 10,
GLSLstd450Radians = 11,
GLSLstd450Degrees = 12,
GLSLstd450Sin = 13,
GLSLstd450Cos = 14,
GLSLstd450Tan = 15,
GLSLstd450Asin = 16,
GLSLstd450Acos = 17,
GLSLstd450Atan = 18,
GLSLstd450Sinh = 19,
GLSLstd450Cosh = 20,
GLSLstd450Tanh = 21,
GLSLstd450Asinh = 22,
GLSLstd450Acosh = 23,
GLSLstd450Atanh = 24,
GLSLstd450Atan2 = 25,
GLSLstd450Pow = 26,
GLSLstd450Exp = 27,
GLSLstd450Log = 28,
GLSLstd450Exp2 = 29,
GLSLstd450Log2 = 30,
GLSLstd450Sqrt = 31,
GLSLstd450InverseSqrt = 32,
GLSLstd450Determinant = 33,
GLSLstd450MatrixInverse = 34,
GLSLstd450Modf = 35, // second operand needs an OpVariable to write to
GLSLstd450ModfStruct = 36, // no OpVariable operand
GLSLstd450FMin = 37,
GLSLstd450UMin = 38,
GLSLstd450SMin = 39,
GLSLstd450FMax = 40,
GLSLstd450UMax = 41,
GLSLstd450SMax = 42,
GLSLstd450FClamp = 43,
GLSLstd450UClamp = 44,
GLSLstd450SClamp = 45,
GLSLstd450FMix = 46,
GLSLstd450IMix = 47, // Reserved
GLSLstd450Step = 48,
GLSLstd450SmoothStep = 49,
GLSLstd450Fma = 50,
GLSLstd450Frexp = 51, // second operand needs an OpVariable to write to
GLSLstd450FrexpStruct = 52, // no OpVariable operand
GLSLstd450Ldexp = 53,
GLSLstd450PackSnorm4x8 = 54,
GLSLstd450PackUnorm4x8 = 55,
GLSLstd450PackSnorm2x16 = 56,
GLSLstd450PackUnorm2x16 = 57,
GLSLstd450PackHalf2x16 = 58,
GLSLstd450PackDouble2x32 = 59,
GLSLstd450UnpackSnorm2x16 = 60,
GLSLstd450UnpackUnorm2x16 = 61,
GLSLstd450UnpackHalf2x16 = 62,
GLSLstd450UnpackSnorm4x8 = 63,
GLSLstd450UnpackUnorm4x8 = 64,
GLSLstd450UnpackDouble2x32 = 65,
GLSLstd450Length = 66,
GLSLstd450Distance = 67,
GLSLstd450Cross = 68,
GLSLstd450Normalize = 69,
GLSLstd450FaceForward = 70,
GLSLstd450Reflect = 71,
GLSLstd450Refract = 72,
GLSLstd450FindILsb = 73,
GLSLstd450FindSMsb = 74,
GLSLstd450FindUMsb = 75,
GLSLstd450InterpolateAtCentroid = 76,
GLSLstd450InterpolateAtSample = 77,
GLSLstd450InterpolateAtOffset = 78,
GLSLstd450NMin = 79,
GLSLstd450NMax = 80,
GLSLstd450NClamp = 81,
GLSLstd450Count
};
}
#endif // #ifndef GLSLstd450_HPP

View File

@ -33,6 +33,12 @@ namespace dxvk {
case DxbcOpcode::DclTemps:
return this->dclTemps(ins);
case DxbcOpcode::Mov:
return this->opMov(ins);
case DxbcOpcode::Ret:
return this->opRet(ins);
default:
Logger::err(str::format(
"DxbcCompiler::processInstruction: Unhandled opcode: ",
@ -52,7 +58,49 @@ namespace dxvk {
void DxbcCompiler::dclInterfaceVar(const DxbcInstruction& ins) {
auto op = ins.operand(0);
auto opcode = ins.token().opcode();
switch (op.token().type()) {
case DxbcOperandType::Input:
case DxbcOperandType::Output: {
uint32_t regId = 0;
uint32_t regDim = 0;
if (op.token().indexDimension() == 1) {
regId = op.index(0).immPart();
} else if (op.token().indexDimension() == 2) {
regDim = op.index(0).immPart();
regId = op.index(1).immPart();
} else {
throw DxvkError(str::format(
"DxbcCompiler::dclInterfaceVar: Invalid index dimension: ",
op.token().indexDimension()));
}
const bool hasSv =
opcode == DxbcOpcode::DclInputSgv
|| opcode == DxbcOpcode::DclInputSiv
|| opcode == DxbcOpcode::DclInputPsSgv
|| opcode == DxbcOpcode::DclInputPsSiv
|| opcode == DxbcOpcode::DclOutputSgv
|| opcode == DxbcOpcode::DclOutputSiv;
DxbcSystemValue sv = DxbcSystemValue::None;
if (hasSv)
sv = ins.readEnum<DxbcSystemValue>(op.length());
m_gen->dclInterfaceVar(
op.token().type(), regId, regDim,
op.token().componentMask(), sv);
} break;
default:
throw DxvkError(str::format(
"DxbcCompiler::dclInterfaceVar: Unhandled operand type: ",
op.token().type()));
}
}
@ -60,4 +108,207 @@ namespace dxvk {
m_gen->dclTemps(ins.arg(0));
}
void DxbcCompiler::opMov(const DxbcInstruction& ins) {
auto dstOp = ins.operand(0);
auto srcOp = ins.operand(dstOp.length());
DxbcComponentMask mask = this->getDstOperandMask(dstOp);
DxbcValue value = this->loadOperand(srcOp, mask, DxbcScalarType::Float32);
this->storeOperand(dstOp, value, mask);
}
void DxbcCompiler::opRet(const DxbcInstruction& ins) {
m_gen->fnReturn();
}
DxbcComponentMask DxbcCompiler::getDstOperandMask(const DxbcOperand& operand) {
const DxbcOperandToken token = operand.token();
if (token.numComponents() == 1) {
return DxbcComponentMask(true, false, false, false);
} else if (token.numComponents() == 4) {
switch (token.selectionMode()) {
case DxbcComponentSelectionMode::Mask:
return token.componentMask();
case DxbcComponentSelectionMode::Select1:
return token.componentSelection();
default:
throw DxvkError(str::format(
"DxbcCompiler::getDstOperandMask: Invalid component selection mode: ",
token.selectionMode()));
}
} else {
throw DxvkError(str::format(
"DxbcCompiler::getDstOperandMask: Invalid component count: ",
token.numComponents()));
}
}
DxbcPointer DxbcCompiler::getTempOperandPtr(const DxbcOperand& operand) {
if (operand.token().indexDimension() != 1) {
throw DxvkError(str::format(
"DxbcCompiler::getTempOperandPtr: Invalid index dimension: ",
operand.token().indexDimension()));
}
if (operand.token().indexRepresentation(0) != DxbcOperandIndexRepresentation::Imm32) {
throw DxvkError(str::format(
"DxbcCompiler::getTempOperandPtr: Invalid index representation: ",
operand.token().indexRepresentation(0)));
}
return m_gen->ptrTempReg(operand.index(0).immPart());
}
DxbcPointer DxbcCompiler::getInterfaceOperandPtr(const DxbcOperand& operand) {
const uint32_t indexDim = operand.token().indexDimension();
// Vertex index ID is unused if the index dimension
// is 1. The element index is always the last index.
// const uint32_t vIndexId = 0;
const uint32_t eIndexId = indexDim - 1;
if (operand.token().indexRepresentation(eIndexId) != DxbcOperandIndexRepresentation::Imm32) {
throw DxvkError(str::format(
"DxbcCompiler::getInterfaceOperandPtr: Invalid element index representation: ",
operand.token().indexRepresentation(eIndexId)));
}
if (indexDim == 1) {
return m_gen->ptrInterfaceVar(
operand.token().type(),
operand.index(eIndexId).immPart());
} else {
// TODO implement index dimension 2
throw DxvkError(str::format(
"DxbcCompiler::getInterfaceOperandPtr: Invalid index dimension: ",
indexDim));
}
}
DxbcPointer DxbcCompiler::getOperandPtr(const DxbcOperand& operand) {
switch (operand.token().type()) {
case DxbcOperandType::Temp:
return this->getTempOperandPtr(operand);
case DxbcOperandType::Input:
case DxbcOperandType::Output:
return this->getInterfaceOperandPtr(operand);
default:
throw DxvkError(str::format(
"DxbcCompiler::getOperandPtr: Unhandled operand type: ",
operand.token().type()));
}
}
DxbcValue DxbcCompiler::selectOperandComponents(
const DxbcOperandToken& opToken,
const DxbcValue& opValue,
DxbcComponentMask dstMask) {
// Four-component source operands can provide either a
// swizzle to select multiple components, or a component
// index that is used to select one single component.
switch (opToken.selectionMode()) {
case DxbcComponentSelectionMode::Swizzle:
return m_gen->regSwizzle(opValue,
opToken.componentSwizzle(), dstMask);
case DxbcComponentSelectionMode::Select1:
return m_gen->regExtract(opValue,
opToken.componentSelection());
default:
throw DxvkError(str::format(
"DxbcCompiler::loadOperand: Invalid component selection mode: ",
opToken.selectionMode()));
}
}
DxbcValue DxbcCompiler::applyOperandModifiers(
DxbcValue value,
DxbcOperandModifiers modifiers) {
if (modifiers.test(DxbcOperandModifier::Abs))
value = m_gen->opAbs(value);
if (modifiers.test(DxbcOperandModifier::Neg))
value = m_gen->opNeg(value);
return value;
}
DxbcValue DxbcCompiler::loadOperand(
const DxbcOperand& operand,
DxbcComponentMask dstMask,
DxbcScalarType dstType) {
const DxbcOperandToken token = operand.token();
DxbcValue result;
switch (token.type()) {
case DxbcOperandType::Imm32: {
if (token.numComponents() == 1) {
result = m_gen->defConstScalar(operand.imm32(0));
} else if (token.numComponents() == 4) {
result = m_gen->defConstVector(
operand.imm32(0), operand.imm32(1),
operand.imm32(2), operand.imm32(3));
} else {
throw DxvkError(str::format(
"DxbcCompiler::loadOperand [imm32]: Invalid number of components: ",
token.numComponents()));
}
} break;
default: {
result = m_gen->regLoad(
this->getOperandPtr(operand));
};
}
// Apply the source operand swizzle
if (token.numComponents() == 4)
result = this->selectOperandComponents(token, result, dstMask);
// Apply source operand modifiers, if any
auto operandModifiers = operand.queryOperandExt(
DxbcOperandExt::OperandModifier);
if (operandModifiers) {
result = this->applyOperandModifiers(
result, operandModifiers->data());
}
return result;
}
void DxbcCompiler::storeOperand(
const DxbcOperand& operand,
DxbcValue value,
DxbcComponentMask mask) {
const DxbcPointer ptr = this->getOperandPtr(operand);
// Cast source value to destination register type.
// TODO verify that this actually works as intended.
DxbcValueType dstType;
dstType.componentType = ptr.type.valueType.componentType;
dstType.componentCount = mask.componentCount();
value = m_gen->regCast(value, dstType);
m_gen->regStore(ptr, value, mask);
}
}

View File

@ -28,13 +28,50 @@ namespace dxvk {
Rc<DxbcCodeGen> m_gen;
void dclGlobalFlags(
const DxbcInstruction& ins);
const DxbcInstruction& ins);
void dclInterfaceVar(
const DxbcInstruction& ins);
const DxbcInstruction& ins);
void dclTemps(
const DxbcInstruction& ins);
const DxbcInstruction& ins);
void opMov(
const DxbcInstruction& ins);
void opRet(
const DxbcInstruction& ins);
DxbcComponentMask getDstOperandMask(
const DxbcOperand& operand);
DxbcPointer getTempOperandPtr(
const DxbcOperand& operand);
DxbcPointer getInterfaceOperandPtr(
const DxbcOperand& operand);
DxbcPointer getOperandPtr(
const DxbcOperand& operand);
DxbcValue selectOperandComponents(
const DxbcOperandToken& opToken,
const DxbcValue& opValue,
DxbcComponentMask dstMask);
DxbcValue applyOperandModifiers(
DxbcValue value,
DxbcOperandModifiers modifiers);
DxbcValue loadOperand(
const DxbcOperand& operand,
DxbcComponentMask dstMask,
DxbcScalarType dstType);
void storeOperand(
const DxbcOperand& operand,
DxbcValue value,
DxbcComponentMask mask);
};

View File

@ -424,4 +424,12 @@ namespace dxvk {
using DxbcGlobalFlags = Flags<DxbcGlobalFlag>;
enum class DxbcOperandModifier : uint32_t {
Neg = 0,
Abs = 1,
};
using DxbcOperandModifiers = Flags<DxbcOperandModifier>;
}

View File

@ -275,6 +275,14 @@ std::ostream& operator << (std::ostream& os, DxbcOperandType e) {
}
std::ostream& operator << (std::ostream& os, dxvk::DxbcOperandExt e) {
switch (e) {
ENUM_NAME(DxbcOperandExt::OperandModifier);
ENUM_DEFAULT(e);
}
}
std::ostream& operator << (std::ostream& os, DxbcComponentCount e) {
switch (e) {
ENUM_NAME(DxbcComponentCount::Component0);

View File

@ -8,6 +8,7 @@
std::ostream& operator << (std::ostream& os, dxvk::DxbcOpcode e);
std::ostream& operator << (std::ostream& os, dxvk::DxbcExtOpcode e);
std::ostream& operator << (std::ostream& os, dxvk::DxbcOperandType e);
std::ostream& operator << (std::ostream& os, dxvk::DxbcOperandExt e);
std::ostream& operator << (std::ostream& os, dxvk::DxbcComponentCount e);
std::ostream& operator << (std::ostream& os, dxvk::DxbcComponentSelectionMode e);
std::ostream& operator << (std::ostream& os, dxvk::DxbcOperandIndexRepresentation e);

View File

@ -6,7 +6,6 @@
namespace dxvk {
DxbcCodeGen::DxbcCodeGen() {
m_module.enableCapability(spv::CapabilityShader);
m_module.setMemoryModel(
spv::AddressingModelLogical,
spv::MemoryModelGLSL450);
@ -25,31 +24,173 @@ namespace dxvk {
if (n > oldSize) {
m_rRegs.resize(n);
DxbcPointer reg;
reg.type = DxbcPointerType(
DxbcValueType(DxbcScalarType::Float32, 4),
spv::StorageClassPrivate);
const uint32_t typeId = this->defPointerType(reg.type);
for (uint32_t i = oldSize; i < n; i++) {
reg.valueId = m_module.newVar(typeId, spv::StorageClassPrivate);
m_module.setDebugName(reg.valueId, str::format("r", i).c_str());
m_rRegs.at(i) = reg;
m_rRegs.at(i) = this->defVar(
DxbcValueType(DxbcScalarType::Float32, 4),
spv::StorageClassPrivate);
m_module.setDebugName(m_rRegs.at(i).valueId,
str::format("r", i).c_str());
}
}
}
DxbcValue DxbcCodeGen::defConstScalar(uint32_t v) {
DxbcValue result;
result.type = DxbcValueType(DxbcScalarType::Uint32, 1);
result.valueId = m_module.constu32(v);
return result;
}
DxbcValue DxbcCodeGen::defConstVector(
uint32_t x, uint32_t y,
uint32_t z, uint32_t w) {
std::array<uint32_t, 4> ids = {
m_module.constu32(x),
m_module.constu32(y),
m_module.constu32(z),
m_module.constu32(w) };
DxbcValue result;
result.type = DxbcValueType(DxbcScalarType::Uint32, 4);
result.valueId = m_module.constComposite(
this->defValueType(result.type),
ids.size(), ids.data());
return result;
}
void DxbcCodeGen::fnReturn() {
// TODO implement control flow
m_module.opReturn();
m_module.functionEnd();
}
DxbcPointer DxbcCodeGen::ptrTempReg(uint32_t regId) {
return m_rRegs.at(regId);
}
DxbcValue DxbcCodeGen::vecStore(
const DxbcValue& dst,
const DxbcValue& src,
DxbcComponentMask mask) {
DxbcValue DxbcCodeGen::opAbs(const DxbcValue& src) {
DxbcValue result;
result.type = src.type;
switch (src.type.componentType) {
case DxbcScalarType::Sint32:
case DxbcScalarType::Sint64:
result.valueId = m_module.opSAbs(
this->defValueType(result.type),
src.valueId);
break;
case DxbcScalarType::Uint32:
case DxbcScalarType::Uint64:
result.valueId = src.valueId;
break;
case DxbcScalarType::Float32:
case DxbcScalarType::Float64:
result.valueId = m_module.opFAbs(
this->defValueType(result.type),
src.valueId);
break;
}
return result;
}
DxbcValue DxbcCodeGen::opNeg(const DxbcValue& src) {
DxbcValue result;
result.type = src.type;
switch (src.type.componentType) {
case DxbcScalarType::Sint32:
case DxbcScalarType::Sint64:
case DxbcScalarType::Uint32:
case DxbcScalarType::Uint64:
result.valueId = m_module.opSNegate(
this->defValueType(result.type),
src.valueId);
break;
case DxbcScalarType::Float32:
case DxbcScalarType::Float64:
result.valueId = m_module.opFNegate(
this->defValueType(result.type),
src.valueId);
break;
}
return result;
}
DxbcValue DxbcCodeGen::regCast(
const DxbcValue& src,
const DxbcValueType& type) {
if (src.type.componentType == type.componentType)
return src;
DxbcValue result;
result.type = type;
result.valueId = m_module.opBitcast(
this->defValueType(result.type),
src.valueId);
return result;
}
DxbcValue DxbcCodeGen::regExtract(
const DxbcValue& src,
DxbcComponentMask mask) {
// TODO implement
}
DxbcValue DxbcCodeGen::regSwizzle(
const DxbcValue& src,
const DxbcComponentSwizzle& swizzle,
DxbcComponentMask mask) {
std::array<uint32_t, 4> indices;
uint32_t dstIndex = 0;
for (uint32_t i = 0; i < src.type.componentCount; i++) {
if (mask.test(i))
indices[dstIndex++] = swizzle[i];
}
bool isIdentitySwizzle = dstIndex == src.type.componentCount;
for (uint32_t i = 0; i < dstIndex && isIdentitySwizzle; i++)
isIdentitySwizzle &= indices[i] == i;
if (isIdentitySwizzle)
return src;
DxbcValue result;
result.type = DxbcValueType(src.type.componentType, dstIndex);
if (dstIndex == 1) {
result.valueId = m_module.opCompositeExtract(
this->defValueType(result.type),
src.valueId, 1, indices.data());
} else {
result.valueId = m_module.opVectorShuffle(
this->defValueType(result.type),
src.valueId, src.valueId,
dstIndex, indices.data());
}
return result;
}
DxbcValue DxbcCodeGen::regInsert(
const DxbcValue& dst,
const DxbcValue& src,
DxbcComponentMask mask) {
DxbcValue result;
result.type = dst.type;
@ -100,15 +241,15 @@ namespace dxvk {
void DxbcCodeGen::regStore(
const DxbcPointer& ptr,
const DxbcValue& val,
DxbcComponentMask mask) {
const DxbcPointer& ptr,
const DxbcValue& val,
DxbcComponentMask mask) {
if (ptr.type.valueType.componentCount != val.type.componentCount) {
// In case we write to only a part of the destination
// register, we need to load the previous value first
// and then update the given components.
DxbcValue tmp = this->regLoad(ptr);
tmp = this->vecStore(tmp, val, mask);
tmp = this->regInsert(tmp, val, mask);
m_module.opStore(ptr.valueId, tmp.valueId);
} else {
@ -195,4 +336,16 @@ namespace dxvk {
return typeId;
}
DxbcPointer DxbcCodeGen::defVar(
const DxbcValueType& type,
spv::StorageClass storageClass) {
DxbcPointer result;
result.type = DxbcPointerType(type, storageClass);
result.valueId = m_module.newVar(
this->defPointerType(result.type),
storageClass);
return result;
}
}

View File

@ -37,6 +37,12 @@ namespace dxvk {
virtual ~DxbcCodeGen();
/**
* \brief Declares temporary registers
* \param [in] n Number of temp registers
*/
void dclTemps(uint32_t n);
/**
* \brief Declares an interface variable
*
@ -54,10 +60,36 @@ namespace dxvk {
DxbcSystemValue sv) = 0;
/**
* \brief Declares temporary registers
* \param [in] n Number of temp registers
* \brief Defines 32-bit constant
*
* The constant will be declared as a 32-bit
* unsigned integer. Cast the resulting value
* to the required type.
* \param [in] v Constant value
* \returns The constant value ID
*/
void dclTemps(uint32_t n);
DxbcValue defConstScalar(uint32_t v);
/**
* \brief Defines 32-bit constant vector
*
* Defines a four-component vector of 32-bit
* unsigned integer values. Cast the resulting
* value to the required type as needed.
* \param [in] x First vector component
* \param [in] y Second vector component
* \param [in] z Third vector component
* \param [in] w Fourth vector component
* \returns The constant value ID
*/
DxbcValue defConstVector(
uint32_t x, uint32_t y,
uint32_t z, uint32_t w);
/**
* \brief Returns from function
*/
void fnReturn();
/**
* \brief Retrieves temporary register pointer
@ -69,42 +101,6 @@ namespace dxvk {
DxbcPointer ptrTempReg(
uint32_t regId);
/**
* \brief Writes to parts of a vector register
*
* Note that the source value must not have the
* same number of components as the write mask.
* \param [in] dst Destination value ID
* \param [in] src Source value ID
* \param [in] mask Write mask
* \returns New destination value ID
*/
DxbcValue vecStore(
const DxbcValue& dst,
const DxbcValue& src,
DxbcComponentMask mask);
/**
* \brief Loads register
*
* \param [in] ptr Register pointer
* \returns The register value ID
*/
DxbcValue regLoad(
const DxbcPointer& ptr);
/**
* \brief Stores register
*
* \param [in] ptr Register pointer
* \param [in] val Value ID to store
* \param [in] mask Write mask
*/
void regStore(
const DxbcPointer& ptr,
const DxbcValue& val,
DxbcComponentMask mask);
/**
* \brief Pointer to an interface variable
*
@ -113,9 +109,9 @@ namespace dxvk {
* \param [in] regId Register index
* \returns Register pointer
*/
virtual void ptrInterfaceVar(
DxbcOperandType regType,
uint32_t regId) = 0;
virtual DxbcPointer ptrInterfaceVar(
DxbcOperandType regType,
uint32_t regId) = 0;
/**
* \brief Pointer to an interface variable
@ -128,10 +124,93 @@ namespace dxvk {
* \param [in] index Array index
* \returns Register pointer
*/
virtual void ptrInterfaceVarIndexed(
DxbcOperandType regType,
uint32_t regId,
const DxbcValue& index) = 0;
virtual DxbcPointer ptrInterfaceVarIndexed(
DxbcOperandType regType,
uint32_t regId,
const DxbcValue& index) = 0;
DxbcValue opAbs(
const DxbcValue& src);
DxbcValue opNeg(
const DxbcValue& src);
/**
* \brief Casts register value to another type
*
* Type cast that does not change the bit pattern
* of the value. This is required as DXBC values
* are not statically typed, but SPIR-V is.
* \param [in] src Source value
* \param [in] type Destination type
* \returns Resulting register value
*/
DxbcValue regCast(
const DxbcValue& src,
const DxbcValueType& type);
/**
* \brief Extracts vector components
*
* Extracts the given set of components.
* \param [in] src Source vector
* \param [in] mask Component mask
* \returns Resulting register value
*/
DxbcValue regExtract(
const DxbcValue& src,
DxbcComponentMask mask);
/**
* \brief Swizzles a vector register
*
* Swizzles the vector and extracts
* the given set of vector components.
* \param [in] src Source vector to swizzle
* \param [in] swizzle The component swizzle
* \param [in] mask Components to extract
* \returns Resulting register value
*/
DxbcValue regSwizzle(
const DxbcValue& src,
const DxbcComponentSwizzle& swizzle,
DxbcComponentMask mask);
/**
* \brief Writes to parts of a vector register
*
* Note that the source value must have the same
* number of components as the write mask.
* \param [in] dst Destination value ID
* \param [in] src Source value ID
* \param [in] mask Write mask
* \returns New destination value ID
*/
DxbcValue regInsert(
const DxbcValue& dst,
const DxbcValue& src,
DxbcComponentMask mask);
/**
* \brief Loads register
*
* \param [in] ptr Register pointer
* \returns The register value ID
*/
DxbcValue regLoad(
const DxbcPointer& ptr);
/**
* \brief Stores register
*
* \param [in] ptr Register pointer
* \param [in] val Value ID to store
* \param [in] mask Write mask
*/
void regStore(
const DxbcPointer& ptr,
const DxbcValue& val,
DxbcComponentMask mask);
/**
* \brief Finalizes shader
@ -177,6 +256,10 @@ namespace dxvk {
uint32_t defPerVertexBlock();
DxbcPointer defVar(
const DxbcValueType& type,
spv::StorageClass storageClass);
};
}

View File

@ -3,9 +3,25 @@
namespace dxvk {
DxbcVsCodeGen::DxbcVsCodeGen() {
m_module.enableCapability(spv::CapabilityShader);
m_module.enableCapability(spv::CapabilityCullDistance);
m_module.enableCapability(spv::CapabilityClipDistance);
m_function = m_module.allocateId();
m_module.setDebugName(m_function, "vs_main");
m_module.functionBegin(
m_module.defVoidType(),
m_function,
m_module.defFunctionType(
m_module.defVoidType(), 0, nullptr),
spv::FunctionControlMaskNone);
m_module.opLabel(m_module.allocateId());
m_outPerVertex = m_module.newVar(
m_module.defPointerType(this->defPerVertexBlock(), spv::StorageClassOutput),
spv::StorageClassOutput);
m_entryPointInterfaces.push_back(m_outPerVertex);
m_module.setDebugName(m_outPerVertex, "vs_out");
}
@ -21,18 +37,79 @@ namespace dxvk {
uint32_t regDim,
DxbcComponentMask regMask,
DxbcSystemValue sv) {
switch (regType) {
case DxbcOperandType::Input: {
if (sv == DxbcSystemValue::None) {
if (m_vRegs.at(regId).valueId == 0) {
m_vRegs.at(regId) = this->defVar(
DxbcValueType(DxbcScalarType::Float32, 4),
spv::StorageClassInput);
m_module.setDebugName(m_vRegs.at(regId).valueId,
str::format("v", regId).c_str());
m_module.decorateLocation(
m_vRegs.at(regId).valueId, regId);
m_entryPointInterfaces.push_back(
m_vRegs.at(regId).valueId);
}
} else {
if (m_vRegsSv.at(regId).valueId == 0) {
m_vRegsSv.at(regId) = this->defVar(
DxbcValueType(DxbcScalarType::Float32, 4),
spv::StorageClassPrivate);
m_module.setDebugName(m_vRegsSv.at(regId).valueId,
str::format("sv", regId).c_str());
}
}
} break;
case DxbcOperandType::Output: {
if (m_oRegs.at(regId).valueId == 0) {
m_oRegs.at(regId) = this->defVar(
DxbcValueType(DxbcScalarType::Float32, 4),
spv::StorageClassOutput);
m_module.setDebugName(m_oRegs.at(regId).valueId,
str::format("o", regId).c_str());
m_module.decorateLocation(
m_oRegs.at(regId).valueId, regId);
m_entryPointInterfaces.push_back(
m_oRegs.at(regId).valueId);
}
if (sv != DxbcSystemValue::None) {
m_svOutputs.push_back(DxbcSvMapping {
regId, regMask, sv });
}
} break;
default:
throw DxvkError(str::format(
"DxbcVsCodeGen::dclInterfaceVar: Unhandled operand type: ",
regType));
}
}
void DxbcVsCodeGen::ptrInterfaceVar(
DxbcPointer DxbcVsCodeGen::ptrInterfaceVar(
DxbcOperandType regType,
uint32_t regId) {
switch (regType) {
case DxbcOperandType::Input:
return m_vRegsSv.at(regId).valueId != 0
? m_vRegsSv.at(regId)
: m_vRegs .at(regId);
case DxbcOperandType::Output:
return m_oRegs.at(regId);
default:
throw DxvkError(str::format(
"DxbcVsCodeGen::ptrInterfaceVar: Unhandled operand type: ",
regType));
}
}
void DxbcVsCodeGen::ptrInterfaceVarIndexed(
DxbcPointer DxbcVsCodeGen::ptrInterfaceVarIndexed(
DxbcOperandType regType,
uint32_t regId,
const DxbcValue& index) {
@ -43,6 +120,23 @@ namespace dxvk {
Rc<DxvkShader> DxbcVsCodeGen::finalize() {
m_module.functionBegin(
m_module.defVoidType(),
m_entryPointId,
m_module.defFunctionType(
m_module.defVoidType(), 0, nullptr),
spv::FunctionControlMaskNone);
m_module.opLabel(m_module.allocateId());
this->prepareSvInputs();
m_module.opFunctionCall(
m_module.defVoidType(),
m_function, 0, nullptr);
this->prepareSvOutputs();
m_module.opReturn();
m_module.functionEnd();
m_module.addEntryPoint(m_entryPointId,
spv::ExecutionModelVertex, "main",
m_entryPointInterfaces.size(),
@ -53,4 +147,49 @@ namespace dxvk {
m_module.compile(), 0, nullptr);
}
void DxbcVsCodeGen::prepareSvInputs() {
// TODO implement
}
void DxbcVsCodeGen::prepareSvOutputs() {
for (const auto& sv : m_svOutputs) {
DxbcValue val = this->regLoad(m_oRegs.at(sv.regId));
// val = this->regExtract(val, sv.regMask);
DxbcPointer dst;
switch (sv.sv) {
case DxbcSystemValue::Position:
dst = this->ptrBuiltInPosition();
break;
default:
Logger::err(str::format(
"DxbcVsCodeGen::prepareSvOutputs: Unsupported system value: ",
sv.sv));
}
if (dst.valueId != 0) {
// val = this->regCast(val, dst.type.valueType);
this->regStore(dst, val, DxbcComponentMask());
}
}
}
DxbcPointer DxbcVsCodeGen::ptrBuiltInPosition() {
const uint32_t memberId = m_module.constu32(PerVertex_Position);
DxbcPointer result;
result.type = DxbcPointerType(
DxbcValueType(DxbcScalarType::Float32, 4),
spv::StorageClassOutput);
result.valueId = m_module.opAccessChain(
this->defPointerType(result.type),
m_outPerVertex, 1, &memberId);
return result;
}
}

View File

@ -21,11 +21,11 @@ namespace dxvk {
DxbcComponentMask regMask,
DxbcSystemValue sv);
void ptrInterfaceVar(
DxbcPointer ptrInterfaceVar(
DxbcOperandType regType,
uint32_t regId);
void ptrInterfaceVarIndexed(
DxbcPointer ptrInterfaceVarIndexed(
DxbcOperandType regType,
uint32_t regId,
const DxbcValue& index);
@ -34,14 +34,21 @@ namespace dxvk {
private:
uint32_t m_function = 0;
uint32_t m_outPerVertex = 0;
std::array<DxbcPointer, 32> m_vRegs;
std::array<DxbcPointer, 32> m_vRegsSv;
std::array<DxbcPointer, 32> m_oRegs;
std::vector<DxbcSvMapping> m_svInputs;
std::vector<DxbcSvMapping> m_svOutputs;
void prepareSvInputs();
void prepareSvOutputs();
DxbcPointer ptrBuiltInPosition();
};
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <spirv/spirv.hpp>
#include <spirv/GLSL.std.450.hpp>
#include "spirv_include.h"

View File

@ -2,14 +2,21 @@
namespace dxvk {
SpirvModule:: SpirvModule() { }
SpirvModule::~SpirvModule() { }
SpirvModule:: SpirvModule() {
this->instImportGlsl450();
}
SpirvModule::~SpirvModule() {
}
SpirvCodeBuffer SpirvModule::compile() const {
SpirvCodeBuffer result;
result.putHeader(m_id);
result.append(m_capabilities);
result.append(m_instExt);
result.append(m_memoryModel);
result.append(m_entryPoints);
result.append(m_execModeInfo);
@ -413,6 +420,24 @@ namespace dxvk {
}
uint32_t SpirvModule::opAccessChain(
uint32_t resultType,
uint32_t composite,
uint32_t indexCount,
const uint32_t* indexArray) {
uint32_t resultId = this->allocateId();
m_code.putIns (spv::OpAccessChain, 4 + indexCount);
m_code.putWord(resultType);
m_code.putWord(resultId);
m_code.putWord(composite);
for (uint32_t i = 0; i < indexCount; i++)
m_code.putInt32(indexArray[i]);
return resultId;
}
uint32_t SpirvModule::opBitcast(
uint32_t resultType,
uint32_t operand) {
@ -484,6 +509,62 @@ namespace dxvk {
}
uint32_t SpirvModule::opSNegate(
uint32_t resultType,
uint32_t operand) {
uint32_t resultId = this->allocateId();
m_code.putIns (spv::OpSNegate, 4);
m_code.putWord(resultType);
m_code.putWord(resultId);
m_code.putWord(operand);
return resultId;
}
uint32_t SpirvModule::opFNegate(
uint32_t resultType,
uint32_t operand) {
uint32_t resultId = this->allocateId();
m_code.putIns (spv::OpFNegate, 4);
m_code.putWord(resultType);
m_code.putWord(resultId);
m_code.putWord(operand);
return resultId;
}
uint32_t SpirvModule::opSAbs(
uint32_t resultType,
uint32_t operand) {
uint32_t resultId = this->allocateId();
m_code.putIns (spv::OpExtInst, 6);
m_code.putWord(resultType);
m_code.putWord(resultId);
m_code.putWord(m_instExtGlsl450);
m_code.putWord(spv::GLSLstd450SAbs);
m_code.putWord(operand);
return resultId;
}
uint32_t SpirvModule::opFAbs(
uint32_t resultType,
uint32_t operand) {
uint32_t resultId = this->allocateId();
m_code.putIns (spv::OpExtInst, 6);
m_code.putWord(resultType);
m_code.putWord(resultId);
m_code.putWord(m_instExtGlsl450);
m_code.putWord(spv::GLSLstd450FAbs);
m_code.putWord(operand);
return resultId;
}
uint32_t SpirvModule::opFunctionCall(
uint32_t resultType,
uint32_t functionId,
@ -562,4 +643,14 @@ namespace dxvk {
return resultId;
}
void SpirvModule::instImportGlsl450() {
m_instExtGlsl450 = this->allocateId();
const char* name = "GLSL.std.450";
m_instExt.putIns (spv::OpExtInstImport, 2 + m_instExt.strLen(name));
m_instExt.putWord(m_instExtGlsl450);
m_instExt.putStr (name);
}
}

View File

@ -155,6 +155,12 @@ namespace dxvk {
void functionEnd();
uint32_t opAccessChain(
uint32_t resultType,
uint32_t composite,
uint32_t indexCount,
const uint32_t* indexArray);
uint32_t opBitcast(
uint32_t resultType,
uint32_t operand);
@ -179,6 +185,22 @@ namespace dxvk {
uint32_t indexCount,
const uint32_t* indexArray);
uint32_t opSNegate(
uint32_t resultType,
uint32_t operand);
uint32_t opFNegate(
uint32_t resultType,
uint32_t operand);
uint32_t opSAbs(
uint32_t resultType,
uint32_t operand);
uint32_t opFAbs(
uint32_t resultType,
uint32_t operand);
uint32_t opFunctionCall(
uint32_t resultType,
uint32_t functionId,
@ -200,9 +222,11 @@ namespace dxvk {
private:
uint32_t m_id = 1;
uint32_t m_id = 1;
uint32_t m_instExtGlsl450 = 0;
SpirvCodeBuffer m_capabilities;
SpirvCodeBuffer m_instExt;
SpirvCodeBuffer m_memoryModel;
SpirvCodeBuffer m_entryPoints;
SpirvCodeBuffer m_execModeInfo;
@ -217,6 +241,8 @@ namespace dxvk {
uint32_t argCount,
const uint32_t* argIds);
void instImportGlsl450();
};
}