mirror of
https://github.com/brl/mutter.git
synced 2024-11-09 23:46:33 -05:00
Change API so that CoglPixelBuffer no longer knows its w/h/format
The idea is that CoglPixelBuffer should just be a buffer that can be used for pixel data and it has no idea about the details of any images that are stored in it. This is analogous to CoglAttributeBuffer which itself does not have any information about the attributes. When you want to use a pixel buffer you should create a CoglBitmap which points to a region of the attribute buffer and provides the extra needed information such as the width, height and format. That way it is also possible to use a single CoglPixelBuffer with multiple bitmaps. The changes that are made are: • cogl_pixel_buffer_new_with_size has been removed and in its place is cogl_bitmap_new_with_size. This will create a pixel buffer at the right size and rowstride for the given width/height/format and immediately create a single CoglBitmap to point into it. The old function had an out-parameter for the stride of the image but with the new API this should be queriable from the bitmap (although there is no function for this yet). • There is now a public cogl_pixel_buffer_new constructor. This takes a size in bytes and data pointer similarly to cogl_attribute_buffer_new. • cogl_texture_new_from_buffer has been removed. If you want to create a texture from a pixel buffer you should wrap it up in a bitmap first. There is already API to create a texture from a bitmap. This patch also does a bit of header juggling because cogl-context.h was including cogl-texture.h and cogl-framebuffer.h which were causing some circular dependencies when cogl-bitmap.h includes cogl-context.h. These weren't actually needed in cogl-context.h itself but a few other headers were relying on them being included so this adds the #includes where necessary. Reviewed-by: Robert Bragg <robert@linux.intel.com>
This commit is contained in:
parent
10a38bb14f
commit
3700cc26a5
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "cogl-object-private.h"
|
#include "cogl-object-private.h"
|
||||||
#include "cogl-attribute.h"
|
#include "cogl-attribute.h"
|
||||||
|
#include "cogl-framebuffer.h"
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "cogl-private.h"
|
#include "cogl-private.h"
|
||||||
#include "cogl-bitmap-private.h"
|
#include "cogl-bitmap-private.h"
|
||||||
#include "cogl-buffer-private.h"
|
#include "cogl-buffer-private.h"
|
||||||
|
#include "cogl-pixel-buffer.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -264,6 +265,40 @@ cogl_bitmap_new_from_buffer (CoglBuffer *buffer,
|
|||||||
return bmp;
|
return bmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CoglBitmap *
|
||||||
|
cogl_bitmap_new_with_size (CoglContext *context,
|
||||||
|
unsigned int width,
|
||||||
|
unsigned int height,
|
||||||
|
CoglPixelFormat format)
|
||||||
|
{
|
||||||
|
CoglPixelBuffer *pixel_buffer;
|
||||||
|
CoglBitmap *bitmap;
|
||||||
|
unsigned int rowstride;
|
||||||
|
|
||||||
|
/* creating a buffer to store "any" format does not make sense */
|
||||||
|
if (G_UNLIKELY (format == COGL_PIXEL_FORMAT_ANY))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* for now we fallback to cogl_pixel_buffer_new, later, we could ask
|
||||||
|
* libdrm a tiled buffer for instance */
|
||||||
|
rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
|
||||||
|
|
||||||
|
pixel_buffer = cogl_pixel_buffer_new (context, height * rowstride, NULL);
|
||||||
|
|
||||||
|
if (G_UNLIKELY (pixel_buffer == NULL))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
bitmap = cogl_bitmap_new_from_buffer (COGL_BUFFER (pixel_buffer),
|
||||||
|
format,
|
||||||
|
width, height,
|
||||||
|
rowstride,
|
||||||
|
0 /* offset */);
|
||||||
|
|
||||||
|
cogl_object_unref (pixel_buffer);
|
||||||
|
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
CoglPixelFormat
|
CoglPixelFormat
|
||||||
_cogl_bitmap_get_format (CoglBitmap *bitmap)
|
_cogl_bitmap_get_format (CoglBitmap *bitmap)
|
||||||
{
|
{
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include <cogl/cogl-types.h>
|
#include <cogl/cogl-types.h>
|
||||||
#include <cogl/cogl-buffer.h>
|
#include <cogl/cogl-buffer.h>
|
||||||
|
#include <cogl/cogl-context.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
@ -91,6 +92,42 @@ cogl_bitmap_new_from_buffer (CoglBuffer *buffer,
|
|||||||
int height,
|
int height,
|
||||||
int rowstride,
|
int rowstride,
|
||||||
int offset);
|
int offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_bitmap_new_with_size:
|
||||||
|
* @context: A #CoglContext
|
||||||
|
* @width: width of the bitmap in pixels
|
||||||
|
* @height: height of the bitmap in pixels
|
||||||
|
* @format: the format of the pixels the array will store
|
||||||
|
*
|
||||||
|
* Creates a new #CoglBitmap with the given width, height and format.
|
||||||
|
* The initial contents of the bitmap are undefined.
|
||||||
|
*
|
||||||
|
* The data for the bitmap will be stored in a newly created
|
||||||
|
* #CoglPixelBuffer. You can get a pointer to the pixel buffer using
|
||||||
|
* cogl_bitmap_get_pixel_buffer(). The #CoglBuffer API can then be
|
||||||
|
* used to fill the bitmap with data.
|
||||||
|
*
|
||||||
|
* <note>Cogl will try its best to provide a hardware array you can
|
||||||
|
* map, write into and effectively do a zero copy upload when creating
|
||||||
|
* a texture from it with cogl_texture_new_from_bitmap(). For various
|
||||||
|
* reasons, such arrays are likely to have a stride larger than width
|
||||||
|
* * bytes_per_pixel. The user must take the stride into account when
|
||||||
|
* writing into it. The stride can be retrieved with
|
||||||
|
* cogl_bitmap_get_rowstride().</note>
|
||||||
|
*
|
||||||
|
* Return value: a #CoglPixelBuffer representing the newly created array or
|
||||||
|
* %NULL on failure
|
||||||
|
*
|
||||||
|
* Since: 1.10
|
||||||
|
* Stability: Unstable
|
||||||
|
*/
|
||||||
|
CoglBitmap *
|
||||||
|
cogl_bitmap_new_with_size (CoglContext *context,
|
||||||
|
unsigned int width,
|
||||||
|
unsigned int height,
|
||||||
|
CoglPixelFormat format);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "cogl2-path.h"
|
#include "cogl2-path.h"
|
||||||
#include "cogl-matrix.h"
|
#include "cogl-matrix.h"
|
||||||
#include "cogl-primitive.h"
|
#include "cogl-primitive.h"
|
||||||
|
#include "cogl-framebuffer.h"
|
||||||
|
|
||||||
/* The clip stack works like a GSList where only a pointer to the top
|
/* The clip stack works like a GSList where only a pointer to the top
|
||||||
of the stack is stored. The empty clip stack is represented simply
|
of the stack is stored. The empty clip stack is represented simply
|
||||||
|
@ -38,9 +38,7 @@ typedef struct _CoglContext CoglContext;
|
|||||||
|
|
||||||
#include <cogl/cogl-defines.h>
|
#include <cogl/cogl-defines.h>
|
||||||
#include <cogl/cogl-display.h>
|
#include <cogl/cogl-display.h>
|
||||||
#include <cogl/cogl-texture.h>
|
|
||||||
#include <cogl/cogl-primitive.h>
|
#include <cogl/cogl-primitive.h>
|
||||||
#include <cogl/cogl-framebuffer.h>
|
|
||||||
#ifdef COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT
|
#ifdef COGL_HAS_EGL_PLATFORM_ANDROID_SUPPORT
|
||||||
#include <android/native_window.h>
|
#include <android/native_window.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#ifndef __COGL_JOURNAL_PRIVATE_H
|
#ifndef __COGL_JOURNAL_PRIVATE_H
|
||||||
#define __COGL_JOURNAL_PRIVATE_H
|
#define __COGL_JOURNAL_PRIVATE_H
|
||||||
|
|
||||||
|
#include "cogl-texture.h"
|
||||||
#include "cogl-handle.h"
|
#include "cogl-handle.h"
|
||||||
#include "cogl-clip-stack.h"
|
#include "cogl-clip-stack.h"
|
||||||
|
|
||||||
|
@ -40,11 +40,6 @@ G_BEGIN_DECLS
|
|||||||
struct _CoglPixelBuffer
|
struct _CoglPixelBuffer
|
||||||
{
|
{
|
||||||
CoglBuffer _parent;
|
CoglBuffer _parent;
|
||||||
|
|
||||||
CoglPixelFormat format;
|
|
||||||
unsigned int width;
|
|
||||||
unsigned int height;
|
|
||||||
unsigned int stride;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@ -66,8 +66,10 @@ _cogl_pixel_buffer_free (CoglPixelBuffer *buffer);
|
|||||||
|
|
||||||
COGL_BUFFER_DEFINE (PixelBuffer, pixel_buffer)
|
COGL_BUFFER_DEFINE (PixelBuffer, pixel_buffer)
|
||||||
|
|
||||||
static CoglPixelBuffer *
|
CoglPixelBuffer *
|
||||||
_cogl_pixel_buffer_new (CoglContext *context, unsigned int size)
|
cogl_pixel_buffer_new (CoglContext *context,
|
||||||
|
gsize size,
|
||||||
|
const void *data)
|
||||||
{
|
{
|
||||||
CoglPixelBuffer *pixel_buffer = g_slice_new0 (CoglPixelBuffer);
|
CoglPixelBuffer *pixel_buffer = g_slice_new0 (CoglPixelBuffer);
|
||||||
CoglBuffer *buffer = COGL_BUFFER (pixel_buffer);
|
CoglBuffer *buffer = COGL_BUFFER (pixel_buffer);
|
||||||
@ -87,42 +89,15 @@ _cogl_pixel_buffer_new (CoglContext *context, unsigned int size)
|
|||||||
COGL_BUFFER_USAGE_HINT_TEXTURE,
|
COGL_BUFFER_USAGE_HINT_TEXTURE,
|
||||||
COGL_BUFFER_UPDATE_HINT_STATIC);
|
COGL_BUFFER_UPDATE_HINT_STATIC);
|
||||||
|
|
||||||
/* return COGL_INVALID_HANDLE; */
|
_cogl_pixel_buffer_object_new (pixel_buffer);
|
||||||
return _cogl_pixel_buffer_object_new (pixel_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
CoglPixelBuffer *
|
if (data)
|
||||||
cogl_pixel_buffer_new_with_size (CoglContext *context,
|
cogl_buffer_set_data (COGL_BUFFER (pixel_buffer),
|
||||||
unsigned int width,
|
0,
|
||||||
unsigned int height,
|
data,
|
||||||
CoglPixelFormat format,
|
size);
|
||||||
unsigned int *rowstride)
|
|
||||||
{
|
|
||||||
CoglPixelBuffer *buffer;
|
|
||||||
CoglPixelBuffer *pixel_buffer;
|
|
||||||
unsigned int stride;
|
|
||||||
|
|
||||||
/* creating a buffer to store "any" format does not make sense */
|
return pixel_buffer;
|
||||||
if (G_UNLIKELY (format == COGL_PIXEL_FORMAT_ANY))
|
|
||||||
return COGL_INVALID_HANDLE;
|
|
||||||
|
|
||||||
/* for now we fallback to cogl_pixel_buffer_new, later, we could ask
|
|
||||||
* libdrm a tiled buffer for instance */
|
|
||||||
stride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
|
|
||||||
if (rowstride)
|
|
||||||
*rowstride = stride;
|
|
||||||
|
|
||||||
buffer = _cogl_pixel_buffer_new (context, height * stride);
|
|
||||||
if (G_UNLIKELY (buffer == COGL_INVALID_HANDLE))
|
|
||||||
return COGL_INVALID_HANDLE;
|
|
||||||
|
|
||||||
pixel_buffer = COGL_PIXEL_BUFFER (buffer);
|
|
||||||
pixel_buffer->width = width;
|
|
||||||
pixel_buffer->height = height;
|
|
||||||
pixel_buffer->format = format;
|
|
||||||
pixel_buffer->stride = stride;
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -54,34 +54,26 @@ G_BEGIN_DECLS
|
|||||||
typedef struct _CoglPixelBuffer CoglPixelBuffer;
|
typedef struct _CoglPixelBuffer CoglPixelBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cogl_pixel_buffer_new_with_size:
|
* cogl_pixel_buffer_new:
|
||||||
* @context: A #CoglContext
|
* @context: A #CoglContext
|
||||||
* @width: width of the pixel array in pixels
|
* @size: The number of bytes to allocate for the pixel data.
|
||||||
* @height: height of the pixel array in pixels
|
* @data: An optional pointer to vertex data to upload immediately
|
||||||
* @format: the format of the pixels the array will store
|
|
||||||
* @stride: if not %NULL the function will return the stride of the array
|
|
||||||
* in bytes
|
|
||||||
*
|
*
|
||||||
* Creates a new array to store pixel data.
|
* Declares a new #CoglPixelBuffer of @size bytes to contain arrays of
|
||||||
|
* pixels. Once declared, data can be set using cogl_buffer_set_data()
|
||||||
|
* or by mapping it into the application's address space using
|
||||||
|
* cogl_buffer_map().
|
||||||
*
|
*
|
||||||
* <note>COGL will try its best to provide a hardware array you can map,
|
* If @data isn't %NULL then @size bytes will be read from @data and
|
||||||
* write into and effectively do a zero copy upload when creating a texture
|
* immediately copied into the new buffer.
|
||||||
* from it with cogl_texture_new_from_buffer(). For various reasons, such
|
|
||||||
* arrays are likely to have a stride larger than width * bytes_per_pixel. The
|
|
||||||
* user must take the stride into account when writing into it.</note>
|
|
||||||
*
|
*
|
||||||
* Return value: a #CoglPixelBuffer representing the newly created array or
|
* Since: 1.10
|
||||||
* %NULL on failure
|
* Stability: unstable
|
||||||
*
|
|
||||||
* Since: 1.2
|
|
||||||
* Stability: Unstable
|
|
||||||
*/
|
*/
|
||||||
CoglPixelBuffer *
|
CoglPixelBuffer *
|
||||||
cogl_pixel_buffer_new_with_size (CoglContext *context,
|
cogl_pixel_buffer_new (CoglContext *context,
|
||||||
unsigned int width,
|
gsize size,
|
||||||
unsigned int height,
|
const void *data);
|
||||||
CoglPixelFormat format,
|
|
||||||
unsigned int *stride);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cogl_is_pixel_buffer:
|
* cogl_is_pixel_buffer:
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "cogl-pipeline-private.h"
|
#include "cogl-pipeline-private.h"
|
||||||
#include "cogl-spans.h"
|
#include "cogl-spans.h"
|
||||||
#include "cogl-meta-texture.h"
|
#include "cogl-meta-texture.h"
|
||||||
|
#include "cogl-framebuffer.h"
|
||||||
|
|
||||||
typedef struct _CoglTextureVtable CoglTextureVtable;
|
typedef struct _CoglTextureVtable CoglTextureVtable;
|
||||||
|
|
||||||
|
@ -497,62 +497,6 @@ cogl_texture_new_from_sub_texture (CoglTexture *full_texture,
|
|||||||
sub_width, sub_height));
|
sub_width, sub_height));
|
||||||
}
|
}
|
||||||
|
|
||||||
CoglTexture *
|
|
||||||
cogl_texture_new_from_buffer_EXP (CoglPixelBuffer *buffer,
|
|
||||||
unsigned int width,
|
|
||||||
unsigned int height,
|
|
||||||
CoglTextureFlags flags,
|
|
||||||
CoglPixelFormat format,
|
|
||||||
CoglPixelFormat internal_format,
|
|
||||||
unsigned int rowstride,
|
|
||||||
const unsigned int offset)
|
|
||||||
{
|
|
||||||
CoglTexture *texture;
|
|
||||||
CoglBuffer *cogl_buffer;
|
|
||||||
CoglPixelBuffer *pixel_buffer;
|
|
||||||
CoglBitmap *bmp;
|
|
||||||
|
|
||||||
_COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), NULL);
|
|
||||||
|
|
||||||
if (format == COGL_PIXEL_FORMAT_ANY)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
cogl_buffer = COGL_BUFFER (buffer);
|
|
||||||
pixel_buffer = COGL_PIXEL_BUFFER (buffer);
|
|
||||||
|
|
||||||
/* Rowstride from CoglBuffer or even width * bpp if not given */
|
|
||||||
if (rowstride == 0)
|
|
||||||
rowstride = pixel_buffer->stride;
|
|
||||||
if (rowstride == 0)
|
|
||||||
rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
|
|
||||||
|
|
||||||
/* use the CoglBuffer height and width as last resort */
|
|
||||||
if (width == 0)
|
|
||||||
width = pixel_buffer->width;
|
|
||||||
if (height == 0)
|
|
||||||
height = pixel_buffer->height;
|
|
||||||
if (width == 0 || height == 0)
|
|
||||||
{
|
|
||||||
/* no width or height specified, neither at creation time (because the
|
|
||||||
* array was created by cogl_pixel_buffer_new()) nor when calling this
|
|
||||||
* function */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wrap the buffer into a bitmap */
|
|
||||||
bmp = cogl_bitmap_new_from_buffer (cogl_buffer,
|
|
||||||
format,
|
|
||||||
width, height,
|
|
||||||
rowstride,
|
|
||||||
offset);
|
|
||||||
|
|
||||||
texture = cogl_texture_new_from_bitmap (bmp, flags, internal_format);
|
|
||||||
|
|
||||||
cogl_object_unref (bmp);
|
|
||||||
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
cogl_texture_get_width (CoglTexture *texture)
|
cogl_texture_get_width (CoglTexture *texture)
|
||||||
{
|
{
|
||||||
|
@ -491,49 +491,6 @@ cogl_texture_new_from_sub_texture (CoglTexture *full_texture,
|
|||||||
int sub_width,
|
int sub_width,
|
||||||
int sub_height);
|
int sub_height);
|
||||||
|
|
||||||
#if defined (COGL_ENABLE_EXPERIMENTAL_API)
|
|
||||||
|
|
||||||
#define cogl_texture_new_from_buffer cogl_texture_new_from_buffer_EXP
|
|
||||||
/**
|
|
||||||
* cogl_texture_new_from_buffer:
|
|
||||||
* @buffer: A #CoglPixelBuffer pointer
|
|
||||||
* @width: width of texture in pixels or 0
|
|
||||||
* @height: height of texture in pixels or 0
|
|
||||||
* @flags: optional flags for the texture, or %COGL_TEXTURE_NONE
|
|
||||||
* @format: the #CoglPixelFormat the buffer is stored in in RAM
|
|
||||||
* @internal_format: the #CoglPixelFormat that will be used for storing
|
|
||||||
* the buffer on the GPU. If %COGL_PIXEL_FORMAT_ANY is given then a
|
|
||||||
* premultiplied format similar to the format of the source data will
|
|
||||||
* be used. The default blending equations of Cogl expect premultiplied
|
|
||||||
* color data; the main use of passing a non-premultiplied format here
|
|
||||||
* is if you have non-premultiplied source data and are going to adjust
|
|
||||||
* the blend mode (see cogl_material_set_blend()) or use the data for
|
|
||||||
* something other than straight blending
|
|
||||||
* @rowstride: the memory offset in bytes between the starts of
|
|
||||||
* scanlines in @data. If 0 is given the row stride will be deduced from
|
|
||||||
* @width and @format or the stride given by cogl_pixel_buffer_new_for_size()
|
|
||||||
* @offset: offset in bytes in @buffer from where the texture data starts
|
|
||||||
*
|
|
||||||
* Creates a new texture using the buffer specified by @handle. If the buffer
|
|
||||||
* has been created using cogl_pixel_buffer_new_for_size() it's possible to omit
|
|
||||||
* the height and width values already specified at creation time.
|
|
||||||
*
|
|
||||||
* Return value: A newly created #CoglTexture or %NULL on failure
|
|
||||||
*
|
|
||||||
* Since: 1.2
|
|
||||||
* Stability: Unstable
|
|
||||||
*/
|
|
||||||
CoglTexture *
|
|
||||||
cogl_texture_new_from_buffer (CoglPixelBuffer *buffer,
|
|
||||||
unsigned int width,
|
|
||||||
unsigned int height,
|
|
||||||
CoglTextureFlags flags,
|
|
||||||
CoglPixelFormat format,
|
|
||||||
CoglPixelFormat internal_format,
|
|
||||||
unsigned int rowstride,
|
|
||||||
unsigned int offset);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef COGL_DISABLE_DEPRECATED
|
#ifndef COGL_DISABLE_DEPRECATED
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -679,12 +679,8 @@ cogl_buffer_set_data
|
|||||||
|
|
||||||
<SUBSECTION>
|
<SUBSECTION>
|
||||||
cogl_pixel_buffer_new
|
cogl_pixel_buffer_new
|
||||||
cogl_pixel_buffer_new_for_size
|
|
||||||
cogl_is_pixel_buffer
|
cogl_is_pixel_buffer
|
||||||
|
|
||||||
<SUBSECTION>
|
|
||||||
cogl_texture_new_from_buffer
|
|
||||||
|
|
||||||
<SUBSECTION Private>
|
<SUBSECTION Private>
|
||||||
cogl_buffer_access_get_type
|
cogl_buffer_access_get_type
|
||||||
cogl_buffer_update_hint_get_type
|
cogl_buffer_update_hint_get_type
|
||||||
|
@ -566,12 +566,8 @@ cogl_buffer_set_data
|
|||||||
|
|
||||||
<SUBSECTION>
|
<SUBSECTION>
|
||||||
cogl_pixel_buffer_new
|
cogl_pixel_buffer_new
|
||||||
cogl_pixel_buffer_new_for_size
|
|
||||||
cogl_is_pixel_buffer
|
cogl_is_pixel_buffer
|
||||||
|
|
||||||
<SUBSECTION>
|
|
||||||
cogl_texture_new_from_buffer
|
|
||||||
|
|
||||||
<SUBSECTION Private>
|
<SUBSECTION Private>
|
||||||
cogl_buffer_access_get_type
|
cogl_buffer_access_get_type
|
||||||
cogl_buffer_update_hint_get_type
|
cogl_buffer_update_hint_get_type
|
||||||
|
Loading…
Reference in New Issue
Block a user