mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-20 19:54:19 +01:00
[d3d11] Added DXGI format properties
This commit is contained in:
parent
b4e10b7f06
commit
659ec7b59d
@ -161,10 +161,13 @@ namespace dxvk {
|
||||
// Fill in the view info. The view type depends solely
|
||||
// on the view dimension field in the view description,
|
||||
// not on the resource type.
|
||||
const DxgiFormatInfo formatInfo = m_dxgiAdapter
|
||||
->LookupFormat(desc.Format, textureInfo.formatMode);
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.format = m_dxgiAdapter->LookupFormat(
|
||||
desc.Format, textureInfo.formatMode).actual;
|
||||
viewInfo.aspect = imageFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.format = formatInfo.format;
|
||||
viewInfo.aspect = formatInfo.aspect;
|
||||
viewInfo.swizzle = formatInfo.swizzle;
|
||||
|
||||
switch (desc.ViewDimension) {
|
||||
case D3D11_SRV_DIMENSION_TEXTURE1D:
|
||||
@ -306,7 +309,7 @@ namespace dxvk {
|
||||
|
||||
// Fill in Vulkan image view info
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.format = m_dxgiAdapter->LookupFormat(desc.Format, DxgiFormatMode::Color).actual;
|
||||
viewInfo.format = m_dxgiAdapter->LookupFormat(desc.Format, DxgiFormatMode::Color).format;
|
||||
viewInfo.aspect = imageFormatInfo(viewInfo.format)->aspectMask;
|
||||
|
||||
switch (desc.ViewDimension) {
|
||||
@ -400,7 +403,7 @@ namespace dxvk {
|
||||
|
||||
// Fill in Vulkan image view info
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.format = m_dxgiAdapter->LookupFormat(desc.Format, DxgiFormatMode::Depth).actual;
|
||||
viewInfo.format = m_dxgiAdapter->LookupFormat(desc.Format, DxgiFormatMode::Depth).format;
|
||||
viewInfo.aspect = imageFormatInfo(viewInfo.format)->aspectMask;
|
||||
|
||||
switch (desc.ViewDimension) {
|
||||
@ -494,7 +497,7 @@ namespace dxvk {
|
||||
attrib.location = entry->registerId;
|
||||
attrib.binding = pInputElementDescs[i].InputSlot;
|
||||
attrib.format = m_dxgiAdapter->LookupFormat(
|
||||
pInputElementDescs[i].Format, DxgiFormatMode::Color).actual;
|
||||
pInputElementDescs[i].Format, DxgiFormatMode::Color).format;
|
||||
attrib.offset = pInputElementDescs[i].AlignedByteOffset;
|
||||
|
||||
// The application may choose to let the implementation
|
||||
@ -886,7 +889,7 @@ namespace dxvk {
|
||||
|
||||
// We need to check whether the format is
|
||||
VkFormat format = m_dxgiAdapter->LookupFormat(
|
||||
Format, DxgiFormatMode::Any).actual;
|
||||
Format, DxgiFormatMode::Any).format;
|
||||
|
||||
if (format == VK_FORMAT_UNDEFINED) {
|
||||
Logger::err(str::format("D3D11: Unsupported format: ", Format));
|
||||
@ -1024,7 +1027,7 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
DxgiFormatPair STDMETHODCALLTYPE D3D11Device::LookupFormat(
|
||||
DxgiFormatInfo STDMETHODCALLTYPE D3D11Device::LookupFormat(
|
||||
DXGI_FORMAT format,
|
||||
DxgiFormatMode mode) const {
|
||||
return m_dxgiAdapter->LookupFormat(format, mode);
|
||||
@ -1382,7 +1385,7 @@ namespace dxvk {
|
||||
|
||||
|
||||
HRESULT D3D11Device::GetFormatSupportFlags(DXGI_FORMAT Format, UINT* pFlags) const {
|
||||
const VkFormat fmt = m_dxgiAdapter->LookupFormat(Format, DxgiFormatMode::Any).actual;
|
||||
const VkFormat fmt = m_dxgiAdapter->LookupFormat(Format, DxgiFormatMode::Any).format;
|
||||
const VkFormatProperties fmtInfo = m_dxvkAdapter->formatProperties(fmt);
|
||||
|
||||
if (fmt == VK_FORMAT_UNDEFINED)
|
||||
|
@ -228,7 +228,7 @@ namespace dxvk {
|
||||
|
||||
VkPipelineStageFlags GetEnabledShaderStages() const;
|
||||
|
||||
DxgiFormatPair STDMETHODCALLTYPE LookupFormat(
|
||||
DxgiFormatInfo STDMETHODCALLTYPE LookupFormat(
|
||||
DXGI_FORMAT format,
|
||||
DxgiFormatMode mode) const;
|
||||
|
||||
|
@ -24,7 +24,7 @@ namespace dxvk {
|
||||
DxvkImageCreateInfo info;
|
||||
info.type = VK_IMAGE_TYPE_2D;
|
||||
info.format = pDevice->LookupFormat(
|
||||
pDesc->Format, m_formatMode).actual;
|
||||
pDesc->Format, m_formatMode).format;
|
||||
info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
|
||||
info.sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
info.extent.width = pDesc->Width;
|
||||
|
@ -1253,6 +1253,13 @@ namespace dxvk {
|
||||
sampledImageId, coord.id);
|
||||
} break;
|
||||
|
||||
case DxbcOpcode::SampleC: {
|
||||
result.id = m_module.opImageSampleDrefImplicitLod(
|
||||
getVectorTypeId(result.type),
|
||||
sampledImageId, coord.id,
|
||||
referenceValue.id);
|
||||
} break;
|
||||
|
||||
case DxbcOpcode::SampleClz: {
|
||||
result.id = m_module.opImageSampleDrefExplicitLod(
|
||||
getVectorTypeId(result.type),
|
||||
|
@ -138,7 +138,7 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
DxgiFormatPair STDMETHODCALLTYPE DxgiAdapter::LookupFormat(DXGI_FORMAT format, DxgiFormatMode mode) {
|
||||
DxgiFormatInfo STDMETHODCALLTYPE DxgiAdapter::LookupFormat(DXGI_FORMAT format, DxgiFormatMode mode) {
|
||||
// If the mode is 'Any', probe color formats first
|
||||
if (mode != DxgiFormatMode::Depth) {
|
||||
auto color = m_colorFormats.find(format);
|
||||
@ -153,26 +153,52 @@ namespace dxvk {
|
||||
return depth->second;
|
||||
}
|
||||
|
||||
return DxgiFormatPair();
|
||||
Logger::err(str::format("DxgiAdapter: No format mapping for ", format));
|
||||
return DxgiFormatInfo();
|
||||
}
|
||||
|
||||
|
||||
void DxgiAdapter::AddColorFormat(
|
||||
DXGI_FORMAT srcFormat,
|
||||
VkFormat dstFormat) {
|
||||
DxgiFormatPair formatPair;
|
||||
formatPair.wanted = dstFormat;
|
||||
formatPair.actual = dstFormat;
|
||||
DxgiFormatInfo formatPair;
|
||||
formatPair.format = dstFormat;
|
||||
formatPair.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
formatPair.swizzle = {
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
};
|
||||
m_colorFormats.insert(std::make_pair(srcFormat, formatPair));
|
||||
}
|
||||
|
||||
|
||||
void DxgiAdapter::AddColorFormat(
|
||||
DXGI_FORMAT srcFormat,
|
||||
VkFormat dstFormat,
|
||||
VkComponentMapping swizzle) {
|
||||
DxgiFormatInfo formatPair;
|
||||
formatPair.format = dstFormat;
|
||||
formatPair.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
formatPair.swizzle = swizzle;
|
||||
m_colorFormats.insert(std::make_pair(srcFormat, formatPair));
|
||||
}
|
||||
|
||||
|
||||
void DxgiAdapter::AddDepthFormat(
|
||||
DXGI_FORMAT srcFormat,
|
||||
VkFormat dstFormat) {
|
||||
DxgiFormatPair formatPair;
|
||||
formatPair.wanted = dstFormat;
|
||||
formatPair.actual = dstFormat;
|
||||
VkFormat dstFormat,
|
||||
VkImageAspectFlags srvAspect) {
|
||||
DxgiFormatInfo formatPair;
|
||||
formatPair.format = dstFormat;
|
||||
formatPair.aspect = srvAspect;
|
||||
formatPair.swizzle = {
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
};
|
||||
m_depthFormats.insert(std::make_pair(srcFormat, formatPair));
|
||||
}
|
||||
|
||||
@ -263,10 +289,18 @@ namespace dxvk {
|
||||
AddColorFormat(DXGI_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM);
|
||||
AddColorFormat(DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, VK_FORMAT_B8G8R8A8_SRGB);
|
||||
|
||||
// TODO implement component swizzle
|
||||
AddColorFormat(DXGI_FORMAT_B8G8R8X8_UNORM, VK_FORMAT_B8G8R8A8_UNORM);
|
||||
AddColorFormat(DXGI_FORMAT_B8G8R8X8_TYPELESS, VK_FORMAT_B8G8R8A8_UNORM);
|
||||
AddColorFormat(DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, VK_FORMAT_B8G8R8A8_SRGB);
|
||||
AddColorFormat(DXGI_FORMAT_B8G8R8X8_UNORM, VK_FORMAT_B8G8R8A8_UNORM,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
|
||||
VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE });
|
||||
|
||||
AddColorFormat(DXGI_FORMAT_B8G8R8X8_TYPELESS, VK_FORMAT_B8G8R8A8_UNORM,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
|
||||
VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE });
|
||||
|
||||
AddColorFormat(DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, VK_FORMAT_B8G8R8A8_SRGB,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
|
||||
VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE });
|
||||
|
||||
// AddColorFormat(DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, VK_FORMAT_UNDEFINED);
|
||||
|
||||
/***********************************************************************************/
|
||||
@ -301,30 +335,32 @@ namespace dxvk {
|
||||
|
||||
/***********************************************************************************/
|
||||
/* D E P T H F O R M A T S */
|
||||
AddDepthFormat(DXGI_FORMAT_D16_UNORM, VK_FORMAT_D16_UNORM);
|
||||
AddDepthFormat(DXGI_FORMAT_R16_UNORM, VK_FORMAT_D16_UNORM);
|
||||
AddDepthFormat(DXGI_FORMAT_R16_TYPELESS, VK_FORMAT_D16_UNORM);
|
||||
AddDepthFormat(DXGI_FORMAT_D16_UNORM, VK_FORMAT_D16_UNORM, 0);
|
||||
AddDepthFormat(DXGI_FORMAT_R16_TYPELESS, VK_FORMAT_D16_UNORM, 0);
|
||||
AddDepthFormat(DXGI_FORMAT_R16_UNORM, VK_FORMAT_D16_UNORM, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
|
||||
AddDepthFormat(DXGI_FORMAT_D32_FLOAT, VK_FORMAT_D32_SFLOAT);
|
||||
AddDepthFormat(DXGI_FORMAT_R32_FLOAT, VK_FORMAT_D32_SFLOAT);
|
||||
AddDepthFormat(DXGI_FORMAT_R32_TYPELESS, VK_FORMAT_D32_SFLOAT);
|
||||
AddDepthFormat(DXGI_FORMAT_D32_FLOAT, VK_FORMAT_D32_SFLOAT, 0);
|
||||
AddDepthFormat(DXGI_FORMAT_R32_TYPELESS, VK_FORMAT_D32_SFLOAT, 0);
|
||||
AddDepthFormat(DXGI_FORMAT_R32_FLOAT, VK_FORMAT_D32_SFLOAT, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
|
||||
AddDepthFormat(DXGI_FORMAT_D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT);
|
||||
AddDepthFormat(DXGI_FORMAT_R32G8X24_TYPELESS, VK_FORMAT_D32_SFLOAT_S8_UINT);
|
||||
AddDepthFormat(DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, VK_FORMAT_D32_SFLOAT_S8_UINT);
|
||||
AddDepthFormat(DXGI_FORMAT_X32_TYPELESS_G8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT);
|
||||
AddDepthFormat(DXGI_FORMAT_D32_FLOAT_S8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, 0);
|
||||
AddDepthFormat(DXGI_FORMAT_R32G8X24_TYPELESS, VK_FORMAT_D32_SFLOAT_S8_UINT, 0);
|
||||
AddDepthFormat(DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
AddDepthFormat(DXGI_FORMAT_X32_TYPELESS_G8X24_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_IMAGE_ASPECT_STENCIL_BIT);
|
||||
|
||||
// Vulkan implementations are not required to support 24-bit depth buffers natively
|
||||
// and AMD decided to not implement them, so we'll fall back to 32-bit depth buffers
|
||||
if (HasFormatSupport(VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
|
||||
AddDepthFormat(DXGI_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT);
|
||||
AddDepthFormat(DXGI_FORMAT_R24_UNORM_X8_TYPELESS, VK_FORMAT_D24_UNORM_S8_UINT);
|
||||
AddDepthFormat(DXGI_FORMAT_X24_TYPELESS_G8_UINT, VK_FORMAT_D24_UNORM_S8_UINT);
|
||||
AddDepthFormat(DXGI_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, 0);
|
||||
AddDepthFormat(DXGI_FORMAT_R24G8_TYPELESS, VK_FORMAT_D24_UNORM_S8_UINT, 0);
|
||||
AddDepthFormat(DXGI_FORMAT_R24_UNORM_X8_TYPELESS, VK_FORMAT_D24_UNORM_S8_UINT, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
AddDepthFormat(DXGI_FORMAT_X24_TYPELESS_G8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, VK_IMAGE_ASPECT_STENCIL_BIT);
|
||||
} else {
|
||||
Logger::warn("DxgiAdapter: DXGI_FORMAT_D24_UNORM_S8_UINT -> VK_FORMAT_D32_SFLOAT_S8_UINT");
|
||||
AddDepthFormat(DXGI_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT);
|
||||
AddDepthFormat(DXGI_FORMAT_R24_UNORM_X8_TYPELESS, VK_FORMAT_D32_SFLOAT_S8_UINT);
|
||||
AddDepthFormat(DXGI_FORMAT_X24_TYPELESS_G8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT);
|
||||
AddDepthFormat(DXGI_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, 0);
|
||||
AddDepthFormat(DXGI_FORMAT_R24G8_TYPELESS, VK_FORMAT_D32_SFLOAT_S8_UINT, 0);
|
||||
AddDepthFormat(DXGI_FORMAT_R24_UNORM_X8_TYPELESS, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
AddDepthFormat(DXGI_FORMAT_X24_TYPELESS_G8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_IMAGE_ASPECT_STENCIL_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -332,7 +368,7 @@ namespace dxvk {
|
||||
bool DxgiAdapter::HasFormatSupport(
|
||||
VkFormat format,
|
||||
VkFormatFeatureFlags features) const {
|
||||
VkFormatProperties info = m_adapter->formatProperties(format);
|
||||
const VkFormatProperties info = m_adapter->formatProperties(format);
|
||||
return ((info.optimalTilingFeatures | info.bufferFeatures) & features) == features;
|
||||
}
|
||||
|
||||
|
@ -48,12 +48,12 @@ namespace dxvk {
|
||||
|
||||
Rc<DxvkAdapter> STDMETHODCALLTYPE GetDXVKAdapter() final;
|
||||
|
||||
DxgiFormatPair STDMETHODCALLTYPE LookupFormat(
|
||||
DxgiFormatInfo STDMETHODCALLTYPE LookupFormat(
|
||||
DXGI_FORMAT format, DxgiFormatMode mode) final;
|
||||
|
||||
private:
|
||||
|
||||
using FormatMap = std::unordered_map<DXGI_FORMAT, DxgiFormatPair>;
|
||||
using FormatMap = std::unordered_map<DXGI_FORMAT, DxgiFormatInfo>;
|
||||
|
||||
Com<DxgiFactory> m_factory;
|
||||
Rc<DxvkAdapter> m_adapter;
|
||||
@ -65,9 +65,15 @@ namespace dxvk {
|
||||
DXGI_FORMAT srcFormat,
|
||||
VkFormat dstFormat);
|
||||
|
||||
void AddColorFormat(
|
||||
DXGI_FORMAT srcFormat,
|
||||
VkFormat dstFormat,
|
||||
VkComponentMapping swizzle);
|
||||
|
||||
void AddDepthFormat(
|
||||
DXGI_FORMAT srcFormat,
|
||||
VkFormat dstFormat);
|
||||
VkFormat dstFormat,
|
||||
VkImageAspectFlags srvAspect);
|
||||
|
||||
void SetupFormatTable();
|
||||
|
||||
|
@ -12,17 +12,17 @@ namespace dxvk {
|
||||
class DxvkImage;
|
||||
|
||||
/**
|
||||
* \brief Format pair
|
||||
* \brief Format info
|
||||
*
|
||||
* For a DXGI format, this stores two Vulkan formats:
|
||||
* The format that directly corresponds to the DXGI
|
||||
* format, and a similar format that the device can
|
||||
* use. If the device supports the desired format,
|
||||
* both formats will be equal.
|
||||
* Stores a Vulkan image format for a given
|
||||
* DXGI format and some additional information
|
||||
* on how resources with the particular format
|
||||
* are supposed to be used.
|
||||
*/
|
||||
struct DxgiFormatPair {
|
||||
VkFormat wanted = VK_FORMAT_UNDEFINED;
|
||||
VkFormat actual = VK_FORMAT_UNDEFINED;
|
||||
struct DxgiFormatInfo {
|
||||
VkFormat format;
|
||||
VkImageAspectFlags aspect;
|
||||
VkComponentMapping swizzle;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -64,7 +64,7 @@ IDXGIAdapterPrivate : public IDXGIAdapter1 {
|
||||
* \param [in] mode Format lookup mode
|
||||
* \returns Vulkan format pair
|
||||
*/
|
||||
virtual dxvk::DxgiFormatPair STDMETHODCALLTYPE LookupFormat(
|
||||
virtual dxvk::DxgiFormatInfo STDMETHODCALLTYPE LookupFormat(
|
||||
DXGI_FORMAT format,
|
||||
dxvk::DxgiFormatMode mode) = 0;
|
||||
};
|
||||
|
@ -1533,6 +1533,41 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvModule::opImageSampleExplicitLod(
|
||||
uint32_t resultType,
|
||||
uint32_t sampledImage,
|
||||
uint32_t coordinates,
|
||||
uint32_t lod) {
|
||||
uint32_t resultId = this->allocateId();
|
||||
|
||||
m_code.putIns (spv::OpImageSampleExplicitLod, 7);
|
||||
m_code.putWord(resultType);
|
||||
m_code.putWord(resultId);
|
||||
m_code.putWord(sampledImage);
|
||||
m_code.putWord(coordinates);
|
||||
m_code.putWord(spv::ImageOperandsLodMask);
|
||||
m_code.putWord(lod);
|
||||
return resultId;
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvModule::opImageSampleDrefImplicitLod(
|
||||
uint32_t resultType,
|
||||
uint32_t sampledImage,
|
||||
uint32_t coordinates,
|
||||
uint32_t reference) {
|
||||
uint32_t resultId = this->allocateId();
|
||||
|
||||
m_code.putIns (spv::OpImageSampleDrefImplicitLod, 6);
|
||||
m_code.putWord(resultType);
|
||||
m_code.putWord(resultId);
|
||||
m_code.putWord(sampledImage);
|
||||
m_code.putWord(coordinates);
|
||||
m_code.putWord(reference);
|
||||
return resultId;
|
||||
}
|
||||
|
||||
|
||||
uint32_t SpirvModule::opImageSampleDrefExplicitLod(
|
||||
uint32_t resultType,
|
||||
uint32_t sampledImage,
|
||||
|
@ -520,6 +520,18 @@ namespace dxvk {
|
||||
uint32_t sampledImage,
|
||||
uint32_t coordinates);
|
||||
|
||||
uint32_t opImageSampleExplicitLod(
|
||||
uint32_t resultType,
|
||||
uint32_t sampledImage,
|
||||
uint32_t coordinates,
|
||||
uint32_t lod);
|
||||
|
||||
uint32_t opImageSampleDrefImplicitLod(
|
||||
uint32_t resultType,
|
||||
uint32_t sampledImage,
|
||||
uint32_t coordinates,
|
||||
uint32_t reference);
|
||||
|
||||
uint32_t opImageSampleDrefExplicitLod(
|
||||
uint32_t resultType,
|
||||
uint32_t sampledImage,
|
||||
|
Loading…
x
Reference in New Issue
Block a user