mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-18 11:52:12 +01:00
[dxbc] Added bound checking for some texel fetch operations
This commit is contained in:
parent
043330132f
commit
bfac9eb737
@ -656,18 +656,14 @@ namespace dxvk {
|
||||
|
||||
// We do not know whether the image is going to be used as a color
|
||||
// image or a depth image yet, so we'll declare types for both.
|
||||
const uint32_t colorTypeId = m_module.defImageType(sampledTypeId,
|
||||
typeInfo.dim, 0, typeInfo.array, typeInfo.ms, typeInfo.sampled,
|
||||
spv::ImageFormatUnknown);
|
||||
|
||||
const uint32_t depthTypeId = m_module.defImageType(sampledTypeId,
|
||||
typeInfo.dim, 1, typeInfo.array, typeInfo.ms, typeInfo.sampled,
|
||||
const uint32_t imageTypeId = m_module.defImageType(sampledTypeId,
|
||||
typeInfo.dim, 2, typeInfo.array, typeInfo.ms, typeInfo.sampled,
|
||||
spv::ImageFormatUnknown);
|
||||
|
||||
// We'll declare the texture variable with the color type
|
||||
// and decide which one to use when the texture is sampled.
|
||||
const uint32_t resourcePtrType = m_module.defPointerType(
|
||||
colorTypeId, spv::StorageClassUniformConstant);
|
||||
imageTypeId, spv::StorageClassUniformConstant);
|
||||
|
||||
const uint32_t varId = m_module.newVar(resourcePtrType,
|
||||
spv::StorageClassUniformConstant);
|
||||
@ -682,7 +678,7 @@ namespace dxvk {
|
||||
uav.varId = varId;
|
||||
uav.sampledType = sampledType;
|
||||
uav.sampledTypeId = sampledTypeId;
|
||||
uav.imageTypeId = colorTypeId;
|
||||
uav.imageTypeId = imageTypeId;
|
||||
uav.structStride = 0;
|
||||
m_uavs.at(registerId) = uav;
|
||||
} else {
|
||||
@ -692,10 +688,15 @@ namespace dxvk {
|
||||
res.varId = varId;
|
||||
res.sampledType = sampledType;
|
||||
res.sampledTypeId = sampledTypeId;
|
||||
res.colorTypeId = colorTypeId;
|
||||
res.depthTypeId = depthTypeId;
|
||||
res.structStride = 0;
|
||||
res.imageTypeId = imageTypeId;
|
||||
res.colorTypeId = m_module.defImageType(sampledTypeId,
|
||||
typeInfo.dim, 0, typeInfo.array, typeInfo.ms, typeInfo.sampled,
|
||||
spv::ImageFormatUnknown);
|
||||
res.depthTypeId = m_module.defImageType(sampledTypeId,
|
||||
typeInfo.dim, 1, typeInfo.array, typeInfo.ms, typeInfo.sampled,
|
||||
spv::ImageFormatUnknown);
|
||||
m_textures.at(registerId) = res;
|
||||
res.structStride = 0;
|
||||
}
|
||||
|
||||
// Compute the DXVK binding slot index for the resource.
|
||||
@ -788,6 +789,7 @@ namespace dxvk {
|
||||
res.varId = varId;
|
||||
res.sampledType = sampledType;
|
||||
res.sampledTypeId = sampledTypeId;
|
||||
res.imageTypeId = resTypeId;
|
||||
res.colorTypeId = resTypeId;
|
||||
res.depthTypeId = resTypeId;
|
||||
res.structStride = resStride;
|
||||
@ -1802,19 +1804,13 @@ namespace dxvk {
|
||||
// (src0) The buffer register to query
|
||||
const DxbcBufferInfo bufferInfo = getBufferInfo(ins.src[0]);
|
||||
|
||||
// This instruction can only be used with t# and u#
|
||||
// registers, which are all mapped to texel buffers
|
||||
const uint32_t bufferId = m_module.opLoad(
|
||||
bufferInfo.typeId, bufferInfo.varId);
|
||||
|
||||
// We'll store this as a scalar unsigned integer
|
||||
DxbcRegisterValue result;
|
||||
result.type.ctype = DxbcScalarType::Uint32;
|
||||
result.type.ccount = 1;
|
||||
|
||||
DxbcRegisterValue result = emitQueryTexelBufferSize(ins.src[0]);
|
||||
const uint32_t typeId = getVectorTypeId(result.type);
|
||||
result.id = m_module.opImageQuerySize(typeId, bufferId);
|
||||
|
||||
// Adjust returned size if this is a raw or structured
|
||||
// buffer, as emitQueryTexelBufferSize only returns the
|
||||
// number of typed elements in the buffer.
|
||||
if (bufferInfo.type == DxbcResourceType::Raw) {
|
||||
result.id = m_module.opIMul(typeId,
|
||||
result.id, m_module.constu32(4));
|
||||
@ -1982,7 +1978,7 @@ namespace dxvk {
|
||||
// TODO support UAVs
|
||||
const uint32_t textureId = ins.src[1].idx[0].offset;
|
||||
const uint32_t imageId = m_module.opLoad(
|
||||
m_textures.at(textureId).colorTypeId,
|
||||
m_textures.at(textureId).imageTypeId,
|
||||
m_textures.at(textureId).varId);
|
||||
|
||||
// Read the exact LOD for the image query
|
||||
@ -2105,23 +2101,14 @@ namespace dxvk {
|
||||
|
||||
// Image type, which stores the image dimensions etc.
|
||||
const DxbcImageInfo imageType = m_textures.at(textureId).imageInfo;
|
||||
const DxbcRegMask coordArrayMask = getTexCoordMask(imageType);
|
||||
|
||||
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;
|
||||
default: throw DxvkError("DxbcCompiler: ld: Unsupported image dim");
|
||||
}
|
||||
}();
|
||||
|
||||
const DxbcRegMask coordArrayMask =
|
||||
DxbcRegMask::firstN(imageLayerDim + imageType.array);
|
||||
const uint32_t imageLayerDim = getTexLayerDim(imageType);
|
||||
const uint32_t imageCoordDim = getTexCoordDim(imageType);
|
||||
|
||||
// Load the texture coordinates. The last component
|
||||
// contains the LOD if the resource is an image.
|
||||
const DxbcRegisterValue coord = emitRegisterLoad(
|
||||
const DxbcRegisterValue address = emitRegisterLoad(
|
||||
ins.src[0], DxbcRegMask(true, true, true, true));
|
||||
|
||||
// Additional image operands. This will store
|
||||
@ -2141,16 +2128,41 @@ namespace dxvk {
|
||||
imageLayerDim, offsetIds.data());
|
||||
}
|
||||
|
||||
// The LOD is not present when reading from a buffer
|
||||
DxbcRegisterValue imageLod;
|
||||
imageLod.type = address.type;
|
||||
imageLod.id = 0;
|
||||
|
||||
if (imageType.dim != spv::DimBuffer) {
|
||||
imageLod = emitRegisterExtract(address,
|
||||
DxbcRegMask(false, false, false, true));
|
||||
|
||||
imageOperands.flags |= spv::ImageOperandsLodMask;
|
||||
imageOperands.sLod = emitRegisterExtract(coord,
|
||||
DxbcRegMask(false, false, false, true)).id;
|
||||
imageOperands.sLod = imageLod.id;
|
||||
}
|
||||
|
||||
// Load image variable, no sampler needed
|
||||
const uint32_t imageId = m_module.opLoad(
|
||||
m_textures.at(textureId).colorTypeId,
|
||||
m_textures.at(textureId).varId);
|
||||
// Extract coordinates from address
|
||||
const DxbcRegisterValue coord = emitRegisterExtract(address, coordArrayMask);
|
||||
|
||||
// Perform bounds checking. If the coordinates are
|
||||
// out of bounds, we return zero in all components.
|
||||
const DxbcRegisterValue resourceSize = imageType.dim != spv::DimBuffer
|
||||
? emitQueryTextureSize(ins.src[1], imageLod)
|
||||
: emitQueryTexelBufferSize(ins.src[1]);
|
||||
|
||||
uint32_t boundCheckId = m_module.opULessThan(
|
||||
m_module.defVectorType(m_module.defBoolType(), imageCoordDim),
|
||||
coord.id, resourceSize.id);
|
||||
|
||||
if (imageCoordDim > 1)
|
||||
boundCheckId = m_module.opAll(m_module.defBoolType(), boundCheckId);
|
||||
|
||||
const uint32_t boundCheckPassLabel = m_module.allocateId();
|
||||
const uint32_t boundCheckFailLabel = m_module.allocateId();
|
||||
const uint32_t boundCheckMergeLabel = m_module.allocateId();
|
||||
|
||||
m_module.opSelectionMerge(boundCheckMergeLabel, spv::SelectionControlMaskNone);
|
||||
m_module.opBranchConditional(boundCheckId, boundCheckPassLabel, boundCheckFailLabel);
|
||||
|
||||
// Reading a typed image or buffer view
|
||||
// always returns a four-component vector.
|
||||
@ -2158,10 +2170,36 @@ namespace dxvk {
|
||||
result.type.ctype = m_textures.at(textureId).sampledType;
|
||||
result.type.ccount = 4;
|
||||
|
||||
result.id = m_module.opImageFetch(
|
||||
// Bound check passed, load the texel
|
||||
m_module.opLabel(boundCheckPassLabel);
|
||||
|
||||
const uint32_t imageId = m_module.opLoad(
|
||||
m_textures.at(textureId).imageTypeId,
|
||||
m_textures.at(textureId).varId);
|
||||
|
||||
const uint32_t boundCheckPassId = m_module.opImageFetch(
|
||||
getVectorTypeId(result.type), imageId,
|
||||
emitRegisterExtract(coord, coordArrayMask).id,
|
||||
imageOperands);
|
||||
coord.id, imageOperands);
|
||||
|
||||
m_module.opBranch(boundCheckMergeLabel);
|
||||
m_module.opLabel (boundCheckFailLabel);
|
||||
|
||||
// Return zeroes if the bound check failed
|
||||
const uint32_t boundCheckFailId = emitBuildZeroVec(result.type).id;
|
||||
|
||||
m_module.opBranch(boundCheckMergeLabel);
|
||||
m_module.opLabel (boundCheckMergeLabel);
|
||||
|
||||
// Use a phi function to determine
|
||||
// which of the results to take.
|
||||
const std::array<SpirvPhiLabel, 2> phiOps = {{
|
||||
{ boundCheckPassId, boundCheckPassLabel },
|
||||
{ boundCheckFailId, boundCheckFailLabel },
|
||||
}};
|
||||
|
||||
result.id = m_module.opPhi(
|
||||
getVectorTypeId(result.type),
|
||||
phiOps.size(), phiOps.data());
|
||||
|
||||
// Swizzle components using the texture swizzle
|
||||
// and the destination operand's write mask
|
||||
@ -2248,7 +2286,7 @@ namespace dxvk {
|
||||
const uint32_t sampledImageId = m_module.opSampledImage(
|
||||
sampledImageType,
|
||||
m_module.opLoad(
|
||||
m_textures.at(textureId).colorTypeId,
|
||||
m_textures.at(textureId).imageTypeId,
|
||||
m_textures.at(textureId).varId),
|
||||
m_module.opLoad(
|
||||
m_samplers.at(samplerId).typeId,
|
||||
@ -2798,6 +2836,43 @@ 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<uint32_t, 4> 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) {
|
||||
@ -3412,6 +3487,55 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
DxbcRegisterValue DxbcCompiler::emitQueryTexelBufferSize(
|
||||
const DxbcRegister& resource) {
|
||||
// Load the texel buffer object. This cannot be used with
|
||||
// constant buffers or any other type of resource.
|
||||
const DxbcBufferInfo bufferInfo = getBufferInfo(resource);
|
||||
|
||||
const uint32_t bufferId = m_module.opLoad(
|
||||
bufferInfo.typeId, bufferInfo.varId);
|
||||
|
||||
// We'll store this as a scalar unsigned integer
|
||||
DxbcRegisterValue result;
|
||||
result.type.ctype = DxbcScalarType::Uint32;
|
||||
result.type.ccount = 1;
|
||||
result.id = m_module.opImageQuerySize(
|
||||
getVectorTypeId(result.type), bufferId);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcRegisterValue DxbcCompiler::emitQueryTextureLods(
|
||||
const DxbcRegister& resource) {
|
||||
const DxbcBufferInfo info = getBufferInfo(resource);
|
||||
|
||||
DxbcRegisterValue result;
|
||||
result.type.ctype = DxbcScalarType::Uint32;
|
||||
result.type.ccount = 1;
|
||||
result.id = m_module.opImageQueryLevels(
|
||||
getVectorTypeId(result.type),
|
||||
m_module.opLoad(info.typeId, info.varId));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcRegisterValue DxbcCompiler::emitQueryTextureSize(
|
||||
const DxbcRegister& resource,
|
||||
DxbcRegisterValue lod) {
|
||||
const DxbcBufferInfo info = getBufferInfo(resource);
|
||||
|
||||
DxbcRegisterValue result;
|
||||
result.type.ctype = DxbcScalarType::Uint32;
|
||||
result.type.ccount = getTexCoordDim(info.image);
|
||||
result.id = m_module.opImageQuerySizeLod(
|
||||
getVectorTypeId(result.type),
|
||||
m_module.opLoad(info.typeId, info.varId),
|
||||
lod.id);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxbcRegisterValue DxbcCompiler::emitCalcBufferIndexStructured(
|
||||
DxbcRegisterValue structId,
|
||||
DxbcRegisterValue structOffset,
|
||||
@ -4124,8 +4248,9 @@ namespace dxvk {
|
||||
switch (reg.type) {
|
||||
case DxbcOperandType::Resource: {
|
||||
DxbcBufferInfo result;
|
||||
result.image = m_textures.at(registerId).imageInfo;
|
||||
result.type = m_textures.at(registerId).type;
|
||||
result.typeId = m_textures.at(registerId).colorTypeId;
|
||||
result.typeId = m_textures.at(registerId).imageTypeId;
|
||||
result.varId = m_textures.at(registerId).varId;
|
||||
result.stride = m_textures.at(registerId).structStride;
|
||||
return result;
|
||||
@ -4133,6 +4258,7 @@ namespace dxvk {
|
||||
|
||||
case DxbcOperandType::UnorderedAccessView: {
|
||||
DxbcBufferInfo result;
|
||||
result.image = m_uavs.at(registerId).imageInfo;
|
||||
result.type = m_uavs.at(registerId).type;
|
||||
result.typeId = m_uavs.at(registerId).imageTypeId;
|
||||
result.varId = m_uavs.at(registerId).varId;
|
||||
@ -4142,6 +4268,7 @@ namespace dxvk {
|
||||
|
||||
case DxbcOperandType::ThreadGroupSharedMemory: {
|
||||
DxbcBufferInfo result;
|
||||
result.image = { spv::DimBuffer, 0, 0, 0 };
|
||||
result.type = m_gRegs.at(registerId).type;
|
||||
result.typeId = m_module.defPointerType(
|
||||
getScalarTypeId(DxbcScalarType::Uint32),
|
||||
@ -4157,19 +4284,24 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
DxbcRegMask DxbcCompiler::getTexCoordMask(const DxbcImageInfo& imageType) const {
|
||||
const uint32_t imageLayerDim = [&] {
|
||||
uint32_t DxbcCompiler::getTexLayerDim(const DxbcImageInfo& imageType) const {
|
||||
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: getTexCoordMask: Unsupported image dimension");
|
||||
default: throw DxvkError("DxbcCompiler: getTexLayerDim: Unsupported image dimension");
|
||||
}
|
||||
}
|
||||
}();
|
||||
|
||||
return DxbcRegMask::firstN(imageLayerDim + imageType.array);
|
||||
uint32_t DxbcCompiler::getTexCoordDim(const DxbcImageInfo& imageType) const {
|
||||
return getTexLayerDim(imageType) + imageType.array;
|
||||
}
|
||||
|
||||
|
||||
DxbcRegMask DxbcCompiler::getTexCoordMask(const DxbcImageInfo& imageType) const {
|
||||
return DxbcRegMask::firstN(getTexCoordDim(imageType));
|
||||
}
|
||||
|
||||
|
||||
|
@ -193,6 +193,7 @@ namespace dxvk {
|
||||
|
||||
|
||||
struct DxbcBufferInfo {
|
||||
DxbcImageInfo image;
|
||||
DxbcResourceType type;
|
||||
uint32_t typeId;
|
||||
uint32_t varId;
|
||||
@ -497,6 +498,12 @@ namespace dxvk {
|
||||
const float values[4],
|
||||
const DxbcRegMask& writeMask);
|
||||
|
||||
DxbcRegisterValue emitBuildZero(
|
||||
DxbcScalarType type);
|
||||
|
||||
DxbcRegisterValue emitBuildZeroVec(
|
||||
DxbcVectorType type);
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Generic register manipulation methods
|
||||
DxbcRegisterValue emitRegisterBitcast(
|
||||
@ -578,6 +585,18 @@ namespace dxvk {
|
||||
DxbcRegisterValue elementIndex,
|
||||
DxbcRegisterValue value);
|
||||
|
||||
//////////////////////////
|
||||
// Resource query methods
|
||||
DxbcRegisterValue emitQueryTexelBufferSize(
|
||||
const DxbcRegister& resource);
|
||||
|
||||
DxbcRegisterValue emitQueryTextureLods(
|
||||
const DxbcRegister& resource);
|
||||
|
||||
DxbcRegisterValue emitQueryTextureSize(
|
||||
const DxbcRegister& resource,
|
||||
DxbcRegisterValue lod);
|
||||
|
||||
////////////////////////////////////
|
||||
// Buffer index calculation methods
|
||||
DxbcRegisterValue emitCalcBufferIndexStructured(
|
||||
@ -694,6 +713,12 @@ namespace dxvk {
|
||||
DxbcBufferInfo getBufferInfo(
|
||||
const DxbcRegister& reg);
|
||||
|
||||
uint32_t getTexLayerDim(
|
||||
const DxbcImageInfo& imageType) const;
|
||||
|
||||
uint32_t getTexCoordDim(
|
||||
const DxbcImageInfo& imageType) const;
|
||||
|
||||
DxbcRegMask getTexCoordMask(
|
||||
const DxbcImageInfo& imageType) const;
|
||||
|
||||
|
@ -74,6 +74,7 @@ namespace dxvk {
|
||||
uint32_t varId = 0;
|
||||
DxbcScalarType sampledType = DxbcScalarType::Float32;
|
||||
uint32_t sampledTypeId = 0;
|
||||
uint32_t imageTypeId = 0;
|
||||
uint32_t colorTypeId = 0;
|
||||
uint32_t depthTypeId = 0;
|
||||
uint32_t structStride = 0;
|
||||
|
@ -212,7 +212,7 @@ namespace dxvk {
|
||||
/* Ld */
|
||||
{ 3, DxbcInstClass::TextureFetch, {
|
||||
{ DxbcOperandKind::DstReg, DxbcScalarType::Float32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Sint32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Uint32 },
|
||||
{ DxbcOperandKind::SrcReg, DxbcScalarType::Float32 },
|
||||
} },
|
||||
/* LdMs */
|
||||
|
@ -591,6 +591,32 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvModule::opAny(
|
||||
uint32_t resultType,
|
||||
uint32_t vector) {
|
||||
uint32_t resultId = this->allocateId();
|
||||
|
||||
m_code.putIns (spv::OpAny, 4);
|
||||
m_code.putWord(resultType);
|
||||
m_code.putWord(resultId);
|
||||
m_code.putWord(vector);
|
||||
return resultId;
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvModule::opAll(
|
||||
uint32_t resultType,
|
||||
uint32_t vector) {
|
||||
uint32_t resultId = this->allocateId();
|
||||
|
||||
m_code.putIns (spv::OpAll, 4);
|
||||
m_code.putWord(resultType);
|
||||
m_code.putWord(resultId);
|
||||
m_code.putWord(vector);
|
||||
return resultId;
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvModule::opAtomicLoad(
|
||||
uint32_t resultType,
|
||||
uint32_t pointer,
|
||||
@ -2410,6 +2436,25 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvModule::opPhi(
|
||||
uint32_t resultType,
|
||||
uint32_t sourceCount,
|
||||
const SpirvPhiLabel* sourceLabels) {
|
||||
uint32_t resultId = this->allocateId();
|
||||
|
||||
m_code.putIns (spv::OpPhi, 3 + 2 * sourceCount);
|
||||
m_code.putWord(resultType);
|
||||
m_code.putWord(resultId);
|
||||
|
||||
for (uint32_t i = 0; i < sourceCount; i++) {
|
||||
m_code.putWord(sourceLabels[i].varId);
|
||||
m_code.putWord(sourceLabels[i].labelId);
|
||||
}
|
||||
|
||||
return resultId;
|
||||
}
|
||||
|
||||
|
||||
void SpirvModule::opReturn() {
|
||||
m_code.putIns (spv::OpReturn, 1);
|
||||
}
|
||||
|
@ -4,6 +4,11 @@
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct SpirvPhiLabel {
|
||||
uint32_t varId = 0;
|
||||
uint32_t labelId = 0;
|
||||
};
|
||||
|
||||
struct SpirvSwitchCaseLabel {
|
||||
uint32_t literal = 0;
|
||||
uint32_t labelId = 0;
|
||||
@ -250,6 +255,14 @@ namespace dxvk {
|
||||
uint32_t indexCount,
|
||||
const uint32_t* indexArray);
|
||||
|
||||
uint32_t opAny(
|
||||
uint32_t resultType,
|
||||
uint32_t vector);
|
||||
|
||||
uint32_t opAll(
|
||||
uint32_t resultType,
|
||||
uint32_t vector);
|
||||
|
||||
uint32_t opAtomicLoad(
|
||||
uint32_t resultType,
|
||||
uint32_t pointer,
|
||||
@ -852,6 +865,10 @@ namespace dxvk {
|
||||
uint32_t caseCount,
|
||||
const SpirvSwitchCaseLabel* caseLabels);
|
||||
|
||||
uint32_t opPhi(
|
||||
uint32_t resultType,
|
||||
uint32_t sourceCount,
|
||||
const SpirvPhiLabel* sourceLabels);
|
||||
|
||||
void opReturn();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user