[spirv] Support Load methods that take Status arg. (#905)

This commit is contained in:
Ehsan 2017-12-12 17:38:30 -05:00 коммит произвёл GitHub
Родитель 674aa26115
Коммит 1d4509f35d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 375 добавлений и 99 удалений

Просмотреть файл

@ -1611,6 +1611,8 @@ Since Buffers are represented as ``OpTypeImage`` with ``Sampled`` set to 1
operation. The return value of ``OpImageFetch`` is always a four-component operation. The return value of ``OpImageFetch`` is always a four-component
vector; so proper additional instructions are generated to truncate the vector vector; so proper additional instructions are generated to truncate the vector
and return the desired number of elements. and return the desired number of elements.
If an output unsigned integer ``status`` argument is present, ``OpImageSparseFetch``
is used instead. The resulting SPIR-V ``Residency Code`` will be written to ``status``.
``operator[]`` ``operator[]``
++++++++++++++ ++++++++++++++
@ -1628,7 +1630,8 @@ Since Buffers are represented as ``OpTypeImage`` with dimension of ``Buffer``,
+++++++++++ +++++++++++
Since RWBuffers are represented as ``OpTypeImage`` with ``Sampled`` set to 2 Since RWBuffers are represented as ``OpTypeImage`` with ``Sampled`` set to 2
(meaning to be used without a sampler), ``OpImageRead`` is used to perform this (meaning to be used without a sampler), ``OpImageRead`` is used to perform this
operation. operation. If an output unsigned integer ``status`` argument is present, ``OpImageSparseRead``
is used instead. The resulting SPIR-V ``Residency Code`` will be written to ``status``.
``operator[]`` ``operator[]``
++++++++++++++ ++++++++++++++
@ -1780,8 +1783,8 @@ for that texture type.
Common texture methods Common texture methods
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
``.Sample(sampler, location[, offset])`` ``.Sample(sampler, location[, offset][, clamp][, Status])``
++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Not available to ``Texture2DMS`` and ``Texture2DMSArray``. Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
@ -1790,12 +1793,15 @@ since texture types are represented as ``OpTypeImage``. An ``OpSampledImage`` is
created based on the ``sampler`` passed to the function. The resulting sampled created based on the ``sampler`` passed to the function. The resulting sampled
image and the ``location`` passed to the function are used as arguments to image and the ``location`` passed to the function are used as arguments to
``OpImageSampleImplicitLod``, with the optional ``offset`` tranlated into ``OpImageSampleImplicitLod``, with the optional ``offset`` tranlated into
addtional SPIR-V image operands ``ConstOffset`` or ``Offset`` on it. addtional SPIR-V image operands ``ConstOffset`` or ``Offset`` on it. The optional
``clamp`` argument will be translated to the ``MinLod`` image operand.
The overload with the status parameter are not supported. If an output unsigned integer ``status`` argument is present,
``OpImageSparseSampleImplicitLod`` is used instead. The resulting SPIR-V
``Residency Code`` will be written to ``status``.
``.SampleLevel(sampler, location, lod[, offset])`` ``.SampleLevel(sampler, location, lod[, offset][, Status])``
++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Not available to ``Texture2DMS`` and ``Texture2DMSArray``. Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
@ -1807,21 +1813,26 @@ is attached to the instruction as an SPIR-V image operands ``Lod``. The optional
``offset`` is also tranlated into addtional SPIR-V image operands ``ConstOffset`` ``offset`` is also tranlated into addtional SPIR-V image operands ``ConstOffset``
or ``Offset`` on it. or ``Offset`` on it.
The overload with the status parameter are not supported. If an output unsigned integer ``status`` argument is present,
``OpImageSparseSampleExplicitLod`` is used instead. The resulting SPIR-V
``Residency Code`` will be written to ``status``.
``.SampleGrad(sampler, location, ddx, ddy[, offset])`` ``.SampleGrad(sampler, location, ddx, ddy[, offset][, clamp][, Status])``
++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Not available to ``Texture2DMS`` and ``Texture2DMSArray``. Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
Similarly to ``.SampleLevel``, the ``ddx`` and ``ddy`` parameter are attached to Similarly to ``.SampleLevel``, the ``ddx`` and ``ddy`` parameter are attached to
the ``OpImageSampleExplicitLod`` instruction as an SPIR-V image operands the ``OpImageSampleExplicitLod`` instruction as an SPIR-V image operands
``Grad``. ``Grad``. The optional ``clamp`` argument will be translated into the ``MinLod``
image operand.
The overload with the status parameter are not supported. If an output unsigned integer ``status`` argument is present,
``OpImageSparseSampleExplicitLod`` is used instead. The resulting SPIR-V
``Residency Code`` will be written to ``status``.
``.SampleBias(sampler, location, bias[, offset])`` ``.SampleBias(sampler, location, bias[, offset][, clamp][, Status])``
++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Not available to ``Texture2DMS`` and ``Texture2DMSArray``. Not available to ``Texture2DMS`` and ``Texture2DMSArray``.
@ -1829,18 +1840,24 @@ The translation is similar to ``.Sample()``, with the ``bias`` parameter
attached to the ``OpImageSampleImplicitLod`` instruction as an SPIR-V image attached to the ``OpImageSampleImplicitLod`` instruction as an SPIR-V image
operands ``Bias``. operands ``Bias``.
The overload with the status parameter are not supported. If an output unsigned integer ``status`` argument is present,
``OpImageSparseSampleImplicitLod`` is used instead. The resulting SPIR-V
``Residency Code`` will be written to ``status``.
``.SampleCmp(sampler, location, comparator[, offset])`` ``.SampleCmp(sampler, location, comparator[, offset][, clamp][, Status])``
+++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Not available to ``Texture3D``, ``Texture2DMS``, and ``Texture2DMSArray``. Not available to ``Texture3D``, ``Texture2DMS``, and ``Texture2DMSArray``.
The translation is similar to ``.Sample()``, but the The translation is similar to ``.Sample()``, but the
``OpImageSampleDrefImplicitLod`` instruction are used. ``OpImageSampleDrefImplicitLod`` instruction are used.
``.SampleCmpLevelZero(sampler, location, comparator[, offset])`` If an output unsigned integer ``status`` argument is present,
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ``OpImageSparseSampleDrefImplicitLod`` is used instead. The resulting SPIR-V
``Residency Code`` will be written to ``status``.
``.SampleCmpLevelZero(sampler, location, comparator[, offset][, Status])``
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Not available to ``Texture3D``, ``Texture2DMS``, and ``Texture2DMSArray``. Not available to ``Texture3D``, ``Texture2DMS``, and ``Texture2DMSArray``.
@ -1848,6 +1865,10 @@ The translation is similar to ``.Sample()``, but the
``OpImageSampleDrefExplicitLod`` instruction are used, with the additional ``OpImageSampleDrefExplicitLod`` instruction are used, with the additional
``Lod`` image operands set to 0.0. ``Lod`` image operands set to 0.0.
If an output unsigned integer ``status`` argument is present,
``OpImageSparseSampleDrefExplicitLod`` is used instead. The resulting SPIR-V
``Residency Code`` will be written to ``status``.
``.Gather()`` ``.Gather()``
+++++++++++++ +++++++++++++
@ -1857,7 +1878,9 @@ Available to ``Texture2D``, ``Texture2DArray``, ``TextureCube``, and
The translation is similar to ``.Sample()``, but the ``OpImageGather`` The translation is similar to ``.Sample()``, but the ``OpImageGather``
instruction is used, with component setting to 0. instruction is used, with component setting to 0.
The overload with the status parameter are not supported. If an output unsigned integer ``status`` argument is present,
``OpImageSparseGather`` is used instead. The resulting SPIR-V
``Residency Code`` will be written to ``status``.
``.GatherRed()``, ``.GatherGreen()``, ``.GatherBlue()``, ``.GatherAlpha()`` ``.GatherRed()``, ``.GatherGreen()``, ``.GatherBlue()``, ``.GatherAlpha()``
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@ -1873,7 +1896,9 @@ There are a few overloads for these functions:
- For those overloads taking 4 offset parameters, those offset parameters will - For those overloads taking 4 offset parameters, those offset parameters will
be conveyed as an additional ``ConstOffsets`` image operands to the be conveyed as an additional ``ConstOffsets`` image operands to the
instruction. So those offset parameters must all be constant values. instruction. So those offset parameters must all be constant values.
- Those overloads with the status parameter are not supported. - For those overloads with the ``status`` parameter, ``OpImageSparseGather``
is used instead, and the resulting SPIR-V ``Residency Code`` will be
written to ``status``.
``.GatherCmp()`` ``.GatherCmp()``
++++++++++++++++ ++++++++++++++++
@ -1884,7 +1909,10 @@ Available to ``Texture2D``, ``Texture2DArray``, ``TextureCube``, and
The translation is similar to ``.Sample()``, but the ``OpImageDrefGather`` The translation is similar to ``.Sample()``, but the ``OpImageDrefGather``
instruction is used. instruction is used.
The overload with the status parameter are not supported. For the overload with the output unsigned integer ``status`` argument,
``OpImageSparseDrefGather`` is used instead. The resulting SPIR-V
``Residency Code`` will be written to ``status``.
``.GatherCmpRed()`` ``.GatherCmpRed()``
+++++++++++++++++++ +++++++++++++++++++
@ -1894,8 +1922,6 @@ Available to ``Texture2D``, ``Texture2DArray``, ``TextureCube``, and
The translation is the same as ``.GatherCmp()``. The translation is the same as ``.GatherCmp()``.
The overload with the status parameter are not supported.
``.Load(location[, sampleIndex][, offset])`` ``.Load(location[, sampleIndex][, offset])``
++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++
@ -1908,7 +1934,9 @@ The return value of ``OpImageFetch`` is always a four-component vector; so
proper additional instructions are generated to truncate the vector and return proper additional instructions are generated to truncate the vector and return
the desired number of elements. the desired number of elements.
The overload with the status parameter are not supported. For the overload with the output unsigned integer ``status`` argument,
``OpImageSparseFetch`` is used instead. The resulting SPIR-V
``Residency Code`` will be written to ``status``.
``operator[]`` ``operator[]``
++++++++++++++ ++++++++++++++
@ -2034,6 +2062,10 @@ Since read-write texture types are represented as ``OpTypeImage`` with
``Sampled`` set to 2 (meaning to be used without a sampler), ``OpImageRead`` is ``Sampled`` set to 2 (meaning to be used without a sampler), ``OpImageRead`` is
used to perform this operation. used to perform this operation.
For the overload with the output unsigned integer ``status`` argument,
``OpImageSparseRead`` is used instead. The resulting SPIR-V
``Residency Code`` will be written to ``status``.
``operator[]`` ``operator[]``
++++++++++++++ ++++++++++++++
Using ``operator[]`` for reading is handled similarly as ``.Load()``, while for Using ``operator[]`` for reading is handled similarly as ``.Load()``, while for
@ -2299,3 +2331,7 @@ either because of no Vulkan equivalents at the moment, or because of deprecation
sample currently being processed.) The compiler will emit an error. sample currently being processed.) The compiler will emit an error.
* ``SV_InnerCoverage`` semantic does not have a Vulkan equivalent. The compiler * ``SV_InnerCoverage`` semantic does not have a Vulkan equivalent. The compiler
will emit an error. will emit an error.
* Since ``StructuredBuffer``, ``RWStructuredBuffer``, ``ByteAddressBuffer``, and
``RWByteAddressBuffer`` are not represented as image types in SPIR-V, using the
output unsigned integer ``status`` argument in their ``Load*`` methods is not
supported. Using these methods with the ``status`` argument will cause a compiler error.

