diff --git a/runtime/gen10/image_gen10.cpp b/runtime/gen10/image_gen10.cpp index e8ba08f459..1e95d69996 100644 --- a/runtime/gen10/image_gen10.cpp +++ b/runtime/gen10/image_gen10.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Intel Corporation + * Copyright (C) 2017-2019 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -8,6 +8,7 @@ #include "hw_cmds.h" #include "runtime/mem_obj/image.h" #include "runtime/mem_obj/image.inl" +#include "runtime/mem_obj/image_base.inl" #include namespace OCLRT { diff --git a/runtime/gen8/image_gen8.cpp b/runtime/gen8/image_gen8.cpp index 161dd2791e..12d447cac1 100644 --- a/runtime/gen8/image_gen8.cpp +++ b/runtime/gen8/image_gen8.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Intel Corporation + * Copyright (C) 2017-2019 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -8,6 +8,7 @@ #include "hw_cmds.h" #include "runtime/mem_obj/image.h" #include "runtime/mem_obj/image.inl" +#include "runtime/mem_obj/image_base.inl" #include namespace OCLRT { diff --git a/runtime/gen9/image_gen9.cpp b/runtime/gen9/image_gen9.cpp index 695896d305..1b2af66f4c 100644 --- a/runtime/gen9/image_gen9.cpp +++ b/runtime/gen9/image_gen9.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017-2018 Intel Corporation + * Copyright (C) 2017-2019 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -8,6 +8,7 @@ #include "hw_cmds.h" #include "runtime/mem_obj/image.h" #include "runtime/mem_obj/image.inl" +#include "runtime/mem_obj/image_base.inl" #include namespace OCLRT { diff --git a/runtime/gmm_helper/gmm.cpp b/runtime/gmm_helper/gmm.cpp index cc2cee287a..6b68c1043f 100644 --- a/runtime/gmm_helper/gmm.cpp +++ b/runtime/gmm_helper/gmm.cpp @@ -249,4 +249,7 @@ bool Gmm::unifiedAuxTranslationCapable() const { return gmmFlags->Gpu.CCS && gmmFlags->Gpu.UnifiedAuxSurface && gmmFlags->Info.RenderCompressed; } +bool Gmm::hasMultisampleControlSurface() const { + return this->gmmResourceInfo->getResourceFlags()->Gpu.MCS; +} } // namespace OCLRT diff --git a/runtime/gmm_helper/gmm.h b/runtime/gmm_helper/gmm.h index 5047fc2b69..94502c071f 100644 --- a/runtime/gmm_helper/gmm.h +++ b/runtime/gmm_helper/gmm.h @@ -37,6 +37,7 @@ class Gmm { void applyMemoryFlags(bool systemMemoryPool); bool unifiedAuxTranslationCapable() const; + bool hasMultisampleControlSurface() const; uint32_t queryQPitch(GMM_RESOURCE_TYPE resType); void updateImgInfo(ImageInfo &imgInfo, cl_image_desc &imgDesc, cl_uint arrayIndex); diff --git a/runtime/mem_obj/CMakeLists.txt b/runtime/mem_obj/CMakeLists.txt index 6511fa0b30..70b86179e0 100644 --- a/runtime/mem_obj/CMakeLists.txt +++ b/runtime/mem_obj/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2018 Intel Corporation +# Copyright (C) 2018-2019 Intel Corporation # # SPDX-License-Identifier: MIT # @@ -13,6 +13,7 @@ set(RUNTIME_SRCS_MEM_OBJ ${CMAKE_CURRENT_SOURCE_DIR}/image.cpp ${CMAKE_CURRENT_SOURCE_DIR}/image.h ${CMAKE_CURRENT_SOURCE_DIR}/image.inl + ${CMAKE_CURRENT_SOURCE_DIR}/image_base.inl ${CMAKE_CURRENT_SOURCE_DIR}/image_factory_init.inl ${CMAKE_CURRENT_SOURCE_DIR}/map_operations_handler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/map_operations_handler.h diff --git a/runtime/mem_obj/image.h b/runtime/mem_obj/image.h index 1efa875806..f8d5d27074 100644 --- a/runtime/mem_obj/image.h +++ b/runtime/mem_obj/image.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018-2019 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -264,7 +264,9 @@ class ImageHw : public Image { void setImageArg(void *memory, bool setAsMediaBlockImage, uint32_t mipLevel) override; void setAuxParamsForMultisamples(RENDER_SURFACE_STATE *surfaceState); void setAuxParamsForCCS(RENDER_SURFACE_STATE *surfaceState, Gmm *gmm); + void setUnifiedAuxBaseAddress(RENDER_SURFACE_STATE *surfaceState, const Gmm *gmm); MOCKABLE_VIRTUAL void setClearColorParams(RENDER_SURFACE_STATE *surfaceState, const Gmm *gmm); + MOCKABLE_VIRTUAL void setAuxParamsForMCSCCS(RENDER_SURFACE_STATE *surfaceState, Gmm *gmm); void setMediaImageArg(void *memory) override; void setMediaSurfaceRotation(void *memory) override; void setSurfaceMemoryObjectControlStateIndexToMocsTable(void *memory, uint32_t value) override; diff --git a/runtime/mem_obj/image.inl b/runtime/mem_obj/image.inl index cf5e8f6137..7e9b0d7300 100644 --- a/runtime/mem_obj/image.inl +++ b/runtime/mem_obj/image.inl @@ -165,7 +165,11 @@ void ImageHw::setAuxParamsForMultisamples(RENDER_SURFACE_STATE *surfa if (getMcsAllocation()) { auto mcsGmm = getMcsAllocation()->gmm; - if (mcsGmm->unifiedAuxTranslationCapable()) { // Ignore MCS allocation when Color Control Surface is available + if (mcsGmm->unifiedAuxTranslationCapable() && mcsGmm->hasMultisampleControlSurface()) { + setAuxParamsForMCSCCS(surfaceState, mcsGmm); + setClearColorParams(surfaceState, mcsGmm); + setUnifiedAuxBaseAddress(surfaceState, mcsGmm); + } else if (mcsGmm->unifiedAuxTranslationCapable()) { setAuxParamsForCCS(surfaceState, mcsGmm); } else { surfaceState->setAuxiliarySurfaceMode((typename RENDER_SURFACE_STATE::AUXILIARY_SURFACE_MODE)1); @@ -183,10 +187,14 @@ void ImageHw::setAuxParamsForCCS(RENDER_SURFACE_STATE *surfaceState, // Its expected to not program pitch/qpitch/baseAddress for Aux surface in CCS scenarios surfaceState->setAuxiliarySurfaceMode(AUXILIARY_SURFACE_MODE::AUXILIARY_SURFACE_MODE_AUX_CCS_E); setClearColorParams(surfaceState, gmm); + setUnifiedAuxBaseAddress(surfaceState, gmm); } template -void ImageHw::setClearColorParams(RENDER_SURFACE_STATE *surfaceState, const Gmm *gmm) { +void ImageHw::setUnifiedAuxBaseAddress(RENDER_SURFACE_STATE *surfaceState, const Gmm *gmm) { + uint64_t baseAddress = surfaceState->getSurfaceBaseAddress() + + gmm->gmmResourceInfo->getUnifiedAuxSurfaceOffset(GMM_UNIFIED_AUX_TYPE::GMM_AUX_SURF); + surfaceState->setAuxiliarySurfaceBaseAddress(baseAddress); } template diff --git a/runtime/mem_obj/image_base.inl b/runtime/mem_obj/image_base.inl new file mode 100644 index 0000000000..a31c61fa03 --- /dev/null +++ b/runtime/mem_obj/image_base.inl @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2019 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +namespace OCLRT { + +template +void ImageHw::setClearColorParams(RENDER_SURFACE_STATE *surfaceState, const Gmm *gmm) { +} + +template +void ImageHw::setAuxParamsForMCSCCS(RENDER_SURFACE_STATE *surfaceState, Gmm *gmm) { +} +} // namespace OCLRT diff --git a/runtime/sharings/gl/gl_texture.cpp b/runtime/sharings/gl/gl_texture.cpp index 38c8c2862f..485117b9e6 100644 --- a/runtime/sharings/gl/gl_texture.cpp +++ b/runtime/sharings/gl/gl_texture.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018-2019 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -130,6 +130,10 @@ Image *GlTexture::createSharedGlTexture(Context *context, cl_mem_flags flags, cl } auto glTexture = new GlTexture(sharingFunctions, getClGlObjectType(target), texture, texInfo, target, std::max(miplevel, 0)); + + if (alloc->gmm->unifiedAuxTranslationCapable()) { + alloc->gmm->isRenderCompressed = context->getMemoryManager()->mapAuxGpuVA(alloc); + } return Image::createSharedImage(context, glTexture, mcsSurfaceInfo, alloc, mcsAlloc, flags, imgInfo, cubeFaceIndex, std::max(miplevel, 0), imgDesc.num_mip_levels); } diff --git a/unit_tests/gmm_helper/gmm_helper_tests.cpp b/unit_tests/gmm_helper/gmm_helper_tests.cpp index a5ddf48d52..d71c210358 100644 --- a/unit_tests/gmm_helper/gmm_helper_tests.cpp +++ b/unit_tests/gmm_helper/gmm_helper_tests.cpp @@ -661,6 +661,18 @@ TEST(GmmTest, whenResourceIsCreatedThenHandleItsOwnership) { EXPECT_NE(myMockResourceInfo1.resourceInfo.get(), myMockResourceInfo2.resourceInfo.get()); } +TEST(GmmTest, givenGmmWithNotSetMCSInResourceInfoGpuFlagsWhenCallHasMultisampleControlSurfaceThenReturnFalse) { + auto gmm = std::unique_ptr(new Gmm(nullptr, 1, false)); + EXPECT_FALSE(gmm->hasMultisampleControlSurface()); +} + +TEST(GmmTest, givenGmmWithSetMCSInResourceInfoGpuFlagsWhenCallhasMultisampleControlSurfaceThenReturnTrue) { + auto gmm = std::unique_ptr(new Gmm(nullptr, 1, false)); + auto mockResource = reinterpret_cast(gmm->gmmResourceInfo.get()); + mockResource->setMultisampleControlSurface(); + EXPECT_TRUE(gmm->hasMultisampleControlSurface()); +} + TEST(GmmSimplifiedCacheSelectionPolicy, givenGmmInSimplifiedCacheSelectionPolicyWhenItIsAskedForUncachedIndexThen0IsReturned) { GmmHelper gmmHelper(*platformDevices); gmmHelper.setSimplifiedMocsTableUsage(true); diff --git a/unit_tests/mem_obj/image_set_arg_tests.cpp b/unit_tests/mem_obj/image_set_arg_tests.cpp index f8ae8080f3..24c001bbe5 100644 --- a/unit_tests/mem_obj/image_set_arg_tests.cpp +++ b/unit_tests/mem_obj/image_set_arg_tests.cpp @@ -586,7 +586,35 @@ HWTEST_F(ImageSetArgTest, givenMcsAllocationWhenSetArgIsCalledWithUnifiedAuxCapa EXPECT_TRUE(surfaceState->getAuxiliarySurfaceMode() == AUXILIARY_SURFACE_MODE::AUXILIARY_SURFACE_MODE_AUX_CCS_E); EXPECT_EQ(1u, surfaceState->getAuxiliarySurfacePitch()); EXPECT_EQ(0u, surfaceState->getAuxiliarySurfaceQpitch()); - EXPECT_EQ(0u, surfaceState->getAuxiliarySurfaceBaseAddress()); +} + +HWTEST_F(ImageSetArgTest, givenMcsAllocationWhenSetArgIsCalledWithUnifiedAuxCapabilityAndMcsThenAuxBaseAddressIsSet) { + using RENDER_SURFACE_STATE = typename FamilyType::RENDER_SURFACE_STATE; + using AUXILIARY_SURFACE_MODE = typename RENDER_SURFACE_STATE::AUXILIARY_SURFACE_MODE; + + McsSurfaceInfo msi = {10, 20, 3}; + auto mcsAlloc = context->getMemoryManager()->allocateGraphicsMemoryWithProperties(MockAllocationProperties{MemoryConstants::pageSize}); + mcsAlloc->gmm = new Gmm(nullptr, 1, false); + cl_image_desc imgDesc = Image2dDefaults::imageDesc; + imgDesc.num_samples = 8; + + auto image = std::unique_ptr(Image2dHelper<>::create(context, &imgDesc)); + image->setMcsSurfaceInfo(msi); + image->setMcsAllocation(mcsAlloc); + cl_mem memObj = image.get(); + + auto mockMcsGmmResInfo = reinterpret_cast *>(mcsAlloc->gmm->gmmResourceInfo.get()); + mockMcsGmmResInfo->setUnifiedAuxTranslationCapable(); + mockMcsGmmResInfo->setMultisampleControlSurface(); + EXPECT_TRUE(mcsAlloc->gmm->unifiedAuxTranslationCapable()); + + retVal = clSetKernelArg(pKernel, 0, sizeof(memObj), &memObj); + ASSERT_EQ(CL_SUCCESS, retVal); + + auto surfaceState = reinterpret_cast(ptrOffset(pKernel->getSurfaceStateHeap(), + pKernelInfo->kernelArgInfo[0].offsetHeap)); + + EXPECT_NE(0u, surfaceState->getAuxiliarySurfaceBaseAddress()); } HWTEST_F(ImageSetArgTest, clSetKernelArgImage1Dbuffer) { @@ -709,7 +737,6 @@ HWTEST_F(ImageSetArgTest, givenRenderCompressedResourceWhenSettingImgArgThenSetC EXPECT_TRUE(surfaceState.getAuxiliarySurfaceMode() == AUXILIARY_SURFACE_MODE::AUXILIARY_SURFACE_MODE_AUX_CCS_E); EXPECT_EQ(1u, surfaceState.getAuxiliarySurfacePitch()); EXPECT_EQ(0u, surfaceState.getAuxiliarySurfaceQpitch()); - EXPECT_EQ(0u, surfaceState.getAuxiliarySurfaceBaseAddress()); } HWTEST_F(ImageSetArgTest, givenNonRenderCompressedResourceWhenSettingImgArgThenDontSetAuxParams) { diff --git a/unit_tests/mem_obj/image_tests.cpp b/unit_tests/mem_obj/image_tests.cpp index d93ac9f175..01a528d111 100644 --- a/unit_tests/mem_obj/image_tests.cpp +++ b/unit_tests/mem_obj/image_tests.cpp @@ -1399,6 +1399,27 @@ HWTEST_F(ImageTransformTest, givenSurfaceStateWhenTransformImage2dArrayTo3dIsCal EXPECT_FALSE(surfaceState.getSurfaceArray()); } +HWTEST_F(ImageTransformTest, givenSurfaceBaseAddressAndUnifiedSurfaceWhenSetUnifiedAuxAddressCalledThenAddressIsSet) { + using RENDER_SURFACE_STATE = typename FamilyType::RENDER_SURFACE_STATE; + using SURFACE_TYPE = typename RENDER_SURFACE_STATE::SURFACE_TYPE; + MockContext context; + auto image = std::unique_ptr(ImageHelper::create(&context)); + auto surfaceState = FamilyType::cmdInitRenderSurfaceState; + auto imageHw = static_cast *>(image.get()); + auto gmm = std::unique_ptr(new Gmm(nullptr, 1, false)); + uint64_t surfBsaseAddress = 0xABCDEF1000; + surfaceState.setSurfaceBaseAddress(surfBsaseAddress); + auto mockResource = reinterpret_cast(gmm->gmmResourceInfo.get()); + mockResource->setUnifiedAuxTranslationCapable(); + + EXPECT_EQ(0u, surfaceState.getAuxiliarySurfaceBaseAddress()); + + imageHw->setUnifiedAuxBaseAddress(&surfaceState, gmm.get()); + uint64_t offset = gmm->gmmResourceInfo->getUnifiedAuxSurfaceOffset(GMM_UNIFIED_AUX_TYPE::GMM_AUX_SURF); + + EXPECT_EQ(surfBsaseAddress + offset, surfaceState.getAuxiliarySurfaceBaseAddress()); +} + template class MockImageHw : public ImageHw { public: @@ -1406,13 +1427,19 @@ class MockImageHw : public ImageHw { } void setClearColorParams(typename FamilyName::RENDER_SURFACE_STATE *surfaceState, const Gmm *gmm) override; + void setAuxParamsForMCSCCS(typename FamilyName::RENDER_SURFACE_STATE *surfaceState, Gmm *gmm) override; bool setClearColorParamsCalled = false; + bool setAuxParamsForMCSCCSCalled = false; }; template void MockImageHw::setClearColorParams(typename FamilyName::RENDER_SURFACE_STATE *surfaceState, const Gmm *gmm) { this->setClearColorParamsCalled = true; } +template +void MockImageHw::setAuxParamsForMCSCCS(typename FamilyName::RENDER_SURFACE_STATE *surfaceState, Gmm *gmm) { + this->setAuxParamsForMCSCCSCalled = true; +} using HwImageTest = ::testing::Test; HWTEST_F(HwImageTest, givenImageHwWhenSettingCCSParamsThenSetClearColorParamsIsCalled) { @@ -1447,3 +1474,45 @@ HWTEST_F(HwImageTest, givenImageHwWhenSettingCCSParamsThenSetClearColorParamsIsC mockImage->setAuxParamsForCCS(&surfaceState, graphicsAllocation->gmm); EXPECT_TRUE(mockImage->setClearColorParamsCalled); } + +using HwImageTest = ::testing::Test; +HWTEST_F(HwImageTest, givenImageHwWithUnifiedSurfaceAndMcsWhenSettingParamsForMultisampleImageThenSetParamsForCcsMcsIsCalled) { + + MockContext context; + OsAgnosticMemoryManager memoryManager(false, false, *context.getDevice(0)->getExecutionEnvironment()); + context.setMemoryManager(&memoryManager); + + cl_image_desc imgDesc = {}; + imgDesc.num_samples = 8; + cl_image_format format = {}; + + auto imgInfo = MockGmm::initImgInfo(imgDesc, 0, nullptr); + AllocationProperties allocProperties = MemObjHelper::getAllocationProperties(&imgInfo, true); + DevicesBitfield devices = 0; + + auto graphicsAllocation = memoryManager.allocateGraphicsMemoryInPreferredPool(allocProperties, devices, nullptr); + + SurfaceFormatInfo formatInfo = {}; + std::unique_ptr> mockImage(new MockImageHw(&context, format, imgDesc, formatInfo, graphicsAllocation)); + + McsSurfaceInfo msi = {10, 20, 3}; + auto mcsAlloc = context.getMemoryManager()->allocateGraphicsMemoryWithProperties(MockAllocationProperties{MemoryConstants::pageSize}); + mcsAlloc->gmm = new Gmm(nullptr, 1, false); + + auto mockMcsGmmResInfo = reinterpret_cast<::testing::NiceMock *>(mcsAlloc->gmm->gmmResourceInfo.get()); + mockMcsGmmResInfo->setUnifiedAuxTranslationCapable(); + mockMcsGmmResInfo->setMultisampleControlSurface(); + EXPECT_TRUE(mcsAlloc->gmm->unifiedAuxTranslationCapable()); + EXPECT_TRUE(mcsAlloc->gmm->hasMultisampleControlSurface()); + + mockImage->setMcsSurfaceInfo(msi); + mockImage->setMcsAllocation(mcsAlloc); + + typedef typename FamilyType::RENDER_SURFACE_STATE RENDER_SURFACE_STATE; + auto surfaceState = FamilyType::cmdInitRenderSurfaceState; + + EXPECT_FALSE(mockImage->setAuxParamsForMCSCCSCalled); + mockImage->setAuxParamsForMultisamples(&surfaceState); + + EXPECT_TRUE(mockImage->setAuxParamsForMCSCCSCalled); +} \ No newline at end of file diff --git a/unit_tests/mocks/mock_gmm_resource_info.cpp b/unit_tests/mocks/mock_gmm_resource_info.cpp index 43f5c7929c..51d2ffdf1e 100644 --- a/unit_tests/mocks/mock_gmm_resource_info.cpp +++ b/unit_tests/mocks/mock_gmm_resource_info.cpp @@ -115,6 +115,10 @@ void MockGmmResourceInfo::setUnifiedAuxTranslationCapable() { mockResourceCreateParams.Flags.Info.RenderCompressed = 1; } +void MockGmmResourceInfo::setMultisampleControlSurface() { + mockResourceCreateParams.Flags.Gpu.MCS = 1; +} + uint32_t MockGmmResourceInfo::getTileModeSurfaceState() { if (mockResourceCreateParams.Type == GMM_RESOURCE_TYPE::RESOURCE_2D || mockResourceCreateParams.Type == GMM_RESOURCE_TYPE::RESOURCE_3D) { diff --git a/unit_tests/mocks/mock_gmm_resource_info.h b/unit_tests/mocks/mock_gmm_resource_info.h index e07fb40a15..33584c605d 100644 --- a/unit_tests/mocks/mock_gmm_resource_info.h +++ b/unit_tests/mocks/mock_gmm_resource_info.h @@ -81,6 +81,7 @@ class MockGmmResourceInfo : public GmmResourceInfo { void overrideReturnedSize(size_t newSize) { size = newSize; } void setUnifiedAuxTranslationCapable(); + void setMultisampleControlSurface(); uint32_t getOffsetCalled = 0u; uint32_t arrayIndexPassedToGetOffset = 0; diff --git a/unit_tests/sharings/gl/gl_texture_tests.cpp b/unit_tests/sharings/gl/gl_texture_tests.cpp index ec7ef3a762..d6c29e6d27 100644 --- a/unit_tests/sharings/gl/gl_texture_tests.cpp +++ b/unit_tests/sharings/gl/gl_texture_tests.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018-2019 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -36,6 +36,11 @@ class GlSharingTextureTests : public ::testing::Test { } OsAgnosticMemoryManager::freeGraphicsMemoryImpl(gfxAllocation); } + bool mapAuxGpuVA(GraphicsAllocation *graphicsAllocation) override { + mapAuxGpuVACalled++; + return false; + } + uint32_t mapAuxGpuVACalled = 0u; size_t forceAllocationSize; std::unique_ptr forceGmm; bool useForcedGmm = true; @@ -68,6 +73,12 @@ class GlSharingTextureTests : public ::testing::Test { delete glSharing; } + void setUnifiedAuxSurf() { + tempMM->useForcedGmm = true; + auto mockGmmResInfo = reinterpret_cast<::testing::NiceMock *>(tempMM->forceGmm->gmmResourceInfo.get()); + mockGmmResInfo->setUnifiedAuxTranslationCapable(); + } + ExecutionEnvironment executionEnvironment; cl_image_desc imgDesc; TempMM *tempMM; @@ -516,6 +527,15 @@ TEST_F(GlSharingTextureTests, givenMockGlWhenGlTextureIsCreatedFromFormatNotIncl EXPECT_EQ(CL_INVALID_GL_OBJECT, retVal); } +TEST_F(GlSharingTextureTests, givenMockGlWhenGlTextureIsCreatedWithUnifiedAuxSurfThenMapAuxGpuVaIsCalled) { + cl_int retVal = CL_SUCCESS; + setUnifiedAuxSurf(); + EXPECT_EQ(0u, tempMM->mapAuxGpuVACalled); + + auto glTexture = std::unique_ptr(GlTexture::createSharedGlTexture(clContext.get(), CL_MEM_WRITE_ONLY, GL_SRGB8_ALPHA8, 0, textureId, &retVal)); + + EXPECT_EQ(1u, tempMM->mapAuxGpuVACalled); +} class GetGlTextureInfoTests : public GlSharingTextureTests, public ::testing::WithParamInterface { };