/* * Copyright (C) 2020-2024 Intel Corporation * * SPDX-License-Identifier: MIT * */ #pragma once #include "shared/source/helpers/debug_helpers.h" #include "shared/source/kernel/kernel_arg_metadata.h" #include "shared/source/utilities/arrayref.h" #include namespace NEO { using CrossThreadDataOffset = uint16_t; using DynamicStateHeapOffset = uint16_t; using SurfaceStateHeapOffset = uint16_t; using InlineDataOffset = uint8_t; template static constexpr T undefined = std::numeric_limits::max(); template bool isUndefinedOffset(T offset) { static_assert(!std::is_pointer_v); return undefined == offset; } template bool isValidOffset(T offset) { return false == isUndefinedOffset(offset); } struct ArgDescPointer final { SurfaceStateHeapOffset bindful = undefined; CrossThreadDataOffset stateless = undefined; CrossThreadDataOffset bindless = undefined; CrossThreadDataOffset bufferOffset = undefined; CrossThreadDataOffset slmOffset = undefined; uint8_t requiredSlmAlignment = 0; uint8_t pointerSize = 0; bool accessedUsingStatelessAddressingMode = true; bool isPureStateful() const { return false == accessedUsingStatelessAddressingMode; } }; struct ArgDescInlineDataPointer { InlineDataOffset offset = 0u; uint8_t pointerSize = 0u; }; enum class NEOImageType : uint8_t { imageTypeUnknown, imageTypeBuffer, imageType1D, imageType1DArray, imageType2D, imageType2DArray, imageType3D, imageTypeCube, imageTypeCubeArray, imageType2DDepth, imageType2DArrayDepth, imageType2DMSAA, imageType2DMSAADepth, imageType2DArrayMSAA, imageType2DArrayMSAADepth, imageType2DMedia, imageType2DMediaBlock, }; struct ArgDescImage final { SurfaceStateHeapOffset bindful = undefined; // stateful with BTI CrossThreadDataOffset bindless = undefined; struct { CrossThreadDataOffset imgWidth = undefined; CrossThreadDataOffset imgHeight = undefined; CrossThreadDataOffset imgDepth = undefined; CrossThreadDataOffset channelDataType = undefined; CrossThreadDataOffset channelOrder = undefined; CrossThreadDataOffset arraySize = undefined; CrossThreadDataOffset numSamples = undefined; CrossThreadDataOffset numMipLevels = undefined; CrossThreadDataOffset flatBaseOffset = undefined; CrossThreadDataOffset flatWidth = undefined; CrossThreadDataOffset flatHeight = undefined; CrossThreadDataOffset flatPitch = undefined; } metadataPayload; NEOImageType imageType; }; struct ArgDescSampler final { uint32_t samplerType = 0; DynamicStateHeapOffset bindful = undefined; CrossThreadDataOffset bindless = undefined; struct { CrossThreadDataOffset samplerSnapWa = undefined; CrossThreadDataOffset samplerAddressingMode = undefined; CrossThreadDataOffset samplerNormalizedCoords = undefined; } metadataPayload; uint8_t index = undefined; uint8_t size = undefined; }; struct ArgDescValue final { struct Element { CrossThreadDataOffset offset = undefined; uint16_t size = 0U; uint16_t sourceOffset = 0U; bool isPtr = false; }; StackVec elements; }; struct ArgDescriptor final { enum ArgType : uint8_t { argTUnknown, argTPointer, argTImage, argTSampler, argTValue }; struct ExtendedTypeInfo { ExtendedTypeInfo() { packed = 0U; } union { struct { bool isAccelerator : 1; bool isDeviceQueue : 1; bool isMediaImage : 1; bool isMediaBlockImage : 1; bool isTransformable : 1; bool needsPatch : 1; bool hasVmeExtendedDescriptor : 1; }; uint32_t packed; }; }; ArgDescriptor(ArgType type); ArgDescriptor() : ArgDescriptor(argTUnknown) { } ArgDescriptor &operator=(const ArgDescriptor &rhs); ArgDescriptor(const ArgDescriptor &rhs) { *this = rhs; } template const T &as() const; template T &as(bool initIfUnknown = false); template bool is() const { return type == this->type; } ArgTypeTraits &getTraits() { return traits; } const ArgTypeTraits &getTraits() const { return traits; } ExtendedTypeInfo &getExtendedTypeInfo() { return extendedTypeInfo; } const ExtendedTypeInfo &getExtendedTypeInfo() const { return extendedTypeInfo; } bool isReadOnly() const { switch (type) { default: return true; case argTImage: return (KernelArgMetadata::AccessReadOnly == traits.accessQualifier); case argTPointer: return (KernelArgMetadata::AddrConstant == traits.addressQualifier) || (KernelArgMetadata::AccessReadOnly == traits.accessQualifier) || traits.typeQualifiers.constQual; } } protected: ArgDescValue asByValue; ArgTypeTraits traits; union { ArgDescPointer asPointer; ArgDescImage asImage; ArgDescSampler asSampler; }; ExtendedTypeInfo extendedTypeInfo; public: ArgType type; }; namespace { constexpr auto argSize = sizeof(ArgDescriptor); static_assert(argSize <= 72, "Keep it small"); } // namespace template <> inline const ArgDescPointer &ArgDescriptor::as() const { UNRECOVERABLE_IF(type != argTPointer); return this->asPointer; } template <> inline const ArgDescImage &ArgDescriptor::as() const { UNRECOVERABLE_IF(type != argTImage); return this->asImage; } template <> inline const ArgDescSampler &ArgDescriptor::as() const { UNRECOVERABLE_IF(type != argTSampler); return this->asSampler; } template <> inline const ArgDescValue &ArgDescriptor::as() const { UNRECOVERABLE_IF(type != argTValue); return this->asByValue; } template <> inline ArgDescPointer &ArgDescriptor::as(bool initIfUnknown) { if ((argTUnknown == type) && initIfUnknown) { this->type = argTPointer; this->asPointer = {}; } UNRECOVERABLE_IF(type != argTPointer); return this->asPointer; } template <> inline ArgDescImage &ArgDescriptor::as(bool initIfUnknown) { if ((argTUnknown == type) && initIfUnknown) { this->type = argTImage; this->asImage = {}; } UNRECOVERABLE_IF(type != argTImage); return this->asImage; } template <> inline ArgDescSampler &ArgDescriptor::as(bool initIfUnknown) { if ((argTUnknown == type) && initIfUnknown) { this->type = argTSampler; this->asSampler = {}; } UNRECOVERABLE_IF(type != argTSampler); return this->asSampler; } template <> inline ArgDescValue &ArgDescriptor::as(bool initIfUnknown) { if ((argTUnknown == type) && initIfUnknown) { this->type = argTValue; this->asByValue.elements.clear(); } UNRECOVERABLE_IF(type != argTValue); return this->asByValue; } template inline void setOffsetsVec(CrossThreadDataOffset (&dst)[vecSize], const T (&src)[vecSize]) { for (uint32_t i = 0; i < vecSize; ++i) { dst[i] = src[i]; } } template inline bool patchNonPointer(ArrayRef buffer, CrossThreadDataOffset location, const SrcT &value) { if (undefined == location) { return false; } DEBUG_BREAK_IF(location + sizeof(DstT) > buffer.size()); *reinterpret_cast(buffer.begin() + location) = static_cast(value); return true; } template inline void patchVecNonPointer(ArrayRef buffer, const CrossThreadDataOffset (&location)[vecSize], const T (&value)[vecSize]) { for (uint32_t i = 0; i < vecSize; ++i) { patchNonPointer(buffer, location[i], value[i]); } return; } inline bool patchPointer(ArrayRef buffer, const ArgDescPointer &arg, uintptr_t value) { if (arg.pointerSize == 8) { return patchNonPointer(buffer, arg.stateless, static_cast(value)); } else { UNRECOVERABLE_IF((arg.pointerSize != 4) && isValidOffset(arg.stateless)); return patchNonPointer(buffer, arg.stateless, static_cast(value)); } } inline ArgDescriptor &ArgDescriptor::operator=(const ArgDescriptor &rhs) { if (this == &rhs) { return *this; } this->type = argTUnknown; switch (rhs.type) { default: break; case argTPointer: this->as(true) = rhs.as(); break; case argTImage: this->as(true) = rhs.as(); break; case argTSampler: this->as(true) = rhs.as(); break; case argTValue: this->as(true) = rhs.as(); break; } this->type = rhs.type; this->traits = rhs.traits; this->extendedTypeInfo = rhs.extendedTypeInfo; return *this; } inline ArgDescriptor::ArgDescriptor(ArgType type) : type(type) { switch (type) { default: break; case argTPointer: this->as(true); break; case argTImage: this->as(true); break; case argTSampler: this->as(true); break; case argTValue: this->as(true); break; } } struct ArgDescriptorExtended { virtual ~ArgDescriptorExtended() = default; }; } // namespace NEO