mirror of
https://github.com/intel/compute-runtime.git
synced 2025-09-15 13:01:45 +08:00
Load GDI once
Resolves: NEO-4174 Change-Id: I465d6137deb1dac1146a5b28ff1c100823a1d6b6 Signed-off-by: Lukasz Jobczyk <lukasz.jobczyk@intel.com>
This commit is contained in:

committed by
sys_ocldev

parent
03ce6681a0
commit
13e053f538
@ -94,6 +94,8 @@ TEST_F(DeviceFactoryTest, overrideKmdNotifySettings) {
|
||||
DebugManager.flags.OverrideEnableQuickKmdSleepForSporadicWaits.set(!refEnableQuickKmdSleepForSporadicWaits);
|
||||
DebugManager.flags.OverrideDelayQuickKmdSleepForSporadicWaitsMicroseconds.set(static_cast<int32_t>(refDelayQuickKmdSleepForSporadicWaitsMicroseconds) + 12);
|
||||
|
||||
platformsImpl.clear();
|
||||
executionEnvironment = constructPlatform()->peekExecutionEnvironment();
|
||||
success = DeviceFactory::getDevices(numDevices, *executionEnvironment);
|
||||
ASSERT_TRUE(success);
|
||||
hwInfo = executionEnvironment->rootDeviceEnvironments[0]->getHardwareInfo();
|
||||
@ -259,7 +261,8 @@ TEST(DeviceFactory, givenNonHwModeSelectedWhenIsHwModeSelectedIsCalledThenFalseI
|
||||
TEST(DiscoverDevices, whenDiscoverDevicesAndForceDeviceIdIsDifferentFromTheExistingDeviceThenReturnNullptr) {
|
||||
DebugManagerStateRestore stateRestore;
|
||||
DebugManager.flags.ForceDeviceId.set("invalid");
|
||||
auto hwDeviceIds = OSInterface::discoverDevices();
|
||||
ExecutionEnvironment executionEnviornment;
|
||||
auto hwDeviceIds = OSInterface::discoverDevices(executionEnviornment);
|
||||
EXPECT_TRUE(hwDeviceIds.empty());
|
||||
}
|
||||
|
||||
|
@ -231,10 +231,10 @@ struct PerformanceCountersFixture {
|
||||
std::unique_ptr<MockClDevice> device;
|
||||
std::unique_ptr<MockContext> context;
|
||||
std::unique_ptr<MockCommandQueue> queue;
|
||||
std::unique_ptr<OSInterface> osInterface;
|
||||
std::unique_ptr<PerformanceCounters> performanceCountersBase;
|
||||
std::unique_ptr<MockExecutionEnvironment> executionEnvironment;
|
||||
std::unique_ptr<RootDeviceEnvironment> rootDeviceEnvironment;
|
||||
std::unique_ptr<OSInterface> osInterface;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
@ -209,10 +209,11 @@ TEST_F(GlArbSyncEventOsTest, GivenNewGlSyncInfoWhenCreateSynchronizationObjectFa
|
||||
}
|
||||
|
||||
TEST_F(GlArbSyncEventOsTest, GivenNewGlSyncInfoWhenCreateEventFailsThenSetupArbSyncObjectFails) {
|
||||
auto rootDeviceEnvironment = platform()->peekExecutionEnvironment()->rootDeviceEnvironments[0].get();
|
||||
MockOSInterface mockOsInterface;
|
||||
MockOSInterfaceImpl *mockOsInterfaceImpl = static_cast<MockOSInterfaceImpl *>(mockOsInterface.get());
|
||||
|
||||
auto wddm = new WddmMock(*rootDeviceEnvironment.get());
|
||||
auto wddm = new WddmMock(*rootDeviceEnvironment);
|
||||
auto gdi = new MockGdi();
|
||||
wddm->resetGdi(gdi);
|
||||
wddm->init();
|
||||
@ -239,8 +240,9 @@ TEST_F(GlArbSyncEventOsTest, GivenInvalidGlSyncInfoWhenCleanupArbSyncObjectIsCal
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
};
|
||||
auto rootDeviceEnvironment = platform()->peekExecutionEnvironment()->rootDeviceEnvironments[0].get();
|
||||
|
||||
auto wddm = new WddmMock(*rootDeviceEnvironment.get());
|
||||
auto wddm = new WddmMock(*rootDeviceEnvironment);
|
||||
auto gdi = new MockGdi();
|
||||
wddm->resetGdi(gdi);
|
||||
wddm->init();
|
||||
@ -268,8 +270,9 @@ TEST_F(GlArbSyncEventOsTest, GivenValidGlSyncInfoWhenCleanupArbSyncObjectIsCalle
|
||||
getDestroyCounter() = 0;
|
||||
}
|
||||
};
|
||||
auto rootDeviceEnvironment = platform()->peekExecutionEnvironment()->rootDeviceEnvironments[0].get();
|
||||
|
||||
auto wddm = new WddmMock(*rootDeviceEnvironment.get());
|
||||
auto wddm = new WddmMock(*rootDeviceEnvironment);
|
||||
auto gdi = new MockGdi();
|
||||
wddm->resetGdi(gdi);
|
||||
wddm->init();
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "shared/source/os_interface/os_library.h"
|
||||
#include "shared/source/os_interface/os_time.h"
|
||||
#include "shared/source/os_interface/windows/os_context_win.h"
|
||||
#include "shared/source/os_interface/windows/os_environment_win.h"
|
||||
#include "shared/source/os_interface/windows/os_interface.h"
|
||||
#include "shared/source/os_interface/windows/wddm/wddm_interface.h"
|
||||
#include "shared/source/os_interface/windows/wddm_allocation.h"
|
||||
@ -92,6 +93,7 @@ TEST_F(Wddm20Tests, givenNullPageTableManagerAndRenderCompressedResourceWhenMapp
|
||||
|
||||
EXPECT_TRUE(wddm->mapGpuVirtualAddress(&allocation));
|
||||
}
|
||||
|
||||
TEST(WddmDiscoverDevices, WhenNoHwDeviceIdIsProvidedToWddmThenWddmIsNotCreated) {
|
||||
struct MockWddm : public Wddm {
|
||||
MockWddm(std::unique_ptr<HwDeviceId> hwDeviceIdIn, RootDeviceEnvironment &rootDeviceEnvironment) : Wddm(std::move(hwDeviceIdIn), rootDeviceEnvironment) {}
|
||||
@ -107,8 +109,9 @@ TEST(WddmDiscoverDevices, WhenAdapterDescriptionContainsDCHDAndgdrclPathDoesntCo
|
||||
descriptionBackup = L"Intel DCH-D";
|
||||
VariableBackup<const wchar_t *> igdrclPathBackup(&SysCalls::igdrclFilePath);
|
||||
igdrclPathBackup = L"intel_dch.inf";
|
||||
ExecutionEnvironment executionEnvironment;
|
||||
|
||||
auto hwDeviceIds = OSInterface::discoverDevices();
|
||||
auto hwDeviceIds = OSInterface::discoverDevices(executionEnvironment);
|
||||
EXPECT_TRUE(hwDeviceIds.empty());
|
||||
}
|
||||
|
||||
@ -117,15 +120,17 @@ TEST(WddmDiscoverDevices, WhenAdapterDescriptionContainsDCHIAndgdrclPathDoesntCo
|
||||
descriptionBackup = L"Intel DCH-I";
|
||||
VariableBackup<const wchar_t *> igdrclPathBackup(&SysCalls::igdrclFilePath);
|
||||
igdrclPathBackup = L"intel_dch.inf";
|
||||
ExecutionEnvironment executionEnvironment;
|
||||
|
||||
auto hwDeviceIds = OSInterface::discoverDevices();
|
||||
auto hwDeviceIds = OSInterface::discoverDevices(executionEnvironment);
|
||||
EXPECT_TRUE(hwDeviceIds.empty());
|
||||
}
|
||||
|
||||
TEST(WddmDiscoverDevices, WhenMultipleRootDevicesAreAvailableThenAllAreDiscovered) {
|
||||
VariableBackup<uint32_t> backup{&numRootDevicesToEnum};
|
||||
numRootDevicesToEnum = 3u;
|
||||
auto hwDeviceIds = OSInterface::discoverDevices();
|
||||
ExecutionEnvironment executionEnvironment;
|
||||
auto hwDeviceIds = OSInterface::discoverDevices(executionEnvironment);
|
||||
EXPECT_EQ(numRootDevicesToEnum, hwDeviceIds.size());
|
||||
}
|
||||
|
||||
@ -134,8 +139,9 @@ TEST(WddmDiscoverDevices, WhenAdapterDescriptionContainsDCHDAndgdrclPathContains
|
||||
descriptionBackup = L"Intel DCH-D";
|
||||
VariableBackup<const wchar_t *> igdrclPathBackup(&SysCalls::igdrclFilePath);
|
||||
igdrclPathBackup = L"intel_dch_d.inf";
|
||||
ExecutionEnvironment executionEnvironment;
|
||||
|
||||
auto hwDeviceIds = OSInterface::discoverDevices();
|
||||
auto hwDeviceIds = OSInterface::discoverDevices(executionEnvironment);
|
||||
EXPECT_EQ(1u, hwDeviceIds.size());
|
||||
EXPECT_NE(nullptr, hwDeviceIds[0].get());
|
||||
}
|
||||
@ -145,8 +151,9 @@ TEST(Wddm20EnumAdaptersTest, WhenAdapterDescriptionContainsDCHIAndgdrclPathConta
|
||||
descriptionBackup = L"Intel DCH-I";
|
||||
VariableBackup<const wchar_t *> igdrclPathBackup(&SysCalls::igdrclFilePath);
|
||||
igdrclPathBackup = L"intel_dch_i.inf";
|
||||
ExecutionEnvironment executionEnvironment;
|
||||
|
||||
auto hwDeviceIds = OSInterface::discoverDevices();
|
||||
auto hwDeviceIds = OSInterface::discoverDevices(executionEnvironment);
|
||||
EXPECT_EQ(1u, hwDeviceIds.size());
|
||||
EXPECT_NE(nullptr, hwDeviceIds[0].get());
|
||||
}
|
||||
@ -154,8 +161,9 @@ TEST(Wddm20EnumAdaptersTest, WhenAdapterDescriptionContainsDCHIAndgdrclPathConta
|
||||
TEST(WddmDiscoverDevices, WhenAdapterDescriptionContainsVirtualRenderThenAdapterIsDiscovered) {
|
||||
VariableBackup<const wchar_t *> descriptionBackup(&UltIDXGIAdapter1::description);
|
||||
descriptionBackup = L"Virtual Render";
|
||||
ExecutionEnvironment executionEnvironment;
|
||||
|
||||
auto hwDeviceIds = OSInterface::discoverDevices();
|
||||
auto hwDeviceIds = OSInterface::discoverDevices(executionEnvironment);
|
||||
EXPECT_EQ(1u, hwDeviceIds.size());
|
||||
EXPECT_NE(nullptr, hwDeviceIds[0].get());
|
||||
}
|
||||
@ -566,7 +574,8 @@ HWTEST_F(Wddm20InstrumentationTest, configureDeviceAddressSpaceOnInit) {
|
||||
}
|
||||
|
||||
TEST_F(Wddm20InstrumentationTest, configureDeviceAddressSpaceNoAdapter) {
|
||||
wddm->hwDeviceId = std::make_unique<HwDeviceId>(0, LUID{}, std::make_unique<Gdi>());
|
||||
auto gdi = std::make_unique<Gdi>();
|
||||
wddm->resetGdi(gdi.release());
|
||||
EXPECT_CALL(*gmmMem,
|
||||
configureDeviceAddressSpace(static_cast<D3DKMT_HANDLE>(0), ::testing::_, ::testing::_, ::testing::_, ::testing::_))
|
||||
.Times(0);
|
||||
@ -1097,14 +1106,14 @@ TEST_F(WddmGfxPartitionTest, initGfxPartition) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(WddmGfxPartitionTest, initGfxPartitionHeapStandard64KBSplit) {
|
||||
TEST(WddmGfxPartitionTests, initGfxPartitionHeapStandard64KBSplit) {
|
||||
struct MockWddm : public Wddm {
|
||||
using Wddm::gfxPartition;
|
||||
|
||||
MockWddm(RootDeviceEnvironment &rootDeviceEnvironment) : Wddm(std::move(OSInterface::discoverDevices()[0]), rootDeviceEnvironment) {}
|
||||
MockWddm(RootDeviceEnvironment &rootDeviceEnvironment) : Wddm(std::move(OSInterface::discoverDevices(rootDeviceEnvironment.executionEnvironment)[0]), rootDeviceEnvironment) {}
|
||||
};
|
||||
|
||||
MockWddm wddm(*executionEnvironment->rootDeviceEnvironments[0].get());
|
||||
MockWddm wddm(*platform()->peekExecutionEnvironment()->rootDeviceEnvironments[0].get());
|
||||
|
||||
uint32_t rootDeviceIndex = 3;
|
||||
size_t numRootDevices = 5;
|
||||
@ -1121,7 +1130,8 @@ TEST_F(WddmGfxPartitionTest, initGfxPartitionHeapStandard64KBSplit) {
|
||||
TEST_F(Wddm20Tests, givenWddmWhenDiscoverDevicesAndForceDeviceIdIsTheSameAsTheExistingDeviceThenReturnTheAdapter) {
|
||||
DebugManagerStateRestore stateRestore;
|
||||
DebugManager.flags.ForceDeviceId.set("1234"); // Existing device Id
|
||||
auto hwDeviceIds = OSInterface::discoverDevices();
|
||||
ExecutionEnvironment executionEnvironment;
|
||||
auto hwDeviceIds = OSInterface::discoverDevices(executionEnvironment);
|
||||
EXPECT_EQ(1u, hwDeviceIds.size());
|
||||
EXPECT_NE(nullptr, hwDeviceIds[0].get());
|
||||
}
|
||||
@ -1259,10 +1269,13 @@ struct GdiWithMockedCloseFunc : public Gdi {
|
||||
uint32_t GdiWithMockedCloseFunc::closeAdapterCalled;
|
||||
D3DKMT_HANDLE GdiWithMockedCloseFunc::closeAdapterCalledArgPassed;
|
||||
TEST(HwDeviceId, whenHwDeviceIdIsDestroyedThenAdapterIsClosed) {
|
||||
auto gdi = std::make_unique<GdiWithMockedCloseFunc>();
|
||||
auto osEnv = std::make_unique<OsEnvironmentWin>();
|
||||
osEnv->gdi.reset(gdi.release());
|
||||
|
||||
D3DKMT_HANDLE adapter = 0x1234;
|
||||
{
|
||||
HwDeviceId hwDeviceId{adapter, {}, std::make_unique<GdiWithMockedCloseFunc>()};
|
||||
HwDeviceId hwDeviceId{adapter, {}, osEnv.get()};
|
||||
}
|
||||
EXPECT_EQ(1u, GdiWithMockedCloseFunc::closeAdapterCalled);
|
||||
EXPECT_EQ(adapter, GdiWithMockedCloseFunc::closeAdapterCalledArgPassed);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "shared/source/helpers/hw_helper.h"
|
||||
#include "shared/source/os_interface/windows/gdi_interface.h"
|
||||
#include "shared/source/os_interface/windows/os_context_win.h"
|
||||
#include "shared/source/os_interface/windows/os_environment_win.h"
|
||||
#include "shared/source/os_interface/windows/os_interface.h"
|
||||
#include "shared/source/os_interface/windows/wddm_memory_operations_handler.h"
|
||||
#include "shared/test/unit_test/helpers/default_hw_info.h"
|
||||
@ -32,13 +33,15 @@ struct WddmFixture : ::testing::Test {
|
||||
void SetUp() override {
|
||||
executionEnvironment = platform()->peekExecutionEnvironment();
|
||||
rootDeviceEnvironemnt = executionEnvironment->rootDeviceEnvironments[0].get();
|
||||
auto osEnvironment = new OsEnvironmentWin();
|
||||
gdi = new MockGdi();
|
||||
osEnvironment->gdi.reset(gdi);
|
||||
executionEnvironment->osEnvironment.reset(osEnvironment);
|
||||
wddm = static_cast<WddmMock *>(Wddm::createWddm(nullptr, *rootDeviceEnvironemnt));
|
||||
rootDeviceEnvironemnt->osInterface = std::make_unique<OSInterface>();
|
||||
rootDeviceEnvironemnt->osInterface->get()->setWddm(wddm);
|
||||
rootDeviceEnvironemnt->memoryOperationsInterface = std::make_unique<WddmMemoryOperationsHandler>(wddm);
|
||||
osInterface = rootDeviceEnvironemnt->osInterface.get();
|
||||
gdi = new MockGdi();
|
||||
wddm->resetGdi(gdi);
|
||||
auto preemptionMode = PreemptionHelper::getDefaultPreemptionMode(*platformDevices[0]);
|
||||
wddm->init();
|
||||
auto hwInfo = rootDeviceEnvironemnt->getHardwareInfo();
|
||||
@ -50,9 +53,9 @@ struct WddmFixture : ::testing::Test {
|
||||
|
||||
WddmMock *wddm = nullptr;
|
||||
OSInterface *osInterface;
|
||||
std::unique_ptr<OsContextWin> osContext;
|
||||
ExecutionEnvironment *executionEnvironment;
|
||||
RootDeviceEnvironment *rootDeviceEnvironemnt = nullptr;
|
||||
std::unique_ptr<OsContextWin> osContext;
|
||||
|
||||
MockGdi *gdi = nullptr;
|
||||
MockWddmResidentAllocationsContainer *mockTemporaryResources;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "shared/source/gmm_helper/gmm.h"
|
||||
#include "shared/source/gmm_helper/gmm_helper.h"
|
||||
#include "shared/source/memory_manager/memory_manager.h"
|
||||
#include "shared/source/os_interface/windows/os_environment_win.h"
|
||||
#include "shared/source/os_interface/windows/wddm/wddm.h"
|
||||
#include "shared/source/os_interface/windows/wddm_allocation.h"
|
||||
#include "shared/test/unit_test/os_interface/windows/mock_gdi_interface.h"
|
||||
@ -27,7 +28,7 @@ class WddmWithKmDafMock : public Wddm {
|
||||
using Wddm::featureTable;
|
||||
using Wddm::mapGpuVirtualAddress;
|
||||
|
||||
WddmWithKmDafMock(RootDeviceEnvironment &rootDeviceEnvironment, Gdi *mockGdi) : Wddm(std::make_unique<HwDeviceId>(ADAPTER_HANDLE, LUID{}, std::unique_ptr<Gdi>(mockGdi)), rootDeviceEnvironment) {
|
||||
WddmWithKmDafMock(RootDeviceEnvironment &rootDeviceEnvironment) : Wddm(std::make_unique<HwDeviceId>(ADAPTER_HANDLE, LUID{}, rootDeviceEnvironment.executionEnvironment.osEnvironment.get()), rootDeviceEnvironment) {
|
||||
kmDafListener.reset(new KmDafListenerMock);
|
||||
}
|
||||
|
||||
@ -41,7 +42,10 @@ class WddmKmDafListenerTest : public ::testing::Test {
|
||||
void SetUp() {
|
||||
executionEnvironment = platform()->peekExecutionEnvironment();
|
||||
rootDeviceEnvironment = executionEnvironment->rootDeviceEnvironments[0].get();
|
||||
wddmWithKmDafMock.reset(new WddmWithKmDafMock(*rootDeviceEnvironment, new MockGdi()));
|
||||
auto osEnvironment = new OsEnvironmentWin();
|
||||
osEnvironment->gdi.reset(new MockGdi());
|
||||
executionEnvironment->osEnvironment.reset(osEnvironment);
|
||||
wddmWithKmDafMock.reset(new WddmWithKmDafMock(*rootDeviceEnvironment));
|
||||
wddmWithKmDafMock->init();
|
||||
wddmWithKmDafMock->featureTable->ftrKmdDaf = true;
|
||||
}
|
||||
|
@ -1268,9 +1268,10 @@ TEST_F(BufferWithWddmMemory, givenFragmentsThatAreNotInOrderWhenGraphicsAllocati
|
||||
memoryManager->freeGraphicsMemory(allocation);
|
||||
}
|
||||
|
||||
struct WddmMemoryManagerWithAsyncDeleterTest : public MockWddmMemoryManagerTest {
|
||||
struct WddmMemoryManagerWithAsyncDeleterTest : public ::testing::Test {
|
||||
void SetUp() {
|
||||
MockWddmMemoryManagerTest::SetUp();
|
||||
executionEnvironment = getExecutionEnvironmentImpl(hwInfo, 1);
|
||||
wddm = static_cast<WddmMock *>(executionEnvironment->rootDeviceEnvironments[0]->osInterface->get()->getWddm());
|
||||
wddm->resetGdi(new MockGdi());
|
||||
wddm->callBaseDestroyAllocations = false;
|
||||
wddm->init();
|
||||
@ -1280,6 +1281,9 @@ struct WddmMemoryManagerWithAsyncDeleterTest : public MockWddmMemoryManagerTest
|
||||
}
|
||||
MockDeferredDeleter *deleter = nullptr;
|
||||
std::unique_ptr<MockWddmMemoryManager> memoryManager;
|
||||
ExecutionEnvironment *executionEnvironment;
|
||||
HardwareInfo *hwInfo;
|
||||
WddmMock *wddm;
|
||||
};
|
||||
|
||||
TEST_F(WddmMemoryManagerWithAsyncDeleterTest, givenWddmWhenAsyncDeleterIsEnabledThenCanDeferDeletions) {
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "shared/source/os_interface/windows/os_environment_win.h"
|
||||
#include "shared/source/os_interface/windows/os_interface.h"
|
||||
#include "shared/source/os_interface/windows/wddm_memory_operations_handler.h"
|
||||
#include "shared/test/unit_test/os_interface/windows/mock_gdi_interface.h"
|
||||
@ -49,10 +50,11 @@ class MockWddmMemoryManagerFixture {
|
||||
void SetUp() {
|
||||
executionEnvironment = platform()->peekExecutionEnvironment();
|
||||
rootDeviceEnvironment = executionEnvironment->rootDeviceEnvironments[0].get();
|
||||
auto osEnvironment = new OsEnvironmentWin();
|
||||
gdi = new MockGdi();
|
||||
|
||||
osEnvironment->gdi.reset(gdi);
|
||||
executionEnvironment->osEnvironment.reset(osEnvironment);
|
||||
wddm = static_cast<WddmMock *>(Wddm::createWddm(nullptr, *rootDeviceEnvironment));
|
||||
wddm->resetGdi(gdi);
|
||||
constexpr uint64_t heap32Base = (is32bit) ? 0x1000 : 0x800000000000;
|
||||
wddm->setHeap32(heap32Base, 1000 * MemoryConstants::pageSize - 1);
|
||||
wddm->init();
|
||||
|
@ -81,10 +81,10 @@ struct WddmResidencyControllerTest : ::testing::Test {
|
||||
residencyController = &mockOsContextWin->mockResidencyController;
|
||||
}
|
||||
|
||||
std::unique_ptr<WddmMock> wddm;
|
||||
std::unique_ptr<MockOsContextWin> mockOsContextWin;
|
||||
std::unique_ptr<MockExecutionEnvironment> executionEnvironment;
|
||||
std::unique_ptr<RootDeviceEnvironment> rootDeviceEnvironment;
|
||||
std::unique_ptr<WddmMock> wddm;
|
||||
std::unique_ptr<MockOsContextWin> mockOsContextWin;
|
||||
MockWddmResidencyController *residencyController = nullptr;
|
||||
};
|
||||
|
||||
@ -106,10 +106,10 @@ struct WddmResidencyControllerWithGdiTest : ::testing::Test {
|
||||
residencyController->registerCallback();
|
||||
}
|
||||
|
||||
std::unique_ptr<WddmMock> wddm;
|
||||
std::unique_ptr<MockOsContextWin> mockOsContextWin;
|
||||
std::unique_ptr<MockExecutionEnvironment> executionEnvironment;
|
||||
std::unique_ptr<RootDeviceEnvironment> rootDeviceEnvironment;
|
||||
std::unique_ptr<WddmMock> wddm;
|
||||
std::unique_ptr<MockOsContextWin> mockOsContextWin;
|
||||
MockWddmResidencyController *residencyController = nullptr;
|
||||
MockGdi *gdi;
|
||||
};
|
||||
|
Reference in New Issue
Block a user