Просмотреть файл

@ -865,6 +865,14 @@ public:
llvm::Optional<spv::ImageOperandsMask> image_operands, llvm::Optional<spv::ImageOperandsMask> image_operands,
bool is_explicit, bool is_sparse); bool is_explicit, bool is_sparse);
// All-in-one method for creating different types of
// OpImageRead*/OpImageFetch*.
InstBuilder &
opImageFetchRead(uint32_t result_type, uint32_t result_id, uint32_t image,
uint32_t coordinate,
llvm::Optional<spv::ImageOperandsMask> image_operands,
bool is_fetch, bool is_sparse);
// Methods for supplying additional parameters. // Methods for supplying additional parameters.
InstBuilder &fPFastMathMode(spv::FPFastMathModeMask); InstBuilder &fPFastMathMode(spv::FPFastMathModeMask);
InstBuilder &fPRoundingMode(spv::FPRoundingMode); InstBuilder &fPRoundingMode(spv::FPRoundingMode);

Просмотреть файл

@ -191,11 +191,16 @@ public:
/// doImageFetch is true, OpImageFetch is used. OpImageRead is used otherwise. /// doImageFetch is true, OpImageFetch is used. OpImageRead is used otherwise.
/// OpImageFetch should be used for sampled images. OpImageRead should be used /// OpImageFetch should be used for sampled images. OpImageRead should be used
/// for images without a sampler. /// for images without a sampler.
///
/// If residencyCodeId is not zero, the sparse version of the instructions
/// will be used, and the SPIR-V instruction for storing the resulting
/// residency code will also be emitted.
uint32_t createImageFetchOrRead(bool doImageFetch, uint32_t texelType, uint32_t createImageFetchOrRead(bool doImageFetch, uint32_t texelType,
QualType imageType, uint32_t image, QualType imageType, uint32_t image,
uint32_t coordinate, uint32_t lod, uint32_t coordinate, uint32_t lod,
uint32_t constOffset, uint32_t varOffset, uint32_t constOffset, uint32_t varOffset,
uint32_t constOffsets, uint32_t sample); uint32_t constOffsets, uint32_t sample,
uint32_t residencyCodeId);
/// \brief Creates SPIR-V instructions for writing to the given image. /// \brief Creates SPIR-V instructions for writing to the given image.
void createImageWrite(QualType imageType, uint32_t imageId, uint32_t coordId, void createImageWrite(QualType imageType, uint32_t imageId, uint32_t coordId,

Просмотреть файл

@ -112,6 +112,28 @@ InstBuilder &InstBuilder::opImageSample(
return *this; return *this;
} }
InstBuilder &InstBuilder::opImageFetchRead(
uint32_t result_type, uint32_t result_id, uint32_t image,
uint32_t coordinate, llvm::Optional<spv::ImageOperandsMask> image_operands,
bool is_fetch, bool is_sparse) {
spv::Op op =
is_fetch
? (is_sparse ? spv::Op::OpImageSparseFetch : spv::Op::OpImageFetch)
: (is_sparse ? spv::Op::OpImageSparseRead : spv::Op::OpImageRead);
TheInst.emplace_back(static_cast<uint32_t>(op));
TheInst.emplace_back(result_type);
TheInst.emplace_back(result_id);
TheInst.emplace_back(image);
TheInst.emplace_back(coordinate);
if (image_operands.hasValue()) {
const auto &val = image_operands.getValue();
encodeImageOperands(val);
}
return *this;
}
void InstBuilder::encodeString(std::string value) { void InstBuilder::encodeString(std::string value) {
const auto &words = string::encodeSPIRVString(value); const auto &words = string::encodeSPIRVString(value);
TheInst.insert(TheInst.end(), words.begin(), words.end()); TheInst.insert(TheInst.end(), words.begin(), words.end());

Просмотреть файл

@ -429,30 +429,44 @@ void ModuleBuilder::createImageWrite(QualType imageType, uint32_t imageId,
uint32_t ModuleBuilder::createImageFetchOrRead( uint32_t ModuleBuilder::createImageFetchOrRead(
bool doImageFetch, uint32_t texelType, QualType imageType, uint32_t image, bool doImageFetch, uint32_t texelType, QualType imageType, uint32_t image,
uint32_t coordinate, uint32_t lod, uint32_t constOffset, uint32_t varOffset, uint32_t coordinate, uint32_t lod, uint32_t constOffset, uint32_t varOffset,
uint32_t constOffsets, uint32_t sample) { uint32_t constOffsets, uint32_t sample, uint32_t residencyCodeId) {
assert(insertPoint && "null insert point"); assert(insertPoint && "null insert point");
// TODO: Update ImageFetch/ImageRead to accept minLod if necessary.
llvm::SmallVector<uint32_t, 2> params; llvm::SmallVector<uint32_t, 2> params;
const auto mask = const auto mask =
llvm::Optional<spv::ImageOperandsMask>(composeImageOperandsMask( llvm::Optional<spv::ImageOperandsMask>(composeImageOperandsMask(
/*bias*/ 0, lod, std::make_pair(0, 0), constOffset, varOffset, /*bias*/ 0, lod, std::make_pair(0, 0), constOffset, varOffset,
constOffsets, sample, /*minLod*/ 0, &params)); constOffsets, sample, /*minLod*/ 0, &params));
const uint32_t texelId = theContext.takeNextId(); const bool isSparse = (residencyCodeId != 0);
if (doImageFetch) { uint32_t retType = texelType;
instBuilder.opImageFetch(texelType, texelId, image, coordinate, mask); if (isSparse) {
} else { requireCapability(spv::Capability::SparseResidency);
retType = getSparseResidencyStructType(texelType);
}
if (!doImageFetch) {
requireCapability( requireCapability(
TypeTranslator::getCapabilityForStorageImageReadWrite(imageType)); TypeTranslator::getCapabilityForStorageImageReadWrite(imageType));
instBuilder.opImageRead(texelType, texelId, image, coordinate, mask);
} }
uint32_t texelId = theContext.takeNextId();
instBuilder.opImageFetchRead(retType, texelId, image, coordinate, mask,
doImageFetch, isSparse);
for (const auto param : params) for (const auto param : params)
instBuilder.idRef(param); instBuilder.idRef(param);
instBuilder.x(); instBuilder.x();
insertPoint->appendInstruction(std::move(constructSite)); insertPoint->appendInstruction(std::move(constructSite));
if (isSparse) {
// Write the Residency Code
const auto status = createCompositeExtract(getUint32Type(), texelId, {0});
createStore(residencyCodeId, status);
// Extract the real result from the struct
texelId = createCompositeExtract(texelType, texelId, {1});
}
return texelId; return texelId;
} }

Просмотреть файл

@ -2350,11 +2350,9 @@ uint32_t SPIRVEmitter::processTextureGatherCmp(const CXXMemberCallExpr *expr) {
/*sampleNumber*/ 0, status); /*sampleNumber*/ 0, status);
} }
SpirvEvalInfo SPIRVEmitter::processBufferTextureLoad(const Expr *object, SpirvEvalInfo SPIRVEmitter::processBufferTextureLoad(
const uint32_t locationId, const Expr *object, const uint32_t locationId, uint32_t constOffset,
uint32_t constOffset, uint32_t varOffset, uint32_t lod, uint32_t residencyCode) {
uint32_t varOffset,
uint32_t lod) {
// Loading for Buffer and RWBuffer translates to an OpImageFetch. // Loading for Buffer and RWBuffer translates to an OpImageFetch.
// The result type of an OpImageFetch must be a vec4 of float or int. // The result type of an OpImageFetch must be a vec4 of float or int.
const auto type = object->getType(); const auto type = object->getType();
@ -2393,10 +2391,9 @@ SpirvEvalInfo SPIRVEmitter::processBufferTextureLoad(const Expr *object,
// OpImageFetch and OpImageRead can only fetch a vector of 4 elements. // OpImageFetch and OpImageRead can only fetch a vector of 4 elements.
const uint32_t texelTypeId = theBuilder.getVecType(elemTypeId, 4u); const uint32_t texelTypeId = theBuilder.getVecType(elemTypeId, 4u);
const uint32_t texel = const uint32_t texel = theBuilder.createImageFetchOrRead(
theBuilder.createImageFetchOrRead(doFetch, texelTypeId, type, objectId, doFetch, texelTypeId, type, objectId, locationId, lod, constOffset,
locationId, lod, constOffset, varOffset, varOffset, /*constOffsets*/ 0, sampleNumber, residencyCode);
/*constOffsets*/ 0, sampleNumber);
uint32_t retVal = texel; uint32_t retVal = texel;
// If the result type is a vec1, vec2, or vec3, some extra processing // If the result type is a vec1, vec2, or vec3, some extra processing
@ -2436,7 +2433,7 @@ SpirvEvalInfo SPIRVEmitter::processByteAddressBufferLoadStore(
typeTranslator.isByteAddressBuffer(type)); typeTranslator.isByteAddressBuffer(type));
if (expr->getNumArgs() == 2) { if (expr->getNumArgs() == 2) {
emitError( emitError(
"(RW)ByteAddressBuffer::Load(in address, out status) unimplemented", "(RW)ByteAddressBuffer::Load(in address, out status) not supported",
expr->getExprLoc()); expr->getExprLoc());
return 0; return 0;
} }
@ -2512,7 +2509,8 @@ SpirvEvalInfo SPIRVEmitter::processByteAddressBufferLoadStore(
SpirvEvalInfo SpirvEvalInfo
SPIRVEmitter::processStructuredBufferLoad(const CXXMemberCallExpr *expr) { SPIRVEmitter::processStructuredBufferLoad(const CXXMemberCallExpr *expr) {
if (expr->getNumArgs() == 2) { if (expr->getNumArgs() == 2) {
emitError("(RW)StructuredBuffer::Load(int, int) unimplemented", emitError(
"(RW)StructuredBuffer::Load(in location, out status) not supported",
expr->getExprLoc()); expr->getExprLoc());
return 0; return 0;
} }
@ -2644,19 +2642,6 @@ void SPIRVEmitter::handleOffsetInMethodCall(const CXXMemberCallExpr *expr,
*varOffset = doExpr(expr->getArg(index)); *varOffset = doExpr(expr->getArg(index));
}; };
void SPIRVEmitter::handleOptionalOffsetInMethodCall(
const CXXMemberCallExpr *expr, uint32_t index, uint32_t *constOffset,
uint32_t *varOffset) {
*constOffset = *varOffset = 0; // Initialize both first
if (expr->getNumArgs() == index + 1) { // Has offset argument
if (*constOffset = tryToEvaluateAsConst(expr->getArg(index)))
return; // Constant offset
else
*varOffset = doExpr(expr->getArg(index));
}
}
SpirvEvalInfo SpirvEvalInfo
SPIRVEmitter::processIntrinsicMemberCall(const CXXMemberCallExpr *expr, SPIRVEmitter::processIntrinsicMemberCall(const CXXMemberCallExpr *expr,
hlsl::IntrinsicOp opcode) { hlsl::IntrinsicOp opcode) {
@ -3074,12 +3059,38 @@ SPIRVEmitter::processTextureSampleCmpCmpLevelZero(const CXXMemberCallExpr *expr,
SpirvEvalInfo SpirvEvalInfo
SPIRVEmitter::processBufferTextureLoad(const CXXMemberCallExpr *expr) { SPIRVEmitter::processBufferTextureLoad(const CXXMemberCallExpr *expr) {
// Signature: // Signature:
// For Texture1D, Texture1DArray, Texture2D, Texture2DArray, Texture3D:
// ret Object.Load(int Location
// [, int Offset]
// [, uint status]);
//
// For Texture2DMS and Texture2DMSArray, there is one additional argument:
// ret Object.Load(int Location // ret Object.Load(int Location
// [, int SampleIndex] // [, int SampleIndex]
// [, int Offset]); // [, int Offset]
// [, uint status]);
//
// For (RW)Buffer, RWTexture1D, RWTexture1DArray, RWTexture2D,
// RWTexture2DArray, RWTexture3D:
// ret Object.Load (int Location
// [, uint status]);
//
// Note: (RW)ByteAddressBuffer and (RW)StructuredBuffer types also have Load
// methods that take an additional Status argument. However, since these types
// are not represented as OpTypeImage in SPIR-V, we don't have a way of
// figuring out the Residency Code for them. Therefore having the Status
// argument for these types is not supported.
//
// For (RW)ByteAddressBuffer:
// ret Object.{Load,Load2,Load3,Load4} (int Location
// [, uint status]);
//
// For (RW)StructuredBuffer:
// ret Object.Load (int Location
// [, uint status]);
//
const auto *object = expr->getImplicitObjectArgument(); const auto *object = expr->getImplicitObjectArgument();
const auto *location = expr->getArg(0);
const auto objectType = object->getType(); const auto objectType = object->getType();
if (typeTranslator.isRWByteAddressBuffer(objectType) || if (typeTranslator.isRWByteAddressBuffer(objectType) ||
@ -3089,10 +3100,23 @@ SPIRVEmitter::processBufferTextureLoad(const CXXMemberCallExpr *expr) {
if (TypeTranslator::isStructuredBuffer(objectType)) if (TypeTranslator::isStructuredBuffer(objectType))
return processStructuredBufferLoad(expr); return processStructuredBufferLoad(expr);
const auto numArgs = expr->getNumArgs();
const auto *location = expr->getArg(0);
const bool isTextureMS = TypeTranslator::isTextureMS(objectType);
const bool hasStatusArg =
expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType();
const auto status = hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : 0;
if (TypeTranslator::isBuffer(objectType) || if (TypeTranslator::isBuffer(objectType) ||
TypeTranslator::isRWBuffer(objectType) || TypeTranslator::isRWBuffer(objectType) ||
TypeTranslator::isRWTexture(objectType)) TypeTranslator::isRWTexture(objectType))
return processBufferTextureLoad(object, doExpr(location)); return processBufferTextureLoad(object, doExpr(location), /*constOffset*/ 0,
/*varOffset*/ 0, /*lod*/ 0,
/*residencyCode*/ status);
// Subtract 1 for status (if it exists), and 1 for sampleIndex (if it exists),
// and 1 for location.
const bool hasOffsetArg = numArgs - hasStatusArg - isTextureMS - 1 > 0;
if (TypeTranslator::isTexture(objectType)) { if (TypeTranslator::isTexture(objectType)) {
// .Load() has a second optional paramter for offset. // .Load() has a second optional paramter for offset.
@ -3100,12 +3124,13 @@ SPIRVEmitter::processBufferTextureLoad(const CXXMemberCallExpr *expr) {
uint32_t constOffset = 0, varOffset = 0; uint32_t constOffset = 0, varOffset = 0;
uint32_t coordinate = locationId, lod = 0; uint32_t coordinate = locationId, lod = 0;
if (TypeTranslator::isTextureMS(objectType)) { if (isTextureMS) {
// SampleIndex is only available when the Object is of Texture2DMS or // SampleIndex is only available when the Object is of Texture2DMS or
// Texture2DMSArray types. Under those cases, Offset will be the third // Texture2DMSArray types. Under those cases, Offset will be the third
// parameter (index 2). // parameter (index 2).
lod = doExpr(expr->getArg(1)); lod = doExpr(expr->getArg(1));
handleOptionalOffsetInMethodCall(expr, 2, &constOffset, &varOffset); if(hasOffsetArg)
handleOffsetInMethodCall(expr, 2, &constOffset, &varOffset);
} else { } else {
// For Texture Load() functions, the location parameter is a vector // For Texture Load() functions, the location parameter is a vector
// that consists of both the coordinate and the mipmap level (via the // that consists of both the coordinate and the mipmap level (via the
@ -3114,11 +3139,12 @@ SPIRVEmitter::processBufferTextureLoad(const CXXMemberCallExpr *expr) {
splitVecLastElement(location->getType(), locationId, &coordinate, &lod); splitVecLastElement(location->getType(), locationId, &coordinate, &lod);
// For textures other than Texture2DMS(Array), offset should be the // For textures other than Texture2DMS(Array), offset should be the
// second parameter (index 1). // second parameter (index 1).
handleOptionalOffsetInMethodCall(expr, 1, &constOffset, &varOffset); if(hasOffsetArg)
handleOffsetInMethodCall(expr, 1, &constOffset, &varOffset);
} }
return processBufferTextureLoad(object, coordinate, constOffset, varOffset, return processBufferTextureLoad(object, coordinate, constOffset, varOffset,
lod); lod, status);
} }
emitError("Load() of the given object type unimplemented", emitError("Load() of the given object type unimplemented",
object->getExprLoc()); object->getExprLoc());
@ -3158,13 +3184,15 @@ SPIRVEmitter::doCXXOperatorCallExpr(const CXXOperatorCallExpr *expr) {
? theBuilder.getConstantUint32(0) ? theBuilder.getConstantUint32(0)
: 0; : 0;
return processBufferTextureLoad(baseExpr, doExpr(indexExpr), return processBufferTextureLoad(baseExpr, doExpr(indexExpr),
/*constOffset*/ 0, /*varOffset*/ 0, lod); /*constOffset*/ 0, /*varOffset*/ 0, lod,
/*residencyCode*/ 0);
} }
// .mips[][] or .sample[][] must use the correct slice. // .mips[][] or .sample[][] must use the correct slice.
if (isTextureMipsSampleIndexing(expr, &baseExpr, &indexExpr, &lodExpr)) { if (isTextureMipsSampleIndexing(expr, &baseExpr, &indexExpr, &lodExpr)) {
const uint32_t lod = doExpr(lodExpr); const uint32_t lod = doExpr(lodExpr);
return processBufferTextureLoad(baseExpr, doExpr(indexExpr), return processBufferTextureLoad(baseExpr, doExpr(indexExpr),
/*constOffset*/ 0, /*varOffset*/ 0, lod); /*constOffset*/ 0, /*varOffset*/ 0, lod,
/*residencyCode*/ 0);
} }
} }

Просмотреть файл

@ -576,14 +576,6 @@ private:
void processSwitchStmtUsingIfStmts(const SwitchStmt *switchStmt); void processSwitchStmtUsingIfStmts(const SwitchStmt *switchStmt);
private: private:
/// Handles the optional offset argument in the given method call at the given
/// argument index.
/// If there exists an offset argument, writes the <result-id> to either
/// *constOffset or *varOffset, depending on the constantness of the offset.
void handleOptionalOffsetInMethodCall(const CXXMemberCallExpr *expr,
uint32_t index, uint32_t *constOffset,
uint32_t *varOffset);
/// Handles the offset argument in the given method call at the given argument /// Handles the offset argument in the given method call at the given argument
/// index. Panics if the argument at the given index does not exist. Writes /// index. Panics if the argument at the given index does not exist. Writes
/// the <result-id> to either *constOffset or *varOffset, depending on the /// the <result-id> to either *constOffset or *varOffset, depending on the
@ -598,10 +590,12 @@ private:
/// \brief Loads one element from the given Buffer/RWBuffer/Texture object at /// \brief Loads one element from the given Buffer/RWBuffer/Texture object at
/// the given location. The type of the loaded element matches the type in the /// the given location. The type of the loaded element matches the type in the
/// declaration for the Buffer/Texture object. /// declaration for the Buffer/Texture object.
/// If residencyCodeId is not zero, the SPIR-V instruction for storing the
/// resulting residency code will also be emitted.
SpirvEvalInfo processBufferTextureLoad(const Expr *object, uint32_t location, SpirvEvalInfo processBufferTextureLoad(const Expr *object, uint32_t location,
uint32_t constOffset = 0, uint32_t constOffset,
uint32_t varOffst = 0, uint32_t varOffset, uint32_t lod,
uint32_t lod = 0); uint32_t residencyCode);
/// \brief Processes .Sample() and .Gather() method calls for texture objects. /// \brief Processes .Sample() and .Gather() method calls for texture objects.
uint32_t processTextureSampleGather(const CXXMemberCallExpr *expr, uint32_t processTextureSampleGather(const CXXMemberCallExpr *expr,

Просмотреть файл

@ -15,66 +15,93 @@ RWBuffer<int4> int4buf;
RWBuffer<uint4> uint4buf; RWBuffer<uint4> uint4buf;
RWBuffer<float4> float4buf; RWBuffer<float4> float4buf;
// CHECK: OpCapability SparseResidency
// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
void main() { void main() {
int address; int address;
// CHECK: [[img1:%\d+]] = OpLoad %type_buffer_image %intbuf // CHECK: [[img1:%\d+]] = OpLoad %type_buffer_image %intbuf
// CHECK: [[f1:%\d+]] = OpImageFetch %v4int [[img1]] {{%\d+}} None // CHECK: [[f1:%\d+]] = OpImageFetch %v4int [[img1]] {{%\d+}} None
// CHECK-NEXT: {{%\d+}} = OpCompositeExtract %int [[f1]] 0 // CHECK-NEXT: {{%\d+}} = OpCompositeExtract %int [[f1]] 0
int int1 = intbuf.Load(address); int i1 = intbuf.Load(address);
// CHECK: [[img2:%\d+]] = OpLoad %type_buffer_image_0 %uintbuf // CHECK: [[img2:%\d+]] = OpLoad %type_buffer_image_0 %uintbuf
// CHECK: [[f2:%\d+]] = OpImageFetch %v4uint [[img2]] {{%\d+}} None // CHECK: [[f2:%\d+]] = OpImageFetch %v4uint [[img2]] {{%\d+}} None
// CHECK-NEXT: {{%\d+}} = OpCompositeExtract %uint [[f2]] 0 // CHECK-NEXT: {{%\d+}} = OpCompositeExtract %uint [[f2]] 0
uint uint1 = uintbuf.Load(address); uint u1 = uintbuf.Load(address);
// CHECK: [[img3:%\d+]] = OpLoad %type_buffer_image_1 %floatbuf // CHECK: [[img3:%\d+]] = OpLoad %type_buffer_image_1 %floatbuf
// CHECK: [[f3:%\d+]] = OpImageFetch %v4float [[img3]] {{%\d+}} None // CHECK: [[f3:%\d+]] = OpImageFetch %v4float [[img3]] {{%\d+}} None
// CHECK-NEXT: {{%\d+}} = OpCompositeExtract %float [[f3]] 0 // CHECK-NEXT: {{%\d+}} = OpCompositeExtract %float [[f3]] 0
float float1 = floatbuf.Load(address); float f1 = floatbuf.Load(address);
// CHECK: [[img4:%\d+]] = OpLoad %type_buffer_image_2 %int2buf // CHECK: [[img4:%\d+]] = OpLoad %type_buffer_image_2 %int2buf
// CHECK: [[f4:%\d+]] = OpImageRead %v4int [[img4]] {{%\d+}} None // CHECK: [[f4:%\d+]] = OpImageRead %v4int [[img4]] {{%\d+}} None
// CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v2int [[f4]] [[f4]] 0 1 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v2int [[f4]] [[f4]] 0 1
int2 int2 = int2buf.Load(address); int2 i2 = int2buf.Load(address);
// CHECK: [[img5:%\d+]] = OpLoad %type_buffer_image_3 %uint2buf // CHECK: [[img5:%\d+]] = OpLoad %type_buffer_image_3 %uint2buf
// CHECK: [[f5:%\d+]] = OpImageRead %v4uint [[img5]] {{%\d+}} None // CHECK: [[f5:%\d+]] = OpImageRead %v4uint [[img5]] {{%\d+}} None
// CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v2uint [[f5]] [[f5]] 0 1 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v2uint [[f5]] [[f5]] 0 1
uint2 uint2 = uint2buf.Load(address); uint2 u2 = uint2buf.Load(address);
// CHECK: [[img6:%\d+]] = OpLoad %type_buffer_image_4 %float2buf // CHECK: [[img6:%\d+]] = OpLoad %type_buffer_image_4 %float2buf
// CHECK: [[f6:%\d+]] = OpImageRead %v4float [[img6]] {{%\d+}} None // CHECK: [[f6:%\d+]] = OpImageRead %v4float [[img6]] {{%\d+}} None
// CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v2float [[f6]] [[f6]] 0 1 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v2float [[f6]] [[f6]] 0 1
float2 float2 = float2buf.Load(address); float2 f2 = float2buf.Load(address);
// CHECK: [[img7:%\d+]] = OpLoad %type_buffer_image_5 %int3buf // CHECK: [[img7:%\d+]] = OpLoad %type_buffer_image_5 %int3buf
// CHECK: [[f7:%\d+]] = OpImageFetch %v4int [[img7]] {{%\d+}} None // CHECK: [[f7:%\d+]] = OpImageFetch %v4int [[img7]] {{%\d+}} None
// CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v3int [[f7]] [[f7]] 0 1 2 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v3int [[f7]] [[f7]] 0 1 2
int3 int3 = int3buf.Load(address); int3 i3 = int3buf.Load(address);
// CHECK: [[img8:%\d+]] = OpLoad %type_buffer_image_6 %uint3buf // CHECK: [[img8:%\d+]] = OpLoad %type_buffer_image_6 %uint3buf
// CHECK: [[f8:%\d+]] = OpImageFetch %v4uint [[img8]] {{%\d+}} None // CHECK: [[f8:%\d+]] = OpImageFetch %v4uint [[img8]] {{%\d+}} None
// CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v3uint [[f8]] [[f8]] 0 1 2 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v3uint [[f8]] [[f8]] 0 1 2
uint3 uint3 = uint3buf.Load(address); uint3 u3 = uint3buf.Load(address);
// CHECK: [[img9:%\d+]] = OpLoad %type_buffer_image_7 %float3buf // CHECK: [[img9:%\d+]] = OpLoad %type_buffer_image_7 %float3buf
// CHECK: [[f9:%\d+]] = OpImageFetch %v4float [[img9]] {{%\d+}} None // CHECK: [[f9:%\d+]] = OpImageFetch %v4float [[img9]] {{%\d+}} None
// CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v3float [[f9]] [[f9]] 0 1 2 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v3float [[f9]] [[f9]] 0 1 2
float3 float3 = float3buf.Load(address); float3 f3 = float3buf.Load(address);
// CHECK: [[img10:%\d+]] = OpLoad %type_buffer_image_8 %int4buf // CHECK: [[img10:%\d+]] = OpLoad %type_buffer_image_8 %int4buf
// CHECK: {{%\d+}} = OpImageRead %v4int [[img10]] {{%\d+}} None // CHECK: {{%\d+}} = OpImageRead %v4int [[img10]] {{%\d+}} None
// CHECK-NEXT: OpStore %int4 {{%\d+}} // CHECK-NEXT: OpStore %i4 {{%\d+}}
int4 int4 = int4buf.Load(address); int4 i4 = int4buf.Load(address);
// CHECK: [[img11:%\d+]] = OpLoad %type_buffer_image_9 %uint4buf // CHECK: [[img11:%\d+]] = OpLoad %type_buffer_image_9 %uint4buf
// CHECK: {{%\d+}} = OpImageRead %v4uint [[img11]] {{%\d+}} None // CHECK: {{%\d+}} = OpImageRead %v4uint [[img11]] {{%\d+}} None
// CHECK-NEXT: OpStore %uint4 {{%\d+}} // CHECK-NEXT: OpStore %u4 {{%\d+}}
uint4 uint4 = uint4buf.Load(address); uint4 u4 = uint4buf.Load(address);
// CHECK: [[img12:%\d+]] = OpLoad %type_buffer_image_10 %float4buf // CHECK: [[img12:%\d+]] = OpLoad %type_buffer_image_10 %float4buf
// CHECK: {{%\d+}} = OpImageRead %v4float [[img12]] {{%\d+}} None // CHECK: {{%\d+}} = OpImageRead %v4float [[img12]] {{%\d+}} None
// CHECK-NEXT: OpStore %float4 {{%\d+}} // CHECK-NEXT: OpStore %f4 {{%\d+}}
float4 float4 = float4buf.Load(address); float4 f4 = float4buf.Load(address);
///////////////////////////////
// Using the Status argument //
///////////////////////////////
uint status;
// CHECK: [[img3:%\d+]] = OpLoad %type_buffer_image_1 %floatbuf
// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct [[img3]] {{%\d+}} None
// CHECK-NEXT: [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[v4result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
// CHECK-NEXT: [[result:%\d+]] = OpCompositeExtract %float [[v4result]] 0
// CHECK-NEXT: OpStore %r1 [[result]]
float r1 = floatbuf.Load(address, status); // Test for Buffer
// CHECK: [[img6:%\d+]] = OpLoad %type_buffer_image_4 %float2buf
// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseRead %SparseResidencyStruct [[img6]] {{%\d+}} None
// CHECK-NEXT: [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[v4result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
// CHECK-NEXT: [[result:%\d+]] = OpVectorShuffle %v2float [[v4result]] [[v4result]] 0 1
// CHECK-NEXT: OpStore %r2 [[result]]
float2 r2 = float2buf.Load(address, status); // Test for RWBuffer
} }

Просмотреть файл

@ -6,6 +6,12 @@ RWTexture3D<float3> float3buf;
RWTexture1DArray<float4> float4buf; RWTexture1DArray<float4> float4buf;
RWTexture2DArray<int3> int3buf; RWTexture2DArray<int3> int3buf;
// CHECK: OpCapability SparseResidency
// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4int
// CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4uint
// CHECK: %SparseResidencyStruct_1 = OpTypeStruct %uint %v4float
void main() { void main() {
// CHECK: [[img1:%\d+]] = OpLoad %type_1d_image %intbuf // CHECK: [[img1:%\d+]] = OpLoad %type_1d_image %intbuf
@ -36,4 +42,49 @@ void main() {
// CHECK-NEXT: [[r5:%\d+]] = OpVectorShuffle %v3int [[ret5]] [[ret5]] 0 1 2 // CHECK-NEXT: [[r5:%\d+]] = OpVectorShuffle %v3int [[ret5]] [[ret5]] 0 1 2
// CHECK-NEXT: OpStore %e [[r5]] // CHECK-NEXT: OpStore %e [[r5]]
int3 e = int3buf.Load(0); int3 e = int3buf.Load(0);
uint status;
// CHECK: [[img1:%\d+]] = OpLoad %type_1d_image %intbuf
// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseRead %SparseResidencyStruct [[img1]] %int_0 None
// CHECK-NEXT: [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[v4result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
// CHECK-NEXT: [[result:%\d+]] = OpCompositeExtract %int [[v4result]] 0
// CHECK-NEXT: OpStore %a2 [[result]]
int a2 = intbuf.Load(0, status);
// CHECK: [[img2:%\d+]] = OpLoad %type_2d_image %uint2buf
// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseRead %SparseResidencyStruct_0 [[img2]] {{%\d+}} None
// CHECK-NEXT: [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[v4result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
// CHECK-NEXT: [[result:%\d+]] = OpVectorShuffle %v2uint [[v4result]] [[v4result]] 0 1
// CHECK-NEXT: OpStore %b2 [[result]]
uint2 b2 = uint2buf.Load(0, status);
// CHECK: [[img3:%\d+]] = OpLoad %type_3d_image %float3buf
// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseRead %SparseResidencyStruct_1 [[img3]] {{%\d+}} None
// CHECK-NEXT: [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[v4result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
// CHECK-NEXT: [[result:%\d+]] = OpVectorShuffle %v3float [[v4result]] [[v4result]] 0 1 2
// CHECK-NEXT: OpStore %c2 [[result]]
float3 c2 = float3buf.Load(0, status);
// CHECK: [[img4:%\d+]] = OpLoad %type_1d_image_array %float4buf
// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseRead %SparseResidencyStruct_1 [[img4]] {{%\d+}} None
// CHECK-NEXT: [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[v4result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
// CHECK-NEXT: OpStore %d2 [[v4result]]
float4 d2 = float4buf.Load(0, status);
// CHECK: [[img5:%\d+]] = OpLoad %type_2d_image_array %int3buf
// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseRead %SparseResidencyStruct [[img5]] {{%\d+}} None
// CHECK-NEXT: [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[v4result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
// CHECK-NEXT: [[result:%\d+]] = OpVectorShuffle %v3int [[v4result]] [[v4result]] 0 1 2
// CHECK-NEXT: OpStore %e2 [[result]]
int3 e2 = int3buf.Load(0, status);
} }

Просмотреть файл

@ -4,7 +4,12 @@ Texture1DArray <float4> t1 : register(t1);
Texture2DArray <float4> t2 : register(t2); Texture2DArray <float4> t2 : register(t2);
// .Load() does not support TextureCubeArray. // .Load() does not support TextureCubeArray.
// CHECK: OpCapability SparseResidency
// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
// CHECK: [[v3ic:%\d+]] = OpConstantComposite %v3int %int_1 %int_2 %int_3 // CHECK: [[v3ic:%\d+]] = OpConstantComposite %v3int %int_1 %int_2 %int_3
// CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
float4 main(int4 location: A) : SV_Target { float4 main(int4 location: A) : SV_Target {
@ -21,9 +26,27 @@ float4 main(int4 location: A) : SV_Target {
// CHECK-NEXT: {{%\d+}} = OpImageFetch %v4float [[t2]] [[coord]] Lod [[lod]] // CHECK-NEXT: {{%\d+}} = OpImageFetch %v4float [[t2]] [[coord]] Lod [[lod]]
float4 val2 = t2.Load(location); float4 val2 = t2.Load(location);
uint status;
// CHECK: [[coord:%\d+]] = OpVectorShuffle %v2int [[v3ic]] [[v3ic]] 0 1
// CHECK-NEXT: [[lod:%\d+]] = OpCompositeExtract %int [[v3ic]] 2
// CHECK-NEXT: [[t1:%\d+]] = OpLoad %type_1d_image_array %t1
// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct [[t1]] [[coord]] Lod|ConstOffset [[lod]] %int_10
// CHECK-NEXT: [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
// CHECK-NEXT: OpStore %val3 [[result]]
float4 val3 = t1.Load(int3(1, 2, 3), 10, status);
// CHECK: [[loc:%\d+]] = OpLoad %v4int %location
// CHECK-NEXT: [[coord:%\d+]] = OpVectorShuffle %v3int [[loc]] [[loc]] 0 1 2
// CHECK-NEXT: [[lod:%\d+]] = OpCompositeExtract %int [[loc]] 3
// CHECK-NEXT: [[t2:%\d+]] = OpLoad %type_2d_image_array %t2
// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct [[t2]] [[coord]] Lod|ConstOffset [[lod]] [[v2ic]]
// CHECK-NEXT: [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
// CHECK-NEXT: OpStore %val4 [[result]]
float4 val4 = t2.Load(location, int2(1, 2), status);
return 1.0; return 1.0;
} }

Просмотреть файл

@ -13,12 +13,18 @@ Texture2DMS <float> t7 : register(t7);
Texture2DMSArray<float3> t8 : register(t8); Texture2DMSArray<float3> t8 : register(t8);
// CHECK: OpCapability ImageGatherExtended // CHECK: OpCapability ImageGatherExtended
// CHECK: OpCapability SparseResidency
// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
// CHECK: %SparseResidencyStruct_0 = OpTypeStruct %uint %v4int
// CHECK: %SparseResidencyStruct_1 = OpTypeStruct %uint %v4uint
// CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_1 %int_2 // CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
// CHECK: [[v4ic:%\d+]] = OpConstantComposite %v4int %int_1 %int_2 %int_3 %int_4 // CHECK: [[v4ic:%\d+]] = OpConstantComposite %v4int %int_1 %int_2 %int_3 %int_4
// CHECK: [[v3ic:%\d+]] = OpConstantComposite %v3int %int_3 %int_3 %int_3 // CHECK: [[v3ic:%\d+]] = OpConstantComposite %v3int %int_3 %int_3 %int_3
float4 main(int3 location: A, int offset: B) : SV_Target { float4 main(int3 location: A, int offset: B) : SV_Target {
uint status;
// CHECK: [[coord:%\d+]] = OpCompositeExtract %int [[v2ic]] 0 // CHECK: [[coord:%\d+]] = OpCompositeExtract %int [[v2ic]] 0
// CHECK-NEXT: [[lod:%\d+]] = OpCompositeExtract %int [[v2ic]] 1 // CHECK-NEXT: [[lod:%\d+]] = OpCompositeExtract %int [[v2ic]] 1
@ -88,5 +94,67 @@ float4 main(int3 location: A, int offset: B) : SV_Target {
// CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v3float [[f81]] [[f81]] 0 1 2 // CHECK-NEXT: {{%\d+}} = OpVectorShuffle %v3float [[f81]] [[f81]] 0 1 2
val8 = t8.Load(pos3, sampleIndex, int2(1,2)); val8 = t8.Load(pos3, sampleIndex, int2(1,2));
/////////////////////////////////
/// Using the Status argument ///
/////////////////////////////////
// CHECK: [[coord:%\d+]] = OpCompositeExtract %int [[v2ic]] 0
// CHECK-NEXT: [[lod:%\d+]] = OpCompositeExtract %int [[v2ic]] 1
// CHECK-NEXT: [[offset:%\d+]] = OpLoad %int %offset
// CHECK-NEXT: [[t4:%\d+]] = OpLoad %type_1d_image %t4
// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct [[t4]] [[coord]] Lod|Offset [[lod]] [[offset]]
// CHECK-NEXT: [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[v4result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
// CHECK-NEXT: [[result:%\d+]] = OpCompositeExtract %float [[v4result]] 0
// CHECK-NEXT: OpStore %val14 [[result]]
float val14 = t4.Load(int2(1,2), offset, status);
// CHECK: [[loc:%\d+]] = OpLoad %v3int %location
// CHECK-NEXT: [[coord:%\d+]] = OpVectorShuffle %v2int [[loc]] [[loc]] 0 1
// CHECK-NEXT: [[lod:%\d+]] = OpCompositeExtract %int [[loc]] 2
// CHECK-NEXT: [[t5:%\d+]] = OpLoad %type_2d_image_0 %t5
// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct_0 [[t5]] [[coord]] Lod|ConstOffset [[lod]] [[v2ic]]
// CHECK-NEXT: [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[v4result:%\d+]] = OpCompositeExtract %v4int [[structResult]] 1
// CHECK-NEXT: [[result:%\d+]] = OpVectorShuffle %v2int [[v4result]] [[v4result]] 0 1
// CHECK-NEXT: OpStore %val15 [[result]]
int2 val15 = t5.Load(location, int2(1,2), status);
// CHECK: [[coord:%\d+]] = OpVectorShuffle %v3int [[v4ic]] [[v4ic]] 0 1 2
// CHECK-NEXT: [[lod:%\d+]] = OpCompositeExtract %int [[v4ic]] 3
// CHECK-NEXT: [[t6:%\d+]] = OpLoad %type_3d_image_0 %t6
// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct_1 [[t6]] [[coord]] Lod|ConstOffset [[lod]] [[v3ic]]
// CHECK-NEXT: [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[v4result:%\d+]] = OpCompositeExtract %v4uint [[structResult]] 1
// CHECK-NEXT: [[result:%\d+]] = OpVectorShuffle %v3uint [[v4result]] [[v4result]] 0 1 2
// CHECK-NEXT: OpStore %val16 [[result]]
uint3 val16 = t6.Load(int4(1, 2, 3, 4), 3, status);
// CHECK: [[pos1:%\d+]] = OpLoad %v2int %pos2
// CHECK-NEXT: [[si1:%\d+]] = OpLoad %int %sampleIndex
// CHECK-NEXT: [[offset2:%\d+]] = OpLoad %v2int %offset2
// CHECK-NEXT: [[t71:%\d+]] = OpLoad %type_2d_image_1 %t7
// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct [[t71]] [[pos1]] Offset|Sample [[offset2]] [[si1]]
// CHECK-NEXT: [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[v4result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
// CHECK-NEXT: [[result:%\d+]] = OpCompositeExtract %float [[v4result]] 0
// CHECK-NEXT: OpStore %val17 [[result]]
float val17 = t7.Load(pos2, sampleIndex, offset2, status);
// CHECK: [[pos3:%\d+]] = OpLoad %v3int %pos3
// CHECK-NEXT: [[si3:%\d+]] = OpLoad %int %sampleIndex
// CHECK-NEXT: [[t81:%\d+]] = OpLoad %type_2d_image_array %t8
// CHECK-NEXT:[[structResult:%\d+]] = OpImageSparseFetch %SparseResidencyStruct [[t81]] [[pos3]] ConstOffset|Sample [[v2ic]] [[si3]]
// CHECK-NEXT: [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
// CHECK-NEXT: OpStore %status [[status]]
// CHECK-NEXT: [[v4result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
// CHECK-NEXT: [[result:%\d+]] = OpVectorShuffle %v3float [[v4result]] [[v4result]] 0 1 2
// CHECK-NEXT: OpStore %val18 [[result]]
float3 val18 = t8.Load(pos3, sampleIndex, int2(1,2), status);
return 1.0; return 1.0;
} }