diff --git a/opencl/source/built_ins/builtins_dispatch_builder.cpp b/opencl/source/built_ins/builtins_dispatch_builder.cpp index 4bb993b128..8a4ded383c 100644 --- a/opencl/source/built_ins/builtins_dispatch_builder.cpp +++ b/opencl/source/built_ins/builtins_dispatch_builder.cpp @@ -182,191 +182,91 @@ class BuiltInOp : public BuiltinDispatchInfoBuilder template bool buildDispatchInfosTyped(MultiDispatchInfo &multiDispatchInfo) const { + DispatchInfoBuilder kernelNoSplit3DBuilder(clDevice); auto &operationParams = multiDispatchInfo.peekBuiltinOpParams(); size_t hostPtrSize = 0; - size_t srcOffsetFromAlignedPtr = 0; - size_t dstOffsetFromAlignedPtr = 0; bool is3D = false; - auto srcPtr = operationParams.srcPtr; - auto dstPtr = operationParams.dstPtr; if (operationParams.srcMemObj && operationParams.dstMemObj) { - DEBUG_BREAK_IF(!((srcPtr == nullptr) && (dstPtr == nullptr))); + DEBUG_BREAK_IF(!((operationParams.srcPtr == nullptr) && (operationParams.dstPtr == nullptr))); is3D = (operationParams.size.z > 1) || (operationParams.srcOffset.z > 0) || (operationParams.dstOffset.z > 0); } else { - if (srcPtr) { + if (operationParams.srcPtr) { size_t origin[] = {operationParams.srcOffset.x, operationParams.srcOffset.y, operationParams.srcOffset.z}; size_t region[] = {operationParams.size.x, operationParams.size.y, operationParams.size.z}; hostPtrSize = Buffer::calculateHostPtrSize(origin, region, operationParams.srcRowPitch, operationParams.srcSlicePitch); is3D = (operationParams.size.z > 1) || (operationParams.dstOffset.z > 0); - if (!is3D) { - auto srcPtrOffset = ptrOffset(srcPtr, operationParams.srcOffset.z * operationParams.srcSlicePitch); - srcPtr = alignDown(srcPtrOffset, 4); - srcOffsetFromAlignedPtr = ptrDiff(srcPtrOffset, srcPtr); - } - } else if (dstPtr) { + } else if (operationParams.dstPtr) { size_t origin[] = {operationParams.dstOffset.x, operationParams.dstOffset.y, operationParams.dstOffset.z}; size_t region[] = {operationParams.size.x, operationParams.size.y, operationParams.size.z}; hostPtrSize = Buffer::calculateHostPtrSize(origin, region, operationParams.dstRowPitch, operationParams.dstSlicePitch); is3D = (operationParams.size.z > 1) || (operationParams.srcOffset.z > 0); - if (!is3D) { - auto dstPtrOffset = ptrOffset(dstPtr, operationParams.dstOffset.z * operationParams.dstSlicePitch); - dstPtr = alignDown(dstPtrOffset, 4); - dstOffsetFromAlignedPtr = ptrDiff(dstPtrOffset, dstPtr); - } } else { DEBUG_BREAK_IF(!false); } } - const uint32_t rootDeviceIndex = clDevice.getRootDeviceIndex(); - const int dimensions = is3D ? 3 : 2; + uint32_t rootDeviceIndex = clDevice.getRootDeviceIndex(); - if (this->clDevice.getProductHelper().isCopyBufferRectSplitSupported()) { - DispatchInfoBuilder kernelSplit3DBuilder(clDevice); + // Set-up ISA + int dimensions = is3D ? 3 : 2; + kernelNoSplit3DBuilder.setKernel(kernelBytes[dimensions - 1]->getKernel(rootDeviceIndex)); - const auto totalSize = operationParams.size.x * operationParams.size.y * operationParams.size.z; - if (totalSize == 0u) { - return true; - } + size_t srcOffsetFromAlignedPtr = 0; + size_t dstOffsetFromAlignedPtr = 0; - const uintptr_t start = reinterpret_cast(dstPtr) + operationParams.dstOffset.x; - - constexpr size_t middleAlignment = MemoryConstants::cacheLineSize; - constexpr size_t middleElSize = sizeof(uint32_t) * 4; - - uintptr_t leftSize = start % middleAlignment; - leftSize = (leftSize > 0) ? (middleAlignment - leftSize) : 0; // calc left leftover size - leftSize = std::min(leftSize, operationParams.size.x); // clamp left leftover size to requested size - - uintptr_t rightSize = (start + operationParams.size.x) % middleAlignment; // calc right leftover size - rightSize = std::min(rightSize, (operationParams.size.x > leftSize) ? (operationParams.size.x - leftSize) : 0); // clamp - - const uintptr_t middleSizeBytes = (operationParams.size.x > leftSize + rightSize) ? operationParams.size.x - leftSize - rightSize : 0u; // calc middle size - - // corner case - fully optimized kernel requires DWORD alignment. If we don't have it, run slower, misaligned kernel - const auto srcMiddleStart = reinterpret_cast(srcPtr) + operationParams.srcOffset.x + leftSize; - const auto srcMisalignment = srcMiddleStart % sizeof(uint32_t); - const auto rowPitchMisalignment = operationParams.srcRowPitch % sizeof(uint32_t); - const auto slicePitchMisalignment = operationParams.srcSlicePitch % sizeof(uint32_t); - const auto isSrcMisaligned = srcMisalignment != 0u || rowPitchMisalignment != 0u || slicePitchMisalignment != 0u; - - const auto middleSizeEls = middleSizeBytes / middleElSize; // num work items in middle walker - - // Set-up ISA - - kernelSplit3DBuilder.setKernel(SplitDispatch::RegionCoordX::left, kernelLeft[dimensions - 1]->getKernel(rootDeviceIndex)); - if (isSrcMisaligned) { - kernelSplit3DBuilder.setKernel(SplitDispatch::RegionCoordX::middle, kernelBytes[dimensions - 1]->getKernel(rootDeviceIndex)); - } else { - kernelSplit3DBuilder.setKernel(SplitDispatch::RegionCoordX::middle, kernelMiddle[dimensions - 1]->getKernel(rootDeviceIndex)); - } - kernelSplit3DBuilder.setKernel(SplitDispatch::RegionCoordX::right, kernelRight[dimensions - 1]->getKernel(rootDeviceIndex)); - - // arg0 = src - if (operationParams.srcMemObj) { - kernelSplit3DBuilder.setArg(0, operationParams.srcMemObj); - } else { - kernelSplit3DBuilder.setArgSvm(0, hostPtrSize, srcPtr, nullptr, CL_MEM_READ_ONLY); - } - - bool isDestinationInSystem = false; - // arg1 = dst - if (operationParams.dstMemObj) { - kernelSplit3DBuilder.setArg(1, operationParams.dstMemObj); - isDestinationInSystem = Kernel::graphicsAllocationTypeUseSystemMemory(operationParams.dstMemObj->getGraphicsAllocation(rootDeviceIndex)->getAllocationType()); - } else { - kernelSplit3DBuilder.setArgSvm(1, hostPtrSize, dstPtr, nullptr, 0u); - isDestinationInSystem = dstPtr != nullptr; - } - kernelSplit3DBuilder.setKernelDestinationArgumentInSystem(isDestinationInSystem); - - // arg2 = srcOrigin - OffsetType kSrcOrigin[4] = {static_cast(operationParams.srcOffset.x + srcOffsetFromAlignedPtr), static_cast(operationParams.srcOffset.y), static_cast(operationParams.srcOffset.z), 0}; - kernelSplit3DBuilder.setArg(SplitDispatch::RegionCoordX::left, 2, sizeof(OffsetType) * 4, kSrcOrigin); - kSrcOrigin[0] += static_cast(leftSize); - kernelSplit3DBuilder.setArg(SplitDispatch::RegionCoordX::middle, 2, sizeof(OffsetType) * 4, kSrcOrigin); - kSrcOrigin[0] += static_cast(middleSizeBytes); - kernelSplit3DBuilder.setArg(SplitDispatch::RegionCoordX::right, 2, sizeof(OffsetType) * 4, kSrcOrigin); - - // arg3 = dstOrigin - OffsetType kDstOrigin[4] = {static_cast(operationParams.dstOffset.x + dstOffsetFromAlignedPtr), static_cast(operationParams.dstOffset.y), static_cast(operationParams.dstOffset.z), 0}; - kernelSplit3DBuilder.setArg(SplitDispatch::RegionCoordX::left, 3, sizeof(OffsetType) * 4, kDstOrigin); - kDstOrigin[0] += static_cast(leftSize); - kernelSplit3DBuilder.setArg(SplitDispatch::RegionCoordX::middle, 3, sizeof(OffsetType) * 4, kDstOrigin); - kDstOrigin[0] += static_cast(middleSizeBytes); - kernelSplit3DBuilder.setArg(SplitDispatch::RegionCoordX::right, 3, sizeof(OffsetType) * 4, kDstOrigin); - - // arg4 = srcPitch - OffsetType kSrcPitch[2] = {static_cast(operationParams.srcRowPitch), static_cast(operationParams.srcSlicePitch)}; - kernelSplit3DBuilder.setArg(4, sizeof(OffsetType) * 2, kSrcPitch); - - // arg5 = dstPitch - OffsetType kDstPitch[2] = {static_cast(operationParams.dstRowPitch), static_cast(operationParams.dstSlicePitch)}; - kernelSplit3DBuilder.setArg(5, sizeof(OffsetType) * 2, kDstPitch); - - // Set-up work sizes - kernelSplit3DBuilder.setDispatchGeometry(SplitDispatch::RegionCoordX::left, Vec3{leftSize, operationParams.size.y, operationParams.size.z}, Vec3{0, 0, 0}, Vec3{0, 0, 0}); - kernelSplit3DBuilder.getDispatchInfo(0u).setDim(0u); - - kernelSplit3DBuilder.setDispatchGeometry(SplitDispatch::RegionCoordX::middle, Vec3{isSrcMisaligned ? middleSizeBytes : middleSizeEls, operationParams.size.y, operationParams.size.z}, Vec3{0, 0, 0}, Vec3{0, 0, 0}); - kernelSplit3DBuilder.getDispatchInfo(1u).setDim(0u); - - kernelSplit3DBuilder.setDispatchGeometry(SplitDispatch::RegionCoordX::right, Vec3{rightSize, operationParams.size.y, operationParams.size.z}, Vec3{0, 0, 0}, Vec3{0, 0, 0}); - kernelSplit3DBuilder.getDispatchInfo(2u).setDim(0u); - - kernelSplit3DBuilder.bake(multiDispatchInfo); - - UNRECOVERABLE_IF(leftSize + rightSize + middleSizeEls * middleElSize != operationParams.size.x); - - return true; + // arg0 = src + if (operationParams.srcMemObj) { + kernelNoSplit3DBuilder.setArg(0, operationParams.srcMemObj); } else { - DispatchInfoBuilder kernelNoSplit3DBuilder(clDevice); - - // Set-up ISA - kernelNoSplit3DBuilder.setKernel(kernelBytes[dimensions - 1]->getKernel(rootDeviceIndex)); - - // arg0 = src - if (operationParams.srcMemObj) { - kernelNoSplit3DBuilder.setArg(0, operationParams.srcMemObj); - } else { - kernelNoSplit3DBuilder.setArgSvm(0, hostPtrSize, srcPtr, nullptr, CL_MEM_READ_ONLY); + void *srcPtrToSet = operationParams.srcPtr; + if (!is3D) { + auto srcPtr = ptrOffset(operationParams.srcPtr, operationParams.srcOffset.z * operationParams.srcSlicePitch); + srcPtrToSet = alignDown(srcPtr, 4); + srcOffsetFromAlignedPtr = ptrDiff(srcPtr, srcPtrToSet); } - - bool isDestinationInSystem = false; - // arg1 = dst - if (operationParams.dstMemObj) { - kernelNoSplit3DBuilder.setArg(1, operationParams.dstMemObj); - isDestinationInSystem = Kernel::graphicsAllocationTypeUseSystemMemory(operationParams.dstMemObj->getGraphicsAllocation(rootDeviceIndex)->getAllocationType()); - } else { - kernelNoSplit3DBuilder.setArgSvm(1, hostPtrSize, dstPtr, nullptr, 0u); - isDestinationInSystem = dstPtr != nullptr; - } - kernelNoSplit3DBuilder.setKernelDestinationArgumentInSystem(isDestinationInSystem); - - // arg2 = srcOrigin - OffsetType kSrcOrigin[4] = {static_cast(operationParams.srcOffset.x + srcOffsetFromAlignedPtr), static_cast(operationParams.srcOffset.y), static_cast(operationParams.srcOffset.z), 0}; - kernelNoSplit3DBuilder.setArg(2, sizeof(OffsetType) * 4, kSrcOrigin); - - // arg3 = dstOrigin - OffsetType kDstOrigin[4] = {static_cast(operationParams.dstOffset.x + dstOffsetFromAlignedPtr), static_cast(operationParams.dstOffset.y), static_cast(operationParams.dstOffset.z), 0}; - kernelNoSplit3DBuilder.setArg(3, sizeof(OffsetType) * 4, kDstOrigin); - - // arg4 = srcPitch - OffsetType kSrcPitch[2] = {static_cast(operationParams.srcRowPitch), static_cast(operationParams.srcSlicePitch)}; - kernelNoSplit3DBuilder.setArg(4, sizeof(OffsetType) * 2, kSrcPitch); - - // arg5 = dstPitch - OffsetType kDstPitch[2] = {static_cast(operationParams.dstRowPitch), static_cast(operationParams.dstSlicePitch)}; - kernelNoSplit3DBuilder.setArg(5, sizeof(OffsetType) * 2, kDstPitch); - - // Set-up work sizes - kernelNoSplit3DBuilder.setDispatchGeometry(operationParams.size, Vec3{0, 0, 0}, Vec3{0, 0, 0}); - kernelNoSplit3DBuilder.bake(multiDispatchInfo); - - return true; + kernelNoSplit3DBuilder.setArgSvm(0, hostPtrSize, srcPtrToSet, nullptr, CL_MEM_READ_ONLY); } + + bool isDestinationInSystem = false; + // arg1 = dst + if (operationParams.dstMemObj) { + kernelNoSplit3DBuilder.setArg(1, operationParams.dstMemObj); + isDestinationInSystem = Kernel::graphicsAllocationTypeUseSystemMemory(operationParams.dstMemObj->getGraphicsAllocation(rootDeviceIndex)->getAllocationType()); + } else { + void *dstPtrToSet = operationParams.dstPtr; + if (!is3D) { + auto dstPtr = ptrOffset(operationParams.dstPtr, operationParams.dstOffset.z * operationParams.dstSlicePitch); + dstPtrToSet = alignDown(dstPtr, 4); + dstOffsetFromAlignedPtr = ptrDiff(dstPtr, dstPtrToSet); + } + kernelNoSplit3DBuilder.setArgSvm(1, hostPtrSize, dstPtrToSet, nullptr, 0u); + isDestinationInSystem = operationParams.dstPtr != nullptr; + } + kernelNoSplit3DBuilder.setKernelDestinationArgumentInSystem(isDestinationInSystem); + + // arg2 = srcOrigin + OffsetType kSrcOrigin[4] = {static_cast(operationParams.srcOffset.x + srcOffsetFromAlignedPtr), static_cast(operationParams.srcOffset.y), static_cast(operationParams.srcOffset.z), 0}; + kernelNoSplit3DBuilder.setArg(2, sizeof(OffsetType) * 4, kSrcOrigin); + + // arg3 = dstOrigin + OffsetType kDstOrigin[4] = {static_cast(operationParams.dstOffset.x + dstOffsetFromAlignedPtr), static_cast(operationParams.dstOffset.y), static_cast(operationParams.dstOffset.z), 0}; + kernelNoSplit3DBuilder.setArg(3, sizeof(OffsetType) * 4, kDstOrigin); + + // arg4 = srcPitch + OffsetType kSrcPitch[2] = {static_cast(operationParams.srcRowPitch), static_cast(operationParams.srcSlicePitch)}; + kernelNoSplit3DBuilder.setArg(4, sizeof(OffsetType) * 2, kSrcPitch); + + // arg5 = dstPitch + OffsetType kDstPitch[2] = {static_cast(operationParams.dstRowPitch), static_cast(operationParams.dstSlicePitch)}; + kernelNoSplit3DBuilder.setArg(5, sizeof(OffsetType) * 2, kDstPitch); + + // Set-up work sizes + kernelNoSplit3DBuilder.setDispatchGeometry(operationParams.size, Vec3{0, 0, 0}, Vec3{0, 0, 0}); + kernelNoSplit3DBuilder.bake(multiDispatchInfo); + + return true; } bool buildDispatchInfos(MultiDispatchInfo &multiDispatchInfo) const override { @@ -375,9 +275,6 @@ class BuiltInOp : public BuiltinDispatchInfoBuilder protected: MultiDeviceKernel *kernelBytes[3]{}; - MultiDeviceKernel *kernelLeft[3]{}; - MultiDeviceKernel *kernelMiddle[3]{}; - MultiDeviceKernel *kernelRight[3]{}; BuiltInOp(BuiltIns &kernelsLib, ClDevice &device, bool populateKernels) : BuiltinDispatchInfoBuilder(kernelsLib, device) { if (populateKernels) { @@ -385,16 +282,7 @@ class BuiltInOp : public BuiltinDispatchInfoBuilder "", "CopyBufferRectBytes2d", kernelBytes[0], "CopyBufferRectBytes2d", kernelBytes[1], - "CopyBufferRectBytes3d", kernelBytes[2], - "CopyBufferRectBytes2d", kernelLeft[0], - "CopyBufferRectBytes2d", kernelLeft[1], - "CopyBufferRectBytes3d", kernelLeft[2], - "CopyBufferRectBytesMiddle2d", kernelMiddle[0], - "CopyBufferRectBytesMiddle2d", kernelMiddle[1], - "CopyBufferRectBytesMiddle3d", kernelMiddle[2], - "CopyBufferRectBytes2d", kernelRight[0], - "CopyBufferRectBytes2d", kernelRight[1], - "CopyBufferRectBytes3d", kernelRight[2]); + "CopyBufferRectBytes3d", kernelBytes[2]); } } }; @@ -408,16 +296,7 @@ class BuiltInOp : public BuiltInOp(multiDispatchInfo); @@ -433,16 +312,7 @@ class BuiltInOp : public BuiltInOp CompilerOptions::greaterThan4gbBuffersRequired, "CopyBufferRectBytes2d", kernelBytes[0], "CopyBufferRectBytes2d", kernelBytes[1], - "CopyBufferRectBytes3d", kernelBytes[2], - "CopyBufferRectBytes2d", kernelLeft[0], - "CopyBufferRectBytes2d", kernelLeft[1], - "CopyBufferRectBytes3d", kernelLeft[2], - "CopyBufferRectBytesMiddle2d", kernelMiddle[0], - "CopyBufferRectBytesMiddle2d", kernelMiddle[1], - "CopyBufferRectBytesMiddle3d", kernelMiddle[2], - "CopyBufferRectBytes2d", kernelRight[0], - "CopyBufferRectBytes2d", kernelRight[1], - "CopyBufferRectBytes3d", kernelRight[2]); + "CopyBufferRectBytes3d", kernelBytes[2]); } bool buildDispatchInfos(MultiDispatchInfo &multiDispatchInfo) const override { return buildDispatchInfosTyped(multiDispatchInfo); diff --git a/opencl/test/unit_test/command_queue/enqueue_copy_buffer_rect_tests.cpp b/opencl/test/unit_test/command_queue/enqueue_copy_buffer_rect_tests.cpp index 66aa7e6288..f70b73446f 100644 --- a/opencl/test/unit_test/command_queue/enqueue_copy_buffer_rect_tests.cpp +++ b/opencl/test/unit_test/command_queue/enqueue_copy_buffer_rect_tests.cpp @@ -373,7 +373,7 @@ HWCMDTEST_F(IGFX_GEN8_CORE, EnqueueCopyBufferRectTest, WhenCopyingBufferRect3DTh // Verify GPGPU_WALKER parameters EXPECT_NE(0u, cmd->getThreadGroupIdXDimension()); EXPECT_NE(0u, cmd->getThreadGroupIdYDimension()); - EXPECT_NE(0u, cmd->getThreadGroupIdZDimension()); + EXPECT_LT(1u, cmd->getThreadGroupIdZDimension()); EXPECT_NE(0u, cmd->getRightExecutionMask()); EXPECT_NE(0u, cmd->getBottomExecutionMask()); EXPECT_EQ(GPGPU_WALKER::SIMD_SIZE_SIMD32, cmd->getSimdSize()); diff --git a/shared/source/os_interface/product_helper.h b/shared/source/os_interface/product_helper.h index 393e0ce9e3..e9ba9597aa 100644 --- a/shared/source/os_interface/product_helper.h +++ b/shared/source/os_interface/product_helper.h @@ -152,7 +152,6 @@ class ProductHelper { virtual bool isIpSamplingSupported(const HardwareInfo &hwInfo) const = 0; virtual bool isGrfNumReportedWithScm() const = 0; virtual bool isThreadArbitrationPolicyReportedWithScm() const = 0; - virtual bool isCopyBufferRectSplitSupported() const = 0; virtual bool isCooperativeEngineSupported(const HardwareInfo &hwInfo) const = 0; virtual bool isTimestampWaitSupportedForEvents() const = 0; virtual bool isTilePlacementResourceWaRequired(const HardwareInfo &hwInfo) const = 0; diff --git a/shared/source/os_interface/product_helper_bdw_and_later.inl b/shared/source/os_interface/product_helper_bdw_and_later.inl index 876dc9a78a..ed931f6168 100644 --- a/shared/source/os_interface/product_helper_bdw_and_later.inl +++ b/shared/source/os_interface/product_helper_bdw_and_later.inl @@ -75,11 +75,6 @@ bool ProductHelperHw::isTimestampWaitSupportedForEvents() const { return false; } -template -bool ProductHelperHw::isCopyBufferRectSplitSupported() const { - return false; -} - template uint32_t ProductHelperHw::getCommandBuffersPreallocatedPerCommandQueue() const { return 0u; diff --git a/shared/source/os_interface/product_helper_hw.h b/shared/source/os_interface/product_helper_hw.h index 5f2f5a72dd..0e8ba8ae26 100644 --- a/shared/source/os_interface/product_helper_hw.h +++ b/shared/source/os_interface/product_helper_hw.h @@ -94,7 +94,6 @@ class ProductHelperHw : public ProductHelper { bool isIpSamplingSupported(const HardwareInfo &hwInfo) const override; bool isGrfNumReportedWithScm() const override; bool isThreadArbitrationPolicyReportedWithScm() const override; - bool isCopyBufferRectSplitSupported() const override; bool isFlatRingBufferSupported() const override; bool isCooperativeEngineSupported(const HardwareInfo &hwInfo) const override; bool isTimestampWaitSupportedForEvents() const override; diff --git a/shared/source/os_interface/product_helper_xe2_and_later.inl b/shared/source/os_interface/product_helper_xe2_and_later.inl index 2fcdc467ff..9783c9041f 100644 --- a/shared/source/os_interface/product_helper_xe2_and_later.inl +++ b/shared/source/os_interface/product_helper_xe2_and_later.inl @@ -78,11 +78,6 @@ bool ProductHelperHw::isInitBuiltinAsyncSupported(const HardwareInfo return false; } -template -bool ProductHelperHw::isCopyBufferRectSplitSupported() const { - return true; -} - template bool ProductHelperHw::isTimestampWaitSupportedForEvents() const { return true; diff --git a/shared/source/os_interface/product_helper_xe_hpg_and_xe_hpc.inl b/shared/source/os_interface/product_helper_xe_hpg_and_xe_hpc.inl index ad7d898428..052ca4a3f7 100644 --- a/shared/source/os_interface/product_helper_xe_hpg_and_xe_hpc.inl +++ b/shared/source/os_interface/product_helper_xe_hpg_and_xe_hpc.inl @@ -74,11 +74,6 @@ bool ProductHelperHw::isInitBuiltinAsyncSupported(const HardwareInfo return true; } -template -bool ProductHelperHw::isCopyBufferRectSplitSupported() const { - return false; -} - template bool ProductHelperHw::isTimestampWaitSupportedForEvents() const { return true; diff --git a/shared/test/common/mocks/mock_product_helper.cpp b/shared/test/common/mocks/mock_product_helper.cpp index 4b4fabbddc..869e2216cc 100644 --- a/shared/test/common/mocks/mock_product_helper.cpp +++ b/shared/test/common/mocks/mock_product_helper.cpp @@ -221,11 +221,6 @@ bool ProductHelperHw::isInitBuiltinAsyncSupported(const HardwareIn return false; } -template <> -bool ProductHelperHw::isCopyBufferRectSplitSupported() const { - return false; -} - template <> bool ProductHelperHw::isAdditionalMediaSamplerProgrammingRequired() const { return false;