mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-26 21:40:07 +00:00
Draw contexts do not fully initialize patch arrays #281
* added the numVertexElements argument to Osd*DrawContext::Create, which is used to initialize the patch arrays when calling OsdDrawContext::ConvertPatchArrays * removed the unused level argument from Osd*DrawContext::_initialize * maintenance work on CL/D3D11 bindings to get them to compile
This commit is contained in:
parent
3405e952ba
commit
2a463b5c83
@ -313,7 +313,7 @@ if(OPENMP_FOUND)
|
||||
else()
|
||||
message(WARNING
|
||||
"OpenMP was not found : support for OMP parallel compute kernels "
|
||||
"will be diabled in Osd. If your compiler supports OpenMP "
|
||||
"will be disabled in Osd. If your compiler supports OpenMP "
|
||||
"directives, please refer to the FindOpenMP.cmake shared module "
|
||||
"in your cmake installation.")
|
||||
endif()
|
||||
@ -327,7 +327,7 @@ if(TBB_FOUND)
|
||||
else()
|
||||
message(WARNING
|
||||
"TBB was not found : support for TBB parallel compute kernels "
|
||||
"will be diabled in Osd. If your compiler supports TBB "
|
||||
"will be disabled in Osd. If your compiler supports TBB "
|
||||
"directives, please refer to the FindTBB.cmake shared module "
|
||||
"in your cmake installation.")
|
||||
endif()
|
||||
|
@ -506,7 +506,7 @@ createOsdMesh( const std::string &shape, int level, int kernel, Scheme scheme=kC
|
||||
hmesh,
|
||||
numVertexElements,
|
||||
numVaryingElements,
|
||||
level, bits, g_pd3dDeviceContext);
|
||||
level, bits, g_clContext, g_clQueue, g_pd3dDeviceContext);
|
||||
#endif
|
||||
#ifdef OPENSUBDIV_HAS_CUDA
|
||||
} else if (g_kernel == kCUDA) {
|
||||
|
@ -86,7 +86,7 @@ public:
|
||||
maxValence, 3);
|
||||
}
|
||||
|
||||
_drawContext = OpenSubdiv::OsdGLDrawContext::Create(&partitioner.GetPatchTables(), false);
|
||||
_drawContext = OpenSubdiv::OsdGLDrawContext::Create(&partitioner.GetPatchTables(), 3, false);
|
||||
_drawContext->UpdateVertexTexture(_vertexBuffer);
|
||||
}
|
||||
|
||||
|
@ -35,12 +35,12 @@ MyDrawContext::~MyDrawContext() {
|
||||
}
|
||||
|
||||
MyDrawContext*
|
||||
MyDrawContext::Create(OpenSubdiv::FarPatchTables const *patchTables, bool requireFVarData)
|
||||
MyDrawContext::Create(OpenSubdiv::FarPatchTables const *patchTables, int numVertexElements, bool requireFVarData)
|
||||
{
|
||||
MyDrawContext * result = new MyDrawContext();
|
||||
|
||||
if (patchTables) {
|
||||
if (result->create(patchTables, requireFVarData)) {
|
||||
if (result->create(patchTables, numVertexElements, requireFVarData)) {
|
||||
return result;
|
||||
} else {
|
||||
delete result;
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
virtual ~MyDrawContext();
|
||||
|
||||
static MyDrawContext *Create(OpenSubdiv::FarPatchTables const *patchTables,
|
||||
int numVertexElements,
|
||||
bool requireFVarData=false);
|
||||
|
||||
GLuint GetVertexArray() const { return _vao; }
|
||||
|
@ -353,7 +353,9 @@ createOsdContext(int level)
|
||||
g_farmesh->GetNumVertices());
|
||||
|
||||
g_drawContext =
|
||||
OpenSubdiv::OsdGLDrawContext::Create(g_farmesh->GetPatchTables(), false);
|
||||
OpenSubdiv::OsdGLDrawContext::Create(g_farmesh->GetPatchTables(),
|
||||
g_farmesh->GetNumVertices(),
|
||||
false);
|
||||
g_drawContext->UpdateVertexTexture(g_vertexBuffer);
|
||||
|
||||
//
|
||||
|
@ -375,6 +375,12 @@ if ( OPENCL_FOUND )
|
||||
list(APPEND GPU_SOURCE_FILES clGLVertexBuffer.cpp)
|
||||
list(APPEND PUBLIC_HEADER_FILES clGLVertexBuffer.h)
|
||||
endif()
|
||||
|
||||
# OpenCL D3D11 interop needs work...
|
||||
#if ( DXSDK_FOUND )
|
||||
# list(APPEND GPU_SOURCE_FILES clD3D11VertexBuffer.cpp)
|
||||
# list(APPEND PUBLIC_HEADER_FILES clD3D11VertexBuffer.h)
|
||||
#endif()
|
||||
endif()
|
||||
|
||||
list(APPEND DOXY_HEADER_FILES ${OPENCL_PUBLIC_HEADERS})
|
||||
|
@ -119,7 +119,7 @@ void
|
||||
OsdCLD3D11VertexBuffer::unmap() {
|
||||
|
||||
if (not _clMapped) return;
|
||||
clEnqueueReleaseD3D11ObjectsKHR(queue, 1, &_clMemory, 0, 0, 0);
|
||||
clEnqueueReleaseD3D11ObjectsKHR(_clQueue, 1, &_clMemory, 0, 0, 0);
|
||||
_clMapped = false;
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,17 @@
|
||||
#include <CL/opencl.h>
|
||||
#endif
|
||||
|
||||
struct ID3D11VertexShader;
|
||||
struct ID3D11HullShader;
|
||||
struct ID3D11DomainShader;
|
||||
struct ID3D11GeometryShader;
|
||||
struct ID3D11PixelShader;
|
||||
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11ShaderResourceView;
|
||||
struct ID3D11Device;
|
||||
struct ID3D11DeviceContext;
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
|
@ -63,10 +63,11 @@ OsdD3D11DrawContext::~OsdD3D11DrawContext()
|
||||
OsdD3D11DrawContext *
|
||||
OsdD3D11DrawContext::Create(FarPatchTables const *patchTables,
|
||||
ID3D11DeviceContext *pd3d11DeviceContext,
|
||||
int numVertexElements,
|
||||
bool requireFVarData)
|
||||
{
|
||||
OsdD3D11DrawContext * result = new OsdD3D11DrawContext();
|
||||
if (result->create(patchTables, pd3d11DeviceContext, requireFVarData))
|
||||
if (result->create(patchTables, pd3d11DeviceContext, numVertexElements, requireFVarData))
|
||||
return result;
|
||||
|
||||
delete result;
|
||||
@ -76,6 +77,7 @@ OsdD3D11DrawContext::Create(FarPatchTables const *patchTables,
|
||||
bool
|
||||
OsdD3D11DrawContext::create(FarPatchTables const *patchTables,
|
||||
ID3D11DeviceContext *pd3d11DeviceContext,
|
||||
int numVertexElements,
|
||||
bool requireFVarData)
|
||||
{
|
||||
// adaptive patches
|
||||
@ -85,7 +87,7 @@ OsdD3D11DrawContext::create(FarPatchTables const *patchTables,
|
||||
pd3d11DeviceContext->GetDevice(&pd3d11Device);
|
||||
assert(pd3d11Device);
|
||||
|
||||
ConvertPatchArrays(patchTables->GetPatchArrayVector(), patchArrays, patchTables->GetMaxValence(), 0);
|
||||
ConvertPatchArrays(patchTables->GetPatchArrayVector(), patchArrays, patchTables->GetMaxValence(), numVertexElements);
|
||||
|
||||
FarPatchTables::PTable const & ptables = patchTables->GetPatchTable();
|
||||
FarPatchTables::PatchParamTable const & ptexCoordTables = patchTables->GetPatchParamTable();
|
||||
@ -231,15 +233,6 @@ OsdD3D11DrawContext::updateVertexTexture(ID3D11Buffer *vbo,
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// XXX: consider moving this proc to base class
|
||||
// updating num elements in descriptor with new vbo specs
|
||||
for (int i = 0; i < (int)patchArrays.size(); ++i) {
|
||||
PatchArray &parray = patchArrays[i];
|
||||
PatchDescriptor desc = parray.GetDescriptor();
|
||||
desc.SetNumElements(numVertexElements);
|
||||
parray.SetDescriptor(desc);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
|
@ -70,12 +70,15 @@ public:
|
||||
///
|
||||
/// @param pd3d11DeviceContext a device context
|
||||
///
|
||||
/// @param numVertexElements the number of vertex elements
|
||||
///
|
||||
/// @param requireFVarData set to true to enable face-varying data to be
|
||||
/// carried over from the Far data structures.
|
||||
///
|
||||
///
|
||||
static OsdD3D11DrawContext *Create(FarPatchTables const *patchTables,
|
||||
ID3D11DeviceContext *pd3d11DeviceContext,
|
||||
int numVertexElements,
|
||||
bool requireFVarData=false);
|
||||
|
||||
/// Set vbo as a vertex texture (for gregory patch drawing)
|
||||
@ -112,12 +115,13 @@ private:
|
||||
// allocate buffers from patchTables
|
||||
bool create(FarPatchTables const *patchTables,
|
||||
ID3D11DeviceContext *pd3d11DeviceContext,
|
||||
int numVertexElements,
|
||||
bool requireFVarData);
|
||||
|
||||
void updateVertexTexture(ID3D11Buffer *vbo,
|
||||
ID3D11DeviceContext *pd3d11DeviceContext,
|
||||
int numVertices,
|
||||
int numElements);
|
||||
int numVertexElements);
|
||||
|
||||
int _numVertices;
|
||||
};
|
||||
|
@ -76,6 +76,7 @@ public:
|
||||
_farMesh->GetVertexEditTables());
|
||||
_drawContext = DrawContext::Create(_farMesh->GetPatchTables(),
|
||||
_pd3d11DeviceContext,
|
||||
numVertexElements,
|
||||
bits.test(MeshFVarData));
|
||||
assert(_drawContext);
|
||||
_drawContext->UpdateVertexTexture(_vertexBuffer, _pd3d11DeviceContext);
|
||||
@ -164,6 +165,7 @@ public:
|
||||
_pd3d11DeviceContext);
|
||||
_drawContext = DrawContext::Create(_farMesh->GetPatchTables(),
|
||||
_pd3d11DeviceContext,
|
||||
numVertexElements,
|
||||
bits.test(MeshFVarData));
|
||||
_drawContext->UpdateVertexTexture(_vertexBuffer, _pd3d11DeviceContext);
|
||||
}
|
||||
@ -251,8 +253,7 @@ public:
|
||||
_pd3d11DeviceContext(d3d11DeviceContext)
|
||||
{
|
||||
FarMeshFactory<OsdVertex> meshFactory(hmesh, level, bits.test(MeshAdaptive));
|
||||
_farMesh = meshFactory.Create(bits.test(MeshPtexData),
|
||||
bits.test(MeshFVarData));
|
||||
_farMesh = meshFactory.Create(bits.test(MeshFVarData));
|
||||
|
||||
ID3D11Device * pd3d11Device;
|
||||
_pd3d11DeviceContext->GetDevice(&pd3d11Device);
|
||||
@ -261,11 +262,14 @@ public:
|
||||
_vertexBuffer = typename VertexBuffer::Create(numVertexElements, numVertices, _clContext, pd3d11Device);
|
||||
if (numVaryingElements)
|
||||
_varyingBuffer = typename VertexBuffer::Create(numVaryingElements, numVertices, _clContext, pd3d11Device);
|
||||
_computeContext = ComputeContext::Create(_farMesh, _clContext);
|
||||
_drawContext = DrawContext::Create(_farMesh, _vertexBuffer,
|
||||
_computeContext = ComputeContext::Create(_farMesh->GetSubdivisionTables(),
|
||||
_farMesh->GetVertexEditTables(), _clContext);
|
||||
_drawContext = DrawContext::Create(_farMesh->GetPatchTables(),
|
||||
_pd3d11DeviceContext,
|
||||
bits.test(MeshPtexData),
|
||||
numVertexElements,
|
||||
bits.test(MeshFVarData));
|
||||
assert(_drawContext);
|
||||
_drawContext->UpdateVertexTexture(_vertexBuffer, _pd3d11DeviceContext);
|
||||
}
|
||||
|
||||
virtual ~OsdMesh() {
|
||||
@ -278,15 +282,15 @@ public:
|
||||
|
||||
virtual int GetNumVertices() const { return _farMesh->GetNumVertices(); }
|
||||
|
||||
virtual void UpdateVertexBuffer(float const *vertexData, int numVerts) {
|
||||
virtual void UpdateVertexBuffer(float const *vertexData, int startVertex, int numVerts) {
|
||||
ID3D11Device * pd3d11Device;
|
||||
_pd3d11DeviceContext->GetDevice(&pd3d11Device);
|
||||
_vertexBuffer->UpdateData(vertexData, numVerts, _clQueue, pd3d11Device);
|
||||
_vertexBuffer->UpdateData(vertexData, startVertex, numVerts, _clQueue);
|
||||
}
|
||||
virtual void UpdateVaryingBuffer(float const *varyingData, int numVerts) {
|
||||
virtual void UpdateVaryingBuffer(float const *varyingData, int startVertex, int numVerts) {
|
||||
ID3D11Device * pd3d11Device;
|
||||
_pd3d11DeviceContext->GetDevice(&pd3d11Device);
|
||||
_varyingBuffer->UpdateData(varyingData, numVerts, _clQueue, pd3d11Device);
|
||||
_varyingBuffer->UpdateData(varyingData, startVertex, numVerts, _clQueue);
|
||||
}
|
||||
virtual void Refine() {
|
||||
_computeController->Refine(_computeContext, _farMesh->GetKernelBatches(), _vertexBuffer, _varyingBuffer);
|
||||
|
@ -97,13 +97,13 @@ createTextureBuffer(T const &data, GLint format, int offset=0)
|
||||
}
|
||||
|
||||
OsdGLDrawContext *
|
||||
OsdGLDrawContext::Create(FarPatchTables const * patchTables, bool requireFVarData) {
|
||||
OsdGLDrawContext::Create(FarPatchTables const * patchTables, int numVertexElements, bool requireFVarData) {
|
||||
|
||||
if (patchTables) {
|
||||
|
||||
OsdGLDrawContext * result = new OsdGLDrawContext();
|
||||
|
||||
if (result->create(patchTables, requireFVarData)) {
|
||||
if (result->create(patchTables, numVertexElements, requireFVarData)) {
|
||||
return result;
|
||||
} else {
|
||||
delete result;
|
||||
@ -113,7 +113,7 @@ OsdGLDrawContext::Create(FarPatchTables const * patchTables, bool requireFVarDat
|
||||
}
|
||||
|
||||
bool
|
||||
OsdGLDrawContext::create(FarPatchTables const * patchTables, bool requireFVarData) {
|
||||
OsdGLDrawContext::create(FarPatchTables const * patchTables, int numVertexElements, bool requireFVarData) {
|
||||
|
||||
assert(patchTables);
|
||||
|
||||
@ -139,7 +139,7 @@ OsdGLDrawContext::create(FarPatchTables const * patchTables, bool requireFVarDat
|
||||
}
|
||||
|
||||
OsdDrawContext::ConvertPatchArrays(patchTables->GetPatchArrayVector(),
|
||||
patchArrays, patchTables->GetMaxValence(), 0);
|
||||
patchArrays, patchTables->GetMaxValence(), numVertexElements);
|
||||
|
||||
// allocate and initialize additional buffer data
|
||||
|
||||
@ -186,7 +186,7 @@ OsdGLDrawContext::create(FarPatchTables const * patchTables, bool requireFVarDat
|
||||
}
|
||||
|
||||
void
|
||||
OsdGLDrawContext::updateVertexTexture(GLuint vbo, int numVertexElements)
|
||||
OsdGLDrawContext::updateVertexTexture(GLuint vbo)
|
||||
{
|
||||
#if defined(GL_ARB_texture_buffer_object) || defined(GL_VERSION_3_1)
|
||||
|
||||
@ -203,15 +203,6 @@ OsdGLDrawContext::updateVertexTexture(GLuint vbo, int numVertexElements)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// XXX: consider moving this proc to base class
|
||||
// updating num elements in descriptor with new vbo specs
|
||||
for (int i = 0; i < (int)patchArrays.size(); ++i) {
|
||||
PatchArray &parray = patchArrays[i];
|
||||
PatchDescriptor desc = parray.GetDescriptor();
|
||||
desc.SetNumElements(numVertexElements);
|
||||
parray.SetDescriptor(desc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -57,12 +57,14 @@ public:
|
||||
|
||||
/// \brief Create an OsdGLDraContext from FarPatchTables
|
||||
///
|
||||
/// @param patchTables a valid set of FarPatchTables
|
||||
/// @param patchTables a valid set of FarPatchTables
|
||||
///
|
||||
/// @param requireFVarData set to true to enable face-varying data to be
|
||||
/// carried over from the Far data structures.
|
||||
/// @param numVertexElements the number of vertex elements
|
||||
///
|
||||
static OsdGLDrawContext * Create(FarPatchTables const * patchTables, bool requireFVarData);
|
||||
/// @param requireFVarData set to true to enable face-varying data to be
|
||||
/// carried over from the Far data structures.
|
||||
///
|
||||
static OsdGLDrawContext * Create(FarPatchTables const * patchTables, int numVertexElements, bool requireFVarData);
|
||||
|
||||
/// Set vbo as a vertex texture (for gregory patch drawing)
|
||||
///
|
||||
@ -71,7 +73,7 @@ public:
|
||||
template<class VERTEX_BUFFER>
|
||||
void UpdateVertexTexture(VERTEX_BUFFER *vbo) {
|
||||
if (vbo)
|
||||
updateVertexTexture(vbo->BindVBO(), vbo->GetNumElements());
|
||||
updateVertexTexture(vbo->BindVBO());
|
||||
}
|
||||
|
||||
/// true if the GL version detected supports shader tessellation
|
||||
@ -134,9 +136,9 @@ protected:
|
||||
OsdGLDrawContext();
|
||||
|
||||
// allocate buffers from patchTables
|
||||
bool create(FarPatchTables const *patchTables, bool requireFVarData);
|
||||
bool create(FarPatchTables const *patchTables, int numElements, bool requireFVarData);
|
||||
|
||||
void updateVertexTexture(GLuint vbo, int numElements);
|
||||
void updateVertexTexture(GLuint vbo);
|
||||
};
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
|
@ -70,7 +70,7 @@ public:
|
||||
FarMeshFactory<OsdVertex> meshFactory(hmesh, level, bits.test(MeshAdaptive));
|
||||
_farMesh = meshFactory.Create(bits.test(MeshFVarData));
|
||||
|
||||
_initialize(numVertexElements, numVaryingElements, level, bits);
|
||||
_initialize(numVertexElements, numVaryingElements, bits);
|
||||
}
|
||||
|
||||
OsdMesh(ComputeController * computeController,
|
||||
@ -87,7 +87,7 @@ public:
|
||||
_computeController(computeController),
|
||||
_drawContext(0)
|
||||
{
|
||||
_initialize(numVertexElements, numVaryingElements, level, bits);
|
||||
_initialize(numVertexElements, numVaryingElements, bits);
|
||||
}
|
||||
|
||||
virtual ~OsdMesh() {
|
||||
@ -135,8 +135,7 @@ private:
|
||||
|
||||
void _initialize( int numVertexElements,
|
||||
int numVaryingElements,
|
||||
int level,
|
||||
OsdMeshBitset bits)
|
||||
OsdMeshBitset bits)
|
||||
{
|
||||
int numVertices = _farMesh->GetNumVertices();
|
||||
if (numVertexElements)
|
||||
@ -144,7 +143,7 @@ private:
|
||||
if (numVaryingElements)
|
||||
_varyingBuffer = VertexBuffer::Create(numVaryingElements, numVertices);
|
||||
_computeContext = ComputeContext::Create(_farMesh->GetSubdivisionTables(), _farMesh->GetVertexEditTables());
|
||||
_drawContext = DrawContext::Create(_farMesh->GetPatchTables(), bits.test(MeshFVarData));
|
||||
_drawContext = DrawContext::Create(_farMesh->GetPatchTables(), numVertexElements, bits.test(MeshFVarData));
|
||||
_drawContext->UpdateVertexTexture(_vertexBuffer);
|
||||
}
|
||||
|
||||
@ -188,7 +187,7 @@ public:
|
||||
FarMeshFactory<OsdVertex> meshFactory(hmesh, level, bits.test(MeshAdaptive));
|
||||
_farMesh = meshFactory.Create(bits.test(MeshFVarData));
|
||||
|
||||
_initialize(numVertexElements, numVaryingElements, level, bits);
|
||||
_initialize(numVertexElements, numVaryingElements, bits);
|
||||
}
|
||||
|
||||
OsdMesh(ComputeController * computeController,
|
||||
@ -209,7 +208,7 @@ public:
|
||||
_clContext(clContext),
|
||||
_clQueue(clQueue)
|
||||
{
|
||||
_initialize(numVertexElements, numVaryingElements, level, bits);
|
||||
_initialize(numVertexElements, numVaryingElements, bits);
|
||||
}
|
||||
|
||||
virtual ~OsdMesh() {
|
||||
@ -256,7 +255,6 @@ private:
|
||||
|
||||
void _initialize( int numVertexElements,
|
||||
int numVaryingElements,
|
||||
int level,
|
||||
OsdMeshBitset bits)
|
||||
{
|
||||
int numVertices = _farMesh->GetNumVertices();
|
||||
@ -265,7 +263,7 @@ private:
|
||||
if (numVaryingElements)
|
||||
_varyingBuffer = VertexBuffer::Create(numVaryingElements, numVertices, _clContext);
|
||||
_computeContext = ComputeContext::Create(_farMesh->GetSubdivisionTables(), _farMesh->GetVertexEditTables(), _clContext);
|
||||
_drawContext = DrawContext::Create(_farMesh->GetPatchTables(), bits.test(MeshFVarData));
|
||||
_drawContext = DrawContext::Create(_farMesh->GetPatchTables(), numVertexElements, bits.test(MeshFVarData));
|
||||
_drawContext->UpdateVertexTexture(_vertexBuffer);
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ public:
|
||||
FarMeshFactory<OsdVertex> meshFactory(hmesh, level, bits.test(MeshAdaptive));
|
||||
_farMesh = meshFactory.Create(bits.test(MeshFVarData));
|
||||
|
||||
_initialize(numVertexElements, numVaryingElements, level, bits);
|
||||
_initialize(numVertexElements, numVaryingElements, bits);
|
||||
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ public:
|
||||
_computeController(computeController),
|
||||
_drawContext(0)
|
||||
{
|
||||
_initialize(numVertexElements, numVaryingElements, level, bits);
|
||||
_initialize(numVertexElements, numVaryingElements, bits);
|
||||
}
|
||||
|
||||
virtual ~OsdMesh() {
|
||||
@ -160,8 +160,7 @@ private:
|
||||
|
||||
void _initialize( int numVertexElements,
|
||||
int numVaryingElements,
|
||||
int level,
|
||||
OsdMeshBitset bits)
|
||||
OsdMeshBitset bits)
|
||||
{
|
||||
int numVertices = _farMesh->GetNumVertices();
|
||||
if (numVertexElements)
|
||||
@ -169,7 +168,7 @@ private:
|
||||
if (numVaryingElements)
|
||||
_varyingBuffer = VertexBuffer::Create(numVaryingElements, numVertices);
|
||||
_computeContext = ComputeContext::Create(_farMesh);
|
||||
_drawContext = DrawContext::Create(_farMesh->GetPatchTables(), bits.test(MeshFVarData));
|
||||
_drawContext = DrawContext::Create(_farMesh->GetPatchTables(), numVertexElements, bits.test(MeshFVarData));
|
||||
}
|
||||
|
||||
FarMesh<OsdVertex> *_farMesh;
|
||||
|
Loading…
Reference in New Issue
Block a user