/* * Copyright (C) 2020-2023 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" namespace NEO { using CrossThreadDataOffset = uint16_t; using DynamicStateHeapOffset = uint16_t; using SurfaceStateHeapOffset = uint16_t; template static constexpr T undefined = std::numeric_limits::max(); template bool isUndefinedOffset(T offset) { 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; } }; 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; }; 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) { 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