mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-18 02:52:10 +01:00
[dxbc] Implemented input mapping + sample controls
Input variables are now copied into a temporary array, which allows dynamic indexing and which also allows us to use system values that are mapped to input registers in DXBC. This breaks geometry shaders for now, however.
This commit is contained in:
parent
109ce0a695
commit
2e4275649e
@ -339,14 +339,14 @@ namespace dxvk {
|
||||
// Avoid declaring the same variable multiple times.
|
||||
// This may happen when multiple system values are
|
||||
// mapped to different parts of the same register.
|
||||
if (m_vRegs.at(regIdx) == 0) {
|
||||
if (m_vRegs.at(regIdx) == 0 && sv == DxbcSystemValue::None) {
|
||||
DxbcRegisterInfo info;
|
||||
info.type.ctype = DxbcScalarType::Float32;
|
||||
info.type.ccount = 4;
|
||||
info.type.alength = regDim;
|
||||
info.sclass = spv::StorageClassInput;
|
||||
|
||||
uint32_t varId = this->emitNewVariable(info);
|
||||
const uint32_t varId = emitNewVariable(info);
|
||||
|
||||
m_module.decorateLocation(varId, regIdx);
|
||||
m_module.setDebugName(varId, str::format("v", regIdx).c_str());
|
||||
@ -370,12 +370,10 @@ namespace dxvk {
|
||||
if (im == DxbcInterpolationMode::LinearSample
|
||||
|| im == DxbcInterpolationMode::LinearNoPerspectiveSample)
|
||||
m_module.decorate(varId, spv::DecorationSample);
|
||||
}
|
||||
|
||||
// Add a new system value mapping if needed
|
||||
// TODO declare SV if necessary
|
||||
if (sv != DxbcSystemValue::None)
|
||||
} else if (sv != DxbcSystemValue::None) {
|
||||
// Add a new system value mapping if needed
|
||||
m_vMappings.push_back({ regIdx, regMask, sv });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -406,7 +404,6 @@ namespace dxvk {
|
||||
|
||||
|
||||
// Add a new system value mapping if needed
|
||||
// TODO declare SV if necessary
|
||||
if (sv != DxbcSystemValue::None)
|
||||
m_oMappings.push_back({ regIdx, regMask, sv });
|
||||
}
|
||||
@ -533,14 +530,7 @@ namespace dxvk {
|
||||
const uint32_t sampledTypeId = getScalarTypeId(sampledType);
|
||||
|
||||
// Declare the resource type
|
||||
struct ImageTypeInfo {
|
||||
spv::Dim dim;
|
||||
uint32_t array;
|
||||
uint32_t ms;
|
||||
uint32_t sampled;
|
||||
};
|
||||
|
||||
const ImageTypeInfo typeInfo = [resourceType] () -> ImageTypeInfo {
|
||||
const DxbcImageInfo typeInfo = [resourceType] () -> DxbcImageInfo {
|
||||
switch (resourceType) {
|
||||
case DxbcResourceDim::Texture1D: return { spv::Dim1D, 0, 0, 1 };
|
||||
case DxbcResourceDim::Texture1DArr: return { spv::Dim1D, 1, 0, 1 };
|
||||
@ -574,6 +564,7 @@ namespace dxvk {
|
||||
m_module.setDebugName(varId,
|
||||
str::format("t", registerId).c_str());
|
||||
|
||||
m_textures.at(registerId).imageInfo = typeInfo;
|
||||
m_textures.at(registerId).varId = varId;
|
||||
m_textures.at(registerId).sampledType = sampledType;
|
||||
m_textures.at(registerId).sampledTypeId = sampledTypeId;
|
||||
@ -611,7 +602,14 @@ namespace dxvk {
|
||||
}
|
||||
}();
|
||||
|
||||
m_gs.inputPrimitive = ins.controls.primitive;
|
||||
m_module.setExecutionMode(m_entryPointId, mode);
|
||||
|
||||
const uint32_t vertexCount
|
||||
= primitiveVertexCount(m_gs.inputPrimitive);
|
||||
|
||||
emitDclInputArray(vertexCount);
|
||||
emitGsInitBuiltins(vertexCount);
|
||||
}
|
||||
|
||||
|
||||
@ -1267,7 +1265,7 @@ namespace dxvk {
|
||||
void DxbcCompiler::emitGeometryEmit(const DxbcShaderInstruction& ins) {
|
||||
switch (ins.op) {
|
||||
case DxbcOpcode::Emit: {
|
||||
emitGsOutputSetup();
|
||||
emitOutputSetup(0);
|
||||
m_module.opEmitVertex();
|
||||
} break;
|
||||
|
||||
@ -1299,9 +1297,26 @@ namespace dxvk {
|
||||
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;
|
||||
|
||||
// FIXME implement properly
|
||||
DxbcRegMask coordArrayMask(true, true, true, true);
|
||||
DxbcRegMask coordLayerMask(true, true, true, true);
|
||||
const uint32_t imageLayerDim = [&] {
|
||||
switch (imageType.dim) {
|
||||
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 =
|
||||
DxbcRegMask::firstN(imageLayerDim + imageType.array);
|
||||
|
||||
const DxbcRegMask coordLayerMask =
|
||||
DxbcRegMask::firstN(imageLayerDim);
|
||||
|
||||
// Load the texture coordinates. SPIR-V allows these
|
||||
// to be float4 even if not all components are used.
|
||||
@ -1346,7 +1361,19 @@ namespace dxvk {
|
||||
// Accumulate additional image operands. These are
|
||||
// not part of the actual operand token in SPIR-V.
|
||||
SpirvImageOperands imageOperands;
|
||||
// TODO implement sample controls
|
||||
|
||||
if (ins.sampleControls.u != 0 || ins.sampleControls.v != 0 || ins.sampleControls.w != 0) {
|
||||
const std::array<uint32_t, 3> offsetIds = {
|
||||
imageLayerDim >= 1 ? m_module.constu32(ins.sampleControls.u) : 0,
|
||||
imageLayerDim >= 2 ? m_module.constu32(ins.sampleControls.v) : 0,
|
||||
imageLayerDim >= 3 ? m_module.constu32(ins.sampleControls.w) : 0,
|
||||
};
|
||||
|
||||
imageOperands.flags |= spv::ImageOperandsConstOffsetMask;
|
||||
imageOperands.sConstOffset = m_module.constComposite(
|
||||
getVectorTypeId({ DxbcScalarType::Sint32, imageLayerDim }),
|
||||
imageLayerDim, offsetIds.data());
|
||||
}
|
||||
|
||||
// Sampling an image always returns a four-component
|
||||
// vector, whereas depth-compare ops return a scalar.
|
||||
@ -1886,25 +1913,20 @@ namespace dxvk {
|
||||
result.type.ctype = DxbcScalarType::Float32;
|
||||
result.type.ccount = 4;
|
||||
|
||||
if (operand.idxDim == 1) {
|
||||
// TODO add support for relative register index
|
||||
result.id = m_vRegs.at(operand.idx[0].offset);
|
||||
return result;
|
||||
} else {
|
||||
// TODO add support for relative register index
|
||||
const DxbcRegisterValue vertexId = emitIndexLoad(operand.idx[0]);
|
||||
std::array<uint32_t, 2> indices = { 0, 0 };
|
||||
|
||||
for (uint32_t i = 0; i < operand.idxDim; i++)
|
||||
indices.at(i) = emitIndexLoad(operand.idx[i]).id;
|
||||
|
||||
DxbcRegisterInfo info;
|
||||
info.type.ctype = result.type.ctype;
|
||||
info.type.ccount = result.type.ccount;
|
||||
info.type.alength = 0;
|
||||
info.sclass = spv::StorageClassInput;
|
||||
DxbcRegisterInfo info;
|
||||
info.type.ctype = result.type.ctype;
|
||||
info.type.ccount = result.type.ccount;
|
||||
info.type.alength = 0;
|
||||
info.sclass = spv::StorageClassPrivate;
|
||||
|
||||
result.id = m_module.opAccessChain(
|
||||
getPointerTypeId(info),
|
||||
m_vRegs.at(operand.idx[1].offset),
|
||||
1, &vertexId.id);
|
||||
}
|
||||
result.id = m_module.opAccessChain(
|
||||
getPointerTypeId(info), m_vArray,
|
||||
operand.idxDim, indices.data());
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -2148,22 +2170,80 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitVsInputSetup() {
|
||||
void DxbcCompiler::emitInputSetup(uint32_t vertexCount) {
|
||||
const uint32_t vecTypeId = m_module.defVectorType(
|
||||
m_module.defFloatType(32), 4);
|
||||
const uint32_t ptrTypeId = m_module.defPointerType(
|
||||
vecTypeId, spv::StorageClassPrivate);
|
||||
|
||||
// Copy all defined user input registers into the array
|
||||
for (uint32_t i = 0; i < m_vRegs.size(); i++) {
|
||||
if (m_vRegs.at(i) != 0) {
|
||||
const uint32_t registerId = m_module.constu32(i);
|
||||
m_module.opStore(
|
||||
m_module.opAccessChain(ptrTypeId, m_vArray, 1, ®isterId),
|
||||
m_module.opLoad(vecTypeId, m_vRegs.at(i)));
|
||||
}
|
||||
}
|
||||
|
||||
// Copy all system value registers into the array,
|
||||
// preserving any previously written contents.
|
||||
for (const DxbcSvMapping& svMapping : m_vMappings) {
|
||||
const uint32_t registerId = m_module.constu32(svMapping.regId);
|
||||
|
||||
DxbcRegisterPointer ptrOut;
|
||||
ptrOut.type.ctype = DxbcScalarType::Float32;
|
||||
ptrOut.type.ccount = 4;
|
||||
ptrOut.id = m_module.opAccessChain(ptrTypeId,
|
||||
m_vArray, 1, ®isterId);
|
||||
|
||||
switch (svMapping.sv) {
|
||||
case DxbcSystemValue::Position: {
|
||||
if (m_version.type() == DxbcProgramType::PixelShader) {
|
||||
DxbcRegisterPointer ptrIn;
|
||||
ptrIn.type.ctype = DxbcScalarType::Float32;
|
||||
ptrIn.type.ccount = 4;
|
||||
ptrIn.id = m_ps.builtinFragCoord;
|
||||
|
||||
emitValueStore(ptrOut,
|
||||
emitRegisterExtract(
|
||||
emitValueLoad(ptrIn),
|
||||
svMapping.regMask),
|
||||
svMapping.regMask);
|
||||
} else {
|
||||
Logger::warn(str::format(
|
||||
"DxbcCompiler: SV_POSITION input not yet supported: ",
|
||||
m_version.type()));
|
||||
}
|
||||
} break;
|
||||
|
||||
case DxbcSystemValue::VertexId: {
|
||||
if (m_version.type() == DxbcProgramType::VertexShader) {
|
||||
DxbcRegisterPointer ptrIn;
|
||||
ptrIn.type.ctype = DxbcScalarType::Uint32;
|
||||
ptrIn.type.ccount = 1;
|
||||
ptrIn.id = m_vs.builtinVertexId;
|
||||
|
||||
emitValueStore(ptrOut,
|
||||
emitValueLoad(ptrIn),
|
||||
svMapping.regMask);
|
||||
} else {
|
||||
Logger::warn(str::format(
|
||||
"DxbcCompiler: SV_VERTEXID input not yet supported: ",
|
||||
m_version.type()));
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
Logger::warn(str::format(
|
||||
"DxbcCompiler: Unhandled sv input: ",
|
||||
svMapping.sv));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitGsInputSetup() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitPsInputSetup() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitVsOutputSetup() {
|
||||
void DxbcCompiler::emitOutputSetup(uint32_t vertexCount) {
|
||||
for (const DxbcSvMapping& svMapping : m_oMappings) {
|
||||
switch (svMapping.sv) {
|
||||
case DxbcSystemValue::Position: {
|
||||
@ -2193,52 +2273,39 @@ namespace dxvk {
|
||||
|
||||
default:
|
||||
Logger::warn(str::format(
|
||||
"DxbcCompiler: Unhandled vertex sv output: ",
|
||||
"DxbcCompiler: Unhandled sv output: ",
|
||||
svMapping.sv));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitGsOutputSetup() {
|
||||
for (const DxbcSvMapping& svMapping : m_oMappings) {
|
||||
switch (svMapping.sv) {
|
||||
case DxbcSystemValue::Position: {
|
||||
DxbcRegisterInfo info;
|
||||
info.type.ctype = DxbcScalarType::Float32;
|
||||
info.type.ccount = 4;
|
||||
info.type.alength = 0;
|
||||
info.sclass = spv::StorageClassOutput;
|
||||
|
||||
const uint32_t ptrTypeId = getPointerTypeId(info);
|
||||
const uint32_t memberId = m_module.constu32(PerVertex_Position);
|
||||
|
||||
DxbcRegisterPointer dstPtr;
|
||||
dstPtr.type.ctype = info.type.ctype;
|
||||
dstPtr.type.ccount = info.type.ccount;
|
||||
dstPtr.id = m_module.opAccessChain(
|
||||
ptrTypeId, m_perVertexOut, 1, &memberId);
|
||||
|
||||
DxbcRegisterPointer srcPtr;
|
||||
srcPtr.type.ctype = info.type.ctype;
|
||||
srcPtr.type.ccount = info.type.ccount;
|
||||
srcPtr.id = m_oRegs.at(svMapping.regId);
|
||||
|
||||
emitValueStore(dstPtr, emitValueLoad(srcPtr),
|
||||
DxbcRegMask(true, true, true, true));
|
||||
} break;
|
||||
|
||||
default:
|
||||
Logger::warn(str::format(
|
||||
"DxbcCompiler: Unhandled vertex sv output: ",
|
||||
svMapping.sv));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitPsOutputSetup() {
|
||||
void DxbcCompiler::emitVsInitBuiltins() {
|
||||
m_vs.builtinVertexId = emitNewBuiltinVariable({
|
||||
{ DxbcScalarType::Uint32, 1, 0 },
|
||||
spv::StorageClassInput },
|
||||
spv::BuiltInVertexIndex, // TODO test
|
||||
"vs_vertex_index");
|
||||
|
||||
m_vs.builtinInstanceId = emitNewBuiltinVariable({
|
||||
{ DxbcScalarType::Uint32, 1, 0 },
|
||||
spv::StorageClassInput },
|
||||
spv::BuiltInInstanceIndex, // TODO test
|
||||
"vs_instance_index");
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitGsInitBuiltins(uint32_t vertexCount) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitPsInitBuiltins() {
|
||||
m_ps.builtinFragCoord = emitNewBuiltinVariable({
|
||||
{ DxbcScalarType::Float32, 4, 0 },
|
||||
spv::StorageClassInput },
|
||||
spv::BuiltInFragCoord,
|
||||
"ps_frag_coord");
|
||||
}
|
||||
|
||||
|
||||
@ -2258,6 +2325,10 @@ namespace dxvk {
|
||||
m_entryPointInterfaces.push_back(m_perVertexOut);
|
||||
m_module.setDebugName(m_perVertexOut, "vs_vertex_out");
|
||||
|
||||
// Standard input array
|
||||
emitDclInputArray(0);
|
||||
emitVsInitBuiltins();
|
||||
|
||||
// Main function of the vertex shader
|
||||
m_vs.functionId = m_module.allocateId();
|
||||
m_module.setDebugName(m_vs.functionId, "vs_main");
|
||||
@ -2332,6 +2403,10 @@ namespace dxvk {
|
||||
}
|
||||
}
|
||||
|
||||
// Standard input array
|
||||
emitDclInputArray(0);
|
||||
emitPsInitBuiltins();
|
||||
|
||||
// Main function of the pixel shader
|
||||
m_ps.functionId = m_module.allocateId();
|
||||
m_module.setDebugName(m_ps.functionId, "ps_main");
|
||||
@ -2347,16 +2422,17 @@ namespace dxvk {
|
||||
|
||||
|
||||
void DxbcCompiler::emitVsFinalize() {
|
||||
this->emitVsInputSetup();
|
||||
this->emitInputSetup(0);
|
||||
m_module.opFunctionCall(
|
||||
m_module.defVoidType(),
|
||||
m_vs.functionId, 0, nullptr);
|
||||
this->emitVsOutputSetup();
|
||||
this->emitOutputSetup(0);
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitGsFinalize() {
|
||||
this->emitGsInputSetup();
|
||||
this->emitInputSetup(
|
||||
primitiveVertexCount(m_gs.inputPrimitive));
|
||||
m_module.opFunctionCall(
|
||||
m_module.defVoidType(),
|
||||
m_gs.functionId, 0, nullptr);
|
||||
@ -2366,11 +2442,41 @@ namespace dxvk {
|
||||
|
||||
|
||||
void DxbcCompiler::emitPsFinalize() {
|
||||
this->emitPsInputSetup();
|
||||
this->emitInputSetup(0);
|
||||
m_module.opFunctionCall(
|
||||
m_module.defVoidType(),
|
||||
m_ps.functionId, 0, nullptr);
|
||||
this->emitPsOutputSetup();
|
||||
this->emitOutputSetup(0);
|
||||
}
|
||||
|
||||
|
||||
void DxbcCompiler::emitDclInputArray(uint32_t vertexCount) {
|
||||
DxbcArrayType info;
|
||||
info.ctype = DxbcScalarType::Float32;
|
||||
info.ccount = 4;
|
||||
info.alength = DxbcMaxInterfaceRegs;
|
||||
|
||||
// Define the array type. This will be two-dimensional
|
||||
// in some shaders, with the outer index representing
|
||||
// the vertex ID within an invocation.
|
||||
uint32_t arrayTypeId = getArrayTypeId(info);
|
||||
|
||||
if (vertexCount != 0) {
|
||||
arrayTypeId = m_module.defArrayType(
|
||||
arrayTypeId, m_module.constu32(vertexCount));
|
||||
}
|
||||
|
||||
// Define the actual variable. Note that this is private
|
||||
// because we will copy input registers and some system
|
||||
// variables to the array during the setup phase.
|
||||
const uint32_t ptrTypeId = m_module.defPointerType(
|
||||
arrayTypeId, spv::StorageClassPrivate);
|
||||
|
||||
const uint32_t varId = m_module.newVar(
|
||||
ptrTypeId, spv::StorageClassPrivate);
|
||||
|
||||
m_module.setDebugName(varId, "shader_in");
|
||||
m_vArray = varId;
|
||||
}
|
||||
|
||||
|
||||
@ -2380,6 +2486,20 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxbcCompiler::emitNewBuiltinVariable(
|
||||
const DxbcRegisterInfo& info,
|
||||
spv::BuiltIn builtIn,
|
||||
const char* name) {
|
||||
const uint32_t varId = emitNewVariable(info);
|
||||
|
||||
m_module.decorateBuiltIn(varId, builtIn);
|
||||
m_module.setDebugName(varId, name);
|
||||
|
||||
m_entryPointInterfaces.push_back(varId);
|
||||
return varId;
|
||||
}
|
||||
|
||||
|
||||
DxbcCfgBlock* DxbcCompiler::cfgFindLoopBlock() {
|
||||
for (auto cur = m_controlFlowBlocks.rbegin();
|
||||
cur != m_controlFlowBlocks.rend(); cur++) {
|
||||
|
@ -91,6 +91,9 @@ namespace dxvk {
|
||||
*/
|
||||
struct DxbcCompilerVsPart {
|
||||
uint32_t functionId = 0;
|
||||
|
||||
uint32_t builtinVertexId = 0;
|
||||
uint32_t builtinInstanceId = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -111,6 +114,9 @@ namespace dxvk {
|
||||
struct DxbcCompilerPsPart {
|
||||
uint32_t functionId = 0;
|
||||
|
||||
uint32_t builtinFragCoord = 0;
|
||||
uint32_t builtinDepth = 0;
|
||||
|
||||
std::array<DxbcVectorType, DxbcMaxInterfaceRegs> oTypes;
|
||||
};
|
||||
|
||||
@ -455,17 +461,16 @@ namespace dxvk {
|
||||
const DxbcRegister& reg,
|
||||
DxbcRegisterValue value);
|
||||
|
||||
/////////////////////////////
|
||||
// Input preparation methods
|
||||
void emitVsInputSetup();
|
||||
void emitGsInputSetup();
|
||||
void emitPsInputSetup();
|
||||
////////////////////////////
|
||||
// Input/output preparation
|
||||
void emitInputSetup(uint32_t vertexCount);
|
||||
void emitOutputSetup(uint32_t vertexCount);
|
||||
|
||||
//////////////////////////////
|
||||
// Output preparation methods
|
||||
void emitVsOutputSetup();
|
||||
void emitGsOutputSetup();
|
||||
void emitPsOutputSetup();
|
||||
////////////////////////////////////////
|
||||
// Builtin variable declaration methods
|
||||
void emitVsInitBuiltins();
|
||||
void emitGsInitBuiltins(uint32_t vertexCount);
|
||||
void emitPsInitBuiltins();
|
||||
|
||||
/////////////////////////////////
|
||||
// Shader initialization methods
|
||||
@ -479,11 +484,21 @@ namespace dxvk {
|
||||
void emitGsFinalize();
|
||||
void emitPsFinalize();
|
||||
|
||||
//////////////
|
||||
// Misc stuff
|
||||
void emitDclInputArray(
|
||||
uint32_t vertexCount);
|
||||
|
||||
///////////////////////////////
|
||||
// Variable definition methods
|
||||
uint32_t emitNewVariable(
|
||||
const DxbcRegisterInfo& info);
|
||||
|
||||
uint32_t emitNewBuiltinVariable(
|
||||
const DxbcRegisterInfo& info,
|
||||
spv::BuiltIn builtIn,
|
||||
const char* name);
|
||||
|
||||
/////////////////////////////////////
|
||||
// Control flow block search methods
|
||||
DxbcCfgBlock* cfgFindLoopBlock();
|
||||
|
@ -51,6 +51,17 @@ namespace dxvk {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Image type information
|
||||
*/
|
||||
struct DxbcImageInfo {
|
||||
spv::Dim dim = spv::Dim1D;
|
||||
uint32_t array = 0;
|
||||
uint32_t ms = 0;
|
||||
uint32_t sampled = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Shader resource binding
|
||||
*
|
||||
@ -58,11 +69,12 @@ namespace dxvk {
|
||||
* and associated type IDs.
|
||||
*/
|
||||
struct DxbcShaderResource {
|
||||
uint32_t varId = 0;
|
||||
DxbcScalarType sampledType = DxbcScalarType::Float32;
|
||||
uint32_t sampledTypeId = 0;
|
||||
uint32_t colorTypeId = 0;
|
||||
uint32_t depthTypeId = 0;
|
||||
DxbcImageInfo imageInfo;
|
||||
uint32_t varId = 0;
|
||||
DxbcScalarType sampledType = DxbcScalarType::Float32;
|
||||
uint32_t sampledTypeId = 0;
|
||||
uint32_t colorTypeId = 0;
|
||||
uint32_t depthTypeId = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -128,6 +140,10 @@ namespace dxvk {
|
||||
bool operator == (const DxbcRegMask& other) const { return m_mask == other.m_mask; }
|
||||
bool operator != (const DxbcRegMask& other) const { return m_mask != other.m_mask; }
|
||||
|
||||
static DxbcRegMask firstN(uint32_t n) {
|
||||
return DxbcRegMask(n >= 1, n >= 2, n >= 3, n >= 4);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint8_t m_mask = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user